Skip to content

fix: rename repos through their config file and never rename them back - #1136

Open
TovaBecker wants to merge 1 commit into
github-community-projects:main-enterprisefrom
TovaBecker:fix/rename-via-file
Open

TovaBecker wants to merge 1 commit into
github-community-projects:main-enterprisefrom
TovaBecker:fix/rename-via-file

Conversation

@TovaBecker

@TovaBecker TovaBecker commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Why

Approach

  • The push handler reads the net diff (compareCommitsWithBasehead). A renamed repo file renames the repo once, before anything else syncs. If the diff can't be read, the push is skipped with an error.
  • A repo that GitHub reaches through a redirect is skipped with a warning unless its config asks for the current name.
  • A rename that can't happen fails the check: the name is taken, the old name redirects elsewhere, the file still sets another repository.name, or one of the names is restricted. A rename never creates a repo.
  • The PR dry run shows the rename as a repository.name change with before and after values, together with every other change in the renamed file. It reads all PR files, not only the first 30. A taken name links to the repo that has it.
  • The README notes that GitHub matches renames by file similarity, so a small file with large edits shows up as removed plus added.

Validation

  • Unit tests: 1050 passed (1015 before). Integration tests: 107 passed. No new standard findings.
  • Tested manually with a local app: a rename, a stale file, a replayed merge, a full sync, BLOCK_REPO_RENAME_BY_HUMAN, a rename with other changes in the file, and the three error cases.

Closes #843
Closes #1123

🤖 Generated with Claude Code

Renaming repos/old.yml to repos/new.yml did not rename the repo (github-community-projects#843), and a removed or replayed config file followed GitHub's rename redirect and renamed the repo back (github-community-projects#1123). Renaming from the file keeps the config the source of truth, and the PR dry run now shows the rename, its errors, and every other change in the file before merge.
@TovaBecker
TovaBecker marked this pull request as ready for review November 10, 2026 14:36
Copilot AI balanced review requested due to automatic review settings November 10, 2026 14:36

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.

🟡 Changes recommended

Unresolved issues can apply settings to unrelated or renamed repositories, rename repositories back using stale identities, and bypass disabled repository management.

4 open issues
What changed in this PR

This PR adds config-file-driven repository renames and guards against stale names undoing renames during synchronization, addressing #843 and #1123.

Changes:

  • Detects renames from push comparisons and paginated PR file lists.
  • Adds rename validation, dry-run previews, and redirect checks before synchronization.
  • Adds regression coverage and documents GitHub’s file-similarity-based rename detection.
File Description
test/​unit/​lib/​settings.test.js Tests app-installation deltas against the previous config path.
test/​unit/​lib/​settings-rename.test.js Covers renames, rejected operations, previews, and stale redirects.
test/​unit/​index-rename.test.js Tests push comparisons, rename detection, and PR pagination.
test/​integration/​plugins/​repository.test.js Aligns repository mocks with live-name checks.
test/​integration/​plugins/​milestones.test.js Aligns milestone test mocks with live-name checks.
README.md Explains rename-detection limitations and dry-run verification.
lib/​settings.js Coordinates renames, config mapping, and redirect protection.
index.js Uses push comparisons and paginated PR files to identify changes.

Review effort: Balanced

Comment thread lib/settings.js
Comment on lines +680 to +682
const changedRepos = await settings.renameReposFromConfigFiles(changedFiles.repos)
await settings.loadConfigs()
for (const { repo, configName } of changedRepos) await settings.useConfigOfRenamedFile(repo, configName)
Comment thread lib/settings.js
shouldUnarchive = state.shouldUnarchive
}

if (this.isRenamedAway(repo, repoConfig, archivePlugin.repository)) {
Comment thread lib/settings.js
Comment on lines +2201 to 2204
if (this.isRenamedAway(repo, null, archivePlugin.repository)) {
return
}
}
Comment thread lib/settings.js
Comment on lines +2384 to +2385
const params = { owner: repo.owner, repo: renamedFrom, name: repo.repo }
if (this.nop) {
@lhoupert

Copy link
Copy Markdown

One case still renames the repo back with this PR: a full sync with archive in disable_plugins. isRenamedAway uses the repo the archive plugin fetched; with that plugin disabled nothing fetches it, the check passes, and the repository plugin sends name: old-name.

#1142 is a smaller fix for #1123 only. It runs the same check inside the repository plugin, right after its own repos.get, so it does not depend on another plugin and adds no request. It leaves the rename-by-file feature to this PR; the guard could equally be taken in here instead.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

3 participants