Skip to content

Commit 045a8ce

Browse files
authored
fix: determine release packages by tag existence on GitHub instead of NPM (#116)
## Summary The `get-release-packages.sh` script (used for independent-versioning monorepos) determined which packages belonged to the current release by querying the npm registry and including any package whose current version was not yet published. That assumption only holds when this action runs *before* npm publish. In the modern publish-release workflow used in `MetaMask/core`, `action-publish-release` now runs *after* `publish-npm`, so by the time this script runs every package version may already be on the registry. The resulting `RELEASE_PACKAGES` is empty, `getReleaseNotesForMonorepoWithIndependentVersions` produces an empty string, and the action fails with `The computed release notes are empty.` This PR replaces the npm check with a tag-existence check. For each workspace, the script asks GitHub whether a tag of the form `<name>@<version>` already exists for the current manifest version. If the tag exists, the package is considered already released and excluded; otherwise it's included. Private packages and `0.0.0` packages continue to be skipped. The output shape of `RELEASE_PACKAGES` is unchanged, so this is not a breaking change for downstream steps. ### Behavior change vs. old npm-check The selection criterion shifts from "not on npm" to "no release tag exists." In practice these produce the same set for normal-path consumers, since a version on npm normally corresponds to a tag this action created. They can diverge in edge cases — e.g. a repo that uses this action but skips creating tags, or a first-time use against a repo that's never been tagged in the `<name>@<version>` format (everything would be treated as unreleased on the first run). Worth calling out in the release notes; a major version bump on the action tag may be warranted. ### Other Also bumps `.nvmrc` from `v14` to `lts/*` since Node.js 14 has been EOL since April 2023. Happy to split this into a separate PR. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes core release-package selection for independent monorepos and relies on GitHub API/tag conventions; edge cases (untyped repos or missing tags) can differ from the old npm-based behavior. > > **Overview** > Fixes independent monorepo releases when publish runs **after** npm publish by changing how `get-release-packages.sh` picks packages for the current release. > > **Release selection** no longer uses `npm view` (“version not on the registry”). It now includes each public, non-`0.0.0` workspace whose manifest version has **no** existing Git tag `<name>@<version>`, checked via `gh api` (optional `RELEASE_TAGS_REPOSITORY` for tests). `action.yml` passes `GH_TOKEN` into that step. > > **Docs and CI** update README to describe tag-based independent versioning. The `updated-packages-test` workflow switches the fixture from `snaps-skunkworks` to `MetaMask/snaps@v120.0.0`, sets `RELEASE_TAGS_REPOSITORY`, and adjusts manifest bump/unbump expectations (including patch-0 unbump semantics) so the script still expects **2** packages in the release set. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f1503fe. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 9c1bbd4 commit 045a8ce

4 files changed

Lines changed: 41 additions & 24 deletions

File tree

.github/workflows/build-lint-test.yml

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ jobs:
2222
steps:
2323
- uses: actions/checkout@v3
2424
with:
25-
repository: MetaMask/snaps-skunkworks
26-
ref: v0.32.2
27-
path: skunkworks
25+
repository: MetaMask/snaps
26+
ref: v120.0.0
27+
path: snaps
2828
- uses: actions/checkout@v3
2929
with:
3030
path: action-publish-release
3131
- name: Get Packages
3232
id: get-packages
3333
run: |
34-
cd skunkworks || exit
34+
cd snaps || exit
3535
WORKSPACES=$(yarn workspaces list --verbose --json)
3636
PUBLIC_PACKAGES=()
3737
PRIVATE_PACKAGE=()
@@ -53,6 +53,13 @@ jobs:
5353
echo "RELEASE_PACKAGES=$RELEASE_PACKAGES_FORMATTED" >> "$GITHUB_OUTPUT"
5454
- name: Modify + Get RELEASE_PACKAGES lengths
5555
id: modify-get-release-packages
56+
env:
57+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58+
# Point the script's release-tag lookup at the checked-out
59+
# MetaMask/snaps repo (which has the `<name>@<version>` tag
60+
# history) rather than this repo. GITHUB_REPOSITORY itself can't
61+
# be overridden at the step level, hence the dedicated var.
62+
RELEASE_TAGS_REPOSITORY: MetaMask/snaps
5663
run: |
5764
# Update the version in a package.json manifest file
5865
#
@@ -71,11 +78,11 @@ jobs:
7178
if [[ "$2" == "unbump" ]]; then
7279
if [[ "$PATCH" == "0" ]]; then
7380
if [[ "$MINOR" == "0" ]]; then
74-
# e.g. 10.0.0 -> 9.9.9
75-
NEW_VERSION="$((MAJOR - 1)).9.9"
81+
# e.g. 10.0.0 -> 9.0.0
82+
NEW_VERSION="$((MAJOR - 1)).0.0"
7683
else
77-
# e.g. 1.10.0 -> 1.9.9
78-
NEW_VERSION="${MAJOR}.$((MINOR - 1)).9"
84+
# e.g. 1.10.0 -> 1.9.0
85+
NEW_VERSION="${MAJOR}.$((MINOR - 1)).0"
7986
fi
8087
else
8188
# e.g. 1.2.10 -> 1.2.9
@@ -91,16 +98,18 @@ jobs:
9198
jq --arg version "$NEW_VERSION" '.version = $version' "$MANIFEST" > "$MANIFEST_TEMP"
9299
mv "$MANIFEST_TEMP" "$MANIFEST"
93100
}
94-
cd skunkworks || exit
101+
cd snaps || exit
95102
IFS="," read -r -a RELEASE_PACKAGES <<< "${{ steps.get-packages.outputs.RELEASE_PACKAGES }}"
96-
# These four packages are public and at version 0.32.2
97-
# They all have published v0.32.1 versions, but no published 0.32.3
98-
# version.
103+
# The first four packages are public; their current manifest
104+
# versions all match release tags in MetaMask/snaps. Two are
105+
# bumped to a version with no tag (included), one is unbumped
106+
# to a previously-tagged version (excluded), and one is set to
107+
# 0.0.0 (excluded by the 0.0.0 rule).
99108
update_manifest "${RELEASE_PACKAGES[0]}" "bump"
100109
update_manifest "${RELEASE_PACKAGES[1]}" "bump"
101110
update_manifest "${RELEASE_PACKAGES[2]}" "unbump"
102111
update_manifest "${RELEASE_PACKAGES[3]}" "0.0.0"
103-
# This last package is the private examples package
112+
# The fifth package is the private examples package.
104113
update_manifest "${RELEASE_PACKAGES[4]}" "bump"
105114
../action-publish-release/scripts/get-release-packages.sh
106115
- name: Get modified RELEASE_PACKAGES lengths

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This is a GitHub action that creates a GitHub release for a project that represe
44

55
- For a polyrepo package, the action will set the title of the GitHub release to the version of the package specified in `package.json`, and it will set the body of the release to the section of the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)-compatible changelog within the project that matches the version.
66

7-
- For a monorepo, the action will first determine the set of packages included in the release by choosing each workspace package (the set of packages matched via the `workspaces` field in `package.json`, recursively) whose version specified in its `package.json` is different from its published version on NPM. It will then set the title of the GitHub release to the version of the root package specified in `package.json`, and it will construct the body of the release by stitching together the sections within the changelogs of each package obtained in the previous step.
7+
- For a monorepo (with independent versioning), the action will first determine the set of packages included in the release by choosing each workspace package (the set of packages matched via the `workspaces` field in `package.json`, recursively) whose current version does not yet have a corresponding Git tag of the form `<package-name>@<version>` (for example, `@metamask/example-package@1.2.3`). It will then set the title of the GitHub release to the version of the root package specified in `package.json`, and it will construct the body of the release by stitching together the sections within the changelogs of each package obtained in the previous step.
88

99
Designed for use with [`action-npm-publish`](https://github.com/MetaMask/action-npm-publish) and (indirectly) [`action-create-release-pr`](https://github.com/MetaMask/action-create-release-pr).
1010

action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ runs:
3131
shell: bash
3232
run: |
3333
${{ github.action_path }}/scripts/get-release-packages.sh
34+
env:
35+
GH_TOKEN: ${{ env.GITHUB_TOKEN || github.token }}
3436
# This sets RELEASE_NOTES as an environment variable, which is expected
3537
# by the create-github-release step.
3638
- id: get-release-notes

scripts/get-release-packages.sh

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ set -u
66
set -o pipefail
77

88
# ============================================================================
9-
# This script determines which packages to publish in a monorepo. It filters
10-
# the collection of package metadata passed in to include just the packages to
11-
# be published, then prints that filtered list.
9+
# This script determines which packages are part of the current release in a
10+
# monorepo. A package is considered part of the release if no git tag of the
11+
# form "<name>@<version>" already exists for its current manifest version.
12+
# Private packages and packages at version "0.0.0" are skipped.
1213
#
13-
# A package will be published if it cannot be found on the npm registry at the
14-
# current version. Packages with the version "0.0.0" are skipped as well; they
15-
# are assumed to not be ready for publishing.
14+
# Tag existence is queried via the GitHub API, so the workflow does not need
15+
# to fetch tags locally or use a deep checkout.
1616
# ============================================================================
1717

1818
# JSON string of packages to publish
@@ -37,14 +37,20 @@ len="${#toPublish}"
3737

3838
workspaces=$(yarn workspaces list --verbose --json)
3939

40+
# Repository to look up release tags in. Defaults to the current workflow's
41+
# repository; can be overridden via the RELEASE_TAGS_REPOSITORY env var
42+
# (used by the integration tests to point at a fixture repo, since GitHub
43+
# Actions does not allow overriding GITHUB_REPOSITORY at the step level).
44+
TAGS_REPOSITORY="${RELEASE_TAGS_REPOSITORY:-$GITHUB_REPOSITORY}"
45+
4046
while read -r location name; do
4147
MANIFEST="$location/package.json"
4248
read -r PRIVATE CURRENT_PACKAGE_VERSION < <(jq --raw-output '.private, .version' "$MANIFEST" | xargs)
4349
if [[ "$PRIVATE" != "true" && "$CURRENT_PACKAGE_VERSION" != '0.0.0' ]]; then
44-
# Get the package name as a way to test whether this version is published already
45-
PUBLISHED_PACKAGE_NAME=$(npm view "$name@$CURRENT_PACKAGE_VERSION" name || echo '')
46-
# If the package name is not set, it implies this version has not been published yet
47-
if [ -z "$PUBLISHED_PACKAGE_NAME" ]; then
50+
# Skip the package if a release tag already exists for its current
51+
# version. A non-existent tag (404) means this version has not been
52+
# released yet, so include it.
53+
if ! gh api "repos/$TAGS_REPOSITORY/git/ref/tags/$name@$CURRENT_PACKAGE_VERSION" --silent 2>/dev/null; then
4854
toPublish+="\"$name\":{\"name\":"\"$name\"",\"path\":"\"$location\"",\"version\":"\"$CURRENT_PACKAGE_VERSION"\"},"
4955
fi
5056
fi

0 commit comments

Comments
 (0)