Build and version a release before tagging it - #9
Merged
Merged
Conversation
Tags carried no built assets. build/ is gitignored, so both the GitHub source archive and a Composer install from a tag gave a plugin that loads and renders nothing, and only the zip attached to the release worked. The old workflow could not fix that from where it ran: it fired on a tag that already existed, so anything it produced landed beside the tag rather than in it. Invert the order, as humanmade/hm-query-loop does. The Release workflow is now dispatched by hand with a version. It builds, stamps that version into the plugin, commits the built assets, and creates the tag on that commit, pushing the tag alone so main is untouched. A tag is therefore installable as it stands, through Composer as well as the zip, and is written once and never moved, which is what Packagist needs. The version follows from the same inversion. main carries the literal __VERSION__ in the header and the VERSION constant, and the real number exists only inside a tag, so the two cannot disagree and there is no bump commit to forget. The old tag-versus-header check has nothing left to check and goes. The zip is now git archive of the tag, so .gitattributes decides what ships instead of a cp list in the workflow. src/ stays in it: the tagged tree can then be rebuilt from itself. CI config, the PHPCS config and composer.lock are the only things dropped. build-and-release.yml is the other half of the pattern, keeping a release branch at main plus a built build/ for sites that install from a branch. It is not part of cutting a release and carries the placeholder, so it is not a versioned artifact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Author
|
I did this alternative https://github.com/pixelfear/composer-dist-plugin but, this set of actions take care of some other nice things like not needing to manually change the version string. |
tomjn
approved these changes
Sep 21, 2026
roborourke
commented
Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release tags now carry the built plugin, so both the source archive and a
Composer install from a tag actually render an icon.
Problem
build/is gitignored. A release tag had no built assets in it, soGitHub's source archive and a Composer install from that tag gave a plugin
that renders nothing. Only the attached zip worked. The old release
workflow ran on a tag that already existed, so it had no way to add
anything into that tag.
Change
Ports the pattern from
humanmade/hm-query-loop..github/workflows/release.ymlis now dispatched by hand with a versioninput (
X.Y.Z, no leadingv). It checks the version is valid and thetag doesn't exist yet, builds, stamps the version over
__VERSION__inbutton-block-icon.php, commits the builtbuild/, tags that commit,and pushes only the tag.
mainnever changes.button-block-icon.phponmainnow says__VERSION__in the pluginheader and the
VERSIONconstant. The real version only exists inside atag, so the header and the tag can't disagree, and there's no bump
commit to remember. The old check that compared them is gone.
.gitattributescontrols what the release zip contains, throughexport-ignore.build/andsrc/both ship, so a tagged tree canrebuild itself. Only
.github,.gitignore,.gitattributes,CLAUDE.md,composer.lockandphpcs.xml.distare left out. The zipis a
git archiveof the tag, attached to a GitHub release withgenerated notes.
.github/workflows/build-and-release.ymlkeeps a rollingreleasebranch at
mainwith a builtbuild/, on every push tomain, usinghumanmade/hm-github-actions'build-to-release-branch. This is forsites that install from a branch, not for cutting a release.
From now on, release by going to the Actions tab, choosing the Release
workflow, and entering a version like
1.2.0. Pushing a tag by hand nolonger builds or versions anything.
Verified locally
PHP lint and PHPCS pass. A full
npm ci && npm run build, stamp, commit,tag and
git archivedry run in a scratch clone produced a zip with thestamped plugin file,
build/,src/,inc/, README, SECURITY, LICENSE,composer.jsonand package files.🤖 Generated with Claude Code