livewire/livewire: 1. Trigger the workflow (Actions → Draft Release → Run workflow)
Contributed by calebporzio
Part of the livewire v4.4.7 release
Livewire's release automation no longer publishes anything the moment it runs. PR #10520 renames the internal release.yml workflow to draft-release.yml (displayed as Draft Release in the Actions tab) and reworks it so that compiled dist/ assets are committed to a dedicated versioned release branch, then attached to a draft GitHub release pinned to the exact build commit. The vX.Y.Z tag — and the public release — only come into existence when a maintainer reviews the draft and publishes it. If you're upgrading from v3.8.10, there is no application-facing change; this is release plumbing. But if you fork Livewire or run tooling against its releases, the workflow's name, file path, and finishing step have all changed.
What changed
- The workflow file moved from
.github/workflows/release.ymlto.github/workflows/draft-release.yml, the display name changed from "Release" to "Draft Release", and the job was renamed fromreleasetodraft-release. - A new Validate version step rejects anything that isn't a strict semantic version matching
^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$— so3.9.0and3.9.0-beta.1pass, whilev3.9.0,3.9, or a typo like3.9.0.fail fast before any build minutes are spent. - The "tag already exists" check now queries the remote with
git ls-remote --exit-code --tags origininstead of a localgit rev-parse, which is immune to stale or shallow local refs. - Tag creation was replaced by release-branch creation: the workflow creates
release/vX.Y.Z, force-addsdist/, commits it as "Build assets for vX.Y.Z", pushes the branch, and records the build commit SHA inRELEASE_TARGET. gh release createnow runs with--draftand--target "${RELEASE_TARGET}", while keeping--generate-notesand the optional--notes-start-tagoverride from a previous tag.
The new release flow, step by step
A maintainer triggers the workflow with a version input (and optionally a previous-tag override to shape the generated notes):
# 1. Trigger the workflow (Actions → Draft Release → Run workflow)
gh workflow run draft-release.yml \
-f version=3.9.0 \
-f previous_tag=v3.8.10 # optional: override where notes start
# 2. Once the run finishes, inspect the draft
gh release view v3.9.0 --json isDraft,targetCommitish,url
# 3. Edit notes or verify assets, then publish —
# this is the moment the v3.9.0 tag is created
gh release edit v3.9.0 --draft=false
Because the draft is created with --target $RELEASE_TARGET, publishing produces the tag at precisely the commit that contains the built assets, even though no tag existed when the draft was made. If a release/vX.Y.Z branch already exists, the run aborts with an error rather than silently overwriting a prior build.
Why a draft boundary matters
Under the old flow, a single workflow run immediately created a public tag and a published release. A mistyped version, bad notes, or a subtly broken build went live instantly, and walking it back meant deleting a published tag — disruptive for anyone mid-install. The draft release inserts a review boundary: generated notes can be edited, the build commit can be inspected, and the release simply doesn't exist publicly until a human says so. The branch name doubles as an audit trail — release/v3.9.0 tells you exactly which commit carries which compiled bundle.
Validation and script hardening
Beyond the semver gate, the workflow scripts were tightened. Inline uses of ${{ env.VERSION }} inside run: blocks were replaced with environment variables ($VERSION, ${PREVIOUS_TAG}, $RELEASE_TARGET) and an explicit shell: bash, which avoids the GitHub Actions expression-injection footgun where interpolated values are spliced directly into shell scripts. Small changes, but they make an automated pipeline that pushes to the main repository considerably safer to extend later.
Upgrade impact
- App developers: nothing to do. Tags keep their
vprefix, releases still carry the compileddist/assets via the tagged build commit, and Composer/npm installs behave identically. Nothing in the Livewire package itself changed. - Forks and automation: update anything referencing
.github/workflows/release.ymlor a workflow named "Release" — the path and name are nowdraft-release.yml/ "Draft Release". - Automation that assumed instant publication: if you scripted around "workflow run finished, therefore release is live," that assumption no longer holds. Wait for the release to leave draft state, or publish it yourself as shown above.
- Re-running a version: re-running for a version whose release branch or tag already exists fails fast; delete the stale branch (and any stale draft) before retrying.
Takeaways
- The release workflow is now
draft-release.yml("Draft Release"); it creates a draft release instead of an instant published one. - Built
dist/assets are committed to arelease/vX.Y.Zbranch, and the draft is pinned to that exact commit. - The
vX.Y.Ztag is created only when the draft is manually published — publishing is tagging. - Versions are validated as strict semver up front, and tag checks now hit the remote.
- Upgraders on v3.8.10 need no action; forks and release tooling should repoint to the new workflow name and account for the draft step.
Categories: 12 (Technical report), 1 (Release)