diff options
| author | Danilo M. <danix@danix.xyz> | 2026-06-13 17:52:50 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-06-13 17:52:50 +0200 |
| commit | 152d1df60289981aadfb23e63de35d33e509f6dd (patch) | |
| tree | da566bed3fa4749a454cd40ec1c2a93580d4b270 /docs/superpowers/specs | |
| parent | 29bbd6377f6e2758b1dea6bcba2f89c991484a19 (diff) | |
| download | mkhintfile-152d1df60289981aadfb23e63de35d33e509f6dd.tar.gz mkhintfile-152d1df60289981aadfb23e63de35d33e509f6dd.zip | |
docs: spec for --check populate missing nvchecker sections
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'docs/superpowers/specs')
| -rw-r--r-- | docs/superpowers/specs/2026-06-13-check-populate-missing-sections-design.md | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-06-13-check-populate-missing-sections-design.md b/docs/superpowers/specs/2026-06-13-check-populate-missing-sections-design.md new file mode 100644 index 0000000..3a8b42a --- /dev/null +++ b/docs/superpowers/specs/2026-06-13-check-populate-missing-sections-design.md @@ -0,0 +1,155 @@ +# `--check` populate missing nvchecker sections — design + +Date: 2026-06-13 + +## Summary + +When `mkhint --check` / `-C` scans hint files, packages that have no `[pkg]` +section in `nvchecker.toml` are currently skipped silently-ish (`skip pkg: no +nvchecker source`). On a fresh/empty `nvchecker.toml` this means *every* hint is +skipped and the command does nothing useful. + +This feature makes `--check` detect those missing-section packages and, after the +scan, offer to populate `nvchecker.toml` by appending sections for them (reusing +the existing `add_nvchecker_section` autodetect logic). If the user accepts, the +sections are written and the run stops with a message telling the user to review +the file (fill any stubs) and re-run `mkhint -C`. + +## Motivation + +`add_nvchecker_section` already exists and is called on `--new`. `--check` should +give the user a path to bootstrap nvchecker config for hints created before this +integration existed, without hand-editing the TOML for every package. + +## Behaviour + +Implemented inside the existing `check_updates` function. + +### 1. Detect missing sections during the classify loop + +The classify loop currently does, per target package: + +```bash +latest=$(nvchecker_latest "$pkg") || { echo "skip ${pkg}: no nvchecker source"; continue; } +``` + +Change so the "no result" case distinguishes two situations: + +- A `[pkg]` section **exists** in `NVCHECKER_CONFIG` but nvchecker produced no + version → genuine "no result", keep the existing skip message + (`skip ${pkg}: no nvchecker result`). +- A `[pkg]` section is **missing** → add `pkg` to a `missing_sections` array and + print `skip ${pkg}: no nvchecker section` (do not classify it as outdated). + +Section presence is tested with the same pattern `add_nvchecker_section` uses, +extracted into a small shared helper: + +```bash +# Return 0 if NVCHECKER_CONFIG has a [pkg] section +_has_nvchecker_section() { + local pkg="$1" + grep -qE "^\[${pkg}\][[:space:]]*$" "$NVCHECKER_CONFIG" +} +``` + +`add_nvchecker_section` is updated to call `_has_nvchecker_section` instead of its +inline `grep` (pure DRY refactor, no behaviour change). + +### 2. Offer to populate, after the classify loop + +After the classify loop completes and before the "nothing outdated" / report +logic, insert: + +```bash +if [[ ${#missing_sections[@]} -gt 0 ]]; then + echo "" + echo "${#missing_sections[@]} package(s) have no nvchecker section: ${missing_sections[*]}" + local answer + read -r -p "Populate ${NVCHECKER_CONFIG} now? [Y/n] " answer + answer="${answer:-Y}" + if [[ "$answer" =~ ^[Yy]$ ]]; then + local mp info + for mp in "${missing_sections[@]}"; do + info=$(find "$REPO_DIR" -mindepth 2 -name "${mp}.info" 2>/dev/null | head -1) + if [[ -z "$info" ]]; then + echo "skip ${mp}: no .info found in $REPO_DIR" + continue + fi + add_nvchecker_section "$mp" "$info" + done + echo "" + echo "Sections added. Review $NVCHECKER_CONFIG (fill any stubs), then re-run 'mkhint -C'." + return 0 + fi +fi +``` + +Key points: + +- Single batch prompt (not per package). Default Yes. +- For each missing package, the `.info` is located in `REPO_DIR` with the same + `find` pattern `list_hint_files` already uses. + - No `.info` found → print `skip ${mp}: no .info found in $REPO_DIR`, do not add + a section. + - `.info` found → call `add_nvchecker_section "$mp" "$info"`, which appends a + github/pypi section if detected, otherwise a commented stub. (Its own + duplicate guard via `_has_nvchecker_section` makes this safe.) +- After populating, **stop the run** (`return 0`) with the review message. The + newly added sections are not queried this run — the user reviews/fills stubs + first, then re-runs. (Decision: simple separation over one-shot convenience.) +- If the user declines, fall through to the normal report path. The + missing-section packages were already excluded during classify, so they simply + don't appear as outdated. + +### Interaction with the outdated set + +A run can have both outdated packages (with sections) and missing-section +packages. If the user accepts populate, the run stops *before* applying any +outdated updates — so populate takes precedence and the user re-runs to pick up +updates afterward. This is acceptable: it keeps each run's effect simple and +predictable. If the user declines populate, outdated updates proceed as today. + +## Affected code + +- `mkhint`: + - New helper `_has_nvchecker_section`. + - `add_nvchecker_section` refactored to use it (no behaviour change). + - `check_updates`: `missing_sections` array, distinguished skip messages, the + populate prompt block. +- `tests/mkhint_test.sh`: T29–T31. +- `CLAUDE.md` / `README.md`: document the populate prompt under `--check`. + +No new dependencies, no new flags, no exit-code changes. + +## Testing + +Mock-based, as existing suite. The mock nvchecker keyfile (`new_ver.json`) only +contains versions for packages we want "found"; a package absent from the keyfile +AND absent from the TOML is a missing-section case. + +| ID | Scenario | +|-----|----------| +| T29 | `-C`, hint with no section, github `.info`, accept populate → github section appended, run stops with review message, hint NOT updated | +| T30 | `-C`, hint with no section, decline populate → no section added, no error (normal skip path) | +| T31 | `-C`, hint with no section, no `.info` in repo, accept populate → `skip ... no .info found`, no section added | + +Test mechanics: + +- T29 uses a package that has a `.info` with a github HOMEPAGE/DOWNLOAD in + `MOCK_REPO` (the existing `ghpkg` fixture) but **no** `[ghpkg]` line in the test + `nvchecker.toml` and **no** entry in `new_ver.json`. After `printf 'Y\n'`, + assert the TOML now contains `[ghpkg]` + `source = "github"`, assert output + contains the review message, assert the hint file VERSION is unchanged. +- T30 uses the same setup but `printf 'n\n'`; assert TOML still has no `[ghpkg]`. +- T31 uses a package name with a hint file but no matching `.info` anywhere in + `MOCK_REPO` (e.g. a hand-written `orphan.hint`); after `printf 'Y\n'`, assert + output contains `no .info found` and TOML has no `[orphan]` section. + +## Self-review notes + +- Reuses `add_nvchecker_section` and the `find` pattern from `list_hint_files` — + no new mechanisms. +- `_has_nvchecker_section` is the only new unit; DRYs an existing grep. +- `set -e` safety: `find ... || head` is in a command substitution (non-fatal); + `add_nvchecker_section` returns 0; `read` is fine. No unguarded fallible calls. +- Scope: single function change plus one helper plus three tests. Single plan. |
