Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Install extends ArboristWorkspaceCmd {
'audit',
'before',
'min-release-age',
'min-release-age-exclude',
'bin-links',
'fund',
'dry-run',
Expand Down
1 change: 1 addition & 0 deletions lib/commands/outdated.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Outdated extends ArboristWorkspaceCmd {
'global',
'workspace',
'before',
'min-release-age-exclude',
]

#tree
Expand Down
2 changes: 2 additions & 0 deletions lib/commands/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class Query extends BaseCommand {
'include-workspace-root',
'package-lock-only',
'expect-results',
'before',
'min-release-age-exclude',
]

constructor (...args) {
Expand Down
13 changes: 12 additions & 1 deletion node_modules/npm-pick-manifest/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const npa = require('npm-package-arg')
const semver = require('semver')
const { minimatch } = require('minimatch')
const { checkEngine } = require('npm-install-checks')
const normalizeBin = require('npm-normalize-package-bin')

Expand All @@ -21,6 +22,13 @@ const avoidSemverOpt = { includePrerelease: true, loose: true }
const shouldAvoid = (ver, avoid) =>
avoid && semver.satisfies(ver, avoid, avoidSemverOpt)

const shouldBypassBefore = (name, exclude) => {
const patterns = Array.isArray(exclude) ? exclude : [exclude]
return patterns
.filter(pattern => typeof pattern === 'string' && pattern)
.some(pattern => minimatch(name, pattern))
}

const decorateAvoid = (result, avoid) =>
result && shouldAvoid(result.version, avoid)
? { ...result, _shouldAvoid: true }
Expand All @@ -35,6 +43,7 @@ const pickManifest = (packument, wanted, opts) => {
includeStaged = false,
avoid = null,
avoidStrict = false,
minReleaseAgeExclude = opts['min-release-age-exclude'],
} = opts

const { name, time: verTimes } = packument
Expand Down Expand Up @@ -84,7 +93,9 @@ const pickManifest = (packument, wanted, opts) => {
const restricted = (packument.policyRestrictions &&
packument.policyRestrictions.versions) || {}

const time = before && verTimes ? +(new Date(before)) : Infinity
const time = before && verTimes && !shouldBypassBefore(name, minReleaseAgeExclude)
? +(new Date(before))
: Infinity
const spec = npa.resolve(name, wanted || defaultTag)
const type = spec.type
const distTags = packument['dist-tags'] || {}
Expand Down
52 changes: 48 additions & 4 deletions tap-snapshots/test/lib/docs.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,6 +1151,19 @@ This config cannot be used with: \`before\`

This value is not exported to the environment for child processes.

#### \`min-release-age-exclude\`

* Default:
* Type: String (can be set multiple times)

Exclude package names from \`min-release-age\` and \`before\` publish-time
filtering.

Values can be exact package names (\`left-pad\`) or glob patterns
(\`@myorg/*\`).

This value is not exported to the environment for child processes.

#### \`name\`

* Default: null
Expand Down Expand Up @@ -2350,6 +2363,7 @@ Array [
"maxsockets",
"message",
"min-release-age",
"min-release-age-exclude",
"node-gyp",
"node-options",
"noproxy",
Expand Down Expand Up @@ -2508,6 +2522,7 @@ Array [
"maxsockets",
"message",
"min-release-age",
"min-release-age-exclude",
"node-gyp",
"noproxy",
"offline",
Expand Down Expand Up @@ -2675,6 +2690,7 @@ Object {
"logColor": false,
"maxSockets": 15,
"message": "%s",
"minReleaseAgeExclude": Array [],
"name": null,
"nodeBin": "{NODE}",
"nodeGyp": "{CWD}/node_modules/node-gyp/bin/node-gyp.js",
Expand Down Expand Up @@ -3948,8 +3964,10 @@ Options:
[--include <prod|dev|optional|peer> [--include <prod|dev|optional|peer> ...]]
[--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only]
[--foreground-scripts] [--ignore-scripts] [--allow-git <all|none|root>]
[--no-audit] [--before <date>|--min-release-age <days>] [--no-bin-links]
[--no-fund] [--dry-run] [--cpu <cpu>] [--os <os>] [--libc <libc>]
[--no-audit] [--before <date>|--min-release-age <days>]
[--min-release-age-exclude <package-name> [--min-release-age-exclude <package-name> ...]]
[--no-bin-links] [--no-fund] [--dry-run] [--cpu <cpu>] [--os <os>]
[--libc <libc>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--install-links]

Expand Down Expand Up @@ -4007,6 +4025,9 @@ Options:
--min-release-age
If set, npm will build the npm tree such that only versions that were

--min-release-age-exclude
Exclude package names from \`min-release-age\` and \`before\` publish-time

--bin-links
Tells npm to create symlinks (or \`.cmd\` shims on Windows) for package

Expand Down Expand Up @@ -4066,6 +4087,7 @@ aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall
#### \`audit\`
#### \`before\`
#### \`min-release-age\`
#### \`min-release-age-exclude\`
#### \`bin-links\`
#### \`fund\`
#### \`dry-run\`
Expand Down Expand Up @@ -4189,8 +4211,10 @@ Options:
[--include <prod|dev|optional|peer> [--include <prod|dev|optional|peer> ...]]
[--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only]
[--foreground-scripts] [--ignore-scripts] [--allow-git <all|none|root>]
[--no-audit] [--before <date>|--min-release-age <days>] [--no-bin-links]
[--no-fund] [--dry-run] [--cpu <cpu>] [--os <os>] [--libc <libc>]
[--no-audit] [--before <date>|--min-release-age <days>]
[--min-release-age-exclude <package-name> [--min-release-age-exclude <package-name> ...]]
[--no-bin-links] [--no-fund] [--dry-run] [--cpu <cpu>] [--os <os>]
[--libc <libc>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--install-links]

Expand Down Expand Up @@ -4248,6 +4272,9 @@ Options:
--min-release-age
If set, npm will build the npm tree such that only versions that were

--min-release-age-exclude
Exclude package names from \`min-release-age\` and \`before\` publish-time

--bin-links
Tells npm to create symlinks (or \`.cmd\` shims on Windows) for package

Expand Down Expand Up @@ -4307,6 +4334,7 @@ alias: it
#### \`audit\`
#### \`before\`
#### \`min-release-age\`
#### \`min-release-age-exclude\`
#### \`bin-links\`
#### \`fund\`
#### \`dry-run\`
Expand Down Expand Up @@ -4739,6 +4767,7 @@ Options:
[-a|--all] [--json] [-l|--long] [-p|--parseable] [-g|--global]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--before <date>|--min-release-age <days>]
[--min-release-age-exclude <package-name> [--min-release-age-exclude <package-name> ...]]

-a|--all
When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
Expand All @@ -4761,6 +4790,9 @@ Options:
--before
If passed to \`npm install\`, will rebuild the npm tree such that only

--min-release-age-exclude
Exclude package names from \`min-release-age\` and \`before\` publish-time


Run "npm help outdated" for more info

Expand All @@ -4776,6 +4808,7 @@ npm outdated [<package-spec> ...]
#### \`workspace\`
#### \`before\`
#### \`min-release-age\`
#### \`min-release-age-exclude\`
`

exports[`test/lib/docs.js TAP usage owner > must match snapshot 1`] = `
Expand Down Expand Up @@ -5132,6 +5165,8 @@ Options:
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--package-lock-only]
[--expect-results|--expect-result-count <count>]
[--before <date>|--min-release-age <days>]
[--min-release-age-exclude <package-name> [--min-release-age-exclude <package-name> ...]]

-g|--global
Operates in "global" mode, so that packages are installed into the
Expand All @@ -5151,6 +5186,12 @@ Options:
--expect-results
Tells npm whether or not to expect results from the command.

--before
If passed to \`npm install\`, will rebuild the npm tree such that only

--min-release-age-exclude
Exclude package names from \`min-release-age\` and \`before\` publish-time


Run "npm help query" for more info

Expand All @@ -5165,6 +5206,9 @@ npm query <selector>
#### \`package-lock-only\`
#### \`expect-results\`
#### \`expect-result-count\`
#### \`before\`
#### \`min-release-age\`
#### \`min-release-age-exclude\`
`

exports[`test/lib/docs.js TAP usage rebuild > must match snapshot 1`] = `
Expand Down
10 changes: 9 additions & 1 deletion workspaces/arborist/lib/query-selector-all.js
Original file line number Diff line number Diff line change
Expand Up @@ -870,9 +870,17 @@ const combinators = {
},
}

const shouldBypassBefore = (name, exclude) => {
Comment thread
caseyjhol marked this conversation as resolved.
Outdated
const patterns = Array.isArray(exclude) ? exclude : [exclude]
return patterns
.filter(pattern => typeof pattern === 'string' && pattern)
.some(pattern => minimatch(name, pattern))
}

// get a list of available versions of a package filtered to respect --before
// NOTE: this runs over each node and should not throw
const getPackageVersions = async (name, opts) => {
const minReleaseAgeExclude = opts.minReleaseAgeExclude ?? opts['min-release-age-exclude']
Comment thread
caseyjhol marked this conversation as resolved.
Outdated
let packument
try {
packument = await pacote.packument(name, {
Expand All @@ -890,7 +898,7 @@ const getPackageVersions = async (name, opts) => {

// if the packument has a time property, and the user passed a before flag, then
// we filter this list down to only those versions that existed before the specified date
if (packument.time && opts.before) {
if (packument.time && opts.before && !shouldBypassBefore(name, minReleaseAgeExclude)) {
candidates = candidates.filter((version) => {
// this version isn't found in the times at all, drop it
if (!packument.time[version]) {
Expand Down
17 changes: 17 additions & 0 deletions workspaces/arborist/test/query-selector-all.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ t.test('query-selector-all', async t => {
: options.before
title += ` before ${friendlyTime}`
}
if (options.minReleaseAgeExclude) {
title += ` exclude ${JSON.stringify(options.minReleaseAgeExclude)}`
}
t.test(title, async t => {
const res = await querySelectorAll(tree, selector, options)
t.same(
Expand Down Expand Up @@ -865,6 +868,20 @@ t.test('query-selector-all', async t => {
[':outdated(out-of-range)', [
'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday
], { before: yesterday }],
[':outdated(out-of-range)', [
'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday
'bar@1.4.0', // excluded from --before filter
], {
before: yesterday,
minReleaseAgeExclude: ['bar'],
}],
[':outdated(out-of-range)', [
'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday
'bar@1.4.0', // excluded from --before filter by glob
], {
before: yesterday,
minReleaseAgeExclude: ['ba*'],
Comment thread
caseyjhol marked this conversation as resolved.
}],
[':outdated(nonsense)', [], { before: yesterday }], // again, no results here ever

// vuln pseudo
Expand Down
19 changes: 19 additions & 0 deletions workspaces/config/lib/definitions/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,25 @@ const definitions = {
}
},
}),
'min-release-age-exclude': new Definition('min-release-age-exclude', {
default: [],
hint: '<package-name>',
type: [String, Array],
envExport: false,
description: `
Exclude package names from \`min-release-age\` and \`before\` publish-time
filtering.

Values can be exact package names (\`left-pad\`) or glob patterns
(\`@myorg/*\`).
`,
flatten: (key, obj, flatOptions) => {
const patterns = Array.isArray(obj[key])
? obj[key]
: obj[key] ? [obj[key]] : []
flatOptions.minReleaseAgeExclude = patterns.filter(Boolean)
},
}),
'node-gyp': new Definition('node-gyp', {
default: (() => {
try {
Expand Down
22 changes: 22 additions & 0 deletions workspaces/config/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1868,3 +1868,25 @@ t.test('before and min-release-age', async t => {
// Simple gut check to make sure we didn't do + instead of -
t.ok(config.flat.before < Date.now(), 'before date is in the past not the future')
})

t.test('min-release-age-exclude flattens to list', async t => {
const path = t.testdir()
const config = new Config({
npmPath: `${path}/npm`,
env: {},
argv: [
process.execPath,
__filename,
'--min-release-age-exclude',
'@myorg/*',
'--min-release-age-exclude',
'left-pad',
],
cwd: path,
definitions,
shorthands,
flatten,
})
await config.load()
t.same(config.flat.minReleaseAgeExclude, ['@myorg/*', 'left-pad'])
})