summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-07-04-semver-adoption-design.md
blob: 8f6478f7ec3bbfc951944244a616765a2d3dbada (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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# Adopt SemVer for mkhint

Date: 2026-07-04
Status: approved

## Goal

Adopt Semantic Versioning for the mkhint project:

1. **Git tags** — signed, annotated `vX.Y.Z` release tags, starting at `v1.0.0`.
2. **Tool reports its own version**`mkhint -v` / `mkhint --version` prints
   `mkhint X.Y.Z` and exits. The version also appears in the `--help` header.
3. **CHANGELOG.md** — Keep a Changelog format, first entry `[1.0.0]`.
4. **Conventional commits** — already in use; formalize the mapping (feat →
   minor, fix → patch, breaking → major) in the docs.

Baseline version: **1.0.0** (the tool is mature: many features, 135 tests).

## Breaking change: flag remap

`-v` / `--version` currently *sets the hint version string* (takes an argument).
To free `-v`/`--version` for the tool's own version, the hint-version flag is
renamed. Clean break, no compatibility alias.

| Old flag | New flag | Meaning |
|----------|----------|---------|
| `-v` / `--version` (takes arg) | `-V` / `--set-version` (takes arg) | set the hint version string |
| — | `-v` / `--version` (no arg) | print `mkhint X.Y.Z`, exit 0 |

## Implementation

### Version constant

Near the top of `mkhint` (by the existing `VERSION=""` at line 35):

```bash
readonly MKHINT_VERSION="1.0.0"
```

### Argument parsing (`getopt`)

Current (line ~1009):

```bash
parsed=$(getopt -o v:f:n:lcCdNhRF \
    --long version:,hintfile:,new:,list,clean,check,delete,no-dl,help,review,fix-current \
    -n 'mkhint' -- "$@") || { show_help; exit 1; }
```

New:

```bash
parsed=$(getopt -o vV:f:n:lcCdNhRF \
    --long version,set-version:,hintfile:,new:,list,clean,check,delete,no-dl,help,review,fix-current \
    -n 'mkhint' -- "$@") || { show_help; exit 1; }
```

- `v` is now a bare short option (no `:`); `V:` takes the hint-version argument.
- Long: `version` (no arg) and `set-version:` (arg) replace `version:`.

### Case handlers

Replace the `--version|-v)` case (line ~1016):

```bash
            --version|-v)
                echo "mkhint $MKHINT_VERSION"
                exit 0
                ;;
            --set-version|-V)
                VERSION="$2"
                shift 2
                ;;
```

The `-v`/`--version` handler prints and exits immediately, like `--help`.

### Mutual-exclusion messages

Lines ~1103 and ~1108 mention `--version`:

```
Error: --check cannot be combined with --version/--hintfile/--new
Error: --fix-current cannot be combined with --version/--hintfile/--new
```

Change `--version``--set-version` in both.

### `--help` text

- Header line gains the version, e.g. `mkhint $MKHINT_VERSION - manage slackrepo hint files`.
- Usage/synopsis lines (script header comments ~6-7, `show_help` ~53-54) that
  read `--version VERSION --hintfile` become `--set-version VERSION --hintfile`.
- Flag list (~68): `--version, -v VERSION` becomes `--set-version, -V VERSION
  New version string ...`; add a new line `--version, -v   Print version and exit`.

### Bash completion (`mkhint.bash-completion`)

- `all_flags` (line 11): replace `--version -v` semantics — keep `--version -v`
  in the list (terminal, no argument) and add `--set-version -V`.
- The `--version|-v)` case (line 42) that suggests the current VERSION from a
  named hint file moves to `--set-version|-V)`. `--version`/`-v` need no case
  (they take no argument).

### CHANGELOG.md (new file)

Keep a Changelog format. Since there are no prior tags, `[1.0.0]` summarizes the
current feature set at a high level plus this release's breaking change:

```markdown
# Changelog

All notable changes to this project are documented here. The format is based on
[Keep a Changelog](https://keepachangelog.com/), and this project adheres to
[Semantic Versioning](https://semver.org/).

## [1.0.0] - 2026-07-04

First tagged release. mkhint manages slackrepo hint files: create/update hints,
nvchecker-driven update checks, phantom-dep stripping for -current, and a
listing/review workflow.

### Changed
- **Breaking:** the hint-version flag is now `-V` / `--set-version`. `-v` /
  `--version` now prints the tool's own version and exits.

### Added
- `-v` / `--version` prints `mkhint X.Y.Z`.
- The `--help` header shows the version.
```

### Versioning policy (docs)

Add a short note to README: this project uses SemVer; commits follow Conventional
Commits, where `feat:` implies a minor bump, `fix:` a patch bump, and a
`!`/`BREAKING CHANGE` a major bump. Version lives in `MKHINT_VERSION` and is
bumped in the same commit that tags a release.

### Git tag

After the code and docs land and tests pass:

```bash
git tag -s v1.0.0 -m "mkhint 1.0.0"
git push origin v1.0.0   # both remotes via origin push URLs
```

## Tests (`tests/mkhint_test.sh`)

Existing invocations that set the hint version via `-v` must switch to `-V`:

- 9 `run_mkhint ... -v <ver>` calls (lines ~330, 347, 372, 389, 401, 419, 456)
  → `-V <ver>`.
- T26 (`-C -v 1.0`, line ~610) and T56 (`-F -v 1.0.0`, line ~1096) test the
  mutual-exclusion path → `-C -V 1.0` / `-F -V 1.0.0`; assertions that grep the
  error text update `--version``--set-version` if they check the message.

New tests:

| ID | Scenario |
|----|----------|
| T65 | `mkhint -v` prints `mkhint 1.0.0`, exit 0 |
| T66 | `mkhint --version` prints `mkhint 1.0.0`, exit 0 |
| T67 | `mkhint -V 8.6.0 -n curl` still sets hint VERSION (rename works) |

## Non-goals

- No runtime version derivation from git (`git describe`) — the installed copy
  has no `.git`. Version is a hardcoded constant.
- No automated release tooling / bump script. Manual bump + tag.
- No compatibility alias for the old `-v` hint-version meaning.