From 4bb954de233f3d1329712ad80beafa10ab83c9ed Mon Sep 17 00:00:00 2001 From: Matt Weber Date: Fri, 12 Apr 2024 19:01:37 -0400 Subject: [PATCH] chore: setup 5.x auto release --- .github/workflows/publish-undici-types.yml | 26 ------ .github/workflows/release.yml | 68 +++++++++++++++ scripts/release.js | 97 ++++++++++++++++++++++ 3 files changed, 165 insertions(+), 26 deletions(-) delete mode 100644 .github/workflows/publish-undici-types.yml create mode 100644 .github/workflows/release.yml create mode 100644 scripts/release.js diff --git a/.github/workflows/publish-undici-types.yml b/.github/workflows/publish-undici-types.yml deleted file mode 100644 index 3f8fea32ce5..00000000000 --- a/.github/workflows/publish-undici-types.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Publish undici-types - -on: - push: - tags: - - 'v*' - workflow_dispatch: - -permissions: - contents: read - -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: - node-version: '16.x' - registry-url: 'https://registry.npmjs.org' - - run: npm install - - run: node scripts/generate-undici-types-package-json.js - - run: npm publish - working-directory: './types' - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000000..d407e0b0bcd --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,68 @@ +name: Create release + +on: + push: + branches: + - v5.x + paths: + - package.json + +permissions: + contents: read + +jobs: + check-release-version: + runs-on: ubuntu-latest + outputs: + release-version: ${{ steps.set-release-version.outputs.result }} + steps: + - uses: actions/checkout@v4 + - uses: actions/github-script@v7 + id: set-release-version + with: + result-encoding: string + script: | + const { owner, repo } = context.repo + const version = require("./package.json").version + const versionTag = `v${version}` + + const previousReleaseTag = await require('./scripts/release').previousReleaseTag({ github, context, versionTag }) + + if (versionTag !== previousReleaseTag) { + return versionTag + } + + release: + runs-on: ubuntu-latest + needs: check-release-version + if: ${{ startsWith(needs.check-release-version.outputs.release-version, 'v') }} + + permissions: + contents: write + id-token: write + + environment: release + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + - run: npm install -g npm@latest + - run: npm install + - name: Create NPM release + run: npm publish --provenance --access public --tag five + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - run: node scripts/generate-undici-types-package-json.js + - run: npm publish --provenance --access public --tag five + working-directory: './types' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Create GitHub release + uses: actions/github-script@v7 + with: + script: | + const versionTag = "${{ needs.check-release-version.outputs.release-version }}" + await require('./scripts/release').release({ github, context, versionTag }) \ No newline at end of file diff --git a/scripts/release.js b/scripts/release.js new file mode 100644 index 00000000000..cb28b610dc7 --- /dev/null +++ b/scripts/release.js @@ -0,0 +1,97 @@ +'use strict' + +// Called from .github/workflows + +// The following two variables should be updated per major version release branch (main, v5.x, etc) +const VERSION_TAG_PREFIX = 'v5.' +const BRANCH = 'v5.x' + +const getLatestRelease = async ({ github, owner, repo }) => { + for await (const { data } of github.paginate.iterator( + github.rest.repos.listReleases, + { + owner, + repo + } + )) { + const latestRelease = data.find((r) => r.tag_name.startsWith(VERSION_TAG_PREFIX)) + + if (latestRelease) { + return latestRelease + } + } + + throw new Error(`Could not find latest release of ${VERSION_TAG_PREFIX}x`) +} + +const generateReleaseNotes = async ({ github, owner, repo, versionTag }) => { + const previousRelease = await getLatestRelease({ github, owner, repo, versionTag }) + + const { data: { body } } = await github.rest.repos.generateReleaseNotes({ + owner, + repo, + tag_name: versionTag, + target_commitish: `heads/${BRANCH}`, + previous_tag_name: previousRelease.tag_name + }) + + const bodyWithoutReleasePr = body.split('\n') + .filter((line) => !line.includes('[Release] v')) + .join('\n') + + return bodyWithoutReleasePr +} + +const generatePr = async ({ github, context, versionTag }) => { + const { owner, repo } = context.repo + const releaseNotes = await generateReleaseNotes({ github, owner, repo, versionTag }) + + await github.rest.pulls.create({ + owner, + repo, + head: `release/${versionTag}`, + base: BRANCH, + title: `[Release] ${versionTag}`, + body: releaseNotes + }) +} + +const release = async ({ github, context, versionTag }) => { + const { owner, repo } = context.repo + const releaseNotes = await generateReleaseNotes({ github, owner, repo, versionTag }) + + await github.rest.repos.createRelease({ + owner, + repo, + tag_name: versionTag, + target_commitish: BRANCH, + name: versionTag, + body: releaseNotes, + draft: false, + prerelease: false, + generate_release_notes: false + }) + + try { + await github.rest.git.deleteRef({ + owner, + repo, + ref: `heads/release/${versionTag}` + }) + } catch (err) { + console.log("Couldn't delete release PR ref") + console.log(err) + } +} + +const previousReleaseTag = async ({ github, context, versionTag }) => { + const { owner, repo } = context.repo + const previousRelease = await getLatestRelease({ github, owner, repo, versionTag }) + return previousRelease.tag_name +} + +module.exports = { + release, + previousReleaseTag, + generatePr +}