Skip to content

post_version hook aborts entire 'semver set' run when hook target file is missing #171

Description

@justinmchase

Description

When a post_version hook (replace, patch, or regexp) in .github/version.yml references a file that doesn't exist, the resulting Deno.errors.NotFound propagates uncaught out of postVersionHook (src/hooks/post.ts), through the set command handler, and the semver process exits non-zero.

This aborts the entire version-set operation, even though:

  • The VERSION file write already happened.
  • Any earlier hooks in the same on.post list already ran successfully.

Callers that shell out to semver set (e.g. our internal release-automation webhook) then treat the whole operation as failed and roll it back / never commit, even though the only real problem is one misconfigured hook referencing a file that no longer exists in that particular repo.

Repro

.github/version.yml contains a regexp hook pointing at a file that was since removed:

on:
  post:
    - kind: regexp
      file: .github/README.md
      pattern: '\[\d+\.\d+\.\d+\]'

Running semver set 1.17.0 when .github/README.md doesn't exist produces:

Invoking post_version hook...
replacing [1.16.0] -> 1.17.0 in .github/plugin.json
replacing [1.16.0] -> 1.17.0 in .github/.codex-plugin/plugin.json
replacing [1.16.0] -> 1.17.0 in .github/.claude-plugin/plugin.json
replacing [1.16.0] -> 1.17.0 in .github/plugin/marketplace.json
replacing [1.16.0] -> 1.17.0 in .claude-plugin/marketplace.json

then exits non-zero with:

NotFound: No such file or directory (os error 2): readfile '.github/README.md'
    at async Object.readTextFile (ext:deno_fs/30_fs.js:1:10081)
    at async Object.regexp (file:///.../src/hooks/regexp.ts:13:20)
    at async postVersionHook (file:///.../src/hooks/post.ts:40:11)
    at async Object.handler (file:///.../src/commands/set.ts:29:5) {
  code: "ENOENT"
}

Note that four of the five replace hooks above already succeeded before the failing regexp hook — but because the whole process exits non-zero, a caller has no way to keep any of that work.

Requested behavior

Treat a missing hook target file as a recoverable warning rather than a fatal error:

  • Continue running the remaining configured hooks instead of aborting the whole on.post list.
  • Exit 0 overall (the version was still set correctly).
  • Surface which hook(s) failed and why in a way callers can detect programmatically — e.g. via the existing GITHUB_OUTPUT mechanism already used for version/dotnet/docker outputs (writeGithubOutput in src/util/version.ts), as a new hook_warnings field.

Other hook error types (unknown kind, invalid YAML, etc.) should stay fail-fast as-is — this is specifically about a hook's file not existing.

I'll follow up with a PR implementing this.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions