Skip to content

Commit

Permalink
feat: set ci versions from engines
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Sep 14, 2023
1 parent de319e8 commit 994a278
Show file tree
Hide file tree
Showing 20 changed files with 251 additions and 344 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/audit.yml
Expand Up @@ -27,8 +27,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci-release.yml
Expand Up @@ -82,8 +82,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down Expand Up @@ -167,6 +167,7 @@ jobs:
- 16.x
- 18.0.0
- 18.x
- 20.x
runs-on: ${{ matrix.platform.os }}
defaults:
run:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci-test-workspace.yml
Expand Up @@ -35,8 +35,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down Expand Up @@ -113,6 +113,7 @@ jobs:
- 16.x
- 18.0.0
- 18.x
- 20.x
runs-on: ${{ matrix.platform.os }}
defaults:
run:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -35,8 +35,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down Expand Up @@ -113,6 +113,7 @@ jobs:
- 16.x
- 18.0.0
- 18.x
- 20.x
runs-on: ${{ matrix.platform.os }}
defaults:
run:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/post-dependabot.yml
Expand Up @@ -28,8 +28,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yml
Expand Up @@ -31,8 +31,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Expand Up @@ -44,8 +44,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down Expand Up @@ -201,8 +201,8 @@ jobs:
uses: actions/setup-node@v3
id: node
with:
node-version: 18.x
check-latest: contains('18.x', '.x')
node-version: 20.x
check-latest: contains('20.x', '.x')

# node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows
- name: Update Windows npm
Expand Down
45 changes: 13 additions & 32 deletions lib/config.js
@@ -1,11 +1,10 @@
const { relative, dirname, join, extname, posix, win32 } = require('path')
const { defaults, pick, omit, uniq } = require('lodash')
const semver = require('semver')
const parseCIVersions = require('./util/parse-ci-versions.js')
const { defaults, pick, omit, uniq, isPlainObject } = require('lodash')
const ciVersions = require('./util/ci-versions.js')
const parseDependabot = require('./util/dependabot.js')
const git = require('./util/git.js')
const gitignore = require('./util/gitignore.js')
const { mergeWithArrays } = require('./util/merge.js')
const { mergeWithCustomizers, customizers } = require('./util/merge.js')
const { FILE_KEYS, parseConfig: parseFiles, getAddedFiles, mergeFiles } = require('./util/files.js')

const CONFIG_KEY = 'templateOSS'
Expand All @@ -15,7 +14,14 @@ const { name: NAME, version: LATEST_VERSION } = require('../package.json')
const MERGE_KEYS = [...FILE_KEYS, 'defaultContent', 'content']
const DEFAULT_CONTENT = require.resolve(NAME)

const merge = mergeWithArrays('branches', 'distPaths', 'allowPaths', 'ignorePaths')
const merge = mergeWithCustomizers(
customizers.mergeArrays('branches', 'distPaths', 'allowPaths', 'ignorePaths'),
(value, srcValue, key) => {
if (key === 'ciVersions' && (Array.isArray(srcValue) || isPlainObject(srcValue))) {
return { ...ciVersions.parse(value), ...ciVersions.parse(srcValue) }
}
}
)

const makePosix = (v) => v.split(win32.sep).join(posix.sep)
const deglob = (v) => makePosix(v).replace(/[/*]+$/, '')
Expand Down Expand Up @@ -235,6 +241,8 @@ const getFullConfig = async ({
// lockfiles are only present at the root, so this only should be set for
// all workspaces based on the root
lockfile: rootPkgConfig.lockfile,
// ci versions / engines
ciVersions: ciVersions.get(pkg.pkgJson.engines?.node, pkgConfig),
// gitignore
ignorePaths: [
...gitignore.sort([
Expand All @@ -259,33 +267,6 @@ const getFullConfig = async ({
__PARTIAL_DIRS__: fileDirs,
}

if (pkgConfig.ciVersions) {
let versions = pkgConfig.ciVersions
if (versions === 'latest' || (Array.isArray(versions) && versions.includes('latest'))) {
const { ciVersions } = [isWorkspace ? rootPkgConfig : {}, defaultConfig]
.find(c => Array.isArray(c.ciVersions))
const defaultLatest = ciVersions[ciVersions.length - 1]
versions = [].concat(versions).map(v => v === 'latest' ? defaultLatest : v)
}

const { targets, engines } = parseCIVersions(versions)

// get just a list of the target versions (not ranges)
// these are used for the node version when doing engines checks
// since we want to test in the lowest version of each major
let targetVersions = targets.filter(t => semver.valid(t))
// if the versions are all ranges then convert them to the lower bound of each range
if (!targetVersions.length) {
targetVersions = targets.filter(t => semver.validRange(t)).map(t => {
return new semver.Range(t).set[0][0].semver.version
})
}

derived.ciVersions = targets
derived.baseCiVersions = targetVersions
derived.engines = pkgConfig.engines || engines
}

if (!pkgConfig.eslint) {
derived.ignorePaths = derived.ignorePaths.filter(p => !p.includes('eslint'))
if (Array.isArray(pkgConfig.requiredPackages?.devDependencies)) {
Expand Down
3 changes: 2 additions & 1 deletion lib/content/index.js
Expand Up @@ -158,7 +158,8 @@ module.exports = {
'/CHANGELOG*',
],
ignorePaths: [],
ciVersions: ['14.17.0', '14.x', '16.13.0', '16.x', '18.0.0', '18.x'],
ciVersions: {},
latestCiVersion: 20,
lockfile: false,
codeowner: '@npm/cli-team',
eslint: true,
Expand Down
5 changes: 0 additions & 5 deletions lib/content/pkg.json
Expand Up @@ -21,11 +21,6 @@
"postpublish": {{{ del }}}
},
"repository": {{#if repository}}{{{ json repository }}}{{else}}{{{ del }}}{{/if}},
"engines": {
{{#if engines}}
"node": {{{ json engines }}}
{{/if}}
},
{{{ json __CONFIG_KEY__ }}}: {
"version": {{#if isDogFood}}{{{ del }}}{{else}}{{{ json __VERSION__ }}}{{/if}}
},
Expand Down
80 changes: 80 additions & 0 deletions lib/util/ci-versions.js
@@ -0,0 +1,80 @@
const { uniq, range, isPlainObject } = require('lodash')
const semver = require('semver')

const parseCiVersions = (ciVersions) => {
if (Array.isArray(ciVersions)) {
return Object.fromEntries(ciVersions.map((v) => [v, true]))
}
if (isPlainObject(ciVersions)) {
return ciVersions
}
}

const getLowerBounds = (sRange) => {
return new semver.Range(sRange).set.map(c => c[0])
}

const getCiVersions = (nodeEngines, pkgConfig) => {
let allCiVersions = {}

// get ci versions
const { latestCiVersion, ciVersions } = pkgConfig

if (latestCiVersion) {
allCiVersions[`${latestCiVersion}.x`] = true
}

// determine the ci versions from the node engines set
if (nodeEngines) {
const lowerBounds = getLowerBounds(nodeEngines)
.map(v => v.semver)
.filter(v => v.version)

for (const version of lowerBounds) {
allCiVersions[version.version] = true
allCiVersions[`${version.major}.x`] = true
}

const lowestCiVersion = semver.sort(lowerBounds)[0]?.major
if (lowestCiVersion && latestCiVersion) {
for (const major of range(lowestCiVersion, latestCiVersion, 2)) {
allCiVersions[`${major}.x`] = true
}
}
}

if (ciVersions === 'latest' && latestCiVersion) {
// the plain string 'latest' means latest only and everything else is removed
allCiVersions = { [`${latestCiVersion}.x`]: true }
} else {
// this allows ciVersions to turn off default versions by setting them to a falsy value
Object.assign(allCiVersions, parseCiVersions(ciVersions))
}

if (allCiVersions.latest && latestCiVersion) {
delete allCiVersions.latest
allCiVersions[`${latestCiVersion}.x`] = true
}

const filteredCiVersions = Object.entries(allCiVersions)
.filter(([, v]) => v)
.map(([k]) => k)

return uniq(filteredCiVersions).sort((a, b) => {
const aComp = getLowerBounds(a)[0]
const bComp = getLowerBounds(b)[0]

if (aComp.semver.major > bComp.semver.major) {
return 1
} else if (aComp.semver.major < bComp.semver.major) {
return -1
}

return aComp.operator ? 1 : -1
})
}

module.exports = {
parse: parseCiVersions,
get: getCiVersions,
}
1 change: 0 additions & 1 deletion lib/util/merge.js
Expand Up @@ -65,7 +65,6 @@ const customizers = {
module.exports = {
// default merge is to overwrite arrays
merge: mergeWithCustomizers(customizers.overwriteArrays),
mergeWithArrays: (...keys) => mergeWithCustomizers(customizers.mergeArrays(...keys)),
mergeWithCustomizers,
mergeWith,
customizers,
Expand Down
78 changes: 0 additions & 78 deletions lib/util/parse-ci-versions.js

This file was deleted.

0 comments on commit 994a278

Please sign in to comment.