From 3e9458a1e43ce7623149dd5360939b0ad0aecb90 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 15 Aug 2024 17:32:30 +0100 Subject: [PATCH] feat: Add #body-in-changelog option to PR/commit bodies Right now this is manually done by the getsentry/sentry-python team. I thought it was a good opportunity improve automatic changelog generation. Thanks to @sentrivana for the idea. --- .vscode/settings.json | 2 +- README.md | 6 +- src/utils/__tests__/changelog.test.ts | 100 +++++++++++++++++++++++++- src/utils/changelog.ts | 30 ++++++-- 4 files changed, 127 insertions(+), 11 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4d84ab76..eb7186a6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.codeActionsOnSave": { - "source.organizeImports": false + "source.organizeImports": "never" }, "editor.formatOnType": true, "editor.formatOnSave": true, diff --git a/README.md b/README.md index 763d2203..d8275702 100644 --- a/README.md +++ b/README.md @@ -526,7 +526,7 @@ contains any one of `preview`, `pre`, `rc`, `dev`,`alpha`, `beta`, `unstable`, | Name | Description | | -------------- | ------------------------------------------------------------------ | -| `GITHUB_TOKEN` | Personal GitHub API token (see https://github.com/settings/tokens) | +| `GITHUB_TOKEN` | Personal GitHub API token (see ) | **Configuration** @@ -617,7 +617,7 @@ like [getsentry/pypi] | Name | Description | | -------------- | ------------------------------------------------------------------ | -| `GITHUB_TOKEN` | Personal GitHub API token (see https://github.com/settings/tokens) | +| `GITHUB_TOKEN` | Personal GitHub API token (see ) | **Configuration** @@ -829,7 +829,7 @@ targets: ### Sentry Release Registry (`registry`) -The target will update the Sentry release registry repo(https://github.com/getsentry/sentry-release-registry/) with the latest version of the +The target will update the Sentry release registry repo() with the latest version of the project `craft` is used with. The release registry repository will be checked out locally, and then the new version file will be created there, along with the necessary symbolic links. diff --git a/src/utils/__tests__/changelog.test.ts b/src/utils/__tests__/changelog.test.ts index 3688c124..49b56062 100644 --- a/src/utils/__tests__/changelog.test.ts +++ b/src/utils/__tests__/changelog.test.ts @@ -5,7 +5,7 @@ import { getGitHubClient } from '../githubApi'; jest.mock('../git'); import { getChangesSince } from '../git'; -import { SimpleGit } from 'simple-git'; +import type { SimpleGit } from 'simple-git'; import { findChangeset, @@ -13,6 +13,7 @@ import { prependChangeset, generateChangesetFromGit, SKIP_CHANGELOG_MAGIC_WORD, + BODY_IN_CHANGELOG_MAGIC_WORD, } from '../changelog'; describe('findChangeset', () => { @@ -705,6 +706,103 @@ describe('generateChangesetFromGit', () => { '- Fix the clacking sound on gear changes (#950) by @alice', ].join('\n'), ], + [ + `should expand commits & prs with the magic ${BODY_IN_CHANGELOG_MAGIC_WORD}`, + [ + { + hash: 'abcdef1234567890', + title: 'Upgraded the kernel', + body: SKIP_CHANGELOG_MAGIC_WORD, + }, + { + hash: 'bcdef1234567890a', + title: 'Upgraded the manifold (#123)', + body: '', + pr: { + local: '123', + remote: { + number: '123', + author: { login: 'alice' }, + milestone: '1', + }, + }, + }, + { + hash: 'cdef1234567890ab', + title: 'Refactored the crankshaft', + body: '', + pr: { + remote: { + number: '456', + author: { login: 'bob' }, + body: `This is important and we'll include the __body__ for attention. ${BODY_IN_CHANGELOG_MAGIC_WORD}`, + milestone: '1', + }, + }, + }, + { + hash: 'def1234567890abc', + title: 'Upgrade the HUD (#789)', + body: '', + pr: { + local: '789', + remote: { + number: '789', + author: { login: 'charlie' }, + milestone: '5', + }, + }, + }, + { + hash: 'ef1234567890abcd', + title: 'Upgrade the steering wheel (#900)', + body: `Some very important update ${BODY_IN_CHANGELOG_MAGIC_WORD}`, + pr: { local: '900' }, + }, + { + hash: 'f1234567890abcde', + title: 'Fix the clacking sound on gear changes (#950)', + body: '', + pr: { + local: '950', + remote: { number: '950', author: { login: 'alice' } }, + }, + }, + ], + { + '1': { + title: 'Better drivetrain', + description: + 'We have upgraded the drivetrain for a smoother and more performant driving experience. Enjoy!', + state: 'CLOSED', + }, + '5': { + title: 'Better driver experience', + description: + 'We are working on making your driving experience more pleasant and safer.', + state: 'OPEN', + }, + }, + [ + '### Better drivetrain', + '', + 'We have upgraded the drivetrain for a smoother and more performant driving experience. Enjoy!', + '', + 'By: @alice (#123), @bob (#456)', + '', + '### Better driver experience (ongoing)', + '', + 'We are working on making your driving experience more pleasant and safer.', + '', + 'By: @charlie (#789)', + '', + '### Various fixes & improvements', + '', + '- Upgrade the steering wheel (#900)', + ' Some very important update ', + '- Fix the clacking sound on gear changes (#950) by @alice', + ].join('\n'), + ], ])( '%s', async ( diff --git a/src/utils/changelog.ts b/src/utils/changelog.ts index 2d276039..3a5c6719 100644 --- a/src/utils/changelog.ts +++ b/src/utils/changelog.ts @@ -1,4 +1,4 @@ -import { SimpleGit } from 'simple-git'; +import type { SimpleGit } from 'simple-git'; import { logger } from '../logger'; import { getGlobalGitHubConfig } from '../config'; @@ -12,6 +12,7 @@ import { getVersion } from './version'; export const DEFAULT_CHANGELOG_PATH = 'CHANGELOG.md'; export const DEFAULT_UNRELEASED_TITLE = 'Unreleased'; export const SKIP_CHANGELOG_MAGIC_WORD = '#skip-changelog'; +export const BODY_IN_CHANGELOG_MAGIC_WORD = '#body-in-changelog'; const DEFAULT_CHANGESET_BODY = '- No documented changes.'; const VERSION_HEADER_LEVEL = 2; const SUBSECTION_HEADER_LEVEL = VERSION_HEADER_LEVEL + 1; @@ -214,8 +215,10 @@ interface Commit { author?: string; hash: string; title: string; + body: string; hasPRinTitle: boolean; pr: string | null; + prBody?: string | null; milestone: string | null; } @@ -224,7 +227,7 @@ interface Milestone { description: string | null; state: 'OPEN' | 'CLOSED'; } -type MilestoneWithPRs = Milestone & { +type MilestoneWithPRs = Partial & { prs: PullRequest[]; }; @@ -242,6 +245,17 @@ function formatCommit(commit: Commit): string { if (commit.author) { text = `${text} by @${commit.author}`; } + let body = ''; + if (commit.prBody?.includes(BODY_IN_CHANGELOG_MAGIC_WORD)) { + body = commit.prBody; + } else if (commit.body.includes(BODY_IN_CHANGELOG_MAGIC_WORD)) { + body = commit.body; + } + body = body.replace(BODY_IN_CHANGELOG_MAGIC_WORD, ''); + if (body) { + text += `\n ${body}`; + } + return text; } @@ -270,12 +284,14 @@ export async function generateChangesetFromGit( continue; } - const commit = (commits[hash] = { + const commit = { hash: hash, title: gitCommit.title, + body: gitCommit.body, hasPRinTitle: Boolean(gitCommit.pr), ...githubCommit, - }); + }; + commits[hash] = commit; if (!githubCommit) { missing.push(commit); @@ -283,7 +299,9 @@ export async function generateChangesetFromGit( if (!commit.milestone) { leftovers.push(commit); } else { - const milestone = milestones[commit.milestone] || { prs: [] }; + const milestone = milestones[commit.milestone] || { + prs: [] as PullRequest[], + }; // We _know_ the PR exists as milestones are attached to PRs milestone.prs.push({ author: commit.author as string, @@ -296,7 +314,7 @@ export async function generateChangesetFromGit( if (missing.length > 0) { logger.warn( - `The following commits were not found on GitHub:`, + 'The following commits were not found on GitHub:', missing.map(commit => `${commit.hash.slice(0, 8)} ${commit.title}`) ); }