@intentius/chant-lexicon-docker 0.124.20 → 0.124.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/generate.d.ts.map +1 -1
- package/dist/dockerfile-order.d.ts +13 -0
- package/dist/dockerfile-order.d.ts.map +1 -0
- package/dist/generated/index.d.ts +121 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/import/adapter.d.ts.map +1 -1
- package/dist/import/parser.d.ts +23 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/integrity.json +17 -8
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-lineage.d.ts.map +1 -1
- package/dist/lint/post-synth/add-url-checksum.d.ts +9 -0
- package/dist/lint/post-synth/add-url-checksum.d.ts.map +1 -0
- package/dist/lint/post-synth/apt-update-alone.d.ts +10 -0
- package/dist/lint/post-synth/apt-update-alone.d.ts.map +1 -0
- package/dist/lint/post-synth/cache-busting-copy.d.ts +11 -0
- package/dist/lint/post-synth/cache-busting-copy.d.ts.map +1 -0
- package/dist/lint/post-synth/copy-from-stage.d.ts +10 -0
- package/dist/lint/post-synth/copy-from-stage.d.ts.map +1 -0
- package/dist/lint/post-synth/docker-helpers.d.ts +35 -0
- package/dist/lint/post-synth/docker-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/no-root-user.d.ts +3 -2
- package/dist/lint/post-synth/no-root-user.d.ts.map +1 -1
- package/dist/lint/post-synth/relative-workdir.d.ts +10 -0
- package/dist/lint/post-synth/relative-workdir.d.ts.map +1 -0
- package/dist/lint/post-synth/repeated-cmd.d.ts +9 -0
- package/dist/lint/post-synth/repeated-cmd.d.ts.map +1 -0
- package/dist/lint/post-synth/root-after-user.d.ts +10 -0
- package/dist/lint/post-synth/root-after-user.d.ts.map +1 -0
- package/dist/lint/post-synth/unused-global-arg.d.ts +10 -0
- package/dist/lint/post-synth/unused-global-arg.d.ts.map +1 -0
- package/dist/lint/rules/index.d.ts +1 -0
- package/dist/lint/rules/index.d.ts.map +1 -1
- package/dist/lint/rules/per-kind-order.d.ts +15 -0
- package/dist/lint/rules/per-kind-order.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/meta.json +6 -0
- package/dist/okf/index.md +10 -1
- package/dist/okf/rules/DKRD012.md +2 -2
- package/dist/okf/rules/DKRD013.md +11 -0
- package/dist/okf/rules/DKRD014.md +11 -0
- package/dist/okf/rules/DKRD015.md +11 -0
- package/dist/okf/rules/DKRD016.md +11 -0
- package/dist/okf/rules/DKRD017.md +11 -0
- package/dist/okf/rules/DKRD018.md +11 -0
- package/dist/okf/rules/DKRD019.md +11 -0
- package/dist/okf/rules/DKRD020.md +11 -0
- package/dist/okf/rules/DKRS002.md +15 -0
- package/dist/okf/types/Dockerfile.md +4 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/rules/add-url-checksum.ts +38 -0
- package/dist/rules/apt-update-alone.ts +39 -0
- package/dist/rules/cache-busting-copy.ts +64 -0
- package/dist/rules/copy-from-stage.ts +54 -0
- package/dist/rules/docker-helpers.ts +80 -0
- package/dist/rules/no-root-user.ts +19 -17
- package/dist/rules/per-kind-order.ts +130 -0
- package/dist/rules/relative-workdir.ts +38 -0
- package/dist/rules/repeated-cmd.ts +35 -0
- package/dist/rules/root-after-user.ts +44 -0
- package/dist/rules/unused-global-arg.ts +38 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/skills/chant-docker-patterns.md +91 -22
- package/dist/skills/chant-docker.md +42 -16
- package/dist/spec/parse-engine.d.ts +9 -0
- package/dist/spec/parse-engine.d.ts.map +1 -1
- package/dist/types/index.d.ts +81 -0
- package/package.json +3 -3
- package/src/codegen/__snapshots__/okf.test.ts.snap +155 -4
- package/src/codegen/docs.ts +14 -0
- package/src/codegen/generate.ts +77 -19
- package/src/dockerfile-order.ts +20 -0
- package/src/docs-examples.test.ts +141 -0
- package/src/generated/index.d.ts +81 -0
- package/src/generated/index.ts +117 -0
- package/src/generated/lexicon-docker.json +6 -0
- package/src/import/adapter.ts +8 -2
- package/src/import/generator.ts +49 -33
- package/src/import/parser.ts +82 -13
- package/src/import/roundtrip.test.ts +105 -0
- package/src/lint/audit-catalog.ts +9 -1
- package/src/lint/audit-lineage.ts +14 -0
- package/src/lint/post-synth/add-url-checksum.ts +38 -0
- package/src/lint/post-synth/apt-update-alone.ts +39 -0
- package/src/lint/post-synth/cache-busting-copy.ts +64 -0
- package/src/lint/post-synth/copy-from-stage.ts +54 -0
- package/src/lint/post-synth/docker-helpers.ts +80 -0
- package/src/lint/post-synth/index.ts +16 -0
- package/src/lint/post-synth/no-root-user.ts +19 -17
- package/src/lint/post-synth/post-synth.test.ts +149 -0
- package/src/lint/post-synth/relative-workdir.ts +38 -0
- package/src/lint/post-synth/repeated-cmd.ts +35 -0
- package/src/lint/post-synth/root-after-user.ts +44 -0
- package/src/lint/post-synth/unused-global-arg.ts +38 -0
- package/src/lint/rules/index.ts +1 -0
- package/src/lint/rules/per-kind-order.ts +130 -0
- package/src/lint/rules/rules.test.ts +88 -0
- package/src/plugin.test.ts +4 -0
- package/src/plugin.ts +2 -1
- package/src/serializer.test.ts +112 -0
- package/src/serializer.ts +58 -11
- package/src/skills/chant-docker-patterns.md +91 -22
- package/src/skills/chant-docker.md +42 -16
- package/src/spec/parse-engine.ts +17 -5
|
@@ -23,8 +23,17 @@ okf_version: '0.2'
|
|
|
23
23
|
* [DKRD003](/rules/DKRD003.md) - Service exposes SSH port (22) externally — this is a security risk
|
|
24
24
|
* [DKRD010](/rules/DKRD010.md) - apt-get install without --no-install-recommends adds unnecessary packages
|
|
25
25
|
* [DKRD011](/rules/DKRD011.md) - Prefer COPY over ADD when not fetching URLs or extracting archives
|
|
26
|
-
* [DKRD012](/rules/DKRD012.md) - Dockerfile has no USER instruction — container runs as root
|
|
26
|
+
* [DKRD012](/rules/DKRD012.md) - Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
|
|
27
|
+
* [DKRD013](/rules/DKRD013.md) - Whole build context copied before a dependency install — every source change re-runs the install
|
|
28
|
+
* [DKRD014](/rules/DKRD014.md) - RUN needs root but comes after USER switched to a non-root user
|
|
29
|
+
* [DKRD015](/rules/DKRD015.md) - More than one CMD or ENTRYPOINT in a stage — only the last one takes effect
|
|
30
|
+
* [DKRD016](/rules/DKRD016.md) - COPY --from names a stage that is not defined before it
|
|
31
|
+
* [DKRD017](/rules/DKRD017.md) - ARG before the first FROM is not used by any FROM or stage
|
|
32
|
+
* [DKRD018](/rules/DKRD018.md) - Relative WORKDIR before any absolute WORKDIR in the stage
|
|
33
|
+
* [DKRD019](/rules/DKRD019.md) - ADD fetches a remote URL without --checksum
|
|
34
|
+
* [DKRD020](/rules/DKRD020.md) - apt-get update in a different RUN from apt-get install — the install can use a stale package index
|
|
27
35
|
* [DKRS001](/rules/DKRS001.md) - No Latest Tag
|
|
36
|
+
* [DKRS002](/rules/DKRS002.md) - Per-kind Dockerfile fields written in a different order
|
|
28
37
|
",
|
|
29
38
|
"path": "index.md",
|
|
30
39
|
},
|
|
@@ -119,14 +128,14 @@ Prefer COPY over ADD when not fetching URLs or extracting archives
|
|
|
119
128
|
"content": "---
|
|
120
129
|
type: post-synth-check
|
|
121
130
|
title: DKRD012
|
|
122
|
-
description: Dockerfile has no USER instruction — container runs as root
|
|
131
|
+
description: Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
|
|
123
132
|
id: DKRD012
|
|
124
133
|
severity: error
|
|
125
134
|
category: post-synth
|
|
126
135
|
lexicon: docker
|
|
127
136
|
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
128
137
|
---
|
|
129
|
-
Dockerfile has no USER instruction — container runs as root
|
|
138
|
+
Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
|
|
130
139
|
|
|
131
140
|
## Applies to
|
|
132
141
|
|
|
@@ -136,6 +145,126 @@ Dockerfile has no USER instruction — container runs as root
|
|
|
136
145
|
},
|
|
137
146
|
{
|
|
138
147
|
"content": "---
|
|
148
|
+
type: post-synth-check
|
|
149
|
+
title: DKRD013
|
|
150
|
+
description: Whole build context copied before a dependency install — every source change re-runs the install
|
|
151
|
+
id: DKRD013
|
|
152
|
+
severity: error
|
|
153
|
+
category: post-synth
|
|
154
|
+
lexicon: docker
|
|
155
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
156
|
+
---
|
|
157
|
+
Whole build context copied before a dependency install — every source change re-runs the install
|
|
158
|
+
",
|
|
159
|
+
"path": "rules/DKRD013.md",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"content": "---
|
|
163
|
+
type: post-synth-check
|
|
164
|
+
title: DKRD014
|
|
165
|
+
description: RUN needs root but comes after USER switched to a non-root user
|
|
166
|
+
id: DKRD014
|
|
167
|
+
severity: error
|
|
168
|
+
category: post-synth
|
|
169
|
+
lexicon: docker
|
|
170
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
171
|
+
---
|
|
172
|
+
RUN needs root but comes after USER switched to a non-root user
|
|
173
|
+
",
|
|
174
|
+
"path": "rules/DKRD014.md",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"content": "---
|
|
178
|
+
type: post-synth-check
|
|
179
|
+
title: DKRD015
|
|
180
|
+
description: More than one CMD or ENTRYPOINT in a stage — only the last one takes effect
|
|
181
|
+
id: DKRD015
|
|
182
|
+
severity: error
|
|
183
|
+
category: post-synth
|
|
184
|
+
lexicon: docker
|
|
185
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
186
|
+
---
|
|
187
|
+
More than one CMD or ENTRYPOINT in a stage — only the last one takes effect
|
|
188
|
+
",
|
|
189
|
+
"path": "rules/DKRD015.md",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"content": "---
|
|
193
|
+
type: post-synth-check
|
|
194
|
+
title: DKRD016
|
|
195
|
+
description: COPY --from names a stage that is not defined before it
|
|
196
|
+
id: DKRD016
|
|
197
|
+
severity: error
|
|
198
|
+
category: post-synth
|
|
199
|
+
lexicon: docker
|
|
200
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
201
|
+
---
|
|
202
|
+
COPY --from names a stage that is not defined before it
|
|
203
|
+
",
|
|
204
|
+
"path": "rules/DKRD016.md",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"content": "---
|
|
208
|
+
type: post-synth-check
|
|
209
|
+
title: DKRD017
|
|
210
|
+
description: ARG before the first FROM is not used by any FROM or stage
|
|
211
|
+
id: DKRD017
|
|
212
|
+
severity: error
|
|
213
|
+
category: post-synth
|
|
214
|
+
lexicon: docker
|
|
215
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
216
|
+
---
|
|
217
|
+
ARG before the first FROM is not used by any FROM or stage
|
|
218
|
+
",
|
|
219
|
+
"path": "rules/DKRD017.md",
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"content": "---
|
|
223
|
+
type: post-synth-check
|
|
224
|
+
title: DKRD018
|
|
225
|
+
description: Relative WORKDIR before any absolute WORKDIR in the stage
|
|
226
|
+
id: DKRD018
|
|
227
|
+
severity: error
|
|
228
|
+
category: post-synth
|
|
229
|
+
lexicon: docker
|
|
230
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
231
|
+
---
|
|
232
|
+
Relative WORKDIR before any absolute WORKDIR in the stage
|
|
233
|
+
",
|
|
234
|
+
"path": "rules/DKRD018.md",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"content": "---
|
|
238
|
+
type: post-synth-check
|
|
239
|
+
title: DKRD019
|
|
240
|
+
description: ADD fetches a remote URL without --checksum
|
|
241
|
+
id: DKRD019
|
|
242
|
+
severity: error
|
|
243
|
+
category: post-synth
|
|
244
|
+
lexicon: docker
|
|
245
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
246
|
+
---
|
|
247
|
+
ADD fetches a remote URL without --checksum
|
|
248
|
+
",
|
|
249
|
+
"path": "rules/DKRD019.md",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"content": "---
|
|
253
|
+
type: post-synth-check
|
|
254
|
+
title: DKRD020
|
|
255
|
+
description: apt-get update in a different RUN from apt-get install — the install can use a stale package index
|
|
256
|
+
id: DKRD020
|
|
257
|
+
severity: error
|
|
258
|
+
category: post-synth
|
|
259
|
+
lexicon: docker
|
|
260
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
261
|
+
---
|
|
262
|
+
apt-get update in a different RUN from apt-get install — the install can use a stale package index
|
|
263
|
+
",
|
|
264
|
+
"path": "rules/DKRD020.md",
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"content": "---
|
|
139
268
|
type: lint-rule
|
|
140
269
|
title: DKRS001
|
|
141
270
|
description: No Latest Tag
|
|
@@ -155,6 +284,25 @@ No Latest Tag
|
|
|
155
284
|
},
|
|
156
285
|
{
|
|
157
286
|
"content": "---
|
|
287
|
+
type: lint-rule
|
|
288
|
+
title: DKRS002
|
|
289
|
+
description: Per-kind Dockerfile fields written in a different order
|
|
290
|
+
id: DKRS002
|
|
291
|
+
severity: warning
|
|
292
|
+
category: correctness
|
|
293
|
+
lexicon: docker
|
|
294
|
+
docs: https://intentius.io/chant/lexicons/docker/rules/
|
|
295
|
+
---
|
|
296
|
+
Per-kind Dockerfile fields written in a different order
|
|
297
|
+
|
|
298
|
+
## Applies to
|
|
299
|
+
|
|
300
|
+
- [Dockerfile](/types/Dockerfile.md)
|
|
301
|
+
",
|
|
302
|
+
"path": "rules/DKRS002.md",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"content": "---
|
|
158
306
|
type: resource-type
|
|
159
307
|
title: DockerConfig
|
|
160
308
|
description: A config definition in Docker Compose
|
|
@@ -201,10 +349,13 @@ A Dockerfile definition with ordered build instructions
|
|
|
201
349
|
- \`entrypoint\`: Set the entrypoint executable
|
|
202
350
|
- \`cmd\`: Default command arguments
|
|
203
351
|
- \`healthcheck\`: Health check instruction
|
|
352
|
+
- \`globalArgs\`: ARG instructions written before the first FROM
|
|
353
|
+
- \`steps\`: Instructions after FROM, written in the order given; one instruction per step
|
|
204
354
|
|
|
205
355
|
## Governed by
|
|
206
356
|
|
|
207
|
-
- [DKRD012](/rules/DKRD012.md): Dockerfile has no USER instruction — container runs as root
|
|
357
|
+
- [DKRD012](/rules/DKRD012.md): Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
|
|
358
|
+
- [DKRS002](/rules/DKRS002.md): Per-kind Dockerfile fields written in a different order
|
|
208
359
|
",
|
|
209
360
|
"path": "types/Dockerfile.md",
|
|
210
361
|
},
|
package/src/codegen/docs.ts
CHANGED
|
@@ -133,6 +133,19 @@ chant build src --lexicon docker -o docker-compose.yml
|
|
|
133
133
|
chant build src --lexicon aws -o template.json
|
|
134
134
|
\`\`\``;
|
|
135
135
|
|
|
136
|
+
// "Optional: hand this page to your coding agent", shown under the overview's
|
|
137
|
+
// title. The Dockerfile shape is the ordered \`steps\` list from chant #3926.
|
|
138
|
+
const prompt = `Read https://intentius.io/chant/lexicons/docker/ and https://intentius.io/chant/lexicons/docker/dockerfiles/ first.
|
|
139
|
+
Bring this project's Docker files into chant TypeScript under src/.
|
|
140
|
+
Import each existing file. \`-o\` names a directory, and each import writes main.ts in it: \`chant import --lexicon docker docker-compose.yml -o src/compose/\`, and \`chant import --lexicon docker Dockerfile -o src/<name>/\` for each Dockerfile.
|
|
141
|
+
An imported Dockerfile is exported as \`app\`. Rename each export after its image, since the export name sets the output file (Dockerfile.<export>), and point the Compose service's \`build.dockerfile\` at that export (\`dockerfile: webImage\`) instead of the old file name.
|
|
142
|
+
Write every Dockerfile stage as an ordered \`steps\` list, one instruction per step, with FROM as the stage's \`from\` and ARGs before the first FROM in \`globalArgs\`:
|
|
143
|
+
steps: [{ workdir: "/app" }, { copy: "package*.json ./" }, { run: "npm ci" }, { copy: ". ." }, { user: "node" }, { cmd: ["node", "dist/index.js"] }]
|
|
144
|
+
Where two Dockerfiles repeat a stage or a run of steps, export it once as a const (a \`DockerfileStage\` or a \`DockerfileStep[]\`) from its own module and import it in both. Spread imported consts, not function results; a Dockerfile that needs parameters is a \`Composite\`.
|
|
145
|
+
Run \`chant build src --lexicon docker -o build/docker-compose.yml\` (Dockerfiles are written beside it) and compare with the original files, then \`chant lint src\`. Run \`chant lint src --fix\` for DKRS002 (per-kind fields to \`steps\`, then reorder the steps it writes), fix every other finding by hand, and repeat until lint is clean.
|
|
146
|
+
Report the generated docker-compose.yml and each Dockerfile.<name>, and any finding you left and why.
|
|
147
|
+
Never push an image, run \`docker compose up\` against anything but the local Docker daemon, or change files outside this project.`;
|
|
148
|
+
|
|
136
149
|
export async function generateDocs(opts?: { verbose?: boolean }): Promise<void> {
|
|
137
150
|
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
138
151
|
|
|
@@ -145,6 +158,7 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
|
|
|
145
158
|
basePath: "/chant/lexicons/docker/",
|
|
146
159
|
overview,
|
|
147
160
|
outputFormat,
|
|
161
|
+
prompt,
|
|
148
162
|
};
|
|
149
163
|
|
|
150
164
|
const result = docsPipeline(config);
|
package/src/codegen/generate.ts
CHANGED
|
@@ -10,8 +10,9 @@ import { join } from "path";
|
|
|
10
10
|
import { generateComposePipeline } from "./generate-compose";
|
|
11
11
|
import { generateDockerfilePipeline } from "./generate-dockerfile";
|
|
12
12
|
import { entityTypeToTsName } from "./naming";
|
|
13
|
+
import { PER_KIND_ORDER } from "../dockerfile-order";
|
|
13
14
|
import type { ComposeParseResult } from "../spec/parse-compose";
|
|
14
|
-
import type { DockerfileParseResult } from "../spec/parse-engine";
|
|
15
|
+
import type { DockerfileParseResult, DockerfileInstruction } from "../spec/parse-engine";
|
|
15
16
|
|
|
16
17
|
export interface DockerGenerateResult {
|
|
17
18
|
resources: number;
|
|
@@ -72,9 +73,13 @@ function generateLexiconJSON(compose: ComposeParseResult[], dockerfile: Dockerfi
|
|
|
72
73
|
resourceType: dockerfile.typeName,
|
|
73
74
|
kind: "resource",
|
|
74
75
|
description: dockerfile.description ?? "",
|
|
75
|
-
properties:
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
properties: {
|
|
77
|
+
...Object.fromEntries(
|
|
78
|
+
dockerfile.instructions.filter((i) => !i.stepOnly).map((i) => [i.name, { description: i.description ?? "" }]),
|
|
79
|
+
),
|
|
80
|
+
globalArgs: { description: "ARG instructions written before the first FROM" },
|
|
81
|
+
steps: { description: "Instructions after FROM, written in the order given; one instruction per step" },
|
|
82
|
+
},
|
|
78
83
|
};
|
|
79
84
|
|
|
80
85
|
return JSON.stringify(entries, null, 2);
|
|
@@ -100,21 +105,7 @@ function generateTypesDTS(compose: ComposeParseResult[], dockerfile: DockerfileP
|
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
const dfName = entityTypeToTsName(dockerfile.typeName);
|
|
103
|
-
lines.push(
|
|
104
|
-
lines.push(` from: string;`);
|
|
105
|
-
lines.push(` as?: string;`);
|
|
106
|
-
for (const i of dockerfile.instructions.filter((i) => i.name !== "from")) {
|
|
107
|
-
lines.push(` ${i.name}?: ${i.multi ? "string[]" : "string"};`);
|
|
108
|
-
}
|
|
109
|
-
lines.push(`}`);
|
|
110
|
-
lines.push(`export interface DockerfileProps {`);
|
|
111
|
-
lines.push(` name?: string;`);
|
|
112
|
-
lines.push(` from?: string;`);
|
|
113
|
-
lines.push(` stages?: DockerfileStage[];`);
|
|
114
|
-
for (const i of dockerfile.instructions.filter((i) => i.name !== "from")) {
|
|
115
|
-
lines.push(` ${i.name}?: ${i.multi ? "string[]" : "string"};`);
|
|
116
|
-
}
|
|
117
|
-
lines.push(`}`);
|
|
108
|
+
lines.push(...dockerfileTypeLines(dockerfile));
|
|
118
109
|
lines.push(`export declare const ${dfName}: new (props?: DockerfileProps) => Declarable;`);
|
|
119
110
|
lines.push("");
|
|
120
111
|
|
|
@@ -137,10 +128,77 @@ function generateIndexTS(compose: ComposeParseResult[], dockerfile: DockerfilePa
|
|
|
137
128
|
const dfName = entityTypeToTsName(dockerfile.typeName);
|
|
138
129
|
lines.push(`export const ${dfName} = createResource("${dockerfile.typeName}", "docker", {});`);
|
|
139
130
|
lines.push("");
|
|
131
|
+
// The Dockerfile prop types are exported from here too (not only from
|
|
132
|
+
// index.d.ts, which index.ts shadows) so a module can type a shared stage
|
|
133
|
+
// or step list: `export const install: DockerfileStep[] = [...]`.
|
|
134
|
+
lines.push(...dockerfileTypeLines(dockerfile));
|
|
135
|
+
lines.push("");
|
|
140
136
|
|
|
141
137
|
return lines.join("\n");
|
|
142
138
|
}
|
|
143
139
|
|
|
140
|
+
/**
|
|
141
|
+
* The Dockerfile prop types: one `DockerfileStep` variant per instruction,
|
|
142
|
+
* the stage, and the props. The per-kind fields keep the instructions they
|
|
143
|
+
* always had; SHELL, STOPSIGNAL and ONBUILD are steps only.
|
|
144
|
+
*/
|
|
145
|
+
function dockerfileTypeLines(dockerfile: DockerfileParseResult): string[] {
|
|
146
|
+
const lines: string[] = [];
|
|
147
|
+
const stepInstructions = dockerfile.instructions.filter((i) => i.name !== "from");
|
|
148
|
+
const perKind = stepInstructions.filter((i) => !i.stepOnly);
|
|
149
|
+
const stepValue = (i: DockerfileInstruction): string =>
|
|
150
|
+
["string", ...(i.numeric ? ["number"] : []), ...(i.execForm ? ["string[]"] : [])].join(" | ");
|
|
151
|
+
const fixed = PER_KIND_ORDER.map((k) => k.toUpperCase()).join(", ");
|
|
152
|
+
|
|
153
|
+
lines.push(`/** The Dockerfile instructions a step can name. FROM is the stage's own \`from\` field. */`);
|
|
154
|
+
lines.push(`export type DockerfileInstructionName = ${stepInstructions.map((i) => JSON.stringify(i.name)).join(" | ")};`);
|
|
155
|
+
lines.push(`type DockerfileStepOf<K extends DockerfileInstructionName, V> = { [P in K]: V } & { [P in Exclude<DockerfileInstructionName, K>]?: never };`);
|
|
156
|
+
lines.push(`/**`);
|
|
157
|
+
lines.push(` * One Dockerfile instruction, named by its single key: \`{ run: "npm ci" }\` is \`RUN npm ci\`.`);
|
|
158
|
+
lines.push(` * A string[] value (run, cmd, entrypoint, shell) is written in JSON exec form.`);
|
|
159
|
+
lines.push(` */`);
|
|
160
|
+
lines.push(`export type DockerfileStep =`);
|
|
161
|
+
for (const i of stepInstructions) {
|
|
162
|
+
lines.push(` /** ${i.name.toUpperCase()}: ${i.description ?? ""} */`);
|
|
163
|
+
lines.push(` | DockerfileStepOf<${JSON.stringify(i.name)}, ${stepValue(i)}>`);
|
|
164
|
+
}
|
|
165
|
+
lines[lines.length - 1] += ";";
|
|
166
|
+
|
|
167
|
+
const fields = (): void => {
|
|
168
|
+
lines.push(` /** Instructions after FROM, written exactly in this order. Can't be combined with the per-kind fields. */`);
|
|
169
|
+
lines.push(` steps?: DockerfileStep[];`);
|
|
170
|
+
for (const i of perKind) {
|
|
171
|
+
lines.push(` /** ${i.name.toUpperCase()} as a per-kind field, written in the fixed order. Use \`steps\` to choose the order. */`);
|
|
172
|
+
lines.push(` ${i.name}?: ${i.multi ? "string[]" : "string"};`);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const fixedDoc = ` * Without \`steps\`, the per-kind fields are written in a fixed order: ${fixed}.`;
|
|
176
|
+
|
|
177
|
+
lines.push(`/**`);
|
|
178
|
+
lines.push(` * One build stage: FROM, then its instructions.`);
|
|
179
|
+
lines.push(fixedDoc);
|
|
180
|
+
lines.push(` */`);
|
|
181
|
+
lines.push(`export interface DockerfileStage {`);
|
|
182
|
+
lines.push(` from: string;`);
|
|
183
|
+
lines.push(` as?: string;`);
|
|
184
|
+
fields();
|
|
185
|
+
lines.push(`}`);
|
|
186
|
+
lines.push(`/**`);
|
|
187
|
+
lines.push(` * A Dockerfile: \`stages\` for a multi-stage build, or \`from\` and the stage fields for one stage.`);
|
|
188
|
+
lines.push(fixedDoc);
|
|
189
|
+
lines.push(` */`);
|
|
190
|
+
lines.push(`export interface DockerfileProps {`);
|
|
191
|
+
lines.push(` name?: string;`);
|
|
192
|
+
lines.push(` /** ARG instructions written before the first FROM, e.g. \`["NODE_VERSION=20"]\`. */`);
|
|
193
|
+
lines.push(` globalArgs?: string[];`);
|
|
194
|
+
lines.push(` from?: string;`);
|
|
195
|
+
lines.push(` as?: string;`);
|
|
196
|
+
lines.push(` stages?: DockerfileStage[];`);
|
|
197
|
+
fields();
|
|
198
|
+
lines.push(`}`);
|
|
199
|
+
return lines;
|
|
200
|
+
}
|
|
201
|
+
|
|
144
202
|
/**
|
|
145
203
|
* Write generated artifacts to disk under baseDir/src/generated/.
|
|
146
204
|
*/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The order a Dockerfile stage's per-kind fields (`run`, `copy`, `user`, ...)
|
|
3
|
+
* are written in when the stage has no `steps`. It never changes, so a
|
|
4
|
+
* Dockerfile declared with per-kind fields builds the same output it always
|
|
5
|
+
* has; `steps` is how a stage controls its own order.
|
|
6
|
+
*/
|
|
7
|
+
export const PER_KIND_ORDER = [
|
|
8
|
+
"arg", "env", "workdir", "user", "run", "copy", "add",
|
|
9
|
+
"expose", "volume", "label", "entrypoint", "cmd", "healthcheck",
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export type PerKindField = (typeof PER_KIND_ORDER)[number];
|
|
13
|
+
|
|
14
|
+
/** The step keys whose array value is written in JSON exec form. */
|
|
15
|
+
export const EXEC_FORM_STEPS: ReadonlySet<string> = new Set(["run", "cmd", "entrypoint", "shell"]);
|
|
16
|
+
|
|
17
|
+
/** Every instruction a step can name. FROM is the stage's own field. */
|
|
18
|
+
export const STEP_INSTRUCTIONS: ReadonlySet<string> = new Set([
|
|
19
|
+
...PER_KIND_ORDER, "shell", "stopsignal", "onbuild",
|
|
20
|
+
]);
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Dockerfile examples in the docs and skills build, and build what the
|
|
3
|
+
* page says they do.
|
|
4
|
+
*
|
|
5
|
+
* - A ```typescript block with no title that declares a Dockerfile is run
|
|
6
|
+
* and serialized. When the next code block is an untitled ```dockerfile
|
|
7
|
+
* block, the built file must equal it.
|
|
8
|
+
* - A titled ```typescript block (`title="src/web.ts"`) must equal that file
|
|
9
|
+
* in examples/dockerfile-sharing, and a titled ```dockerfile block
|
|
10
|
+
* (`title="Dockerfile.web"`) must equal that file from building the
|
|
11
|
+
* example.
|
|
12
|
+
* - In importing.mdx, importing the ```dockerfile block titled "Dockerfile"
|
|
13
|
+
* must give the ```typescript block that follows it.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, test, expect } from "vitest";
|
|
17
|
+
import { readFileSync } from "fs";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
import * as ts from "typescript";
|
|
20
|
+
import { build } from "@intentius/chant/build";
|
|
21
|
+
import * as chant from "@intentius/chant";
|
|
22
|
+
import type { Declarable } from "@intentius/chant/declarable";
|
|
23
|
+
import * as lexicon from "./index";
|
|
24
|
+
import { dockerSerializer } from "./serializer";
|
|
25
|
+
import { DockerTemplateGenerator, DockerTemplateParser } from "./import/adapter";
|
|
26
|
+
|
|
27
|
+
const root = join(import.meta.dirname, "..");
|
|
28
|
+
const sharingExample = join(root, "examples", "dockerfile-sharing");
|
|
29
|
+
|
|
30
|
+
interface Block {
|
|
31
|
+
lang: string;
|
|
32
|
+
title?: string;
|
|
33
|
+
code: string;
|
|
34
|
+
/** The prose between the previous code block and this one. */
|
|
35
|
+
before: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function blocks(file: string): Block[] {
|
|
39
|
+
const text = readFileSync(join(root, file), "utf8");
|
|
40
|
+
const out: Block[] = [];
|
|
41
|
+
let last = 0;
|
|
42
|
+
for (const m of text.matchAll(/^```(\w+)([^\n]*)\n([\s\S]*?)^```$/gm)) {
|
|
43
|
+
const title = m[2]!.match(/title="([^"]+)"/)?.[1];
|
|
44
|
+
out.push({ lang: m[1]!, ...(title ? { title } : {}), code: m[3]!, before: text.slice(last, m.index) });
|
|
45
|
+
last = m.index! + m[0].length;
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Run one TypeScript block as a module and serialize the Dockerfiles it
|
|
52
|
+
* exports. A block whose first line is a path comment (`// src/web.ts`) is
|
|
53
|
+
* one module of a multi-file example: `modules` holds the exports of the
|
|
54
|
+
* page's earlier modules, by path, for its relative imports.
|
|
55
|
+
*/
|
|
56
|
+
function buildBlock(code: string, pageModules: Map<string, Record<string, unknown>> = new Map()): Record<string, string> {
|
|
57
|
+
const js = ts.transpileModule(code, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 } }).outputText;
|
|
58
|
+
const modules: Record<string, unknown> = { "@intentius/chant-lexicon-docker": lexicon, "@intentius/chant": chant };
|
|
59
|
+
const path = code.match(/^\/\/ (src\/\S+)\.ts\s*$/m)?.[1];
|
|
60
|
+
const req = (name: string): unknown => {
|
|
61
|
+
if (name.startsWith("./") && path) {
|
|
62
|
+
const target = join(path, "..", name).replace(/\\/g, "/");
|
|
63
|
+
const found = pageModules.get(target);
|
|
64
|
+
if (found) return found;
|
|
65
|
+
}
|
|
66
|
+
if (!(name in modules)) throw new Error(`docs example imports ${name}, which this test does not provide`);
|
|
67
|
+
return modules[name];
|
|
68
|
+
};
|
|
69
|
+
const mod = { exports: {} as Record<string, unknown> };
|
|
70
|
+
// Snippets that leave out the import line still see the lexicon's exports.
|
|
71
|
+
const globals = Object.keys(lexicon).filter((k) => /^[A-Za-z_$][\w$]*$/.test(k));
|
|
72
|
+
new Function("require", "module", "exports", ...globals, js)(req, mod, mod.exports, ...globals.map((k) => (lexicon as Record<string, unknown>)[k]));
|
|
73
|
+
if (path) pageModules.set(path, mod.exports);
|
|
74
|
+
const entities = new Map<string, Declarable>();
|
|
75
|
+
for (const [name, value] of Object.entries(mod.exports)) {
|
|
76
|
+
if (value && typeof value === "object" && "entityType" in value) entities.set(name, value as Declarable);
|
|
77
|
+
}
|
|
78
|
+
const result = dockerSerializer.serialize(entities);
|
|
79
|
+
return typeof result === "string" ? {} : (result.files ?? {});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const PAGES = [
|
|
83
|
+
"docs/pages/dockerfiles.mdx",
|
|
84
|
+
"docs/pages/examples.mdx",
|
|
85
|
+
"docs/pages/lint-rules.mdx",
|
|
86
|
+
"src/skills/chant-docker.md",
|
|
87
|
+
"src/skills/chant-docker-patterns.md",
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
describe("docs Dockerfile examples", () => {
|
|
91
|
+
for (const page of PAGES) {
|
|
92
|
+
test(`${page}: every Dockerfile example builds what the page shows`, () => {
|
|
93
|
+
const list = blocks(page);
|
|
94
|
+
const pageModules = new Map<string, Record<string, unknown>>();
|
|
95
|
+
let checked = 0;
|
|
96
|
+
list.forEach((b, i) => {
|
|
97
|
+
if (b.lang !== "typescript" || b.title) return;
|
|
98
|
+
const isModule = /^\/\/ src\/\S+\.ts\s*$/m.test(b.code);
|
|
99
|
+
if (!b.code.includes("new Dockerfile(") && !isModule) return;
|
|
100
|
+
const files = buildBlock(b.code, pageModules);
|
|
101
|
+
if (!b.code.includes("new Dockerfile(")) return;
|
|
102
|
+
expect(Object.keys(files).length, `${page} block ${i + 1} declares a Dockerfile`).toBeGreaterThan(0);
|
|
103
|
+
checked++;
|
|
104
|
+
// The output shown right after it, under a "`Dockerfile.name`:" line.
|
|
105
|
+
const next = list[i + 1];
|
|
106
|
+
if (next && next.lang === "dockerfile" && !next.title && /^\s*`Dockerfile\.\w+`:\s*$/.test(next.before)) {
|
|
107
|
+
expect(Object.values(files).join("---\n"), `${page} block ${i + 1}`).toBe(next.code);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
expect(checked, `${page} has Dockerfile examples`).toBeGreaterThan(0);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
test("dockerfiles.mdx sharing section matches the dockerfile-sharing example and its build", async () => {
|
|
115
|
+
const titled = blocks("docs/pages/dockerfiles.mdx").filter((b) => b.title);
|
|
116
|
+
const sources = titled.filter((b) => b.lang === "typescript");
|
|
117
|
+
const outputs = titled.filter((b) => b.lang === "dockerfile");
|
|
118
|
+
expect(sources.map((b) => b.title)).toEqual(["src/shared/node.ts", "src/web.ts", "src/worker.ts", "src/shared/node-image.ts", "src/api.ts"]);
|
|
119
|
+
for (const b of sources) {
|
|
120
|
+
expect(b.code, b.title).toBe(readFileSync(join(sharingExample, b.title!), "utf8"));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const result = await build(join(sharingExample, "src"), [dockerSerializer]);
|
|
124
|
+
expect(result.errors).toEqual([]);
|
|
125
|
+
const files = (result.outputs.get("docker") as unknown as { files: Record<string, string> }).files;
|
|
126
|
+
expect(outputs.map((b) => b.title).sort()).toEqual(Object.keys(files).sort());
|
|
127
|
+
for (const b of outputs) {
|
|
128
|
+
expect(b.code, b.title).toBe(files[b.title!]);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("importing.mdx shows what importing its Dockerfile produces", () => {
|
|
133
|
+
const list = blocks("docs/pages/importing.mdx");
|
|
134
|
+
const at = list.findIndex((b) => b.lang === "dockerfile" && b.title === "Dockerfile");
|
|
135
|
+
expect(at).toBeGreaterThan(-1);
|
|
136
|
+
const [file] = new DockerTemplateGenerator().generate(new DockerTemplateParser().parse(list[at]!.code));
|
|
137
|
+
expect(list[at + 1]!.code).toBe(file!.content.endsWith("\n") ? file!.content : `${file!.content}\n`);
|
|
138
|
+
// And building the import gives the Dockerfile back.
|
|
139
|
+
expect(Object.values(buildBlock(list[at + 1]!.code))[0]).toBe(list[at]!.code.replace(/^#.*\n/gm, ""));
|
|
140
|
+
});
|
|
141
|
+
});
|
package/src/generated/index.d.ts
CHANGED
|
@@ -56,39 +56,120 @@ export interface DockerSecretProps {
|
|
|
56
56
|
}
|
|
57
57
|
export declare const DockerSecret: new (props?: DockerSecretProps) => Declarable;
|
|
58
58
|
|
|
59
|
+
/** The Dockerfile instructions a step can name. FROM is the stage's own `from` field. */
|
|
60
|
+
export type DockerfileInstructionName = "arg" | "env" | "run" | "copy" | "add" | "workdir" | "user" | "expose" | "volume" | "label" | "entrypoint" | "cmd" | "healthcheck" | "shell" | "stopsignal" | "onbuild";
|
|
61
|
+
type DockerfileStepOf<K extends DockerfileInstructionName, V> = { [P in K]: V } & { [P in Exclude<DockerfileInstructionName, K>]?: never };
|
|
62
|
+
/**
|
|
63
|
+
* One Dockerfile instruction, named by its single key: `{ run: "npm ci" }` is `RUN npm ci`.
|
|
64
|
+
* A string[] value (run, cmd, entrypoint, shell) is written in JSON exec form.
|
|
65
|
+
*/
|
|
66
|
+
export type DockerfileStep =
|
|
67
|
+
/** ARG: Build-time argument */
|
|
68
|
+
| DockerfileStepOf<"arg", string>
|
|
69
|
+
/** ENV: Environment variable */
|
|
70
|
+
| DockerfileStepOf<"env", string>
|
|
71
|
+
/** RUN: Run a command during build */
|
|
72
|
+
| DockerfileStepOf<"run", string | string[]>
|
|
73
|
+
/** COPY: Copy files from build context */
|
|
74
|
+
| DockerfileStepOf<"copy", string>
|
|
75
|
+
/** ADD: Add files (supports URLs and archives) */
|
|
76
|
+
| DockerfileStepOf<"add", string>
|
|
77
|
+
/** WORKDIR: Set working directory */
|
|
78
|
+
| DockerfileStepOf<"workdir", string>
|
|
79
|
+
/** USER: Set user for subsequent instructions */
|
|
80
|
+
| DockerfileStepOf<"user", string>
|
|
81
|
+
/** EXPOSE: Document exposed ports */
|
|
82
|
+
| DockerfileStepOf<"expose", string | number>
|
|
83
|
+
/** VOLUME: Create mount points */
|
|
84
|
+
| DockerfileStepOf<"volume", string>
|
|
85
|
+
/** LABEL: Add metadata labels */
|
|
86
|
+
| DockerfileStepOf<"label", string>
|
|
87
|
+
/** ENTRYPOINT: Set the entrypoint executable */
|
|
88
|
+
| DockerfileStepOf<"entrypoint", string | string[]>
|
|
89
|
+
/** CMD: Default command arguments */
|
|
90
|
+
| DockerfileStepOf<"cmd", string | string[]>
|
|
91
|
+
/** HEALTHCHECK: Health check instruction */
|
|
92
|
+
| DockerfileStepOf<"healthcheck", string>
|
|
93
|
+
/** SHELL: Set the shell for shell-form commands (JSON array form) */
|
|
94
|
+
| DockerfileStepOf<"shell", string | string[]>
|
|
95
|
+
/** STOPSIGNAL: Signal sent to stop the container */
|
|
96
|
+
| DockerfileStepOf<"stopsignal", string>
|
|
97
|
+
/** ONBUILD: Instruction to run when the image is used as a base */
|
|
98
|
+
| DockerfileStepOf<"onbuild", string>;
|
|
99
|
+
/**
|
|
100
|
+
* One build stage: FROM, then its instructions.
|
|
101
|
+
* Without `steps`, the per-kind fields are written in a fixed order: ARG, ENV, WORKDIR, USER, RUN, COPY, ADD, EXPOSE, VOLUME, LABEL, ENTRYPOINT, CMD, HEALTHCHECK.
|
|
102
|
+
*/
|
|
59
103
|
export interface DockerfileStage {
|
|
60
104
|
from: string;
|
|
61
105
|
as?: string;
|
|
106
|
+
/** Instructions after FROM, written exactly in this order. Can't be combined with the per-kind fields. */
|
|
107
|
+
steps?: DockerfileStep[];
|
|
108
|
+
/** ARG as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
62
109
|
arg?: string[];
|
|
110
|
+
/** ENV as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
63
111
|
env?: string[];
|
|
112
|
+
/** RUN as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
64
113
|
run?: string[];
|
|
114
|
+
/** COPY as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
65
115
|
copy?: string[];
|
|
116
|
+
/** ADD as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
66
117
|
add?: string[];
|
|
118
|
+
/** WORKDIR as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
67
119
|
workdir?: string;
|
|
120
|
+
/** USER as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
68
121
|
user?: string;
|
|
122
|
+
/** EXPOSE as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
69
123
|
expose?: string[];
|
|
124
|
+
/** VOLUME as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
70
125
|
volume?: string[];
|
|
126
|
+
/** LABEL as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
71
127
|
label?: string[];
|
|
128
|
+
/** ENTRYPOINT as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
72
129
|
entrypoint?: string;
|
|
130
|
+
/** CMD as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
73
131
|
cmd?: string;
|
|
132
|
+
/** HEALTHCHECK as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
74
133
|
healthcheck?: string;
|
|
75
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* A Dockerfile: `stages` for a multi-stage build, or `from` and the stage fields for one stage.
|
|
137
|
+
* Without `steps`, the per-kind fields are written in a fixed order: ARG, ENV, WORKDIR, USER, RUN, COPY, ADD, EXPOSE, VOLUME, LABEL, ENTRYPOINT, CMD, HEALTHCHECK.
|
|
138
|
+
*/
|
|
76
139
|
export interface DockerfileProps {
|
|
77
140
|
name?: string;
|
|
141
|
+
/** ARG instructions written before the first FROM, e.g. `["NODE_VERSION=20"]`. */
|
|
142
|
+
globalArgs?: string[];
|
|
78
143
|
from?: string;
|
|
144
|
+
as?: string;
|
|
79
145
|
stages?: DockerfileStage[];
|
|
146
|
+
/** Instructions after FROM, written exactly in this order. Can't be combined with the per-kind fields. */
|
|
147
|
+
steps?: DockerfileStep[];
|
|
148
|
+
/** ARG as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
80
149
|
arg?: string[];
|
|
150
|
+
/** ENV as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
81
151
|
env?: string[];
|
|
152
|
+
/** RUN as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
82
153
|
run?: string[];
|
|
154
|
+
/** COPY as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
83
155
|
copy?: string[];
|
|
156
|
+
/** ADD as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
84
157
|
add?: string[];
|
|
158
|
+
/** WORKDIR as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
85
159
|
workdir?: string;
|
|
160
|
+
/** USER as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
86
161
|
user?: string;
|
|
162
|
+
/** EXPOSE as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
87
163
|
expose?: string[];
|
|
164
|
+
/** VOLUME as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
88
165
|
volume?: string[];
|
|
166
|
+
/** LABEL as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
89
167
|
label?: string[];
|
|
168
|
+
/** ENTRYPOINT as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
90
169
|
entrypoint?: string;
|
|
170
|
+
/** CMD as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
91
171
|
cmd?: string;
|
|
172
|
+
/** HEALTHCHECK as a per-kind field, written in the fixed order. Use `steps` to choose the order. */
|
|
92
173
|
healthcheck?: string;
|
|
93
174
|
}
|
|
94
175
|
export declare const Dockerfile: new (props?: DockerfileProps) => Declarable;
|