name: Release
on:
- workflow_dispatch:
- inputs:
- branch:
- description: 'Branch to publish'
- required: true
- default: 'main'
- type: choice
- options:
- - main
- - minor
- bump:
- description: 'Bump version'
- required: true
- default: 'patch'
- type: choice
- options:
- - patch
- - minor
- - prepatch
- - preminor
- - custom
- custom_version:
- description: 'Custom version'
- required: false
- default: ''
- type: string
+ push:
+ tags:
+ - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
release:
steps:
- name: Checkout
uses: actions/checkout@v4
- with:
- ref: ${{ inputs.branch }}
- fetch-depth: 0 # need this to get tags for changelog generation
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install deps
run: pnpm install
- - name: Configure git user as vue bot
- run: |
- git config user.name "vue-bot"
- git config user.email "<bot@vuejs.org>"
-
- - name: Import GPG key
- uses: crazy-max/ghaction-import-gpg@v6
- with:
- gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
- passphrase: ${{ secrets.GPG_PASSPHRASE }}
- git_user_signingkey: true
- git_commit_gpgsign: true
-
- - name: Run release script
- id: release
+ - name: Build and publish
+ id: publish
run: |
- pnpm release ${{ inputs.bump != 'custom' && inputs.bump || inputs.custom_version }} --skipPrompts
- RELEASE_TAG=$(git describe --tags --abbrev=0)
- echo "tag=$RELEASE_TAG" >> $GITHUB_OUTPUT
+ pnpm release --publishOnly
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- - name: Push tags
- run: git push -u origin ${{ inputs.branch }} --follow-tags
-
- - name: Create Release for Tag
+ - name: Create GitHub release
id: release_tag
uses: yyx990803/release-tag@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
- tag_name: ${{ steps.release.outputs.tag }}
+ tag_name: ${{ github.ref }}
body: |
For stable releases, please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/main/CHANGELOG.md) for details.
For pre-releases, please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/minor/CHANGELOG.md) of the `minor` branch.
skipPrompts: {
type: 'boolean',
},
+ publish: {
+ type: 'boolean',
+ default: false,
+ },
+ publishOnly: {
+ type: 'boolean',
+ },
},
})
}
}
- if (!skipTests) {
- step('Checking CI status for HEAD...')
- let isCIPassed = await getCIResult()
- skipTests ||= isCIPassed
-
- if (isCIPassed) {
- if (!skipPrompts) {
- /** @type {{ yes: boolean }} */
- const { yes: promptSkipTests } = await prompt({
- type: 'confirm',
- name: 'yes',
- message: `CI for this commit passed. Skip local tests?`,
- })
- skipTests = promptSkipTests
- } else {
- skipTests = true
- }
- } else if (skipPrompts) {
- throw new Error(
- 'CI for the latest commit has not passed yet. ' +
- 'Only run the release workflow after the CI has passed.',
- )
- }
- }
-
- if (!skipTests) {
- step('\nRunning tests...')
- if (!isDryRun) {
- await run('pnpm', ['run', 'test', '--run'])
- } else {
- console.log(`Skipped (dry run)`)
- }
- } else {
- step('Tests skipped.')
- }
+ await runTestsIfNeeded()
// update all package versions and inter-dependencies
step('\nUpdating cross dependencies...')
)
versionUpdated = true
- // build all packages with types
- step('\nBuilding all packages...')
- if (!skipBuild && !isDryRun) {
- await run('pnpm', ['run', 'build', '--withTypes'])
- step('\nTesting built types...')
- await run('pnpm', ['test-dts-only'])
- } else {
- console.log(`(skipped)`)
- }
-
// generate changelog
step('\nGenerating changelog...')
await run(`pnpm`, ['run', 'changelog'])
}
// publish packages
- step('\nPublishing packages...')
-
- const additionalPublishFlags = []
- if (isDryRun) {
- additionalPublishFlags.push('--dry-run')
- }
- if (isDryRun || skipGit) {
- additionalPublishFlags.push('--no-git-checks')
- }
- // bypass the pnpm --publish-branch restriction which isn't too useful to us
- // otherwise it leads to a prompt and blocks the release script
- const branch = await getBranch()
- if (branch !== 'main') {
- additionalPublishFlags.push('--publish-branch', branch)
- }
- // add provenance metadata when releasing from CI
- // canary release commits are not pushed therefore we don't need to add provenance
- if (process.env.CI && !isCanary) {
- additionalPublishFlags.push('--provenance')
- }
-
- for (const pkg of packages) {
- await publishPackage(pkg, targetVersion, additionalPublishFlags)
+ if (args.publish) {
+ await buildPackages()
+ await publishPackages(targetVersion)
+ } else {
+ console.log(
+ pico.yellow(
+ '\nPublish step skipped (will be done in GitHub actions on successful push)',
+ ),
+ )
}
// push to GitHub
console.log()
}
+async function runTestsIfNeeded() {
+ if (!skipTests) {
+ step('Checking CI status for HEAD...')
+ let isCIPassed = await getCIResult()
+ skipTests ||= isCIPassed
+
+ if (isCIPassed) {
+ if (!skipPrompts) {
+ /** @type {{ yes: boolean }} */
+ const { yes: promptSkipTests } = await prompt({
+ type: 'confirm',
+ name: 'yes',
+ message: `CI for this commit passed. Skip local tests?`,
+ })
+ skipTests = promptSkipTests
+ } else {
+ skipTests = true
+ }
+ } else if (skipPrompts) {
+ throw new Error(
+ 'CI for the latest commit has not passed yet. ' +
+ 'Only run the release workflow after the CI has passed.',
+ )
+ }
+ }
+
+ if (!skipTests) {
+ step('\nRunning tests...')
+ if (!isDryRun) {
+ await run('pnpm', ['run', 'test', '--run'])
+ } else {
+ console.log(`Skipped (dry run)`)
+ }
+ } else {
+ step('Tests skipped.')
+ }
+}
+
async function getCIResult() {
try {
const sha = await getSha()
})
}
+async function buildPackages() {
+ step('\nBuilding all packages...')
+ if (!skipBuild) {
+ await run('pnpm', ['run', 'build', '--withTypes'])
+ } else {
+ console.log(`(skipped)`)
+ }
+}
+
+/**
+ * @param {string} version
+ */
+async function publishPackages(version) {
+ // publish packages
+ step('\nPublishing packages...')
+
+ const additionalPublishFlags = []
+ if (isDryRun) {
+ additionalPublishFlags.push('--dry-run')
+ }
+ if (isDryRun || skipGit) {
+ additionalPublishFlags.push('--no-git-checks')
+ }
+ // bypass the pnpm --publish-branch restriction which isn't too useful to us
+ // otherwise it leads to a prompt and blocks the release script
+ const branch = await getBranch()
+ if (branch !== 'main') {
+ additionalPublishFlags.push('--publish-branch', branch)
+ }
+ // add provenance metadata when releasing from CI
+ // canary release commits are not pushed therefore we don't need to add provenance
+ if (process.env.CI && !isCanary) {
+ additionalPublishFlags.push('--provenance')
+ }
+
+ for (const pkg of packages) {
+ await publishPackage(pkg, version, additionalPublishFlags)
+ }
+}
+
/**
* @param {string} pkgName
* @param {string} version
}
}
-main().catch(err => {
+async function publishOnly() {
+ await buildPackages()
+ await publishPackages(currentVersion)
+}
+
+const fnToRun = args.publishOnly ? publishOnly : main
+
+fnToRun().catch(err => {
if (versionUpdated) {
// revert to current version on failed releases
updateVersions(currentVersion)