Skip to content

Commit cbe2c85

Browse files
committed
feat: replace Bash update with full JS build
1 parent df210e4 commit cbe2c85

11 files changed

Lines changed: 124 additions & 1076 deletions

‎CONTRIBUTING.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ After the end of Debian LTS support, the corresponding Debian release is dropped
149149
### Image Creation Automation
150150

151151
- 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).
152-
- If found, the [update script](https://github.com/nodejs/docker-node/blob/main/update.sh) runs
152+
- If found, the [update script](https://github.com/nodejs/docker-node/blob/main/build-automation.mjs) runs
153153
- 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.
154154
- 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).
155155
- 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.
167167
To set up a version update pull request, see the [Pull Requests](#pull-requests) section above and follow these instructions:
168168

169169
1. Create a `version-update` branch
170-
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.
170+
1. Run `npm run build`. This script will automatically update the appropriate files with the latest versions.
171171
1. Commit the modified files to the `version-update` branch and push the branch to your fork.
172172
1. Create a pull request.
173173

‎Dockerfile-alpine.template‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ RUN addgroup -g 1000 node \
1212
curl \
1313
&& ARCH= OPENSSL_ARCH='linux*' && alpineArch="$(apk --print-arch)" \
1414
&& case "${alpineArch##*-}" in \
15-
"${ALPINE_ARCH[@]}"
15+
"${SUPPORTED_ARCH[@]}"
1616
esac \
1717
# use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150
1818
&& export GNUPGHOME="$(mktemp -d)" \

‎Dockerfile-debian.template‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ENV NODE_VERSION=0.0.0
77

88
RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \
99
&& case "${dpkgArch##*-}" in \
10-
"${DEB_ARCH[@]}"
10+
"${SUPPORTED_ARCH[@]}"
1111
esac \
1212
# use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150
1313
&& export GNUPGHOME="$(mktemp -d)" \

‎Dockerfile-slim.template‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ENV NODE_VERSION=0.0.0
77

88
RUN ARCH= OPENSSL_ARCH= && dpkgArch="$(dpkg --print-architecture)" \
99
&& case "${dpkgArch##*-}" in \
10-
"${DEB_ARCH[@]}"
10+
"${SUPPORTED_ARCH[@]}"
1111
esac \
1212
&& set -ex \
1313
&& apt-get update && apt-get install -y ca-certificates curl wget gnupg dirmngr xz-utils libatomic1 --no-install-recommends \

‎architectures‎

Lines changed: 0 additions & 7 deletions
This file was deleted.

‎build-automation.mjs‎

Lines changed: 117 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
import { readFileSync } from 'node:fs';
2-
import { join } from 'node:path';
1+
import { readFileSync, writeFileSync } from 'node:fs';
2+
import { join, resolve } from 'node:path';
33
import { exportVariable } from '@actions/core';
44

5-
import shell from 'shelljs';
5+
const supportedVersions = JSON.parse(readFileSync('versions.json'));
6+
7+
const nodeKeys = readFileSync(resolve(import.meta.dirname, 'keys', 'node.keys'))
8+
.toString()
9+
.trim()
10+
.split('\n');
611

712
const updatedVersions = [];
8-
let prTitle = '';
913

1014
try {
11-
const supportedVersions = JSON.parse(readFileSync('versions.json'));
12-
1315
console.log(
1416
`Found major versions in versions.json: ${Object.keys(supportedVersions).join(', ')}`,
1517
);
@@ -26,48 +28,123 @@ try {
2628
indexVersion.version.startsWith(`v${supportedVersion}`),
2729
);
2830

29-
const variant = Object.keys(
30-
supportedVersions[supportedVersion].variants,
31-
)[0];
32-
const dockerFile = readFileSync(
33-
join('.', supportedVersion, variant, 'Dockerfile'),
34-
'utf-8',
35-
);
36-
37-
const localVersion =
38-
'v' +
39-
dockerFile.match(/NODE_VERSION=(?<version>\d*\.\d*\.\d)/).groups[
40-
'version'
41-
];
42-
console.log(`\tRead version ${localVersion} from ${variant}`);
43-
44-
if (latestVersion.version !== localVersion) {
45-
console.warn(
46-
`\tFound new version ${latestVersion.version}, released on ${latestVersion.date}!`,
47-
);
48-
let updateStatement = `bash update.sh ${supportedVersion}`;
49-
console.log(`\tRunning '${updateStatement}'.`);
50-
shell.exec(updateStatement);
51-
updatedVersions.push(latestVersion.version);
52-
} else {
53-
console.log(`\tEverything up to date for ${latestVersion.version}!
31+
console.log(`\tLatest version: ${latestVersion.version}
5432
\tReleased: ${latestVersion.date}
5533
\tSecurity release: ${latestVersion.security}`);
34+
35+
for (let variant in supportedVersions[supportedVersion].variants) {
36+
const dockerfilePath = join('.', supportedVersion, variant, 'Dockerfile');
37+
const currentDockerfile = readFileSync(dockerfilePath, 'utf-8');
38+
39+
const localVersion =
40+
'v' +
41+
currentDockerfile.match(/NODE_VERSION=(?<version>\d*\.\d*\.\d)/).groups[
42+
'version'
43+
];
44+
45+
const arches = supportedVersions[supportedVersion].variants[variant];
46+
47+
let baseImage;
48+
let archString = '';
49+
let dockerfileTemplate;
50+
if (variant.startsWith('alpine')) {
51+
dockerfileTemplate = readFileSync(
52+
resolve(import.meta.dirname, 'Dockerfile-alpine.template'),
53+
).toString();
54+
55+
baseImage = `alpine:${variant.replace(/alpine/, '')}`;
56+
if (arches.includes('amd64'))
57+
archString += `x86_64) ARCH='x64' OPENSSL_ARCH=linux-x86_64;; \\\n `;
58+
if (arches.includes('arm64v8'))
59+
archString += `aarch64) OPENSSL_ARCH=linux-aarch64;; \\\n `;
60+
if (arches.includes('arm32v6') || arches.includes('arm32v7'))
61+
archString += `arm*) OPENSSL_ARCH=linux-armv4;; \\\n `;
62+
if (arches.includes('ppc64le'))
63+
archString += `ppc64le) OPENSSL_ARCH=linux-ppc64le;; \\\n `;
64+
if (arches.includes('s390x'))
65+
archString += `s390x) OPENSSL_ARCH=linux-s390x;; \\\n `;
66+
archString += '*) echo "unsupported architecture"; exit 1 ;; \\';
67+
} else if (variant.endsWith('-slim')) {
68+
dockerfileTemplate = readFileSync(
69+
resolve(import.meta.dirname, 'Dockerfile-slim.template'),
70+
).toString();
71+
baseImage = `debian:${variant}`;
72+
if (arches.includes('amd64'))
73+
archString += `amd64) ARCH='x64' OPENSSL_ARCH='linux-x86_64';; \\\n `;
74+
if (arches.includes('ppc64le'))
75+
archString += `ppc64el) ARCH='ppc64le' OPENSSL_ARCH='linux-ppc64le';; \\\n `;
76+
if (arches.includes('s390x'))
77+
archString += `s390x) ARCH='s390x' OPENSSL_ARCH='linux*-s390x';; \\\n `;
78+
if (arches.includes('arm64v8'))
79+
archString += `arm64) ARCH='arm64' OPENSSL_ARCH='linux-aarch64';; \\\n `;
80+
if (arches.includes('arm32v7'))
81+
archString += `armhf) ARCH='armv7l' OPENSSL_ARCH='linux-armv4';; \\\n `;
82+
archString += '*) echo "unsupported architecture"; exit 1 ;; \\';
83+
} else {
84+
dockerfileTemplate = readFileSync(
85+
resolve(import.meta.dirname, 'Dockerfile-debian.template'),
86+
).toString();
87+
baseImage = `buildpack-deps:${variant}`;
88+
if (arches.includes('amd64'))
89+
archString += `amd64) ARCH='x64';; \\\n `;
90+
if (arches.includes('ppc64le'))
91+
archString += `ppc64el) ARCH='ppc64le';; \\\n `;
92+
if (arches.includes('s390x'))
93+
archString += `s390x) ARCH='s390x';; \\\n `;
94+
if (arches.includes('arm64v8'))
95+
archString += `arm64) ARCH='arm64';; \\\n `;
96+
if (arches.includes('arm32v7'))
97+
archString += `armhf) ARCH='armv7l';; \\\n `;
98+
archString += '*) echo "unsupported architecture"; exit 1 ;; \\';
99+
}
100+
101+
let dockerfileOutput = dockerfileTemplate
102+
.replace(/^FROM.+$/m, `FROM ${baseImage}`)
103+
.replace(
104+
/^ENV NODE_VERSION=.+$/m,
105+
`ENV NODE_VERSION=${latestVersion.version.substring(1)}`,
106+
)
107+
.replace(
108+
/^(\s*)"\${NODE_KEYS\[@]}".*$/m,
109+
((keys) => keys.map((key) => `$1${key} \\`).join('\n'))(nodeKeys),
110+
)
111+
.replace(/"\$\{SUPPORTED_ARCH\[@\]\}"/s, archString);
112+
113+
if (parseInt(supportedVersion, 10) >= 26) {
114+
dockerfileOutput = dockerfileOutput.replace(
115+
/ENV YARN_VERSION.*\*\n/s,
116+
'',
117+
);
118+
} else {
119+
// Strip out rust and cargo packages for Node.js < 26
120+
dockerfileOutput = dockerfileOutput.replace(
121+
/\s{4}rust \\.*cargo \\\s*/s,
122+
'',
123+
);
124+
}
125+
if (dockerfileOutput === currentDockerfile) {
126+
console.log(`\t${variant}: everything up to date!`);
127+
} else if (latestVersion.version !== localVersion) {
128+
console.log(`\t${variant}: updating to ${latestVersion.version}`);
129+
updatedVersions.push(latestVersion.version);
130+
writeFileSync(dockerfilePath, dockerfileOutput);
131+
} else {
132+
console.warn(
133+
`\t${variant}: non-version changes detected, but file not updated .`,
134+
);
135+
}
56136
}
57137
}
58-
59138
if (updatedVersions.length !== 0) {
60-
prTitle = `feat: Node.js ${updatedVersions.join(', ')}`;
61139
// Let the GitHub Action library set the GITHUB_ENV file rather than manually handling it
62-
exportVariable('NODE_PR_TITLE', prTitle);
140+
exportVariable(
141+
'NODE_PR_TITLE',
142+
`feat: Node.js ${[...new Set(updatedVersions)].join(', ')}`,
143+
);
144+
} else {
145+
console.log('No Pull Request will be created.');
63146
}
64147
} catch (error) {
65148
console.error(error);
66149
process.exit(1);
67-
} finally {
68-
if (prTitle) {
69-
console.log(`PR will be created with title '${prTitle}'`);
70-
} else {
71-
console.log('No Pull Request will be created.');
72-
}
73150
}

‎config‎

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)