Skip to content

refactor(review): extract the null-disables-label idiom into one helper (#4618) - #4756

Merged
JSONbored merged 1 commit into
mainfrom
chore/4618-label-idiom-dry-refactor
Jul 10, 2026
Merged

refactor(review): extract the null-disables-label idiom into one helper (#4618)#4756
JSONbored merged 1 commit into
mainfrom
chore/4618-label-idiom-dry-refactor

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

Scoped-down slice of #4618 item 3, per discussion: the full type/DB/YAML collapse of the 13 label fields into one labels map is deliberately deferred (see below) as a separate, higher-risk follow-up. This PR ships the safe, zero-behavior-change half.

9 of the 13 near-identical per-repo "close/hold with this label" settings (blacklistLabel, contributorCapLabel, reviewNagLabel, reviewEvasionLabel, manualReviewLabel, readyToMergeLabel, changesRequestedLabel, migrationCollisionLabel, pendingClosureLabel) share the exact same "explicit null disables the label, undefined uses the operator-facing default" resolution idiom — copy-pasted independently 9 times across settings/agent-actions.ts and queue/processors.ts rather than routed through a shared function.

  • Adds resolveNullableLabel(configured, fallback) and replaces every call site with it.
  • Pure mechanical refactor — zero behavior change, confirmed by the full existing test suite (which already exercised the null/undefined/explicit-string cases for each field) passing unchanged.

Why the full collapse is deferred

Researched the complete footprint before deciding scope: the 13 fields are not type-uniform (3 different nullability shapes — gittensorLabel is a bare required string; newAccountLabel/moderationWarningLabel/moderationBannedLabel are string | undefined with no null-disable semantics; the other 9 are string | null | undefined). Only 6 of 13 have DB columns with a SQL default, 2 have nullable columns with no default, and 5 are config-as-code-only with no DB column at all. Critically, all 13 are live top-level .gittensory.yml keys today — a real collapse to a nested labels: map would break every self-hoster's existing config file unless a backward-compat parsing shim is added, on top of a data migration across 8 differently-shaped columns. That's correctly scoped as its own follow-up, matching the issue's own "expect multiple PRs" framing — not something to rush alongside 3 other PRs in one sitting given these labels gate real moderation/ban/close actions.

Test plan

  • npx tsc --noEmit — clean
  • Full unit + integration suite: 687 files / 13,683 tests passing (unchanged pass count — confirms zero behavior change)
  • npm audit --audit-level=moderate — 0 vulnerabilities
  • No engine-parity twin exists for agent-actions.ts — nothing to mirror

…er (#4618)

9 of the 13 near-identical per-repo "close/hold with this label" settings
(blacklistLabel, contributorCapLabel, reviewNagLabel, reviewEvasionLabel,
manualReviewLabel, readyToMergeLabel, changesRequestedLabel,
migrationCollisionLabel, pendingClosureLabel) share the exact same
"explicit null disables the label, undefined uses the operator-facing
default" resolution idiom -- copy-pasted independently 9 times across
settings/agent-actions.ts and queue/processors.ts rather than routed
through a shared function.

Adds resolveNullableLabel(configured, fallback) and replaces every
call site with it. Pure mechanical DRY refactor -- zero behavior
change, confirmed by the full existing test suite (which already
exercised the null/undefined/explicit-string cases for each field)
passing unchanged.

This addresses the duplication half of #4618 item 3. The other half --
collapsing the 13 fields' TYPE surface, DB columns, and yml keys into
one labels map -- is deliberately deferred: the fields are not
type-uniform (3 different nullability shapes), only 6 of 13 have DB
columns with a default, 2 have nullable columns with no default, 5 are
config-as-code-only with no DB column at all, and the 13 keys are live
top-level `.gittensory.yml` keys today, so a real collapse needs a
backward-compat parsing shim and a data migration across 8 differently-
shaped columns -- correctly scoped as its own follow-up per the issue's
own "expect multiple PRs" framing.
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@JSONbored JSONbored self-assigned this Jul 10, 2026
@JSONbored JSONbored linked an issue Jul 10, 2026 that may be closed by this pull request
4 tasks
@JSONbored
JSONbored merged commit bb64b4e into main Jul 10, 2026
7 checks passed
@JSONbored
JSONbored deleted the chore/4618-label-idiom-dry-refactor branch July 10, 2026 23:36
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.22%. Comparing base (3ae7ece) to head (42b9f4d).
⚠️ Report is 6 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4756      +/-   ##
==========================================
- Coverage   94.22%   94.22%   -0.01%     
==========================================
  Files         441      441              
  Lines       38741    38737       -4     
  Branches    14117    14107      -10     
==========================================
- Hits        36504    36500       -4     
  Misses       1577     1577              
  Partials      660      660              
Files with missing lines Coverage Δ
src/queue/processors.ts 95.70% <100.00%> (ø)
src/settings/agent-actions.ts 97.72% <100.00%> (-0.05%) ⬇️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

Reduce redundant config surface: linked-issue knob, gateCheckMode, label fields

1 participant