Release Workflow #98
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: "Release Workflow" | |
# Manual trigger workflow to automatically setup, build and push a new release (or prerelease) on NPM | |
on: | |
workflow_dispatch: | |
inputs: | |
releaseType: | |
description: 'Release type' | |
required: true | |
default: 'prerelease' | |
type: choice | |
options: | |
- prerelease | |
- patch | |
- minor | |
- major | |
prereleaseName: | |
description: 'Prerelease name (ignore if release type is not `prerelease`)' | |
default: 'alpha' | |
type: string | |
concurrency: | |
group: "${{ github.workflow }}-${{ github.ref_name }}" | |
cancel-in-progress: true | |
jobs: | |
publish_version: | |
name: "Publish version" | |
runs-on: ubuntu-latest | |
steps: | |
- name: "Checkout repository" | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
- name: "Setup" | |
uses: ./.github/actions/setup | |
- name: "Create version" | |
id: version | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const refType = '${{ github.ref_type }}'; | |
const refName = '${{ github.ref_name }}'; | |
if (refType !== 'branch') { | |
console.log(`Release workflow can only be run from a branch.\n`); | |
process.exit(1); | |
} | |
const run = require('util').promisify(require('child_process').exec); | |
const lodash = require('lodash'); | |
const semver = require('semver'); | |
const releaseType = '${{ inputs.releaseType }}' || 'prerelease'; | |
console.log(`Release type: ${releaseType}`); | |
const prereleaseName = lodash.kebabCase('${{ inputs.prereleaseName }}' || 'alpha'); | |
const getVersion = (tag) => run(`npm view @lumx/core@${tag} version`).then(({ stdout }) => stdout.trim()); | |
const npmLatestVersion = await getVersion('latest'); | |
if (releaseType !== 'prerelease') { | |
// Exit if not on master | |
if (refName !== 'master') { | |
console.log(`New ${releaseType} release can only be created from master.\n`); | |
process.exit(1); | |
} | |
const localVersion = require('./lerna.json').version; | |
if (localVersion !== npmLatestVersion) { | |
console.log(`NPM latest version (${npmLatestVersion}) does not match the local latest version (${localVersion}).\n`); | |
process.exit(1); | |
} | |
// Check that the changelog has unreleased changes. | |
try { | |
await run('yarn changelog-verify --unreleased'); | |
} catch(err) { | |
console.log(err); | |
process.exit(1); | |
} | |
} else { | |
console.log(`Prerelease name: ${prereleaseName}`); | |
} | |
// Get NPM dist tag | |
const distTag = releaseType === 'prerelease' ? prereleaseName : 'latest'; | |
console.log(`NPM dist tag: ${distTag}`); | |
// Get base version (version from which to increment) | |
let baseVersion = await getVersion(distTag) | |
// Prerelease should start with latest NPM version + patch (ex: 'v1.0.0' => 'v1.0.1-alpha.0') | |
if (releaseType === 'prerelease' && (!baseVersion || !baseVersion.startsWith(semver.inc(npmLatestVersion, 'patch')))) { | |
baseVersion = npmLatestVersion; | |
} | |
console.log(`${releaseType} base version: ${baseVersion}`); | |
// Increment version | |
const nextVersion = semver.inc(baseVersion, releaseType, prereleaseName); | |
console.log(`New ${releaseType} version: ${nextVersion}`); | |
// Checkout new branch (lerna version requires this) | |
const branch = `release/${nextVersion}`; | |
await run(`git checkout -b ${branch}`); | |
// Update version in all packages | |
await run(`yarn lerna version --no-git-tag-version --yes ${nextVersion}`); | |
// Update yarn.lock with new package versions | |
await run(`YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install`); | |
// Update version in changelog (need to run in a package which has a version, so not the root package) | |
await run(`yarn workspace @lumx/core update-version-changelog`); | |
return { nextVersion, distTag, branch, releaseType, refName }; | |
- name: "Build libs" | |
run: yarn build:libs | |
- name: "Publish version to NPM" | |
env: | |
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
DIST_TAG: ${{ fromJSON(steps.version.outputs.result).distTag }} | |
run: | | |
for package in $(echo packages/lumx-*); | |
do | |
(echo "Publishing $package"; cd $package/dist; npm publish --tag $DIST_TAG) | |
done | |
- name: "Git commit, tag & push" | |
if: ${{ fromJSON(steps.version.outputs.result).releaseType != 'prerelease' }} | |
id: git | |
run: | | |
git config --global user.name "github-actions" | |
git config --global user.email "[email protected]" | |
branch="${{ fromJSON(steps.version.outputs.result).branch }}" | |
echo "branch=$branch" >> $GITHUB_OUTPUT | |
tag="v${{ fromJSON(steps.version.outputs.result).nextVersion }}" | |
echo "tag=$tag" >> $GITHUB_OUTPUT | |
# Commit and push branch | |
commit="chore(release): release $tag" | |
echo "commit=$commit" >> $GITHUB_OUTPUT | |
git commit -am "$commit" | |
git push origin "$branch" | |
# TODO: need to a new git user to push tags | |
# Tag and push tag | |
#git tag "$tag" | |
#git push origin "$tag" | |
outputs: | |
releaseType: ${{ fromJSON(steps.version.outputs.result).releaseType }} | |
baseRef: ${{ fromJSON(steps.version.outputs.result).refName }} | |
commit: ${{ steps.git.outputs.commit }} | |
branch: ${{ steps.git.outputs.branch }} | |
versionTag: ${{ steps.git.outputs.tag }} | |
create_gh_pull_request: | |
if: ${{ needs.publish_version.outputs.releaseType != 'prerelease' }} | |
name: "Create pull request" | |
runs-on: ubuntu-latest | |
needs: [ publish_version ] | |
steps: | |
- name: "Create pull request" | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
github.rest.pulls.create({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
title: '${{ needs.publish_version.outputs.commit }}', | |
head: '${{ needs.publish_version.outputs.branch }}', | |
base: '${{ needs.publish_version.outputs.baseRef }}', | |
body: 'https://github.com/lumapps/design-system/releases/tag/${{ needs.publish_version.outputs.versionTag }}\nTODO: `git tag ${{ needs.publish_version.outputs.versionTag }}` & `git push origin ${{ needs.publish_version.outputs.versionTag }}`', | |
draft: false, | |
}); |