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..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 'kodiak%[bot]' + 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 'kodiak%[bot]' + 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 'kodiak%[bot]') THEN + AND payload -> 'sender' ->> 'login' LIKE '{_BOT_USERNAME_PATTERN}') THEN 1 ELSE 0 @@ -787,7 +790,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 +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 'kodiak%%[bot]' + 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 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]")