Merge pull request #556 from actions/juxtin/dr-snaps-pre-launch
Dr Snaps launch PR
This commit is contained in:
@@ -26,7 +26,9 @@ const defaultConfig: ConfigurationOptions = {
|
|||||||
deny_licenses: [],
|
deny_licenses: [],
|
||||||
deny_packages: [],
|
deny_packages: [],
|
||||||
deny_groups: [],
|
deny_groups: [],
|
||||||
comment_summary_in_pr: true
|
comment_summary_in_pr: true,
|
||||||
|
retry_on_snapshot_warnings: false,
|
||||||
|
retry_on_snapshot_warnings_timeout: 120
|
||||||
}
|
}
|
||||||
|
|
||||||
const changesWithEmptyManifests: Changes = [
|
const changesWithEmptyManifests: Changes = [
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ inputs:
|
|||||||
deny-groups:
|
deny-groups:
|
||||||
description: A comma-separated list of package URLs for group(s)/namespace(s) to deny (e.g. "pkg:npm/express, pkg:pip/pycrypto")
|
description: A comma-separated list of package URLs for group(s)/namespace(s) to deny (e.g. "pkg:npm/express, pkg:pip/pycrypto")
|
||||||
required: false
|
required: false
|
||||||
|
retry-on-snapshot-warnings:
|
||||||
|
description: Whether to retry on snapshot warnings
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
retry-on-snapshot-warnings-timeout:
|
||||||
|
description: Number of seconds to wait before stopping snapshot retries.
|
||||||
|
required: false
|
||||||
|
default: 120
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
+51
-16
@@ -564,17 +564,47 @@ const git_refs_1 = __nccwpck_require__(1086);
|
|||||||
const utils_1 = __nccwpck_require__(918);
|
const utils_1 = __nccwpck_require__(918);
|
||||||
const comment_pr_1 = __nccwpck_require__(5842);
|
const comment_pr_1 = __nccwpck_require__(5842);
|
||||||
const deny_1 = __nccwpck_require__(2134);
|
const deny_1 = __nccwpck_require__(2134);
|
||||||
|
function delay(ms) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getComparison(baseRef, headRef, retryOpts) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const comparison = yield dependencyGraph.compare({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
baseRef,
|
||||||
|
headRef
|
||||||
|
});
|
||||||
|
if (comparison.snapshot_warnings.trim() !== '') {
|
||||||
|
core.info(comparison.snapshot_warnings);
|
||||||
|
if (retryOpts !== undefined) {
|
||||||
|
if (retryOpts.retryUntil < Date.now()) {
|
||||||
|
core.info(`Retry timeout exceeded. Proceeding...`);
|
||||||
|
return comparison;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.info(`Retrying in ${retryOpts.retryDelay} seconds...`);
|
||||||
|
yield delay(retryOpts.retryDelay * 1000);
|
||||||
|
return getComparison(baseRef, headRef, retryOpts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comparison;
|
||||||
|
});
|
||||||
|
}
|
||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
const config = yield (0, config_1.readConfig)();
|
const config = yield (0, config_1.readConfig)();
|
||||||
const refs = (0, git_refs_1.getRefs)(config, github.context);
|
const refs = (0, git_refs_1.getRefs)(config, github.context);
|
||||||
const comparison = yield dependencyGraph.compare({
|
const comparison = yield getComparison(refs.base, refs.head, config.retry_on_snapshot_warnings
|
||||||
owner: github.context.repo.owner,
|
? {
|
||||||
repo: github.context.repo.repo,
|
retryUntil: Date.now() + config.retry_on_snapshot_warnings_timeout * 1000,
|
||||||
baseRef: refs.base,
|
retryDelay: 10
|
||||||
headRef: refs.head
|
}
|
||||||
});
|
: undefined);
|
||||||
const changes = comparison.changes;
|
const changes = comparison.changes;
|
||||||
const snapshot_warnings = comparison.snapshot_warnings;
|
const snapshot_warnings = comparison.snapshot_warnings;
|
||||||
if (!changes) {
|
if (!changes) {
|
||||||
@@ -818,6 +848,8 @@ exports.ConfigurationOptionsSchema = z
|
|||||||
config_file: z.string().optional(),
|
config_file: z.string().optional(),
|
||||||
base_ref: z.string().optional(),
|
base_ref: z.string().optional(),
|
||||||
head_ref: z.string().optional(),
|
head_ref: z.string().optional(),
|
||||||
|
retry_on_snapshot_warnings: z.boolean().default(false),
|
||||||
|
retry_on_snapshot_warnings_timeout: z.number().default(120),
|
||||||
comment_summary_in_pr: z
|
comment_summary_in_pr: z
|
||||||
.union([
|
.union([
|
||||||
z.preprocess(val => (val === 'true' ? true : val === 'false' ? false : val), z.boolean()),
|
z.preprocess(val => (val === 'true' ? true : val === 'false' ? false : val), z.boolean()),
|
||||||
@@ -1061,17 +1093,9 @@ function addScannedDependencies(changes) {
|
|||||||
}
|
}
|
||||||
exports.addScannedDependencies = addScannedDependencies;
|
exports.addScannedDependencies = addScannedDependencies;
|
||||||
function addSnapshotWarnings(warnings) {
|
function addSnapshotWarnings(warnings) {
|
||||||
// For now, we want to ignore warnings that just complain
|
|
||||||
// about missing snapshots on the head SHA. This is a product
|
|
||||||
// decision to avoid presenting warnings to users who simply
|
|
||||||
// don't use snapshots.
|
|
||||||
const ignore_regex = new RegExp(/No.*snapshot.*found.*head.*/, 'i');
|
|
||||||
if (ignore_regex.test(warnings)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
core.summary.addHeading('Snapshot Warnings', 2);
|
core.summary.addHeading('Snapshot Warnings', 2);
|
||||||
core.summary.addQuote(`${icons.warning}: ${warnings}`);
|
core.summary.addQuote(`${icons.warning}: ${warnings}`);
|
||||||
core.summary.addRaw('Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice.');
|
core.summary.addRaw('Re-running this action after a short time may resolve the issue. See <a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#best-practices-for-using-the-dependency-review-api-and-the-dependency-submission-api-together">the documentation</a> for more information and troubleshooting advice.');
|
||||||
}
|
}
|
||||||
exports.addSnapshotWarnings = addSnapshotWarnings;
|
exports.addSnapshotWarnings = addSnapshotWarnings;
|
||||||
function countLicenseIssues(invalidLicenseChanges) {
|
function countLicenseIssues(invalidLicenseChanges) {
|
||||||
@@ -47968,6 +47992,8 @@ function readInlineConfig() {
|
|||||||
const base_ref = getOptionalInput('base-ref');
|
const base_ref = getOptionalInput('base-ref');
|
||||||
const head_ref = getOptionalInput('head-ref');
|
const head_ref = getOptionalInput('head-ref');
|
||||||
const comment_summary_in_pr = getOptionalInput('comment-summary-in-pr');
|
const comment_summary_in_pr = getOptionalInput('comment-summary-in-pr');
|
||||||
|
const retry_on_snapshot_warnings = getOptionalBoolean('retry-on-snapshot-warnings');
|
||||||
|
const retry_on_snapshot_warnings_timeout = getOptionalNumber('retry-on-snapshot-warnings-timeout');
|
||||||
validatePURL(allow_dependencies_licenses);
|
validatePURL(allow_dependencies_licenses);
|
||||||
validateLicenses('allow-licenses', allow_licenses);
|
validateLicenses('allow-licenses', allow_licenses);
|
||||||
validateLicenses('deny-licenses', deny_licenses);
|
validateLicenses('deny-licenses', deny_licenses);
|
||||||
@@ -47984,10 +48010,17 @@ function readInlineConfig() {
|
|||||||
vulnerability_check,
|
vulnerability_check,
|
||||||
base_ref,
|
base_ref,
|
||||||
head_ref,
|
head_ref,
|
||||||
comment_summary_in_pr
|
comment_summary_in_pr,
|
||||||
|
retry_on_snapshot_warnings,
|
||||||
|
retry_on_snapshot_warnings_timeout
|
||||||
};
|
};
|
||||||
return Object.fromEntries(Object.entries(keys).filter(([_, value]) => value !== undefined));
|
return Object.fromEntries(Object.entries(keys).filter(([_, value]) => value !== undefined));
|
||||||
}
|
}
|
||||||
|
function getOptionalNumber(name) {
|
||||||
|
const value = core.getInput(name);
|
||||||
|
const parsed = z.string().regex(/^\d+$/).transform(Number).safeParse(value);
|
||||||
|
return parsed.success ? parsed.data : undefined;
|
||||||
|
}
|
||||||
function getOptionalBoolean(name) {
|
function getOptionalBoolean(name) {
|
||||||
const value = core.getInput(name);
|
const value = core.getInput(name);
|
||||||
return value.length > 0 ? core.getBooleanInput(name) : undefined;
|
return value.length > 0 ? core.getBooleanInput(name) : undefined;
|
||||||
@@ -48271,6 +48304,8 @@ exports.ConfigurationOptionsSchema = z
|
|||||||
config_file: z.string().optional(),
|
config_file: z.string().optional(),
|
||||||
base_ref: z.string().optional(),
|
base_ref: z.string().optional(),
|
||||||
head_ref: z.string().optional(),
|
head_ref: z.string().optional(),
|
||||||
|
retry_on_snapshot_warnings: z.boolean().default(false),
|
||||||
|
retry_on_snapshot_warnings_timeout: z.number().default(120),
|
||||||
comment_summary_in_pr: z
|
comment_summary_in_pr: z
|
||||||
.union([
|
.union([
|
||||||
z.preprocess(val => (val === 'true' ? true : val === 'false' ? false : val), z.boolean()),
|
z.preprocess(val => (val === 'true' ? true : val === 'false' ? false : val), z.boolean()),
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -258,3 +258,39 @@ jobs:
|
|||||||
deny-packages: 'pkg:maven/org.apache.logging.log4j/log4j-api,pkg:maven/org.apache.logging.log4j/log4j-core'
|
deny-packages: 'pkg:maven/org.apache.logging.log4j/log4j-api,pkg:maven/org.apache.logging.log4j/log4j-core'
|
||||||
deny-groups: 'pkg:maven/com.bazaarvoice.jolt'
|
deny-groups: 'pkg:maven/com.bazaarvoice.jolt'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Waiting for dependency submission jobs to complete
|
||||||
|
|
||||||
|
When possible, this action will [include dependencies submitted through the dependency submission API][DSAPI]. In this case,
|
||||||
|
it's important for the action not to complete until all of the relevant dependencies have been submitted for both the base
|
||||||
|
and head commits.
|
||||||
|
|
||||||
|
When this action runs before one or more of the dependency submission actions, there will be an unequal number of dependency
|
||||||
|
snapshots between the base and head commits. For example, there may be one snapshot available for the tip of `main` and none
|
||||||
|
for the PR branch. In that case, the API response will contain a "snapshot warning" explaining the discrepancy.
|
||||||
|
|
||||||
|
In this example, when the action encounters one of these warnings it will retry every 10 seconds after that for 60 seconds
|
||||||
|
or until there is no warning in the response.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: 'Dependency Review'
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dependency-review:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 'Checkout Repository'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: 'Dependency Review'
|
||||||
|
uses: actions/dependency-review-action@v3
|
||||||
|
with:
|
||||||
|
retry-on-snapshot-warnings: true
|
||||||
|
retry-on-snapshot-warnings-timeout: 60
|
||||||
|
```
|
||||||
|
|
||||||
|
[DSAPI]: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#best-practices-for-using-the-dependency-review-api-and-the-dependency-submission-api-together
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ const defaultConfig: ConfigurationOptions = {
|
|||||||
'pkg:pip/certifi',
|
'pkg:pip/certifi',
|
||||||
'pkg:pip/[email protected]'
|
'pkg:pip/[email protected]'
|
||||||
],
|
],
|
||||||
comment_summary_in_pr: 'never'
|
comment_summary_in_pr: true,
|
||||||
|
retry_on_snapshot_warnings: false,
|
||||||
|
retry_on_snapshot_warnings_timeout: 120
|
||||||
}
|
}
|
||||||
|
|
||||||
const tmpDir = path.resolve(__dirname, '../tmp')
|
const tmpDir = path.resolve(__dirname, '../tmp')
|
||||||
|
|||||||
+15
-1
@@ -41,6 +41,12 @@ function readInlineConfig(): ConfigurationOptionsPartial {
|
|||||||
const base_ref = getOptionalInput('base-ref')
|
const base_ref = getOptionalInput('base-ref')
|
||||||
const head_ref = getOptionalInput('head-ref')
|
const head_ref = getOptionalInput('head-ref')
|
||||||
const comment_summary_in_pr = getOptionalInput('comment-summary-in-pr')
|
const comment_summary_in_pr = getOptionalInput('comment-summary-in-pr')
|
||||||
|
const retry_on_snapshot_warnings = getOptionalBoolean(
|
||||||
|
'retry-on-snapshot-warnings'
|
||||||
|
)
|
||||||
|
const retry_on_snapshot_warnings_timeout = getOptionalNumber(
|
||||||
|
'retry-on-snapshot-warnings-timeout'
|
||||||
|
)
|
||||||
|
|
||||||
validatePURL(allow_dependencies_licenses)
|
validatePURL(allow_dependencies_licenses)
|
||||||
validateLicenses('allow-licenses', allow_licenses)
|
validateLicenses('allow-licenses', allow_licenses)
|
||||||
@@ -59,7 +65,9 @@ function readInlineConfig(): ConfigurationOptionsPartial {
|
|||||||
vulnerability_check,
|
vulnerability_check,
|
||||||
base_ref,
|
base_ref,
|
||||||
head_ref,
|
head_ref,
|
||||||
comment_summary_in_pr
|
comment_summary_in_pr,
|
||||||
|
retry_on_snapshot_warnings,
|
||||||
|
retry_on_snapshot_warnings_timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
@@ -67,6 +75,12 @@ function readInlineConfig(): ConfigurationOptionsPartial {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getOptionalNumber(name: string): number | undefined {
|
||||||
|
const value = core.getInput(name)
|
||||||
|
const parsed = z.string().regex(/^\d+$/).transform(Number).safeParse(value)
|
||||||
|
return parsed.success ? parsed.data : undefined
|
||||||
|
}
|
||||||
|
|
||||||
function getOptionalBoolean(name: string): boolean | undefined {
|
function getOptionalBoolean(name: string): boolean | undefined {
|
||||||
const value = core.getInput(name)
|
const value = core.getInput(name)
|
||||||
return value.length > 0 ? core.getBooleanInput(name) : undefined
|
return value.length > 0 ? core.getBooleanInput(name) : undefined
|
||||||
|
|||||||
+48
-6
@@ -18,18 +18,60 @@ import {groupDependenciesByManifest} from './utils'
|
|||||||
import {commentPr} from './comment-pr'
|
import {commentPr} from './comment-pr'
|
||||||
import {getDeniedChanges} from './deny'
|
import {getDeniedChanges} from './deny'
|
||||||
|
|
||||||
|
async function delay(ms: number): Promise<void> {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getComparison(
|
||||||
|
baseRef: string,
|
||||||
|
headRef: string,
|
||||||
|
retryOpts?: {
|
||||||
|
retryUntil: number
|
||||||
|
retryDelay: number
|
||||||
|
}
|
||||||
|
): ReturnType<typeof dependencyGraph.compare> {
|
||||||
|
const comparison = await dependencyGraph.compare({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
baseRef,
|
||||||
|
headRef
|
||||||
|
})
|
||||||
|
|
||||||
|
if (comparison.snapshot_warnings.trim() !== '') {
|
||||||
|
core.info(comparison.snapshot_warnings)
|
||||||
|
if (retryOpts !== undefined) {
|
||||||
|
if (retryOpts.retryUntil < Date.now()) {
|
||||||
|
core.info(`Retry timeout exceeded. Proceeding...`)
|
||||||
|
return comparison
|
||||||
|
} else {
|
||||||
|
core.info(`Retrying in ${retryOpts.retryDelay} seconds...`)
|
||||||
|
await delay(retryOpts.retryDelay * 1000)
|
||||||
|
return getComparison(baseRef, headRef, retryOpts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return comparison
|
||||||
|
}
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const config = await readConfig()
|
const config = await readConfig()
|
||||||
|
|
||||||
const refs = getRefs(config, github.context)
|
const refs = getRefs(config, github.context)
|
||||||
|
|
||||||
const comparison = await dependencyGraph.compare({
|
const comparison = await getComparison(
|
||||||
owner: github.context.repo.owner,
|
refs.base,
|
||||||
repo: github.context.repo.repo,
|
refs.head,
|
||||||
baseRef: refs.base,
|
config.retry_on_snapshot_warnings
|
||||||
headRef: refs.head
|
? {
|
||||||
})
|
retryUntil:
|
||||||
|
Date.now() + config.retry_on_snapshot_warnings_timeout * 1000,
|
||||||
|
retryDelay: 10
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
)
|
||||||
|
|
||||||
const changes = comparison.changes
|
const changes = comparison.changes
|
||||||
const snapshot_warnings = comparison.snapshot_warnings
|
const snapshot_warnings = comparison.snapshot_warnings
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ export const ConfigurationOptionsSchema = z
|
|||||||
config_file: z.string().optional(),
|
config_file: z.string().optional(),
|
||||||
base_ref: z.string().optional(),
|
base_ref: z.string().optional(),
|
||||||
head_ref: z.string().optional(),
|
head_ref: z.string().optional(),
|
||||||
|
retry_on_snapshot_warnings: z.boolean().default(false),
|
||||||
|
retry_on_snapshot_warnings_timeout: z.number().default(120),
|
||||||
comment_summary_in_pr: z
|
comment_summary_in_pr: z
|
||||||
.union([
|
.union([
|
||||||
z.preprocess(
|
z.preprocess(
|
||||||
|
|||||||
+1
-10
@@ -232,19 +232,10 @@ export function addScannedDependencies(changes: Changes): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function addSnapshotWarnings(warnings: string): void {
|
export function addSnapshotWarnings(warnings: string): void {
|
||||||
// For now, we want to ignore warnings that just complain
|
|
||||||
// about missing snapshots on the head SHA. This is a product
|
|
||||||
// decision to avoid presenting warnings to users who simply
|
|
||||||
// don't use snapshots.
|
|
||||||
const ignore_regex = new RegExp(/No.*snapshot.*found.*head.*/, 'i')
|
|
||||||
if (ignore_regex.test(warnings)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
core.summary.addHeading('Snapshot Warnings', 2)
|
core.summary.addHeading('Snapshot Warnings', 2)
|
||||||
core.summary.addQuote(`${icons.warning}: ${warnings}`)
|
core.summary.addQuote(`${icons.warning}: ${warnings}`)
|
||||||
core.summary.addRaw(
|
core.summary.addRaw(
|
||||||
'Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice.'
|
'Re-running this action after a short time may resolve the issue. See <a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#best-practices-for-using-the-dependency-review-api-and-the-dependency-submission-api-together">the documentation</a> for more information and troubleshooting advice.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user