Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 21 additions & 33 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,52 +1,36 @@

name: Release Full

on:
workflow_dispatch:
inputs:
version:
type: choice
description: "Release Version Type"
required: true
default: "patch"
options:
- major
- premajor
- minor
- preminor
- patch
- prepatch
- prerelease

tag:
type: choice
description: "Release Npm Tag"
required: true
default: "latest"
default: "nightly"
options:
- alpha
- beta
- canary
- nightly
- latest
- beta
- alpha
- nightly
- rc

dry_run:
type: boolean
description: "DryRun release"
required: true
default: false

permissions:
contents: write
# To publish packages with provenance
id-token: write

jobs:
release:
name: Release
permissions:
contents: write
# To publish packages with provenance
id-token: write
environment: npm
runs-on: ubuntu-latest

steps:
Expand All @@ -62,18 +46,22 @@ jobs:
node-version: 20
cache: "pnpm"

# Update npm to the latest version to enable OIDC
- name: Update npm
run: |
npm install -g npm@latest
npm --version

- name: Install Dependencies
run: pnpm install

- name: Run Test
run: pnpm run test

- name: Try release to npm
run: pnpm run release
env:
DRY_RUN: ${{ inputs.dry_run }}
TAG: ${{ inputs.tag }}
VERSION: ${{ inputs.version }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}


- name: Dry run release to npm
if: inputs.dry_run
run: node scripts/release.mjs --dry-run --tag ${{ inputs.tag }}

- name: Release to npm
if: ${{ !inputs.dry_run }}
run: node scripts/release.mjs --tag ${{ inputs.tag }}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"prepare": "simple-git-hooks && npm run build",
"test": "cross-env RSPACK_HOT_TEST=true jest --colors",
"testu": "cross-env RSPACK_HOT_TEST=true jest --colors --updateSnapshot",
"release": "node ./scripts/release.mjs"
"release": "node ./scripts/release.mjs",
"bump": "npx bumpp --no-push --no-tag --no-commit"
},
"files": [
"client",
Expand Down Expand Up @@ -71,7 +72,6 @@
"packageManager": "pnpm@10.17.1",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/",
"provenance": true
"registry": "https://registry.npmjs.org/"
}
}
78 changes: 37 additions & 41 deletions scripts/release.mjs
Original file line number Diff line number Diff line change
@@ -1,57 +1,64 @@
import path from 'path';
import * as url from 'url';
import cac from 'cac';
import { $ } from 'execa';
import fs from 'fs-extra';
import { inc } from 'semver';

const RELEASE_TAG = process.env.TAG || 'beta';
const RELEASE_DRY_RUN = process.env.DRY_RUN || 'true';
const RELEASE_VERSION_TYPE = process.env.VERSION || 'prerelease';
const RELEASE_NPM_TOKEN = process.env.NPM_TOKEN || '';
let cli = cac('release');
cli.option(
'--dry-run <run>',
'Perform a dry run without publishing or pushing tags',
{
default: 'false',
},
);
cli.option('--tag <tag>', 'The npm tag to publish under (default: canary)', {
default: 'canary',
});

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const PKG_PATH = path.resolve(__dirname, '../package.json');
const pkg = fs.readJsonSync(PKG_PATH);
const currentVersion = pkg.version;
const nextVersion = inc(currentVersion, RELEASE_VERSION_TYPE);
if (!nextVersion) {
const publishVersion = pkg.version;

const parsed = cli.parse();
const npmTag = parsed.options.tag;
const isDryRun = parsed.options.dryRun === 'true';

const allowedTags = ['latest', 'canary', 'alpha', 'beta', 'rc', 'nightly'];
if (!allowedTags.includes(npmTag)) {
throw new Error(
`Failed to generate next version from "${currentVersion}" with type "${RELEASE_VERSION_TYPE}"`,
`Invalid npm tag: ${npmTag}. Allowed tags: ${allowedTags.join(', ')}`,
);
}

console.info(`Release ${RELEASE_TAG} version ${nextVersion}`);

// Update pkg version
console.info(`Updating version from ${currentVersion} to ${nextVersion}`);
pkg.version = nextVersion;
fs.writeJsonSync(PKG_PATH, pkg, { spaces: 2 });
const prereleaseTags = ['alpha', 'beta', 'rc', 'canary', 'nightly'];
if (
npmTag === 'latest' &&
prereleaseTags.some((tag) => publishVersion.includes(tag))
) {
throw Error(`Can't release ${publishVersion} to latest tag`);
}

// Write npmrc
const npmrcPath = `${process.env.HOME}/.npmrc`;
console.info(`Writing npmrc to ${npmrcPath}`);
fs.writeFileSync(
npmrcPath,
`//registry.npmjs.org/:_authToken=${RELEASE_NPM_TOKEN}`,
console.info(
`Release ${npmTag} version ${publishVersion}${isDryRun ? '(dry-run)' : ''}`,
);

// Publish to npm
console.info(`Publishing to npm with tag ${RELEASE_TAG}`);
const dryRun = RELEASE_DRY_RUN === 'true' ? ['--dry-run'] : [];
try {
await $`pnpm publish ${dryRun} --tag ${RELEASE_TAG} --no-git-checks --provenance`;
const flags = isDryRun
? ['--dry-run', `--tag`, npmTag, `--no-git-checks`]
: [`--tag`, npmTag, `--no-git-checks`];
await $`pnpm publish ${flags}`;
console.info(`Published successfully`);
} catch (e) {
console.error(`Publish failed: ${e.message}`);
process.exit(1);
} finally {
fs.removeSync(npmrcPath);
}

// Push tag to github
if (RELEASE_DRY_RUN !== 'true') {
// Push tag to GitHub
if (!isDryRun) {
console.info(`Pushing tag to github`);
const tagName = `v${nextVersion}`;
const tagName = `v${publishVersion}`;
try {
await $`git config --global --add safe.directory /github/workspace`;
await $`git config --global user.name "github-actions[bot]"`;
Expand All @@ -64,17 +71,6 @@ if (RELEASE_DRY_RUN !== 'true') {
console.error(`Push tag failed: ${e.message}`);
process.exit(1);
}

try {
await $`git add --all`;
const commitMsg = `release ${tagName}`;
await $`git commit -m ${commitMsg}`;
await $`git push`;
console.info(`Pushed branch successfully`);
} catch (e) {
console.error(`Update branch failed: ${e.message}`);
process.exit(1);
}
}

console.info(`Release completed`);