-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathDockerfile
More file actions
236 lines (187 loc) · 8.63 KB
/
Copy pathDockerfile
File metadata and controls
236 lines (187 loc) · 8.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# Multi-stage Dockerfile for scriptlets CI optimization
# Dependencies are cached until package.json/pnpm-lock.yaml change
# Each stage can be built independently via --target
FROM adguard/node-ssh:22.22--0 AS base
SHELL ["/bin/bash", "-lc"]
WORKDIR /scriptlets
ENV PNPM_STORE=/pnpm-store
# Cap the V8 old-space heap. Builds run on a shared remote BuildKit instance
# (the CI workflow runs lint/vitest/qunit/smoke/build as strictly sequential
# steps within a single job to avoid crashing the shared builder), and Node's
# default multi-GB heap lets eslint/Rollup grow far beyond what they need.
# 1536 MB is most of the 1800m buildx memory cap, leaving headroom for non-heap
# RSS while still forcing earlier GC than the unlimited default.
ENV NODE_OPTIONS="--max-old-space-size=1536"
# Configure pnpm store globally so it doesn't need to be set in each stage
RUN pnpm config set store-dir /pnpm-store
# ============================================================================
# Stage: base-puppeteer
# Heavy base with bundled Chromium — used only for QUnit tests
# ============================================================================
FROM adguard/puppeteer-runner:22.21.1--24.35.0--0 AS base-puppeteer
SHELL ["/bin/bash", "-lc"]
WORKDIR /scriptlets
ENV PNPM_STORE=/pnpm-store
# Smaller than above so Chromium has more physical RAM available (its RSS
# can be significant when running many parallel browser tests)
# with 1800m buildx memory cap.
ENV NODE_OPTIONS="--max-old-space-size=1024"
# Point puppeteer to the cache directory where Chrome is pre-installed in the Docker image
ENV PUPPETEER_CACHE_DIR=/home/pptruser/.cache/puppeteer
# Configure pnpm store globally so it doesn't need to be set in each stage
RUN pnpm config set store-dir /pnpm-store
# ============================================================================
# Stage: deps
# Cached until package.json/pnpm-lock.yaml changes
# ============================================================================
FROM base AS deps
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true pnpm install \
--frozen-lockfile \
--prefer-offline
# ============================================================================
# Stage: deps-puppeteer
# Dependencies installed on the puppeteer base (Chromium download not skipped)
# ============================================================================
FROM base-puppeteer AS deps-puppeteer
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm-puppeteer \
pnpm install \
--frozen-lockfile \
--prefer-offline
# ============================================================================
# Stage: source
# Cached until source code changes
# Has source + node_modules
# ============================================================================
FROM deps AS source
COPY . /scriptlets
# ============================================================================
# Stage: source-puppeteer
# Source + deps on the puppeteer base — parent of browser-based test stages
# ============================================================================
FROM deps-puppeteer AS source-puppeteer
COPY . /scriptlets
# ============================================================================
# Stage: test-output
# Aggregate of all granular verification stages. Consumed by the shared
# publish-release.yml (`--target test-output`). Composing from the granular
# outputs (the same stages ci.yml builds individually) gives the check set a
# single definition and avoids re-executing lint + tests from scratch.
# BuildKit resolves named stages regardless of position, so the COPY
# directives below can reference stages defined later in this file.
# ============================================================================
FROM scratch AS test-output
COPY --from=lint /out/ /
COPY --from=test-vitest /out/ /
COPY --from=test-qunit /out/ /
COPY --from=test-smoke /out/ /
# ============================================================================
# Stage: dist
# Builds the library dist/ once; shared by the build and test-smoke stages
# so the library is not built multiple times per CI run (QUnit keeps its own
# build on the puppeteer base).
# ============================================================================
FROM source AS dist
ARG BUILD_RUN_ID
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
pnpm build
# ============================================================================
# Stage: build
# Packs the pre-built dist/ into a tarball.
# ============================================================================
FROM dist AS build
ARG BUILD_RUN_ID
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
pnpm tgz && \
mkdir -p /out && \
mv scriptlets.tgz /out/
# build-output exports scriptlets.tgz at the root, so
# `docker build --target build-output --output ./artifacts` yields
# `artifacts/scriptlets.tgz` (no artifacts/artifacts/ double-nesting).
FROM scratch AS build-output
COPY --from=build /out/ /
# ============================================================================
# Stage: wiki
# Builds documentation (wiki)
# ============================================================================
FROM source AS wiki
ARG BUILD_RUN_ID
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
pnpm wiki && \
mkdir -p /out && \
cp -r wiki /out/wiki
FROM scratch AS wiki-output
COPY --from=wiki /out/ /
# ============================================================================
# Stage: lint
# Runs all linting
# ============================================================================
FROM source AS lint
ARG BUILD_RUN_ID
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
pnpm lint && \
mkdir -p /out && \
touch /out/lint.txt
FROM scratch AS lint-output
COPY --from=lint /out/ /
# ============================================================================
# Stage: test-qunit
# Runs QUnit tests
# ============================================================================
FROM source-puppeteer AS test-qunit
ARG BUILD_RUN_ID
# Build dist + test bundles in a separate RUN (separate Node process) so the
# build's memory is released before Chrome is launched, reducing peak RSS
# under the CI builder's memory cap.
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm-puppeteer \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
pnpm test:qunit:build
# Run only the browser tests in a fresh process. The runner closes each test
# page itself (see tests/index.js), so Chrome RSS stays bounded.
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm-puppeteer \
mkdir -p /out && \
touch /out/qunit.txt && \
pnpm test:qunit:run
FROM scratch AS test-qunit-output
COPY --from=test-qunit /out/ /
# ============================================================================
# Stage: test-vitest
# Runs Vitest tests
# ============================================================================
FROM source AS test-vitest
ARG BUILD_RUN_ID
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
mkdir -p /out && \
touch /out/vitest.txt && \
pnpm test:vitest
FROM scratch AS test-vitest-output
COPY --from=test-vitest /out/ /
# ============================================================================
# Stage: test-smoke
# Runs smoke tests against the pre-built tarball from the build stage, avoiding
# a redundant `pnpm build` inside test.sh.
# ============================================================================
FROM source AS test-smoke
ARG BUILD_RUN_ID
COPY --from=build /out/scriptlets.tgz /tmp/scriptlets.tgz
# Smoke tests run in Node (jsdom-level); Chromium is never launched. Setting
# PUPPETEER_SKIP_CHROMIUM_DOWNLOAD here as well guarantees no Chrome install
# is triggered while the smoke suite runs `pnpm install` in the packed-package
# sandbox — saving RAM and time on the shared builder.
# SMOKE_TGZ_PATH tells test.sh to use the pre-built tarball instead of
# stamping + building + packing locally.
RUN --mount=type=cache,target=/pnpm-store,id=scriptlets-pnpm \
echo "${BUILD_RUN_ID}" > /tmp/.build-run-id && \
mkdir -p /out && \
touch /out/smoke.txt && \
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
SMOKE_TGZ_PATH=/tmp/scriptlets.tgz pnpm test:smoke
FROM scratch AS test-smoke-output
COPY --from=test-smoke /out/ /