#236: pin the Node version #257
@ -86,7 +86,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
|
||||
@ -58,13 +58,46 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# One authoritative Node version (issue #236): `.node-version` is the
|
||||
# pin; every Dockerfile image tag and the engines floor must match it
|
||||
# exactly, and workflows select Node only through node-version-file.
|
||||
# Raising Node = update .node-version, every `FROM node:` tag and the
|
||||
# engines floor in ONE commit (procedure: docs/architecture/operations.md
|
||||
# §Update strategy). The bracketed grep pattern keeps this step from
|
||||
# matching its own source (same trick as the secret fence above).
|
||||
- name: Node version pin is consistent
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ver="$(cat .node-version)"
|
||||
echo "pinned Node version: $ver"
|
||||
bad=0
|
||||
for f in apps/*/Dockerfile; do
|
||||
if grep '^FROM node:' "$f" | grep -v "node:${ver}-alpine"; then
|
||||
echo "$f pins a different Node image than node:${ver}-alpine"
|
||||
bad=1
|
||||
fi
|
||||
done
|
||||
if grep -rn "node-version[:] " .gitea/workflows; then
|
||||
echo "workflows must use node-version-file, not a literal version"
|
||||
bad=1
|
||||
fi
|
||||
if grep -rnE 'node:[0-9][^ ]*-alpine' .gitea/workflows | grep -v "node:${ver}-alpine"; then
|
||||
echo "a workflow references a different node image than node:${ver}-alpine"
|
||||
bad=1
|
||||
fi
|
||||
if ! grep -q "\"node\": \">=${ver}\"" package.json; then
|
||||
echo "package.json engines floor does not match ${ver}"
|
||||
bad=1
|
||||
fi
|
||||
exit "$bad"
|
||||
|
||||
- name: Set up pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
@ -119,7 +152,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
@ -594,7 +627,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
node-version-file: .node-version
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
|
||||
@ -55,7 +55,7 @@ jobs:
|
||||
} > comment.md
|
||||
# JSON-encode via a node container — the runner image guarantees
|
||||
# only git/curl/docker, not python or node.
|
||||
docker run --rm -i node:22.15-alpine node -e \
|
||||
docker run --rm -i node:22.15.1-alpine node -e \
|
||||
'const fs=require("fs");process.stdout.write(JSON.stringify({body:fs.readFileSync(0,"utf8")}))' \
|
||||
< comment.md > comment.json
|
||||
curl -sf -X POST \
|
||||
|
||||
@ -54,7 +54,7 @@ jobs:
|
||||
echo '_No database migrations in this release._'
|
||||
fi
|
||||
} > notes.md
|
||||
TAG=$TAG docker run --rm -i -e TAG node:22.15-alpine node -e \
|
||||
TAG=$TAG docker run --rm -i -e TAG node:22.15.1-alpine node -e \
|
||||
'const fs=require("fs");const body=fs.readFileSync(0,"utf8");process.stdout.write(JSON.stringify({tag_name:process.env.TAG,name:process.env.TAG,body}))' \
|
||||
< notes.md > release.json
|
||||
curl -sf -X POST \
|
||||
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
||||
22.15.1
|
||||
@ -1,7 +1,7 @@
|
||||
# Build context is the repository root (workspace build):
|
||||
# docker build -f apps/api/Dockerfile .
|
||||
|
||||
FROM node:22.15-alpine AS build
|
||||
FROM node:22.15.1-alpine AS build
|
||||
WORKDIR /repo
|
||||
RUN npm install -g pnpm@11
|
||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
||||
@ -23,7 +23,7 @@ RUN pnpm install --frozen-lockfile --filter @dorfteich/api... \
|
||||
&& cp -r apps/api/dist /out/dist \
|
||||
&& cp -r /repo/fonts /out/fonts
|
||||
|
||||
FROM node:22.15-alpine
|
||||
FROM node:22.15.1-alpine
|
||||
ARG APP_VERSION=0.0.0-dev
|
||||
# Default the data dirs to the writable, node-owned locations created below, so
|
||||
# the image works out of the box even where compose does not set them; compose
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Build context is the repository root (workspace build):
|
||||
# docker build -f apps/backup/Dockerfile .
|
||||
|
||||
FROM node:22.15-alpine AS build
|
||||
FROM node:22.15.1-alpine AS build
|
||||
WORKDIR /repo
|
||||
RUN npm install -g pnpm@11
|
||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
||||
@ -14,7 +14,7 @@ RUN pnpm install --frozen-lockfile --filter @dorfteich/backup... \
|
||||
&& pnpm --filter @dorfteich/backup deploy --prod --legacy /out \
|
||||
&& cp -r apps/backup/dist /out/dist
|
||||
|
||||
FROM node:22.15-alpine
|
||||
FROM node:22.15.1-alpine
|
||||
ARG APP_VERSION=0.0.0-dev
|
||||
ENV NODE_ENV=production APP_VERSION=${APP_VERSION} \
|
||||
# Baked-in volume paths (self-sufficient without compose env, like the
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Build context is the repository root (workspace build):
|
||||
# docker build -f apps/collab/Dockerfile .
|
||||
|
||||
FROM node:22.15-alpine AS build
|
||||
FROM node:22.15.1-alpine AS build
|
||||
WORKDIR /repo
|
||||
RUN npm install -g pnpm@11
|
||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
||||
@ -14,7 +14,7 @@ RUN pnpm install --frozen-lockfile --filter @dorfteich/collab... \
|
||||
&& pnpm --filter @dorfteich/collab deploy --prod --legacy /out \
|
||||
&& cp -r apps/collab/dist /out/dist
|
||||
|
||||
FROM node:22.15-alpine
|
||||
FROM node:22.15.1-alpine
|
||||
ARG APP_VERSION=0.0.0-dev
|
||||
ENV NODE_ENV=production APP_VERSION=${APP_VERSION}
|
||||
WORKDIR /app
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Build context is the repository root (workspace build):
|
||||
# docker build -f apps/web/Dockerfile .
|
||||
|
||||
FROM node:22.15-alpine AS build
|
||||
FROM node:22.15.1-alpine AS build
|
||||
ARG APP_VERSION=0.0.0-dev
|
||||
WORKDIR /repo
|
||||
RUN npm install -g pnpm@11
|
||||
|
||||
@ -169,6 +169,16 @@ not a copy of the purged page.
|
||||
- **Base image / dependency hygiene**: monthly dependency-update story
|
||||
(renovate-style batch PR); security advisories for pinned images tracked
|
||||
in the release checklist.
|
||||
- **Toolchain pin (issue #236)**: `.node-version` is the single
|
||||
authoritative Node version. CI/CD select Node exclusively via
|
||||
`node-version-file`, every Dockerfile pins `node:<version>-alpine`, and
|
||||
the `engines.node` floor in `package.json` states the same version
|
||||
(open-ended upwards — a newer local Node keeps working; reproducibility
|
||||
rests on the images and CI, not the laptop). An early CI step fails on
|
||||
any drift between those places. Raising Node (e.g. for a security fix):
|
||||
update `.node-version`, all four Dockerfiles and the engines floor in
|
||||
ONE commit and let CI confirm. pnpm is pinned the same way via
|
||||
`packageManager`.
|
||||
|
||||
## Capacity & limits (initial values, instance-tunable)
|
||||
|
||||
|
||||
@ -255,7 +255,7 @@ fehlten — als Issues angelegt:
|
||||
· 1 AT · #234 (M24, I-23)
|
||||
- [x] `page_links.target_slug`-Residuum nach Purge entscheiden
|
||||
· 0,5 AT · #235 (M24, I-24)
|
||||
- [ ] Node-Version pinnen — Voraussetzung für #219 · 0,5 AT · #236 (M25, I-26)
|
||||
- [x] Node-Version pinnen — Voraussetzung für #219 · 0,5 AT · #236 (M25, I-26)
|
||||
|
||||
Ohne eigenes Issue: IndexedDB-Kopie auf Endgeräten (I-25) — als
|
||||
Akzeptanzkriterium in #226 (Abgrenzungserklärung) und #231
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
"description": "Dorfteich — an open-source wiki system with real-time collaboration",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
"node": ">=22.15.1"
|
||||
},
|
||||
"packageManager": "pnpm@11.9.0",
|
||||
"scripts": {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user