Added flag if "Maintainer changes" appears in the PR body (#174)

Ideally this would get passed over in the commit message instead of being part of the (editable) PR body. For now though we can just use the PR body.
This commit is contained in:
Michael Waddell
2023-04-24 15:14:30 -05:00
committed by GitHub
parent 5a033be007
commit 32fd3a60da
11 changed files with 72 additions and 15 deletions

View File

@@ -19,6 +19,7 @@ const baseDependency = {
prevVersion: '',
newVersion: '',
compatScore: 0,
maintainerChanges: false,
alertState: '',
ghsaId: '',
cvss: 0
@@ -36,6 +37,7 @@ test('when given a single dependency it sets its values', async () => {
prevVersion: '1.0.2',
newVersion: '1.1.3-beta',
compatScore: 43,
maintainerChanges: true,
alertState: 'FIXED',
ghsaId: 'VERY_LONG_ID',
cvss: 4.6

View File

@@ -27,6 +27,7 @@ export function set (updatedDependencies: Array<updatedDependency>): void {
const prevVersion = firstDependency?.prevVersion
const newVersion = firstDependency?.newVersion
const compatScore = firstDependency?.compatScore
const maintainerChanges = firstDependency?.maintainerChanges
const alertState = firstDependency?.alertState
const ghsaId = firstDependency?.ghsaId
const cvss = firstDependency?.cvss
@@ -41,6 +42,7 @@ export function set (updatedDependencies: Array<updatedDependency>): void {
core.info(`outputs.previous-version: ${prevVersion}`)
core.info(`outputs.new-version: ${newVersion}`)
core.info(`outputs.compatibility-score: ${compatScore}`)
core.info(`outputs.maintainer-changes: ${maintainerChanges}`)
core.info(`outputs.alert-state: ${alertState}`)
core.info(`outputs.ghsa-id: ${ghsaId}`)
core.info(`outputs.cvss: ${cvss}`)
@@ -56,6 +58,7 @@ export function set (updatedDependencies: Array<updatedDependency>): void {
core.setOutput('previous-version', prevVersion)
core.setOutput('new-version', newVersion)
core.setOutput('compatibility-score', compatScore)
core.setOutput('maintainer-changes', maintainerChanges)
core.setOutput('alert-state', alertState)
core.setOutput('ghsa-id', ghsaId)
core.setOutput('cvss', cvss)

View File

@@ -3,7 +3,7 @@ import * as updateMetadata from './update_metadata'
test('it returns an empty array for a blank string', async () => {
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
const getScore = async () => Promise.resolve(43)
expect(updateMetadata.parse('', 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)).resolves.toEqual([])
expect(updateMetadata.parse('', '', 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)).resolves.toEqual([])
})
test('it returns an empty array for commit message with no dependabot yaml fragment', async () => {
@@ -16,7 +16,7 @@ test('it returns an empty array for commit message with no dependabot yaml fragm
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
const getScore = async () => Promise.resolve(43)
expect(updateMetadata.parse(commitMessage, 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)).resolves.toEqual([])
expect(updateMetadata.parse(commitMessage, '', 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)).resolves.toEqual([])
})
test('it returns the updated dependency information when there is a yaml fragment', async () => {
@@ -33,10 +33,18 @@ test('it returns the updated dependency information when there is a yaml fragmen
'...\n' +
'\n' +
'Signed-off-by: dependabot[bot] <support@github.com>'
const body =
'Bumps [coffee-rails](https://github.com/rails/coffee-rails) from 4.0.1 to 4.2.2.\n' +
'- [Release notes](https://github.com/rails/coffee-rails/releases)\n' +
'- [Changelog](https://github.com/rails/coffee-rails/blob/master/CHANGELOG.md)\n' +
'- [Commits](rails/coffee-rails@v4.0.1...v4.2.2)\n' +
'\n' +
'Maintainer changes:\n' +
'The maintainer changed!'
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
const getScore = async () => Promise.resolve(43)
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)
const updatedDependencies = await updateMetadata.parse(commitMessage, body, 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)
expect(updatedDependencies).toHaveLength(1)
@@ -49,6 +57,7 @@ test('it returns the updated dependency information when there is a yaml fragmen
expect(updatedDependencies[0].prevVersion).toEqual('4.0.1')
expect(updatedDependencies[0].newVersion).toEqual('4.2.2')
expect(updatedDependencies[0].compatScore).toEqual(43)
expect(updatedDependencies[0].maintainerChanges).toEqual(true)
expect(updatedDependencies[0].alertState).toEqual('DISMISSED')
expect(updatedDependencies[0].ghsaId).toEqual('GHSA-III-BBB')
expect(updatedDependencies[0].cvss).toEqual(4.6)
@@ -72,6 +81,13 @@ test('it supports multiple dependencies within a single fragment', async () => {
'...\n' +
'\n' +
'Signed-off-by: dependabot[bot] <support@github.com>'
const body =
'Bumps [coffee-rails](https://github.com/rails/coffee-rails) from 4.0.1 to 4.2.2.\n' +
'- [Release notes](https://github.com/rails/coffee-rails/releases)\n' +
'- [Changelog](https://github.com/rails/coffee-rails/blob/master/CHANGELOG.md)\n' +
'- [Commits](rails/coffee-rails@v4.0.1...v4.2.2)\n' +
'\n' +
'Has the maintainer changed?'
const getAlert = async (name: string) => {
if (name === 'coffee-rails') {
@@ -89,7 +105,7 @@ test('it supports multiple dependencies within a single fragment', async () => {
return Promise.resolve(0)
}
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/api/main/coffee-rails', 'main', getAlert, getScore)
const updatedDependencies = await updateMetadata.parse(commitMessage, body, 'dependabot/nuget/api/main/coffee-rails', 'main', getAlert, getScore)
expect(updatedDependencies).toHaveLength(2)
@@ -102,6 +118,7 @@ test('it supports multiple dependencies within a single fragment', async () => {
expect(updatedDependencies[0].prevVersion).toEqual('4.0.1')
expect(updatedDependencies[0].newVersion).toEqual('4.2.2')
expect(updatedDependencies[0].compatScore).toEqual(34)
expect(updatedDependencies[0].maintainerChanges).toEqual(false)
expect(updatedDependencies[0].alertState).toEqual('DISMISSED')
expect(updatedDependencies[0].ghsaId).toEqual('GHSA-III-BBB')
expect(updatedDependencies[0].cvss).toEqual(4.6)
@@ -114,6 +131,7 @@ test('it supports multiple dependencies within a single fragment', async () => {
expect(updatedDependencies[1].targetBranch).toEqual('main')
expect(updatedDependencies[1].prevVersion).toEqual('')
expect(updatedDependencies[1].compatScore).toEqual(0)
expect(updatedDependencies[1].maintainerChanges).toEqual(false)
expect(updatedDependencies[1].alertState).toEqual('')
expect(updatedDependencies[1].ghsaId).toEqual('')
expect(updatedDependencies[1].cvss).toEqual(0)
@@ -136,7 +154,7 @@ test('it returns the updated dependency information when there is a leading v in
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
const getScore = async () => Promise.resolve(43)
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)
const updatedDependencies = await updateMetadata.parse(commitMessage, '', 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)
expect(updatedDependencies).toHaveLength(1)
@@ -176,7 +194,7 @@ test('it only returns information within the first fragment if there are multipl
'\n' +
'Signed-off-by: dependabot[bot] <support@github.com>'
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot|nuget|coffee-rails', 'main', undefined, undefined)
const updatedDependencies = await updateMetadata.parse(commitMessage, '', 'dependabot|nuget|coffee-rails', 'main', undefined, undefined)
expect(updatedDependencies).toHaveLength(1)
@@ -189,6 +207,7 @@ test('it only returns information within the first fragment if there are multipl
expect(updatedDependencies[0].prevVersion).toEqual('')
expect(updatedDependencies[0].newVersion).toEqual('')
expect(updatedDependencies[0].compatScore).toEqual(0)
expect(updatedDependencies[0].maintainerChanges).toEqual(false)
expect(updatedDependencies[0].alertState).toEqual('')
expect(updatedDependencies[0].ghsaId).toEqual('')
expect(updatedDependencies[0].cvss).toEqual(0)
@@ -211,7 +230,7 @@ test('it properly handles dependencies which contain slashes', async () => {
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
const getScore = async () => Promise.resolve(0)
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/api/rails/coffee', 'main', getAlert, getScore)
const updatedDependencies = await updateMetadata.parse(commitMessage, '', 'dependabot/nuget/api/rails/coffee', 'main', getAlert, getScore)
expect(updatedDependencies).toHaveLength(1)
@@ -224,6 +243,7 @@ test('it properly handles dependencies which contain slashes', async () => {
expect(updatedDependencies[0].prevVersion).toEqual('')
expect(updatedDependencies[0].newVersion).toEqual('')
expect(updatedDependencies[0].compatScore).toEqual(0)
expect(updatedDependencies[0].maintainerChanges).toEqual(false)
expect(updatedDependencies[0].alertState).toEqual('')
expect(updatedDependencies[0].ghsaId).toEqual('')
expect(updatedDependencies[0].cvss).toEqual(0)

View File

@@ -15,7 +15,8 @@ export interface updatedDependency extends dependencyAlert {
targetBranch: string,
prevVersion: string,
newVersion: string,
compatScore: number
compatScore: number,
maintainerChanges: boolean
}
export interface alertLookup {
@@ -26,10 +27,11 @@ export interface scoreLookup {
(dependencyName: string, previousVersion: string, newVersion: string, ecosystem: string): Promise<number>;
}
export async function parse (commitMessage: string, branchName: string, mainBranch: string, lookup?: alertLookup, getScore?: scoreLookup): Promise<Array<updatedDependency>> {
export async function parse (commitMessage: string, body: string, branchName: string, mainBranch: string, lookup?: alertLookup, getScore?: scoreLookup): Promise<Array<updatedDependency>> {
const bumpFragment = commitMessage.match(/^Bumps .* from (?<from>v?\d[^ ]*) to (?<to>v?\d[^ ]*)\.$/m)
const updateFragment = commitMessage.match(/^Update .* requirement from \S*? ?(?<from>v?\d[^ ]*) to \S*? ?(?<to>v?\d[^ ]*)$/m)
const yamlFragment = commitMessage.match(/^-{3}\n(?<dependencies>[\S|\s]*?)\n^\.{3}\n/m)
const newMaintainer = !!body.match(/Maintainer changes/m)
const lookupFn = lookup ?? (() => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 }))
const scoreFn = getScore ?? (() => Promise.resolve(0))
@@ -58,6 +60,7 @@ export async function parse (commitMessage: string, branchName: string, mainBran
prevVersion: lastVersion,
newVersion: nextVersion,
compatScore: await scoreFn(dependency['dependency-name'], lastVersion, nextVersion, chunks[1]),
maintainerChanges: newMaintainer,
...await lookupFn(dependency['dependency-name'], lastVersion, dirname)
}
}))

View File

@@ -19,3 +19,8 @@ export function getBranchNames (context: Context): branchNames {
const { pull_request: pr } = context.payload
return { headName: pr?.head.ref || '', baseName: pr?.base.ref }
}
export function getBody (context: Context): string {
const { pull_request: pr } = context.payload
return pr?.body || ''
}

View File

@@ -53,7 +53,7 @@ async function check (args: any): Promise<void> {
const branchNames = getBranchNames(newContext)
const lookupFn = (name, version, directory) => getAlert(name, version, directory, githubClient, actionContext)
const updatedDependencies = await parse(commitMessage, branchNames.headName, branchNames.baseName, lookupFn, getCompatibility)
const updatedDependencies = await parse(commitMessage, pullRequest.body, branchNames.headName, branchNames.baseName, lookupFn, getCompatibility)
if (updatedDependencies.length > 0) {
console.log('Updated dependencies:')

View File

@@ -111,6 +111,7 @@ test('it sets the updated dependency as an output for subsequent actions when gi
prevVersion: '4.0.1',
newVersion: '4.2.2',
compatScore: 0,
maintainerChanges: false,
alertState: '',
ghsaId: '',
cvss: 0
@@ -127,6 +128,7 @@ test('it sets the updated dependency as an output for subsequent actions when gi
expect(core.setOutput).toBeCalledWith('previous-version', '4.0.1')
expect(core.setOutput).toBeCalledWith('new-version', '4.2.2')
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
expect(core.setOutput).toBeCalledWith('maintainer-changes', false)
expect(core.setOutput).toBeCalledWith('alert-state', '')
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
expect(core.setOutput).toBeCalledWith('cvss', 0)
@@ -176,6 +178,7 @@ test('it sets the updated dependency as an output for subsequent actions when th
updateType: 'version-update:semver-minor',
directory: '/',
packageEcosystem: 'nuget',
maintainerChanges: false,
targetBranch: 'main',
prevVersion: 'v4.0.1',
newVersion: 'v4.2.2',
@@ -196,6 +199,7 @@ test('it sets the updated dependency as an output for subsequent actions when th
expect(core.setOutput).toBeCalledWith('previous-version', 'v4.0.1')
expect(core.setOutput).toBeCalledWith('new-version', 'v4.2.2')
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
expect(core.setOutput).toBeCalledWith('maintainer-changes', false)
expect(core.setOutput).toBeCalledWith('alert-state', '')
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
expect(core.setOutput).toBeCalledWith('cvss', 0)
@@ -247,6 +251,7 @@ test('it sets the updated dependency as an output for subsequent actions when gi
directory: '/',
packageEcosystem: 'bundler',
targetBranch: 'main',
maintainerChanges: false,
prevVersion: '1.30.1',
newVersion: '1.31.0',
compatScore: 0,
@@ -266,6 +271,7 @@ test('it sets the updated dependency as an output for subsequent actions when gi
expect(core.setOutput).toBeCalledWith('previous-version', '1.30.1')
expect(core.setOutput).toBeCalledWith('new-version', '1.31.0')
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
expect(core.setOutput).toBeCalledWith('maintainer-changes', false)
expect(core.setOutput).toBeCalledWith('alert-state', '')
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
expect(core.setOutput).toBeCalledWith('cvss', 0)
@@ -324,6 +330,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
prevVersion: '4.0.1',
newVersion: '4.2.2',
compatScore: 34,
maintainerChanges: false,
alertState: '',
ghsaId: '',
cvss: 0
@@ -338,6 +345,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
prevVersion: '',
newVersion: '',
compatScore: 34,
maintainerChanges: false,
alertState: '',
ghsaId: '',
cvss: 0
@@ -354,6 +362,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
expect(core.setOutput).toBeCalledWith('previous-version', '4.0.1')
expect(core.setOutput).toBeCalledWith('new-version', '4.2.2')
expect(core.setOutput).toBeCalledWith('compatibility-score', 34)
expect(core.setOutput).toBeCalledWith('maintainer-changes', false)
expect(core.setOutput).toBeCalledWith('alert-state', '')
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
expect(core.setOutput).toBeCalledWith('cvss', 0)

View File

@@ -24,6 +24,7 @@ export async function run (): Promise<void> {
// Validate the job
const commitMessage = await verifiedCommits.getMessage(githubClient, github.context, core.getBooleanInput('skip-commit-verification'), core.getBooleanInput('skip-verification'))
const branchNames = util.getBranchNames(github.context)
const body = util.getBody(github.context)
let alertLookup: updateMetadata.alertLookup | undefined
if (core.getInput('alert-lookup')) {
alertLookup = (name, version, directory) => verifiedCommits.getAlert(name, version, directory, githubClient, github.context)
@@ -34,7 +35,7 @@ export async function run (): Promise<void> {
// Parse metadata
core.info('Parsing Dependabot metadata')
const updatedDependencies = await updateMetadata.parse(commitMessage, branchNames.headName, branchNames.baseName, alertLookup, scoreLookup)
const updatedDependencies = await updateMetadata.parse(commitMessage, body, branchNames.headName, branchNames.baseName, alertLookup, scoreLookup)
if (updatedDependencies.length > 0) {
output.set(updatedDependencies)