mirror of
https://gh-proxy.org/https://github.com/softprops/action-gh-release.git
synced 2026-07-15 23:13:02 +08:00
Compare commits
3 Commits
v3
...
d100e75a45
| Author | SHA1 | Date | |
|---|---|---|---|
| d100e75a45 | |||
| 81bcd9dd59 | |||
| b05950fac2 |
+6
-3
@@ -38,8 +38,8 @@ claim a reproducible release-creation fix.
|
||||
|
||||
`3.0.0` is a major release that moves the action runtime from Node 20 to Node 24.
|
||||
Use `v3` on GitHub-hosted runners and self-hosted fleets that already support the
|
||||
Node 24 Actions runtime. If you still need the last Node 20-compatible line, stay on
|
||||
`v2.6.2`.
|
||||
Node 24 Actions runtime. `v2.6.2` was the final Node 20-compatible release and is
|
||||
no longer maintained or supported.
|
||||
|
||||
## What's Changed
|
||||
|
||||
@@ -47,10 +47,13 @@ Node 24 Actions runtime. If you still need the last Node 20-compatible line, sta
|
||||
|
||||
* Move the action runtime and bundle target to Node 24
|
||||
* Update `@types/node` to the Node 24 line and allow future Dependabot updates
|
||||
* Keep the floating major tag on `v3`; `v2` remains pinned to the latest `2.x` release
|
||||
* Keep the floating major tag on `v3`; freeze `v2` at the final `v2.6.2` release
|
||||
|
||||
## 2.6.2
|
||||
|
||||
`2.6.2` is the final `v2` release and is no longer maintained or supported. Upgrade
|
||||
to `v3` for the supported Node 24 runtime and current fixes.
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Other Changes 🔄
|
||||
|
||||
@@ -39,8 +39,11 @@ Typically usage of this action involves adding a step to a build that
|
||||
is gated pushes to git tags. You may find `step.if` field helpful in accomplishing this
|
||||
as it maximizes the reuse value of your workflow for non-tag pushes.
|
||||
|
||||
`v3` requires a GitHub Actions runtime that supports Node 24. If you still need the
|
||||
last Node 20-compatible line, stay on `v2.6.2`.
|
||||
`v2.6.2` is the final `v2` release and is no longer maintained or supported. It
|
||||
uses the [Node 20 runtime deprecated by GitHub Actions](https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/).
|
||||
Upgrade to `v3`, which runs on Node 24. If a problem still reproduces on the
|
||||
latest `v3`, open a new issue with the exact action ref, workflow run URL,
|
||||
runner, and relevant logs.
|
||||
|
||||
Below is a simple example of `step.if` tag gating
|
||||
|
||||
|
||||
+23
-10
@@ -23,21 +23,34 @@ Use this checklist when cutting a new `action-gh-release` release.
|
||||
- `npm run build`
|
||||
- `npm test`
|
||||
5. Commit the release prep.
|
||||
- Use a plain release commit message like `release 3.0.0`.
|
||||
6. Create the annotated tag for the release commit.
|
||||
- Example: `git tag -a v3.0.0 -m "v3.0.0"`
|
||||
7. Push the commit and tag.
|
||||
- Example: `git push origin master && git push origin v3.0.0`
|
||||
8. Move the floating major tag to the new release tag.
|
||||
- Use `git commit -s` so the release commit carries a DCO sign-off.
|
||||
- Use a plain release commit message like `release X.Y.Z`.
|
||||
6. Push a release branch and open a pull request against `master`.
|
||||
- Wait for required checks and reviews.
|
||||
- Do not bypass branch protection or tag an unmerged release branch.
|
||||
7. After merge, fetch `origin/master` and resolve the exact merged release commit.
|
||||
- Confirm that commit contains the expected package version and top changelog entry.
|
||||
- When the PR is squash-merged, do not assume the release branch commit is the release commit.
|
||||
8. Create and push the full annotated version tag on the merged release commit.
|
||||
- Example: `git tag -a vX.Y.Z -m "vX.Y.Z" <release-commit>`
|
||||
- Push only the full version tag first, then wait for its tag-triggered CI to pass.
|
||||
9. Move the floating major tag to the same merged release commit.
|
||||
- For the current major line, run `npm run updatetag` to move `v3`.
|
||||
- Keep `v2` pinned to the latest `2.x` release for consumers that still need the Node 20 runtime.
|
||||
- Verify the floating tag points at the same commit as the new full tag.
|
||||
9. Create the GitHub release from the new tag.
|
||||
- Do not move `v2`; it is frozen at the final, unsupported `v2.6.2` release.
|
||||
- Verify `v3` and the full version tag are annotated and peel to the same commit.
|
||||
- Verify `v2` did not move, then wait for the separate `v3` tag-triggered CI run to pass.
|
||||
10. Create the GitHub release from the full version tag.
|
||||
- Prefer the release body from [CHANGELOG.md](CHANGELOG.md), then let GitHub append generated notes only if they add value.
|
||||
- Verify the release shows the expected tag, title, notes, and attached artifacts.
|
||||
- Verify the release shows the expected tag, title, notes, draft/prerelease state, and attached artifacts.
|
||||
11. Run post-release consumer verification in `ruitest2/action-gh-release-test`.
|
||||
- Run the generic smoke against both the full version tag and `v3`.
|
||||
- Run regression workflows relevant to the fixes in the release.
|
||||
- Confirm that every disposable release, tag, discussion, container, volume, and temporary credential was cleaned up.
|
||||
|
||||
## Notes
|
||||
|
||||
- Behavior changes should already have matching updates in [README.md](README.md), [action.yml](action.yml), tests, and `dist/index.js` before release prep begins.
|
||||
- Docs-only releases still need an intentional changelog entry and version bump decision.
|
||||
- If a release is mainly bug fixes, keep the title and summary patch-oriented; do not bury the actual fixes under dependency noise.
|
||||
- Do not move the floating major tag or publish the GitHub release until the full
|
||||
version tag's CI passes.
|
||||
|
||||
@@ -1063,6 +1063,61 @@ describe('github', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('reuses a published prerelease found by listing after direct tag lookup returns 404', async () => {
|
||||
const existingRelease: Release = {
|
||||
id: 77,
|
||||
upload_url: 'existing-upload',
|
||||
html_url: 'existing-html',
|
||||
tag_name: 'v1.0.0',
|
||||
name: 'nightly',
|
||||
body: 'previous nightly body',
|
||||
target_commitish: 'old-commit',
|
||||
draft: false,
|
||||
prerelease: true,
|
||||
assets: [{ id: 5, name: 'nightly.zip' }],
|
||||
};
|
||||
const updatedRelease: Release = {
|
||||
...existingRelease,
|
||||
name: 'updated nightly',
|
||||
body: 'updated nightly body',
|
||||
target_commitish: 'new-commit',
|
||||
};
|
||||
const createRelease = unexpected('createRelease');
|
||||
const updateRelease = vi.fn().mockResolvedValue({ data: updatedRelease });
|
||||
const releaser = createReleaser({
|
||||
getReleaseByTag: vi.fn().mockRejectedValue({ status: 404 }),
|
||||
allReleases: async function* () {
|
||||
yield { data: [existingRelease] };
|
||||
},
|
||||
createRelease,
|
||||
updateRelease,
|
||||
});
|
||||
|
||||
const result = await release(
|
||||
{
|
||||
...config,
|
||||
input_name: 'updated nightly',
|
||||
input_body: 'updated nightly body',
|
||||
input_prerelease: true,
|
||||
input_draft: false,
|
||||
input_target_commitish: 'new-commit',
|
||||
},
|
||||
releaser,
|
||||
);
|
||||
|
||||
expect(result).toEqual({ release: updatedRelease, created: false });
|
||||
expect(updateRelease).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
release_id: existingRelease.id,
|
||||
tag_name: existingRelease.tag_name,
|
||||
target_commitish: 'new-commit',
|
||||
draft: false,
|
||||
prerelease: true,
|
||||
}),
|
||||
);
|
||||
expect(createRelease).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['an omitted draft input', undefined],
|
||||
['a null-expression draft input', undefined],
|
||||
|
||||
@@ -286,6 +286,54 @@ describe('run', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('uses the selected moving-tag release ID for upload, finalization, and outputs', async () => {
|
||||
config = {
|
||||
...config,
|
||||
input_tag_name: 'nightly',
|
||||
input_draft: false,
|
||||
input_prerelease: true,
|
||||
input_files: ['nightly.zip'],
|
||||
};
|
||||
const selectedRelease: Release = {
|
||||
...initialRelease,
|
||||
id: 77,
|
||||
upload_url: 'https://uploads.example.test/releases/77/assets{?name,label}',
|
||||
html_url: 'https://example.test/releases/77',
|
||||
tag_name: 'nightly',
|
||||
name: 'nightly',
|
||||
prerelease: true,
|
||||
};
|
||||
const publishedRelease: Release = {
|
||||
...selectedRelease,
|
||||
draft: false,
|
||||
};
|
||||
mocks.release.mockResolvedValue({ release: selectedRelease, created: false });
|
||||
mocks.paths.mockReturnValue(['nightly.zip']);
|
||||
mocks.upload.mockResolvedValue({ id: 9 });
|
||||
mocks.finalizeRelease.mockResolvedValue(publishedRelease);
|
||||
mocks.listReleaseAssets.mockResolvedValue([{ id: 9, name: 'nightly.zip' }]);
|
||||
|
||||
await run();
|
||||
|
||||
expect(mocks.upload).toHaveBeenCalledWith(
|
||||
config,
|
||||
mocks.releaser,
|
||||
'https://uploads.example.test/releases/77/assets',
|
||||
'nightly.zip',
|
||||
selectedRelease.assets,
|
||||
77,
|
||||
);
|
||||
expect(mocks.finalizeRelease).toHaveBeenCalledWith(
|
||||
config,
|
||||
mocks.releaser,
|
||||
selectedRelease,
|
||||
false,
|
||||
);
|
||||
expect(mocks.listReleaseAssets).toHaveBeenCalledWith(config, mocks.releaser, publishedRelease);
|
||||
expect(mocks.setOutput).toHaveBeenCalledWith('id', '77');
|
||||
expect(mocks.setOutput).toHaveBeenCalledWith('url', publishedRelease.html_url);
|
||||
});
|
||||
|
||||
it('leaves an existing draft recoverable when an upload fails', async () => {
|
||||
config = {
|
||||
...config,
|
||||
|
||||
Reference in New Issue
Block a user