ci: canary and internal releases [skip ci] (#11565)

- Adds support for numeric canary versions ie. `3.28.0-canary.0`,
subsequent prereleases will increment accordingly (like Next.js)
- _Our old way of doing canary releases_ is still available but will now
be tagged as `internal` ex. `3.28.0-internal.shorthash`
- Releases are triggered via workflow dispatch in Actions. Triggers off
of main will be released as `canary`, all others will be `internal`.
This commit is contained in:
Elliot DeNolf
2025-03-05 23:19:01 -05:00
committed by GitHub
parent 1e708bdd12
commit 179778223f
5 changed files with 67 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
name: release-canary
name: publish-prerelease
on:
workflow_dispatch:
@@ -11,7 +11,7 @@ env:
jobs:
release:
name: release-canary-${{ github.ref_name }}-${{ github.sha }}
name: publish-prerelease-${{ github.ref_name }}-${{ github.sha }}
permissions:
id-token: write
runs-on: ubuntu-24.04
@@ -27,8 +27,19 @@ jobs:
run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Canary release script
run: pnpm release:canary
- name: Determine release type
id: determine_release_type
# Use 'canary' for main branch, 'internal' for others
run: |
if [[ ${{ github.ref_name }} == "main" ]]; then
echo "::set-output name=release_type::canary"
else
echo "::set-output name=release_type::internal"
fi
- name: Release
run: pnpm publish-prerelease --tag ${{ steps.determine_release_type.outputs.release_type }}
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true

View File

@@ -81,10 +81,9 @@
"prepare": "husky",
"prepare-run-test-against-prod": "pnpm bf && rm -rf test/packed && rm -rf test/node_modules && rm -rf app && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd ..",
"prepare-run-test-against-prod:ci": "rm -rf test/node_modules && rm -rf app && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd ..",
"publish-prerelease": "pnpm --filter releaser publish-prerelease",
"reinstall": "pnpm clean:all && pnpm install",
"release": "pnpm --filter releaser release --tag latest",
"release:beta": "pnpm runts ./scripts/release.ts --bump prerelease --tag beta",
"release:canary": "pnpm --filter releaser release:canary",
"runts": "cross-env NODE_OPTIONS=--no-deprecation node --no-deprecation --import @swc-node/register/esm-register",
"script:build-template-with-local-pkgs": "pnpm --filter scripts build-template-with-local-pkgs",
"script:gen-templates": "pnpm --filter scripts gen-templates",

View File

@@ -29,8 +29,8 @@
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"list-published": "tsx src/lib/getPackageRegistryVersions.ts",
"publish-prerelease": "tsx src/publish-prerelease.ts",
"release": "tsx src/release.ts",
"release:canary": "tsx src/publish-canary.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {

View File

@@ -27,7 +27,7 @@ type PackageDetails = {
version: string
}
type PackageReleaseType = 'canary' | ReleaseType
type PackageReleaseType = 'canary' | 'internal' | ReleaseType
type PublishResult = {
name: string
@@ -140,11 +140,42 @@ export const getWorkspace = async () => {
const { version: monorepoVersion, packages: packageDetails } = await getCurrentPackageState()
let nextReleaseVersion
if (bumpType === 'canary') {
if (bumpType === 'internal') {
const hash = execSync('git rev-parse --short HEAD', { encoding: 'utf8' }).trim().slice(0, 7)
nextReleaseVersion = semver.inc(monorepoVersion, 'minor') + `-canary.${hash}`
nextReleaseVersion = semver.inc(monorepoVersion, 'minor') + `-internal.${hash}`
} else if (bumpType === 'canary') {
const minorCandidateBaseVersion = semver.inc(monorepoVersion, 'minor')
if (!minorCandidateBaseVersion) {
throw new Error(`Could not determine minor candidate version from ${monorepoVersion}`)
}
// Get latest canary version from registry
const json = await fetch(`https://registry.npmjs.org/payload`).then((res) => res.json())
const { canary: latestCanaryVersion } = (json['dist-tags'] ?? {}) as {
canary?: string | undefined
}
console.log(`Latest canary version: ${latestCanaryVersion}`)
if (
latestCanaryVersion?.startsWith(minorCandidateBaseVersion) &&
latestCanaryVersion.includes('-canary.')
) {
const canaryIteration = Number(latestCanaryVersion.split('-canary.')[1])
if (isNaN(canaryIteration)) {
console.log(`Latest canary version is not a valid canary version, starting from 0`)
nextReleaseVersion = semver.inc(monorepoVersion, 'minor') + '-canary.0'
} else {
nextReleaseVersion = semver.inc(monorepoVersion, bumpType)
console.log(`Incrementing canary version from ${latestCanaryVersion}`)
nextReleaseVersion = `${minorCandidateBaseVersion}-canary.${canaryIteration + 1}`
}
} else {
console.log(`Latest canary does not match minor candidate, incrementing minor`)
nextReleaseVersion = semver.inc(monorepoVersion, 'minor') + '-canary.0'
}
} else {
throw new Error(`Invalid bump type: ${bumpType}. Only 'internal' and 'canary' are supported.`)
}
if (!nextReleaseVersion) {

View File

@@ -1,12 +1,25 @@
import chalk from 'chalk'
import minimist from 'minimist'
import { getWorkspace } from './lib/getWorkspace.js'
async function main() {
const args = minimist(process.argv.slice(2))
const { bump = 'minor', 'dry-run': dryRun, tag } = args
if (!tag || !['canary', 'internal'].includes(tag)) {
abort('Tag is required. Use --tag <canary|internal>')
}
console.log(`\n Bump: ${bump}`)
console.log(` Tag: ${tag}`)
console.log(` Dry Run: ${dryRun ? 'Enabled' : 'Disabled'}`)
const workspace = await getWorkspace()
await workspace.bumpVersion('canary')
await workspace.bumpVersion(tag)
await workspace.build()
await workspace.publishSync({ dryRun: false, tag: 'canary' })
await workspace.publishSync({ dryRun: dryRun ?? false, tag })
header('🎉 Done!')
}