aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-06-13-check-populate-missing-sections-design.md
blob: 3a8b42ac218796a83ef5a524afcd0889fe86dec5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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.