Skip to content

Commit b8cf803

Browse files
authored
fix: only use latest template-oss specific commits in changelog (#430)
1 parent 5d806ab commit b8cf803

File tree

2 files changed

+107
-19
lines changed

2 files changed

+107
-19
lines changed

lib/release/changelog.js

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class ChangelogNotes {
110110
return authorsByCommit
111111
}
112112

113-
async #getPullRequestForCommits (commits) {
113+
async #getPullRequestNumbersForCommits (commits) {
114114
const shas = commits
115115
.filter(c => !c.pullRequest?.number)
116116
.map(c => c.sha)
@@ -134,7 +134,7 @@ class ChangelogNotes {
134134
return pullRequestsByCommit
135135
}
136136

137-
#buildEntry (commit, { authors = [], pullRequest }) {
137+
#buildEntry (commit) {
138138
const entry = []
139139

140140
if (commit.sha) {
@@ -143,7 +143,7 @@ class ChangelogNotes {
143143
}
144144

145145
// A link to the pull request if the commit has one
146-
const commitPullRequest = commit.pullRequest?.number ?? pullRequest
146+
const commitPullRequest = commit.pullRequestNumber
147147
if (commitPullRequest) {
148148
entry.push(link(`#${commitPullRequest}`, this.#ghUrl('pull', commitPullRequest)))
149149
}
@@ -154,21 +154,65 @@ class ChangelogNotes {
154154
entry.push([scope, subject].filter(Boolean).join(' '))
155155

156156
// A list og the authors github handles or names
157-
if (authors.length) {
158-
entry.push(`(${authors.join(', ')})`)
157+
if (commit.authors.length) {
158+
entry.push(`(${commit.authors.join(', ')})`)
159159
}
160160

161161
return entry.join(' ')
162162
}
163163

164-
async buildNotes (commits, { version, previousTag, currentTag, changelogSections }) {
164+
#filterCommits (commits) {
165+
const filteredCommits = []
166+
const keyedDuplicates = {}
167+
168+
// Filter certain commits so we can make sure only the latest version of
169+
// each one gets into the changelog
170+
for (const commit of commits) {
171+
if (commit.bareMessage.startsWith('postinstall for dependabot template-oss PR')) {
172+
keyedDuplicates.templateOssPostInstall ??= []
173+
keyedDuplicates.templateOssPostInstall.push(commit)
174+
continue
175+
}
176+
177+
if (commit.bareMessage.startsWith('bump @npmcli/template-oss from')) {
178+
keyedDuplicates.templateOssBump ??= []
179+
keyedDuplicates.templateOssBump.push(commit)
180+
continue
181+
}
182+
183+
filteredCommits.push(commit)
184+
}
185+
186+
// Sort all our duplicates so we get the latest verion (by PR number) of each type.
187+
// Then flatten so we can put them all back into the changelog
188+
const sortedDupes = Object.values(keyedDuplicates)
189+
.filter((items) => Boolean(items.length))
190+
.map((items) => items.sort((a, b) => b.pullRequestNumber - a.pullRequestNumber))
191+
.flatMap(items => items[0])
192+
193+
// This moves them to the bottom of their changelog section which is not
194+
// strictly necessary but it's easier to do this way.
195+
for (const duplicate of sortedDupes) {
196+
filteredCommits.push(duplicate)
197+
}
198+
199+
return filteredCommits
200+
}
201+
202+
async buildNotes (rawCommits, { version, previousTag, currentTag, changelogSections }) {
165203
// get authors for commits for each sha
166-
const authorsByCommit = await this.#getAuthorsForCommits(commits)
204+
const authors = await this.#getAuthorsForCommits(rawCommits)
167205

168206
// when rebase merging multiple commits with a single PR, only the first commit
169207
// will have a pr number when coming from release-please. this check will manually
170208
// lookup commits without a pr number and find one if it exists
171-
const pullRequestByCommit = await this.#getPullRequestForCommits(commits)
209+
const prNumbers = await this.#getPullRequestNumbersForCommits(rawCommits)
210+
211+
const fullCommits = rawCommits.map((commit) => {
212+
commit.authors = authors[commit.sha] ?? []
213+
commit.pullRequestNumber = Number(commit.pullRequest?.number ?? prNumbers[commit.sha])
214+
return commit
215+
})
172216

173217
const changelog = new Changelog({
174218
version,
@@ -178,12 +222,9 @@ class ChangelogNotes {
178222
sections: changelogSections,
179223
})
180224

181-
for (const commit of commits) {
225+
for (const commit of this.#filterCommits(fullCommits)) {
182226
// Collect commits by type
183-
changelog.add(commit.type, this.#buildEntry(commit, {
184-
authors: authorsByCommit[commit.sha],
185-
pullRequest: pullRequestByCommit[commit.sha],
186-
}))
227+
changelog.add(commit.type, this.#buildEntry(commit))
187228

188229
// And breaking changes to its own section
189230
changelog.add(Changelog.BREAKING, ...commit.notes

test/release/changelog.js

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ const mockGitHub = ({ commits, authors }) => ({
3636
},
3737
})
3838

39-
const mockChangelog = async ({ shas = true, authors = true, previousTag = true } = {}) => {
40-
const commits = [{
39+
const mockChangelog = async ({
40+
shas = true,
41+
authors = true,
42+
previousTag = true,
43+
commits: rawCommits = [{
4144
sha: 'a',
4245
type: 'feat',
43-
notes: [],
4446
bareMessage: 'Hey now',
4547
scope: 'bin',
4648
}, {
@@ -55,13 +57,15 @@ const mockChangelog = async ({ shas = true, authors = true, previousTag = true }
5557
sha: 'c',
5658
type: 'deps',
5759
bareMessage: 'test@1.2.3',
58-
notes: [],
5960
}, {
6061
sha: 'd',
6162
type: 'fix',
6263
bareMessage: 'this fixes it',
63-
notes: [],
64-
}].map(({ sha, ...rest }) => shas ? { sha, ...rest } : rest)
64+
}],
65+
} = {}) => {
66+
const commits = rawCommits
67+
.map(({ notes = [], ...rest }) => ({ notes, ...rest }))
68+
.map(({ sha, ...rest }) => shas ? { sha, ...rest } : { ...rest })
6569

6670
const github = mockGitHub({ commits, authors })
6771
const changelog = new ChangelogNotes(github)
@@ -112,3 +116,46 @@ t.test('no tag/authors/shas', async t => {
112116
'* `test@1.2.3`',
113117
])
114118
})
119+
120+
t.test('filters out multiple template oss commits', async t => {
121+
const changelog = await mockChangelog({
122+
authors: false,
123+
commits: [{
124+
sha: 'a',
125+
type: 'chore',
126+
bareMessage: 'postinstall for dependabot template-oss PR',
127+
pullRequest: {
128+
number: '100',
129+
},
130+
}, {
131+
sha: 'b',
132+
type: 'chore',
133+
bareMessage: 'postinstall for dependabot template-oss PR',
134+
pullRequest: {
135+
number: '101',
136+
},
137+
}, {
138+
sha: 'c',
139+
type: 'chore',
140+
bareMessage: 'bump @npmcli/template-oss from 1 to 2',
141+
pullRequest: {
142+
number: '101',
143+
},
144+
}, {
145+
sha: 'd',
146+
type: 'chore',
147+
bareMessage: 'bump @npmcli/template-oss from 0 to 1',
148+
pullRequest: {
149+
number: '100',
150+
},
151+
}],
152+
})
153+
t.strictSame(changelog, [
154+
'## [1.0.0](https://github.com/npm/cli/compare/v0.1.0...v1.0.0) (DATE)',
155+
'### Chores',
156+
// eslint-disable-next-line max-len
157+
'* [`b`](https://github.com/npm/cli/commit/b) [#101](https://github.com/npm/cli/pull/101) postinstall for dependabot template-oss PR',
158+
// eslint-disable-next-line max-len
159+
'* [`c`](https://github.com/npm/cli/commit/c) [#101](https://github.com/npm/cli/pull/101) bump @npmcli/template-oss from 1 to 2',
160+
])
161+
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy