Skip to content

fix: correct make upgrade version reporting (yq, gh-aw, google-workspace-cli, node, npm globals)#94

Merged
CybotTM merged 14 commits into
mainfrom
fix/upgrade-version-reporting
Jun 20, 2026
Merged

fix: correct make upgrade version reporting (yq, gh-aw, google-workspace-cli, node, npm globals)#94
CybotTM merged 14 commits into
mainfrom
fix/upgrade-version-reporting

Conversation

@CybotTM

@CybotTM CybotTM commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

make upgrade reported wrong, missing, or confusing information — and make update vs make upgrade disagreed on the outdated count. This PR fixes the underlying detection/reporting and data-model bugs. No tool's actual upgrade behavior changed.

Version detection / reporting fixes

Tool Before Root cause Fix
yq installed: 19.169 (garbage) generic probe tries -v first = --verbose; grabs a DEBUG-log timestamp version_flag: --version
gh-aw before/after: <none> prints --version to stderr stderr fallback (gated on a version-like token)
google-workspace-cli Download failed wrong release asset prefix corrected download_url_template
node needless sudo/apt + Failed to install Node.js 26 prefers_nvm_node compared the unresolved symlink; ensure_nvm checked before sourcing nvm resolve symlinks; source nvm first; clear NODE_VERSION; guard corrupt-nvm re-bootstrap
eslint / gemini / pnpm / npm <none> / binary not found npm global bin off PATH resolve_global_bin / warn_if_bin_off_path; off-PATH install-dir fallback

Data-model fix — make update and make upgrade now agree

The render showed 53 "outdated" while make update showed 3. Root causes:

  • Status was computed by equality (installed != latest → OUTDATED), so a tool ahead of the (stale) committed baseline was falsely flagged (e.g. ansible-core 2.21.1 vs baseline 2.20.1). New compute_status() uses directional comparison (installed >= latest → UP-TO-DATE; missing latest → UNKNOWN). ~41 false "outdated" → 0.
  • make update's category summary omitted multi-version cycles; it now emits the same Readiness line as make upgrade.

Verified: both print the identical Readiness: line.

Testing & review

  • Regression + behavioral tests added (catalog, stderr/banner gate, off-PATH resolution, directional status). Full suite 629 passed.
  • Reviewed across multiple independent passes (security, reliability, DRY, coverage); SonarCloud findings resolved; gemini-code-assist threads addressed.
  • shellcheck/flake8 clean on changed lines; CI green across ubuntu/macOS/Windows.

CybotTM added 5 commits June 20, 2026 17:14
yq's -v flag means --verbose, not --version. The generic version probe
tries -v first, so it captured a DEBUG log line and parsed the timestamp
millis (e.g. 19.169) as the version. Pin version_flag to --version so
detection reads 'yq ... version v4.53.3'.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The release asset is google-workspace-cli-<arch>-unknown-linux-gnu.tar.gz,
not gws-<arch>-... The wrong template 404'd ('Download failed'). The
binary inside the archive is still 'gws'.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
…binary

gh-aw prints 'gh aw version vX.Y.Z' to stderr, but the before/after probes
redirected stderr to /dev/null, so both showed <none>. Add a shared
detect_version_string helper that prefers stdout and falls back to stderr.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
…prefix

Three PATH-trust bugs surfaced during make upgrade:
- prefers_nvm_node compared the unresolved symlink path, so a
  ~/.local/bin/node shim into ~/.nvm was misread as a manual install and
  triggered the apt removal path. Resolve symlinks first.
- ensure_nvm checked 'nvm' before sourcing nvm.sh, re-running the nvm web
  installer every run (which hijacked NODE_VERSION, printing 'Failed to
  install Node.js <ver>'). Source nvm first; clear NODE_VERSION on bootstrap.
- npm installs globals into 'npm prefix -g'/bin, which is not always on
  PATH; command -v then reported freshly-installed tools as <none> or
  'binary not found'. Add resolve_global_bin/warn_if_bin_off_path and use
  them in npm_global.sh and reconcile.sh.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Covers yq version_flag, google-workspace-cli asset URL, github_release
stderr fallback, prefers_nvm_node symlink resolution, and off-PATH npm
global resolution.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI review requested due to automatic review settings June 20, 2026 15:15
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.68%. Comparing base (710bb48) to head (50f331b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #94      +/-   ##
==========================================
+ Coverage   68.87%   69.68%   +0.80%     
==========================================
  Files          22       22              
  Lines        3345     3345              
==========================================
+ Hits         2304     2331      +27     
+ Misses       1041     1014      -27     
Flag Coverage Δ
unittests 69.68% <ø> (+0.80%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces several fixes to improve tool installation, version detection, and path resolution. Key changes include correcting the download URL for google-workspace-cli, adding an explicit version flag for yq, resolving symlinks for NVM-managed Node.js, and handling globally installed npm binaries that are off-PATH. Additionally, version detection has been updated to capture stderr output for tools like gh-aw. Feedback on these changes suggests making version detection in github_release_binary.sh more robust by falling back to the target installation directory, optimizing get_npm_tool_version in npm_global.sh to exit early if the binary path is empty, and prepending the resolved binary's directory to PATH in reconcile.sh to ensure detect_install_method functions correctly when the binary is off-PATH.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread scripts/installers/github_release_binary.sh
Comment thread scripts/installers/npm_global.sh Outdated
Comment thread scripts/lib/reconcile.sh Outdated
CybotTM added 9 commits June 20, 2026 17:23
…talled display

The guide rendered 'installed:' from a possibly-stale snapshot while the
installers detect the live 'before:'. When the snapshot lagged reality the two
contradicted each other (e.g. 'installed: not installed' directly above
'before: 10.5.0', or 'installed: 11.12.1' above 'before: 11.17.0'). Refresh
local installation state (network-free 'audit.py --update-local') at guide
startup so the displayed status matches what the installers see. Upstream
'target' versions still come from the cached baseline, so the guide stays
offline.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- github_release_binary: gate the stderr version fallback on a version-like
  token so a stderr banner/warning is not surfaced as the version.
- npm_global: only prepend the npm-global bin dir to PATH for a version_command
  when it is genuinely off PATH, so a stray or hostile npm prefix cannot shadow
  normal PATH lookups in the common (on-PATH) case.
- common: generalize the off-PATH warning message (it is used for non-nvm tools
  too).
- tests: pin the yq verbose-misparse regression to the exact misparsed value
  instead of a weak inequality.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
TestVersionLineRespectsFlag executes a #!/bin/sh fake binary via
get_version_line, which cannot run on the Windows CI runner. Mark it
@skip_on_windows like the other shell-based test classes; the JSON-only
catalog tests still run on all platforms.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The startup 'audit.py --update-local' added to the guide writes local_state.json,
but the guide's render reads tools_snapshot.json (load_snapshot), so the refresh
never updated the displayed 'installed:' status -- it only added ~5s latency.
Remove it. Installed-vs-snapshot consistency is a separate data-model concern
(tools_snapshot.json vs local_state.json vs the upstream baseline).

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
- github_release_binary: extract the version-token regex to a constant (Sonar
  S1192), use [[ ]] (S7688), and broaden the stderr gate to also accept 8-digit
  dates so a dotless/CalVer version is not dropped (matches normalize_version_output).
- npm_global / common: use [[ ]]; add path_contains_dir helper and reuse it; only
  prepend the npm-global bin dir to PATH when it is genuinely off PATH.
- common: npm_global_bin_dir now always returns 0 (safe to call bare).
- install_node: guard ensure_nvm against an endless re-bootstrap when ~/.nvm/nvm.sh
  exists but is corrupt.
- tests: add behavioral tests for the stderr/banner gate and the npm PATH-prepend
  gating; strengthen the yq verbose-misparse assertion; drop the obsolete guide test.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
detect_version_string and get_npm_tool_version use 'timeout', which BSD/macOS
lacks, so the extracted-function tests returned empty on the macOS runner. Add a
passthrough timeout() shim when the command is absent so the tests run on macOS.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The render (make upgrade) showed 53 'outdated' while make update showed 3. Two
root causes, both fixed:

- Status was computed by EQUALITY (installed != latest => OUTDATED), so a tool
  AHEAD of the (possibly stale) committed upstream baseline was falsely flagged
  OUTDATED (e.g. ansible-core 2.21.1 vs baseline 2.20.1). Add compute_status()
  with DIRECTIONAL comparison (installed >= latest => UP-TO-DATE; missing latest
  => UNKNOWN, never a false OUTDATED) and use it at all three sites (audit_tool,
  multi-version, cmd_update_local). False 'outdated' dropped from ~41 to 0.
- make update's per-category summary omitted multi-version cycles while make
  upgrade's Readiness line counts them. Emit the same Readiness summary at the
  end of make update so both report identical totals.

Verified: make update and make upgrade now print the identical Readiness line.
Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
compute_status pushed the 'NOT INSTALLED' literal to 6 occurrences, which Sonar
flagged (S1192). Name it once as STATUS_NOT_INSTALLED. Behavior unchanged (the
string value is identical, so JSON/status filtering still match).

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Address gemini-code-assist review feedback:
- detect_version_string (github_release_binary): when command -v misses the
  binary (install dir not yet on PATH on a first-time install), fall back to the
  install dir from get_install_dir and run the version probe on that path.
- get_npm_tool_version (npm_global): return early when the binary was not found,
  instead of running a version_command that cannot resolve it.
- reconcile verify: prepend the resolved binary's dir to PATH so
  detect_install_method (which uses command -v) can classify an off-PATH install
  instead of returning 'none'.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
@CybotTM CybotTM merged commit 30336cb into main Jun 20, 2026
21 checks passed
@CybotTM CybotTM deleted the fix/upgrade-version-reporting branch June 20, 2026 16:52
@sonarqubecloud

Copy link
Copy Markdown

CybotTM added a commit that referenced this pull request Jun 20, 2026
…before: (#95)

## Summary

In `make upgrade`, the `installed:` line (from the cached snapshot)
could disagree with the installer's live `before:` line — e.g.
`installed: not installed` directly above `before: v10.5.0`, or
`installed: 11.12.1` above `before: 11.17.0`. They describe the same
thing (the version present before the upgrade), so they must match.

**Root cause:** the guide renders `installed:` from
`tools_snapshot.json`, which goes stale (e.g. after tools change outside
the tool), while the installers detect live.

## Fix

The guide now refreshes the snapshot's **installed** state at startup
(network-free) so `installed:` matches `before:`.

Crucially, the full `audit.py --update-local` path now **refreshes
`installed_version` + status from live detection but PRESERVES each
tool's existing `latest_version`** — instead of rebuilding `latest` from
the older committed baseline (which would show a `target` *lower* than
`installed` and re-open the `make update` vs `make upgrade` divergence
fixed in #94). Status is recomputed with the directional
`compute_status` from #94.

Multi-version cycles (`node@24`, `python@3.12`, …) are left to `make
update` / the per-cycle re-audit, since `--update-local` has no
per-cycle local-only data.

## Verified

| tool | before (stale snapshot) | after refresh | live `before:` |
|------|------------------------|---------------|----------------|
| npm | installed `11.12.1`, latest `11.17.0` | installed **`11.17.0`**,
latest `11.17.0` (preserved) → UP-TO-DATE | `11.17.0` ✓ |
| prettier | installed `—`, latest `3.8.4` | installed **`3.8.4`**,
latest `3.8.4` (preserved) → UP-TO-DATE | `3.8.4` ✓ |
| eslint | installed `10.5.0`, latest `10.5.0` | unchanged → UP-TO-DATE
| `v10.5.0` ✓ |

Behavioral test added (`--update-local` preserves a seeded `latest`
while refreshing `installed`). Full suite **630 passed**;
`flake8`/`shellcheck` clean on changed lines.

Trade-off: adds a ~5s network-free local detection at guide startup —
the accepted cost of an accurate `installed:` before modifying the
system.
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.

2 participants