Skip to content

fix: preserve .vscode/settings.json and script +x bit on integration upgrade#3020

Merged
mnriem merged 2 commits into
mainfrom
benbtg/fix-integration-upgrade-preserve-setting
Jun 17, 2026
Merged

fix: preserve .vscode/settings.json and script +x bit on integration upgrade#3020
mnriem merged 2 commits into
mainfrom
benbtg/fix-integration-upgrade-preserve-setting

Conversation

@BenBtg

@BenBtg BenBtg commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

The bug

During specify integration upgrade, Phase 2 stale-cleanup deletes files that were recorded in the prior manifest but are absent from the new one. The Copilot integration's setup() merges into .vscode/settings.json when it already exists and intentionally stops tracking it in the manifest. As a result, on upgrade that file was treated as stale and deleted — destroying the user's VS Code settings.

Separately, shared .sh scripts could lose their executable (+x) bit during the managed-refresh step.

The fix

  • Add a stale_cleanup_exclusions() hook on IntegrationBase (returns an empty set by default) so integrations can protect conditionally-tracked merge targets from stale-cleanup.
  • Override it in the Copilot integration to protect .vscode/settings.json.
  • Use the hook during the integration upgrade stale-cleanup in _migrate_commands.py, and restore the executable bit on shared .sh scripts after the managed-refresh step (POSIX only).

Regression tests

Two new tests in tests/integrations/test_integration_subcommand.py:

  • test_upgrade_preserves_existing_vscode_settings — verifies an existing .vscode/settings.json survives an upgrade.
  • test_upgrade_restores_executable_bit_on_shared_scripts — verifies shared .sh scripts keep their +x bit after upgrade.

Full tests/integrations suite passes (2382 passed, 1 skipped).

Notes

Split out of #3001 to keep that PR scoped to the /speckit.converge command.


🤖 Authored with GitHub Copilot on behalf of @BenBtg, who reviewed the change.

…upgrade

During 'specify integration upgrade', Phase 2 stale-cleanup removes files
present in the old manifest but absent from the new one. Copilot's setup()
merges into an existing .vscode/settings.json and stops tracking it, so the
file was being deleted on upgrade (destroying user settings). Add a
stale_cleanup_exclusions() hook that integrations use to protect such
conditionally-tracked merge targets. Also restore the executable bit on
shared .sh scripts after the managed-refresh step on POSIX.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 17, 2026 14:40
@BenBtg BenBtg mentioned this pull request Jun 17, 2026
2 tasks

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

Fixes two upgrade regressions in specify integration upgrade: (1) preventing stale-cleanup from deleting conditionally-untracked merge targets like .vscode/settings.json (Copilot), and (2) ensuring shared POSIX .sh scripts retain executable permissions after a managed refresh.

Changes:

  • Add IntegrationBase.stale_cleanup_exclusions() hook (default empty) so integrations can protect specific project-relative paths from Phase 2 stale cleanup.
  • Implement Copilot’s override to exclude .vscode/settings.json from stale deletion.
  • During integration upgrade, re-apply executable bits to shared .sh scripts on POSIX after the managed-refresh step; add regression tests for both issues.
Show a summary per file
File Description
src/specify_cli/integrations/base.py Adds the stale_cleanup_exclusions() hook to the integration base class.
src/specify_cli/integrations/copilot/__init__.py Excludes .vscode/settings.json from upgrade stale cleanup for Copilot.
src/specify_cli/integrations/_migrate_commands.py Applies exclusions during stale cleanup and restores +x after managed shared-infra refresh (POSIX).
tests/integrations/test_integration_subcommand.py Adds regression tests for settings preservation and script execute-bit restoration.

Copilot's findings

Tip

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

  • Files reviewed: 4/4 changed files
  • Comments generated: 0

@BenBtg BenBtg marked this pull request as ready for review June 17, 2026 17:23
@BenBtg BenBtg requested a review from mnriem as a code owner June 17, 2026 17:23
@BenBtg BenBtg self-assigned this Jun 17, 2026
@BenBtg BenBtg requested a review from Copilot June 17, 2026 17:25

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.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 2

Comment thread tests/integrations/test_integration_subcommand.py Outdated
Comment thread src/specify_cli/integrations/_migrate_commands.py Outdated

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address Copilot feedback

- Normalize stale_cleanup_exclusions() to POSIX before subtracting from
  manifest keys, so exclusions built with os.path.join / backslashes still
  match on Windows.
- Strengthen test_upgrade_preserves_existing_vscode_settings to add a
  user-defined key and assert it survives the upgrade (via --force, exercising
  the merge + stale-cleanup path) instead of the brittle after == before check.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@BenBtg

BenBtg commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review — both points addressed in 255cb8c.

POSIX normalization (_migrate_commands.py): stale_cleanup_exclusions() results are now normalized with PurePath(...).as_posix() before being subtracted from the manifest keys, so exclusions built with os.path.join/backslashes still match on Windows.

Brittle test assertion (test_upgrade_preserves_existing_vscode_settings): the test now writes a user-defined key (editor.fontSize) into .vscode/settings.json before upgrading and asserts it survives, instead of after == before. It runs the upgrade with --force so the modified-file guard is bypassed and the real merge + stale-cleanup path is exercised — which is exactly what the exclusion hook protects.

Full tests/integrations suite: 2382 passed, 1 skipped.

Posted on behalf of @BenBtg by GitHub Copilot (model: Claude Opus 4.8), reviewed by @BenBtg.

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.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new

@mnriem mnriem self-requested a review June 17, 2026 19:21
@mnriem mnriem merged commit 84db931 into main Jun 17, 2026
13 checks passed
@mnriem

mnriem commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

@mnriem mnriem deleted the benbtg/fix-integration-upgrade-preserve-setting branch June 17, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants