Add Node LTS auto-update script (#11927)

* Add Node LTS auto-update script

* fix: Validate LTS version and update CI step name in Node update workflow

Add semver validation for the fetched LTS version to prevent creating
PRs with invalid node versions (e.g. null) if the upstream API changes.
Also update the human-readable step name in ci.yml during major bumps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-04-01 19:47:40 -04:00
committed by GitHub
parent 0d0f5cb5c7
commit c3c5f148b7
+94
View File
@@ -0,0 +1,94 @@
name: Update Node.js LTS
on:
schedule:
# Run every Monday at 9:00 UTC
- cron: "0 9 * * 1"
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
update-node:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Check for Node.js LTS update
id: check
run: |
# Get current Node version from Dockerfile
CURRENT_VERSION=$(grep -oP 'FROM node:\K[0-9]+\.[0-9]+\.[0-9]+' Dockerfile.base)
echo "current=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
echo "Current Node.js version: $CURRENT_VERSION"
# Fetch the latest LTS release (any major version) from nodejs.org
LATEST_VERSION=$(curl -s https://nodejs.org/dist/index.json | \
jq -r '[.[] | select(.lts != false)][0].version' | \
sed 's/^v//')
if ! [[ "$LATEST_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Failed to fetch a valid LTS version (got '$LATEST_VERSION')"
exit 1
fi
echo "latest=$LATEST_VERSION" >> "$GITHUB_OUTPUT"
echo "Latest Node.js LTS version: $LATEST_VERSION"
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
echo "updated=false" >> "$GITHUB_OUTPUT"
echo "Already up to date."
else
echo "updated=true" >> "$GITHUB_OUTPUT"
echo "Update available: $CURRENT_VERSION -> $LATEST_VERSION"
fi
- name: Update Node.js version references
if: steps.check.outputs.updated == 'true'
env:
CURRENT: ${{ steps.check.outputs.current }}
LATEST: ${{ steps.check.outputs.latest }}
run: |
CURRENT_MAJOR=$(echo "$CURRENT" | cut -d. -f1)
LATEST_MAJOR=$(echo "$LATEST" | cut -d. -f1)
# Update Dockerfiles
sed -i "s/node:${CURRENT}-slim/node:${LATEST}-slim/g" Dockerfile
sed -i "s/node:${CURRENT} /node:${LATEST} /g" Dockerfile.base
# Update references that depend on major version
if [ "$CURRENT_MAJOR" != "$LATEST_MAJOR" ]; then
# .nvmrc
echo "$LATEST_MAJOR" > .nvmrc
# CI workflow: step name, node-version, and cache keys
sed -i "s/Use Node.js ${CURRENT_MAJOR}.x/Use Node.js ${LATEST_MAJOR}.x/g" .github/workflows/ci.yml
sed -i "s/node-version: ${CURRENT_MAJOR}.x/node-version: ${LATEST_MAJOR}.x/g" .github/workflows/ci.yml
# Update cache keys: replace node-modules-[optional old version] with new version
sed -i -E "s/node-modules-([0-9]+\.x-)?/node-modules-${LATEST_MAJOR}.x-/g" .github/workflows/ci.yml
# package.json engines field: append new major version
sed -i "s/\"node\": \"\(.*\)\"/\"node\": \"\1 || ${LATEST_MAJOR}\"/" package.json
fi
echo "Updated Node.js from $CURRENT to $LATEST"
- name: Create pull request
if: steps.check.outputs.updated == 'true'
uses: peter-evans/create-pull-request@v7
with:
commit-message: "fix: Update Node.js to ${{ steps.check.outputs.latest }}"
title: "fix: Update Node.js to ${{ steps.check.outputs.latest }}"
body: |
Automated update of Node.js in Docker images.
- **Previous version:** ${{ steps.check.outputs.current }}
- **New version:** ${{ steps.check.outputs.latest }}
[Release notes](https://nodejs.org/en/blog/release/v${{ steps.check.outputs.latest }})
branch: automated/update-node-lts
delete-branch: true
labels: dependencies