Skip to content

fix(rulesets): resolve {{EXTERNALLY_DEFINED}} before diffing so unchanged rulesets don't plan updates#1023

Open
tdabasinskas wants to merge 1 commit into
github-community-projects:main-enterprisefrom
datolabs-io:fix/rulesets-externally-defined-diff
Open

fix(rulesets): resolve {{EXTERNALLY_DEFINED}} before diffing so unchanged rulesets don't plan updates#1023
tdabasinskas wants to merge 1 commit into
github-community-projects:main-enterprisefrom
datolabs-io:fix/rulesets-externally-defined-diff

Conversation

@tdabasinskas

Copy link
Copy Markdown

Fixes #1022.

Diffable.sync() now gives plugins an optional resolveOverrides(existingRecords, filteredEntries) hook, called after find() and before the comparison. The rulesets plugin implements it: each config entry is matched to its live record (by the existing comparator) and passed through Overrides.removeOverrides, so {{EXTERNALLY_DEFINED}} placeholders are replaced by the live values before changed() ever sees them. This mirrors how the branches plugin already resolves overrides inside its compareDeep call.

Behavior change, intentionally: a ruleset whose only difference from GitHub is the placeholder no longer reports "Update Ruleset" in dry runs, and no longer issues a redundant PUT in apply mode. Rulesets with real differences behave exactly as before — resolution happens against the same live record that update() would have used, so the applied values are identical. The hook is opt-in per plugin; no other diffable plugin changes behavior.

The entries are cloned before resolution (removeOverrides mutates its input) so the loaded config is never modified.

When rulesets use {{EXTERNALLY_DEFINED}} placeholders in required_status_checks, the diff comparison was seeing the literal placeholder string instead of the resolved values from GitHub. This caused every sync to report an update even when the actual status checks matched.

Introduce a resolveOverrides hook in the diffable plugin that allows plugins to resolve config placeholders against live records before comparison. The rulesets plugin now implements this to resolve {{EXTERNALLY_DEFINED}} against matching GitHub rulesets, mirroring how branches.js handles overrides.

This ensures placeholders never report spurious changes when the underlying values are identical.
Copilot AI review requested due to automatic review settings July 11, 2026 10:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes repeated phantom “Update Ruleset” plans/PUTs when a ruleset config uses {{EXTERNALLY_DEFINED}} by resolving placeholders against the live ruleset before diffing, so placeholder-only differences no longer count as changes.

Changes:

  • Adds an opt-in resolveOverrides(existingRecords, filteredEntries) hook to Diffable.sync() so plugins can normalize config entries against live records prior to comparison.
  • Implements resolveOverrides in the rulesets plugin to replace {{EXTERNALLY_DEFINED}} with live GitHub values via Overrides.removeOverrides(...) (using a clone to avoid mutating loaded config).
  • Updates and extends unit tests to assert that placeholder-only rulesets no longer plan/apply updates (including in nop mode).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
lib/plugins/diffable.js Introduces the optional pre-diff resolveOverrides hook in the shared sync flow.
lib/plugins/rulesets.js Resolves {{EXTERNALLY_DEFINED}} against the matching live ruleset before calling changed().
test/unit/lib/plugins/rulesets.test.js Adjusts expectations and adds coverage for “no-op” behavior when only placeholders differ (including nop mode).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rulesets using {{EXTERNALLY_DEFINED}} report "Update Ruleset" in every dry run

2 participants