Skip to content

feat(cli): implement specify self upgrade#2475

Open
chordpli wants to merge 28 commits intogithub:mainfrom
chordpli:002-self-upgrade-apply
Open

feat(cli): implement specify self upgrade#2475
chordpli wants to merge 28 commits intogithub:mainfrom
chordpli:002-self-upgrade-apply

Conversation

@chordpli
Copy link
Copy Markdown
Contributor

@chordpli chordpli commented May 7, 2026

Summary

Replace the v0.7.5 reserved stub from #2316 with an actually working specify self upgrade command. Closes the unresolved portion of #2282.

The CLI classifies the runtime via a 3-tier detection ladder, runs the appropriate installer subprocess, and verifies the result by spawning a fresh specify --version in a child process (the in-process module is still the pre-upgrade build).

Behavior

  • Bare specify self upgrade — executes immediately. No confirmation prompt. Matches the pip install -U / uv tool upgrade / npm update convention.
  • --dry-run — on upgradable paths (uv tool, pipx) prints the preview block (method / current / target / installer argv) and exits 0 without launching any subprocess. On non-upgradable paths (uvx (ephemeral) / source checkout / unsupported) emits the same path-specific guidance as a non-dry-run invocation and exits 0.
  • --tag vX.Y.Z[suffix] — pins a specific release tag. Validated against ^v\d+\.\d+\.\d+(?:[a-z0-9.+\-]*)?$; rejects bare latest, branch names, hash refs.
  • Detectionuv tool / pipx (auto-upgrade), uvx (ephemeral) / source-checkout / unsupported (path-specific guidance + exit 0, no installer launched).
  • Token hygieneGH_TOKEN / GITHUB_TOKEN scrubbed from child-process environments; never appears in installer argv.

Exit codes

Code Meaning
0 Success, no-op-success (already on latest, --dry-run, or non-upgradable path with guidance)
1 Target-tag resolution failure or --tag regex validation failure
2 Verification mismatch (installer exited 0 but child specify --version does not resolve to target)
3 Installer binary not found on PATH
124 Installer subprocess timed out (only when SPECIFY_UPGRADE_TIMEOUT_SECS is set)
other Installer exit code propagated verbatim

Files changed

  • src/specify_cli/__init__.py — Phase 2 helpers (_InstallMethod, _UpgradePlan, _detect_install_method, _assemble_installer_argv, _build_upgrade_plan, _run_installer, _verify_upgrade, _emit_guidance, _emit_failure, _validate_tag, _scrubbed_env, …) + replaced self_upgrade() orchestrator body. Also refreshes the now-stale self group help and self_check() docstring so specify self --help / specify self check --help reflect the current behavior.
  • tests/test_self_upgrade.py (new) — 44 test cases across 23 classes covering detection, argv assembly, dry-run, tag validation, token scrubbing, verification flows.
  • tests/test_upgrade.py — removed TestSelfUpgradeStub (the stub it pinned no longer exists).
  • README.mdGet Started → Install Specify CLI → Option 1 now leads with specify self upgrade as the recommended path; manual --force retained as fallback.
  • docs/upgrade.md — Quick Reference table, Part 1, Verify, Common Scenarios, and Troubleshooting all updated.
  • docs/installation.md — Verification section gets a "Stay current" pointer.

Test plan

  • uvx ruff check src/ — clean
  • uv sync --extra test + uv run pytest — 2828 passed, 34 skipped on Python 3.11 / 3.12 / 3.13
  • tests/test_self_upgrade.py + tests/test_upgrade.py — 88 passed combined
  • Manual smoke (uv-tool installed working tree):
    • specify self upgrade --dry-run → preview, target=v0.8.6 (auto-resolved)
    • specify self upgrade --dry-run --tag v0.8.0+build.42 → build-metadata tag accepted
    • specify self upgrade --dry-run --tag latestBadParameter (regex rejection)
  • End-to-end automatic upgrade (separate session) — pipx-installed 0.7.6.dev0 → 0.8.1 succeeded

Notes for reviewers

  • Bare invocation executes immediately (clarification Q1 → C1; matches pip install -U / uv tool upgrade / npm update).
  • Phase 1's _fetch_latest_release_tag() (added in feat(cli): add specify self check and self upgrade stub #2316) is reused unchanged. No new GitHub HTTP code.
  • All Phase 2 imports are stdlib (re, dataclasses, enum, urllib.parse); PEP 723 deps unchanged.
  • All Phase 2 symbols are _-prefixed; no new public API surface.
Design and ripple review context

This change was developed through the full speckit workflow:
specify -> plan -> tasks -> blueprint -> implement -> ripple-scan -> ripple-resolve.

Design artifacts (spec, plan, blueprint, ripple-report) were kept in specs/002-self-upgrade-apply/ during development and are not part of this PR.

Ripple review surfaced 9 findings. Each was triaged as either resolved in-branch or accepted risk with explicit rationale.

@chordpli chordpli requested a review from mnriem as a code owner May 7, 2026 05:12
Copilot AI review requested due to automatic review settings May 7, 2026 06:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a functional specify self upgrade command to replace the previous reserved stub, enabling in-place upgrades (uv tool / pipx) with install-method detection, dry-run previews, tag pinning, token scrubbing, and post-upgrade verification via a child specify --version.

Changes:

  • Adds install-method detection + upgrade orchestration helpers and replaces the self upgrade stub with a working implementation.
  • Introduces a comprehensive new test suite for specify self upgrade and removes the old stub-pin tests.
  • Updates README and docs to recommend specify self upgrade and document the new flows.

Reviewed changes

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

Show a summary per file
File Description
src/specify_cli/__init__.py Adds self-upgrade planning/execution/verification logic and updates self command help text.
tests/test_self_upgrade.py New test module covering detection, argv assembly, dry-run behavior, tag validation, token scrubbing, and verification.
tests/test_upgrade.py Removes tests that pinned the previous non-functional stub output.
README.md Documents specify self check / specify self upgrade as the preferred upgrade path.
docs/upgrade.md Refreshes upgrade guide to include self-upgrade commands, verification steps, and troubleshooting.
docs/installation.md Adds “Stay current” pointer to specify self check and upgrade guide.

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

Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py
Comment thread tests/test_self_upgrade.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/specify_cli/__init__.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py
Comment thread tests/test_self_upgrade.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread src/specify_cli/__init__.py
Comment thread src/specify_cli/__init__.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/specify_cli/__init__.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

@chordpli chordpli requested a review from mnriem May 8, 2026 00:41
@chordpli
Copy link
Copy Markdown
Contributor Author

chordpli commented May 8, 2026

@mnriem I’ve addressed the Copilot review feedback, rebased onto the latest main, and re-ran the self-upgrade tests. Could you please take another look?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

Comments suppressed due to low confidence (1)

docs/upgrade.md:40

  • In the recommended command block, specify self upgrade --tag vX.Y.Z is shown without indicating it’s a placeholder; the implementation rejects that literal value via --tag validation. Consider adding “replace vX.Y.Z …” or using a real tag so the snippet is copy/paste-safe.
# Upgrade in place to the latest stable release (auto-detects uv tool vs pipx install)
specify self upgrade

# Or pin a specific release tag
specify self upgrade --tag vX.Y.Z
</details>


- **Files reviewed:** 6/6 changed files
- **Comments generated:** 3

Comment thread src/specify_cli/__init__.py
Comment thread README.md
Comment thread docs/upgrade.md
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/specify_cli/__init__.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread README.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

@chordpli
Copy link
Copy Markdown
Contributor Author

chordpli commented May 8, 2026

@mnriem I’ve addressed the latest review feedback and pushed the follow-up fixes. Could you please take another look when you have a moment?

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.

3 participants