Skip to content

Commit ec2e331

Browse files
authored
docs: correct default branch prefixes and explain seeding the first tag (#87)
The provider docs showed fix/ and feat/ branches, which the default branch-prefix config ignores (defaults are feature/, bugfix/, hotfix/). The tag output example used v1.2.3, but v-prefixed tags do not parse and semvertag creates unprefixed ones. Nothing said a first tag must exist; the no_tags message now tells the user to push one instead of citing v1.0.
1 parent a3b0049 commit ec2e331

9 files changed

Lines changed: 52 additions & 18 deletions

File tree

‎README.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Auto-tag your GitLab or GitHub repository with semantic version tags from CI —
2626
uvx semvertag tag
2727
```
2828

29+
semvertag bumps from the highest existing semver tag and never creates
30+
the first one. Before the first run, create a plain semver tag such as
31+
`0.1.0` (a `v` prefix does not parse and is ignored).
32+
2933
## Use it in GitLab CI
3034

3135
Paste this job into your `.gitlab-ci.yml`:
@@ -83,8 +87,8 @@ GitHub Enterprise setup, outputs, and troubleshooting.
8387
## Strategies
8488

8589
- **branch-prefix** (default): the head commit on the default branch
86-
must be a merge commit whose source branch starts with `feature/`
87-
(minor), `bugfix/`, or `hotfix/` (patch).
90+
must be a merge commit whose subject names a `feature/` (minor),
91+
`bugfix/`, or `hotfix/` (patch) branch.
8892
- **conventional-commits**: parses the head commit's
8993
[Conventional Commits](https://www.conventionalcommits.org/)
9094
header (`feat:` minor, `fix:`/`perf:` patch, `!` or `BREAKING

‎action.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ inputs:
2222

2323
outputs:
2424
tag:
25-
description: 'The created tag (e.g. v1.2.3), or empty string if no bump was warranted.'
25+
description: 'The created tag (e.g. 1.2.3), or empty string if no bump was warranted.'
2626
value: ${{ steps.run.outputs.tag }}
2727
bump:
2828
description: 'The computed bump: none | patch | minor | major.'

‎docs/index.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ semvertag:
3333
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
3434
```
3535
36+
semvertag bumps from the highest existing semver tag and never creates
37+
the first one. Before the first run, create a plain semver tag such as
38+
`0.1.0` (a `v` prefix does not parse and is ignored).
39+
3640
For local testing or one-off invocations:
3741

3842
```sh

‎docs/providers/github.md‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ a bump is warranted by the configured strategy, creates a new tag
4040
ref via the GitHub API. If no bump is warranted, the job exits 0
4141
without pushing.
4242
43+
> **First tag.** semvertag bumps from the highest existing semver tag
44+
> and never creates the first one. It reads only plain semver tags such
45+
> as `0.1.0`; a `v` prefix (`v0.1.0`) does not parse and is ignored. Until
46+
> one exists, every run reports `no_tags` and exits 0. Push one with
47+
> `git tag 0.1.0 && git push origin 0.1.0`.
48+
4349
> **Auto-detection.** semvertag detects GitHub Actions from the
4450
> `GITHUB_ACTIONS=true` env var that GHA sets automatically. The
4551
> `--provider` flag is therefore optional inside GHA — explicit
@@ -92,7 +98,7 @@ When you give the step an `id:`, downstream steps can read three outputs:
9298

9399
| Output | Value |
94100
|---|---|
95-
| `tag` | The created tag (e.g. `v1.2.3`), or empty string when `status` is `no-bump`. |
101+
| `tag` | The created tag (e.g. `1.2.3`), or empty string when `status` is `no-bump`. |
96102
| `bump` | `none` \| `patch` \| `minor` \| `major`. |
97103
| `status` | `created` (tag pushed) \| `no-bump` (nothing to tag — no prior tag, already tagged, no merge commit, or non-conforming commit). On CLI error the action itself exits non-zero and this output is not written. |
98104

@@ -189,12 +195,12 @@ is the entire setup.
189195
## Branch-prefix vs conventional-commits
190196

191197
Pick `branch-prefix` if your team merges PRs with branch names that
192-
follow a `fix/...`, `feat/...`, `chore/...` convention and lands them
193-
as merge commits. semvertag reads the head commit's source-branch
194-
prefix and bumps accordingly — `fix/` bumps patch, `feat/` bumps
195-
minor, `chore/` bumps nothing. With squash merges the head is not a
196-
merge commit and the run reports `no_merge_commit`. This is the
197-
default. See
198+
follow a `feature/...`, `bugfix/...`, `hotfix/...` convention and lands
199+
them as merge commits. semvertag reads the head commit's source-branch
200+
prefix and bumps accordingly: `feature/` bumps minor, `bugfix/` and
201+
`hotfix/` bump patch, and any other prefix bumps nothing. With squash
202+
merges the head is not a merge commit and the run reports
203+
`no_merge_commit`. This is the default. See
198204
[Branch-prefix strategy](../strategies/branch-prefix.md) for the full
199205
prefix-to-bump table and edge-case behavior.
200206

‎docs/providers/gitlab.md‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ bump is warranted by the configured strategy, pushes a new tag to the
4444
project's `origin`. If no bump is warranted, the job exits 0 without
4545
pushing.
4646

47+
> **First tag.** semvertag bumps from the highest existing semver tag
48+
> and never creates the first one. It reads only plain semver tags such
49+
> as `0.1.0`; a `v` prefix (`v0.1.0`) does not parse and is ignored. Until
50+
> one exists, every run reports `no_tags` and exits 0. Push one with
51+
> `git tag 0.1.0 && git push origin 0.1.0`.
52+
4753
> **Concurrency default.** `resource_group: semvertag` makes GitLab
4854
> serialize concurrent `semvertag` jobs across pipelines on the same
4955
> project — back-to-back pushes will queue rather than race the
@@ -117,10 +123,11 @@ write scope, the minimal job snippet above is the entire setup.
117123
## Branch-prefix vs conventional-commits
118124

119125
Pick `branch-prefix` if your team merges merge requests with branch
120-
names that follow a `fix/...`, `feat/...`, `chore/...` convention
121-
and lands them as merge commits. semvertag reads the head commit's
122-
source-branch prefix and bumps accordingly — `fix/` bumps patch,
123-
`feat/` bumps minor, `chore/` bumps nothing. With squash merges the
126+
names that follow a `feature/...`, `bugfix/...`, `hotfix/...`
127+
convention and lands them as merge commits. semvertag reads the head
128+
commit's source-branch prefix and bumps accordingly: `feature/` bumps
129+
minor, `bugfix/` and `hotfix/` bump patch, and any other prefix bumps
130+
nothing. With squash merges the
124131
head is not a merge commit and the run reports `no_merge_commit`.
125132
This is the default. See
126133
[Branch-prefix strategy](../strategies/branch-prefix.md) for the full

‎semvertag/_outcome.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
# These are the JSON wire reasons. The human terminal path (_output._format_outcome)
88
# words NoTags/AlreadyTagged differently on purpose — edit both if you change the
99
# message for one audience.
10-
_NO_TAGS_REASON: typing.Final = "No prior semver-conforming tags found; not seeding an initial tag in v1.0."
10+
_NO_TAGS_REASON: typing.Final = (
11+
"No prior semver-conforming tags found; create an initial tag such as 0.1.0 on a default-branch commit."
12+
)
1113
_ALREADY_TAGGED_REASON: typing.Final = "Latest commit already tagged."
1214

1315

@@ -31,7 +33,7 @@ class DryRun:
3133

3234
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
3335
class NoTags:
34-
"""No prior semver tag to bump from; v1.0 does not seed one."""
36+
"""No prior semver tag to bump from; semvertag does not create the first one."""
3537

3638
commit: str
3739

‎semvertag/_output.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ def _format_outcome(outcome: Outcome, *, strategy: str) -> str:
6363
short = commit[:_COMMIT_SHORT_LEN]
6464
return f"Dry run: would create tag {tag} on commit {short} (strategy: {strategy}, bump: {bump.value})"
6565
case NoTags():
66-
return "No tag created — no prior semver-conforming tag to bump from."
66+
return (
67+
"No tag created — no prior semver-conforming tag to bump from; "
68+
"create an initial tag such as 0.1.0 on a default-branch commit."
69+
)
6770
case AlreadyTagged(tag=tag):
6871
return f"No tag created — latest commit is already tagged {tag}."
6972
case NoBump(reason=reason):

‎tests/unit/test_outcome.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ def test_no_tags_maps_with_none_bump_and_fixed_reason() -> None:
3838
)
3939

4040

41+
def test_no_tags_reason_says_how_to_seed_the_first_tag() -> None:
42+
reason: typing.Final = to_run_result(NoTags(commit=_COMMIT), strategy=_STRATEGY).reason
43+
assert reason is not None
44+
assert "create an initial tag such as 0.1.0" in reason
45+
assert "v1.0" not in reason
46+
47+
4148
def test_already_tagged_maps_with_tag_and_fixed_reason() -> None:
4249
result: typing.Final = to_run_result(AlreadyTagged(tag="0.3.1", commit=_COMMIT), strategy=_STRATEGY)
4350
assert result == RunResult(

‎tests/unit/test_output_rich.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def test_matrix_keeps_stderr_for_errors(quiet: bool) -> None:
9595
("outcome", "expected"),
9696
[
9797
(NoTags(commit="abc1234def"), "no prior semver-conforming tag"),
98+
(NoTags(commit="abc1234def"), "create an initial tag such as 0.1.0"),
9899
(AlreadyTagged(tag="1.2.0", commit="abc1234def"), "already tagged 1.2.0"),
99100
(
100101
NoBump(status="no_merge_commit", reason="Latest commit is not a merge commit.", commit="abc1234def"),
@@ -105,7 +106,7 @@ def test_matrix_keeps_stderr_for_errors(quiet: bool) -> None:
105106
def test_emit_renders_no_bump_outcomes_as_human_sentences(outcome: Outcome, expected: str) -> None:
106107
output, stdout_buf, _stderr = _make_pair()
107108
output.emit(outcome, strategy=_STRATEGY)
108-
stdout_text: typing.Final = stdout_buf.getvalue()
109+
stdout_text: typing.Final = " ".join(stdout_buf.getvalue().split())
109110
assert "No tag created" in stdout_text
110111
assert expected in stdout_text
111112

0 commit comments

Comments
 (0)