Files
vercel__next.js/scripts/start-release.js
T
Zack Tanner 084f2bcf19 [ci]: trigger signed release commit via API (#93285)
Stacked on https://github.com/vercel/next.js/pull/93245

Commit signing is required for anything that lands on `canary`. Our
previous workflow of using a PAT to push a commit no longer works, since
that would have been an unsigned commit.

In #93245 we switched to an app token for release workflow steps. This
continues by:

- Telling Lerna to bump packages but not commit
- Creating a signed commit with the staged changes via GitHub's API
- Then running the publish flow

Test Plan:
Dry run
[here](https://github.com/vercel/next.js/actions/runs/25001287978/job/73211826479)
Commit
[here](https://github.com/vercel/next.js/commit/3a8456a62b56615e2f8c1d1e6e7b4e14ce89e078)

(cherry picked from commit 012fd7df4b)
2026-04-27 14:48:10 -07:00

114 lines
2.7 KiB
JavaScript

// @ts-check
const path = require('path')
const execa = require('execa')
const resolveFrom = require('resolve-from')
const {
configureGitHubAuth,
getGitHubToken,
getGitHubTokenMissingMessage,
verifyGitHubApiAccess,
} = require('./release-github-auth')
const { createGitHubReleaseCommit } = require('./release-github-api')
const SEMVER_TYPES = ['patch', 'minor', 'major']
async function main() {
const args = process.argv
const releaseType = args[args.indexOf('--release-type') + 1]
const semverType = args[args.indexOf('--semver-type') + 1]
const isCanary = releaseType === 'canary'
const isReleaseCandidate = releaseType === 'release-candidate'
const isBeta = releaseType === 'beta'
if (
releaseType !== 'stable' &&
releaseType !== 'canary' &&
releaseType !== 'release-candidate' &&
releaseType !== 'beta'
) {
console.log(
`Invalid release type ${releaseType}, must be stable, canary, release-candidate, or beta`
)
return
}
if (!isCanary && !SEMVER_TYPES.includes(semverType)) {
console.log(
`Invalid semver type ${semverType}, must be one of ${SEMVER_TYPES.join(
', '
)}`
)
return
}
const githubToken = getGitHubToken()
if (!githubToken) {
console.log(getGitHubTokenMissingMessage())
return
}
const configStorePath = resolveFrom(
path.join(process.cwd(), 'node_modules/release'),
'configstore'
)
const ConfigStore = require(configStorePath)
const config = new ConfigStore('release')
config.set('token', githubToken)
await configureGitHubAuth(githubToken)
await verifyGitHubApiAccess(
githubToken,
'/repos/vercel/next.js/releases?per_page=1',
'release lookup'
)
console.log(`Running pnpm release-${isCanary ? 'canary' : 'stable'}...`)
const preleaseType =
semverType === 'major'
? 'premajor'
: semverType === 'minor'
? 'preminor'
: 'prerelease'
const lernaArgs = [
'lerna',
'version',
isCanary || isReleaseCandidate || isBeta ? preleaseType : semverType,
]
if (isCanary) {
lernaArgs.push('--preid', 'canary')
} else if (isReleaseCandidate) {
lernaArgs.push('--preid', 'rc')
} else if (isBeta) {
lernaArgs.push('--preid', 'beta')
}
lernaArgs.push('--force-publish', '-y', '--no-push')
const child = execa('pnpm', lernaArgs, {
stdio: 'inherit',
})
await child
await createGitHubReleaseCommit(githubToken)
if (isCanary || isReleaseCandidate || isBeta) {
const releaseChild = execa(
'pnpm',
['release', '--pre', '--skip-questions', '--show-url'],
{
stdio: 'inherit',
}
)
await releaseChild
}
console.log('Release process is finished')
}
main()