From 3ea864ca745508ec7ab898a45a5fde9c9f32ed67 Mon Sep 17 00:00:00 2001 From: Guillaume Cornut Date: Tue, 27 Aug 2024 15:25:00 +0200 Subject: [PATCH] chore(workflow): rework the release workflow --- .github/actions/release-note/action.yml | 7 +- .github/actions/release-note/index.js | 19 +- .github/actions/utils.js | 6 +- .github/workflows/release-build-site.yml | 68 ------- .../workflows/release-deploy-chromatic.yaml | 47 ----- .../workflows/release-github-release-note.yml | 26 --- .github/workflows/release-prepare.yml | 75 ++++++++ .github/workflows/release-publish.yaml | 171 ++++++++++++++++++ .github/workflows/release.yml | 100 ---------- 9 files changed, 260 insertions(+), 259 deletions(-) delete mode 100644 .github/workflows/release-build-site.yml delete mode 100644 .github/workflows/release-deploy-chromatic.yaml delete mode 100644 .github/workflows/release-github-release-note.yml create mode 100644 .github/workflows/release-prepare.yml create mode 100644 .github/workflows/release-publish.yaml delete mode 100644 .github/workflows/release.yml diff --git a/.github/actions/release-note/action.yml b/.github/actions/release-note/action.yml index 0f2b592a6..02b92e927 100644 --- a/.github/actions/release-note/action.yml +++ b/.github/actions/release-note/action.yml @@ -1,11 +1,6 @@ name: 'Release note' description: 'Create GitHub release with autogenerated notes (coming from the CHANGELOG)' -inputs: - versionTag: - description: The version tag for the release - required: true - runs: using: composite steps: @@ -13,4 +8,4 @@ runs: with: script: | const main = require('.github/actions/release-note/index.js'); - await main({ versionTag: '${{ inputs.versionTag}}', context, github }); + await main({ context, github }); diff --git a/.github/actions/release-note/index.js b/.github/actions/release-note/index.js index 5eca295a3..9f6c928e5 100644 --- a/.github/actions/release-note/index.js +++ b/.github/actions/release-note/index.js @@ -22,16 +22,18 @@ async function getLatestVersionChangelog() { /** * Generate release note and create a release on GH. */ -async function main({ versionTag, github, context }) { - const [{ version, versionChangelog }, storybookURL] = await Promise.all([ - getLatestVersionChangelog(), - getStoryBookURL(versionTag), - ]); +async function main({ github, context }) { + const storybookURLPromise = getStoryBookURL(context.sha); + const { version, versionChangelog } = await getLatestVersionChangelog(); + const versionTag = `v${version}`; + // Related links const changelogURL = `https://github.com/lumapps/design-system/blob/${versionTag}/CHANGELOG.md`; + const storyBookURL = await storybookURLPromise; + const links = `[🎨 StoryBook](${storyBookURL}) - [📄 See changelog history](${changelogURL})`; // Release notes - const body = `### [🎨 StoryBook](${storybookURL})\n\n### [📄 Changelog](${changelogURL})\n\n${versionChangelog}`; + const body = `${versionChangelog}\n\n${links}`; await github.rest.repos.createRelease({ draft: false, @@ -40,7 +42,7 @@ async function main({ versionTag, github, context }) { owner: context.repo.owner, repo: context.repo.repo, tag_name: versionTag, - name: `v${version}`, + name: versionTag, body, }); } @@ -49,8 +51,7 @@ module.exports = main; // Example use (run with `node .github/actions/release-note/index.js`) if (require.main === module) main({ - versionTag: 'v3.0.5', - context: { repo: { repo: 'design-system', owner: 'lumapps' } }, + context: { repo: { repo: 'design-system', owner: 'lumapps' }, sha: 'cdde1f3d1' }, // Mocked GH API github: { rest: { repos: { createRelease: console.log } } }, }); diff --git a/.github/actions/utils.js b/.github/actions/utils.js index a23af05f9..2a30ecd5a 100644 --- a/.github/actions/utils.js +++ b/.github/actions/utils.js @@ -1,10 +1,10 @@ +const util = require('util'); +const exec = util.promisify(require('child_process').exec); + /** * Get short SHA for git ref. */ async function getShortSHA(gitRef) { - const util = require('util'); - const exec = util.promisify(require('child_process').exec); - return exec(`git rev-parse --short ${gitRef}`) .then(({ stdout }) => stdout.trim()); } diff --git a/.github/workflows/release-build-site.yml b/.github/workflows/release-build-site.yml deleted file mode 100644 index 8ebce9092..000000000 --- a/.github/workflows/release-build-site.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: "Build & Push Demo Site" - -# Build and push the demo site on the docker registry when a new release tag is pushed on GitHub - -on: - push: - tags: - - v* - -concurrency: - group: "${{ github.workflow }}-${{ github.ref_name }}" - cancel-in-progress: true - -jobs: - build_demo_site: - name: "Build & push demo site" - timeout-minutes: 30 - runs-on: ubuntu-latest - env: - GCP_PROD_REGISTRY: gcr.io/lumapps-registry - steps: - - name: "Checkout repository" - uses: actions/checkout@v3 - - - name: "Login to GCR" - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a - with: - registry: gcr.io - username: _json_key - password: ${{ secrets.GCR_PROD_RW_CREDS }} - - - name: "Setup buildx" - id: buildx_setup - uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 - with: - install: true - - - run: | - echo "git_commit=$(git rev-parse HEAD)" >> $GITHUB_ENV - echo "build_date=$(date --rfc-3339=seconds)" >> $GITHUB_ENV - - - name: "Docker metadata" - id: meta - uses: docker/metadata-action@f206c36955d3cc6213c38fb3747d9ba4113e686a - with: - tags: | - type=match,pattern=/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ - type=raw,enable=true,priority=200,value=${{ env.git_commit }},event=tag - images: | - ${{ env.GCP_PROD_REGISTRY }}/design-system - labels: | - com.lumapps.image.created=${{ env.build_date }} - com.lumapps.image.sha1=${{ env.git_commit }} - com.lumapps.image.authors=frontend@lumapps.com - com.lumapps.image.version={{tag}} - - - name: "Build image" - uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 - with: - context: ./ - file: ${{ matrix.dockerfile }} - builder: ${{ steps.buildx_setup.outputs.name }} - build-args: version=${{ env.version }} - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha, scope=${{ github.workflow }} - cache-to: type=gha, scope=${{ github.workflow }}, mode=max diff --git a/.github/workflows/release-deploy-chromatic.yaml b/.github/workflows/release-deploy-chromatic.yaml deleted file mode 100644 index fbe897dad..000000000 --- a/.github/workflows/release-deploy-chromatic.yaml +++ /dev/null @@ -1,47 +0,0 @@ -name: "Deploy Chromatic Release" - -# Deploy chromatic when a new release commit is pushed on master - -on: - push: - branches: - - master - -concurrency: - group: chromatic-release-${{ github.head_ref }} - cancel-in-progress: true - -jobs: - deploy_chromatic: - name: "Deploy chromatic" - runs-on: ubuntu-latest - steps: - - name: "Checkout repository" - uses: actions/checkout@v3 - with: - fetch-depth: 0 # retrieve all the repo history (required by chromatic) - - - name: "Check is release commit" - id: check - env: - GH_TOKEN: ${{ github.token }} - run: | - set -x # verbose - message=$(git show -s --format=%s) - - # Check is release commit - if [[ "$message" == 'chore(release): release'* ]]; then - echo "is_release_commit=true" >> "$GITHUB_OUTPUT" - fi - - - name: "Setup" - if: ${{ steps.check.outputs.is_release_commit == 'true' }} - uses: ./.github/actions/setup - - - name: "Deploy chromatic" - if: ${{ steps.check.outputs.is_release_commit == 'true' }} - uses: chromaui/action@3f82bf5d065290658af8add6dce946809ee0f923 #v6.1.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - projectToken: ${{ secrets.CHROMATIC_TOKEN }} - buildScriptName: build:storybook diff --git a/.github/workflows/release-github-release-note.yml b/.github/workflows/release-github-release-note.yml deleted file mode 100644 index 1c8891457..000000000 --- a/.github/workflows/release-github-release-note.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: "Create GitHub Release Notes" - -# Generate a release note when a new release tag is pushed on GitHub - -on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - -concurrency: - group: "${{ github.workflow }}-${{ github.ref_name }}" - cancel-in-progress: true - -jobs: - create_gh_release: - name: "Create release note" - runs-on: ubuntu-latest - steps: - - name: "Checkout repository" - uses: actions/checkout@v3 - - - name: "Create release note" - uses: ./.github/actions/release-note - with: - versionTag: ${{ github.ref_name }} - diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml new file mode 100644 index 000000000..3a4e2ba66 --- /dev/null +++ b/.github/workflows/release-prepare.yml @@ -0,0 +1,75 @@ +name: "Prepare Release Workflow" + +# Manual trigger workflow to automatically setup a new release PR (built & publish on merge) + +on: + workflow_dispatch: + inputs: + releaseType: + description: 'Release type' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + +concurrency: + group: "${{ github.workflow }}-${{ github.ref_name }}" + cancel-in-progress: true + +jobs: + prepare_release: + name: "Prepare Release" + runs-on: ubuntu-latest + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + with: + token: ${{ secrets.GITBOT_TOKEN }} + fetch-depth: 0 + + - name: "Setup" + uses: ./.github/actions/setup + + - name: "Increment package versions" + id: version + uses: ./.github/actions/increment-package-versions + with: + releaseType: '${{ inputs.releaseType }}' + + - name: "Check build libs" + run: yarn build:libs + + - name: "Git commit & push" + id: git + run: | + set -x # verbose + git config --global user.name "lumbot" + git config --global user.email "lumbot@users.noreply.github.com" + + # Commit + commit="chore(release): release v${{ steps.version.outputs.nextVersion }}" + echo "commit=$commit" >> $GITHUB_OUTPUT + git commit -am "$commit" + + # Push + git push origin "${{ steps.version.outputs.releaseBranch }}" + + - name: "Create pull request" + uses: actions/github-script@v6 + with: + github-token: '${{ secrets.GITBOT_TOKEN }}' + script: | + github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + base: 'master', + head: '${{ steps.version.outputs.releaseBranch }}', + title: '${{ steps.git.outputs.commit }}', + body: '# Release v${{ steps.version.outputs.nextVersion }}\n\n' + + 'Review, test and merge to publish to NPM.\n\n' + + 'Triggered by @${{ github.actor }}', + draft: false, + }); diff --git a/.github/workflows/release-publish.yaml b/.github/workflows/release-publish.yaml new file mode 100644 index 000000000..1c2608ce6 --- /dev/null +++ b/.github/workflows/release-publish.yaml @@ -0,0 +1,171 @@ +name: "Publish Release Workflow" + +# When merging release commit on master +# - Build & publish NPM libs +# - Create & push git tag +# - Build & publish demo site docker image +# - Deploy chromatic +# - Create GH release notes + +on: + push: + branches: + - master + +concurrency: + group: "${{ github.workflow }}-${{ github.ref_name }}" + cancel-in-progress: true + +jobs: + is_release_commit: + name: "Check is release commit" + runs-on: ubuntu-latest + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha || env.GITHUB_SHA }} + + - name: "Check is release commit" + id: check + run: | + set -x # verbose + message=$(git show -s --format=%s) + version=$(echo $message | egrep -o '[0-9]+\.[0-9]+\.[0-9]+' || true) + + # Check is release commit has version + if [[ "$message" == 'chore(release): release v'* ]] && [ -n "$version" ]; then + echo "version=$version" >> "$GITHUB_OUTPUT" + fi + outputs: + version: ${{ steps.check.outputs.version }} + + build_publish_NPM: + name: "Build & publish NPM libs" + needs: [is_release_commit] + if: ${{ needs.is_release_commit.outputs.version }} + runs-on: ubuntu-latest + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + with: + token: '${{ secrets.GITBOT_TOKEN }}' + fetch-depth: 0 + + - name: "Setup" + uses: ./.github/actions/setup + + - name: "Build libs" + run: yarn build:libs + + - name: "Publish version to NPM" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + for package in $(echo packages/lumx-*); + do + (echo "Publishing $package"; cd $package/dist; npm publish --tag latest) + done + + - name: "Git tag" + id: git + run: | + set -x + + # Create tag + tag="v${{ needs.is_release_commit.outputs.version }}" + git tag "$tag" + + # Push tag + git push origin "$tag" + + deploy_chromatic: + name: "Deploy chromatic" + needs: [build_publish_NPM] + runs-on: ubuntu-latest + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + with: + fetch-depth: 0 # retrieve all the repo history (required by chromatic) + + - name: "Setup" + uses: ./.github/actions/setup + + - name: "Deploy chromatic" + uses: chromaui/action@3f82bf5d065290658af8add6dce946809ee0f923 #v6.1.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + projectToken: ${{ secrets.CHROMATIC_TOKEN }} + buildScriptName: build:storybook + + build_demo_site: + name: "Build & push demo site" + needs: [build_publish_NPM] + timeout-minutes: 30 + runs-on: ubuntu-latest + env: + GCP_PROD_REGISTRY: gcr.io/lumapps-registry + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: "Login to GCR" + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + registry: gcr.io + username: _json_key + password: ${{ secrets.GCR_PROD_RW_CREDS }} + + - name: "Setup buildx" + id: buildx_setup + uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 + with: + install: true + + - run: | + echo "git_commit=$(git rev-parse HEAD)" >> $GITHUB_ENV + echo "build_date=$(date --rfc-3339=seconds)" >> $GITHUB_ENV + + - name: "Docker metadata" + id: meta + uses: docker/metadata-action@f206c36955d3cc6213c38fb3747d9ba4113e686a + with: + tags: | + type=match,pattern=/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + type=raw,enable=true,priority=200,value=${{ env.git_commit }},event=tag + images: | + ${{ env.GCP_PROD_REGISTRY }}/design-system + labels: | + com.lumapps.image.created=${{ env.build_date }} + com.lumapps.image.sha1=${{ env.git_commit }} + com.lumapps.image.authors=frontend@lumapps.com + com.lumapps.image.version={{tag}} + + - name: "Build image" + uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 + with: + context: ./ + file: ${{ matrix.dockerfile }} + builder: ${{ steps.buildx_setup.outputs.name }} + build-args: version=${{ env.version }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha, scope=${{ github.workflow }} + cache-to: type=gha, scope=${{ github.workflow }}, mode=max + + create_gh_release: + name: "Create release note" + needs: [build_publish_NPM] + runs-on: ubuntu-latest + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + + - name: "Create release note" + uses: ./.github/actions/release-note + + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index bceeb508e..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: "Release Workflow" - -# Manual trigger workflow to automatically setup, build and push a new release on NPM - -on: - workflow_dispatch: - inputs: - releaseType: - description: 'Release type' - required: true - default: 'patch' - type: choice - options: - - patch - - minor - - major - -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: "Increment package versions" - id: version - uses: ./.github/actions/increment-package-versions - with: - releaseType: '${{ inputs.releaseType }}' - - - name: "Build libs" - run: yarn build:libs - - - name: "Publish version to NPM" - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - DIST_TAG: ${{ steps.version.outputs.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" - id: git - run: | - git config --global user.name "github-actions" - git config --global user.email "github-actions@users.noreply.github.com" - - branch="${{ steps.version.outputs.releaseBranch }}" - echo "branch=$branch" >> $GITHUB_OUTPUT - - tag="v${{ steps.version.outputs.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: ${{ inputs.releaseType }} - commit: ${{ steps.git.outputs.commit }} - branch: ${{ steps.git.outputs.branch }} - versionTag: ${{ steps.git.outputs.tag }} - - create_gh_pull_request: - 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: 'master', - 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, - });