From 6b4b77723cebf5ccbd29583ea6f35b5a618d494d Mon Sep 17 00:00:00 2001 From: Amy Blais <29708087+amyblais@users.noreply.github.com> Date: Tue, 14 Jul 2026 13:04:40 +0300 Subject: [PATCH] Update config change checker script and workflow (#37226) * Update config change checker script and workflow Co-Authored-By: Claude Sonnet 4.6 * Update check_config_changes_ci.py --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Mattermost Build --- .github/scripts/check_config_changes_ci.py | 46 +++++++++++---------- .github/workflows/config-change-checker.yml | 16 +++---- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/.github/scripts/check_config_changes_ci.py b/.github/scripts/check_config_changes_ci.py index ad3f3ce3e15..8d96781c8cb 100644 --- a/.github/scripts/check_config_changes_ci.py +++ b/.github/scripts/check_config_changes_ci.py @@ -127,11 +127,11 @@ def file_at(ref: str, path: str) -> str: ).stdout except subprocess.CalledProcessError: return "" - - + + def _compute_merge_base() -> str: """Resolve the merge-base of BASE_SHA and HEAD_SHA. - + Per-checker comparisons must use this rather than BASE_SHA. BASE_SHA is the tip of the target branch at PR-event time; if that branch advances on a watched file after the PR diverges, comparing branch-tip vs target-tip @@ -143,8 +143,8 @@ def _compute_merge_base() -> str: ["git", "merge-base", BASE_SHA, HEAD_SHA], capture_output=True, text=True, check=True, ).stdout.strip() - - + + MERGE_BASE = _compute_merge_base() @@ -182,8 +182,11 @@ def _scan_struct_fields(src: str) -> set[tuple[str, str]]: while struct_stack and depth <= struct_stack[-1][1]: struct_stack.pop() - # Record fields only when we're directly inside exactly one named struct - if len(struct_stack) == 1: + # Record fields only when we're directly inside the named struct body. + # The depth check (depth == struct_stack[0][1] + 1) ensures that fields + # inside nested anonymous struct { ... } blocks are not incorrectly + # attributed to the outer named struct. + if len(struct_stack) == 1 and depth == struct_stack[0][1] + 1: fm = _FIELD_LINE_RE.match(line) if fm: fields.add((struct_stack[0][0], fm.group(1))) @@ -195,7 +198,7 @@ def check_config(patches: dict[str, str]) -> CheckResult: """ Detect exported Go struct field additions/removals in config.go. - Compares full-file snapshots at BASE_SHA and HEAD_SHA so that fields + Compares full-file snapshots at MERGE_BASE and HEAD_SHA so that fields are always attributed to the correct struct regardless of which diff hunks are present. """ @@ -209,8 +212,8 @@ def check_config(patches: dict[str, str]) -> CheckResult: added = head_fields - base_fields removed = base_fields - head_fields - result.additions = sorted(f"`{s}.{f}`" for s, f in added) - result.removals = sorted(f"`{s}.{f}`" for s, f in removed) + result.additions = sorted(f"``{s}.{f}``" for s, f in added) + result.removals = sorted(f"``{s}.{f}``" for s, f in removed) return result @@ -273,7 +276,7 @@ def check_api(patches: dict[str, str]) -> CheckResult: """ Detect API endpoint additions/removals in the api4/ directory. - Compares full-file snapshots at BASE_SHA and HEAD_SHA via set arithmetic, + Compares full-file snapshots at MERGE_BASE and HEAD_SHA via set arithmetic, so multi-line and multi-method registrations are handled correctly. """ result = CheckResult(label="API Changes (`api4`)") @@ -320,7 +323,7 @@ def check_audit_events(patches: dict[str, str]) -> CheckResult: """ Detect AuditEvent* constant additions/removals. - Uses full-file snapshots at BASE_SHA/HEAD_SHA so reorderings and + Uses full-file snapshots at MERGE_BASE/HEAD_SHA so reorderings and cross-constant name collisions don't produce false results. """ result = CheckResult(label="Audit Log Event Changes") @@ -330,8 +333,8 @@ def check_audit_events(patches: dict[str, str]) -> CheckResult: base_events = _parse_audit_events(file_at(MERGE_BASE, _AUDIT_EVENT_PATH)) head_events = _parse_audit_events(file_at(HEAD_SHA, _AUDIT_EVENT_PATH)) - result.additions = sorted(f"`{e}`" for e in head_events - base_events) - result.removals = sorted(f"`{e}`" for e in base_events - head_events) + result.additions = sorted(f"``{e}``" for e in head_events - base_events) + result.removals = sorted(f"``{e}``" for e in base_events - head_events) return result @@ -366,9 +369,9 @@ def check_go_version(patches: dict[str, str]) -> CheckResult: new_ver = _parse_go_version(file_at(HEAD_SHA, _DOCKERFILE_PATH)) if old_ver and new_ver and old_ver != new_ver: - result.changes.append(f"Go updated: `{old_ver}` → `{new_ver}`") + result.changes.append(f"Go updated: ``{old_ver}`` → ``{new_ver}``") elif new_ver and not old_ver: - result.additions.append(f"`{new_ver}`") + result.additions.append(f"``{new_ver}``") return result @@ -376,10 +379,11 @@ def check_go_version(patches: dict[str, str]) -> CheckResult: # Matches lines that were auto-generated by this script so they can be stripped # before re-injecting a fresh set on subsequent commits. +# Handles both single-backtick (older runs) and double-backtick (current) format. _AUTO_LINE_RE = re.compile( - r"^(Added|Removed) `[^`]+`.*(configuration setting|API endpoint|audit log event)\." + r"^(Added|Removed) `{1,2}[^`]+`{1,2}.*(configuration setting|API endpoint|audit log event)\." r"|^Go runtime updated from \S+ to \S+\." - r"|^Go runtime set to `[^`]+`\." + r"|^Go runtime set to `{1,2}[^`]+`{1,2}\." r"|^🆕 New API file:" r"|^🗑️ Removed API file:" ) @@ -415,11 +419,11 @@ def _format_lines(result: CheckResult) -> list[str]: elif "Go Runtime" in result.label: for item in result.additions: - # item is e.g. "`1.22`" — strip backticks for the prose form + # item is e.g. "``1.22``" lines.append(f"Go runtime set to {item}.") for c in result.changes: - # c arrives as "Go updated: `1.21` → `1.22`" — rewrite it - m = re.search(r"`([^`]+)`\s*→\s*`([^`]+)`", c) + # c arrives as "Go updated: ``1.21`` → ``1.22``" — rewrite it + m = re.search(r"``([^`]+)``\s*→\s*``([^`]+)``", c) if m: lines.append(f"Go runtime updated from {m.group(1)} to {m.group(2)}.") else: diff --git a/.github/workflows/config-change-checker.yml b/.github/workflows/config-change-checker.yml index 7a816fde3bc..b166f1be6b7 100644 --- a/.github/workflows/config-change-checker.yml +++ b/.github/workflows/config-change-checker.yml @@ -11,9 +11,9 @@ # • server/build/Dockerfile.buildenv — Go runtime version changes # # No secrets needed — uses the built-in GITHUB_TOKEN. - + name: Config Change Checker - + on: pull_request: types: [opened, synchronize, reopened] @@ -22,7 +22,7 @@ on: - 'server/channels/api4/**' - 'server/public/model/audit_events.go' - 'server/build/Dockerfile.buildenv' - + # Cancel any in-progress run for the same PR when a new commit is pushed. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -38,11 +38,11 @@ jobs: # not touch these paths intentionally and cannot receive description updates # via GITHUB_TOKEN anyway (fork-like restrictions apply to most bots). if: github.event.pull_request.user.type != 'Bot' - + permissions: pull-requests: write # needed to update the PR description contents: read - + steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -50,15 +50,15 @@ jobs: persist-credentials: false # Fetch enough history to diff against the base branch fetch-depth: 0 - + - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: '3.11' - + - name: Install dependencies run: pip install requests==2.32.3 --quiet - + - name: Detect changes and update PR description env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}