Skip to content

Commit a44a9df

Browse files
committed
Handle branch names containing hyphen separators
1 parent 518993c commit a44a9df

File tree

5 files changed

+154
-6
lines changed

5 files changed

+154
-6
lines changed

dist/index.js

+23-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dependabot/update_metadata.test.ts

+100-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ test('it supports multiple dependencies within a single fragment', async () => {
106106
return Promise.resolve(0)
107107
}
108108

109-
const updatedDependencies = await updateMetadata.parse(commitMessage, body, 'dependabot/nuget/api/main/coffee-rails', 'main', getAlert, getScore)
109+
const updatedDependencies = await updateMetadata.parse(commitMessage, body, 'dependabot/nuget/api/main/coffee-rails/and/coffeescript', 'main', getAlert, getScore)
110110

111111
expect(updatedDependencies).toHaveLength(2)
112112

@@ -299,6 +299,105 @@ test('it properly handles dependencies which contain slashes', async () => {
299299
expect(updatedDependencies[0].dependencyGroup).toEqual('')
300300
})
301301

302+
test('it handles branch names with hyphen separator', async () => {
303+
const commitMessage =
304+
'- [Release notes](https://github.com/fsevents/fsevents/releases)\n' +
305+
'- [Commits](fsevents/[email protected])\n' +
306+
'\n' +
307+
'---\n' +
308+
'updated-dependencies:\n' +
309+
'- dependency-name: fsevents\n' +
310+
' dependency-type: indirect\n' +
311+
'...\n' +
312+
'\n' +
313+
'Signed-off-by: dependabot[bot] <[email protected]>'
314+
315+
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
316+
const getScore = async () => Promise.resolve(0)
317+
const updatedDependencies = await updateMetadata.parse(commitMessage, '', 'dependabot-npm_and_yarn-fsevents-1.2.13', 'master', getAlert, getScore)
318+
319+
expect(updatedDependencies[0].directory).toEqual('/')
320+
})
321+
322+
test('it handles branch names with hyphen separator and manifest files in nested directories', async () => {
323+
const commitMessage =
324+
'- [Release notes](https://github.com/fsevents/fsevents/releases)\n' +
325+
'- [Commits](fsevents/[email protected])\n' +
326+
'\n' +
327+
'---\n' +
328+
'updated-dependencies:\n' +
329+
'- dependency-name: fsevents\n' +
330+
' dependency-type: indirect\n' +
331+
'...\n' +
332+
'\n' +
333+
'Signed-off-by: dependabot[bot] <[email protected]>'
334+
335+
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
336+
const getScore = async () => Promise.resolve(0)
337+
const updatedDependencies = await updateMetadata.parse(commitMessage, '', 'dependabot-npm_and_yarn-nested-nested-fsevents-1.2.13', 'master', getAlert, getScore)
338+
339+
expect(updatedDependencies[0].directory).toEqual('/nested/nested')
340+
})
341+
342+
test('it handles branch names with hyphen separator and dependency names with forward slashes', async () => {
343+
const commitMessage =
344+
'- [Release notes](https://github.com/composer/composer/releases)\n' +
345+
'- [Changelog](https://github.com/composer/composer/blob/main/CHANGELOG.md)\n' +
346+
'- [Commits](composer/[email protected])\n' +
347+
'\n' +
348+
'---\n' +
349+
'updated-dependencies:\n' +
350+
'- dependency-name: composer/composer\n' +
351+
' dependency-type: indirect\n' +
352+
'...\n' +
353+
'\n' +
354+
'Signed-off-by: dependabot[bot] <[email protected]>'
355+
356+
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
357+
const getScore = async () => Promise.resolve(0)
358+
const updatedDependencies = await updateMetadata.parse(commitMessage, '', 'dependabot-composer-composer-composer-2.6.5', 'master', getAlert, getScore)
359+
360+
expect(updatedDependencies[0].directory).toEqual('/')
361+
})
362+
363+
test('it handles branch names with hyphen separator and multiple dependencies', async () => {
364+
const commitMessage =
365+
'Updates `twilio-video` from 2.7.0 to 2.28.1\n' +
366+
'- [Release notes](https://github.com/twilio/twilio-video.js/releases)\n' +
367+
'- [Changelog](https://github.com/twilio/twilio-video.js/blob/master/CHANGELOG.md)\n' +
368+
'- [Commits](twilio/[email protected])\n' +
369+
'\n' +
370+
'Updates `@types/twilio-video` from 2.7.0 to 2.11.0\n' +
371+
'- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)\n' +
372+
'- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/twilio-video)\n' +
373+
'\n' +
374+
'---\n' +
375+
'updated-dependencies:\n' +
376+
'- dependency-name: twilio-video\n' +
377+
' dependency-type: direct:production\n' +
378+
' update-type: version-update:semver-minor\n' +
379+
'- dependency-name: "@types/twilio-video"\n' +
380+
' dependency-type: direct:development\n' +
381+
' update-type: version-update:semver-minor\n' +
382+
'...\n' +
383+
'\n' +
384+
'Signed-off-by: dependabot[bot] <[email protected]>'
385+
386+
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
387+
const getScore = async () => Promise.resolve(0)
388+
389+
const updatedDependencies = await updateMetadata.parse(
390+
commitMessage,
391+
'',
392+
'dependabot-npm_and_yarn-twilio-video-and-types-twilio-video-2.28.1',
393+
'master',
394+
getAlert,
395+
getScore
396+
)
397+
398+
expect(updatedDependencies[0].directory).toEqual('/')
399+
})
400+
302401
test('calculateUpdateType should handle all paths', () => {
303402
expect(updateMetadata.calculateUpdateType('', '')).toEqual('')
304403
expect(updateMetadata.calculateUpdateType('', '1')).toEqual('')

src/dependabot/update_metadata.ts

+29-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,32 @@ export interface scoreLookup {
2828
(dependencyName: string, previousVersion: string, newVersion: string, ecosystem: string): Promise<number>;
2929
}
3030

31+
function branchNameToDirectoryName (chunks: string[], delimiter: string, updatedDependencies: any): string {
32+
// We can always slice after the first 2 pieces, because they will always contain "dependabot" followed by the name
33+
// of the package ecosystem. e.g. "dependabot/npm_and_yarn".
34+
const sliceStart = 2
35+
let sliceEnd = chunks.length
36+
37+
// If the delimiter is "-", we assume the last piece of the branch name is a version number.
38+
if (delimiter === '-') {
39+
sliceEnd -= 1
40+
}
41+
42+
// If there is more than 1 dependency name being updated, we assume 1 piece of the branch name will be "and".
43+
if (updatedDependencies.length > 1) {
44+
sliceEnd -= 1
45+
}
46+
47+
updatedDependencies.forEach(dependency => {
48+
// After replacing "/" in the dependency name with the delimiter, which could also be "/", we count how many pieces
49+
// the dependency name would split into by the delimiter, and slicing that amount off the end of the branch name.
50+
// e.g. "@types/twilio-video" and a delimiter of "-" would show up in the branch name as "types-twilio-video".
51+
sliceEnd -= dependency['dependency-name'].replace('/', delimiter).split(delimiter).length
52+
})
53+
54+
return `/${chunks.slice(sliceStart, sliceEnd).join('/')}`
55+
}
56+
3157
export async function parse (commitMessage: string, body: string, branchName: string, mainBranch: string, lookup?: alertLookup, getScore?: scoreLookup): Promise<Array<updatedDependency>> {
3258
const bumpFragment = commitMessage.match(/^Bumps .* from (?<from>v?\d[^ ]*) to (?<to>v?\d[^ ]*)\.$/m)
3359
const updateFragment = commitMessage.match(/^Update .* requirement from \S*? ?(?<from>v?\d\S*) to \S*? ?(?<to>v?\d\S*)$/m)
@@ -48,8 +74,9 @@ export async function parse (commitMessage: string, body: string, branchName: st
4874
const dependencyGroup = groupName?.groups?.name ?? ''
4975

5076
if (data['updated-dependencies']) {
77+
const dirname = branchNameToDirectoryName(chunks, delim, data['updated-dependencies'])
78+
5179
return await Promise.all(data['updated-dependencies'].map(async (dependency, index) => {
52-
const dirname = `/${chunks.slice(2, -1 * (1 + (dependency['dependency-name'].match(/\//g) || []).length)).join(delim) || ''}`
5380
const lastVersion = index === 0 ? prev : ''
5481
const nextVersion = index === 0 ? next : ''
5582
const updateType = dependency['update-type'] || calculateUpdateType(lastVersion, nextVersion)
@@ -64,7 +91,7 @@ export async function parse (commitMessage: string, body: string, branchName: st
6491
newVersion: nextVersion,
6592
compatScore: await scoreFn(dependency['dependency-name'], lastVersion, nextVersion, chunks[1]),
6693
maintainerChanges: newMaintainer,
67-
dependencyGroup: dependencyGroup,
94+
dependencyGroup,
6895
...await lookupFn(dependency['dependency-name'], lastVersion, dirname)
6996
}
7097
}))

src/dry-run.ts

+1
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,5 @@ require('yargs')(hideBin(process.argv))
9393
})
9494
.demandCommand(1)
9595
.help()
96+
.strict()
9697
.argv

src/main.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
415415
const mockAlert = { alertState: '', ghsaId: '', cvss: 0 }
416416

417417
jest.spyOn(core, 'getInput').mockReturnValue('mock-token')
418-
jest.spyOn(util, 'getBranchNames').mockReturnValue({ headName: 'dependabot/npm_and_yarn/api/main/feature1', baseName: 'trunk' })
418+
jest.spyOn(util, 'getBranchNames').mockReturnValue({ headName: 'dependabot/npm_and_yarn/api/main/coffee-rails/and/coffeescript', baseName: 'trunk' })
419419
jest.spyOn(dependabotCommits, 'getMessage').mockImplementation(jest.fn(
420420
() => Promise.resolve(mockCommitMessage)
421421
))

0 commit comments

Comments
 (0)