-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: tav versions update script (#3680)
- Loading branch information
1 parent
6c558d9
commit b31f56a
Showing
3 changed files
with
291 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,18 +94,27 @@ redis: | |
# subset (the first, plus then the latest in each major.minor). | ||
ioredis-v2-v4: | ||
name: ioredis | ||
versions: '2.0.0 || 2.0.1 || 2.1.0 || 2.2.0 || 2.3.1 || 2.4.3 || 2.5.0 || 3.0.0 || 3.1.4 || 3.2.2 || >3.2.2 <4' | ||
versions: '2.0.0 || 2.0.1 || 2.1.0 || 2.2.0 || 2.3.1 || 2.4.3 || 2.5.0 || 3.0.0 || 3.1.4 || ^3.2.2' | ||
commands: node test/instrumentation/modules/ioredis.test.js | ||
update-versions: | ||
mode: latest-minors | ||
include: '>=2.0.0 <4' | ||
ioredis-v4-v5: | ||
name: ioredis | ||
versions: '4.0.0 || 4.0.2 || 4.1.0 || 4.2.3 || 4.3.1 || 4.4.0 || 4.5.1 || 4.6.3 || 4.7.0 || 4.8.0 || 4.9.0 || 4.9.5 || 4.10.4 || 4.11.2 || 4.12.2 || 4.13.1 || 4.14.4 || 4.15.1 || 4.16.3 || 4.17.3 || 4.18.0 || 4.19.4 || 4.20.0 || 4.21.0 || 4.22.0 || 4.23.1 || 4.24.6 || 4.25.0 || 4.26.0 || 4.27.11 || ^4.28.0' | ||
versions: '4.0.0 || 4.0.2 || 4.1.0 || 4.2.3 || 4.3.1 || 4.4.0 || 4.5.1 || 4.6.3 || 4.7.0 || 4.8.0 || 4.9.5 || 4.10.4 || 4.11.2 || 4.12.2 || 4.13.1 || 4.14.4 || 4.15.1 || 4.16.3 || 4.17.3 || 4.18.0 || 4.19.4 || 4.20.0 || 4.21.0 || 4.22.0 || 4.23.1 || 4.24.6 || 4.25.0 || 4.26.0 || 4.27.11 || ^4.28.5' | ||
node: '>=6' | ||
commands: node test/instrumentation/modules/ioredis.test.js | ||
update-versions: | ||
mode: latest-minors | ||
include: '>=4.0.0 <5' | ||
ioredis: | ||
name: ioredis | ||
versions: '^5.0.0' | ||
versions: '5.0.0 || 5.0.6 || 5.1.0 || 5.2.6 || ^5.3.2' | ||
node: '>=12.22.0' | ||
commands: node test/instrumentation/modules/ioredis.test.js | ||
update-versions: | ||
mode: latest-minors | ||
include: '>=5.0.0 <6' | ||
|
||
pg-old-node: | ||
name: pg | ||
|
@@ -138,8 +147,11 @@ pg-new-node: | |
# Latest mongodb-core release (v3.2.7) was released in 2019. We test a subset | ||
# of the full supported range. | ||
mongodb-core: | ||
versions: '1.2.19 || 1.2.32 || 1.3.21 || 2.0.14 || 2.1.20 || 3.0.11 || 3.1.11 || 3.2.7' # latest minors subset of '>=1.2.19 <4' | ||
versions: '1.2.19 || 1.2.32 || 1.3.21 || 2.0.14 || 2.1.20 || 3.0.11 || 3.1.11 || ^3.2.7' | ||
commands: node test/instrumentation/modules/mongodb-core.test.js | ||
update-versions: | ||
mode: latest-minors | ||
include: '>=1.2.19 <4' # latest minors subset of '>=1.2.19 <4' | ||
|
||
mongodb-3: | ||
name: mongodb | ||
|
@@ -476,25 +488,32 @@ fastify-v2: | |
fastify-v3: | ||
name: fastify | ||
# Update versions periodically with "./dev-utils/tav-versions-fastify.sh". | ||
versions: '3.0.0 || 3.6.0 || 3.14.2 || 3.20.1 || 3.24.0 || 3.29.0 || 3.29.5 || >3.29.5 <4' # subset of '>=3 <4' | ||
versions: '3.0.0 || 3.6.0 || 3.14.2 || 3.20.1 || 3.24.0 || 3.29.0 || ^3.29.5' | ||
peerDependencies: '@fastify/formbody@^6.0.1' | ||
node: '>=10' | ||
commands: | ||
- node test/instrumentation/modules/fastify/fastify.test.js | ||
- node test/instrumentation/modules/fastify/async-await.test.js | ||
- node test/instrumentation/modules/fastify/set-framework.test.js | ||
- node test/sanitize-field-names/fastify.test.js | ||
update-versions: | ||
mode: max-5 | ||
include: '>=3 <4' | ||
fastify: | ||
name: fastify | ||
# Update versions periodically with "./dev-utils/tav-versions-fastify.sh". | ||
versions: '4.0.0 || 4.2.1 || 4.5.2 || 4.8.1 || 4.10.1 || 4.14.0 || 4.17.0 || >4.17.0' # subset of '>=4 <4.0.1 || >4.0.1 <4.16.0 || >4.16.2' | ||
versions: '4.0.0 || 4.5.0 || 4.9.0 || 4.13.0 || 4.19.1 || 4.23.1 || ^4.24.3' | ||
peerDependencies: '@fastify/formbody@^7' | ||
node: '>=14.6.0' | ||
commands: | ||
- node test/instrumentation/modules/fastify/fastify.test.js | ||
- node test/instrumentation/modules/fastify/async-await.test.js | ||
- node test/instrumentation/modules/fastify/set-framework.test.js | ||
- node test/sanitize-field-names/fastify.test.js | ||
update-versions: | ||
mode: max-5 | ||
include: '>=4 <5' | ||
exclude: '4.0.1 || >=4.16.0 <=4.16.2' | ||
|
||
finalhandler: | ||
versions: '*' | ||
|
@@ -531,45 +550,48 @@ aws-sdk: | |
# However, @awk-sdk/client-* releases *very* frequently (almost every day) and there | ||
# is no need to test *all* those releases. Instead we statically list a subset | ||
# of versions to test. | ||
# Maintenance note: This should be updated periodically using: | ||
# node ./dev-utils/update-tav-versions.js | ||
|
||
'@aws-sdk/client-s3': | ||
# Maintenance note: This should be updated periodically using: | ||
# node ./dev-utils/tav-versions.js @aws-sdk/client-s3 ">=3.15.0 <4" | ||
# | ||
# Test v3.15.0, every N=47 of 241 releases, and current latest. | ||
versions: '3.15.0 || 3.56.0 || 3.159.0 || 3.236.0 || 3.319.0 || 3.400.0 || 3.412.0 || >3.412.0 <4' | ||
versions: '3.15.0 || 3.72.0 || 3.170.0 || 3.264.0 || 3.347.0 || 3.435.0 || ^3.436.0' | ||
commands: | ||
- node test/instrumentation/modules/@aws-sdk/client-s3.test.js | ||
node: '>=14' | ||
# Test v3.15.0, current latest and 5 versions in between. | ||
update-versions: | ||
mode: max-5 | ||
include: '>=3.15.0 <4' | ||
|
||
'@aws-sdk/client-dynamodb': | ||
# Maintenance note: This should be updated periodically using: | ||
# node ./dev-utils/tav-versions.js @aws-sdk/client-dynamodb ">=3.15.0 <4" | ||
# | ||
# Test v3.15.0, every N=44 of 225 releases, and current latest. | ||
versions: '3.15.0 || 3.55.0 || 3.165.0 || 3.234.0 || 3.312.0 || 3.398.0 || 3.410.0 || >3.410.0 <4' | ||
versions: '3.15.0 || 3.72.0 || 3.180.0 || 3.261.0 || 3.344.0 || 3.435.0 || ^3.436.0' | ||
commands: | ||
- node test/instrumentation/modules/@aws-sdk/client-s3.test.js | ||
node: '>=14' | ||
# Test v3.15.0, current latest and 5 versions in between. | ||
update-versions: | ||
mode: max-5 | ||
include: '>=3.15.0 <4' | ||
|
||
'@aws-sdk/client-sns': | ||
# Maintenance note: This should be updated periodically using: | ||
# node ./dev-utils/tav-versions.js @aws-sdk/client-sns ">=3.15.0 <4" | ||
# | ||
# Test v3.15.0, every N=40 of 205 releases, and current latest. | ||
versions: '3.15.0 || 3.53.0 || 3.154.0 || 3.218.0 || 3.294.0 || 3.360.0 || 3.370.0 || >3.370.0 <4' | ||
versions: '3.15.0 || 3.67.0 || 3.178.0 || 3.259.0 || 3.337.0 || 3.431.0 || ^3.436.0' | ||
commands: | ||
- node test/instrumentation/modules/@aws-sdk/client-sns.test.js | ||
node: '>=14' | ||
# Test v3.15.0, current latest and 5 versions in between. | ||
update-versions: | ||
mode: max-5 | ||
include: '>=3.15.0 <4' | ||
|
||
'@aws-sdk/client-sqs': | ||
# Maintenance note: This should be updated periodically using: | ||
# node ./dev-utils/tav-versions.js @aws-sdk/client-sqs ">=3.15.0 <4" | ||
# | ||
# Test v3.15.0, every N=43 of 220 releases, and current latest. | ||
versions: '3.15.0 || 3.55.0 || 3.165.0 || 3.238.0 || 3.319.0 || 3.409.0 || 3.418.0 || >3.418.0 <4' | ||
versions: '3.15.0 || 3.58.0 || 3.171.0 || 3.257.0 || 3.335.0 || 3.429.0 || ^3.436.0' | ||
commands: | ||
- node test/instrumentation/modules/@aws-sdk/client-sqs.test.js | ||
node: '>=14' | ||
# Test v3.15.0, current latest and 5 versions in between. | ||
update-versions: | ||
mode: max-5 | ||
include: '>=3.15.0 <4' | ||
|
||
# - [email protected] added its diagnostics_channel support. | ||
# - In [email protected] the `request.origin` property was added, which we need | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
#!/usr/bin/env node | ||
|
||
/* | ||
* Copyright Elasticsearch B.V. and other contributors where applicable. | ||
* Licensed under the BSD 2-Clause License; you may not use this file except in | ||
* compliance with the BSD 2-Clause License. | ||
*/ | ||
|
||
/** @typedef {import('semver').SemVer} SemVer */ | ||
/** | ||
* @typedef {Object} TavConfig | ||
* @property {String} [name] | ||
* @property {String} versions | ||
* @property {String} node | ||
* @property {String[]} commands | ||
* @property {Object} update-versions | ||
* @property {String} update-versions.include | ||
* @property {String} [update-versions.exclude] | ||
*/ | ||
|
||
'use strict'; | ||
|
||
// This script scans the `.tav.yml` file placed at the root folder and for each | ||
// entry checks if the `update-versions` property is defined. In that case | ||
// the script will update the versions property according to the `update-versions` | ||
// configuration: | ||
// - include(required): Versions satisfiying this range will be in the update | ||
// - exclude(optional): Versions satisfiying this range won't be in the update | ||
// - mode(required): how we want to pick the versions within the range. These are | ||
// - latest-minors: picks 1st version of the range and all the latest minor versions | ||
// - latest-majors: picks 1st version of the range and all the latest major versions | ||
// - max-(n): picks 1st version, the last version and (n) versions in between them | ||
// | ||
// Usage: | ||
// node dev-utils/update-tav-versions.js | ||
|
||
const { execSync } = require('child_process'); | ||
const { readFileSync, writeFileSync } = require('fs'); | ||
const path = require('path'); | ||
|
||
const semver = require('semver'); | ||
const yaml = require('js-yaml'); | ||
|
||
const TOP = path.resolve(path.join(__dirname, '..')); | ||
const TAV_PATH = path.join(TOP, '.tav.yml'); | ||
const UPDATE_PROP = 'update-versions'; | ||
const INCLUDE_REGEXP = /^>=\d+(\.\d+){0,2} <\d+(\.\d+){0,2}$/; | ||
|
||
async function main() { | ||
/** @type {Map<string, string[]>} */ | ||
const pkgVersMap = new Map(); // versions per package name | ||
/** @type {Map<string, string[]>} */ | ||
const tavVersMap = new Map(); // versions per TAV configuration | ||
|
||
const tavContent = readFileSync(TAV_PATH, { encoding: 'utf-8' }); | ||
/** @type {Record<string, TavConfig>} */ | ||
const tavConfig = yaml.load(tavContent); | ||
const tavEntries = Object.entries(tavConfig); | ||
|
||
for (const entry of tavEntries) { | ||
const [name, cfg] = entry; | ||
|
||
if (!cfg[UPDATE_PROP]) continue; | ||
|
||
const { mode, include, exclude } = cfg[UPDATE_PROP]; | ||
|
||
// Check format before doing fetch | ||
if (mode.startsWith('max-')) { | ||
const num = Number(mode.split('-')[1]); | ||
if (isNaN(num)) { | ||
throw new Error( | ||
`Error: TAV config ${name} invalid "max-n" mode, "n" must be a number (current: ${mode})`, | ||
); | ||
} | ||
} | ||
if (!INCLUDE_REGEXP.test(include)) { | ||
throw new Error( | ||
`Error: TAV config ${name} include property must be in the form ">=SemVer <SemVer" (current: ${include})`, | ||
); | ||
} | ||
|
||
const pkgName = cfg.name || name; | ||
let pkgVersions = pkgVersMap.get(pkgName); | ||
|
||
if (!pkgVersions) { | ||
console.log(`Fetching versions for ${pkgName}`); | ||
pkgVersions = JSON.parse( | ||
execSync(`npm view ${pkgName} versions -j`, { encoding: 'utf-8' }), | ||
); | ||
pkgVersMap.set(pkgName, pkgVersions); | ||
} | ||
|
||
let versions; | ||
const filteredVers = pkgVersions | ||
.filter((v) => semver.satisfies(v, include)) | ||
.filter((v) => !exclude || !semver.satisfies(v, exclude)) | ||
.map(semver.parse); | ||
|
||
console.log( | ||
`Calculating ${mode} for ${name} including ${include} and excluding ${ | ||
exclude || 'none' | ||
}`, | ||
); | ||
if (mode === 'latest-minors') { | ||
versions = getLatestMinors(filteredVers); | ||
} else if (mode === 'latest-majors') { | ||
versions = getLatestMajors(filteredVers); | ||
} else if (mode.startsWith('max-')) { | ||
const num = Number(mode.split('-')[1]); | ||
versions = getMax(filteredVers, Number(num)); | ||
} else { | ||
throw new Error( | ||
`Error: Version selection mode for TAV config ${name} unknown (${mode})`, | ||
); | ||
} | ||
|
||
if (versions.length === 0) { | ||
console.log( | ||
`Info: all versions excluded for TAV config ${name}, please review include/exclude. Skipping`, | ||
); | ||
continue; | ||
} | ||
|
||
// Assuming `include` is always in the form ">={Lower_limit} <{Higher_Limit}" | ||
// - append lower version if not present | ||
// - append a caret to the latest version in the list to test any higher version | ||
const firstVers = versions[0]; | ||
const lastVers = versions[versions.length - 1]; | ||
const [low] = include.split(' ').map(semver.coerce); | ||
|
||
if (semver.neq(firstVers, low)) { | ||
versions.unshift(low); | ||
} | ||
|
||
versions = versions.map((v) => v.toString()); | ||
versions[versions.length - 1] = `^${lastVers.toString()}`; | ||
tavVersMap.set(name, versions); | ||
} | ||
|
||
// Now modify the file contents using the string so we do not loose comments | ||
const tavLines = tavContent.split('\n'); | ||
let tavToUpdate; | ||
|
||
tavLines.forEach((line, idx) => { | ||
const isCfgStart = !/^[\s#]/.test(line) && line.endsWith(':'); | ||
const tavName = isCfgStart ? line.replace(/[':]/g, '') : undefined; | ||
|
||
if (tavName) { | ||
tavToUpdate = tavVersMap.has(tavName) ? tavName : undefined; | ||
} else if (tavToUpdate && line.startsWith(' versions:')) { | ||
console.log(`Updating versions of ${tavToUpdate}`); | ||
const tavVers = tavVersMap.get(tavToUpdate); | ||
tavLines[idx] = ` versions: '${tavVers.join(' || ')}'`; | ||
} | ||
}); | ||
|
||
writeFileSync(TAV_PATH, tavLines.join('\n'), { encoding: 'utf-8' }); | ||
} | ||
|
||
// support functions | ||
|
||
/** | ||
* From a given ordered list of versions returns the first, num in between and last. Example | ||
* - input: ['5.0.0', '5.0.1', '5.1.0', '5.2.0', '5.3.0', '5.4.0', '5.5.0', '5.6.0', '5.7.0', '5.8.0', '5.8.1', '5.9.0'] | ||
* - input: num = 4 | ||
* - output: ['5.0.0', '5.1.0', '5.3.0', '5.5.0', '5.7.0', '5.8.1', '5.9.0'] | ||
* first ^^^^^^^^^ 4 version in between ^^^^^^^^^^^^ last | ||
* | ||
* @param {SemVer[]} versions the version list where to extract | ||
* @param {Number} num the number of versions that should be in between | ||
* @returns {SemVer[]} | ||
*/ | ||
function getMax(versions, num) { | ||
const modulus = Math.floor((versions.length - 2) / num); | ||
|
||
return versions.filter( | ||
(v, idx, arr) => idx % modulus === 0 || idx === arr.length - 1, | ||
); | ||
} | ||
|
||
/** | ||
* From a given ordered list of versions returns the latest minors. Example | ||
* - input: ['5.0.0', '5.0.1', '5.1.0', '5.2.0', '5.3.0', '5.4.0', '5.5.0', '5.6.0', '5.7.0', '5.8.0', '5.8.1', '5.9.0'] | ||
* - output: ['5.0.1', '5.1.0', '5.2.0', '5.3.0', '5.4.0', '5.5.0', '5.6.0', '5.7.0', '5.8.1', '5.9.0'] | ||
* | ||
* @param {SemVer[]} versions the version list where to extract latest minoes | ||
* @returns {SemVer[]} | ||
*/ | ||
function getLatestMajors(versions) { | ||
// assuming sorted array | ||
const result = []; | ||
|
||
for (const ver of versions) { | ||
const lastVer = result[result.length - 1]; | ||
|
||
if (!lastVer) { | ||
result.push(ver); | ||
continue; | ||
} | ||
|
||
if (lastVer.major === ver.major) { | ||
result.pop(); | ||
} | ||
result.push(ver); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* From a given ordered list of versions returns the latest minors. Example | ||
* - input: ['5.0.0', '5.0.1', '5.1.0', '5.2.0', '5.3.0', '5.4.0', '5.5.0', '5.6.0', '5.7.0', '5.8.0', '5.8.1', '5.9.0'] | ||
* - output: ['5.0.1', '5.1.0', '5.2.0', '5.3.0', '5.4.0', '5.5.0', '5.6.0', '5.7.0', '5.8.1', '5.9.0'] | ||
* | ||
* @param {SemVer[]} versions the version list where to extract latest minoes | ||
* @returns {SemVer[]} | ||
*/ | ||
function getLatestMinors(versions) { | ||
// assuming sorted array | ||
const result = []; | ||
|
||
for (const ver of versions) { | ||
const lastVer = result[result.length - 1]; | ||
|
||
if (!lastVer) { | ||
result.push(ver); | ||
continue; | ||
} | ||
|
||
if (lastVer.major !== ver.major || lastVer.minor !== ver.minor) { | ||
result.push(ver); | ||
} else if (lastVer.compare(ver) < 0) { | ||
result[result.length - 1] = ver; | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
// run | ||
main(); |