Compare commits
1 Commits
054551b677
...
chore/ci-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80faab34f5 |
@@ -1,9 +1,5 @@
|
|||||||
# &node_image is the pre-baked CI base built by .woodpecker/ci-image.yml:
|
|
||||||
# node:22-alpine + python3/make/g++/postgresql-client + pnpm + a warm pnpm
|
|
||||||
# store. The install step resolves from the baked store (--prefer-offline)
|
|
||||||
# instead of paying a ~731s cold fetch + native compile every run.
|
|
||||||
variables:
|
variables:
|
||||||
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
|
- &node_image 'node:22-alpine'
|
||||||
- &enable_pnpm 'corepack enable'
|
- &enable_pnpm 'corepack enable'
|
||||||
|
|
||||||
when:
|
when:
|
||||||
@@ -19,9 +15,8 @@ steps:
|
|||||||
image: *node_image
|
image: *node_image
|
||||||
commands:
|
commands:
|
||||||
- corepack enable
|
- corepack enable
|
||||||
# python3/make/g++ are baked into ci-base; --prefer-offline resolves from
|
- apk add --no-cache python3 make g++
|
||||||
# the baked pnpm store.
|
- pnpm install --frozen-lockfile
|
||||||
- pnpm install --frozen-lockfile --prefer-offline
|
|
||||||
|
|
||||||
# Blocking gate: public framework package must contain no operator-specific
|
# Blocking gate: public framework package must contain no operator-specific
|
||||||
# personal data or private $HOME defaults. Runs early (no node_modules needed).
|
# personal data or private $HOME defaults. Runs early (no node_modules needed).
|
||||||
@@ -69,7 +64,8 @@ steps:
|
|||||||
DATABASE_URL: postgresql://mosaic:mosaic@ci-postgres:5432/mosaic
|
DATABASE_URL: postgresql://mosaic:mosaic@ci-postgres:5432/mosaic
|
||||||
commands:
|
commands:
|
||||||
- *enable_pnpm
|
- *enable_pnpm
|
||||||
# postgresql-client (pg_isready) is baked into ci-base.
|
# Install postgresql-client for pg_isready
|
||||||
|
- apk add --no-cache postgresql-client
|
||||||
# Wait up to 60s for CI postgres to be ready; fail fast if it never comes up.
|
# Wait up to 60s for CI postgres to be ready; fail fast if it never comes up.
|
||||||
- |
|
- |
|
||||||
ready=0
|
ready=0
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
# Runs only on main branch push/tag
|
# Runs only on main branch push/tag
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
# Pre-baked CI base (see .woodpecker/ci-image.yml): node:22-alpine +
|
- &node_image 'node:22-alpine'
|
||||||
# toolchain + warm pnpm store. Kills the second cold install publish pays.
|
|
||||||
- &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
|
|
||||||
- &enable_pnpm 'corepack enable'
|
- &enable_pnpm 'corepack enable'
|
||||||
# Heavy kaniko image builds (~25 min) — gate them so a merge that only touches
|
# Heavy kaniko image builds (~25 min) — gate them so a merge that only touches
|
||||||
# the npm-only CLI (@mosaicstack/mosaic) or docs does NOT rebuild the platform
|
# the npm-only CLI (@mosaicstack/mosaic) or docs does NOT rebuild the platform
|
||||||
@@ -33,8 +31,7 @@ steps:
|
|||||||
image: *node_image
|
image: *node_image
|
||||||
commands:
|
commands:
|
||||||
- corepack enable
|
- corepack enable
|
||||||
# Resolve from the baked pnpm store instead of a cold network fetch.
|
- pnpm install --frozen-lockfile
|
||||||
- pnpm install --frozen-lockfile --prefer-offline
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
image: *node_image
|
image: *node_image
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
#
|
#
|
||||||
# Purpose: eliminate the cold `pnpm install` that dominates every pipeline
|
# Purpose: eliminate the cold `pnpm install` that dominates every pipeline
|
||||||
# (~731s median). This image ships the native toolchain (no per-run `apk add`)
|
# (~731s median). This image ships the native toolchain (no per-run `apk add`)
|
||||||
# AND a warm, content-addressable pnpm store with the dependency tree already
|
# AND a warm, content-addressable pnpm store with the dependency-tree tarballs
|
||||||
# fetched and its musl native modules (better-sqlite3, node-pty, sqlite3,
|
# already fetched at build time. `pnpm fetch` only populates the store from the
|
||||||
# canvas, sharp) compiled ONCE at build time. A pipeline `pnpm install
|
# lockfile — it does NOT run the native node-gyp builds (better-sqlite3,
|
||||||
# --frozen-lockfile --prefer-offline` then resolves from local hard-links in
|
# node-pty, sqlite3, canvas, sharp); those still compile at `pnpm install`,
|
||||||
# tens of seconds.
|
# which is exactly why the musl toolchain stays baked into this image. A
|
||||||
|
# pipeline `pnpm install --frozen-lockfile --prefer-offline` then resolves
|
||||||
|
# tarballs from local hard-links (no network) and compiles natives against the
|
||||||
|
# already-present toolchain, in tens of seconds instead of ~731s.
|
||||||
#
|
#
|
||||||
# Rebuilt only when `pnpm-lock.yaml` or this Dockerfile change
|
# Rebuilt only when `pnpm-lock.yaml` or this Dockerfile change
|
||||||
# (see .woodpecker/ci-image.yml).
|
# (see .woodpecker/ci-image.yml).
|
||||||
@@ -17,8 +20,10 @@
|
|||||||
FROM node:22-alpine
|
FROM node:22-alpine
|
||||||
|
|
||||||
# Native toolchain required to compile node-gyp deps on musl, plus the
|
# Native toolchain required to compile node-gyp deps on musl, plus the
|
||||||
# postgresql-client used by the test step's pg_isready readiness probe.
|
# postgresql-client used by the test step's pg_isready readiness probe. `bash`
|
||||||
RUN apk add --no-cache python3 make g++ postgresql-client
|
# is baked here too — the sanitization step in ci.yml otherwise does a per-run
|
||||||
|
# `apk add bash`.
|
||||||
|
RUN apk add --no-cache python3 make g++ postgresql-client bash
|
||||||
|
|
||||||
# Pin pnpm to the repo's packageManager version via corepack.
|
# Pin pnpm to the repo's packageManager version via corepack.
|
||||||
RUN corepack enable && corepack prepare pnpm@10.6.2 --activate
|
RUN corepack enable && corepack prepare pnpm@10.6.2 --activate
|
||||||
@@ -29,8 +34,10 @@ WORKDIR /app
|
|||||||
ENV PNPM_HOME=/root/.local/share/pnpm
|
ENV PNPM_HOME=/root/.local/share/pnpm
|
||||||
RUN pnpm config set store-dir /root/.local/share/pnpm/store
|
RUN pnpm config set store-dir /root/.local/share/pnpm/store
|
||||||
|
|
||||||
# Warm the store + compile native modules once. `pnpm fetch` populates the
|
# Warm the store. `pnpm fetch` populates the content-addressable store with the
|
||||||
# content-addressable store directly from the lockfile (no package.json /
|
# dependency tarballs directly from the lockfile (no package.json / workspace
|
||||||
# workspace needed), so a baked store stays valid until the lockfile changes.
|
# needed), so a baked store stays valid until the lockfile changes. Note:
|
||||||
|
# `fetch` does NOT compile native modules — that happens later at `pnpm install`
|
||||||
|
# in the pipeline, against the toolchain baked above.
|
||||||
COPY pnpm-lock.yaml ./
|
COPY pnpm-lock.yaml ./
|
||||||
RUN pnpm fetch --frozen-lockfile
|
RUN pnpm fetch --frozen-lockfile
|
||||||
|
|||||||
@@ -2,20 +2,12 @@
|
|||||||
when:
|
when:
|
||||||
- event: [push, pull_request, manual]
|
- event: [push, pull_request, manual]
|
||||||
|
|
||||||
# Dependencies are installed ONCE in the `install` step and every downstream
|
|
||||||
# step depends on it, reusing the populated node_modules from the shared
|
|
||||||
# workspace volume. Do NOT re-run `npm ci` per step — that pays the full cold
|
|
||||||
# install (network fetch + native rebuilds) N times and is the dominant cost
|
|
||||||
# in a pipeline.
|
|
||||||
#
|
|
||||||
# For best results, replace `&node_image` with a pre-baked CI base image that
|
|
||||||
# ships your toolchain (python3/make/g++ for native modules) and a warm npm
|
|
||||||
# cache, then keep `--prefer-offline` so installs resolve from the cache. See
|
|
||||||
# the Mosaic Stack repo's Dockerfile.ci + .woodpecker/ci-image.yml for the
|
|
||||||
# baked-image pattern.
|
|
||||||
variables:
|
variables:
|
||||||
- &node_image 'node:20-alpine'
|
- &node_image 'node:20-alpine'
|
||||||
- &gitleaks_image 'ghcr.io/gitleaks/gitleaks:v8.24.0'
|
- &gitleaks_image 'ghcr.io/gitleaks/gitleaks:v8.24.0'
|
||||||
|
- &install_deps |
|
||||||
|
corepack enable
|
||||||
|
npm ci --ignore-scripts
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Secret scanning (runs in parallel with install, no deps)
|
# Secret scanning (runs in parallel with install, no deps)
|
||||||
@@ -25,18 +17,15 @@ steps:
|
|||||||
- gitleaks git --redact --verbose --log-opts="HEAD~1..HEAD"
|
- gitleaks git --redact --verbose --log-opts="HEAD~1..HEAD"
|
||||||
depends_on: []
|
depends_on: []
|
||||||
|
|
||||||
# Single cached install. Every other step depends on this and reuses the
|
|
||||||
# node_modules it produces in the shared workspace.
|
|
||||||
install:
|
install:
|
||||||
image: *node_image
|
image: *node_image
|
||||||
commands:
|
commands:
|
||||||
- corepack enable
|
- *install_deps
|
||||||
- npm ci --ignore-scripts --prefer-offline
|
|
||||||
depends_on: []
|
|
||||||
|
|
||||||
security-audit:
|
security-audit:
|
||||||
image: *node_image
|
image: *node_image
|
||||||
commands:
|
commands:
|
||||||
|
- *install_deps
|
||||||
- npm audit --audit-level=high
|
- npm audit --audit-level=high
|
||||||
depends_on:
|
depends_on:
|
||||||
- install
|
- install
|
||||||
@@ -46,6 +35,7 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
SKIP_ENV_VALIDATION: 'true'
|
SKIP_ENV_VALIDATION: 'true'
|
||||||
commands:
|
commands:
|
||||||
|
- *install_deps
|
||||||
- npm run lint
|
- npm run lint
|
||||||
depends_on:
|
depends_on:
|
||||||
- install
|
- install
|
||||||
@@ -55,6 +45,7 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
SKIP_ENV_VALIDATION: 'true'
|
SKIP_ENV_VALIDATION: 'true'
|
||||||
commands:
|
commands:
|
||||||
|
- *install_deps
|
||||||
- npm run type-check
|
- npm run type-check
|
||||||
depends_on:
|
depends_on:
|
||||||
- install
|
- install
|
||||||
@@ -64,6 +55,7 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
SKIP_ENV_VALIDATION: 'true'
|
SKIP_ENV_VALIDATION: 'true'
|
||||||
commands:
|
commands:
|
||||||
|
- *install_deps
|
||||||
- npm run test -- --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80,"statements":80}}'
|
- npm run test -- --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80,"statements":80}}'
|
||||||
depends_on:
|
depends_on:
|
||||||
- install
|
- install
|
||||||
@@ -74,6 +66,7 @@ steps:
|
|||||||
SKIP_ENV_VALIDATION: 'true'
|
SKIP_ENV_VALIDATION: 'true'
|
||||||
NODE_ENV: 'production'
|
NODE_ENV: 'production'
|
||||||
commands:
|
commands:
|
||||||
|
- *install_deps
|
||||||
- npm run build
|
- npm run build
|
||||||
depends_on:
|
depends_on:
|
||||||
- lint
|
- lint
|
||||||
|
|||||||
Reference in New Issue
Block a user