From 7acf8e1d724c3327c92d04ab32149d4bb63f9337 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Thu, 15 Jun 2023 14:59:36 +0200 Subject: [PATCH] Merge pull request #23083 from storybookjs/kasper/imrpove-release-title Release: A bunch of fixes to the release tooling (cherry picked from commit c33d131c051bdfcdf11b6982c6a283d68253948c) --- .github/workflows/check-release-tasks.yml | 19 ----- .github/workflows/prepare-patch-release.yml | 12 ++-- .github/workflows/publish.yml | 4 +- .../__tests__/generate-pr-description.test.ts | 71 +++++++++---------- .../release/__tests__/label-patches.test.ts | 32 +++++---- scripts/release/generate-pr-description.ts | 45 ++++++------ 6 files changed, 80 insertions(+), 103 deletions(-) delete mode 100644 .github/workflows/check-release-tasks.yml diff --git a/.github/workflows/check-release-tasks.yml b/.github/workflows/check-release-tasks.yml deleted file mode 100644 index 4848ae35f07e..000000000000 --- a/.github/workflows/check-release-tasks.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Check release tasks -run-name: 'Check tasks for "${{ github.event.pull_request.title }}" PR' - -on: - pull_request: - types: - - opened - - edited - branches: - - 'latest-release' - - 'next-release' - -jobs: - task-check: - runs-on: ubuntu-latest - steps: - - uses: chromaui/task-completed-checker-action@main - with: - repo-token: '${{ secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index d1f29d808402..3d60b139e858 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -56,7 +56,7 @@ jobs: id: check-frozen env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: yarn release:is-pr-frozen + run: yarn release:is-pr-frozen --patch - name: Cancel when frozen if: steps.check-frozen.outputs.frozen == 'true' && github.event_name != 'workflow_dispatch' @@ -138,13 +138,14 @@ jobs: if PR_STATE=$(gh pr view --json state --jq .state 2>/dev/null) && [[ -n "$PR_STATE" && "$PR_STATE" == *"OPEN"* ]]; then gh pr edit \ --repo "${{github.repository }}" \ - --title "Bump version on \`main\`: patch from ${{ steps.versions.outputs.current }} to ${{ steps.versions.outputs.next }}" \ + --title "Release: Patch ${{ steps.versions.outputs.next }}" \ --body "${{ steps.description.outputs.description }}" else gh pr create \ --repo "${{github.repository }}" \ - --title "Bump version on \`main\`: patch from ${{ steps.versions.outputs.current }} to ${{ steps.versions.outputs.next }}" \ + --title "Release: Patch ${{ steps.versions.outputs.next }}" \ --base latest-release \ + --label "maintenance" --head version-patch-from-${{ steps.versions.outputs.current }} \ --body "${{ steps.description.outputs.description }}" fi @@ -157,13 +158,14 @@ jobs: if PR_STATE=$(gh pr view --json state --jq .state 2>/dev/null) && [[ -n "$PR_STATE" && "$PR_STATE" == *"OPEN"* ]]; then gh pr edit \ --repo "${{github.repository }}"\ - --title "Merge patches to \`main\`" \ + --title "Release: Merge patches to \`main\` (without version bump)" \ --body "${{ steps.description.outputs.description }}" else gh pr create \ --repo "${{github.repository }}"\ - --title "Merge patches to \`main\`" \ + --title "Release: Merge patches to \`main\` (without version bump)" \ --base latest-release \ + --label "build" \ --head version-patch-from-${{ steps.versions.outputs.current }} \ --body "${{ steps.description.outputs.description }}" fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c6c92b600c2d..329823876e9b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -88,11 +88,11 @@ jobs: # tags are needed to get list of patches to label as picked - name: Fetch git tags - if: github.ref_name == 'main-release' + if: github.ref_name == 'latest-release' run: git fetch --tags origin - name: Label patch PRs as picked - if: github.ref_name == 'main-release' + if: github.ref_name == 'latest-release' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: yarn release:label-patches diff --git a/scripts/release/__tests__/generate-pr-description.test.ts b/scripts/release/__tests__/generate-pr-description.test.ts index b84c7a5d8dae..5323f6bc2a87 100644 --- a/scripts/release/__tests__/generate-pr-description.test.ts +++ b/scripts/release/__tests__/generate-pr-description.test.ts @@ -10,10 +10,11 @@ describe('Generate PR Description', () => { const changes: Change[] = [ { user: 'JReinhold', + id: 'pr-id-42', title: 'Some PR title for a bug', labels: ['bug', 'build', 'other label', 'patch'], commit: 'abc123', - pull: '42', + pull: 42, links: { commit: '[abc123](https://github.com/storybookjs/storybook/commit/abc123)', pull: '[#42](https://github.com/storybookjs/storybook/pull/42)', @@ -22,6 +23,7 @@ describe('Generate PR Description', () => { }, { // this Bump version commit should be ignored + id: null, user: 'github-actions[bot]', pull: null, commit: '012b58140c3606efeacbe99c0c410624b0a1ed1f', @@ -35,6 +37,7 @@ describe('Generate PR Description', () => { }, }, { + id: null, user: 'shilman', title: 'Some title for a "direct commit"', labels: null, @@ -47,11 +50,12 @@ describe('Generate PR Description', () => { }, }, { + id: 'pr-id-11', user: 'shilman', title: 'Another PR `title` for docs', labels: ['another label', 'documentation', 'patch'], commit: 'ddd222', - pull: '11', + pull: 11, links: { commit: '[ddd222](https://github.com/storybookjs/storybook/commit/ddd222)', pull: '[#11](https://github.com/storybookjs/storybook/pull/11)', @@ -59,11 +63,12 @@ describe('Generate PR Description', () => { }, }, { + id: 'pr-id-48', user: 'JReinhold', title: "Some PR title for a 'new' feature", labels: ['feature request', 'other label'], commit: 'wow1337', - pull: '48', + pull: 48, links: { commit: '[wow1337](https://github.com/storybookjs/storybook/commit/wow1337)', pull: '[#48](https://github.com/storybookjs/storybook/pull/48)', @@ -71,11 +76,12 @@ describe('Generate PR Description', () => { }, }, { + id: 'pr-id-77', user: 'JReinhold', title: 'Some PR title with a missing label', labels: ['incorrect label', 'other label'], commit: 'bad999', - pull: '77', + pull: 77, links: { commit: '[bad999](https://github.com/storybookjs/storybook/commit/bad999)', pull: '[#77](https://github.com/storybookjs/storybook/pull/77)', @@ -84,35 +90,22 @@ describe('Generate PR Description', () => { }, ]; describe('mapToChangelist', () => { - it('should return a correct string for releases', () => { - expect(mapToChangelist({ changes, isRelease: true })).toMatchInlineSnapshot(` - "- **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42) - - [ ] The change is appropriate for the version bump - - [ ] The PR is labeled correctly - - [ ] The PR title is correct - - **⚠️ Direct commit**: Some title for a "direct commit" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11) - - [ ] The change is appropriate for the version bump - - **📝 Documentation**: Another PR \`title\` for docs [#11](https://github.com/storybookjs/storybook/pull/11) - - [ ] The change is appropriate for the version bump - - [ ] The PR is labeled correctly - - [ ] The PR title is correct - - **✨ Feature Request**: Some PR title for a 'new' feature [#48](https://github.com/storybookjs/storybook/pull/48) - - [ ] The change is appropriate for the version bump - - [ ] The PR is labeled correctly - - [ ] The PR title is correct - - **❔ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77) - - [ ] The change is appropriate for the version bump - - [ ] The PR is labeled correctly - - [ ] The PR title is correct" + it('should return a correct string for patch PRs', () => { + expect(mapToChangelist({ changes, unpickedPatches: true })).toMatchInlineSnapshot(` + "- [ ] **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42) + - [ ] **✨ Feature Request**: Some PR title for a 'new' feature [#48](https://github.com/storybookjs/storybook/pull/48) + - [ ] **⚠️ Direct commit**: Some title for a "direct commit" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11) + - [ ] **📝 Documentation**: Another PR \`title\` for docs [#11](https://github.com/storybookjs/storybook/pull/11) + - [ ] **❔ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)" `); }); - it('should return a correct string for non-releases', () => { - expect(mapToChangelist({ changes, isRelease: false })).toMatchInlineSnapshot(` - "- **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42) - - **⚠️ Direct commit**: Some title for a "direct commit" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11) - - **📝 Documentation**: Another PR \`title\` for docs [#11](https://github.com/storybookjs/storybook/pull/11) - - **✨ Feature Request**: Some PR title for a 'new' feature [#48](https://github.com/storybookjs/storybook/pull/48) - - **❔ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)" + it('should return a correct string for prerelease PRs', () => { + expect(mapToChangelist({ changes, unpickedPatches: false })).toMatchInlineSnapshot(` + "- [ ] **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42) (will also be patched) + - [ ] **✨ Feature Request**: Some PR title for a 'new' feature [#48](https://github.com/storybookjs/storybook/pull/48) + - [ ] **⚠️ Direct commit**: Some title for a "direct commit" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11) + - [ ] **📝 Documentation**: Another PR \`title\` for docs [#11](https://github.com/storybookjs/storybook/pull/11) (will also be patched) + - [ ] **❔ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)" `); }); }); @@ -222,8 +215,8 @@ For each pull request below, you need to either manually cherry pick it, or disc If you\\'ve made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-prerelease.yml) and wait for it to finish. It will wipe your progress in this to do, which is expected. When everything above is done: - - [ ] Merge this PR - - [ ] [Follow the publish workflow run and see it finishes succesfully](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) + - Merge this PR + - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) --- @@ -273,8 +266,8 @@ For each pull request below, you need to either manually cherry pick it, or disc If you\\'ve made any changes (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-prerelease.yml) and wait for it to finish. When everything above is done: - - [ ] Merge this PR - - [ ] [Approve the publish workflow run](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)" + - Merge this PR + - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)" `); }); @@ -337,8 +330,8 @@ For each pull request below, you need to either manually cherry pick it, or disc If you\\'ve made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-prerelease.yml) and wait for it to finish. It will wipe your progress in this to do, which is expected. When everything above is done: - - [ ] Merge this PR - - [ ] [Follow the publish workflow run and see it finishes succesfully](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) + - Merge this PR + - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) --- @@ -383,8 +376,8 @@ For each pull request below, you need to either manually cherry pick it, or disc If you\\'ve made any changes (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-prerelease.yml) and wait for it to finish. When everything above is done: - - [ ] Merge this PR - - [ ] [Approve the publish workflow run](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)" + - Merge this PR + - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)" `); }); }); diff --git a/scripts/release/__tests__/label-patches.test.ts b/scripts/release/__tests__/label-patches.test.ts index 31203529a0ca..0ee57a2dbe0e 100644 --- a/scripts/release/__tests__/label-patches.test.ts +++ b/scripts/release/__tests__/label-patches.test.ts @@ -112,22 +112,26 @@ test('it should label the PR associated with cheery picks in the current branch' ] `); - expect.addSnapshotSerializer({ - serialize: (value) => { - const stripAnsi = value.map((it: string) => it.replace(ansiRegex(), '')); - return JSON.stringify(stripAnsi, null, 2); - }, - test: () => true, - }); + const stderrCalls = writeStderr.mock.calls + .map(([text]) => + typeof text === 'string' + ? text + .replace(ansiRegex(), '') + .replace(/[^\x20-\x7E]/g, '') + .replaceAll('-', '') + .trim() + : text + ) + .filter((it) => it !== ''); - expect(writeStderr.mock.calls.map(([text]) => text)).toMatchInlineSnapshot(` + expect(stderrCalls).toMatchInlineSnapshot(` [ - "- Looking for latest tag\\n", - "✔ Found latest tag: v7.2.1\\n", - "- Looking at cherry pick commits since v7.2.1\\n", - "✔ Found the following picks 🍒:\\n Commit: 930b47f011f750c44a1782267d698ccdd3c04da3\\n PR: [#55](https://github.com/storybookjs/storybook/pull/55)\\n", - "- Labeling the PRs with the picked label...\\n", - "✔ Successfully labeled all PRs with the picked label.\\n" + "Looking for latest tag", + "Found latest tag: v7.2.1", + "Looking at cherry pick commits since v7.2.1", + "Found the following picks : Commit: 930b47f011f750c44a1782267d698ccdd3c04da3 PR: [#55](https://github.com/storybookjs/storybook/pull/55)", + "Labeling the PRs with the picked label...", + "Successfully labeled all PRs with the picked label.", ] `); }); diff --git a/scripts/release/generate-pr-description.ts b/scripts/release/generate-pr-description.ts index 35654d9d601c..f326ddb259a5 100644 --- a/scripts/release/generate-pr-description.ts +++ b/scripts/release/generate-pr-description.ts @@ -5,8 +5,9 @@ import { z } from 'zod'; import dedent from 'ts-dedent'; import { setOutput } from '@actions/core'; import type { Change } from './utils/get-changes'; -import { getChanges, LABELS_BY_IMPORTANCE } from './utils/get-changes'; +import { getChanges, LABELS_BY_IMPORTANCE, RELEASED_LABELS } from './utils/get-changes'; import { getCurrentVersion } from './get-current-version'; +import type { PullRequestInfo } from './utils/get-github-info'; program .name('generate-pr-description') @@ -48,14 +49,15 @@ const CHANGE_TITLES_TO_IGNORE = [ /^merge branch.*/i, /\[skip ci\]/i, /\[ci skip\]/i, + /^Update CHANGELOG\.md for.*/i, ]; export const mapToChangelist = ({ changes, - isRelease, + unpickedPatches, }: { changes: Change[]; - isRelease: boolean; + unpickedPatches: boolean; }): string => { return changes .filter((change) => { @@ -67,14 +69,14 @@ export const mapToChangelist = ({ } return true; }) + .sort((a, b) => { + const isReleasable = (pr: PullRequestInfo) => + (pr.labels ?? []).some((label) => Object.keys(RELEASED_LABELS).includes(label)); + return Number(isReleasable(b)) - Number(isReleasable(a)); + }) .map((change) => { - const lines: string[] = []; if (!change.pull) { - lines.push(`- **⚠️ Direct commit**: ${change.title} ${change.links.commit}`); - if (isRelease) { - lines.push('\t- [ ] The change is appropriate for the version bump'); - } - return lines.join('\n'); + return `- [ ] **⚠️ Direct commit**: ${change.title} ${change.links.commit}`; } const label = (change.labels @@ -85,14 +87,9 @@ export const mapToChangelist = ({ Object.keys(LABELS_BY_IMPORTANCE).indexOf(b) )[0] || 'unknown') as keyof typeof LABELS_BY_IMPORTANCE; - lines.push(`- **${LABELS_BY_IMPORTANCE[label]}**: ${change.title} ${change.links.pull}`); - - if (isRelease) { - lines.push('\t- [ ] The change is appropriate for the version bump'); - lines.push('\t- [ ] The PR is labeled correctly'); - lines.push('\t- [ ] The PR title is correct'); - } - return lines.join('\n'); + return `- [ ] **${LABELS_BY_IMPORTANCE[label]}**: ${change.title} ${change.links.pull}${ + !unpickedPatches && change.labels.includes('patch') ? ' (will also be patched)' : '' + }`; }) .join('\n'); }; @@ -171,10 +168,10 @@ export const generateReleaseDescription = ({ ${manualCherryPicks || ''} If you've made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-prerelease.yml) and wait for it to finish. It will wipe your progress in this to do, which is expected. - + When everything above is done: - - [ ] Merge this PR - - [ ] [Follow the publish workflow run and see it finishes succesfully](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) + - Merge this PR + - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) --- @@ -206,8 +203,8 @@ export const generateNonReleaseDescription = ( If you've made any changes (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-prerelease.yml) and wait for it to finish. When everything above is done: - - [ ] Merge this PR - - [ ] [Approve the publish workflow run](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)` + - Merge this PR + - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)` // don't mention contributors in the release PR, to avoid spamming them .replaceAll('[@', '[@ ') .replaceAll('"', '\\"') @@ -248,7 +245,7 @@ export const run = async (rawOptions: unknown) => { ? generateReleaseDescription({ currentVersion, nextVersion, - changeList: mapToChangelist({ changes, isRelease: true }), + changeList: mapToChangelist({ changes, unpickedPatches }), changelogText, ...(hasCherryPicks && { manualCherryPicks: mapCherryPicksToTodo({ @@ -259,7 +256,7 @@ export const run = async (rawOptions: unknown) => { }), }) : generateNonReleaseDescription( - mapToChangelist({ changes, isRelease: false }), + mapToChangelist({ changes, unpickedPatches }), hasCherryPicks ? mapCherryPicksToTodo({ commits: manualCherryPicks,