From df210e413e567ec3fd4c62c9e58cb4c75d65ac32 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Sat, 10 Oct 2026 14:43:05 -0400 Subject: [PATCH 1/2] chore: update automation script to run locally - Use ShellJS for better GitBash compat than process spawn calls for remaining `update.sh` use - Use the GItHub Action library to pass/set the ENV for the GitHub Action - Add additional logging for local troubleshooting --- .github/workflows/automatic-updates.yml | 23 +- build-automation.mjs | 148 ++++----- package-lock.json | 420 +++++++++++++++++++++++- package.json | 5 +- 4 files changed, 492 insertions(+), 104 deletions(-) diff --git a/.github/workflows/automatic-updates.yml b/.github/workflows/automatic-updates.yml index cf0b4b915..2b7acf1d5 100644 --- a/.github/workflows/automatic-updates.yml +++ b/.github/workflows/automatic-updates.yml @@ -15,26 +15,27 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Run automation script - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - id: updt + - name: Set up Node.js + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: - result-encoding: string - script: | - const { default: script } = await import(`${process.env.GITHUB_WORKSPACE}/build-automation.mjs`); - return script(github); + node-version-file: .node-version + cache: npm + - name: Install dependencies + run: npm ci + + - name: Run automation script + run: npm run build - name: Create update PR - id: cpr - if: steps.updt.outputs.result != '' + if: env.NODE_PR_TITLE != '' uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.GH_API_TOKEN }} author: 'Node.js GitHub Bot ' branch: update-branch base: main - commit-message: 'feat: Node.js ${{ steps.updt.outputs.result }}' - title: 'feat: Node.js ${{ steps.updt.outputs.result }}' + commit-message: '${{ env.NODE_PR_TITLE }}' + title: '${{ env.NODE_PR_TITLE }}' delete-branch: true team-reviewers: | nodejs/docker diff --git a/build-automation.mjs b/build-automation.mjs index ce6200dd7..108d72908 100644 --- a/build-automation.mjs +++ b/build-automation.mjs @@ -1,107 +1,73 @@ -import { promisify } from 'util'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { exportVariable } from '@actions/core'; -import child_process from 'child_process'; +import shell from 'shelljs'; -const exec = promisify(child_process.exec); +const updatedVersions = []; +let prTitle = ''; -// a function that queries the Node.js release website for new versions, -// compare the available ones with the ones we use in this repo -// and returns whether we should update or not -const checkIfThereAreNewVersions = async (github) => { - try { - const { stdout: versionsOutput } = await exec( - '. ./functions.sh && get_versions', - { shell: 'bash' }, - ); - - const supportedVersions = versionsOutput.trim().split(' '); - - let latestSupportedVersions = {}; +try { + const supportedVersions = JSON.parse(readFileSync('versions.json')); - for (let supportedVersion of supportedVersions) { - const { stdout } = await exec(`ls ${supportedVersion}`); - - const { stdout: fullVersionOutput } = await exec( - `. ./functions.sh && get_full_version ./${supportedVersion}/${stdout.trim().split('\n')[0]}`, - { shell: 'bash' }, - ); + console.log( + `Found major versions in versions.json: ${Object.keys(supportedVersions).join(', ')}`, + ); - console.log(fullVersionOutput); + console.log('Grabbing Index.json files'); + const availableVersions = await fetch( + 'https://nodejs.org/download/release/index.json', + ); + const officialIndexJson = await availableVersions.json(); - latestSupportedVersions[supportedVersion] = { - fullVersion: fullVersionOutput.trim(), - }; - } - - const { data: availableVersionsJson } = await github.request( - 'https://nodejs.org/download/release/index.json', + for (let supportedVersion in supportedVersions) { + console.log(`Checking for updates for ${supportedVersion}`); + let latestVersion = officialIndexJson.find((indexVersion) => + indexVersion.version.startsWith(`v${supportedVersion}`), ); - // filter only more recent versions of availableVersionsJson for each major version in latestSupportedVersions' keys - // e.g. if latestSupportedVersions = { "12": "12.22.10", "14": "14.19.0", "16": "16.14.0", "17": "17.5.0" } - // and availableVersions = ["Node.js 12.22.10", "Node.js 12.24.0", "Node.js 14.19.0", "Node.js 14.22.0", "Node.js 16.14.0", "Node.js 16.16.0", "Node.js 17.5.0", "Node.js 17.8.0"] - // return { "12": "12.24.0", "14": "14.22.0", "16": "16.16.0", "17": "17.8.0" } + const variant = Object.keys( + supportedVersions[supportedVersion].variants, + )[0]; + const dockerFile = readFileSync( + join('.', supportedVersion, variant, 'Dockerfile'), + 'utf-8', + ); - let filteredNewerVersions = {}; + const localVersion = + 'v' + + dockerFile.match(/NODE_VERSION=(?\d*\.\d*\.\d)/).groups[ + 'version' + ]; + console.log(`\tRead version ${localVersion} from ${variant}`); - for (let availableVersion of availableVersionsJson) { - const [availableMajor, availableMinor, availablePatch] = - availableVersion.version.split('v')[1].split('.'); - if (latestSupportedVersions[availableMajor] == null) { - continue; - } - // eslint-disable-next-line no-unused-vars - const [_latestMajor, latestMinor, latestPatch] = - latestSupportedVersions[availableMajor].fullVersion.split('.'); - if ( - latestSupportedVersions[availableMajor] && - (Number(availableMinor) > Number(latestMinor) || - (availableMinor === latestMinor && - Number(availablePatch) > Number(latestPatch))) - ) { - filteredNewerVersions[availableMajor] = { - fullVersion: `${availableMajor}.${availableMinor}.${availablePatch}`, - }; - } + if (latestVersion.version !== localVersion) { + console.warn( + `\tFound new version ${latestVersion.version}, released on ${latestVersion.date}!`, + ); + let updateStatement = `bash update.sh ${supportedVersion}`; + console.log(`\tRunning '${updateStatement}'.`); + shell.exec(updateStatement); + updatedVersions.push(latestVersion.version); + } else { + console.log(`\tEverything up to date for ${latestVersion.version}! +\tReleased: ${latestVersion.date} +\tSecurity release: ${latestVersion.security}`); } - - return { - shouldUpdate: - Object.keys(filteredNewerVersions).length > 0 && - JSON.stringify(filteredNewerVersions) !== - JSON.stringify(latestSupportedVersions), - versions: filteredNewerVersions, - }; - } catch (error) { - console.error(error); - process.exit(1); } -}; - -export default async function (github) { - // if there are no new versions, exit gracefully - // if there are new versions, run update.sh - const { shouldUpdate, versions } = await checkIfThereAreNewVersions(github); - if (!shouldUpdate) { - console.log('No new versions found. No update required.'); - process.exit(0); + if (updatedVersions.length !== 0) { + prTitle = `feat: Node.js ${updatedVersions.join(', ')}`; + // Let the GitHub Action library set the GITHUB_ENV file rather than manually handling it + exportVariable('NODE_PR_TITLE', prTitle); + } +} catch (error) { + console.error(error); + process.exit(1); +} finally { + if (prTitle) { + console.log(`PR will be created with title '${prTitle}'`); } else { - let updatedVersions = []; - for (const [version, newVersion] of Object.entries(versions)) { - const { stdout } = await exec(`./update.sh ${version}`); - console.log(stdout); - updatedVersions.push(newVersion.fullVersion); - } - - if (updatedVersions.length === 0) { - console.log('No versions with musl builds were updated.'); - process.exit(0); - } - - const { stdout } = await exec(`git diff`); - console.log(stdout); - - return updatedVersions.join(', '); + console.log('No Pull Request will be created.'); } } diff --git a/package-lock.json b/package-lock.json index 6d286bcfe..3ce8764bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,15 +6,66 @@ "": { "name": "docker-node", "devDependencies": { + "@actions/core": "3.0.1", "@eslint/js": "10.0.1", "doctoc": "2.5.0", "eslint": "10.12.0", "globals": "17.13.0", "markdown-link-check": "3.15.0", "npm-run-all2": "9.0.3", - "prettier": "3.9.9" + "prettier": "3.9.9", + "shelljs": "0.10.0" } }, + "node_modules/@actions/core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/exec": "^3.0.0", + "@actions/http-client": "^4.0.0" + } + }, + "node_modules/@actions/exec": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-3.0.0.tgz", + "integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/io": "^3.0.2" + } + }, + "node_modules/@actions/http-client": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz", + "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^6.23.0" + } + }, + "node_modules/@actions/http-client/node_modules/undici": { + "version": "6.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz", + "integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@actions/io": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-3.0.2.tgz", + "integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==", + "dev": true, + "license": "MIT" + }, "node_modules/@cacheable/memory": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", @@ -257,6 +308,44 @@ "dev": true, "license": "MIT" }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@oozcitak/dom": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", @@ -532,6 +621,19 @@ "node": "20 || >=22" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cacheable": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", @@ -1312,6 +1414,30 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1326,6 +1452,36 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1340,6 +1496,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fault": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", @@ -1364,6 +1530,19 @@ "flat-cache": "^6.1.23" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1409,6 +1588,19 @@ "node": ">=0.4.x" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-uri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-8.0.1.tgz", @@ -1530,6 +1722,16 @@ "node": ">= 20" } }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -1681,6 +1883,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1707,6 +1919,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", @@ -2091,6 +2316,23 @@ "node": ">= 0.10.0" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromark": { "version": "2.11.4", "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", @@ -2226,6 +2468,43 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", @@ -2354,6 +2633,19 @@ "npm": ">= 10" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -2367,6 +2659,22 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2702,6 +3010,27 @@ "dev": true, "license": "MIT" }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/quickjs-wasi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/quickjs-wasi/-/quickjs-wasi-2.2.0.tgz", @@ -2799,6 +3128,41 @@ "node": ">=0.10" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2852,6 +3216,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shelljs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.10.0.tgz", + "integrity": "sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "execa": "^5.1.1", + "fast-glob": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -2904,6 +3289,16 @@ "node": ">=0.10.0" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/structured-source": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", @@ -2914,6 +3309,19 @@ "boundary": "^2.0.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", @@ -2932,6 +3340,16 @@ "dev": true, "license": "0BSD" }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index f7f709cec..7c7c86615 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "type": "commonjs", "scripts": { + "build": "node build-automation.mjs", "format:toc": "doctoc --update-only .", "format:toc:check": "doctoc --update-only --dryrun .", "format:prettier": "prettier --write .", @@ -15,12 +16,14 @@ "check:markdown-links": "find *.md docs/*.md -print0 | xargs -0 -n1 markdown-link-check -c markdown_link_check_config.json" }, "devDependencies": { + "@actions/core": "3.0.1", "@eslint/js": "10.0.1", "doctoc": "2.5.0", "eslint": "10.12.0", "globals": "17.13.0", "markdown-link-check": "3.15.0", "npm-run-all2": "9.0.3", - "prettier": "3.9.9" + "prettier": "3.9.9", + "shelljs": "0.10.0" } } From cbe2c85a61a17a019db6635b5f0d2a307a1791c1 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Sat, 17 Oct 2026 13:13:58 -0400 Subject: [PATCH 2/2] feat: replace Bash update with full JS build --- CONTRIBUTING.md | 4 +- Dockerfile-alpine.template | 2 +- Dockerfile-debian.template | 2 +- Dockerfile-slim.template | 2 +- architectures | 7 - build-automation.mjs | 157 ++++++++++++---- config | 4 - functions.sh | 368 ------------------------------------- package-lock.json | 360 +----------------------------------- package.json | 3 +- update.sh | 291 ----------------------------- 11 files changed, 124 insertions(+), 1076 deletions(-) delete mode 100644 architectures delete mode 100644 config delete mode 100755 functions.sh delete mode 100755 update.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ba0c7779..4a0080777 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -149,7 +149,7 @@ After the end of Debian LTS support, the corresponding Debian release is dropped ### Image Creation Automation - Every 15 minutes, the [workflow](https://github.com/nodejs/docker-node/blob/main/.github/workflows/automatic-updates.yml) within the [nodejs/docker-node](https://github.com/nodejs/docker-node) repo [checks](https://github.com/nodejs/docker-node/blob/main/build-automation.mjs) for new versions of Node.js [published to the website's `index.json` file](https://nodejs.org/download/release/index.json). - - If found, the [update script](https://github.com/nodejs/docker-node/blob/main/update.sh) runs + - If found, the [update script](https://github.com/nodejs/docker-node/blob/main/build-automation.mjs) runs - The workflow opens a pull request either automatically via [nodejs-github-bot](https://github.com/nodejs-github-bot) or in some cases manually, such as when there is a new major release. - Another [workflow](https://github.com/nodejs/docker-node/blob/main/.github/workflows/official-pr.yml) detects the merger of these pull requests and opens a pull request to [docker-library/official-images](https://github.com/docker-library/official-images). - The official images are built and published according to [docker's process](https://github.com/docker-library/faq#an-images-source-changed-in-git-now-what), resulting in the new images being available on [Docker Hub](https://hub.docker.com/_/node). @@ -167,7 +167,7 @@ and your suggestion to resolve it. To set up a version update pull request, see the [Pull Requests](#pull-requests) section above and follow these instructions: 1. Create a `version-update` branch -1. Run `./update.sh`. You can see additional options by using the built-in help documentation with `./update.sh -h`. This script will automatically update the appropriate files with the latest versions and checksums. +1. Run `npm run build`. This script will automatically update the appropriate files with the latest versions. 1. Commit the modified files to the `version-update` branch and push the branch to your fork. 1. Create a pull request. diff --git a/Dockerfile-alpine.template b/Dockerfile-alpine.template index 298f67387..c1ae4f377 100644 --- a/Dockerfile-alpine.template +++ b/Dockerfile-alpine.template @@ -12,7 +12,7 @@ RUN addgroup -g 1000 node \ curl \ && ARCH= OPENSSL_ARCH='linux*' && alpineArch="$(apk --print-arch)" \ && case "${alpineArch##*-}" in \ - "${ALPINE_ARCH[@]}" + "${SUPPORTED_ARCH[@]}" esac \ # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 && export GNUPGHOME="$(mktemp -d)" \ diff --git a/Dockerfile-debian.template b/Dockerfile-debian.template index 23a503dc8..4c5fb79b3 100644 --- a/Dockerfile-debian.template +++ b/Dockerfile-debian.template @@ -7,7 +7,7 @@ ENV NODE_VERSION=0.0.0 RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ && case "${dpkgArch##*-}" in \ - "${DEB_ARCH[@]}" + "${SUPPORTED_ARCH[@]}" esac \ # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 && export GNUPGHOME="$(mktemp -d)" \ diff --git a/Dockerfile-slim.template b/Dockerfile-slim.template index 65972bba3..ba8872319 100644 --- a/Dockerfile-slim.template +++ b/Dockerfile-slim.template @@ -7,7 +7,7 @@ ENV NODE_VERSION=0.0.0 RUN ARCH= OPENSSL_ARCH= && dpkgArch="$(dpkg --print-architecture)" \ && case "${dpkgArch##*-}" in \ - "${DEB_ARCH[@]}" + "${SUPPORTED_ARCH[@]}" esac \ && set -ex \ && apt-get update && apt-get install -y ca-certificates curl wget gnupg dirmngr xz-utils libatomic1 --no-install-recommends \ diff --git a/architectures b/architectures deleted file mode 100644 index 3447a5084..000000000 --- a/architectures +++ /dev/null @@ -1,7 +0,0 @@ -bashbrew-arch variants -amd64 alpine3.23,alpine3.24,bookworm,bookworm-slim,trixie,trixie-slim -arm32v6 alpine3.23,alpine3.24 -arm32v7 alpine3.23,alpine3.24,bookworm,bookworm-slim,trixie,trixie-slim -arm64v8 alpine3.23,alpine3.24,bookworm,bookworm-slim,trixie,trixie-slim -ppc64le bookworm,bookworm-slim,trixie,trixie-slim -s390x alpine3.23,alpine3.24,bookworm,bookworm-slim,trixie,trixie-slim diff --git a/build-automation.mjs b/build-automation.mjs index 108d72908..85ec7e7dc 100644 --- a/build-automation.mjs +++ b/build-automation.mjs @@ -1,15 +1,17 @@ -import { readFileSync } from 'node:fs'; -import { join } from 'node:path'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; import { exportVariable } from '@actions/core'; -import shell from 'shelljs'; +const supportedVersions = JSON.parse(readFileSync('versions.json')); + +const nodeKeys = readFileSync(resolve(import.meta.dirname, 'keys', 'node.keys')) + .toString() + .trim() + .split('\n'); const updatedVersions = []; -let prTitle = ''; try { - const supportedVersions = JSON.parse(readFileSync('versions.json')); - console.log( `Found major versions in versions.json: ${Object.keys(supportedVersions).join(', ')}`, ); @@ -26,48 +28,123 @@ try { indexVersion.version.startsWith(`v${supportedVersion}`), ); - const variant = Object.keys( - supportedVersions[supportedVersion].variants, - )[0]; - const dockerFile = readFileSync( - join('.', supportedVersion, variant, 'Dockerfile'), - 'utf-8', - ); - - const localVersion = - 'v' + - dockerFile.match(/NODE_VERSION=(?\d*\.\d*\.\d)/).groups[ - 'version' - ]; - console.log(`\tRead version ${localVersion} from ${variant}`); - - if (latestVersion.version !== localVersion) { - console.warn( - `\tFound new version ${latestVersion.version}, released on ${latestVersion.date}!`, - ); - let updateStatement = `bash update.sh ${supportedVersion}`; - console.log(`\tRunning '${updateStatement}'.`); - shell.exec(updateStatement); - updatedVersions.push(latestVersion.version); - } else { - console.log(`\tEverything up to date for ${latestVersion.version}! + console.log(`\tLatest version: ${latestVersion.version} \tReleased: ${latestVersion.date} \tSecurity release: ${latestVersion.security}`); + + for (let variant in supportedVersions[supportedVersion].variants) { + const dockerfilePath = join('.', supportedVersion, variant, 'Dockerfile'); + const currentDockerfile = readFileSync(dockerfilePath, 'utf-8'); + + const localVersion = + 'v' + + currentDockerfile.match(/NODE_VERSION=(?\d*\.\d*\.\d)/).groups[ + 'version' + ]; + + const arches = supportedVersions[supportedVersion].variants[variant]; + + let baseImage; + let archString = ''; + let dockerfileTemplate; + if (variant.startsWith('alpine')) { + dockerfileTemplate = readFileSync( + resolve(import.meta.dirname, 'Dockerfile-alpine.template'), + ).toString(); + + baseImage = `alpine:${variant.replace(/alpine/, '')}`; + if (arches.includes('amd64')) + archString += `x86_64) ARCH='x64' OPENSSL_ARCH=linux-x86_64;; \\\n `; + if (arches.includes('arm64v8')) + archString += `aarch64) OPENSSL_ARCH=linux-aarch64;; \\\n `; + if (arches.includes('arm32v6') || arches.includes('arm32v7')) + archString += `arm*) OPENSSL_ARCH=linux-armv4;; \\\n `; + if (arches.includes('ppc64le')) + archString += `ppc64le) OPENSSL_ARCH=linux-ppc64le;; \\\n `; + if (arches.includes('s390x')) + archString += `s390x) OPENSSL_ARCH=linux-s390x;; \\\n `; + archString += '*) echo "unsupported architecture"; exit 1 ;; \\'; + } else if (variant.endsWith('-slim')) { + dockerfileTemplate = readFileSync( + resolve(import.meta.dirname, 'Dockerfile-slim.template'), + ).toString(); + baseImage = `debian:${variant}`; + if (arches.includes('amd64')) + archString += `amd64) ARCH='x64' OPENSSL_ARCH='linux-x86_64';; \\\n `; + if (arches.includes('ppc64le')) + archString += `ppc64el) ARCH='ppc64le' OPENSSL_ARCH='linux-ppc64le';; \\\n `; + if (arches.includes('s390x')) + archString += `s390x) ARCH='s390x' OPENSSL_ARCH='linux*-s390x';; \\\n `; + if (arches.includes('arm64v8')) + archString += `arm64) ARCH='arm64' OPENSSL_ARCH='linux-aarch64';; \\\n `; + if (arches.includes('arm32v7')) + archString += `armhf) ARCH='armv7l' OPENSSL_ARCH='linux-armv4';; \\\n `; + archString += '*) echo "unsupported architecture"; exit 1 ;; \\'; + } else { + dockerfileTemplate = readFileSync( + resolve(import.meta.dirname, 'Dockerfile-debian.template'), + ).toString(); + baseImage = `buildpack-deps:${variant}`; + if (arches.includes('amd64')) + archString += `amd64) ARCH='x64';; \\\n `; + if (arches.includes('ppc64le')) + archString += `ppc64el) ARCH='ppc64le';; \\\n `; + if (arches.includes('s390x')) + archString += `s390x) ARCH='s390x';; \\\n `; + if (arches.includes('arm64v8')) + archString += `arm64) ARCH='arm64';; \\\n `; + if (arches.includes('arm32v7')) + archString += `armhf) ARCH='armv7l';; \\\n `; + archString += '*) echo "unsupported architecture"; exit 1 ;; \\'; + } + + let dockerfileOutput = dockerfileTemplate + .replace(/^FROM.+$/m, `FROM ${baseImage}`) + .replace( + /^ENV NODE_VERSION=.+$/m, + `ENV NODE_VERSION=${latestVersion.version.substring(1)}`, + ) + .replace( + /^(\s*)"\${NODE_KEYS\[@]}".*$/m, + ((keys) => keys.map((key) => `$1${key} \\`).join('\n'))(nodeKeys), + ) + .replace(/"\$\{SUPPORTED_ARCH\[@\]\}"/s, archString); + + if (parseInt(supportedVersion, 10) >= 26) { + dockerfileOutput = dockerfileOutput.replace( + /ENV YARN_VERSION.*\*\n/s, + '', + ); + } else { + // Strip out rust and cargo packages for Node.js < 26 + dockerfileOutput = dockerfileOutput.replace( + /\s{4}rust \\.*cargo \\\s*/s, + '', + ); + } + if (dockerfileOutput === currentDockerfile) { + console.log(`\t${variant}: everything up to date!`); + } else if (latestVersion.version !== localVersion) { + console.log(`\t${variant}: updating to ${latestVersion.version}`); + updatedVersions.push(latestVersion.version); + writeFileSync(dockerfilePath, dockerfileOutput); + } else { + console.warn( + `\t${variant}: non-version changes detected, but file not updated .`, + ); + } } } - if (updatedVersions.length !== 0) { - prTitle = `feat: Node.js ${updatedVersions.join(', ')}`; // Let the GitHub Action library set the GITHUB_ENV file rather than manually handling it - exportVariable('NODE_PR_TITLE', prTitle); + exportVariable( + 'NODE_PR_TITLE', + `feat: Node.js ${[...new Set(updatedVersions)].join(', ')}`, + ); + } else { + console.log('No Pull Request will be created.'); } } catch (error) { console.error(error); process.exit(1); -} finally { - if (prTitle) { - console.log(`PR will be created with title '${prTitle}'`); - } else { - console.log('No Pull Request will be created.'); - } } diff --git a/config b/config deleted file mode 100644 index 68ff056a9..000000000 --- a/config +++ /dev/null @@ -1,4 +0,0 @@ -baseuri https://nodejs.org/dist -default_variant trixie -alpine_version 3.23 -debian_versions bookworm bullseye trixie diff --git a/functions.sh b/functions.sh deleted file mode 100755 index f19c5003b..000000000 --- a/functions.sh +++ /dev/null @@ -1,368 +0,0 @@ -#!/usr/bin/env bash -# -# Utility functions -# Don't change this file unless needed -# The GitHub Action for automating new builds rely on this file - -info() { - printf "%s\\n" "$@" -} - -fatal() { - printf "**********\\n" - printf "Fatal Error: %s\\n" "$@" - printf "**********\\n" - exit 1 -} - -# Get system architecture -# -# This is used to get the target architecture for docker image. -# For crossing building, we need a way to specify the target -# architecture manually. -function get_arch() { - local arch - case $(uname -m) in - x86_64) - arch="amd64" - ;; - ppc64le) - arch="ppc64le" - ;; - s390x) - arch="s390x" - ;; - aarch64 | arm64) - arch="arm64" - ;; - armv7l) - arch="arm32v7" - ;; - *) - echo "$0 does not support architecture ${arch:-unknown} ... aborting" - exit 1 - ;; - esac - - echo "${arch}" -} - -# Get corresponding variants based on the architecture. -# All supported variants of each supported architecture are listed in a -# file - 'architectures'. Its format is: -# ,... -# ,... -function get_variants() { - local dir - dir=${1:-.} - shift - - local arch - local availablevariants - local variantsfilter - local variants=() - - arch=$(get_arch) - variantsfilter=("$@") - IFS=' ' read -ra availablevariants <<< "$(grep "^${arch}" "${dir}/architectures" | sed -E 's/'"${arch}"'[[:space:]]*//' | sed -E 's/,/ /g')" - - if [ ${#variantsfilter[@]} -gt 0 ]; then - for variant1 in "${availablevariants[@]}"; do - for variant2 in "${variantsfilter[@]}"; do - if [ "${variant1}" = "${variant2}" ]; then - variants+=("${variant1}") - fi - done - done - - if [ ${#variants[@]} -gt 0 ]; then - echo "${variants[@]}" - fi - else - echo "${availablevariants[@]}" - fi -} - -# Get supported architectures for a specific version and variant -# -# Get default supported architectures from 'architectures'. Then go to the version folder -# to see if there is a local architectures file. The local architectures will override the -# default architectures. This will give us some benefits: -# - a specific version may or may not support some architectures -# - if there is no specialization for a version, just don't provide local architectures -function get_supported_arches() { - local version - local variant - local arches - local lines - local line - version="$1" - shift - variant="$1" - shift - - # Get default supported arches - lines=$(grep "${variant}" "$(dirname "${version}")"/architectures 2> /dev/null | cut -d' ' -f1) - - # Get version specific supported architectures if there is specialized information - if [ -e "${version}"/architectures ]; then - lines=$(grep "${variant}" "${version}"/architectures 2> /dev/null | cut -d' ' -f1) - fi - - while IFS='' read -r line; do - arches+=("${line}") - done <<< "${lines}" - - echo "${arches[@]}" -} - -# Get configuration values from the config file -# -# The configuration entries are simple key/value pairs which are whitespace separated. -function get_config() { - local dir - dir=${1:-.} - shift - - local name - name=${1} - shift - - local value - value=$(grep "^${name}" "${dir}/config" | sed -E 's/'"${name}"'[[:space:]]*//') - echo "${value}" -} - -# Get available versions for a given path -# -# The result is a list of valid versions. -# shellcheck disable=SC2120 -function get_versions() { - shift - - local versions=() - local dirs=("$@") - - local default_variant - default_variant=$(get_config "./" "default_variant") - if [ ${#dirs[@]} -eq 0 ]; then - IFS=' ' read -ra dirs <<< "$(echo "./"*/)" - fi - - for dir in "${dirs[@]}"; do - if [ -e "${dir}/Dockerfile" ] || [ -e "${dir}/${default_variant}/Dockerfile" ]; then - versions+=("${dir#./}") - fi - done - - if [ ${#versions[@]} -gt 0 ]; then - echo "${versions[@]%/}" - fi -} - -function is_alpine() { - local variant - variant=${1} - shift - - if [ "${variant}" = "${variant#alpine}" ]; then - return 1 - fi -} - -function is_debian() { - local variant - variant=$1 - shift - - IFS=' ' read -ra debianVersions <<< "$(get_config "./" "debian_versions")" - for d in "${debianVersions[@]}"; do - if [ "${d}" = "${variant}" ]; then - return 0 - fi - done - return 1 -} - -function is_debian_slim() { - local variant - variant=$1 - shift - - IFS=' ' read -ra debianVersions <<< "$(get_config "./" "debian_versions")" - for d in "${debianVersions[@]}"; do - if [ "${d}-slim" = "${variant}" ]; then - return 0 - fi - done - return 1 -} - -function get_fork_name() { - local version - version=$1 - shift - - IFS='/' read -ra versionparts <<< "${version}" - if [ ${#versionparts[@]} -gt 1 ]; then - echo "${versionparts[0]}" - fi -} - -function get_full_tag() { - local variant - local tag - local full_tag - variant="$1" - shift - tag="$1" - shift - if [ -z "${variant}" ]; then - full_tag="${tag}" - elif [ "${variant}" = "default" ]; then - full_tag="${tag}" - else - full_tag="${tag}-${variant}" - fi - echo "${full_tag}" -} - -function get_full_version() { - local version - version=$1 - shift - - local default_dockerfile - if [ -f "${version}/${default_variant}/Dockerfile" ]; then - default_dockerfile="${version}/${default_variant}/Dockerfile" - else - default_dockerfile="${version}/Dockerfile" - fi - - grep -m1 'ENV NODE_VERSION=' "${default_dockerfile}" | cut -d= -f2 -} - -function get_major_minor_version() { - local version - version=$1 - shift - - local fullversion - fullversion=$(get_full_version "${version}") - - echo "$(echo "${fullversion}" | cut -d'.' -f1).$(echo "${fullversion}" | cut -d'.' -f2)" -} - -function get_path() { - local version - local variant - local path - version="$1" - shift - variant="$1" - shift - - if [ -z "${variant}" ]; then - path="${version}/${variant}" - elif [ "${variant}" = "default" ]; then - path="${version}" - else - path="${version}/${variant}" - fi - echo "${path}" -} - -function get_tag() { - local version - version=$1 - shift - - local versiontype - versiontype=${1:-full} - shift - - local tagversion - if [ "${versiontype}" = full ]; then - tagversion=$(get_full_version "${version}") - elif [ "${versiontype}" = majorminor ]; then - tagversion=$(get_major_minor_version "${version}") - fi - - local tagparts - IFS=' ' read -ra tagparts <<< "$(get_fork_name "${version}") ${tagversion}" - IFS='-' - echo "${tagparts[*]}" - unset IFS -} - -function sort_versions() { - local versions=("$@") - local sorted - local lines - local line - - IFS=$'\n' - lines="${versions[*]}" - unset IFS - - while IFS='' read -r line; do - sorted+=("${line}") - done <<< "$(echo "${lines}" | grep "^[0-9]" | sort -r)" - - while IFS='' read -r line; do - sorted+=("${line}") - done <<< "$(echo "${lines}" | grep -v "^[0-9]" | sort -r)" - - echo "${sorted[@]}" -} - -function commit_range() { - local commit_id_end=${1} - shift - local commit_id_start=${1} - - if [ -z "${commit_id_start}" ]; then - if [ -z "${commit_id_end}" ]; then - echo "HEAD~1..HEAD" - elif [[ "${commit_id_end}" =~ .. ]]; then - echo "${commit_id_end}" - else - echo "${commit_id_end}~1..${commit_id_end}" - fi - else - echo "${commit_id_end}..${commit_id_start}" - fi -} - -function images_updated() { - local commit_range - local versions - local images_changed - - commit_range="$(commit_range "$@")" - - IFS=' ' read -ra versions <<< "$( - IFS=',' - get_versions - )" - images_changed=$(git diff --name-only "${commit_range}" "${versions[@]}") - - if [ -z "${images_changed}" ]; then - return 1 - fi - return 0 -} - -function tests_updated() { - local commit_range - local test_changed - - commit_range="$(commit_range "$@")" - - test_changed=$(git diff --name-only "${commit_range}" test*) - - if [ -z "${test_changed}" ]; then - return 1 - fi - return 0 -} diff --git a/package-lock.json b/package-lock.json index 3ce8764bf..5f45c0672 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,7 @@ "globals": "17.13.0", "markdown-link-check": "3.15.0", "npm-run-all2": "9.0.3", - "prettier": "3.9.9", - "shelljs": "0.10.0" + "prettier": "3.9.9" } }, "node_modules/@actions/core": { @@ -308,44 +307,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@oozcitak/dom": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", @@ -621,19 +582,6 @@ "node": "20 || >=22" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cacheable": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", @@ -1414,30 +1362,6 @@ "node": ">=0.10.0" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1452,36 +1376,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1496,16 +1390,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", - "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/fault": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", @@ -1530,19 +1414,6 @@ "flat-cache": "^6.1.23" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1588,19 +1459,6 @@ "node": ">=0.4.x" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-uri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-8.0.1.tgz", @@ -1722,16 +1580,6 @@ "node": ">= 20" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -1883,16 +1731,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1919,19 +1757,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isexe": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", @@ -2316,23 +2141,6 @@ "node": ">= 0.10.0" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/micromark": { "version": "2.11.4", "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", @@ -2468,43 +2276,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/minimatch": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", @@ -2633,19 +2404,6 @@ "npm": ">= 10" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -2659,22 +2417,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3010,27 +2752,6 @@ "dev": true, "license": "MIT" }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/quickjs-wasi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/quickjs-wasi/-/quickjs-wasi-2.2.0.tgz", @@ -3128,41 +2849,6 @@ "node": ">=0.10" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3216,27 +2902,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shelljs": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.10.0.tgz", - "integrity": "sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "execa": "^5.1.1", - "fast-glob": "^3.3.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -3289,16 +2954,6 @@ "node": ">=0.10.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/structured-source": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", @@ -3309,19 +2964,6 @@ "boundary": "^2.0.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", diff --git a/package.json b/package.json index 7c7c86615..8478c8004 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "globals": "17.13.0", "markdown-link-check": "3.15.0", "npm-run-all2": "9.0.3", - "prettier": "3.9.9", - "shelljs": "0.10.0" + "prettier": "3.9.9" } } diff --git a/update.sh b/update.sh deleted file mode 100755 index e76eae74e..000000000 --- a/update.sh +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/env bash - -set -ue - -function usage() { - cat << EOF - - Update the node docker images. - - Usage: - $0 [MAJOR_VERSION(S)] [VARIANT(S)] - - Examples: - - update.sh # Update all images - - update.sh 22,24 # Update all variants of version 22 and 24 - - update.sh 24 alpine3.23,alpine3.24 # Update only alpine3.23 & alpine3.24 variants for version 24 - - update.sh . trixie,trixie-slim # Update only trixie & trixie-slim Debian variants for all versions - - OPTIONS: - -h Show this message - -EOF -} - -while getopts "h" opt; do - case "${opt}" in - h) - usage - exit - ;; - \?) - usage - exit - ;; - esac -done - -if ! command -v jq > /dev/null; then - echo "**jq not installed**" >&2 - echo "Follow the instructions in https://jqlang.org/download/ to install" >&2 - exit 1 -fi - -. functions.sh - -cd "$(cd "${0%/*}" && pwd -P)" - -IFS=',' read -ra versions_arg <<< "${1:-}" -IFS=',' read -ra variant_arg <<< "${2:-}" - -IFS=' ' read -ra versions <<< "$(get_versions .)" -IFS=' ' read -ra update_versions <<< "$(get_versions . "${versions_arg[@]:-}")" -IFS=' ' read -ra update_variants <<< "$(get_variants . "${variant_arg[@]:-}")" -if [ ${#versions[@]} -eq 0 ]; then - fatal "No valid versions found!" -fi - -# Global variables -# Get architecture and use this as target architecture for docker image -# See details in function.sh -# TODO: Should be able to specify target architecture manually -arch=$(get_arch) - -function in_versions_to_update() { - local version=$1 - - if [ "${#update_versions[@]}" -eq 0 ]; then - echo 0 - return - fi - - for version_to_update in "${update_versions[@]}"; do - if [ "${version_to_update}" = "${version}" ]; then - echo 0 - return - fi - done - - echo 1 -} - -function in_variants_to_update() { - local variant=$1 - - if [ "${#update_variants[@]}" -eq 0 ]; then - echo 0 - return - fi - - for variant_to_update in "${update_variants[@]}"; do - if [ "${variant_to_update}" = "${variant}" ]; then - echo 0 - return - fi - done - - echo 1 -} - -function update_node_version() { - - local baseuri=${1} - shift - local version=${1} - shift - local template=${1} - shift - local dockerfile=${1} - shift - local variant="" - if [ $# -eq 1 ]; then - variant=${1} - shift - fi - - nodeVersion="$(curl -sSL --compressed "${baseuri}/index.json" | jq -r '[.[] | select(.version | startswith("v'"${version}"'."))] | first | .version | ltrimstr("v")')" - ( - cp "${template}" "${dockerfile}-tmp" - local fromprefix="" - if [ "${arch}" != "amd64" ] && [ "${arch}" != "arm64" ]; then - fromprefix="${arch}\\/" - fi - - sed -Ei -e 's/^FROM (.*)/FROM '"$fromprefix"'\1/' "${dockerfile}-tmp" - sed -Ei -e 's/^(ENV NODE_VERSION)=.*/\1='"${nodeVersion}"'/' "${dockerfile}-tmp" - - # shellcheck disable=SC1004 - new_line=' \\\ -' - - # Add GPG keys - while read -r line; do - pattern='"\$\{'$(echo "node" | tr '[:lower:]' '[:upper:]')'_KEYS\[@\]\}"' - sed -Ei -e "s/([ \\t]*)(${pattern})/\\1${line}${new_line}\\1\\2/" "${dockerfile}-tmp" - done < "keys/node.keys" - sed -Ei -e "/${pattern}/d" "${dockerfile}-tmp" - - if is_alpine "${variant}"; then - alpine_version="${variant#*alpine}" - sed -Ei -e "s/(alpine:)0.0/\\1${alpine_version}/" "${dockerfile}-tmp" - - alpine_arch='' - local -a arches - arches=$(jq -r ".\"${version}\".variants.\"alpine${alpine_version}\" | @sh" "versions.json") - if [[ "${arches[0]}" == *"amd64"* ]]; then - alpine_arch+='x86_64) ARCH='"'"'x64'"'"' OPENSSL_ARCH=linux-x86_64;; \\\n ' - fi - if [[ "${arches[0]}" == *"arm64v8"* ]]; then - alpine_arch+='aarch64) OPENSSL_ARCH=linux-aarch64;; \\\n ' - fi - if [[ "${arches[0]}" == *"arm32"* ]]; then - alpine_arch+='arm*) OPENSSL_ARCH=linux-armv4;; \\\n ' - fi - if [[ "${arches[0]}" == *"ppc64le"* ]]; then - alpine_arch+='ppc64le) OPENSSL_ARCH=linux-ppc64le;; \\\n ' - fi - if [[ "${arches[0]}" == *"s390x"* ]]; then - alpine_arch+='s390x) OPENSSL_ARCH=linux-s390x;; \\\n ' - fi - # shellcheck disable=SC1003 - alpine_arch+='*) echo "unsupported architecture"; exit 1 ;; \\' - sed -Ei -e "s/\"\\$\{ALPINE_ARCH\[@\]\}\"/${alpine_arch}/" "${dockerfile}-tmp" - elif is_debian "${variant}"; then - sed -Ei -e "s/(buildpack-deps:)name/\\1${variant}/" "${dockerfile}-tmp" - deb_arch='' - local -a arches - arches=$(jq -r ".\"${version}\".variants.\"${variant}\" | @sh" "versions.json") - if [[ "${arches[0]}" == *"amd64"* ]]; then - deb_arch+='amd64) ARCH='"'"'x64'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"ppc64le"* ]]; then - deb_arch+='ppc64el) ARCH='"'"'ppc64le'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"s390x"* ]]; then - deb_arch+='s390x) ARCH='"'"'s390x'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"arm64v8"* ]]; then - deb_arch+='arm64) ARCH='"'"'arm64'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"arm32v7"* ]]; then - deb_arch+='armhf) ARCH='"'"'armv7l'"'"';; \\\n ' - fi - # shellcheck disable=SC1003 - deb_arch+='*) echo "unsupported architecture"; exit 1 ;; \\' - sed -Ei -e "s/\"\\$\{DEB_ARCH\[@\]\}\"/${deb_arch}/" "${dockerfile}-tmp" - elif is_debian_slim "${variant}"; then - sed -Ei -e "s/(debian:)name-slim/\\1${variant}/" "${dockerfile}-tmp" - deb_arch='' - local -a arches - arches=$(jq -r ".\"${version}\".variants.\"${variant}\" | @sh" "versions.json") - if [[ "${arches[0]}" == *"amd64"* ]]; then - deb_arch+='amd64) ARCH='"'"'x64'"'"' OPENSSL_ARCH='"'"'linux-x86_64'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"ppc64le"* ]]; then - deb_arch+='ppc64el) ARCH='"'"'ppc64le'"'"' OPENSSL_ARCH='"'"'linux-ppc64le'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"s390x"* ]]; then - deb_arch+='s390x) ARCH='"'"'s390x'"'"' OPENSSL_ARCH='"'"'linux*-s390x'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"arm64v8"* ]]; then - deb_arch+='arm64) ARCH='"'"'arm64'"'"' OPENSSL_ARCH='"'"'linux-aarch64'"'"';; \\\n ' - fi - if [[ "${arches[0]}" == *"arm32v7"* ]]; then - deb_arch+='armhf) ARCH='"'"'armv7l'"'"' OPENSSL_ARCH='"'"'linux-armv4'"'"';; \\\n ' - fi - # shellcheck disable=SC1003 - deb_arch+='*) echo "unsupported architecture"; exit 1 ;; \\' - sed -Ei -e "s/\"\\$\{DEB_ARCH\[@\]\}\"/${deb_arch}/" "${dockerfile}-tmp" - fi - - # Strip out Yarn v1 from Node 26+ images https://github.com/nodejs/docker-node/issues/2407 - # Can be removed from the image templates once Node 24 hits EOL on 2028-04-30 - if [ "${nodeVersion:0:2}" -ge "26" ]; then - sed -Ei -e "/ENV YARN_VERSION/,/rm -rf \/tmp\/\*/d" "${dockerfile}-tmp" - fi - - # Strip out rust/cargo from Alpine images for Node < 26 since these versions don't need rust/cargo for Temporal - # See: https://github.com/nodejs/docker-node/pull/2488 - if [ "${nodeVersion:0:2}" -lt "26" ]; then - sed -Ei -e "/rust/,/cargo/d" "${dockerfile}-tmp" - fi - - if diff -q "${dockerfile}-tmp" "${dockerfile}" > /dev/null; then - echo "${dockerfile} is already up to date!" - else - echo "${dockerfile} updated!" - fi - - # Required for POSIX sed - if [ -f "${dockerfile}-tmp-e" ]; then - rm "${dockerfile}-tmp-e" - fi - - # Guard the move because Alpine sometimes will be missing - if [ -f "${dockerfile}-tmp" ]; then - mv -f "${dockerfile}-tmp" "${dockerfile}" - fi - ) -} - -pids=() - -for version in "${versions[@]}"; do - parentpath=$(dirname "${version}") - versionnum=$(basename "${version}") - baseuri=$(get_config "${parentpath}" "baseuri") - update_version=$(in_versions_to_update "${version}") - - [ "${update_version}" -eq 0 ] && info "Updating version ${version}..." - - # Get supported variants according the target architecture - # See details in function.sh - IFS=' ' read -ra variants <<< "$(get_variants "${parentpath}")" - - if [ -f "${version}/Dockerfile" ]; then - if [ "${update_version}" -eq 0 ]; then - update_node_version "${baseuri}" "${versionnum}" "${parentpath}/Dockerfile.template" "${version}/Dockerfile" & - pids+=($!) - fi - fi - - for variant in "${variants[@]}"; do - # Skip non-docker directories - [ -f "${version}/${variant}/Dockerfile" ] || continue - - update_variant=$(in_variants_to_update "${variant}") - template_file="${parentpath}/Dockerfile-${variant}.template" - - if is_debian "${variant}"; then - template_file="${parentpath}/Dockerfile-debian.template" - elif is_debian_slim "${variant}"; then - template_file="${parentpath}/Dockerfile-slim.template" - elif is_alpine "${variant}"; then - template_file="${parentpath}/Dockerfile-alpine.template" - fi - - cp "${parentpath}/docker-entrypoint.sh" "${version}/${variant}/docker-entrypoint.sh" - if [ "${update_version}" -eq 0 ] && [ "${update_variant}" -eq 0 ]; then - update_node_version "${baseuri}" "${versionnum}" "${template_file}" "${version}/${variant}/Dockerfile" "${variant}" & - pids+=($!) - fi - done -done - -# The reason we explicitly wait on each pid is so the return status of this script is set properly -# if one of the jobs fails. If we just called "wait", the exit status would always be 0 -for pid in "${pids[@]}"; do - wait "$pid" -done - -info "Done!"