Repository navigation
Add release-publish: the GitHub release for a version at a commit, with a title, notes and assets - #16
Conversation
…le, notes and assets release-merge published the release as its second step, right after the merges and before the caller built anything, so a release went public without its build and a failed build left a published release behind; with immutable releases that could not be corrected. Publishing is now the release-publish action, which the caller runs after its build at the commit release-merge leaves on the base (its base-sha output). release-publish takes a title (the version by default), a notes file (GitHub's generated notes by default) and assets, one path per line. With assets the release is created as a draft, the files are uploaded, and the draft is published last: a draft makes no tag, so an upload that fails is undone by deleting it. A hotfix on an older line no longer takes Latest from a newer release (make_latest by version order). A release that already exists is skipped, as before. validateVersion moved to the shared lib for both actions. release-merge loses the publish input and the published / release-url outputs; the template runs the two actions with the build between them. SOFT-5188
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough
Merge Risk:
|
…p attached, through release-publish release-merge no longer publishes: the toolbox split the release into its own action, release-publish, run after the build at the commit the merge left on master. The release is created with give.zip already on it and only once the wp.org deploy succeeded, so a failed build or deploy leaves no release behind. Pinned to plugin-toolbox 657eb50 (stellarwp/plugin-toolbox#16).
b529772 to
eab1115
Compare
…l publishes The merge template had grown a publish step. Each template now shows one action; a repository that merges with release-merge adds release-publish to that workflow after its build, as GiveWP's deploy workflow does, and the READMEs say so. SOFT-5188
The release-publish template checked out the branch, invited a build from that checkout, and passed the branch name as target, which the action resolves to the branch's tip when it runs: a push between the checkout and the publish would tag a commit other than the one the assets came from. The template now records the checked-out commit and passes it. SOFT-5188
05d78d2 to
9603173
Compare
6568397 to
e6c9816
Compare
e6c9816 to
ef353a6
Compare
…ispatches The per-action templates matched no repository: nobody merges without publishing, and a repository that only publishes does not go through the dashboard. release.yml, the name the dashboard looks for by default, runs release-merge, leaves room for the build, then release-publish at the merged commit. The publish-only shape stays as a snippet in release-publish's README. SOFT-5188
ef353a6 to
879516b
Compare
…s github.token cannot create The environment's branch policy protects the branch a run is started on, not the branch input, so a run started on an allowed branch could merge and publish any other. The template's first step fails when the two differ; the dashboard starts the run on the release branch, and a hand dispatch passes --ref. A failing step rather than an if on the job, since a skipped job reads as a success to the dispatcher. The release-publish README also says that a release at a commit that changes a workflow file relative to the default branch needs a token allowed to modify workflows, which github.token cannot be; after release-merge the published commit is the base branch's tip, so the case is the hand-merged publish only. SOFT-5188
release-merge now merges through the GitHub API and touches no checkout, so the template checks out base-sha after it, where the build runs, and needs no checkout before it. release-publish's README shows the same chain.
e6cee72 to
356cf3e
Compare
356cf3e to
2f2f4f0
Compare
…e released generateReleaseNotes was called without previous_tag_name, so GitHub chose where the notes start, and its choice is not documented: a hotfix on an older line, 2.1.38.3 after 2.1.46 is out, could get the changes since 2.1.46. The releases are listed and the highest published version below the one released is passed as previous_tag_name; drafts and tags that are not plain versions are skipped. With nothing below, the start is left to GitHub as before.
…s deleted The draft was deleted only when an upload failed. When the call that publishes it failed, which is what a tag ruleset that blocks the tag produces, the draft stayed, and a rerun found no release by the tag and made a second one. The publish is now undone the same way. The error says the draft was deleted only when the delete succeeded; otherwise it says where to delete it by hand. A draft of the version left behind by an earlier run, cancelled while uploading, is deleted before publishing.
GitHub ignores target_commitish when the tag already exists, so a tag named after the version that someone creates between the first check and the publish attaches the release to that commit, and the action reported the commit it asked for. With files, the tag is read before the draft is published: one that appeared during the uploads deletes the draft and fails, naming its commit. Without files, it is read right after the release is created: one that points elsewhere fails naming the commit the release is at and its URL, since the release is public by then. The README asks the publish-only workflow for the template's concurrency group.
…, not the branch The input's description recommended the branch for a release a person merged by hand and said the tag is made at the commit whatever the branch points to by then. A branch name is resolved to its tip when the action runs, so a push after the checkout would be tagged with assets built from another commit. The description now says what the README's publish-only snippet already does.
… template The approval of the live environment may come long after the run was started, and release-merge reads the branch's tip when its step runs. With head: github.sha a push to the release branch in between is refused rather than merged unreviewed.
2f2f4f0 to
dd3544c
Compare
| // A draft of this version left by a run that was cancelled while uploading, or whose publish | ||
| // failed before the draft could be deleted. getReleaseByTag does not return drafts, so a rerun | ||
| // would otherwise leave it there and add a second one. | ||
| const releases = await listReleases({ github, owner, repo }) | ||
| for (const stale of releases.filter((release) => release.draft && release.tag_name === version)) { | ||
| try { | ||
| await github.rest.repos.deleteRelease({ owner, repo, release_id: stale.id }) | ||
| core.info(`Deleted a draft of ${version} left behind by an earlier run (${stale.html_url}).`) | ||
| } catch (error) { | ||
| core.warning( | ||
| `A draft of ${version} left behind by an earlier run could not be deleted (HTTP ${error.status}): ` + | ||
| `delete it by hand at ${stale.html_url}.` | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
This deletes every draft whose tag_name is version, not only drafts an earlier run of this action made. A draft a person created by hand for the upcoming version, for example to write the release notes in the GitHub UI, has the same tag_name and is deleted here without any check. Can the action mark the drafts it creates, for example with a fixed line in the body or a name it sets, and delete only drafts with that mark? The comment above and the README's "Running it again" section both describe the deleted drafts as ones left behind by an earlier run, which is narrower than what the filter matches.
There was a problem hiding this comment.
You're right, the filter took any draft with that tag name. Fixed in 2fb753b: the action names its draft <title> [release-publish draft], publishes it under the title, and deletes only drafts that carry the mark. The README and the comment say so now. Checked on a test plugin with a draft made by hand for the same version sitting there: the deploy left it alone, published 2.1.49 under the plain title (run).
The rerun deleted every draft whose tag name was the version, a draft a person made by hand to write the notes included. The action now names its draft <title> [release-publish draft], publishes it under the title, and deletes only drafts that carry the mark.
d10f4e0 to
2fb753b
Compare
Related
Part of SOFT-5188. Answers three review comments on #10: publish inputs,
make_latest, the token andon: release.Summary
release-publishcreates the GitHub release for a version at a commit: the tag and the release in one step, with a title, notes from a file and assets. A repository's deploy workflow runs it afterrelease-merge(#10) and its build, at the commitrelease-mergeleaves on the base branch (base-sha), so the release is published only once the build exists and carries it. A repository that merges by hand runs it alone, with a branch astarget.Changes
version,target(a commit hash; a branch name is resolved to its tip when the action runs, so a workflow that builds from a checkout passes that checkout's commit),title(the version by default),notes-file(a file in the checkout; GitHub's generated notes by default),files(assets, one path per line),token(defaultgithub.token). Outputs:published(trueorskipped),release-url,sha.files, the release is created as a draft, the files are uploaded, and the draft is published last. A draft makes no tag, so a failed upload is undone by deleting the draft; every path is checked before anything is created. A repository with immutable releases needs this order, since a published release cannot be changed.make_latestfollows version order against the repository's current latest release, so a hotfix on an older line does not take "Latest" from a newer release.templates/workflows/release.yml: the deploy workflow the dashboard dispatches, under the name it looks for by default. It runsrelease-merge, checks outbase-sha(the merges go through the API, so no checkout is needed before it), leaves room for the build, thenrelease-publishwithtarget: ${{ steps.merge.outputs.base-sha }}, as GiveWP's deploy workflow does. Its first step fails when the run was not started on the branch it is asked to merge, so theliveenvironment's branch policy covers what is merged and published; the dashboard starts the run on the release branch, a hand dispatch passes--ref. The merge-only template is gone (Add release-merge: the release branch into the base branch, then the base branch into develop #10), and the publish-only shape (a release a person merged by hand) is a snippet inrelease-publish's README, with the checked-out commit astarget.develop; the publish: creating the tag, so a tag ruleset should block deletion and updates, not creation), that a personal access token or a GitHub App token does triggeron: releasewhilegithub.tokendoes not, that the caller template's environment with required reviewers is the human gate, and the one releasegithub.tokencannot create: one at a commit that changes a workflow file relative to the default branch, which afterrelease-mergenever happens (the published commit is the base branch's tip) and is the hand-merged publish's case. Therelease-mergeREADME and manifest point atrelease-publish; its code does not change here.develop-branch: ''has to be written in the caller: aworkflow_dispatchinput left empty takes its default, so the empty value cannot be passed through one. Said in therelease-mergeREADME.tests/actions/release-publish/release-publish.test.js, against the recorded Octokit and real files in a temporary directory. The recording fetch keeps a non-JSON body (an asset upload) as it was sent.How to test
mainanddevelop, copytemplates/workflows/release.ymlto.github/workflows/, with bothuses:pointing at this branch's commit, add a build step between the two actions and uncommentfiles:with the path it writes.release/x.y.zfrommain, bump the version files.puprclists on it (release-prepdoes this) and push.gh workflow run release.yml --ref release/x.y.z -f branch=release/x.y.z -f version=x.y.z(without--refthe first step fails and nothing is merged):mainanddevelopget the merges, the releasex.y.zexists with the file attached, and its tag points at the merge commit onmain.node --test(332 tests).docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:latest templates/workflows/release.yml.The steps were run on the two private test plugins, pinned to
356cf3e, this stack's head. The deploy callers of both and GiveWP'srelease-dashboard-deploy.ymlhave the shape ofrelease.yml:release-merge, the checkout ofbase-sha, the build, thenrelease-publish.develop:release-mergefails,release-publishnever runs, no tag and no release; after the conflict is resolved by hand the rerun publishes 1.1.17mainforrelease/M26.api5: refused by the first step, nothing merged; the same dispatch with--refgoes throughrelease-merge, the checkout ofbase-shaand this action; 2.1.47 published with the zip, 1.1.18 without, both tagged at the merge commitgithub.tokenat the merge commit (ate6cee72;release-publish.jsis unchanged since)dd3544c: a full cycle on both plugins (prepare, RC, deploy) withhead: ${{ github.sha }}passed to release-merge. 2.1.48 with the zip and 1.1.19 without, each at its merge commit; the log says "The notes cover the changes since 2.1.47" / "since 1.1.18", and the release body linkscompare/2.1.47...2.1.48. Rerun of 2.1.48: already published, nothing merged, nothing publishedhead≠ tip): refused by release-merge before any read or merge, "release/head-check is at 086e24d…, not at 56c9989…, the commit this run was started on"; dispatched at the tip, the check passesd10f4e0, with a draft a person made by hand for 2.1.49 sitting in the repository: the deploy left it alone, created its own marked draft, uploaded the zip and published 2.1.49 under the plain title; 1.1.20 the same without assetsStack created with GitHub Stacks CLI • Give Feedback 💬
Summary by CodeRabbit
New Features
Documentation