Skip to content

Single-source the version and add release.ps1 - #47

Merged
JacobPoteet merged 1 commit into
mainfrom
release-tooling
Aug 22, 2026
Merged

Single-source the version and add release.ps1#47
JacobPoteet merged 1 commit into
mainfrom
release-tooling

Conversation

@JacobPoteet

Copy link
Copy Markdown
Owner

Closes #46.

Tagging v0.6.0 failed the release build, and fixing it took a bump PR, a merge, and a force-moved tag. Two things made that possible: the version lived in more than one manual place, and bumping and tagging were separate acts that could happen in the wrong order. This removes both.

Cutting a release now

./release.ps1 -Version 0.7.0

Bumps, commits, tags, pushes. -WhatIf prints the plan without touching anything; -Branch cuts from somewhere else.

One place for the version

Directory.Build.props holds <Version>; both projects inherit it and neither csproj names a number. build.ps1 defaults to it instead of carrying its own.

That also unsticks ExplorerHelper.ShellExtension, which had been stamping 0.1.0 since it was created — for exactly the reason this issue is about, it was a separate number nobody remembered. Verified after the change:

ExplorerHelper.dll                 0.6.0+0a32ca9
ExplorerHelper.ShellExtension.dll  0.6.0+0a32ca9

The script

Preconditions all run before the first write, so a rejected release leaves the repo untouched: right branch, clean tree, in sync with origin, tag not already taken locally or on origin, and the version actually different from what's there.

It pushes the commit before the tag. A tag arriving first would start a release build against a ref the runner can't check out.

Verified

Guards, each producing its own message:

release: on 'release-tooling', expected 'main'. Switch branches or pass -Branch release-tooling.
release: working tree has uncommitted changes. Commit or stash them first.
release: v0.6.0 already exists locally. Delete it first (git tag -d v0.6.0) if you mean to redo it.

The write path was exercised for real against a throwaway bare clone acting as origin, rather than shipped untested. It bumped 0.6.0 → 0.7.0, committed, tagged, pushed both, and left a clean tree; the pushed tag resolved to the same SHA as the bump commit, and the committed diff touched only the version line.

dotnet build on the solution passes, and ./build.ps1 with no arguments reports Version 0.6.0 (from Directory.Build.props).

Docs

README's Releasing section is now the command plus what the guards do and how to recover a mis-pointed tag. CLAUDE.md gets a convention bullet, including the detail that the declared version never reaches a released binary — build.ps1 passes -p:Version from the tag, which overrides it — so it only affects local builds. That is the whole reason the CI guard exists, and it wasn't written down anywhere.

The guard stays, now reading the props file and pointing its error at release.ps1. It should never fire again.

🤖 Generated with Claude Code

Tagging v0.6.0 failed the release build because the csproj still said
0.5.0. Fixing it took a bump PR, a merge, and a force-moved tag. Two
things made that possible: the version lived in more than one manual
place, and bumping and tagging were separate acts that could happen in
the wrong order.

Directory.Build.props now holds the version and both projects inherit
it, so neither csproj names a number and build.ps1 defaults to it
rather than carrying its own. That also unsticks the shell extension,
which had been stamping 0.1.0 since it was created for exactly this
reason - it was a separate number nobody remembered.

release.ps1 makes the ordering mistake impossible by doing the whole
thing at once. It checks the branch, a clean tree, sync with origin and
that the tag is free, all before writing anything, then bumps, commits,
tags, and pushes the commit before the tag so the runner never sees a
ref it cannot check out.

release.yml reads the props file and points its error at release.ps1.
It stays as a backstop rather than the thing expected to catch this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JacobPoteet
JacobPoteet merged commit 1fbd1b3 into main Aug 22, 2026
1 check passed
@JacobPoteet
JacobPoteet deleted the release-tooling branch August 22, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make cutting a release a single step

1 participant