@alchemy.run/docker 2.0.0-beta.85 → 2.0.0-beta.86

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.
Files changed (93) hide show
  1. package/README.md +16 -0
  2. package/lib/Bootstrap.d.ts.map +1 -1
  3. package/lib/Bootstrap.js +2 -1
  4. package/lib/Bootstrap.js.map +1 -1
  5. package/lib/BuildCache.d.ts +87 -0
  6. package/lib/BuildCache.d.ts.map +1 -0
  7. package/lib/BuildCache.js +39 -0
  8. package/lib/BuildCache.js.map +1 -0
  9. package/lib/BuildHash.d.ts +9 -1
  10. package/lib/BuildHash.d.ts.map +1 -1
  11. package/lib/BuildHash.js +51 -19
  12. package/lib/BuildHash.js.map +1 -1
  13. package/lib/BuildPlan.d.ts +202 -0
  14. package/lib/BuildPlan.d.ts.map +1 -0
  15. package/lib/BuildPlan.js +514 -0
  16. package/lib/BuildPlan.js.map +1 -0
  17. package/lib/Container.d.ts +24 -1
  18. package/lib/Container.d.ts.map +1 -1
  19. package/lib/Container.js +14 -0
  20. package/lib/Container.js.map +1 -1
  21. package/lib/Context.d.ts +20 -1
  22. package/lib/Context.d.ts.map +1 -1
  23. package/lib/Context.js +15 -0
  24. package/lib/Context.js.map +1 -1
  25. package/lib/Docker.d.ts +33 -0
  26. package/lib/Docker.d.ts.map +1 -1
  27. package/lib/Docker.js +23 -2
  28. package/lib/Docker.js.map +1 -1
  29. package/lib/Dockerfile.d.ts +0 -2
  30. package/lib/Dockerfile.d.ts.map +1 -1
  31. package/lib/Dockerfile.js.map +1 -1
  32. package/lib/DockerfileParser.d.ts +125 -0
  33. package/lib/DockerfileParser.d.ts.map +1 -0
  34. package/lib/DockerfileParser.js +1040 -0
  35. package/lib/DockerfileParser.js.map +1 -0
  36. package/lib/HealthcheckCommand.d.ts.map +1 -1
  37. package/lib/HealthcheckCommand.js.map +1 -1
  38. package/lib/Image.d.ts +40 -12
  39. package/lib/Image.d.ts.map +1 -1
  40. package/lib/Image.js +41 -9
  41. package/lib/Image.js.map +1 -1
  42. package/lib/ImageArchive.d.ts +41 -0
  43. package/lib/ImageArchive.d.ts.map +1 -0
  44. package/lib/ImageArchive.js +54 -0
  45. package/lib/ImageArchive.js.map +1 -0
  46. package/lib/ImageSource.d.ts +100 -11
  47. package/lib/ImageSource.d.ts.map +1 -1
  48. package/lib/ImageSource.js +219 -73
  49. package/lib/ImageSource.js.map +1 -1
  50. package/lib/Network.d.ts +175 -3
  51. package/lib/Network.d.ts.map +1 -1
  52. package/lib/Network.js +296 -8
  53. package/lib/Network.js.map +1 -1
  54. package/lib/Providers.d.ts.map +1 -1
  55. package/lib/Providers.js.map +1 -1
  56. package/lib/Registry.d.ts.map +1 -1
  57. package/lib/Registry.js.map +1 -1
  58. package/lib/RegistryError.d.ts.map +1 -1
  59. package/lib/RegistryError.js.map +1 -1
  60. package/lib/RemoteImage.d.ts.map +1 -1
  61. package/lib/RemoteImage.js.map +1 -1
  62. package/lib/Service.d.ts.map +1 -1
  63. package/lib/Service.js.map +1 -1
  64. package/lib/ServiceImage.d.ts.map +1 -1
  65. package/lib/ServiceImage.js.map +1 -1
  66. package/lib/ShellWord.d.ts +28 -0
  67. package/lib/ShellWord.d.ts.map +1 -0
  68. package/lib/ShellWord.js +301 -0
  69. package/lib/ShellWord.js.map +1 -0
  70. package/lib/Swarm.d.ts.map +1 -1
  71. package/lib/Swarm.js.map +1 -1
  72. package/lib/Volume.d.ts +24 -1
  73. package/lib/Volume.d.ts.map +1 -1
  74. package/lib/Volume.js +16 -0
  75. package/lib/Volume.js.map +1 -1
  76. package/lib/index.d.ts.map +1 -1
  77. package/lib/index.js.map +1 -1
  78. package/package.json +9 -9
  79. package/src/Bootstrap.ts +2 -0
  80. package/src/BuildCache.ts +111 -0
  81. package/src/BuildHash.ts +73 -24
  82. package/src/BuildPlan.ts +758 -0
  83. package/src/Container.ts +31 -1
  84. package/src/Context.ts +27 -1
  85. package/src/Docker.ts +56 -2
  86. package/src/Dockerfile.ts +0 -2
  87. package/src/DockerfileParser.ts +1152 -0
  88. package/src/Image.ts +45 -14
  89. package/src/ImageArchive.ts +77 -0
  90. package/src/ImageSource.ts +322 -103
  91. package/src/Network.ts +432 -10
  92. package/src/ShellWord.ts +326 -0
  93. package/src/Volume.ts +33 -1
package/src/Image.ts CHANGED
@@ -6,6 +6,7 @@ import * as Effect from "effect/Effect";
6
6
  import * as FileSystem from "effect/FileSystem";
7
7
  import * as Path from "effect/Path";
8
8
  import type * as Redacted from "effect/Redacted";
9
+ import { type BuildCacheOptions, buildCacheRef, resolveBuildCache } from "./BuildCache.ts";
9
10
  import { Docker, dockerContextName, dockerPhysicalName } from "./Docker.ts";
10
11
  import type { Providers } from "./Providers.ts";
11
12
  import {
@@ -16,7 +17,7 @@ import {
16
17
  withRegistryHost,
17
18
  } from "./Registry.ts";
18
19
 
19
- export interface DockerBuildOptions {
20
+ export interface DockerBuildOptions extends BuildCacheOptions {
20
21
  /**
21
22
  * Build context directory.
22
23
  *
@@ -45,10 +46,6 @@ export interface DockerBuildOptions {
45
46
  secrets?: Record<string, Redacted.Redacted<string>>;
46
47
  /** Multi-stage build target. */
47
48
  target?: string;
48
- /** Cache sources passed as `--cache-from`. */
49
- cacheFrom?: string[];
50
- /** Cache destinations passed as `--cache-to`. */
51
- cacheTo?: string[];
52
49
  /** Additional Docker build options. */
53
50
  options?: string[];
54
51
  }
@@ -159,18 +156,35 @@ export interface Image extends Resource<
159
156
  * });
160
157
  * ```
161
158
  *
162
- * ### Private Base Images and Registry Caches
163
- * **Example:** Build FROM a private base image with a registry cache
159
+ * ### Private Base Images
160
+ * **Example:** Build FROM a private base image
164
161
  * ```typescript
165
162
  * // Dockerfile: FROM registry.example.com/base:v1
166
163
  * const image = yield* Docker.Image("app", {
167
164
  * name: "registry.example.com/app",
168
- * build: {
169
- * context: "./app",
170
- * cacheFrom: ["type=registry,ref=registry.example.com/app:buildcache"],
171
- * cacheTo: ["type=registry,ref=registry.example.com/app:buildcache,mode=max"],
165
+ * build: { context: "./app" },
166
+ * // Authenticates the base-image pull, then the push.
167
+ * registry: {
168
+ * server: "registry.example.com",
169
+ * username: "deploy",
170
+ * password: Config.Redacted("REGISTRY_PASSWORD"),
172
171
  * },
173
- * // Authenticates the base-image pull and cache import/export, then the push.
172
+ * });
173
+ * ```
174
+ *
175
+ * ### Caching Build Layers
176
+ * Builds reuse the local BuildKit cache of the machine they run on, and
177
+ * nothing but the image is pushed. A builder that has never built the image,
178
+ * such as a fresh CI runner, reruns every step. Set `build.cache: true` to keep
179
+ * every stage's layers at the image repository's `:buildcache` tag, so fresh
180
+ * builders skip unchanged steps. For another backend, pass BuildKit's own
181
+ * `--cache-from` / `--cache-to` values as `from` and `to`.
182
+ *
183
+ * **Example:** Cache layers in the image's registry
184
+ * ```typescript
185
+ * const image = yield* Docker.Image("app", {
186
+ * name: "registry.example.com/app",
187
+ * build: { context: "./app", cache: true },
174
188
  * registry: {
175
189
  * server: "registry.example.com",
176
190
  * username: "deploy",
@@ -179,6 +193,20 @@ export interface Image extends Resource<
179
193
  * });
180
194
  * ```
181
195
  *
196
+ * **Example:** Cache layers in GitHub Actions
197
+ * ```typescript
198
+ * const image = yield* Docker.Image("app", {
199
+ * name: "my-app",
200
+ * build: {
201
+ * context: "./app",
202
+ * cache: {
203
+ * from: ["type=gha,scope=app"],
204
+ * to: ["type=gha,scope=app,mode=max"],
205
+ * },
206
+ * },
207
+ * });
208
+ * ```
209
+ *
182
210
  * ### Docker Context
183
211
  * **Example:** Build in a named Docker context
184
212
  * ```typescript
@@ -221,8 +249,11 @@ export const ImageProvider = () =>
221
249
  target: props.build.target,
222
250
  "build-arg": props.build.args,
223
251
  secrets: props.build.secrets,
224
- "cache-from": props.build.cacheFrom,
225
- "cache-to": props.build.cacheTo,
252
+ // The registry cache lives next to the image.
253
+ ...resolveBuildCache(
254
+ props.build.cache,
255
+ buildCacheRef(props.registry ? withRegistryHost(ref, props.registry) : ref),
256
+ ),
226
257
  args: props.build.options,
227
258
  engineContext,
228
259
  // Base images and registry caches may live in the same registry;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Image archives: a Docker build context built for one platform and saved
3
+ * with `docker save`, for hosts with no registry between the deploy and the
4
+ * machine that runs it (a VM that loads the archive into its own Docker).
5
+ */
6
+ import * as Effect from "effect/Effect";
7
+ import * as FileSystem from "effect/FileSystem";
8
+ import * as Path from "effect/Path";
9
+ import { hashDockerBuildInputs, resolveDockerBuildPaths } from "./BuildHash.ts";
10
+ import { Docker } from "./Docker.ts";
11
+
12
+ export interface ImageArchiveSource {
13
+ /** The Docker build context directory. */
14
+ context: string;
15
+ /**
16
+ * The Dockerfile, relative to the context unless absolute.
17
+ * @default "Dockerfile"
18
+ */
19
+ dockerfile?: string;
20
+ /** The platform the archive's image is built for, e.g. `linux/amd64`. */
21
+ platform: string;
22
+ }
23
+
24
+ const pathsOf = Effect.fn(function* (source: ImageArchiveSource) {
25
+ const path = yield* Path.Path;
26
+ const dockerfile =
27
+ source.dockerfile === undefined
28
+ ? path.join(source.context, "Dockerfile")
29
+ : path.isAbsolute(source.dockerfile)
30
+ ? source.dockerfile
31
+ : path.join(source.context, source.dockerfile);
32
+ return yield* resolveDockerBuildPaths({ context: source.context, dockerfile });
33
+ });
34
+
35
+ /**
36
+ * A content hash of the inputs an archive is built from: the context's
37
+ * files (after `.dockerignore`), the Dockerfile and the platform. It
38
+ * changes exactly when the archive's image would.
39
+ */
40
+ export const hashImageArchive = Effect.fn(function* (source: ImageArchiveSource) {
41
+ const { context, dockerfile } = yield* pathsOf(source);
42
+ return yield* hashDockerBuildInputs(
43
+ { context, dockerfile, platform: source.platform },
44
+ "effective",
45
+ );
46
+ });
47
+
48
+ /**
49
+ * Build `source` and save its image to an archive at `output`, tagged
50
+ * `tag`, the name `docker load` reports where the archive is loaded.
51
+ * Resolves to the archive's bytes.
52
+ */
53
+ export const buildImageArchive = Effect.fn(function* (
54
+ source: ImageArchiveSource,
55
+ options: { readonly tag: string; readonly output: string },
56
+ ) {
57
+ const docker = yield* Docker;
58
+ const fs = yield* FileSystem.FileSystem;
59
+ const path = yield* Path.Path;
60
+ const { context, dockerfile } = yield* pathsOf(source);
61
+ yield* docker.image.build({
62
+ context,
63
+ file: dockerfile,
64
+ tag: options.tag,
65
+ platform: source.platform,
66
+ });
67
+ yield* fs.makeDirectory(path.dirname(options.output), { recursive: true });
68
+ yield* docker.run(["save", options.tag, "-o", options.output]);
69
+ return yield* fs.readFile(options.output);
70
+ });
71
+
72
+ /**
73
+ * Shell lines that load the archive at `archive` into Docker and set the
74
+ * shell variable `IMAGE` to the image it holds.
75
+ */
76
+ export const loadImageArchiveScript = (archive: string) =>
77
+ `IMAGE="$(docker load -i ${archive} | sed -n 's/^Loaded image: //p' | tail -1)"`;