From 5f2595a6583c90e4c3d08330e29da41c74b3d938 Mon Sep 17 00:00:00 2001 From: "artem.kravchenko" Date: Tue, 2 Dec 2025 16:07:45 +0100 Subject: [PATCH 1/2] web api: configurable bot name --- web_api/example.env | 3 +++ web_api/web_api/models.py | 10 +++++----- web_api/web_api/settings.py | 3 +++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/web_api/example.env b/web_api/example.env index 14e562987..6b0d57857 100644 --- a/web_api/example.env +++ b/web_api/example.env @@ -9,3 +9,6 @@ STRIPE_PLAN_ID=plan_somePlanId STRIPE_ANNUAL_PLAN_ID=price_somePriceId STRIPE_WEBHOOK_SECRET=whsec_someWebhookSecret STRIPE_PUBLISHABLE_API_KEY=pk_test_someExampleStripeApiKey +# Bot username pattern for activity tracking (default: kodiak%[bot]) +# Use LIKE pattern for wildcards, e.g., "kodiak%[bot]" or exact match +KODIAK_BOT_USERNAME_PATTERN=kodiak%[bot] diff --git a/web_api/web_api/models.py b/web_api/web_api/models.py index c77c321ff..c55b882b9 100644 --- a/web_api/web_api/models.py +++ b/web_api/web_api/models.py @@ -653,7 +653,7 @@ def generate_activity_data( (payload -> 'installation' ->> 'id')::integer github_installation_id, sum( CASE WHEN (event_name = 'pull_request' - AND payload -> 'sender' ->> 'login' LIKE 'kodiak%[bot]' + AND payload -> 'sender' ->> 'login' LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}' AND payload ->> 'action' = 'synchronize') THEN 1 ELSE @@ -661,7 +661,7 @@ def generate_activity_data( END) kodiak_updated, sum( CASE WHEN (event_name = 'pull_request' - AND payload -> 'sender' ->> 'login' LIKE 'kodiak%[bot]' + AND payload -> 'sender' ->> 'login' LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}' AND payload ->> 'action' = 'closed' AND payload -> 'pull_request' -> 'merged' = to_jsonb (TRUE)) THEN 1 @@ -670,7 +670,7 @@ def generate_activity_data( END) kodiak_merged, sum( CASE WHEN (event_name = 'pull_request_review' - AND payload -> 'sender' ->> 'login' LIKE 'kodiak%[bot]') THEN + AND payload -> 'sender' ->> 'login' LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}') THEN 1 ELSE 0 @@ -787,7 +787,7 @@ class Meta: def get_active_users_in_last_30_days(account: Account) -> List[ActiveUser]: with connection.cursor() as cursor: cursor.execute( - """ + f""" SELECT max(a.github_user_login) github_user_login, a.github_user_id, @@ -800,7 +800,7 @@ def get_active_users_in_last_30_days(account: Account) -> List[ActiveUser]: AND a.github_repository_name = b.github_repository_name AND a.github_pull_request_number = b.github_pull_request_number WHERE - b.github_user_login LIKE 'kodiak%%[bot]' + b.github_user_login LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}' AND a.github_user_login NOT LIKE '%%[bot]' -- We only consider users that open pull requests. -- For table b we look at all pull request events for Kodiak to diff --git a/web_api/web_api/settings.py b/web_api/web_api/settings.py index 811ef6b91..1842d5a26 100644 --- a/web_api/web_api/settings.py +++ b/web_api/web_api/settings.py @@ -120,3 +120,6 @@ STRIPE_ANNUAL_PLAN_ID = os.environ["STRIPE_ANNUAL_PLAN_ID"] STRIPE_WEBHOOK_SECRET = os.environ["STRIPE_WEBHOOK_SECRET"] STRIPE_PUBLISHABLE_API_KEY = os.environ["STRIPE_PUBLISHABLE_API_KEY"] + +# Bot username pattern for activity tracking (default: kodiak%[bot]) +KODIAK_BOT_USERNAME_PATTERN = os.environ.get("KODIAK_BOT_USERNAME_PATTERN", "kodiak%[bot]") From 8f240ce398bde287829d1f56a1b8e88ff071d2cb Mon Sep 17 00:00:00 2001 From: "artem.kravchenko" Date: Fri, 5 Dec 2025 02:40:36 +0100 Subject: [PATCH 2/2] web api: escaping % for query f-strings --- web_api/web_api/models.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/web_api/web_api/models.py b/web_api/web_api/models.py index c55b882b9..4f40be9d4 100644 --- a/web_api/web_api/models.py +++ b/web_api/web_api/models.py @@ -26,6 +26,9 @@ # to write a check constraint on the length of a text field. models.TextField.register_lookup(models.functions.Length) +# Escape % for Python f-string formatting (so it becomes literal % in SQL LIKE wildcard) +_BOT_USERNAME_PATTERN = settings.KODIAK_BOT_USERNAME_PATTERN.replace("%", "%%") + def sane_repr(*attrs: str) -> Callable[[object], str]: """ @@ -653,7 +656,7 @@ def generate_activity_data( (payload -> 'installation' ->> 'id')::integer github_installation_id, sum( CASE WHEN (event_name = 'pull_request' - AND payload -> 'sender' ->> 'login' LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}' + AND payload -> 'sender' ->> 'login' LIKE '{_BOT_USERNAME_PATTERN}' AND payload ->> 'action' = 'synchronize') THEN 1 ELSE @@ -661,7 +664,7 @@ def generate_activity_data( END) kodiak_updated, sum( CASE WHEN (event_name = 'pull_request' - AND payload -> 'sender' ->> 'login' LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}' + AND payload -> 'sender' ->> 'login' LIKE '{_BOT_USERNAME_PATTERN}' AND payload ->> 'action' = 'closed' AND payload -> 'pull_request' -> 'merged' = to_jsonb (TRUE)) THEN 1 @@ -670,7 +673,7 @@ def generate_activity_data( END) kodiak_merged, sum( CASE WHEN (event_name = 'pull_request_review' - AND payload -> 'sender' ->> 'login' LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}') THEN + AND payload -> 'sender' ->> 'login' LIKE '{_BOT_USERNAME_PATTERN}') THEN 1 ELSE 0 @@ -800,7 +803,7 @@ def get_active_users_in_last_30_days(account: Account) -> List[ActiveUser]: AND a.github_repository_name = b.github_repository_name AND a.github_pull_request_number = b.github_pull_request_number WHERE - b.github_user_login LIKE '{settings.KODIAK_BOT_USERNAME_PATTERN}' + b.github_user_login LIKE '{_BOT_USERNAME_PATTERN}' AND a.github_user_login NOT LIKE '%%[bot]' -- We only consider users that open pull requests. -- For table b we look at all pull request events for Kodiak to