mirror of
https://github.com/dependabot/fetch-metadata.git
synced 2026-03-12 18:07:12 -04:00
Merge pull request #146 from pangaeatech/get_compat_score
Return compatibility score
This commit is contained in:
@@ -25,6 +25,7 @@ jobs:
|
|||||||
uses: dependabot/fetch-metadata@v1.2.1
|
uses: dependabot/fetch-metadata@v1.2.1
|
||||||
with:
|
with:
|
||||||
alert-lookup: true
|
alert-lookup: true
|
||||||
|
compat-lookup: true
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported inputs are:
|
Supported inputs are:
|
||||||
@@ -33,7 +34,10 @@ Supported inputs are:
|
|||||||
- The `GITHUB_TOKEN` secret
|
- The `GITHUB_TOKEN` secret
|
||||||
- Defaults to `${{ github.token }}`
|
- Defaults to `${{ github.token }}`
|
||||||
- `alert-lookup` (boolean)
|
- `alert-lookup` (boolean)
|
||||||
- If `true`, then call populate the `alert-state`, `ghsa-id` and `cvss` outputs.
|
- If `true`, then populate the `alert-state`, `ghsa-id` and `cvss` outputs.
|
||||||
|
- Defaults to `false`
|
||||||
|
- `compat-lookup` (boolean)
|
||||||
|
- If `true`, then populate the `compatibility-score` output.
|
||||||
- Defaults to `false`
|
- Defaults to `false`
|
||||||
|
|
||||||
Subsequent actions will have access to the following outputs:
|
Subsequent actions will have access to the following outputs:
|
||||||
@@ -62,6 +66,8 @@ Subsequent actions will have access to the following outputs:
|
|||||||
- If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the GHSA-ID of that alert.
|
- If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the GHSA-ID of that alert.
|
||||||
- `steps.dependabot-metadata.outputs.cvss`
|
- `steps.dependabot-metadata.outputs.cvss`
|
||||||
- If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the CVSS value of that alert (otherwise it contains 0).
|
- If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the CVSS value of that alert (otherwise it contains 0).
|
||||||
|
- `steps.dependabot-metadata.outputs.compatibility-score`
|
||||||
|
- If this PR has a known compatibility score and `compat-lookup` is `true`, this contains the compatibility score (otherwise it contains 0).
|
||||||
|
|
||||||
**Note:** These outputs will only be populated if the target Pull Request was opened by Dependabot and contains
|
**Note:** These outputs will only be populated if the target Pull Request was opened by Dependabot and contains
|
||||||
**only** Dependabot-created commits.
|
**only** Dependabot-created commits.
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ branding:
|
|||||||
inputs:
|
inputs:
|
||||||
alert-lookup:
|
alert-lookup:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'If true, then call populate the `alert-state`, `ghsa-id` and `cvss` outputs'
|
description: 'If true, then populate the `alert-state`, `ghsa-id` and `cvss` outputs'
|
||||||
|
compat-lookup:
|
||||||
|
type: boolean
|
||||||
|
description: 'If true, then populate the `compatibility-score` output'
|
||||||
github-token:
|
github-token:
|
||||||
description: 'The GITHUB_TOKEN secret'
|
description: 'The GITHUB_TOKEN secret'
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
@@ -35,6 +38,8 @@ outputs:
|
|||||||
description: 'If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the GHSA-ID of that alert.'
|
description: 'If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the GHSA-ID of that alert.'
|
||||||
cvss:
|
cvss:
|
||||||
description: 'If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the CVSS value of that alert (otherwise it contains 0).'
|
description: 'If this PR is associated with a security alert and `alert-lookup` is `true`, this contains the CVSS value of that alert (otherwise it contains 0).'
|
||||||
|
compatibility-score:
|
||||||
|
description: 'If this PR has a known compatibility score and `compat-lookup` is `true`, this contains the compatibility score (otherwise it contains 0).'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
33
dist/index.js
generated
vendored
33
dist/index.js
generated
vendored
@@ -8958,6 +8958,7 @@ function set(updatedDependencies) {
|
|||||||
const target = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.targetBranch;
|
const target = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.targetBranch;
|
||||||
const prevVersion = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.prevVersion;
|
const prevVersion = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.prevVersion;
|
||||||
const newVersion = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.newVersion;
|
const newVersion = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.newVersion;
|
||||||
|
const compatScore = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.compatScore;
|
||||||
const alertState = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.alertState;
|
const alertState = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.alertState;
|
||||||
const ghsaId = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.ghsaId;
|
const ghsaId = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.ghsaId;
|
||||||
const cvss = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.cvss;
|
const cvss = firstDependency === null || firstDependency === void 0 ? void 0 : firstDependency.cvss;
|
||||||
@@ -8970,6 +8971,7 @@ function set(updatedDependencies) {
|
|||||||
core.info(`outputs.target-branch: ${target}`);
|
core.info(`outputs.target-branch: ${target}`);
|
||||||
core.info(`outputs.previous-version: ${prevVersion}`);
|
core.info(`outputs.previous-version: ${prevVersion}`);
|
||||||
core.info(`outputs.new-version: ${newVersion}`);
|
core.info(`outputs.new-version: ${newVersion}`);
|
||||||
|
core.info(`outputs.compatibility-score: ${compatScore}`);
|
||||||
core.info(`outputs.alert-state: ${alertState}`);
|
core.info(`outputs.alert-state: ${alertState}`);
|
||||||
core.info(`outputs.ghsa-id: ${ghsaId}`);
|
core.info(`outputs.ghsa-id: ${ghsaId}`);
|
||||||
core.info(`outputs.cvss: ${cvss}`);
|
core.info(`outputs.cvss: ${cvss}`);
|
||||||
@@ -8983,6 +8985,7 @@ function set(updatedDependencies) {
|
|||||||
core.setOutput('target-branch', target);
|
core.setOutput('target-branch', target);
|
||||||
core.setOutput('previous-version', prevVersion);
|
core.setOutput('previous-version', prevVersion);
|
||||||
core.setOutput('new-version', newVersion);
|
core.setOutput('new-version', newVersion);
|
||||||
|
core.setOutput('compatibility-score', compatScore);
|
||||||
core.setOutput('alert-state', alertState);
|
core.setOutput('alert-state', alertState);
|
||||||
core.setOutput('ghsa-id', ghsaId);
|
core.setOutput('ghsa-id', ghsaId);
|
||||||
core.setOutput('cvss', cvss);
|
core.setOutput('cvss', cvss);
|
||||||
@@ -9042,12 +9045,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.parse = void 0;
|
exports.parse = void 0;
|
||||||
const YAML = __importStar(__nccwpck_require__(4603));
|
const YAML = __importStar(__nccwpck_require__(4603));
|
||||||
function parse(commitMessage, branchName, mainBranch, lookup) {
|
function parse(commitMessage, branchName, mainBranch, lookup, getScore) {
|
||||||
var _a, _b, _c, _d;
|
var _a, _b, _c, _d;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const bumpFragment = commitMessage.match(/^Bumps .* from (?<from>\d[^ ]*) to (?<to>\d[^ ]*)\.$/m);
|
const bumpFragment = commitMessage.match(/^Bumps .* from (?<from>\d[^ ]*) to (?<to>\d[^ ]*)\.$/m);
|
||||||
const yamlFragment = commitMessage.match(/^-{3}\n(?<dependencies>[\S|\s]*?)\n^\.{3}\n/m);
|
const yamlFragment = commitMessage.match(/^-{3}\n(?<dependencies>[\S|\s]*?)\n^\.{3}\n/m);
|
||||||
const lookupFn = lookup !== null && lookup !== void 0 ? lookup : (() => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 }));
|
const lookupFn = lookup !== null && lookup !== void 0 ? lookup : (() => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 }));
|
||||||
|
const scoreFn = getScore !== null && getScore !== void 0 ? getScore : (() => Promise.resolve(0));
|
||||||
if ((yamlFragment === null || yamlFragment === void 0 ? void 0 : yamlFragment.groups) && branchName.startsWith('dependabot')) {
|
if ((yamlFragment === null || yamlFragment === void 0 ? void 0 : yamlFragment.groups) && branchName.startsWith('dependabot')) {
|
||||||
const data = YAML.parse(yamlFragment.groups.dependencies);
|
const data = YAML.parse(yamlFragment.groups.dependencies);
|
||||||
// Since we are on the `dependabot` branch (9 letters), the 10th letter in the branch name is the delimiter
|
// Since we are on the `dependabot` branch (9 letters), the 10th letter in the branch name is the delimiter
|
||||||
@@ -9058,7 +9062,9 @@ function parse(commitMessage, branchName, mainBranch, lookup) {
|
|||||||
if (data['updated-dependencies']) {
|
if (data['updated-dependencies']) {
|
||||||
return yield Promise.all(data['updated-dependencies'].map((dependency, index) => __awaiter(this, void 0, void 0, function* () {
|
return yield Promise.all(data['updated-dependencies'].map((dependency, index) => __awaiter(this, void 0, void 0, function* () {
|
||||||
const dirname = `/${chunks.slice(2, -1 * (1 + (dependency['dependency-name'].match(/\//g) || []).length)).join(delim) || ''}`;
|
const dirname = `/${chunks.slice(2, -1 * (1 + (dependency['dependency-name'].match(/\//g) || []).length)).join(delim) || ''}`;
|
||||||
return Object.assign({ dependencyName: dependency['dependency-name'], dependencyType: dependency['dependency-type'], updateType: dependency['update-type'], directory: dirname, packageEcosystem: chunks[1], targetBranch: mainBranch, prevVersion: index === 0 ? prev : '', newVersion: index === 0 ? next : '' }, yield lookupFn(dependency['dependency-name'], index === 0 ? prev : '', dirname));
|
const lastVersion = index === 0 ? prev : '';
|
||||||
|
const nextVersion = index === 0 ? next : '';
|
||||||
|
return Object.assign({ dependencyName: dependency['dependency-name'], dependencyType: dependency['dependency-type'], updateType: dependency['update-type'], directory: dirname, packageEcosystem: chunks[1], targetBranch: mainBranch, prevVersion: lastVersion, newVersion: nextVersion, compatScore: yield scoreFn(dependency['dependency-name'], lastVersion, nextVersion, chunks[1]) }, yield lookupFn(dependency['dependency-name'], lastVersion, dirname));
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9127,9 +9133,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.trimSlashes = exports.getAlert = exports.getMessage = void 0;
|
exports.getCompatibility = exports.trimSlashes = exports.getAlert = exports.getMessage = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
|
const https_1 = __importDefault(__nccwpck_require__(5687));
|
||||||
const DEPENDABOT_LOGIN = 'dependabot[bot]';
|
const DEPENDABOT_LOGIN = 'dependabot[bot]';
|
||||||
function getMessage(client, context) {
|
function getMessage(client, context) {
|
||||||
var _a;
|
var _a;
|
||||||
@@ -9206,6 +9216,20 @@ function trimSlashes(value) {
|
|||||||
return value.replace(/^\/+/, '').replace(/\/+$/, '');
|
return value.replace(/^\/+/, '').replace(/\/+$/, '');
|
||||||
}
|
}
|
||||||
exports.trimSlashes = trimSlashes;
|
exports.trimSlashes = trimSlashes;
|
||||||
|
function getCompatibility(name, oldVersion, newVersion, ecosystem) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const svg = yield new Promise((resolve) => {
|
||||||
|
https_1.default.get(`https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=${name}&package-manager=${ecosystem}&previous-version=${oldVersion}&new-version=${newVersion}`, res => {
|
||||||
|
let data = '';
|
||||||
|
res.on('data', chunk => { data += chunk.toString('utf8'); });
|
||||||
|
res.on('end', () => { resolve(data); });
|
||||||
|
}).on('error', () => { resolve(''); });
|
||||||
|
});
|
||||||
|
const scoreChunk = svg.match(/<title>compatibility: (?<score>\d+)%<\/title>/m);
|
||||||
|
return (scoreChunk === null || scoreChunk === void 0 ? void 0 : scoreChunk.groups) ? parseInt(scoreChunk.groups.score) : 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getCompatibility = getCompatibility;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@@ -9270,10 +9294,11 @@ function run() {
|
|||||||
if (core.getInput('alert-lookup')) {
|
if (core.getInput('alert-lookup')) {
|
||||||
alertLookup = (name, version, directory) => verifiedCommits.getAlert(name, version, directory, githubClient, github.context);
|
alertLookup = (name, version, directory) => verifiedCommits.getAlert(name, version, directory, githubClient, github.context);
|
||||||
}
|
}
|
||||||
|
const scoreLookup = core.getInput('compat-lookup') ? verifiedCommits.getCompatibility : undefined;
|
||||||
if (commitMessage) {
|
if (commitMessage) {
|
||||||
// Parse metadata
|
// Parse metadata
|
||||||
core.info('Parsing Dependabot metadata');
|
core.info('Parsing Dependabot metadata');
|
||||||
const updatedDependencies = yield updateMetadata.parse(commitMessage, branchNames.headName, branchNames.baseName, alertLookup);
|
const updatedDependencies = yield updateMetadata.parse(commitMessage, branchNames.headName, branchNames.baseName, alertLookup, scoreLookup);
|
||||||
if (updatedDependencies.length > 0) {
|
if (updatedDependencies.length > 0) {
|
||||||
output.set(updatedDependencies);
|
output.set(updatedDependencies);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const baseDependency = {
|
|||||||
targetBranch: '',
|
targetBranch: '',
|
||||||
prevVersion: '',
|
prevVersion: '',
|
||||||
newVersion: '',
|
newVersion: '',
|
||||||
|
compatScore: 0,
|
||||||
alertState: '',
|
alertState: '',
|
||||||
ghsaId: '',
|
ghsaId: '',
|
||||||
cvss: 0
|
cvss: 0
|
||||||
@@ -34,6 +35,7 @@ test('when given a single dependency it sets its values', async () => {
|
|||||||
targetBranch: 'main',
|
targetBranch: 'main',
|
||||||
prevVersion: '1.0.2',
|
prevVersion: '1.0.2',
|
||||||
newVersion: '1.1.3-beta',
|
newVersion: '1.1.3-beta',
|
||||||
|
compatScore: 43,
|
||||||
alertState: 'FIXED',
|
alertState: 'FIXED',
|
||||||
ghsaId: 'VERY_LONG_ID',
|
ghsaId: 'VERY_LONG_ID',
|
||||||
cvss: 4.6
|
cvss: 4.6
|
||||||
@@ -56,6 +58,7 @@ test('when given a single dependency it sets its values', async () => {
|
|||||||
expect(core.setOutput).toBeCalledWith('target-branch', 'main')
|
expect(core.setOutput).toBeCalledWith('target-branch', 'main')
|
||||||
expect(core.setOutput).toBeCalledWith('previous-version', '1.0.2')
|
expect(core.setOutput).toBeCalledWith('previous-version', '1.0.2')
|
||||||
expect(core.setOutput).toBeCalledWith('new-version', '1.1.3-beta')
|
expect(core.setOutput).toBeCalledWith('new-version', '1.1.3-beta')
|
||||||
|
expect(core.setOutput).toBeCalledWith('compatibility-score', 43)
|
||||||
expect(core.setOutput).toBeCalledWith('alert-state', 'FIXED')
|
expect(core.setOutput).toBeCalledWith('alert-state', 'FIXED')
|
||||||
expect(core.setOutput).toBeCalledWith('ghsa-id', 'VERY_LONG_ID')
|
expect(core.setOutput).toBeCalledWith('ghsa-id', 'VERY_LONG_ID')
|
||||||
expect(core.setOutput).toBeCalledWith('cvss', 4.6)
|
expect(core.setOutput).toBeCalledWith('cvss', 4.6)
|
||||||
@@ -101,6 +104,7 @@ test('when given a multiple dependencies, it uses the highest values for types',
|
|||||||
expect(core.setOutput).toBeCalledWith('target-branch', '')
|
expect(core.setOutput).toBeCalledWith('target-branch', '')
|
||||||
expect(core.setOutput).toBeCalledWith('previous-version', '')
|
expect(core.setOutput).toBeCalledWith('previous-version', '')
|
||||||
expect(core.setOutput).toBeCalledWith('new-version', '')
|
expect(core.setOutput).toBeCalledWith('new-version', '')
|
||||||
|
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
|
||||||
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
||||||
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
||||||
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
||||||
@@ -131,6 +135,7 @@ test('when the dependency has no update type', async () => {
|
|||||||
expect(core.setOutput).toBeCalledWith('target-branch', '')
|
expect(core.setOutput).toBeCalledWith('target-branch', '')
|
||||||
expect(core.setOutput).toBeCalledWith('previous-version', '')
|
expect(core.setOutput).toBeCalledWith('previous-version', '')
|
||||||
expect(core.setOutput).toBeCalledWith('new-version', '')
|
expect(core.setOutput).toBeCalledWith('new-version', '')
|
||||||
|
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
|
||||||
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
||||||
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
||||||
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
||||||
@@ -174,6 +179,7 @@ test('when given a multiple dependencies, and some do not have update types', as
|
|||||||
expect(core.setOutput).toBeCalledWith('target-branch', '')
|
expect(core.setOutput).toBeCalledWith('target-branch', '')
|
||||||
expect(core.setOutput).toBeCalledWith('previous-version', '')
|
expect(core.setOutput).toBeCalledWith('previous-version', '')
|
||||||
expect(core.setOutput).toBeCalledWith('new-version', '')
|
expect(core.setOutput).toBeCalledWith('new-version', '')
|
||||||
|
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
|
||||||
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
||||||
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
||||||
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export function set (updatedDependencies: Array<updatedDependency>): void {
|
|||||||
const target = firstDependency?.targetBranch
|
const target = firstDependency?.targetBranch
|
||||||
const prevVersion = firstDependency?.prevVersion
|
const prevVersion = firstDependency?.prevVersion
|
||||||
const newVersion = firstDependency?.newVersion
|
const newVersion = firstDependency?.newVersion
|
||||||
|
const compatScore = firstDependency?.compatScore
|
||||||
const alertState = firstDependency?.alertState
|
const alertState = firstDependency?.alertState
|
||||||
const ghsaId = firstDependency?.ghsaId
|
const ghsaId = firstDependency?.ghsaId
|
||||||
const cvss = firstDependency?.cvss
|
const cvss = firstDependency?.cvss
|
||||||
@@ -39,6 +40,7 @@ export function set (updatedDependencies: Array<updatedDependency>): void {
|
|||||||
core.info(`outputs.target-branch: ${target}`)
|
core.info(`outputs.target-branch: ${target}`)
|
||||||
core.info(`outputs.previous-version: ${prevVersion}`)
|
core.info(`outputs.previous-version: ${prevVersion}`)
|
||||||
core.info(`outputs.new-version: ${newVersion}`)
|
core.info(`outputs.new-version: ${newVersion}`)
|
||||||
|
core.info(`outputs.compatibility-score: ${compatScore}`)
|
||||||
core.info(`outputs.alert-state: ${alertState}`)
|
core.info(`outputs.alert-state: ${alertState}`)
|
||||||
core.info(`outputs.ghsa-id: ${ghsaId}`)
|
core.info(`outputs.ghsa-id: ${ghsaId}`)
|
||||||
core.info(`outputs.cvss: ${cvss}`)
|
core.info(`outputs.cvss: ${cvss}`)
|
||||||
@@ -53,6 +55,7 @@ export function set (updatedDependencies: Array<updatedDependency>): void {
|
|||||||
core.setOutput('target-branch', target)
|
core.setOutput('target-branch', target)
|
||||||
core.setOutput('previous-version', prevVersion)
|
core.setOutput('previous-version', prevVersion)
|
||||||
core.setOutput('new-version', newVersion)
|
core.setOutput('new-version', newVersion)
|
||||||
|
core.setOutput('compatibility-score', compatScore)
|
||||||
core.setOutput('alert-state', alertState)
|
core.setOutput('alert-state', alertState)
|
||||||
core.setOutput('ghsa-id', ghsaId)
|
core.setOutput('ghsa-id', ghsaId)
|
||||||
core.setOutput('cvss', cvss)
|
core.setOutput('cvss', cvss)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import * as updateMetadata from './update_metadata'
|
|||||||
|
|
||||||
test('it returns an empty array for a blank string', async () => {
|
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 getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
|
||||||
expect(updateMetadata.parse('', 'dependabot/nuget/coffee-rails', 'main', getAlert)).resolves.toEqual([])
|
const getScore = async () => Promise.resolve(43)
|
||||||
|
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 () => {
|
test('it returns an empty array for commit message with no dependabot yaml fragment', async () => {
|
||||||
@@ -14,7 +15,8 @@ test('it returns an empty array for commit message with no dependabot yaml fragm
|
|||||||
Signed-off-by: dependabot[bot] <support@github.com>`
|
Signed-off-by: dependabot[bot] <support@github.com>`
|
||||||
|
|
||||||
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
|
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
|
||||||
expect(updateMetadata.parse(commitMessage, 'dependabot/nuget/coffee-rails', 'main', getAlert)).resolves.toEqual([])
|
const getScore = async () => Promise.resolve(43)
|
||||||
|
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 () => {
|
test('it returns the updated dependency information when there is a yaml fragment', async () => {
|
||||||
@@ -34,7 +36,8 @@ test('it returns the updated dependency information when there is a yaml fragmen
|
|||||||
'Signed-off-by: dependabot[bot] <support@github.com>'
|
'Signed-off-by: dependabot[bot] <support@github.com>'
|
||||||
|
|
||||||
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
|
const getAlert = async () => Promise.resolve({ alertState: 'DISMISSED', ghsaId: 'GHSA-III-BBB', cvss: 4.6 })
|
||||||
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/coffee-rails', 'main', getAlert)
|
const getScore = async () => Promise.resolve(43)
|
||||||
|
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/coffee-rails', 'main', getAlert, getScore)
|
||||||
|
|
||||||
expect(updatedDependencies).toHaveLength(1)
|
expect(updatedDependencies).toHaveLength(1)
|
||||||
|
|
||||||
@@ -46,6 +49,7 @@ test('it returns the updated dependency information when there is a yaml fragmen
|
|||||||
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
||||||
expect(updatedDependencies[0].prevVersion).toEqual('4.0.1')
|
expect(updatedDependencies[0].prevVersion).toEqual('4.0.1')
|
||||||
expect(updatedDependencies[0].newVersion).toEqual('4.2.2')
|
expect(updatedDependencies[0].newVersion).toEqual('4.2.2')
|
||||||
|
expect(updatedDependencies[0].compatScore).toEqual(43)
|
||||||
expect(updatedDependencies[0].alertState).toEqual('DISMISSED')
|
expect(updatedDependencies[0].alertState).toEqual('DISMISSED')
|
||||||
expect(updatedDependencies[0].ghsaId).toEqual('GHSA-III-BBB')
|
expect(updatedDependencies[0].ghsaId).toEqual('GHSA-III-BBB')
|
||||||
expect(updatedDependencies[0].cvss).toEqual(4.6)
|
expect(updatedDependencies[0].cvss).toEqual(4.6)
|
||||||
@@ -78,7 +82,15 @@ test('it supports multiple dependencies within a single fragment', async () => {
|
|||||||
return Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
|
return Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/api/main/coffee-rails', 'main', getAlert)
|
const getScore = async (name: string) => {
|
||||||
|
if (name === 'coffee-rails') {
|
||||||
|
return Promise.resolve(34)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/api/main/coffee-rails', 'main', getAlert, getScore)
|
||||||
|
|
||||||
expect(updatedDependencies).toHaveLength(2)
|
expect(updatedDependencies).toHaveLength(2)
|
||||||
|
|
||||||
@@ -90,6 +102,7 @@ test('it supports multiple dependencies within a single fragment', async () => {
|
|||||||
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
||||||
expect(updatedDependencies[0].prevVersion).toEqual('4.0.1')
|
expect(updatedDependencies[0].prevVersion).toEqual('4.0.1')
|
||||||
expect(updatedDependencies[0].newVersion).toEqual('4.2.2')
|
expect(updatedDependencies[0].newVersion).toEqual('4.2.2')
|
||||||
|
expect(updatedDependencies[0].compatScore).toEqual(34)
|
||||||
expect(updatedDependencies[0].alertState).toEqual('DISMISSED')
|
expect(updatedDependencies[0].alertState).toEqual('DISMISSED')
|
||||||
expect(updatedDependencies[0].ghsaId).toEqual('GHSA-III-BBB')
|
expect(updatedDependencies[0].ghsaId).toEqual('GHSA-III-BBB')
|
||||||
expect(updatedDependencies[0].cvss).toEqual(4.6)
|
expect(updatedDependencies[0].cvss).toEqual(4.6)
|
||||||
@@ -101,7 +114,7 @@ test('it supports multiple dependencies within a single fragment', async () => {
|
|||||||
expect(updatedDependencies[1].packageEcosystem).toEqual('nuget')
|
expect(updatedDependencies[1].packageEcosystem).toEqual('nuget')
|
||||||
expect(updatedDependencies[1].targetBranch).toEqual('main')
|
expect(updatedDependencies[1].targetBranch).toEqual('main')
|
||||||
expect(updatedDependencies[1].prevVersion).toEqual('')
|
expect(updatedDependencies[1].prevVersion).toEqual('')
|
||||||
expect(updatedDependencies[1].newVersion).toEqual('')
|
expect(updatedDependencies[1].compatScore).toEqual(0)
|
||||||
expect(updatedDependencies[1].alertState).toEqual('')
|
expect(updatedDependencies[1].alertState).toEqual('')
|
||||||
expect(updatedDependencies[1].ghsaId).toEqual('')
|
expect(updatedDependencies[1].ghsaId).toEqual('')
|
||||||
expect(updatedDependencies[1].cvss).toEqual(0)
|
expect(updatedDependencies[1].cvss).toEqual(0)
|
||||||
@@ -129,7 +142,7 @@ test('it only returns information within the first fragment if there are multipl
|
|||||||
'\n' +
|
'\n' +
|
||||||
'Signed-off-by: dependabot[bot] <support@github.com>'
|
'Signed-off-by: dependabot[bot] <support@github.com>'
|
||||||
|
|
||||||
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot|nuget|coffee-rails', 'main', undefined)
|
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot|nuget|coffee-rails', 'main', undefined, undefined)
|
||||||
|
|
||||||
expect(updatedDependencies).toHaveLength(1)
|
expect(updatedDependencies).toHaveLength(1)
|
||||||
|
|
||||||
@@ -141,6 +154,7 @@ test('it only returns information within the first fragment if there are multipl
|
|||||||
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
||||||
expect(updatedDependencies[0].prevVersion).toEqual('')
|
expect(updatedDependencies[0].prevVersion).toEqual('')
|
||||||
expect(updatedDependencies[0].newVersion).toEqual('')
|
expect(updatedDependencies[0].newVersion).toEqual('')
|
||||||
|
expect(updatedDependencies[0].compatScore).toEqual(0)
|
||||||
expect(updatedDependencies[0].alertState).toEqual('')
|
expect(updatedDependencies[0].alertState).toEqual('')
|
||||||
expect(updatedDependencies[0].ghsaId).toEqual('')
|
expect(updatedDependencies[0].ghsaId).toEqual('')
|
||||||
expect(updatedDependencies[0].cvss).toEqual(0)
|
expect(updatedDependencies[0].cvss).toEqual(0)
|
||||||
@@ -162,7 +176,8 @@ test('it properly handles dependencies which contain slashes', async () => {
|
|||||||
'Signed-off-by: dependabot[bot] <support@github.com>'
|
'Signed-off-by: dependabot[bot] <support@github.com>'
|
||||||
|
|
||||||
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
|
const getAlert = async () => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 })
|
||||||
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/api/rails/coffee', 'main', getAlert)
|
const getScore = async () => Promise.resolve(0)
|
||||||
|
const updatedDependencies = await updateMetadata.parse(commitMessage, 'dependabot/nuget/api/rails/coffee', 'main', getAlert, getScore)
|
||||||
|
|
||||||
expect(updatedDependencies).toHaveLength(1)
|
expect(updatedDependencies).toHaveLength(1)
|
||||||
|
|
||||||
@@ -174,6 +189,7 @@ test('it properly handles dependencies which contain slashes', async () => {
|
|||||||
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
expect(updatedDependencies[0].targetBranch).toEqual('main')
|
||||||
expect(updatedDependencies[0].prevVersion).toEqual('')
|
expect(updatedDependencies[0].prevVersion).toEqual('')
|
||||||
expect(updatedDependencies[0].newVersion).toEqual('')
|
expect(updatedDependencies[0].newVersion).toEqual('')
|
||||||
|
expect(updatedDependencies[0].compatScore).toEqual(0)
|
||||||
expect(updatedDependencies[0].alertState).toEqual('')
|
expect(updatedDependencies[0].alertState).toEqual('')
|
||||||
expect(updatedDependencies[0].ghsaId).toEqual('')
|
expect(updatedDependencies[0].ghsaId).toEqual('')
|
||||||
expect(updatedDependencies[0].cvss).toEqual(0)
|
expect(updatedDependencies[0].cvss).toEqual(0)
|
||||||
|
|||||||
@@ -14,17 +14,23 @@ export interface updatedDependency extends dependencyAlert {
|
|||||||
packageEcosystem: string,
|
packageEcosystem: string,
|
||||||
targetBranch: string,
|
targetBranch: string,
|
||||||
prevVersion: string,
|
prevVersion: string,
|
||||||
newVersion: string
|
newVersion: string,
|
||||||
|
compatScore: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface alertLookup {
|
export interface alertLookup {
|
||||||
(dependencyName: string, dependencyVersion: string, directory: string): Promise<dependencyAlert>;
|
(dependencyName: string, dependencyVersion: string, directory: string): Promise<dependencyAlert>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parse (commitMessage: string, branchName: string, mainBranch: string, lookup?: alertLookup): Promise<Array<updatedDependency>> {
|
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>> {
|
||||||
const bumpFragment = commitMessage.match(/^Bumps .* from (?<from>\d[^ ]*) to (?<to>\d[^ ]*)\.$/m)
|
const bumpFragment = commitMessage.match(/^Bumps .* from (?<from>\d[^ ]*) to (?<to>\d[^ ]*)\.$/m)
|
||||||
const yamlFragment = commitMessage.match(/^-{3}\n(?<dependencies>[\S|\s]*?)\n^\.{3}\n/m)
|
const yamlFragment = commitMessage.match(/^-{3}\n(?<dependencies>[\S|\s]*?)\n^\.{3}\n/m)
|
||||||
const lookupFn = lookup ?? (() => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 }))
|
const lookupFn = lookup ?? (() => Promise.resolve({ alertState: '', ghsaId: '', cvss: 0 }))
|
||||||
|
const scoreFn = getScore ?? (() => Promise.resolve(0))
|
||||||
|
|
||||||
if (yamlFragment?.groups && branchName.startsWith('dependabot')) {
|
if (yamlFragment?.groups && branchName.startsWith('dependabot')) {
|
||||||
const data = YAML.parse(yamlFragment.groups.dependencies)
|
const data = YAML.parse(yamlFragment.groups.dependencies)
|
||||||
@@ -38,6 +44,8 @@ export async function parse (commitMessage: string, branchName: string, mainBran
|
|||||||
if (data['updated-dependencies']) {
|
if (data['updated-dependencies']) {
|
||||||
return await Promise.all(data['updated-dependencies'].map(async (dependency, index) => {
|
return await Promise.all(data['updated-dependencies'].map(async (dependency, index) => {
|
||||||
const dirname = `/${chunks.slice(2, -1 * (1 + (dependency['dependency-name'].match(/\//g) || []).length)).join(delim) || ''}`
|
const dirname = `/${chunks.slice(2, -1 * (1 + (dependency['dependency-name'].match(/\//g) || []).length)).join(delim) || ''}`
|
||||||
|
const lastVersion = index === 0 ? prev : ''
|
||||||
|
const nextVersion = index === 0 ? next : ''
|
||||||
return {
|
return {
|
||||||
dependencyName: dependency['dependency-name'],
|
dependencyName: dependency['dependency-name'],
|
||||||
dependencyType: dependency['dependency-type'],
|
dependencyType: dependency['dependency-type'],
|
||||||
@@ -45,9 +53,10 @@ export async function parse (commitMessage: string, branchName: string, mainBran
|
|||||||
directory: dirname,
|
directory: dirname,
|
||||||
packageEcosystem: chunks[1],
|
packageEcosystem: chunks[1],
|
||||||
targetBranch: mainBranch,
|
targetBranch: mainBranch,
|
||||||
prevVersion: index === 0 ? prev : '',
|
prevVersion: lastVersion,
|
||||||
newVersion: index === 0 ? next : '',
|
newVersion: nextVersion,
|
||||||
...await lookupFn(dependency['dependency-name'], index === 0 ? prev : '', dirname)
|
compatScore: await scoreFn(dependency['dependency-name'], lastVersion, nextVersion, chunks[1]),
|
||||||
|
...await lookupFn(dependency['dependency-name'], lastVersion, dirname)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as github from '@actions/github'
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import nock from 'nock'
|
import nock from 'nock'
|
||||||
import { Context } from '@actions/github/lib/context'
|
import { Context } from '@actions/github/lib/context'
|
||||||
import { getAlert, getMessage, trimSlashes } from './verified_commits'
|
import { getAlert, getMessage, trimSlashes, getCompatibility } from './verified_commits'
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
nock.disableNetConnect()
|
nock.disableNetConnect()
|
||||||
@@ -177,6 +177,48 @@ test('trimSlashes should only trim slashes from both ends', () => {
|
|||||||
expect(trimSlashes('//a//b//c//')).toEqual('a//b//c')
|
expect(trimSlashes('//a//b//c//')).toEqual('a//b//c')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const svgContents = `<svg width="132.9" height="20" viewBox="0 0 1329 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="compatibility: 75%">
|
||||||
|
<title>compatibility: 75%</title>
|
||||||
|
<linearGradient id="a" x2="0" y2="100%">
|
||||||
|
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
|
||||||
|
<stop offset="1" stop-opacity=".1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<mask id="m"><rect width="1329" height="200" rx="30" fill="#FFF"/></mask>
|
||||||
|
<g mask="url(#m)">
|
||||||
|
<rect width="969" height="200" fill="#555"/>
|
||||||
|
<rect width="360" height="200" fill="#3C1" x="969"/>
|
||||||
|
<rect width="1329" height="200" fill="url(#a)"/>
|
||||||
|
</g>
|
||||||
|
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
|
||||||
|
<text x="220" y="148" textLength="709" fill="#000" opacity="0.25">compatibility</text>
|
||||||
|
<text x="210" y="138" textLength="709">compatibility</text>
|
||||||
|
<text x="1024" y="148" textLength="260" fill="#000" opacity="0.25">75%</text>
|
||||||
|
<text x="1014" y="138" textLength="260">75%</text>
|
||||||
|
</g>
|
||||||
|
<image x="40" y="35" width="130" height="130" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB2aWV3Qm94PSIwIDAgNTQgNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMzAgMTV2LTNoLTVhMSAxIDAgMDEtMS0xVjRhMSAxIDAgMDExLTFoN2ExIDEgMCAwMTEgMXYxMWgxNWEzIDMgMCAwMTMgM3YxMmgyYTEgMSAwIDAxMSAxdjEwYTEgMSAwIDAxLTEgMWgtMnY2YTMgMyAwIDAxLTMgM0g2YTMgMyAwIDAxLTMtM3YtNkgxYTEgMSAwIDAxLTEtMVYzMWExIDEgMCAwMTEtMWgyVjE4YTMgMyAwIDAxMy0zem02Ljg1NCAyMy42NDNsNi4yOS02LjI4OWExLjIxIDEuMjEgMCAwMDAtMS43MWwtMS4yOS0xLjI5YTEuMjEgMS4yMSAwIDAwLTEuNzEgMEwzNS45OTggMzMuNWwtMS42NDUtMS42NDVhMS4yMSAxLjIxIDAgMDAtMS43MSAwbC0xLjI5IDEuMjlhMS4yMSAxLjIxIDAgMDAwIDEuNzFsMy43OSAzLjc5YTEuMjEgMS4yMSAwIDAwMS43MSAwem0tMTMuNzEtNi4yODlsLTYuMjkgNi4yOWExLjIxIDEuMjEgMCAwMS0xLjcxIDBsLTMuNzktMy43OWExLjIxIDEuMjEgMCAwMTAtMS43MWwxLjI5LTEuMjlhMS4yMSAxLjIxIDAgMDExLjcxIDBMMTYgMzMuNWw0LjE0NC00LjE0NWExLjIxIDEuMjEgMCAwMTEuNzExIDBsMS4yOSAxLjI5YTEuMjEgMS4yMSAwIDAxMCAxLjcxeiIgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+Cg=="/>
|
||||||
|
</svg>`
|
||||||
|
|
||||||
|
test('getCompatibility pulls out the score', async () => {
|
||||||
|
nock('https://dependabot-badges.githubapp.com').get('/badges/compatibility_score?dependency-name=coffee-script&package-manager=npm_and_yarn&previous-version=2.1.3&new-version=2.2.0')
|
||||||
|
.reply(200, svgContents)
|
||||||
|
|
||||||
|
expect(await getCompatibility('coffee-script', '2.1.3', '2.2.0', 'npm_and_yarn')).toEqual(75)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getCompatibility fails gracefully', async () => {
|
||||||
|
nock('https://dependabot-badges.githubapp.com').get('/badges/compatibility_score?dependency-name=coffee-script&package-manager=npm_and_yarn&previous-version=2.1.3&new-version=2.2.0')
|
||||||
|
.reply(200, '')
|
||||||
|
|
||||||
|
expect(await getCompatibility('coffee-script', '2.1.3', '2.2.0', 'npm_and_yarn')).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('getCompatibility handles errors', async () => {
|
||||||
|
nock('https://dependabot-badges.githubapp.com').get('/badges/compatibility_score?dependency-name=coffee-script&package-manager=npm_and_yarn&previous-version=2.1.3&new-version=2.2.0')
|
||||||
|
.reply(500, '')
|
||||||
|
|
||||||
|
expect(await getCompatibility('coffee-script', '2.1.3', '2.2.0', 'npm_and_yarn')).toEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
const mockGitHubClient = github.getOctokit('mock-token')
|
const mockGitHubClient = github.getOctokit('mock-token')
|
||||||
|
|
||||||
function mockGitHubOtherContext (): Context {
|
function mockGitHubOtherContext (): Context {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as core from '@actions/core'
|
|||||||
import { GitHub } from '@actions/github/lib/utils'
|
import { GitHub } from '@actions/github/lib/utils'
|
||||||
import { Context } from '@actions/github/lib/context'
|
import { Context } from '@actions/github/lib/context'
|
||||||
import type { dependencyAlert } from './update_metadata'
|
import type { dependencyAlert } from './update_metadata'
|
||||||
|
import https from 'https'
|
||||||
|
|
||||||
const DEPENDABOT_LOGIN = 'dependabot[bot]'
|
const DEPENDABOT_LOGIN = 'dependabot[bot]'
|
||||||
|
|
||||||
@@ -90,3 +91,16 @@ export async function getAlert (name: string, version: string, directory: string
|
|||||||
export function trimSlashes (value: string): string {
|
export function trimSlashes (value: string): string {
|
||||||
return value.replace(/^\/+/, '').replace(/\/+$/, '')
|
return value.replace(/^\/+/, '').replace(/\/+$/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getCompatibility (name: string, oldVersion: string, newVersion: string, ecosystem: string): Promise<number> {
|
||||||
|
const svg = await new Promise<string>((resolve) => {
|
||||||
|
https.get(`https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=${name}&package-manager=${ecosystem}&previous-version=${oldVersion}&new-version=${newVersion}`, res => {
|
||||||
|
let data = ''
|
||||||
|
res.on('data', chunk => { data += chunk.toString('utf8') })
|
||||||
|
res.on('end', () => { resolve(data) })
|
||||||
|
}).on('error', () => { resolve('') })
|
||||||
|
})
|
||||||
|
|
||||||
|
const scoreChunk = svg.match(/<title>compatibility: (?<score>\d+)%<\/title>/m)
|
||||||
|
return scoreChunk?.groups ? parseInt(scoreChunk.groups.score) : 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as dotenv from 'dotenv'
|
|||||||
import { Argv } from 'yargs'
|
import { Argv } from 'yargs'
|
||||||
import { hideBin } from 'yargs/helpers'
|
import { hideBin } from 'yargs/helpers'
|
||||||
|
|
||||||
import { getMessage, getAlert } from './dependabot/verified_commits'
|
import { getMessage, getAlert, getCompatibility } from './dependabot/verified_commits'
|
||||||
import { parse } from './dependabot/update_metadata'
|
import { parse } from './dependabot/update_metadata'
|
||||||
import { getBranchNames, parseNwo } from './dependabot/util'
|
import { getBranchNames, parseNwo } from './dependabot/util'
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ async function check (args: any): Promise<void> {
|
|||||||
const branchNames = getBranchNames(newContext)
|
const branchNames = getBranchNames(newContext)
|
||||||
const lookupFn = (name, version, directory) => getAlert(name, version, directory, githubClient, actionContext)
|
const lookupFn = (name, version, directory) => getAlert(name, version, directory, githubClient, actionContext)
|
||||||
|
|
||||||
const updatedDependencies = await parse(commitMessage, branchNames.headName, branchNames.baseName, lookupFn)
|
const updatedDependencies = await parse(commitMessage, branchNames.headName, branchNames.baseName, lookupFn, getCompatibility)
|
||||||
|
|
||||||
if (updatedDependencies.length > 0) {
|
if (updatedDependencies.length > 0) {
|
||||||
console.log('Updated dependencies:')
|
console.log('Updated dependencies:')
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ test('it sets the updated dependency as an output for subsequent actions', async
|
|||||||
jest.spyOn(dependabotCommits, 'getAlert').mockImplementation(jest.fn(
|
jest.spyOn(dependabotCommits, 'getAlert').mockImplementation(jest.fn(
|
||||||
() => Promise.resolve(mockAlert)
|
() => Promise.resolve(mockAlert)
|
||||||
))
|
))
|
||||||
|
jest.spyOn(dependabotCommits, 'getCompatibility').mockImplementation(jest.fn(
|
||||||
|
() => Promise.resolve(34)
|
||||||
|
))
|
||||||
jest.spyOn(core, 'setOutput').mockImplementation(jest.fn())
|
jest.spyOn(core, 'setOutput').mockImplementation(jest.fn())
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
@@ -106,6 +109,7 @@ test('it sets the updated dependency as an output for subsequent actions', async
|
|||||||
targetBranch: 'main',
|
targetBranch: 'main',
|
||||||
prevVersion: '4.0.1',
|
prevVersion: '4.0.1',
|
||||||
newVersion: '4.2.2',
|
newVersion: '4.2.2',
|
||||||
|
compatScore: 0,
|
||||||
alertState: '',
|
alertState: '',
|
||||||
ghsaId: '',
|
ghsaId: '',
|
||||||
cvss: 0
|
cvss: 0
|
||||||
@@ -121,6 +125,7 @@ test('it sets the updated dependency as an output for subsequent actions', async
|
|||||||
expect(core.setOutput).toBeCalledWith('target-branch', 'main')
|
expect(core.setOutput).toBeCalledWith('target-branch', 'main')
|
||||||
expect(core.setOutput).toBeCalledWith('previous-version', '4.0.1')
|
expect(core.setOutput).toBeCalledWith('previous-version', '4.0.1')
|
||||||
expect(core.setOutput).toBeCalledWith('new-version', '4.2.2')
|
expect(core.setOutput).toBeCalledWith('new-version', '4.2.2')
|
||||||
|
expect(core.setOutput).toBeCalledWith('compatibility-score', 0)
|
||||||
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
||||||
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
||||||
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
||||||
@@ -155,6 +160,9 @@ test('if there are multiple dependencies, it summarizes them', async () => {
|
|||||||
jest.spyOn(dependabotCommits, 'getAlert').mockImplementation(jest.fn(
|
jest.spyOn(dependabotCommits, 'getAlert').mockImplementation(jest.fn(
|
||||||
() => Promise.resolve(mockAlert)
|
() => Promise.resolve(mockAlert)
|
||||||
))
|
))
|
||||||
|
jest.spyOn(dependabotCommits, 'getCompatibility').mockImplementation(jest.fn(
|
||||||
|
() => Promise.resolve(34)
|
||||||
|
))
|
||||||
jest.spyOn(core, 'setOutput').mockImplementation(jest.fn())
|
jest.spyOn(core, 'setOutput').mockImplementation(jest.fn())
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
@@ -175,6 +183,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
|
|||||||
targetBranch: 'trunk',
|
targetBranch: 'trunk',
|
||||||
prevVersion: '4.0.1',
|
prevVersion: '4.0.1',
|
||||||
newVersion: '4.2.2',
|
newVersion: '4.2.2',
|
||||||
|
compatScore: 34,
|
||||||
alertState: '',
|
alertState: '',
|
||||||
ghsaId: '',
|
ghsaId: '',
|
||||||
cvss: 0
|
cvss: 0
|
||||||
@@ -188,6 +197,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
|
|||||||
targetBranch: 'trunk',
|
targetBranch: 'trunk',
|
||||||
prevVersion: '',
|
prevVersion: '',
|
||||||
newVersion: '',
|
newVersion: '',
|
||||||
|
compatScore: 34,
|
||||||
alertState: '',
|
alertState: '',
|
||||||
ghsaId: '',
|
ghsaId: '',
|
||||||
cvss: 0
|
cvss: 0
|
||||||
@@ -203,6 +213,7 @@ test('if there are multiple dependencies, it summarizes them', async () => {
|
|||||||
expect(core.setOutput).toBeCalledWith('target-branch', 'trunk')
|
expect(core.setOutput).toBeCalledWith('target-branch', 'trunk')
|
||||||
expect(core.setOutput).toBeCalledWith('previous-version', '4.0.1')
|
expect(core.setOutput).toBeCalledWith('previous-version', '4.0.1')
|
||||||
expect(core.setOutput).toBeCalledWith('new-version', '4.2.2')
|
expect(core.setOutput).toBeCalledWith('new-version', '4.2.2')
|
||||||
|
expect(core.setOutput).toBeCalledWith('compatibility-score', 34)
|
||||||
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
expect(core.setOutput).toBeCalledWith('alert-state', '')
|
||||||
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
expect(core.setOutput).toBeCalledWith('ghsa-id', '')
|
||||||
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
expect(core.setOutput).toBeCalledWith('cvss', 0)
|
||||||
|
|||||||
@@ -28,12 +28,13 @@ export async function run (): Promise<void> {
|
|||||||
if (core.getInput('alert-lookup')) {
|
if (core.getInput('alert-lookup')) {
|
||||||
alertLookup = (name, version, directory) => verifiedCommits.getAlert(name, version, directory, githubClient, github.context)
|
alertLookup = (name, version, directory) => verifiedCommits.getAlert(name, version, directory, githubClient, github.context)
|
||||||
}
|
}
|
||||||
|
const scoreLookup = core.getInput('compat-lookup') ? verifiedCommits.getCompatibility : undefined
|
||||||
|
|
||||||
if (commitMessage) {
|
if (commitMessage) {
|
||||||
// Parse metadata
|
// Parse metadata
|
||||||
core.info('Parsing Dependabot metadata')
|
core.info('Parsing Dependabot metadata')
|
||||||
|
|
||||||
const updatedDependencies = await updateMetadata.parse(commitMessage, branchNames.headName, branchNames.baseName, alertLookup)
|
const updatedDependencies = await updateMetadata.parse(commitMessage, branchNames.headName, branchNames.baseName, alertLookup, scoreLookup)
|
||||||
|
|
||||||
if (updatedDependencies.length > 0) {
|
if (updatedDependencies.length > 0) {
|
||||||
output.set(updatedDependencies)
|
output.set(updatedDependencies)
|
||||||
|
|||||||
Reference in New Issue
Block a user