Skip to content

Release

Release #17

Workflow file for this run

name: Release
on:
release:
# `published` covers new releases and prereleases; `released` also fires
# when an existing prerelease is changed to a full release.
types: [published, released]
workflow_dispatch:
inputs:
version:
type: choice
description: Release Version
required: true
default: next
options:
- latest
- next
branch:
description: Release Branch (confirm release branch)
required: true
default: main
permissions:
contents: read
id-token: write
concurrency:
group: publish-${{ github.workflow }}-${{ github.ref_name || github.run_id }}
cancel-in-progress: false
env:
PACKAGE_NAME: "@module-federation/vinext"
PACKAGE_DIR: packages/vinext
jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
environment: Publish
# A new stable release fires both `published` and `released`; publish
# stable releases from `released` only so they run once.
if: github.event_name != 'release' || github.event.action == 'released' || github.event.release.prerelease
steps:
- name: Validate manual publish target
if: github.event_name == 'workflow_dispatch'
env:
RELEASE_BRANCH: ${{ github.event.inputs.branch }}
run: |
if [ "$RELEASE_BRANCH" != "main" ]; then
echo "Releases must publish from main."
echo "Got: $RELEASE_BRANCH"
exit 1
fi
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.release.tag_name || github.event.inputs.branch }}
- name: Verify source is on main
run: |
git fetch --no-tags origin main:refs/remotes/origin/main
if ! git merge-base --is-ancestor HEAD origin/main; then
echo "Release source must be reachable from main."
echo "Got: $(git rev-parse HEAD)"
exit 1
fi
- name: Cache tool downloads
uses: actions/cache@v4
with:
path: ~/.cache
key: ${{ runner.os }}-toolcache-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-toolcache-
- name: Set up pnpm
uses: pnpm/action-setup@v4
with:
version: "10.33.2"
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: "24.15.0"
cache: pnpm
registry-url: "https://registry.npmjs.org"
- name: Set up npm
run: npm install --global npm@12.0.2
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Generate preview version
if: github.event_name == 'workflow_dispatch' && github.event.inputs.version == 'next'
run: |
pnpm exec changeset version --snapshot next
cd "$PACKAGE_DIR"
SNAPSHOT_VERSION="$(node -p "require('./package.json').version")"
BASE_VERSION="${SNAPSHOT_VERSION%%-*}"
NEXT_VERSION="${BASE_VERSION}-next.${GITHUB_RUN_ID}"
npm pkg set version="$NEXT_VERSION"
echo "Set preview version: $NEXT_VERSION"
- name: Verify tag matches package version
if: github.event_name == 'release'
working-directory: ${{ env.PACKAGE_DIR }}
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
TAG="$RELEASE_TAG"
if [ "${TAG#v}" != "$TAG" ]; then
echo "Invalid tag format; refusing to publish."
echo "Expected: 1.2.3 (no leading 'v')"
echo "Got: $TAG"
exit 1
fi
PKG_VERSION="$(node -p "require('./package.json').version")"
if [ "$PKG_VERSION" != "$TAG" ]; then
echo "Version mismatch; refusing to publish."
echo "Git tag: $TAG"
echo "package.json version: $PKG_VERSION"
exit 1
fi
- name: Set deterministic prerelease version
if: github.event_name == 'release' && github.event.release.prerelease
working-directory: ${{ env.PACKAGE_DIR }}
run: |
CURRENT_VERSION="$(node -p "require('./package.json').version")"
BASE_VERSION="${CURRENT_VERSION%%-*}"
NEXT_VERSION="${BASE_VERSION}-next.${GITHUB_RUN_ID}"
npm pkg set version="$NEXT_VERSION"
echo "Set prerelease version: $NEXT_VERSION"
- name: Run checks
run: pnpm run check
- name: Check formatting
run: pnpm run fmt.check
- name: Pack package
working-directory: ${{ env.PACKAGE_DIR }}
# pnpm pack resolves catalog: and workspace: specifiers; npm publish does not.
run: pnpm pack --pack-destination "$RUNNER_TEMP/package"
- name: Compute npm dist-tag
id: dist
env:
EVENT_NAME: ${{ github.event_name }}
IS_PRERELEASE: ${{ github.event.release.prerelease || false }}
RELEASE_VERSION: ${{ github.event.inputs.version }}
run: |
DIST_TAG="latest"
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
if [ "$RELEASE_VERSION" = "next" ]; then
DIST_TAG="next"
fi
elif [ "$IS_PRERELEASE" = "true" ]; then
DIST_TAG="next"
fi
echo "dist_tag=$DIST_TAG" >> "$GITHUB_OUTPUT"
- name: Resolve publish action
working-directory: ${{ env.PACKAGE_DIR }}
id: publish_action
env:
DIST_TAG: ${{ steps.dist.outputs.dist_tag }}
run: |
PKG_VERSION="$(node -p "require('./package.json').version")"
ACTION="publish"
REASON="new version not yet on npm"
EXISTING_VERSION="$(npm view "$PACKAGE_NAME@$PKG_VERSION" version --json 2>/dev/null || true)"
EXISTING_VERSION="${EXISTING_VERSION#\"}"
EXISTING_VERSION="${EXISTING_VERSION%\"}"
if [ "$EXISTING_VERSION" = "$PKG_VERSION" ]; then
CURRENT_TAG_VERSION="$(npm view "$PACKAGE_NAME" "dist-tags.$DIST_TAG" --json 2>/dev/null || true)"
CURRENT_TAG_VERSION="${CURRENT_TAG_VERSION#\"}"
CURRENT_TAG_VERSION="${CURRENT_TAG_VERSION%\"}"
if [ "$CURRENT_TAG_VERSION" = "null" ]; then
CURRENT_TAG_VERSION=""
fi
if [ "$CURRENT_TAG_VERSION" = "$PKG_VERSION" ]; then
ACTION="skip"
REASON="version already published and dist-tag already points to it"
else
echo "Refusing to republish existing npm version:"
echo "Package: $PACKAGE_NAME"
echo "Version: $PKG_VERSION"
echo "Target dist-tag: $DIST_TAG"
echo "Current '$DIST_TAG' dist-tag points to: ${CURRENT_TAG_VERSION:-<unset>}"
echo ""
echo "Trusted Publishers do not support dist-tag promotion without publishing."
echo "Use a new semver version for this release flow."
exit 1
fi
fi
echo "action=$ACTION" >> "$GITHUB_OUTPUT"
echo "reason=$REASON" >> "$GITHUB_OUTPUT"
- name: Publish to npm
if: steps.publish_action.outputs.action == 'publish'
env:
DIST_TAG: ${{ steps.dist.outputs.dist_tag }}
run: npm publish "$RUNNER_TEMP"/package/*.tgz --provenance --tag "$DIST_TAG" --access public
- name: Skip npm publish
if: steps.publish_action.outputs.action == 'skip'
env:
REASON: ${{ steps.publish_action.outputs.reason }}
run: |
echo "Skipping npm publish:"
echo "$REASON"
- name: Post summary
if: always()
working-directory: ${{ env.PACKAGE_DIR }}
continue-on-error: true
env:
SOURCE_REF: ${{ github.event.release.tag_name || github.event.inputs.branch }}
DIST_TAG: ${{ steps.dist.outputs.dist_tag }}
ACTION: ${{ steps.publish_action.outputs.action || 'unknown' }}
REASON: ${{ steps.publish_action.outputs.reason || 'n/a' }}
EVENT_NAME: ${{ github.event_name }}
run: |
PKG_VERSION="$(node -p "require('./package.json').version")"
{
echo "## npm publish"
echo ""
echo "Package: \`$PACKAGE_NAME\`"
echo "Version: \`$PKG_VERSION\`"
echo "Dist-tag: \`$DIST_TAG\`"
echo "Action: \`$ACTION\`"
echo "Reason: \`$REASON\`"
echo "Trigger: \`$EVENT_NAME\`"
echo "Source ref: \`$SOURCE_REF\`"
if [ "$ACTION" = "publish" ]; then
echo ""
echo '```sh'
echo "pnpm add $PACKAGE_NAME@$PKG_VERSION"
echo '```'
fi
} >> "$GITHUB_STEP_SUMMARY"