From 91562a93a8efda08f2148fe807787d9ee1750528 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 23 Nov 2023 14:23:41 +0100 Subject: [PATCH 01/10] ci: support pre-release --- .github/workflows/pre-release.yml | 74 +++++++++++++ .github/workflows/release.yml | 169 ------------------------------ 2 files changed, 74 insertions(+), 169 deletions(-) create mode 100644 .github/workflows/pre-release.yml delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 000000000..a2fe54c79 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,74 @@ +name: pre-release + +on: + workflow_dispatch: + inputs: + dry-run: + type: boolean + description: 'Run release process in dry-run mode' + default: true + +permissions: + contents: read + +jobs: + release: + runs-on: ubuntu-latest + permissions: + # Needed to write the release changelog + contents: write + steps: + - name: Configure github token + uses: elastic/apm-pipeline-library/.github/actions/github-token@current + with: + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + + - name: Configure git user + uses: elastic/apm-pipeline-library/.github/actions/setup-git@current + with: + username: ${{ env.GIT_USER }} + email: ${{ env.GIT_EMAIL }} + token: ${{ env.GITHUB_TOKEN }} + + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ env.GITHUB_TOKEN }} + + - uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + + - name: Install dependencies + run: npm ci + + # This prevent lerna command from throwing this error: + # "Working tree has uncommitted changes, please commit or remove the following changes before continuing" + - name: Ignore git uncommitted changes + run: git update-index --skip-worktree .npmrc + + - name: Pre-release + env: + DRY_RUN: ${{ inputs.dry-run }} + run: npm run ci:pre-release + + status: + if: always() && inputs.dry-run == false + needs: + - release + runs-on: ubuntu-latest + steps: + - id: check + uses: elastic/apm-pipeline-library/.github/actions/check-dependent-jobs@current + with: + needs: ${{ toJSON(needs) }} + - uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current + with: + status: ${{ steps.check.outputs.status }} + vaultUrl: ${{ secrets.VAULT_ADDR }} + vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} + vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} + slackChannel: "#apm-agent-js" + message: "Build result for pre-release" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 8703c1edb..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: release - -on: - workflow_dispatch: - inputs: - dry-run: - type: boolean - description: 'Run release process in dry-run mode' - default: true - -permissions: - contents: read - -jobs: - release: - runs-on: ubuntu-latest - permissions: - # Needed to write the release changelog - contents: write - services: - verdaccio: - image: verdaccio/verdaccio:5 - ports: - - 4873:4873 - steps: - - name: Configure github token - uses: elastic/apm-pipeline-library/.github/actions/github-token@current - with: - url: ${{ secrets.VAULT_ADDR }} - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - - - name: Configure git user - uses: elastic/apm-pipeline-library/.github/actions/setup-git@current - with: - username: ${{ env.GIT_USER }} - email: ${{ env.GIT_EMAIL }} - token: ${{ env.GITHUB_TOKEN }} - - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - token: ${{ env.GITHUB_TOKEN }} - - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - - name: Install dependencies - run: npm ci - - - name: Read NPM vault secrets - if: inputs.dry-run == false - uses: hashicorp/vault-action@v2.7.3 - with: - method: approle - url: ${{ secrets.VAULT_ADDR }} - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - secrets: | - totp/code/npmjs-elasticmachine code | TOTP_CODE - - # This prevent lerna command from throwing this error: - # "Working tree has uncommitted changes, please commit or remove the following changes before continuing" - - name: Ignore git uncommitted changes - run: | - git update-index --skip-worktree .npmrc - - - name: Configure npm registry - uses: elastic/apm-pipeline-library/.github/actions/setup-npmrc@current - if: inputs.dry-run == false - with: - vault-url: ${{ secrets.VAULT_ADDR }} - vault-role-id: ${{ secrets.VAULT_ROLE_ID }} - vault-secret-id: ${{ secrets.VAULT_SECRET_ID }} - secret: secret/jenkins-ci/npmjs/elasticmachine - secret-key: token - - - name: Publish the release - env: - DRY_RUN: ${{ inputs.dry-run }} - run: npm run ci:release - - - name: Setup credentials - env: - DRY_RUN: ${{ inputs.dry-run }} - run: | - if [ "${DRY_RUN}" == "false" ]; then - echo 'ELASTIC_CDN_BUCKET_NAME=apm-rum-357700bc' >> ${GITHUB_ENV} - echo 'ELASTIC_CDN_CREDENTIALS=secret/gce/elastic-cdn/service-account/apm-rum-admin' >> ${GITHUB_ENV} - else - echo 'ELASTIC_CDN_BUCKET_NAME=oblt-apm-agent-rum-js-ci' >> ${GITHUB_ENV} - echo 'ELASTIC_CDN_CREDENTIALS=secret/observability-team/ci/service-account/apm-agent-rum-js' >> ${GITHUB_ENV} - fi - - - name: Read GCE vault secrets - uses: hashicorp/vault-action@v2.7.3 - with: - method: approle - url: ${{ secrets.VAULT_ADDR }} - roleId: ${{ secrets.VAULT_ROLE_ID }} - secretId: ${{ secrets.VAULT_SECRET_ID }} - secrets: | - ${{ env.ELASTIC_CDN_CREDENTIALS }} value | GOOGLE_CREDENTIALS ; - - - name: 'Authenticate to Google Cloud' - uses: 'google-github-actions/auth@v1' - with: - credentials_json: '${{ env.GOOGLE_CREDENTIALS }}' - create_credentials_file: true - - - id: prepare-release - name: 'Prepare CDN release' - run: echo "versions=$(npm run --silent ci:prepare-release)" >> ${GITHUB_OUTPUT} - - - id: 'upload-files-version' - if: ${{ always() && hashFiles('packages/rum/dist/bundles/*.js') }} - uses: 'google-github-actions/upload-cloud-storage@v1' - with: - parent: false - path: 'packages/rum/dist/bundles/' - destination: '${{ env.ELASTIC_CDN_BUCKET_NAME }}/${{ fromJSON(steps.prepare-release.outputs.versions).version }}' - glob: '*.js' - process_gcloudignore: false - headers: |- - cache-control: public,max-age=31536000,immutable - - - id: 'upload-files-major-version' - if: ${{ always() && hashFiles('packages/rum/dist/bundles/*.js') }} - uses: 'google-github-actions/upload-cloud-storage@v1' - with: - parent: false - path: 'packages/rum/dist/bundles/' - destination: '${{ env.ELASTIC_CDN_BUCKET_NAME }}/${{ fromJSON(steps.prepare-release.outputs.versions).major_version }}' - glob: '*.js' - process_gcloudignore: false - headers: |- - cache-control: public,max-age=604800,immutable - - - id: 'upload-file-index' - if: ${{ always() && hashFiles('index.html') }} - uses: 'google-github-actions/upload-cloud-storage@v1' - with: - parent: false - path: 'index.html' - destination: '${{ env.ELASTIC_CDN_BUCKET_NAME }}' - process_gcloudignore: false - headers: |- - cache-control: public,max-age=604800,immutable - - status: - if: always() - needs: - - release - runs-on: ubuntu-latest - steps: - - id: check - uses: elastic/apm-pipeline-library/.github/actions/check-dependent-jobs@current - with: - needs: ${{ toJSON(needs) }} - - uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current - if: inputs.dry-run == false - with: - status: ${{ steps.check.outputs.status }} - vaultUrl: ${{ secrets.VAULT_ADDR }} - vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} - vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} - slackChannel: "#apm-agent-js" - message: "Build result for release publication" From 163d9bc1c79434f7b8e51d8b837dc190c8aa3ba8 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 23 Nov 2023 15:34:22 +0100 Subject: [PATCH 02/10] ci: split pre-release versus release --- .github/workflows/pre-release.yml | 16 ++- .github/workflows/release.yml | 163 ++++++++++++++++++++++++++++++ package.json | 1 + scripts/ci-pre-release.js | 81 +++++++++++++++ scripts/ci-release.mjs | 12 +-- 5 files changed, 256 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 scripts/ci-pre-release.js diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index a2fe54c79..0424120e3 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -1,12 +1,10 @@ +--- +# When triggered it will prepare the release by creating a Pull Request with the +# changes to be merged, then the automation will run and release it. name: pre-release on: - workflow_dispatch: - inputs: - dry-run: - type: boolean - description: 'Run release process in dry-run mode' - default: true + workflow_dispatch: ~ permissions: contents: read @@ -49,13 +47,11 @@ jobs: - name: Ignore git uncommitted changes run: git update-index --skip-worktree .npmrc - - name: Pre-release - env: - DRY_RUN: ${{ inputs.dry-run }} + - name: Create PR with the release to be reviewed run: npm run ci:pre-release status: - if: always() && inputs.dry-run == false + if: always() needs: - release runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..3e930d57d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,163 @@ +--- +# When triggered it will publish the release only if the changes are related to the +# release +name: release + +on: + push: + branches: + - main + paths: + - 'CHANGELOG.md' + - 'package.json' + +permissions: + contents: read + +jobs: + release: + runs-on: ubuntu-latest + permissions: + # Needed to write the release changelog + contents: write + services: + verdaccio: + image: verdaccio/verdaccio:5 + ports: + - 4873:4873 + steps: + - name: Configure github token + uses: elastic/apm-pipeline-library/.github/actions/github-token@current + with: + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + token: ${{ env.GITHUB_TOKEN }} + + - uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + + - name: Install dependencies + run: npm ci + + - name: Read NPM vault secrets + if: inputs.dry-run == false + uses: hashicorp/vault-action@v2.7.3 + with: + method: approle + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + secrets: | + totp/code/npmjs-elasticmachine code | TOTP_CODE + + # This prevent lerna command from throwing this error: + # "Working tree has uncommitted changes, please commit or remove the following changes before continuing" + - name: Ignore git uncommitted changes + run: | + git update-index --skip-worktree .npmrc + + - name: Configure npm registry + uses: elastic/apm-pipeline-library/.github/actions/setup-npmrc@current + with: + vault-url: ${{ secrets.VAULT_ADDR }} + vault-role-id: ${{ secrets.VAULT_ROLE_ID }} + vault-secret-id: ${{ secrets.VAULT_SECRET_ID }} + secret: secret/jenkins-ci/npmjs/elasticmachine + secret-key: token + + - name: Publish the release + env: + DRY_RUN: true + run: npm run ci:release + + - name: Setup credentials + env: + DRY_RUN: true + run: | + if [ "${DRY_RUN}" == "false" ]; then + echo 'ELASTIC_CDN_BUCKET_NAME=apm-rum-357700bc' >> ${GITHUB_ENV} + echo 'ELASTIC_CDN_CREDENTIALS=secret/gce/elastic-cdn/service-account/apm-rum-admin' >> ${GITHUB_ENV} + else + echo 'ELASTIC_CDN_BUCKET_NAME=oblt-apm-agent-rum-js-ci' >> ${GITHUB_ENV} + echo 'ELASTIC_CDN_CREDENTIALS=secret/observability-team/ci/service-account/apm-agent-rum-js' >> ${GITHUB_ENV} + fi + + - name: Read GCE vault secrets + uses: hashicorp/vault-action@v2.7.3 + with: + method: approle + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + secrets: | + ${{ env.ELASTIC_CDN_CREDENTIALS }} value | GOOGLE_CREDENTIALS ; + + - name: 'Authenticate to Google Cloud' + uses: 'google-github-actions/auth@v1' + with: + credentials_json: '${{ env.GOOGLE_CREDENTIALS }}' + create_credentials_file: true + + - id: prepare-release + name: 'Prepare CDN release' + run: echo "versions=$(npm run --silent ci:prepare-release)" >> ${GITHUB_OUTPUT} + + - id: 'upload-files-version' + if: ${{ always() && hashFiles('packages/rum/dist/bundles/*.js') }} + uses: 'google-github-actions/upload-cloud-storage@v1' + with: + parent: false + path: 'packages/rum/dist/bundles/' + destination: '${{ env.ELASTIC_CDN_BUCKET_NAME }}/${{ fromJSON(steps.prepare-release.outputs.versions).version }}' + glob: '*.js' + process_gcloudignore: false + headers: |- + cache-control: public,max-age=31536000,immutable + + - id: 'upload-files-major-version' + if: ${{ always() && hashFiles('packages/rum/dist/bundles/*.js') }} + uses: 'google-github-actions/upload-cloud-storage@v1' + with: + parent: false + path: 'packages/rum/dist/bundles/' + destination: '${{ env.ELASTIC_CDN_BUCKET_NAME }}/${{ fromJSON(steps.prepare-release.outputs.versions).major_version }}' + glob: '*.js' + process_gcloudignore: false + headers: |- + cache-control: public,max-age=604800,immutable + + - id: 'upload-file-index' + if: ${{ always() && hashFiles('index.html') }} + uses: 'google-github-actions/upload-cloud-storage@v1' + with: + parent: false + path: 'index.html' + destination: '${{ env.ELASTIC_CDN_BUCKET_NAME }}' + process_gcloudignore: false + headers: |- + cache-control: public,max-age=604800,immutable + + status: + if: always() + needs: + - release + runs-on: ubuntu-latest + steps: + - id: check + uses: elastic/apm-pipeline-library/.github/actions/check-dependent-jobs@current + with: + needs: ${{ toJSON(needs) }} + - uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current + with: + status: ${{ steps.check.outputs.status }} + vaultUrl: ${{ secrets.VAULT_ADDR }} + vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} + vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} + slackChannel: "#apm-agent-js" + message: "Build result for release publication" diff --git a/package.json b/package.json index 68599be26..1a638b160 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "package:snapshot": "lerna exec npm pack", "clean": "lerna exec -- rm -rf dist/", "ci:prepare-release": "node ./scripts/ci-prepare-release.js", + "ci:pre-release": "node ./scripts/ci-pre-release.mjs", "ci:release": "node ./scripts/ci-release.mjs" }, "lint-staged": { diff --git a/scripts/ci-pre-release.js b/scripts/ci-pre-release.js new file mode 100644 index 000000000..314f08d4b --- /dev/null +++ b/scripts/ci-pre-release.js @@ -0,0 +1,81 @@ +/** + * MIT License + * + * Copyright (c) 2017-present, Elasticsearch BV + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +const { version } = require('../packages/rum/package.json') +import { execa } from 'execa' +const process = require('node:process') + +// Script logic +async function main() { + const githubToken = process.env.GITHUB_TOKEN + if (githubToken == null || githubToken === '') { + raiseError("The 'GITHUB_TOKEN' env var isn't defined") + } + try { + await execa('git', ['checkout', '-b', 'release/'+version], { + stdin: process.stdin + }) + .pipeStdout(process.stdout) + .pipeStderr(process.stderr) + } catch (err) { + raiseError('Failed to create git branch') + } + + try { + await execa('npx', ['lerna', 'version', '--yes'], { + stdin: process.stdin, + env: { + GH_TOKEN: githubToken + } + }) + .pipeStdout(process.stdout) + .pipeStderr(process.stderr) + } catch (err) { + raiseError('Failed to version npm') + } + + try { + await execa('gh', ['pr', 'create', '--title', 'release ' + version, '--body', 'When merged then a new release happens', '--label', 'release', '--reviewer', 'v1v'], { + stdin: process.stdin, + env: { + GH_TOKEN: githubToken + } + }) + .pipeStdout(process.stdout) + .pipeStderr(process.stderr) + } catch (err) { + raiseError('Failed to create GitHub PR') + } + +} + +// Entrypoint +;(async () => { + try { + await main() + } catch (err) { + console.log(err) + } +})() diff --git a/scripts/ci-release.mjs b/scripts/ci-release.mjs index 1b1e10c05..a9d3237bc 100644 --- a/scripts/ci-release.mjs +++ b/scripts/ci-release.mjs @@ -108,7 +108,7 @@ async function dryRunMode() { try { await execa( 'npx', - ['lerna', 'publish', `--registry=${registryUrl}`, '--no-push', '--yes'], + ['lerna', 'publish', `--registry=${registryUrl}`, '--no-push', '--no-git-tag-version', '--no-changelog', '--yes'], { stdin: process.stdin } ) .pipeStdout(process.stdout) @@ -140,12 +140,10 @@ async function prodMode() { } try { - await execa('npx', ['lerna', 'publish', `--otp=${totpCode}`, '--yes'], { - stdin: process.stdin, - env: { - GH_TOKEN: githubToken - } - }) + await execa('npx', + ['lerna', 'publish', `--otp=${totpCode}`, '--no-push', '--no-git-tag-version', '--no-changelog', '--yes'], + { stdin: process.stdin} + ) .pipeStdout(process.stdout) .pipeStderr(process.stderr) } catch (err) { From 9ca844be6fc8230460136cda1eb4b1e53ea7ef78 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 23 Nov 2023 15:35:43 +0100 Subject: [PATCH 03/10] chore: tbc --- .github/workflows/release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e930d57d..bb6d7fcaf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,8 +15,16 @@ permissions: contents: read jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: are changes only for version? + run: echo 'TBC' + release: runs-on: ubuntu-latest + needs: + - validate permissions: # Needed to write the release changelog contents: write From 53c7c39dc5628d532084df14c58b322eff68365e Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 24 Nov 2023 11:57:58 +0100 Subject: [PATCH 04/10] support release manually In two different steps --- .github/workflows/pre-release.yml | 47 ++++++++----- .github/workflows/release.yml | 69 +++++++------------ lerna.json | 2 +- .../{ci-pre-release.js => ci-pre-release.mjs} | 32 +++++++-- 4 files changed, 79 insertions(+), 71 deletions(-) rename scripts/{ci-pre-release.js => ci-pre-release.mjs} (76%) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 0424120e3..78a2e9342 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -1,6 +1,6 @@ --- # When triggered it will prepare the release by creating a Pull Request with the -# changes to be merged, then the automation will run and release it. +# changes to be merged. Then it will be possible to run the release manually name: pre-release on: @@ -9,6 +9,9 @@ on: permissions: contents: read +env: + SLACK_BUILD_MESSAGE: "Build: (<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|here>)" + jobs: release: runs-on: ubuntu-latest @@ -47,24 +50,30 @@ jobs: - name: Ignore git uncommitted changes run: git update-index --skip-worktree .npmrc - - name: Create PR with the release to be reviewed - run: npm run ci:pre-release + - name: Create PR with the required changes to be released + id: pre-release + run: | + npm run ci:pre-release + if [ -e .pr.txt ] ; then + echo "pr=$(cat .pr.txt)" >> "$GITHUB_OUTPUT" + fi - status: - if: always() - needs: - - release - runs-on: ubuntu-latest - steps: - - id: check - uses: elastic/apm-pipeline-library/.github/actions/check-dependent-jobs@current + - if: ${{ success() }} + uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: - needs: ${{ toJSON(needs) }} - - uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + channel: "#apm-agent-js" + message: | + :runner: [${{ github.repository }}] Pre Release has been triggered. Review the PR ${{ steps.pre-release.outputs.pr }}. ${{ env.SLACK_BUILD_MESSAGE }} + + - if: ${{ failure() }} + uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: - status: ${{ steps.check.outputs.status }} - vaultUrl: ${{ secrets.VAULT_ADDR }} - vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} - vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} - slackChannel: "#apm-agent-js" - message: "Build result for pre-release" + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + channel: "#apm-agent-js" + message: | + :ghost: [${{ github.repository }}] Pre Release failed. ${{ env.SLACK_BUILD_MESSAGE }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bb6d7fcaf..8ef8853eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,27 +4,20 @@ name: release on: - push: - branches: - - main - paths: - - 'CHANGELOG.md' - - 'package.json' + workflow_dispatch: ~ permissions: contents: read -jobs: - validate: - runs-on: ubuntu-latest - steps: - - name: are changes only for version? - run: echo 'TBC' +env: + DRY_RUN: false + ELASTIC_CDN_BUCKET_NAME: apm-rum-357700bc + ELASTIC_CDN_CREDENTIALS: secret/gce/elastic-cdn/service-account/apm-rum-admin + SLACK_BUILD_MESSAGE: "Build: (<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|here>)" +jobs: release: runs-on: ubuntu-latest - needs: - - validate permissions: # Needed to write the release changelog contents: write @@ -54,7 +47,6 @@ jobs: run: npm ci - name: Read NPM vault secrets - if: inputs.dry-run == false uses: hashicorp/vault-action@v2.7.3 with: method: approle @@ -80,22 +72,8 @@ jobs: secret-key: token - name: Publish the release - env: - DRY_RUN: true run: npm run ci:release - - name: Setup credentials - env: - DRY_RUN: true - run: | - if [ "${DRY_RUN}" == "false" ]; then - echo 'ELASTIC_CDN_BUCKET_NAME=apm-rum-357700bc' >> ${GITHUB_ENV} - echo 'ELASTIC_CDN_CREDENTIALS=secret/gce/elastic-cdn/service-account/apm-rum-admin' >> ${GITHUB_ENV} - else - echo 'ELASTIC_CDN_BUCKET_NAME=oblt-apm-agent-rum-js-ci' >> ${GITHUB_ENV} - echo 'ELASTIC_CDN_CREDENTIALS=secret/observability-team/ci/service-account/apm-agent-rum-js' >> ${GITHUB_ENV} - fi - - name: Read GCE vault secrets uses: hashicorp/vault-action@v2.7.3 with: @@ -151,21 +129,22 @@ jobs: headers: |- cache-control: public,max-age=604800,immutable - status: - if: always() - needs: - - release - runs-on: ubuntu-latest - steps: - - id: check - uses: elastic/apm-pipeline-library/.github/actions/check-dependent-jobs@current + - if: ${{ success() }} + uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: - needs: ${{ toJSON(needs) }} - - uses: elastic/apm-pipeline-library/.github/actions/notify-build-status@current + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + channel: "#apm-agent-js" + message: | + :runner: [${{ github.repository }}] Release has been published. ${{ env.SLACK_BUILD_MESSAGE }} + + - if: ${{ failure() }} + uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: - status: ${{ steps.check.outputs.status }} - vaultUrl: ${{ secrets.VAULT_ADDR }} - vaultRoleId: ${{ secrets.VAULT_ROLE_ID }} - vaultSecretId: ${{ secrets.VAULT_SECRET_ID }} - slackChannel: "#apm-agent-js" - message: "Build result for release publication" + url: ${{ secrets.VAULT_ADDR }} + roleId: ${{ secrets.VAULT_ROLE_ID }} + secretId: ${{ secrets.VAULT_SECRET_ID }} + channel: "#apm-agent-js" + message: | + :ghost: [${{ github.repository }}] Release failed. ${{ env.SLACK_BUILD_MESSAGE }} diff --git a/lerna.json b/lerna.json index a08b1576d..e7b4e4656 100644 --- a/lerna.json +++ b/lerna.json @@ -6,7 +6,7 @@ "registry": "https://registry.npmjs.org", "command": { "version": { - "allowBranch": ["main", "4.x", "release"], + "allowBranch": ["main", "4.x", "release", "release/*"], "conventionalCommits": true, "message": "chore(release): publish", "changelogPreset": "conventionalcommits", diff --git a/scripts/ci-pre-release.js b/scripts/ci-pre-release.mjs similarity index 76% rename from scripts/ci-pre-release.js rename to scripts/ci-pre-release.mjs index 314f08d4b..676100d01 100644 --- a/scripts/ci-pre-release.js +++ b/scripts/ci-pre-release.mjs @@ -23,9 +23,17 @@ * */ -const { version } = require('../packages/rum/package.json') import { execa } from 'execa' -const process = require('node:process') +import * as process from 'node:process' +// To read the version then use https://nodejs.org/api/esm.html#no-require-exports-or-moduleexports +import { createRequire } from 'node:module' +const require = createRequire(import.meta.url) +const { version } = require('../packages/rum/package.json') + +function raiseError(msg) { + console.log(msg) + process.exit(1) +} // Script logic async function main() { @@ -33,8 +41,11 @@ async function main() { if (githubToken == null || githubToken === '') { raiseError("The 'GITHUB_TOKEN' env var isn't defined") } + + const branch = `release/${version}-next` + try { - await execa('git', ['checkout', '-b', 'release/'+version], { + await execa('git', ['checkout', '-b', branch], { stdin: process.stdin }) .pipeStdout(process.stdout) @@ -43,6 +54,16 @@ async function main() { raiseError('Failed to create git branch') } + try { + await execa('git', ['push', 'origin', branch], { + stdin: process.stdin + }) + .pipeStdout(process.stdout) + .pipeStderr(process.stderr) + } catch (err) { + raiseError('Failed to push git branch') + } + try { await execa('npx', ['lerna', 'version', '--yes'], { stdin: process.stdin, @@ -57,18 +78,17 @@ async function main() { } try { - await execa('gh', ['pr', 'create', '--title', 'release ' + version, '--body', 'When merged then a new release happens', '--label', 'release', '--reviewer', 'v1v'], { + await execa('gh', ['pr', 'create', '--fill-first'], { stdin: process.stdin, env: { GH_TOKEN: githubToken } }) - .pipeStdout(process.stdout) + .pipeStdout('.pr.txt') .pipeStderr(process.stderr) } catch (err) { raiseError('Failed to create GitHub PR') } - } // Entrypoint From 07c61d050ef83095cbbb6c65c23d4e499030b031 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 24 Nov 2023 11:59:02 +0100 Subject: [PATCH 05/10] docs --- RELEASE.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 4f6110344..db07c9f02 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -42,8 +42,12 @@ Before releasing, be sure to update the following documentation: The release process is also automated in the way any specific commit from the main branch can be potentially released, for such it's required the below steps: -* Go to the [GitHub Actions](https://github.com/elastic/apm-agent-rum-js/actions/workflows/release.yml) workflow. +* Go to the [GitHub Actions](https://github.com/elastic/apm-agent-rum-js/actions/workflows/pre-release.yml) workflow. * Click on `Run workflow` and select the `main` branch. * Click on `Run workflow`. * Wait for completion. +* Review the PR with the changes when merged +* Go to the [GitHub Actions](https://github.com/elastic/apm-agent-rum-js/actions/workflows/release.yml) workflow. +* Click on `Run workflow` and select the `main` branch. +* Click on `Run workflow`. * You can go to the `https://www.npmjs.com/package/@elastic/apm-rum` and [GitHub releases](https://github.com/elastic/apm-agent-rum-js/releases) to validate that the bundles and release notes have been published. From 22c52d0b09c097004856337cb57fec23e183becf Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 24 Nov 2023 12:01:15 +0100 Subject: [PATCH 06/10] chore: required --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ef8853eb..121b5c334 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,13 @@ jobs: roleId: ${{ secrets.VAULT_ROLE_ID }} secretId: ${{ secrets.VAULT_SECRET_ID }} + - name: Configure git user + uses: elastic/apm-pipeline-library/.github/actions/setup-git@current + with: + username: ${{ env.GIT_USER }} + email: ${{ env.GIT_EMAIL }} + token: ${{ env.GITHUB_TOKEN }} + - uses: actions/checkout@v3 with: fetch-depth: 0 From ded30c400905a01dd744b5b93a8180c90c4c3ec4 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 24 Nov 2023 13:33:26 +0100 Subject: [PATCH 07/10] ci: enable dry-run --- .github/workflows/release.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 121b5c334..bb4d5f7d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,15 +4,19 @@ name: release on: - workflow_dispatch: ~ + workflow_dispatch: + inputs: + dry-run: + type: boolean + description: 'Run release process in dry-run mode' + default: true permissions: contents: read env: - DRY_RUN: false - ELASTIC_CDN_BUCKET_NAME: apm-rum-357700bc - ELASTIC_CDN_CREDENTIALS: secret/gce/elastic-cdn/service-account/apm-rum-admin + ELASTIC_CDN_BUCKET_NAME: ${{ inputs.dry-run == false && 'apm-rum-357700bc' || 'oblt-apm-agent-rum-js-ci' }} + ELASTIC_CDN_CREDENTIALS: ${{ inputs.dry-run == false && 'secret/gce/elastic-cdn/service-account/apm-rum-admin' || 'secret/observability-team/ci/service-account/apm-agent-rum-js' }} SLACK_BUILD_MESSAGE: "Build: (<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|here>)" jobs: @@ -53,7 +57,8 @@ jobs: - name: Install dependencies run: npm ci - - name: Read NPM vault secrets + - name: Read NPM vault TOTP + if: inputs.dry-run == false uses: hashicorp/vault-action@v2.7.3 with: method: approle @@ -70,6 +75,7 @@ jobs: git update-index --skip-worktree .npmrc - name: Configure npm registry + if: inputs.dry-run == false uses: elastic/apm-pipeline-library/.github/actions/setup-npmrc@current with: vault-url: ${{ secrets.VAULT_ADDR }} @@ -79,6 +85,8 @@ jobs: secret-key: token - name: Publish the release + env: + DRY_RUN: "${{ inputs.dry-run }}" run: npm run ci:release - name: Read GCE vault secrets @@ -136,7 +144,7 @@ jobs: headers: |- cache-control: public,max-age=604800,immutable - - if: ${{ success() }} + - if: ${{ success() && inputs.dry-run == false }} uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: url: ${{ secrets.VAULT_ADDR }} @@ -146,7 +154,7 @@ jobs: message: | :runner: [${{ github.repository }}] Release has been published. ${{ env.SLACK_BUILD_MESSAGE }} - - if: ${{ failure() }} + - if: ${{ failure() && inputs.dry-run == false }} uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: url: ${{ secrets.VAULT_ADDR }} From 2c03560738e919931839eadf4bcb0a783d880878 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 24 Nov 2023 13:44:45 +0100 Subject: [PATCH 08/10] support dry-run in pre-release --- .github/workflows/pre-release.yml | 13 +++++-- scripts/ci-pre-release.mjs | 65 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 78a2e9342..612667153 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -4,7 +4,12 @@ name: pre-release on: - workflow_dispatch: ~ + workflow_dispatch: + inputs: + dry-run: + type: boolean + description: 'Run release process in dry-run mode' + default: true permissions: contents: read @@ -52,13 +57,15 @@ jobs: - name: Create PR with the required changes to be released id: pre-release + env: + DRY_RUN: "${{ inputs.dry-run }}" run: | npm run ci:pre-release if [ -e .pr.txt ] ; then echo "pr=$(cat .pr.txt)" >> "$GITHUB_OUTPUT" fi - - if: ${{ success() }} + - if: ${{ success() && inputs.dry-run == false }} uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: url: ${{ secrets.VAULT_ADDR }} @@ -68,7 +75,7 @@ jobs: message: | :runner: [${{ github.repository }}] Pre Release has been triggered. Review the PR ${{ steps.pre-release.outputs.pr }}. ${{ env.SLACK_BUILD_MESSAGE }} - - if: ${{ failure() }} + - if: ${{ failure() && inputs.dry-run == false }} uses: elastic/apm-pipeline-library/.github/actions/slack-message@current with: url: ${{ secrets.VAULT_ADDR }} diff --git a/scripts/ci-pre-release.mjs b/scripts/ci-pre-release.mjs index 676100d01..8b51c31c7 100644 --- a/scripts/ci-pre-release.mjs +++ b/scripts/ci-pre-release.mjs @@ -35,8 +35,73 @@ function raiseError(msg) { process.exit(1) } +async function gitContext() { + try { + const { stdout: username } = await execa('git', ['config', 'user.name']) + const { stdout: email } = await execa('git', ['config', 'user.email']) + return { + username, + email + } + } catch (err) { + raiseError('Failed to extract git context') + } +} + // Script logic async function main() { + const isDryRun = + process.env.DRY_RUN == null || process.env.DRY_RUN !== 'false' + + // Extract git context + const ctx = await gitContext() + console.log(`Git User: username=${ctx.username}, email=${ctx.email}`) + + if (isDryRun) { + await dryRunMode() + } else { + await prodMode() + } +} + +// Script logic +async function dryRunMode() { + console.log('Running in dry-run mode') + + const githubToken = process.env.GITHUB_TOKEN + if (githubToken == null || githubToken === '') { + raiseError("The 'GITHUB_TOKEN' env var isn't defined") + } + + const branch = `release/${version}-next` + + try { + await execa('git', ['checkout', '-b', branch], { + stdin: process.stdin + }) + .pipeStdout(process.stdout) + .pipeStderr(process.stderr) + } catch (err) { + raiseError('Failed to create git branch') + } + + try { + await execa('npx', ['lerna', 'version', '--no-push', '--no-git-tag-version', '--no-changelog', 'yes'], { + stdin: process.stdin, + env: { + GH_TOKEN: githubToken + } + }) + .pipeStdout(process.stdout) + .pipeStderr(process.stderr) + } catch (err) { + raiseError('Failed to version npm') + } +} + +async function prodMode() { + console.log('Running in prod mode') + const githubToken = process.env.GITHUB_TOKEN if (githubToken == null || githubToken === '') { raiseError("The 'GITHUB_TOKEN' env var isn't defined") From eef32223064d4b2523659e5dfac824f542b95e2e Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Tue, 12 Dec 2023 13:16:14 +0100 Subject: [PATCH 09/10] avoid pushing git tag when running lerna version --- .github/workflows/pre-release.yml | 1 + scripts/ci-pre-release.mjs | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 612667153..1bb2dd995 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -63,6 +63,7 @@ jobs: npm run ci:pre-release if [ -e .pr.txt ] ; then echo "pr=$(cat .pr.txt)" >> "$GITHUB_OUTPUT" + rm .pr.txt fi - if: ${{ success() && inputs.dry-run == false }} diff --git a/scripts/ci-pre-release.mjs b/scripts/ci-pre-release.mjs index 8b51c31c7..9c851ed8a 100644 --- a/scripts/ci-pre-release.mjs +++ b/scripts/ci-pre-release.mjs @@ -120,26 +120,28 @@ async function prodMode() { } try { - await execa('git', ['push', 'origin', branch], { - stdin: process.stdin + await execa('npx', ['lerna', 'version', '--yes', '--no-push'], { + stdin: process.stdin, + env: { + GH_TOKEN: githubToken + } }) .pipeStdout(process.stdout) .pipeStderr(process.stderr) } catch (err) { - raiseError('Failed to push git branch') + raiseError('Failed to version npm') } + // As long as lerna version uses --no-push then it's required to push the commits + // this will avoid pushing the git tag too. try { - await execa('npx', ['lerna', 'version', '--yes'], { - stdin: process.stdin, - env: { - GH_TOKEN: githubToken - } + await execa('git', ['push', 'origin', branch], { + stdin: process.stdin }) .pipeStdout(process.stdout) .pipeStderr(process.stderr) } catch (err) { - raiseError('Failed to version npm') + raiseError('Failed to push git branch') } try { From ee3eb33c2031379c7057250a14e4dd9a77bba0e8 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Wed, 13 Dec 2023 09:43:18 +0100 Subject: [PATCH 10/10] chore: use lerna pubish from-package To avoid bumping the versions --- scripts/ci-release.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci-release.mjs b/scripts/ci-release.mjs index a9d3237bc..fc919e435 100644 --- a/scripts/ci-release.mjs +++ b/scripts/ci-release.mjs @@ -108,7 +108,7 @@ async function dryRunMode() { try { await execa( 'npx', - ['lerna', 'publish', `--registry=${registryUrl}`, '--no-push', '--no-git-tag-version', '--no-changelog', '--yes'], + ['lerna', 'publish', 'from-package', `--registry=${registryUrl}`, '--no-push', '--no-git-tag-version', '--no-changelog', '--yes'], { stdin: process.stdin } ) .pipeStdout(process.stdout) @@ -141,7 +141,7 @@ async function prodMode() { try { await execa('npx', - ['lerna', 'publish', `--otp=${totpCode}`, '--no-push', '--no-git-tag-version', '--no-changelog', '--yes'], + ['lerna', 'publish', 'from-package', `--otp=${totpCode}`, '--no-push', '--no-git-tag-version', '--no-changelog', '--yes'], { stdin: process.stdin} ) .pipeStdout(process.stdout)