feat(cmd): release v1.10.0 — shallow clone guard and --check preflight
ci / vet, staticcheck, test, build (push) Successful in 3m46s
docs / Build and deploy docs (push) Failing after 11s
release / Build and publish release (push) Successful in 4m34s

- refuse to release when the clone is shallow and no previous release tag
  is found: tags beyond the fetch depth would silently restart versioning
  at X.Y.0; --allow-shallow bypasses the guard for a true first release
- new --check preflight validates the release environment without
  releasing: branch resolution + pattern, working tree, tag discovery,
  shallow clone, remote origin URL parse (same parse the push performs),
  push auth method, version files, release target — all problems reported
  at once, non-zero exit on failure
- .releaser.gitlab-ci.yml gains an optional .releaser:check MR-pipeline
  job; CI examples now set GIT_DEPTH: 0

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 22:12:17 +02:00
parent 2a6a65ce80
commit 37db8e97ca
11 changed files with 539 additions and 1 deletions
+27
View File
@@ -29,6 +29,7 @@ release:
- if: $CI_COMMIT_BRANCH =~ /^release\/.+$/
variables:
GITLAB_TOKEN: $RELEASE_TOKEN
GIT_DEPTH: 0 # full history — shallow clones hide previous release tags
script:
- releaser
artifacts:
@@ -93,6 +94,32 @@ jobs:
`fetch-depth: 0` is required. A shallow clone (`--depth 1`) hides the previous tag, causing `releaser` to treat every commit as the first release.
{{< /hint >}}
## Preflight checks
`releaser --check` validates the release environment without releasing anything: branch resolution and pattern match, working tree state, shallow clone, remote URL parseability (the same parse the push performs — it catches shell-quoting accidents in `set-url` lines), which push auth would be used, configured version files, and the release target. All problems are reported at once, and the exit code is non-zero if any check fails.
Note the split with `--dry-run`: dry-run answers *"what version would be released?"* (it analyzes commits and computes the bump); `--check` answers *"will the release plumbing work?"* (everything dry-run never touches). Run `--check` in merge-request pipelines to catch broken CI configuration before it blocks a real release:
```yaml
release:check:
stage: test
image: registry.example.com/releaser:latest
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GIT_DEPTH: 0
script:
- releaser --check --branch "release/0.0" # any pattern-matching name works for validation
```
## Shallow clones
GitLab CI checks out a shallow clone by default (`GIT_DEPTH: 20`), and shallow clones hide any release tag beyond the fetch depth — tag discovery would silently restart versioning at `X.Y.0`. `releaser` detects this: when the clone is shallow **and** no previous release tag is found, it refuses to release and asks for full history.
Fix it by fetching full history (`GIT_DEPTH: 0` in GitLab CI, `fetch-depth: 0` in GitHub Actions, or `git fetch --unshallow`). If the project genuinely has no release tag yet, pass `--allow-shallow` to release anyway.
A shallow clone whose history does include the latest release tag is fine — the version calculation is unaffected, and `releaser` proceeds normally.
## Detached HEAD
CI runners check out a commit SHA, leaving the repository in detached HEAD state. `releaser` detects this and falls back to the branch name from the CI environment, in order: