From 335122a99a002b6775b505ccdaf59c753f8ff3d1 Mon Sep 17 00:00:00 2001 From: Dimitris Kargatzis Date: Fri, 27 Feb 2026 21:51:48 +0200 Subject: [PATCH 1/5] feat: ignore disabled rules during loading from GitHub rules.yaml --- src/rules/loaders/github_loader.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rules/loaders/github_loader.py b/src/rules/loaders/github_loader.py index 6568f7a..58fc673 100644 --- a/src/rules/loaders/github_loader.py +++ b/src/rules/loaders/github_loader.py @@ -59,6 +59,12 @@ async def get_rules(self, repository: str, installation_id: int) -> list[Rule]: try: if not isinstance(rule_data, dict): continue + + # Skip disabled rules + if str(rule_data.get("enabled", True)).lower() == "false": + logger.info(f"Skipping disabled rule: {rule_data.get('description', 'unknown')}") + continue + rule = GitHubRuleLoader._parse_rule(rule_data) if rule: rules.append(rule) From 871a066eb847b8ae1573d6c253c6c8ac115cf888 Mon Sep 17 00:00:00 2001 From: Dimitris Kargatzis Date: Fri, 27 Feb 2026 21:56:13 +0200 Subject: [PATCH 2/5] docs: remove legacy rule ID references from generated PR comments and error messages --- src/integrations/github/rules_service.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/integrations/github/rules_service.py b/src/integrations/github/rules_service.py index 436324d..84528c1 100644 --- a/src/integrations/github/rules_service.py +++ b/src/integrations/github/rules_service.py @@ -38,7 +38,7 @@ async def _validate_rules_yaml(repo: str, installation_id: int) -> dict[str, Any "**How to set up rules:**\n" "1. Create a file at `.watchflow/rules.yaml` in your repository root\n" "2. Add your rules in the following format:\n" - " ```yaml\n rules:\n - id: pr-approval-required\n name: PR Approval Required\n description: All pull requests must have at least 2 approvals\n enabled: true\n severity: high\n event_types: [pull_request]\n parameters:\n min_approvals: 2\n ```\n\n" + " ```yaml\n rules:\n - description: All pull requests must have at least 2 approvals\n enabled: true\n severity: high\n event_types: [pull_request]\n parameters:\n min_approvals: 2\n ```\n\n" "**Note:** Rules are currently read from the main branch only.\n\n" "📖 [Read the documentation for more examples](https://github.com/warestack/watchflow/blob/main/docs/getting-started/configuration.md)\n\n" "After adding the file, push your changes to re-run validation." @@ -64,7 +64,7 @@ async def _validate_rules_yaml(repo: str, installation_id: int) -> dict[str, Any "message": ( "❌ **Invalid `.watchflow/rules.yaml`: missing top-level `rules:` key**\n\n" "Your file must start with a `rules:` key, like:\n" - "```yaml\nrules:\n - id: ...\n```\n" + "```yaml\nrules:\n - description: ...\n```\n" f"[See configuration docs.]({DOCS_URL})" ), } @@ -74,7 +74,7 @@ async def _validate_rules_yaml(repo: str, installation_id: int) -> dict[str, Any "message": ( "❌ **Invalid `.watchflow/rules.yaml`: `rules` must be a list**\n\n" "Example:\n" - "```yaml\nrules:\n - id: my-rule\n description: ...\n```\n" + "```yaml\nrules:\n - description: my-rule\n```\n" f"[See configuration docs.]({DOCS_URL})" ), } @@ -94,7 +94,7 @@ async def _validate_rules_yaml(repo: str, installation_id: int) -> dict[str, Any return { "success": False, "message": ( - f"❌ **Rule #{i + 1} (`{rule_data.get('id', 'N/A')}`) failed validation**\n\n" + f"❌ **Rule #{i + 1} (`{rule_data.get('description', 'N/A')}`) failed validation**\n\n" f"Error: `{e}`\n\n" "Please check your rule definition and fix the error above.\n\n" f"[See rule schema docs.]({DOCS_URL})" From 6091225c3bb5ab4bcaefc0d1d7f700c1e059ce62 Mon Sep 17 00:00:00 2001 From: Dimitris Kargatzis Date: Fri, 27 Feb 2026 21:58:03 +0200 Subject: [PATCH 3/5] style: fix trailing whitespace in github loader --- src/rules/loaders/github_loader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rules/loaders/github_loader.py b/src/rules/loaders/github_loader.py index 58fc673..27f19e4 100644 --- a/src/rules/loaders/github_loader.py +++ b/src/rules/loaders/github_loader.py @@ -59,12 +59,12 @@ async def get_rules(self, repository: str, installation_id: int) -> list[Rule]: try: if not isinstance(rule_data, dict): continue - + # Skip disabled rules if str(rule_data.get("enabled", True)).lower() == "false": logger.info(f"Skipping disabled rule: {rule_data.get('description', 'unknown')}") continue - + rule = GitHubRuleLoader._parse_rule(rule_data) if rule: rules.append(rule) From 4e30d5e8a5234cbdaaf5cd56332916fbfc2b8e95 Mon Sep 17 00:00:00 2001 From: Dimitris Kargatzis Date: Fri, 27 Feb 2026 22:24:06 +0200 Subject: [PATCH 4/5] ux: add watchflow footer to PR comments --- src/presentation/github_formatter.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/presentation/github_formatter.py b/src/presentation/github_formatter.py index e5ed98e..53ae2f6 100644 --- a/src/presentation/github_formatter.py +++ b/src/presentation/github_formatter.py @@ -206,7 +206,9 @@ def format_violations_comment(violations: list[Violation]) -> str: comment = f"### 🛡️ Watchflow Governance Checks\n**Status:** ❌ {len(violations)} Violations Found\n\n" comment += _build_collapsible_violations_text(violations) comment += "---\n" - comment += "💡 *Reply with `@watchflow ack [reason]` to override these rules, or `@watchflow help` for commands.*" + comment += "💡 *Reply with `@watchflow ack [reason]` to override these rules, or `@watchflow help` for commands.*\n\n" + comment += "Thanks for using [Watchflow](https://watchflow.dev)! It's completely free for OSS and private repositories. " + comment += "You can also [self-host it easily](https://github.com/warestack/watchflow)." return comment From 1800dcef675984e380d36f1f535beddfec8f7358 Mon Sep 17 00:00:00 2001 From: Dimitris Kargatzis Date: Fri, 27 Feb 2026 22:26:40 +0200 Subject: [PATCH 5/5] style: fix ruff line length pre-commit issues in github formatter --- src/presentation/github_formatter.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/presentation/github_formatter.py b/src/presentation/github_formatter.py index 53ae2f6..f2a6c00 100644 --- a/src/presentation/github_formatter.py +++ b/src/presentation/github_formatter.py @@ -206,8 +206,12 @@ def format_violations_comment(violations: list[Violation]) -> str: comment = f"### 🛡️ Watchflow Governance Checks\n**Status:** ❌ {len(violations)} Violations Found\n\n" comment += _build_collapsible_violations_text(violations) comment += "---\n" - comment += "💡 *Reply with `@watchflow ack [reason]` to override these rules, or `@watchflow help` for commands.*\n\n" - comment += "Thanks for using [Watchflow](https://watchflow.dev)! It's completely free for OSS and private repositories. " + comment += ( + "💡 *Reply with `@watchflow ack [reason]` to override these rules, or `@watchflow help` for commands.*\n\n" + ) + comment += ( + "Thanks for using [Watchflow](https://watchflow.dev)! It's completely free for OSS and private repositories. " + ) comment += "You can also [self-host it easily](https://github.com/warestack/watchflow)." return comment