From 5cb0eebe36e0e26d58d511ebe262a8bceef498b2 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Thu, 29 Oct 2026 18:05:38 -0400 Subject: [PATCH 1/4] chore: convert stackbrew to MJS --- .github/workflows/official-pr.yml | 4 ++-- stackbrew.js => stackbrew.mjs | 35 ++++++++++++++----------------- 2 files changed, 18 insertions(+), 21 deletions(-) rename stackbrew.js => stackbrew.mjs (85%) mode change 100755 => 100644 diff --git a/.github/workflows/official-pr.yml b/.github/workflows/official-pr.yml index a1429eb090..6baaf2127a 100644 --- a/.github/workflows/official-pr.yml +++ b/.github/workflows/official-pr.yml @@ -10,7 +10,7 @@ on: - '**/Dockerfile' - '**/docker-entrypoint.sh' - 'versions.json' - - 'stackbrew.js' + - 'stackbrew.mjs' jobs: pr: @@ -36,7 +36,7 @@ jobs: - name: Generate Stackbrew for diff run: | cd docker-node - ./stackbrew.js > ../official-images/library/node + ./stackbrew.mjs > ../official-images/library/node - name: Create PR in official-images id: create-pr diff --git a/stackbrew.js b/stackbrew.mjs old mode 100755 new mode 100644 similarity index 85% rename from stackbrew.js rename to stackbrew.mjs index 5a00e332ee..6ecf96b2b0 --- a/stackbrew.js +++ b/stackbrew.mjs @@ -1,17 +1,15 @@ #!/usr/bin/env node -const fs = require('fs'); -const path = require('path'); +import { readFileSync } from 'node:fs'; +import { basename, join } from 'node:path'; +import { execSync } from 'node:child_process'; // Grab last git commit function getCommitHasForPath(path) { - return require('child_process') - .execSync(`git log -1 --format=%H HEAD -- ${path}`) - .toString() - .trim(); + return execSync(`git log -1 --format=%H HEAD -- ${path}`).toString().trim(); } -const stackbrewPath = path.basename(__filename); +const stackbrewPath = basename(import.meta.filename); // Header let stackbrew = `# this file is generated via https://github.com/nodejs/docker-node/blob/${getCommitHasForPath(stackbrewPath)}/${stackbrewPath} @@ -21,8 +19,7 @@ GitRepo: https://github.com/nodejs/docker-node.git GitFetch: refs/heads/main\n`; // Loop versions - -const config = require('./versions.json'); +const config = JSON.parse(readFileSync('versions.json')); const versions = Object.keys(config).reverse(); @@ -45,13 +42,13 @@ for (const version of versions) { let defaultDebian = config[version]['debian-default']; let variants = config[version].variants; for (const variant in variants) { - let dockerfilePath = path.join(version, variant, 'Dockerfile'); + let dockerfilePath = join(version, variant, 'Dockerfile'); let isAlpine = alpineRE.test(variant); let isSlim = slimRE.test(variant); let isDefaultSlim = new RegExp(`${defaultDebian}-slim`).test(variant); // Get full version from the Dockerfile - let dockerfile = fs.readFileSync(dockerfilePath, 'utf-8'); + let dockerfile = readFileSync(dockerfilePath, 'utf-8'); let fullVersion = dockerfile.match( /ENV NODE_VERSION=(?\d+)\.(?\d+)\.(?\d+)/, ); @@ -157,14 +154,14 @@ for (const version of versions) { } } - // remove duplicates - tags = tags.filter((x, i, a) => a.indexOf(x) == i); - tags = tags.sort(); - let directory = `${version}/${variant}`; - stackbrew += `\nTags: ${tags.join(', ')}\n`; - stackbrew += `Architectures: ${config[version].variants[variant].join(', ')}\n`; - stackbrew += `GitCommit: ${getCommitHasForPath(directory)}\n`; - stackbrew += `Directory: ${directory}\n`; + stackbrew += ` +Tags: ${tags + .filter((x, i, a) => a.indexOf(x) == i) + .sort() + .join(', ')} +Architectures: ${config[version].variants[variant].join(', ')} +GitCommit: ${getCommitHasForPath(`${version}/${variant}`)} +Directory: ${`${version}/${variant}`}\n`; } } From c4620c722cfd5e5b93d644d0825b9ce813639433 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Fri, 30 Oct 2026 16:15:51 -0400 Subject: [PATCH 2/4] feat: Node.js 27.0.0-alpha.0.0.0 --- 27/alpine3.23/Dockerfile | 87 +++++++++++++++++++++++++++ 27/alpine3.23/docker-entrypoint.sh | 11 ++++ 27/alpine3.24/Dockerfile | 87 +++++++++++++++++++++++++++ 27/alpine3.24/docker-entrypoint.sh | 11 ++++ 27/bookworm-slim/Dockerfile | 63 +++++++++++++++++++ 27/bookworm-slim/docker-entrypoint.sh | 11 ++++ 27/bookworm/Dockerfile | 50 +++++++++++++++ 27/bookworm/docker-entrypoint.sh | 11 ++++ 27/trixie-slim/Dockerfile | 64 ++++++++++++++++++++ 27/trixie-slim/docker-entrypoint.sh | 11 ++++ 27/trixie/Dockerfile | 51 ++++++++++++++++ 27/trixie/docker-entrypoint.sh | 11 ++++ versions.json | 41 +++++++++++++ 13 files changed, 509 insertions(+) create mode 100644 27/alpine3.23/Dockerfile create mode 100755 27/alpine3.23/docker-entrypoint.sh create mode 100644 27/alpine3.24/Dockerfile create mode 100755 27/alpine3.24/docker-entrypoint.sh create mode 100644 27/bookworm-slim/Dockerfile create mode 100755 27/bookworm-slim/docker-entrypoint.sh create mode 100644 27/bookworm/Dockerfile create mode 100755 27/bookworm/docker-entrypoint.sh create mode 100644 27/trixie-slim/Dockerfile create mode 100755 27/trixie-slim/docker-entrypoint.sh create mode 100644 27/trixie/Dockerfile create mode 100755 27/trixie/docker-entrypoint.sh diff --git a/27/alpine3.23/Dockerfile b/27/alpine3.23/Dockerfile new file mode 100644 index 0000000000..5f71eee2b7 --- /dev/null +++ b/27/alpine3.23/Dockerfile @@ -0,0 +1,87 @@ +FROM alpine:3.23 + +ENV NODE_VERSION=27.0.0-alpha.0.0.0 + +RUN addgroup -g 1000 node \ + && adduser -u 1000 -G node -s /bin/sh -D node \ + && apk add --no-cache \ + libatomic \ + libstdc++ \ + && apk add --no-cache --virtual .build-deps \ + gnupg \ + curl \ + && ARCH= OPENSSL_ARCH='linux*' && alpineArch="$(apk --print-arch)" \ + && case "${alpineArch##*-}" in \ + x86_64) ARCH='x64' OPENSSL_ARCH=linux-x86_64;; \ + aarch64) OPENSSL_ARCH=linux-aarch64;; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 + && export GNUPGHOME="$(mktemp -d)" \ + # gpg keys listed at https://github.com/nodejs/node#release-keys + && set -ex \ + && for key in \ + 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + CC68F5A3106FF448322E48ED27F5E38D5B0A215F \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD \ + A363A499291CBBC940DD62E41F10027AF002F8B0 \ + ; do \ + { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" && gpg --batch --fingerprint "$key"; } || \ + { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" && gpg --batch --fingerprint "$key"; } ; \ + done \ + && if [ "$ARCH" = "x64" ]; then \ + curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs; \ + else \ + echo "Building from source" \ + && apk add --no-cache --virtual .build-deps-full \ + binutils-gold \ + g++ \ + gcc \ + libgcc \ + linux-headers \ + make \ + python3 \ + py-setuptools \ + rust \ + cargo \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xf "node-v$NODE_VERSION.tar.xz" \ + && cd "node-v$NODE_VERSION" \ + && ./configure \ + && make -j$(getconf _NPROCESSORS_ONLN) V= \ + && make install \ + && apk del .build-deps-full \ + && cd .. \ + && rm -Rf "node-v$NODE_VERSION" \ + && rm "node-v$NODE_VERSION.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt; \ + fi \ + # Remove unused OpenSSL headers to save ~34MB. See this NodeJS issue: https://github.com/nodejs/node/issues/46451 + && find /usr/local/include/node/openssl/archs -mindepth 1 -maxdepth 1 ! -name "$OPENSSL_ARCH" -exec rm -rf {} \; \ + && apk del .build-deps \ + # smoke tests + && node --version \ + && npm --version \ + && rm -rf /tmp/* + + +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +CMD [ "node" ] diff --git a/27/alpine3.23/docker-entrypoint.sh b/27/alpine3.23/docker-entrypoint.sh new file mode 100755 index 0000000000..1b3116e53b --- /dev/null +++ b/27/alpine3.23/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Run command with node if the first argument contains a "-" or is not a system command. The last +# part inside the "{}" is a workaround for the following bug in ash/dash: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264 +if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then + set -- node "$@" +fi + +exec "$@" diff --git a/27/alpine3.24/Dockerfile b/27/alpine3.24/Dockerfile new file mode 100644 index 0000000000..713db86e90 --- /dev/null +++ b/27/alpine3.24/Dockerfile @@ -0,0 +1,87 @@ +FROM alpine:3.24 + +ENV NODE_VERSION=27.0.0-alpha.0.0.0 + +RUN addgroup -g 1000 node \ + && adduser -u 1000 -G node -s /bin/sh -D node \ + && apk add --no-cache \ + libatomic \ + libstdc++ \ + && apk add --no-cache --virtual .build-deps \ + gnupg \ + curl \ + && ARCH= OPENSSL_ARCH='linux*' && alpineArch="$(apk --print-arch)" \ + && case "${alpineArch##*-}" in \ + x86_64) ARCH='x64' OPENSSL_ARCH=linux-x86_64;; \ + aarch64) OPENSSL_ARCH=linux-aarch64;; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 + && export GNUPGHOME="$(mktemp -d)" \ + # gpg keys listed at https://github.com/nodejs/node#release-keys + && set -ex \ + && for key in \ + 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + CC68F5A3106FF448322E48ED27F5E38D5B0A215F \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD \ + A363A499291CBBC940DD62E41F10027AF002F8B0 \ + ; do \ + { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" && gpg --batch --fingerprint "$key"; } || \ + { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" && gpg --batch --fingerprint "$key"; } ; \ + done \ + && if [ "$ARCH" = "x64" ]; then \ + curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs; \ + else \ + echo "Building from source" \ + && apk add --no-cache --virtual .build-deps-full \ + binutils-gold \ + g++ \ + gcc \ + libgcc \ + linux-headers \ + make \ + python3 \ + py-setuptools \ + rust \ + cargo \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xf "node-v$NODE_VERSION.tar.xz" \ + && cd "node-v$NODE_VERSION" \ + && ./configure \ + && make -j$(getconf _NPROCESSORS_ONLN) V= \ + && make install \ + && apk del .build-deps-full \ + && cd .. \ + && rm -Rf "node-v$NODE_VERSION" \ + && rm "node-v$NODE_VERSION.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt; \ + fi \ + # Remove unused OpenSSL headers to save ~34MB. See this NodeJS issue: https://github.com/nodejs/node/issues/46451 + && find /usr/local/include/node/openssl/archs -mindepth 1 -maxdepth 1 ! -name "$OPENSSL_ARCH" -exec rm -rf {} \; \ + && apk del .build-deps \ + # smoke tests + && node --version \ + && npm --version \ + && rm -rf /tmp/* + + +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +CMD [ "node" ] diff --git a/27/alpine3.24/docker-entrypoint.sh b/27/alpine3.24/docker-entrypoint.sh new file mode 100755 index 0000000000..1b3116e53b --- /dev/null +++ b/27/alpine3.24/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Run command with node if the first argument contains a "-" or is not a system command. The last +# part inside the "{}" is a workaround for the following bug in ash/dash: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264 +if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then + set -- node "$@" +fi + +exec "$@" diff --git a/27/bookworm-slim/Dockerfile b/27/bookworm-slim/Dockerfile new file mode 100644 index 0000000000..64cadb3836 --- /dev/null +++ b/27/bookworm-slim/Dockerfile @@ -0,0 +1,63 @@ +FROM debian:bookworm-slim + +RUN groupadd --gid 1000 node \ + && useradd --uid 1000 --gid node --shell /bin/bash --create-home node + +ENV NODE_VERSION=27.0.0-alpha.0.0.0 + +RUN ARCH= OPENSSL_ARCH= && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) ARCH='x64' OPENSSL_ARCH='linux-x86_64';; \ + ppc64el) ARCH='ppc64le' OPENSSL_ARCH='linux-ppc64le';; \ + arm64) ARCH='arm64' OPENSSL_ARCH='linux-aarch64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + && set -ex \ + && apt-get update && apt-get install -y ca-certificates curl wget gnupg dirmngr xz-utils libatomic1 --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 + && export GNUPGHOME="$(mktemp -d)" \ + # gpg keys listed at https://github.com/nodejs/node#release-keys + && for key in \ + 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + CC68F5A3106FF448322E48ED27F5E38D5B0A215F \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD \ + A363A499291CBBC940DD62E41F10027AF002F8B0 \ + ; do \ + { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" && gpg --batch --fingerprint "$key"; } || \ + { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" && gpg --batch --fingerprint "$key"; } ; \ + done \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + # Remove unused OpenSSL headers to save ~34MB. See this NodeJS issue: https://github.com/nodejs/node/issues/46451 + && find /usr/local/include/node/openssl/archs -mindepth 1 -maxdepth 1 ! -name "$OPENSSL_ARCH" -exec rm -rf {} \; \ + && apt-mark auto '.*' > /dev/null \ + && find /usr/local -type f -executable -exec ldd '{}' ';' \ + | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ + | sort -u \ + | xargs -r dpkg-query --search \ + | cut -d: -f1 \ + | sort -u \ + | xargs -r apt-mark manual \ + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ + # smoke tests + && node --version \ + && npm --version \ + && rm -rf /tmp/* + + +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +CMD [ "node" ] diff --git a/27/bookworm-slim/docker-entrypoint.sh b/27/bookworm-slim/docker-entrypoint.sh new file mode 100755 index 0000000000..1b3116e53b --- /dev/null +++ b/27/bookworm-slim/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Run command with node if the first argument contains a "-" or is not a system command. The last +# part inside the "{}" is a workaround for the following bug in ash/dash: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264 +if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then + set -- node "$@" +fi + +exec "$@" diff --git a/27/bookworm/Dockerfile b/27/bookworm/Dockerfile new file mode 100644 index 0000000000..fff3fb8b6c --- /dev/null +++ b/27/bookworm/Dockerfile @@ -0,0 +1,50 @@ +FROM buildpack-deps:bookworm + +RUN groupadd --gid 1000 node \ + && useradd --uid 1000 --gid node --shell /bin/bash --create-home node + +ENV NODE_VERSION=27.0.0-alpha.0.0.0 + +RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) ARCH='x64';; \ + ppc64el) ARCH='ppc64le';; \ + arm64) ARCH='arm64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 + && export GNUPGHOME="$(mktemp -d)" \ + # gpg keys listed at https://github.com/nodejs/node#release-keys + && set -ex \ + && for key in \ + 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + CC68F5A3106FF448322E48ED27F5E38D5B0A215F \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD \ + A363A499291CBBC940DD62E41F10027AF002F8B0 \ + ; do \ + { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" && gpg --batch --fingerprint "$key"; } || \ + { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" && gpg --batch --fingerprint "$key"; } ; \ + done \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ + # smoke tests + && node --version \ + && npm --version \ + && rm -rf /tmp/* + + +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +CMD [ "node" ] diff --git a/27/bookworm/docker-entrypoint.sh b/27/bookworm/docker-entrypoint.sh new file mode 100755 index 0000000000..1b3116e53b --- /dev/null +++ b/27/bookworm/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Run command with node if the first argument contains a "-" or is not a system command. The last +# part inside the "{}" is a workaround for the following bug in ash/dash: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264 +if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then + set -- node "$@" +fi + +exec "$@" diff --git a/27/trixie-slim/Dockerfile b/27/trixie-slim/Dockerfile new file mode 100644 index 0000000000..baef31f621 --- /dev/null +++ b/27/trixie-slim/Dockerfile @@ -0,0 +1,64 @@ +FROM debian:trixie-slim + +RUN groupadd --gid 1000 node \ + && useradd --uid 1000 --gid node --shell /bin/bash --create-home node + +ENV NODE_VERSION=27.0.0-alpha.0.0.0 + +RUN ARCH= OPENSSL_ARCH= && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) ARCH='x64' OPENSSL_ARCH='linux-x86_64';; \ + ppc64el) ARCH='ppc64le' OPENSSL_ARCH='linux-ppc64le';; \ + s390x) ARCH='s390x' OPENSSL_ARCH='linux*-s390x';; \ + arm64) ARCH='arm64' OPENSSL_ARCH='linux-aarch64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + && set -ex \ + && apt-get update && apt-get install -y ca-certificates curl wget gnupg dirmngr xz-utils libatomic1 --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 + && export GNUPGHOME="$(mktemp -d)" \ + # gpg keys listed at https://github.com/nodejs/node#release-keys + && for key in \ + 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + CC68F5A3106FF448322E48ED27F5E38D5B0A215F \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD \ + A363A499291CBBC940DD62E41F10027AF002F8B0 \ + ; do \ + { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" && gpg --batch --fingerprint "$key"; } || \ + { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" && gpg --batch --fingerprint "$key"; } ; \ + done \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + # Remove unused OpenSSL headers to save ~34MB. See this NodeJS issue: https://github.com/nodejs/node/issues/46451 + && find /usr/local/include/node/openssl/archs -mindepth 1 -maxdepth 1 ! -name "$OPENSSL_ARCH" -exec rm -rf {} \; \ + && apt-mark auto '.*' > /dev/null \ + && find /usr/local -type f -executable -exec ldd '{}' ';' \ + | awk '/=>/ { so = $(NF-1); if (index(so, "/usr/local/") == 1) { next }; gsub("^/(usr/)?", "", so); print so }' \ + | sort -u \ + | xargs -r dpkg-query --search \ + | cut -d: -f1 \ + | sort -u \ + | xargs -r apt-mark manual \ + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ + # smoke tests + && node --version \ + && npm --version \ + && rm -rf /tmp/* + + +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +CMD [ "node" ] diff --git a/27/trixie-slim/docker-entrypoint.sh b/27/trixie-slim/docker-entrypoint.sh new file mode 100755 index 0000000000..1b3116e53b --- /dev/null +++ b/27/trixie-slim/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Run command with node if the first argument contains a "-" or is not a system command. The last +# part inside the "{}" is a workaround for the following bug in ash/dash: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264 +if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then + set -- node "$@" +fi + +exec "$@" diff --git a/27/trixie/Dockerfile b/27/trixie/Dockerfile new file mode 100644 index 0000000000..5168c624fa --- /dev/null +++ b/27/trixie/Dockerfile @@ -0,0 +1,51 @@ +FROM buildpack-deps:trixie + +RUN groupadd --gid 1000 node \ + && useradd --uid 1000 --gid node --shell /bin/bash --create-home node + +ENV NODE_VERSION=27.0.0-alpha.0.0.0 + +RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) ARCH='x64';; \ + ppc64el) ARCH='ppc64le';; \ + s390x) ARCH='s390x';; \ + arm64) ARCH='arm64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + # use pre-existing gpg directory, see https://github.com/nodejs/docker-node/pull/1895#issuecomment-1550389150 + && export GNUPGHOME="$(mktemp -d)" \ + # gpg keys listed at https://github.com/nodejs/node#release-keys + && set -ex \ + && for key in \ + 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + CC68F5A3106FF448322E48ED27F5E38D5B0A215F \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD \ + A363A499291CBBC940DD62E41F10027AF002F8B0 \ + ; do \ + { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" && gpg --batch --fingerprint "$key"; } || \ + { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" && gpg --batch --fingerprint "$key"; } ; \ + done \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" \ + && grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ + # smoke tests + && node --version \ + && npm --version \ + && rm -rf /tmp/* + + +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +CMD [ "node" ] diff --git a/27/trixie/docker-entrypoint.sh b/27/trixie/docker-entrypoint.sh new file mode 100755 index 0000000000..1b3116e53b --- /dev/null +++ b/27/trixie/docker-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Run command with node if the first argument contains a "-" or is not a system command. The last +# part inside the "{}" is a workaround for the following bug in ash/dash: +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264 +if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then + set -- node "$@" +fi + +exec "$@" diff --git a/versions.json b/versions.json index 479c550111..b522ec294f 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,45 @@ { + "27": { + "alpha": "2026-10-28", + "lts": "2027-10-20", + "start": "2027-04-22", + "end": "2030-04-30", + "codename": "", + "alpine-default": "alpine3.24", + "debian-default": "trixie", + "variants": { + "alpine3.23": [ + "amd64", + "arm64v8" + ], + "alpine3.24": [ + "amd64", + "arm64v8" + ], + "bookworm": [ + "amd64", + "arm64v8", + "ppc64le" + ], + "bookworm-slim": [ + "amd64", + "arm64v8", + "ppc64le" + ], + "trixie": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ], + "trixie-slim": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + } + }, "26": { "start": "2026-05-05", "lts": "2026-10-28", From f724207c83c7fd3e96c468d2445bbfc09f60bc86 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Fri, 30 Oct 2026 17:27:58 -0400 Subject: [PATCH 3/4] feat: handle alpha versions with minimal tags --- .github/workflows/official-pr.yml | 2 +- stackbrew.mjs | 239 ++++++++++++++++-------------- versions.json | 20 --- 3 files changed, 128 insertions(+), 133 deletions(-) diff --git a/.github/workflows/official-pr.yml b/.github/workflows/official-pr.yml index 6baaf2127a..2c6aeaa125 100644 --- a/.github/workflows/official-pr.yml +++ b/.github/workflows/official-pr.yml @@ -36,7 +36,7 @@ jobs: - name: Generate Stackbrew for diff run: | cd docker-node - ./stackbrew.mjs > ../official-images/library/node + ./stackbrew.mjs ../official-images/library/node - name: Create PR in official-images id: create-pr diff --git a/stackbrew.mjs b/stackbrew.mjs index 6ecf96b2b0..62e4c78a64 100644 --- a/stackbrew.mjs +++ b/stackbrew.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node -import { readFileSync } from 'node:fs'; -import { basename, join } from 'node:path'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { basename, resolve } from 'node:path'; import { execSync } from 'node:child_process'; // Grab last git commit @@ -9,6 +9,18 @@ function getCommitHasForPath(path) { return execSync(`git log -1 --format=%H HEAD -- ${path}`).toString().trim(); } +// Grab nodejs/Release values as the authoritative start/maintenance/end dates +const releaseTimes = await fetch( + 'https://raw.githubusercontent.com/nodejs/Release/refs/heads/main/schedule.json', +); +const releaseJson = await releaseTimes.json(); + +// Grab the nodejs.org index.json as the authoritative Codename values, since that can lag the Release repo JSON +const availableVersions = await fetch( + 'https://nodejs.org/download/release/index.json', +); +const officialIndexJson = await availableVersions.json(); + const stackbrewPath = basename(import.meta.filename); // Header @@ -18,97 +30,60 @@ Maintainers: The Node.js Docker Team (@n GitRepo: https://github.com/nodejs/docker-node.git GitFetch: refs/heads/main\n`; -// Loop versions const config = JSON.parse(readFileSync('versions.json')); -const versions = Object.keys(config).reverse(); +const localVersions = Object.keys(config).reverse(); let midnight = new Date(); midnight.setHours(0, 0, 0, 0); const now = midnight.getTime(); -const alpineRE = new RegExp(/alpine*/); -const slimRE = new RegExp(/\*-slim/); let foundLTS = false; let foundCurrent = false; -for (const version of versions) { - let lts = new Date(`${config[version].lts}T00:00:00.00`).getTime(); - let isCurrent = foundCurrent ? false : isNaN(lts) || lts >= now; - foundCurrent = isCurrent || foundCurrent; - let isLTS = foundLTS ? false : now >= lts; - foundLTS = isLTS || foundLTS; - let codename = config[version].codename; - let defaultAlpine = config[version]['alpine-default']; - let defaultDebian = config[version]['debian-default']; - let variants = config[version].variants; +for (const majorVersion of localVersions) { + let releaseRepoInfo = releaseJson[`v${majorVersion}`]; + let nodejsOrgReleaseInfo = officialIndexJson.find((indexVersion) => + indexVersion.version.startsWith(`v${majorVersion}`), + ); + let currentStart = new Date(`${releaseRepoInfo.start}T00:00:00.00`).getTime(); + // First Alpha build is the only active one, and when the "start" of the release hasn't cut over + let isAlpha = nodejsOrgReleaseInfo.version.includes('alpha'); + // The Current/Latest release is the first non-Alpha major that has hit it's "start" date + let isCurrent = foundCurrent + ? false + : !isAlpha && (isNaN(currentStart) || now >= currentStart); + foundCurrent |= isCurrent; + let codename = nodejsOrgReleaseInfo.lts + ? nodejsOrgReleaseInfo.lts.toLowerCase() + : ''; + // The LTS tag is only set on the most recent LTS release + let isLTS = foundLTS ? false : codename !== ''; + foundLTS |= isLTS; + let defaultAlpine = config[majorVersion]['alpine-default']; + let defaultDebian = config[majorVersion]['debian-default']; + let defaultSlim = `${config[majorVersion]['debian-default']}-slim`; + let variants = config[majorVersion].variants; for (const variant in variants) { - let dockerfilePath = join(version, variant, 'Dockerfile'); - let isAlpine = alpineRE.test(variant); - let isSlim = slimRE.test(variant); - let isDefaultSlim = new RegExp(`${defaultDebian}-slim`).test(variant); - - // Get full version from the Dockerfile - let dockerfile = readFileSync(dockerfilePath, 'utf-8'); - let fullVersion = dockerfile.match( - /ENV NODE_VERSION=(?\d+)\.(?\d+)\.(?\d+)/, - ); - - let tags = [ - `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-${variant}`, - `${fullVersion.groups.major}.${fullVersion.groups.minor}-${variant}`, - `${fullVersion.groups.major}-${variant}`, - ]; - - if (codename) { - tags.push(`${codename}-${variant}`); - } - - if (variant === defaultAlpine) { - tags.push( - `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-alpine`, - ); - tags.push( - `${fullVersion.groups.major}.${fullVersion.groups.minor}-alpine`, + let tags; + + if (isAlpha) { + // Only push explicit variants during the Alpha phase + tags = [`${nodejsOrgReleaseInfo.version.substring(1)}-${variant}`]; + } else { + let fullVersion = nodejsOrgReleaseInfo.version.match( + /v(?\d+)\.(?\d+)\.(?\d+)/, ); - tags.push(`${fullVersion.groups.major}-alpine`); - if (codename) { - tags.push(`${codename}-alpine`); - } - } + tags = [ + `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-${variant}`, + `${fullVersion.groups.major}.${fullVersion.groups.minor}-${variant}`, + `${fullVersion.groups.major}-${variant}`, + ]; - if (variant === defaultDebian) { - tags.push( - `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}`, - ); - tags.push(`${fullVersion.groups.major}.${fullVersion.groups.minor}`); - tags.push(`${fullVersion.groups.major}`); - if (isSlim) { - tags.push( - `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-slim`, - ); - tags.push( - `${fullVersion.groups.major}.${fullVersion.groups.minor}-slim`, - ); - tags.push(`${fullVersion.groups.major}-slim`); - } if (codename) { - tags.push(`${codename}`); + tags.push(`${codename}-${variant}`); } - } - if (isDefaultSlim) { - tags.push( - `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-slim`, - ); - tags.push(`${fullVersion.groups.major}.${fullVersion.groups.minor}-slim`); - tags.push(`${fullVersion.groups.major}-slim`); - if (codename) { - tags.push(`${codename}-slim`); - } - } - if (isCurrent) { if (variant === defaultAlpine) { - tags.push(variant); tags.push( `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-alpine`, ); @@ -116,41 +91,72 @@ for (const version of versions) { `${fullVersion.groups.major}.${fullVersion.groups.minor}-alpine`, ); tags.push(`${fullVersion.groups.major}-alpine`); - tags.push('alpine'); - tags.push('current-alpine'); - } - if (variant === defaultDebian) { - tags.push(variant); - tags.push('latest'); - tags.push('current'); - } - if (isAlpine) { - tags.push(`${variant}`); - tags.push(`current-${variant}`); - } - if (!isAlpine) { - tags.push(`${variant}`); - tags.push(`current-${variant}`); - } - if (isDefaultSlim) { - tags.push('slim'); - tags.push('current-slim'); - } - } - if (isLTS) { - tags.push(`lts-${variant}`); - if (variant === defaultDebian) { - tags.push('lts'); if (codename) { - tags.push(`lts-${codename}`); + tags.push(`${codename}-alpine`); + } + + if (isCurrent) { + tags.push('alpine'); + tags.push('current-alpine'); + } + + if (isLTS) { + tags.push(`lts-alpine`); + } + } else if (variant === defaultDebian) { + tags.push( + `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}`, + ); + tags.push(`${fullVersion.groups.major}.${fullVersion.groups.minor}`); + tags.push(`${fullVersion.groups.major}`); + + if (codename) { + tags.push(`${codename}`); + } + + if (isCurrent) { + tags.push(variant); + tags.push('latest'); + tags.push('current'); + } + + if (isLTS) { + tags.push('lts'); + if (codename) { + tags.push(`lts-${codename}`); + } + } + } else if (variant === defaultSlim) { + tags.push( + `${fullVersion.groups.major}.${fullVersion.groups.minor}.${fullVersion.groups.patch}-slim`, + ); + tags.push( + `${fullVersion.groups.major}.${fullVersion.groups.minor}-slim`, + ); + tags.push(`${fullVersion.groups.major}-slim`); + + if (codename) { + tags.push(`${codename}-slim`); + } + + if (isCurrent) { + tags.push('slim'); + tags.push('current-slim'); + } + + if (isLTS) { + tags.push(`lts-slim`); } } - if (isDefaultSlim) { - tags.push(`lts-slim`); + + if (isCurrent) { + tags.push(`${variant}`); + tags.push(`current-${variant}`); } - if (variant === defaultAlpine) { - tags.push(`lts-alpine`); + + if (isLTS) { + tags.push(`lts-${variant}`); } } @@ -159,11 +165,20 @@ Tags: ${tags .filter((x, i, a) => a.indexOf(x) == i) .sort() .join(', ')} -Architectures: ${config[version].variants[variant].join(', ')} -GitCommit: ${getCommitHasForPath(`${version}/${variant}`)} -Directory: ${`${version}/${variant}`}\n`; +Architectures: ${config[majorVersion].variants[variant].join(', ')} +GitCommit: ${getCommitHasForPath(`${majorVersion}/${variant}`)} +Directory: ${`${majorVersion}/${variant}`}\n`; } } -// output -console.log(stackbrew); +try { + const outputFile = process.argv[2]; + + if (outputFile) { + writeFileSync(resolve(outputFile), stackbrew); + } else { + console.log(stackbrew); + } +} catch (ex) { + console.error("Couldn't handle output", ex); +} diff --git a/versions.json b/versions.json index b522ec294f..3f3b72fc52 100644 --- a/versions.json +++ b/versions.json @@ -1,10 +1,5 @@ { "27": { - "alpha": "2026-10-28", - "lts": "2027-10-20", - "start": "2027-04-22", - "end": "2030-04-30", - "codename": "", "alpine-default": "alpine3.24", "debian-default": "trixie", "variants": { @@ -41,11 +36,6 @@ } }, "26": { - "start": "2026-05-05", - "lts": "2026-10-28", - "maintenance": "2027-10-20", - "end": "2029-04-30", - "codename": "lithium", "alpine-default": "alpine3.24", "debian-default": "trixie", "variants": { @@ -82,11 +72,6 @@ } }, "24": { - "start": "2025-05-06", - "lts": "2025-10-28", - "maintenance": "2026-10-20", - "end": "2028-04-30", - "codename": "krypton", "alpine-default": "alpine3.24", "debian-default": "bookworm", "variants": { @@ -125,11 +110,6 @@ } }, "22": { - "start": "2024-04-23", - "lts": "2024-10-29", - "maintenance": "2025-10-21", - "end": "2027-04-30", - "codename": "jod", "alpine-default": "alpine3.24", "debian-default": "bookworm", "variants": { From a26b642fc0912c90b999af3151c36ae1d2f4f72f Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Fri, 30 Oct 2026 18:45:58 -0400 Subject: [PATCH 4/4] ci: allow the full Alpha string in the build matrix --- genMatrix.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genMatrix.js b/genMatrix.js index fc10f8d994..a1249d9e61 100644 --- a/genMatrix.js +++ b/genMatrix.js @@ -52,7 +52,7 @@ const getAffectedDockerfiles = (filesAdded, filesModified, filesRenamed) => { }; const getFullNodeVersionFromDockerfile = (file) => - fs.readFileSync(file, 'utf8').match(/^ENV NODE_VERSION=(\d*\.*\d*\.\d*)/m)[1]; + fs.readFileSync(file, 'utf8').match(/^ENV NODE_VERSION=(\S*)/m)[1]; const getDockerfileMatrixEntry = (file) => { const [variant] = path.dirname(file).split(path.sep).slice(-1);