Skip to content

feat(cli): add specify self check and self upgrade stub#2316

Merged
mnriem merged 7 commits intogithub:mainfrom
chordpli:feat/2282-upgrade-check
Apr 22, 2026
Merged

feat(cli): add specify self check and self upgrade stub#2316
mnriem merged 7 commits intogithub:mainfrom
chordpli:feat/2282-upgrade-check

Conversation

@chordpli
Copy link
Copy Markdown
Contributor

@chordpli chordpli commented Apr 22, 2026

Closes #2282.

Summary

This PR introduces a new specify self Typer sub-app, following the direction in the issue discussion.

  • specify self check performs a read-only lookup of the latest GitHub release, compares it with the installed specify-cli version, and prints either an update verdict or a graceful fallback message. When a newer release exists, it also prints a copy-pasteable uv tool install --force --from git+…@<tag> reinstall command.
  • specify self upgrade is introduced as a reserved, non-destructive stub in this release. It prints a fixed three-line guidance message and exits 0. Actual self-upgrade remains out of scope for this PR.

Design Notes

  • Uses GH_TOKEN / GITHUB_TOKEN automatically when present to avoid anonymous GitHub API rate limits.
  • Single outbound attempt, 5-second timeout, no retries, no caching, no install-method detection, and no machine-readable output mode in this release.
  • Failure vocabulary is intentionally small and fixed: offline or timeout, rate limited (try setting GH_TOKEN or GITHUB_TOKEN), and HTTP <code>.
  • Unexpected internal exceptions are not swallowed; they propagate so real bugs surface instead of being silently converted into user-facing success output.
  • Tests mock urllib.request.urlopen, so the feature test suite performs zero real network traffic.

Example output

specify self check — up to date
Up to date: 0.7.5.dev0
specify self check — newer release available (mocked example)
Update available: 0.7.4 → 0.9.0

To upgrade:
  uv tool install specify-cli --force \
    --from git+https://github.com/github/spec-kit.git@v0.9.0
specify self upgrade
specify self upgrade is not implemented yet.
Run 'specify self check' to see whether a newer release is available.
Actual self-upgrade is planned as follow-up work.

Verification

  • uv run pytest -q tests/test_upgrade.py
  • uv run pytest -q
  • uvx ruff check src/specify_cli/__init__.py
  • Manual smoke on macOS:
    • uv run specify self --help
    • uv run specify self check --help
    • uv run specify self upgrade --help
    • uv run specify self check online
    • uv run specify self check offline
    • GH_TOKEN="SENTINEL-TOKEN-VALUE" uv run specify self check 2>&1 | grep SENTINEL-TOKEN-VALUE returns no output
    • uv run specify self upgrade prints the exact three-line stub and exits 0

Notes

  • Console(highlight=False) is included to avoid Rich auto-highlighting plain numeric output, which was causing existing plain-text CLI tests to fail.
  • Destructive specify self upgrade behavior is intentionally left for follow-up work.

Introduce a new `specify self` Typer sub-app with two subcommands.

`specify self check` performs a read-only lookup against the GitHub Releases
API, compares the installed version to the latest tag with PEP 440 semantics,
and prints one of four verdicts (newer-available, up-to-date, indeterminate,
graceful-failure). When a newer stable release is available, the output
includes a copy-pasteable `uv tool install --force --from git+...@<tag>`
reinstall command. `GH_TOKEN` / `GITHUB_TOKEN` is attached as a bearer
credential when set so users behind shared IPs escape the anonymous 60/hour
rate limit.

`specify self upgrade` is a documented non-destructive stub in this release:
three-line guidance output, exit 0, no outbound call, no install-method
detection. The real destructive implementation is planned as follow-up work.

Failure categorization is a fixed three-entry enum (offline or timeout,
rate limited, HTTP <code>). Anything outside those three categories
propagates as a non-zero exit so bugs surface instead of being silently
swallowed. No machine-readable output, no retries, no caching in this
release — see issue github#2282 discussion.

Tests mock `urllib.request.urlopen`; the suite performs zero real network
calls. Full regression suite: 1586 passed.
Rich's default `highlight=True` applies ANSI color to detected patterns
(integers, version strings, paths) whenever stdout is deemed a TTY.
This caused intermittent failures in existing pytest assertions in
tests/test_cli_version.py and tests/test_extensions.py::TestExtensionRemoveCLI
that compare plain-text output without passing through `strip_ansi()`.

Setting `Console(highlight=False)` globally makes all CLI output
deterministic and fixes the flake without modifying the affected tests.
The numeric cyan highlighting was not a documented part of the CLI
visual contract.
Copilot AI review requested due to automatic review settings April 22, 2026 15:59
@chordpli chordpli requested a review from mnriem as a code owner April 22, 2026 15:59
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

Adds a new specify self CLI surface for checking whether a newer released version is available, and reserves a future self upgrade command as a non-destructive stub.

Changes:

  • Introduces specify self check to query the latest GitHub release tag and print upgrade/reinstall guidance.
  • Adds specify self upgrade as a fixed-output stub (no network, exits 0).
  • Adds a dedicated test module that mocks urllib.request.urlopen to keep the suite network-isolated.

Reviewed changes

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

File Description
tests/test_upgrade.py Adds tests for version comparison, tag normalization, failure categorization, token header behavior, and the self upgrade stub output/network isolation.
src/specify_cli/init.py Implements release lookup + comparison helpers and wires the new self Typer sub-app into the CLI.

💡 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 Outdated
Comment thread tests/test_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 2 out of 2 changed files in this pull request and generated 3 comments.


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

Comment thread src/specify_cli/__init__.py Outdated
Comment thread tests/test_upgrade.py
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 2 out of 2 changed files in this pull request and generated 3 comments.


💡 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 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 2 out of 2 changed files in this pull request and generated 1 comment.


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

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 2 out of 2 changed files in this pull request and generated 2 comments.


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

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 2 out of 2 changed files in this pull request and generated 1 comment.


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

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 2 out of 2 changed files in this pull request and generated no new comments.


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

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

Tip

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

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

@mnriem mnriem merged commit c5c2013 into github:main Apr 22, 2026
18 of 19 checks passed
@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 22, 2026

Thank you!

@rcollette
Copy link
Copy Markdown

@mnriem I'm disappointed that #2282 was closed. This only half implements the #2282 request. I get wanting to keep the PR small, but the PR is not a 1-1 with the issue.

@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Apr 22, 2026

Feel free to bring it the rest of the way!

@chordpli
Copy link
Copy Markdown
Contributor Author

@rcollette @mnriem

Thanks for the review and for merging this.

I’d like to follow up with a Phase 2 PR for the actual specify self upgrade flow, building on the read-only specify self check work from this PR.

@rcollette
Copy link
Copy Markdown

Feel free to bring it the rest of the way!

That's not the point. The point is that issues are being closed, before completion. Feel free to be a manager, the proper way.

@rcollette
Copy link
Copy Markdown

I'm also a paying customer at the moment. So telling me to feel free to develop the product I am paying for is absolutely ludicrous.

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.

[Feature]: Allow update to @latest release

4 participants