@procedures/docker 0.0.0-stage → 0.2.0
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/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +752 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +22 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +211 -0
- package/dist/module.js.map +1 -0
- package/dist/procedures/docker/build.d.ts +12 -0
- package/dist/procedures/docker/build.d.ts.map +1 -0
- package/dist/procedures/docker/build.js +34 -0
- package/dist/procedures/docker/build.js.map +1 -0
- package/dist/procedures/docker/down.d.ts +12 -0
- package/dist/procedures/docker/down.d.ts.map +1 -0
- package/dist/procedures/docker/down.js +25 -0
- package/dist/procedures/docker/down.js.map +1 -0
- package/dist/procedures/docker/exec.d.ts +12 -0
- package/dist/procedures/docker/exec.d.ts.map +1 -0
- package/dist/procedures/docker/exec.js +30 -0
- package/dist/procedures/docker/exec.js.map +1 -0
- package/dist/procedures/docker/index.d.ts +11 -0
- package/dist/procedures/docker/index.d.ts.map +1 -0
- package/dist/procedures/docker/index.js +11 -0
- package/dist/procedures/docker/index.js.map +1 -0
- package/dist/procedures/docker/logs.d.ts +16 -0
- package/dist/procedures/docker/logs.d.ts.map +1 -0
- package/dist/procedures/docker/logs.js +40 -0
- package/dist/procedures/docker/logs.js.map +1 -0
- package/dist/procedures/docker/ps.d.ts +12 -0
- package/dist/procedures/docker/ps.d.ts.map +1 -0
- package/dist/procedures/docker/ps.js +22 -0
- package/dist/procedures/docker/ps.js.map +1 -0
- package/dist/procedures/docker/pull.d.ts +12 -0
- package/dist/procedures/docker/pull.d.ts.map +1 -0
- package/dist/procedures/docker/pull.js +17 -0
- package/dist/procedures/docker/pull.js.map +1 -0
- package/dist/procedures/docker/rm.d.ts +12 -0
- package/dist/procedures/docker/rm.d.ts.map +1 -0
- package/dist/procedures/docker/rm.js +21 -0
- package/dist/procedures/docker/rm.js.map +1 -0
- package/dist/procedures/docker/run.d.ts +21 -0
- package/dist/procedures/docker/run.d.ts.map +1 -0
- package/dist/procedures/docker/run.js +56 -0
- package/dist/procedures/docker/run.js.map +1 -0
- package/dist/procedures/docker/shared.d.ts +23 -0
- package/dist/procedures/docker/shared.d.ts.map +1 -0
- package/dist/procedures/docker/shared.js +51 -0
- package/dist/procedures/docker/shared.js.map +1 -0
- package/dist/procedures/docker/stop.d.ts +12 -0
- package/dist/procedures/docker/stop.d.ts.map +1 -0
- package/dist/procedures/docker/stop.js +20 -0
- package/dist/procedures/docker/stop.js.map +1 -0
- package/dist/procedures/docker/up.d.ts +12 -0
- package/dist/procedures/docker/up.d.ts.map +1 -0
- package/dist/procedures/docker/up.js +28 -0
- package/dist/procedures/docker/up.js.map +1 -0
- package/dist/register.d.ts +7 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +9 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +207 -0
- package/dist/types.js.map +1 -0
- package/package.json +84 -3
- package/src/index.ts +75 -0
- package/src/module.ts +266 -0
- package/src/procedures/docker/build.ts +46 -0
- package/src/procedures/docker/down.ts +31 -0
- package/src/procedures/docker/exec.ts +37 -0
- package/src/procedures/docker/index.ts +10 -0
- package/src/procedures/docker/logs.ts +52 -0
- package/src/procedures/docker/ps.ts +27 -0
- package/src/procedures/docker/pull.ts +23 -0
- package/src/procedures/docker/rm.ts +28 -0
- package/src/procedures/docker/run.ts +65 -0
- package/src/procedures/docker/shared.ts +62 -0
- package/src/procedures/docker/stop.ts +29 -0
- package/src/procedures/docker/up.ts +35 -0
- package/src/register.ts +11 -0
- package/src/types.ts +351 -0
package/package.json
CHANGED
|
@@ -1,6 +1,87 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package",
|
|
2
3
|
"name": "@procedures/docker",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"description": "Docker and Docker Compose as typed procedures: ps, run, exec, logs (streaming), build, pull, stop, rm, compose up and down, run with argv and no shell injection.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"docker",
|
|
8
|
+
"docker-compose",
|
|
9
|
+
"containers",
|
|
10
|
+
"devops",
|
|
11
|
+
"automation",
|
|
12
|
+
"procedures"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://mark1russell7.github.io/client/",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/mark1russell7/client/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/mark1russell7/client.git",
|
|
21
|
+
"directory": "packages/client-docker"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Mark Russell (https://github.com/mark1russell7)",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./module": {
|
|
34
|
+
"types": "./dist/module.d.ts",
|
|
35
|
+
"import": "./dist/module.js"
|
|
36
|
+
},
|
|
37
|
+
"./register": {
|
|
38
|
+
"types": "./dist/register.d.ts",
|
|
39
|
+
"import": "./dist/register.js"
|
|
40
|
+
},
|
|
41
|
+
"./register.js": {
|
|
42
|
+
"import": "./dist/register.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"src",
|
|
48
|
+
"!src/**/*.test.ts",
|
|
49
|
+
"!src/**/*.test.tsx",
|
|
50
|
+
"!src/**/__tests__",
|
|
51
|
+
"CHANGELOG.md"
|
|
52
|
+
],
|
|
53
|
+
"sideEffects": [
|
|
54
|
+
"./dist/register.js"
|
|
55
|
+
],
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=22"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public",
|
|
61
|
+
"provenance": true
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@procedures/client": "0.2.0",
|
|
65
|
+
"@procedures/shell": "0.2.0",
|
|
66
|
+
"zod": "^4.6.5"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"typescript": "^7.0.2",
|
|
70
|
+
"@mark1russell7/cue": "^1.0.0",
|
|
71
|
+
"vitest": "^5.0.3",
|
|
72
|
+
"@types/node": "^22.0.0"
|
|
73
|
+
},
|
|
74
|
+
"client": {
|
|
75
|
+
"procedures": "./dist/register.js"
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"build": "tsc -b",
|
|
79
|
+
"typecheck": "tsc --noEmit",
|
|
80
|
+
"clean": "rm -rf dist .tsbuildinfo",
|
|
81
|
+
"test": "vitest run --exclude '**/*.integration.test.ts'",
|
|
82
|
+
"test:watch": "vitest",
|
|
83
|
+
"test:unit": "vitest run --exclude '**/*.integration.test.ts'",
|
|
84
|
+
"test:integration": "vitest run __tests__/docker.integration.test.ts",
|
|
85
|
+
"test:coverage": "vitest run --coverage"
|
|
86
|
+
}
|
|
6
87
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @procedures/docker
|
|
3
|
+
*
|
|
4
|
+
* Wraps Docker CLI commands as procedures using client-shell.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Client } from "@procedures/client";
|
|
9
|
+
*
|
|
10
|
+
* // Run a container
|
|
11
|
+
* await client.call(["docker", "run"], {
|
|
12
|
+
* image: "nginx:latest",
|
|
13
|
+
* name: "my-nginx",
|
|
14
|
+
* ports: ["8080:80"],
|
|
15
|
+
* detach: true,
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // Build an image
|
|
19
|
+
* await client.call(["docker", "build"], {
|
|
20
|
+
* context: ".",
|
|
21
|
+
* tag: "my-app:latest",
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Docker compose up
|
|
25
|
+
* await client.call(["docker", "compose", "up"], {
|
|
26
|
+
* detach: true,
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// Types
|
|
32
|
+
export type {
|
|
33
|
+
DockerRunInput,
|
|
34
|
+
DockerBuildInput,
|
|
35
|
+
DockerPullInput,
|
|
36
|
+
DockerExecInput,
|
|
37
|
+
DockerStopInput,
|
|
38
|
+
DockerRmInput,
|
|
39
|
+
DockerPsInput,
|
|
40
|
+
DockerLogsInput,
|
|
41
|
+
DockerComposeUpInput,
|
|
42
|
+
DockerComposeDownInput,
|
|
43
|
+
DockerCommandOutput,
|
|
44
|
+
} from "./types.js";
|
|
45
|
+
export type { DockerLogItem } from "./procedures/docker/logs.js";
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
DockerRunInputSchema,
|
|
49
|
+
DockerBuildInputSchema,
|
|
50
|
+
DockerPullInputSchema,
|
|
51
|
+
DockerExecInputSchema,
|
|
52
|
+
DockerStopInputSchema,
|
|
53
|
+
DockerRmInputSchema,
|
|
54
|
+
DockerPsInputSchema,
|
|
55
|
+
DockerLogsInputSchema,
|
|
56
|
+
DockerComposeUpInputSchema,
|
|
57
|
+
DockerComposeDownInputSchema,
|
|
58
|
+
} from "./types.js";
|
|
59
|
+
|
|
60
|
+
// Procedures
|
|
61
|
+
export {
|
|
62
|
+
dockerRun,
|
|
63
|
+
dockerBuild,
|
|
64
|
+
dockerPull,
|
|
65
|
+
dockerExec,
|
|
66
|
+
dockerStop,
|
|
67
|
+
dockerRm,
|
|
68
|
+
dockerPs,
|
|
69
|
+
dockerLogs,
|
|
70
|
+
dockerComposeUp,
|
|
71
|
+
dockerComposeDown,
|
|
72
|
+
} from "./procedures/docker/index.js";
|
|
73
|
+
|
|
74
|
+
// Registration
|
|
75
|
+
export { registerDockerProcedures } from "./module.js";
|
package/src/module.ts
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module (no side effects): the procedures of this package as data, for `createRegistry()`.
|
|
3
|
+
*
|
|
4
|
+
* Procedure Registration for Docker operations
|
|
5
|
+
*
|
|
6
|
+
* Provides docker.run, docker.build, docker.pull, docker.exec, docker.stop,
|
|
7
|
+
* docker.rm, docker.ps, docker.logs, docker.compose.up, docker.compose.down procedures.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import { createProcedure, zodAdapter, defineModule, type ProcedureModule, PROCEDURE_REGISTRY, registerModules, type ProcedureRegistry } from "@procedures/client";
|
|
12
|
+
import shellModule from "@procedures/shell/module";
|
|
13
|
+
import {
|
|
14
|
+
dockerRun,
|
|
15
|
+
dockerBuild,
|
|
16
|
+
dockerPull,
|
|
17
|
+
dockerExec,
|
|
18
|
+
dockerStop,
|
|
19
|
+
dockerRm,
|
|
20
|
+
dockerPs,
|
|
21
|
+
dockerLogs,
|
|
22
|
+
dockerComposeUp,
|
|
23
|
+
dockerComposeDown,
|
|
24
|
+
} from "./procedures/docker/index.js";
|
|
25
|
+
import type { DockerLogItem } from "./procedures/docker/index.js";
|
|
26
|
+
import {
|
|
27
|
+
DockerRunInputSchema,
|
|
28
|
+
DockerBuildInputSchema,
|
|
29
|
+
DockerPullInputSchema,
|
|
30
|
+
DockerExecInputSchema,
|
|
31
|
+
DockerStopInputSchema,
|
|
32
|
+
DockerRmInputSchema,
|
|
33
|
+
DockerPsInputSchema,
|
|
34
|
+
DockerLogsInputSchema,
|
|
35
|
+
DockerComposeUpInputSchema,
|
|
36
|
+
DockerComposeDownInputSchema,
|
|
37
|
+
type DockerRunInput,
|
|
38
|
+
type DockerBuildInput,
|
|
39
|
+
type DockerPullInput,
|
|
40
|
+
type DockerExecInput,
|
|
41
|
+
type DockerStopInput,
|
|
42
|
+
type DockerRmInput,
|
|
43
|
+
type DockerPsInput,
|
|
44
|
+
type DockerLogsInput,
|
|
45
|
+
type DockerComposeUpInput,
|
|
46
|
+
type DockerComposeDownInput,
|
|
47
|
+
type DockerCommandOutput,
|
|
48
|
+
DockerCommandOutputSchema,
|
|
49
|
+
DockerLogsOutputSchema,
|
|
50
|
+
} from "./types.js";
|
|
51
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
52
|
+
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// Procedures
|
|
55
|
+
// =============================================================================
|
|
56
|
+
|
|
57
|
+
const dockerRunProcedure = createProcedure()
|
|
58
|
+
.path(["docker", "run"])
|
|
59
|
+
.input(zodAdapter<DockerRunInput>(DockerRunInputSchema))
|
|
60
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
61
|
+
.meta({
|
|
62
|
+
description: "Run a Docker container",
|
|
63
|
+
calls: ["shell.run"],
|
|
64
|
+
// The container runs the image and command of the caller. The volumes give it host files, and
|
|
65
|
+
// docker pulls a missing image.
|
|
66
|
+
effects: { reads: ["docker", "fs", "network"], writes: ["docker", "fs", "process"] },
|
|
67
|
+
args: ["image"],
|
|
68
|
+
shorts: { name: "n", detach: "d" },
|
|
69
|
+
output: "json",
|
|
70
|
+
})
|
|
71
|
+
.handler(async (input: DockerRunInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
72
|
+
return dockerRun(input, ctx);
|
|
73
|
+
})
|
|
74
|
+
.build();
|
|
75
|
+
|
|
76
|
+
const dockerBuildProcedure = createProcedure()
|
|
77
|
+
.path(["docker", "build"])
|
|
78
|
+
.input(zodAdapter<DockerBuildInput>(DockerBuildInputSchema))
|
|
79
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
80
|
+
.meta({
|
|
81
|
+
description: "Build a Docker image",
|
|
82
|
+
calls: ["shell.run"],
|
|
83
|
+
// The RUN steps of the Dockerfile are code of the project. Docker reads the context and pulls
|
|
84
|
+
// the base images. The tag goes to the new image, and the earlier image stays.
|
|
85
|
+
effects: { reads: ["docker", "fs", "network"], writes: ["docker", "process"], destructive: false },
|
|
86
|
+
args: ["context"],
|
|
87
|
+
shorts: { tag: "t", dockerfile: "f" },
|
|
88
|
+
output: "json",
|
|
89
|
+
})
|
|
90
|
+
.handler(async (input: DockerBuildInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
91
|
+
return dockerBuild(input, ctx);
|
|
92
|
+
})
|
|
93
|
+
.build();
|
|
94
|
+
|
|
95
|
+
const dockerPullProcedure = createProcedure()
|
|
96
|
+
.path(["docker", "pull"])
|
|
97
|
+
.input(zodAdapter<DockerPullInput>(DockerPullInputSchema))
|
|
98
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
99
|
+
.meta({
|
|
100
|
+
description: "Pull a Docker image",
|
|
101
|
+
calls: ["shell.run"],
|
|
102
|
+
effects: { reads: ["docker", "network"], writes: ["docker"], destructive: false, idempotent: true },
|
|
103
|
+
args: ["image"],
|
|
104
|
+
output: "json",
|
|
105
|
+
})
|
|
106
|
+
.handler(async (input: DockerPullInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
107
|
+
return dockerPull(input, ctx);
|
|
108
|
+
})
|
|
109
|
+
.build();
|
|
110
|
+
|
|
111
|
+
const dockerExecProcedure = createProcedure()
|
|
112
|
+
.path(["docker", "exec"])
|
|
113
|
+
.input(zodAdapter<DockerExecInput>(DockerExecInputSchema))
|
|
114
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
115
|
+
.meta({
|
|
116
|
+
description: "Execute command in a running container",
|
|
117
|
+
calls: ["shell.run"],
|
|
118
|
+
// The container runs the command of the caller
|
|
119
|
+
effects: { reads: ["docker"], writes: ["docker", "process"] },
|
|
120
|
+
args: ["container", "command"],
|
|
121
|
+
shorts: { interactive: "i", tty: "t", workdir: "w" },
|
|
122
|
+
output: "json",
|
|
123
|
+
})
|
|
124
|
+
.handler(async (input: DockerExecInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
125
|
+
return dockerExec(input, ctx);
|
|
126
|
+
})
|
|
127
|
+
.build();
|
|
128
|
+
|
|
129
|
+
const dockerStopProcedure = createProcedure()
|
|
130
|
+
.path(["docker", "stop"])
|
|
131
|
+
.input(zodAdapter<DockerStopInput>(DockerStopInputSchema))
|
|
132
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
133
|
+
.meta({
|
|
134
|
+
description: "Stop running container(s)",
|
|
135
|
+
calls: ["shell.run"],
|
|
136
|
+
// The stop of a stopped container changes nothing
|
|
137
|
+
effects: { reads: ["docker"], writes: ["docker"], idempotent: true },
|
|
138
|
+
args: ["containers"],
|
|
139
|
+
shorts: { time: "t" },
|
|
140
|
+
output: "json",
|
|
141
|
+
})
|
|
142
|
+
.handler(async (input: DockerStopInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
143
|
+
return dockerStop(input, ctx);
|
|
144
|
+
})
|
|
145
|
+
.build();
|
|
146
|
+
|
|
147
|
+
const dockerRmProcedure = createProcedure()
|
|
148
|
+
.path(["docker", "rm"])
|
|
149
|
+
.input(zodAdapter<DockerRmInput>(DockerRmInputSchema))
|
|
150
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
151
|
+
.meta({
|
|
152
|
+
description: "Remove container(s)",
|
|
153
|
+
calls: ["shell.run"],
|
|
154
|
+
effects: { reads: ["docker"], writes: ["docker"] },
|
|
155
|
+
args: ["containers"],
|
|
156
|
+
shorts: { force: "f", volumes: "v" },
|
|
157
|
+
output: "json",
|
|
158
|
+
})
|
|
159
|
+
.handler(async (input: DockerRmInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
160
|
+
return dockerRm(input, ctx);
|
|
161
|
+
})
|
|
162
|
+
.build();
|
|
163
|
+
|
|
164
|
+
const dockerPsProcedure = createProcedure()
|
|
165
|
+
.path(["docker", "ps"])
|
|
166
|
+
.input(zodAdapter<DockerPsInput>(DockerPsInputSchema))
|
|
167
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
168
|
+
.meta({
|
|
169
|
+
description: "List containers",
|
|
170
|
+
calls: ["shell.run"],
|
|
171
|
+
effects: { reads: ["docker"], writes: [] },
|
|
172
|
+
shorts: { all: "a", filter: "f", format: "F" },
|
|
173
|
+
output: "json",
|
|
174
|
+
})
|
|
175
|
+
.handler(async (input: DockerPsInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
176
|
+
return dockerPs(input, ctx);
|
|
177
|
+
})
|
|
178
|
+
.build();
|
|
179
|
+
|
|
180
|
+
const dockerLogsProcedure = createProcedure()
|
|
181
|
+
.path(["docker", "logs"])
|
|
182
|
+
.input(zodAdapter<DockerLogsInput>(DockerLogsInputSchema))
|
|
183
|
+
// One value, or with follow one item for each log line (a stream)
|
|
184
|
+
.output(zodAdapter<DockerCommandOutput | DockerLogItem>(DockerLogsOutputSchema))
|
|
185
|
+
.meta({
|
|
186
|
+
description: "Get container logs",
|
|
187
|
+
calls: ["shell.run", "shell.stream"],
|
|
188
|
+
effects: { reads: ["docker"], writes: [] },
|
|
189
|
+
args: ["container"],
|
|
190
|
+
shorts: { follow: "f", tail: "n", timestamps: "t" },
|
|
191
|
+
output: "json",
|
|
192
|
+
})
|
|
193
|
+
// With follow, the promise gives a stream: invokeProcedure reads a returned async iterable as a
|
|
194
|
+
// stream, and the handler types of the core do not describe that case
|
|
195
|
+
.handler((input: DockerLogsInput, ctx: ProcedureContext) =>
|
|
196
|
+
dockerLogs(input, ctx) as unknown as Promise<DockerCommandOutput | DockerLogItem>
|
|
197
|
+
)
|
|
198
|
+
.build();
|
|
199
|
+
|
|
200
|
+
const dockerComposeUpProcedure = createProcedure()
|
|
201
|
+
.path(["docker", "compose", "up"])
|
|
202
|
+
.input(zodAdapter<DockerComposeUpInput>(DockerComposeUpInputSchema))
|
|
203
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
204
|
+
.meta({
|
|
205
|
+
description: "Start services with docker compose",
|
|
206
|
+
calls: ["shell.run"],
|
|
207
|
+
// The compose file of the caller sets the images, the commands and the host folders of the
|
|
208
|
+
// services. An up can replace the containers of changed services.
|
|
209
|
+
effects: { reads: ["docker", "fs", "network"], writes: ["docker", "fs", "process"] },
|
|
210
|
+
shorts: { file: "f", detach: "d", build: "b" },
|
|
211
|
+
output: "json",
|
|
212
|
+
})
|
|
213
|
+
.handler(async (input: DockerComposeUpInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
214
|
+
return dockerComposeUp(input, ctx);
|
|
215
|
+
})
|
|
216
|
+
.build();
|
|
217
|
+
|
|
218
|
+
const dockerComposeDownProcedure = createProcedure()
|
|
219
|
+
.path(["docker", "compose", "down"])
|
|
220
|
+
.input(zodAdapter<DockerComposeDownInput>(DockerComposeDownInputSchema))
|
|
221
|
+
.output(zodAdapter<DockerCommandOutput>(DockerCommandOutputSchema))
|
|
222
|
+
.meta({
|
|
223
|
+
description: "Stop services with docker compose",
|
|
224
|
+
calls: ["shell.run"],
|
|
225
|
+
// It removes the containers of the project, and with volumes: true its volumes. A second down
|
|
226
|
+
// changes nothing.
|
|
227
|
+
effects: { reads: ["docker", "fs"], writes: ["docker"], idempotent: true },
|
|
228
|
+
shorts: { file: "f", volumes: "v" },
|
|
229
|
+
output: "json",
|
|
230
|
+
})
|
|
231
|
+
.handler(async (input: DockerComposeDownInput, ctx: ProcedureContext): Promise<DockerCommandOutput> => {
|
|
232
|
+
return dockerComposeDown(input, ctx);
|
|
233
|
+
})
|
|
234
|
+
.build();
|
|
235
|
+
|
|
236
|
+
// =============================================================================
|
|
237
|
+
// Registration
|
|
238
|
+
// =============================================================================
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* The module of this package, for `createRegistry()`: its procedures as data. Importing this
|
|
242
|
+
* file registers nothing. (`register.ts` registers the same procedures in the global registry.)
|
|
243
|
+
*/
|
|
244
|
+
export const dockerModule: ProcedureModule = defineModule("@procedures/docker", [
|
|
245
|
+
dockerRunProcedure,
|
|
246
|
+
dockerBuildProcedure,
|
|
247
|
+
dockerPullProcedure,
|
|
248
|
+
dockerExecProcedure,
|
|
249
|
+
dockerStopProcedure,
|
|
250
|
+
dockerRmProcedure,
|
|
251
|
+
dockerPsProcedure,
|
|
252
|
+
dockerLogsProcedure,
|
|
253
|
+
dockerComposeUpProcedure,
|
|
254
|
+
dockerComposeDownProcedure,
|
|
255
|
+
], [shellModule]);
|
|
256
|
+
|
|
257
|
+
export default dockerModule;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* This function registers the procedures of @procedures/docker, and of the modules that it requires, in
|
|
261
|
+
* a registry. The default is the global registry. Importing this file registers nothing: the
|
|
262
|
+
* `./register` entry starts this function (ARCHITECTURE-PROPOSALS-2026-10, P9).
|
|
263
|
+
*/
|
|
264
|
+
export function registerDockerProcedures(registry: ProcedureRegistry = PROCEDURE_REGISTRY): void {
|
|
265
|
+
registerModules(registry, [dockerModule]);
|
|
266
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.build procedure
|
|
3
|
+
*
|
|
4
|
+
* Build a Docker image.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
8
|
+
import { dockerArg, runDocker } from "./shared.js";
|
|
9
|
+
import type { DockerBuildInput, DockerCommandOutput } from "../../types.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Build a Docker image
|
|
13
|
+
*/
|
|
14
|
+
export async function dockerBuild(
|
|
15
|
+
input: DockerBuildInput,
|
|
16
|
+
ctx: ProcedureContext
|
|
17
|
+
): Promise<DockerCommandOutput> {
|
|
18
|
+
{
|
|
19
|
+
const args: string[] = ["build"];
|
|
20
|
+
|
|
21
|
+
// Add tag
|
|
22
|
+
args.push("-t", input.tag);
|
|
23
|
+
|
|
24
|
+
// Add dockerfile if specified
|
|
25
|
+
if (input.dockerfile) {
|
|
26
|
+
args.push("-f", input.dockerfile);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Add build args
|
|
30
|
+
if (input.buildArgs) {
|
|
31
|
+
for (const [key, value] of Object.entries(input.buildArgs)) {
|
|
32
|
+
args.push("--build-arg", `${key}=${value}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Add no-cache flag
|
|
37
|
+
if (input.noCache) {
|
|
38
|
+
args.push("--no-cache");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Add context
|
|
42
|
+
args.push(dockerArg("context", input.context));
|
|
43
|
+
|
|
44
|
+
return runDocker(args, input, ctx);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.compose.down procedure
|
|
3
|
+
*
|
|
4
|
+
* Stop services with docker compose.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
8
|
+
import { runDocker } from "./shared.js";
|
|
9
|
+
import type { DockerComposeDownInput, DockerCommandOutput } from "../../types.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Stop services with docker compose
|
|
13
|
+
*/
|
|
14
|
+
export async function dockerComposeDown(
|
|
15
|
+
input: DockerComposeDownInput,
|
|
16
|
+
ctx: ProcedureContext
|
|
17
|
+
): Promise<DockerCommandOutput> {
|
|
18
|
+
{
|
|
19
|
+
const args: string[] = ["compose"];
|
|
20
|
+
|
|
21
|
+
if (input.file) args.push("-f", input.file);
|
|
22
|
+
|
|
23
|
+
args.push("down");
|
|
24
|
+
|
|
25
|
+
if (input.volumes) args.push("-v");
|
|
26
|
+
if (input.removeOrphans) args.push("--remove-orphans");
|
|
27
|
+
if (input.rmi) args.push("--rmi", input.rmi);
|
|
28
|
+
|
|
29
|
+
return runDocker(args, input, ctx);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.exec procedure
|
|
3
|
+
*
|
|
4
|
+
* Execute command in a running container.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
8
|
+
import { dockerArg, runDocker, words } from "./shared.js";
|
|
9
|
+
import type { DockerExecInput, DockerCommandOutput } from "../../types.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Execute command in container
|
|
13
|
+
*/
|
|
14
|
+
export async function dockerExec(
|
|
15
|
+
input: DockerExecInput,
|
|
16
|
+
ctx: ProcedureContext
|
|
17
|
+
): Promise<DockerCommandOutput> {
|
|
18
|
+
{
|
|
19
|
+
const args: string[] = ["exec"];
|
|
20
|
+
|
|
21
|
+
if (input.interactive) args.push("-i");
|
|
22
|
+
if (input.tty) args.push("-t");
|
|
23
|
+
if (input.workdir) args.push("-w", input.workdir);
|
|
24
|
+
|
|
25
|
+
// Add environment variables
|
|
26
|
+
if (input.env) {
|
|
27
|
+
for (const [key, value] of Object.entries(input.env)) {
|
|
28
|
+
args.push("-e", `${key}=${value}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
args.push(dockerArg("container", input.container));
|
|
33
|
+
args.push(...words(input.command));
|
|
34
|
+
|
|
35
|
+
return runDocker(args, input, ctx);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { dockerRun } from "./run.js";
|
|
2
|
+
export { dockerBuild } from "./build.js";
|
|
3
|
+
export { dockerPull } from "./pull.js";
|
|
4
|
+
export { dockerExec } from "./exec.js";
|
|
5
|
+
export { dockerStop } from "./stop.js";
|
|
6
|
+
export { dockerRm } from "./rm.js";
|
|
7
|
+
export { dockerPs } from "./ps.js";
|
|
8
|
+
export { dockerLogs, type DockerLogItem } from "./logs.js";
|
|
9
|
+
export { dockerComposeUp } from "./up.js";
|
|
10
|
+
export { dockerComposeDown } from "./down.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.logs procedure
|
|
3
|
+
*
|
|
4
|
+
* Get container logs. With `follow`, the procedure is a stream: each log line is an item while
|
|
5
|
+
* the container runs. The stream ends when the reader stops or the signal aborts, and that ends
|
|
6
|
+
* `docker logs -f`. Before, `follow` waited for docker to end, so the call gave nothing until a
|
|
7
|
+
* timeout or a cancel.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
11
|
+
import { dockerArg, runDocker } from "./shared.js";
|
|
12
|
+
import type { DockerLogsInput, DockerCommandOutput, DockerLogItem } from "../../types.js";
|
|
13
|
+
|
|
14
|
+
// The type lives in types.ts, next to its output schema
|
|
15
|
+
export type { DockerLogItem };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get container logs: one value, or with `follow` a stream of lines
|
|
19
|
+
*/
|
|
20
|
+
export async function dockerLogs(
|
|
21
|
+
input: DockerLogsInput,
|
|
22
|
+
ctx: ProcedureContext
|
|
23
|
+
): Promise<DockerCommandOutput | AsyncGenerator<DockerLogItem, void, undefined>> {
|
|
24
|
+
const args: string[] = ["logs"];
|
|
25
|
+
|
|
26
|
+
if (input.follow) args.push("-f");
|
|
27
|
+
if (input.tail !== undefined) args.push("--tail", String(input.tail));
|
|
28
|
+
if (input.timestamps) args.push("-t");
|
|
29
|
+
|
|
30
|
+
// The guard runs before anything starts, also for a stream
|
|
31
|
+
args.push(dockerArg("container", input.container));
|
|
32
|
+
|
|
33
|
+
if (input.follow) {
|
|
34
|
+
return followLogs(args, input, ctx);
|
|
35
|
+
}
|
|
36
|
+
return runDocker(args, input, ctx);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The lines of `docker <args>` through shell.stream, which runs no shell and ends the program when the reader stops. */
|
|
40
|
+
async function* followLogs(
|
|
41
|
+
args: string[],
|
|
42
|
+
input: DockerLogsInput,
|
|
43
|
+
ctx: ProcedureContext
|
|
44
|
+
): AsyncGenerator<DockerLogItem, void, undefined> {
|
|
45
|
+
const shellInput: { command: string; args: string[]; cwd?: string; timeout?: number } = { command: "docker", args };
|
|
46
|
+
if (input.cwd !== undefined) shellInput.cwd = input.cwd;
|
|
47
|
+
if (input.timeout !== undefined) shellInput.timeout = input.timeout;
|
|
48
|
+
if (!ctx.client.stream) {
|
|
49
|
+
throw new Error("docker.logs with follow needs a host whose client can stream");
|
|
50
|
+
}
|
|
51
|
+
yield* ctx.client.stream<typeof shellInput, DockerLogItem>(["shell", "stream"], shellInput);
|
|
52
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.ps procedure
|
|
3
|
+
*
|
|
4
|
+
* List containers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
8
|
+
import { runDocker } from "./shared.js";
|
|
9
|
+
import type { DockerPsInput, DockerCommandOutput } from "../../types.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* List containers
|
|
13
|
+
*/
|
|
14
|
+
export async function dockerPs(
|
|
15
|
+
input: DockerPsInput,
|
|
16
|
+
ctx: ProcedureContext
|
|
17
|
+
): Promise<DockerCommandOutput> {
|
|
18
|
+
{
|
|
19
|
+
const args: string[] = ["ps"];
|
|
20
|
+
|
|
21
|
+
if (input.all) args.push("-a");
|
|
22
|
+
if (input.filter) args.push("--filter", input.filter);
|
|
23
|
+
if (input.format) args.push("--format", input.format);
|
|
24
|
+
|
|
25
|
+
return runDocker(args, input, ctx);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.pull procedure
|
|
3
|
+
*
|
|
4
|
+
* Pull a Docker image.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
8
|
+
import { dockerArg, runDocker } from "./shared.js";
|
|
9
|
+
import type { DockerPullInput, DockerCommandOutput } from "../../types.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pull a Docker image
|
|
13
|
+
*/
|
|
14
|
+
export async function dockerPull(
|
|
15
|
+
input: DockerPullInput,
|
|
16
|
+
ctx: ProcedureContext
|
|
17
|
+
): Promise<DockerCommandOutput> {
|
|
18
|
+
{
|
|
19
|
+
const imageWithTag = input.tag ? `${input.image}:${input.tag}` : input.image;
|
|
20
|
+
const args = ["pull", dockerArg("image", imageWithTag)];
|
|
21
|
+
return runDocker(args, input, ctx);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* docker.rm procedure
|
|
3
|
+
*
|
|
4
|
+
* Remove container(s).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
8
|
+
import { dockerArg, runDocker } from "./shared.js";
|
|
9
|
+
import type { DockerRmInput, DockerCommandOutput } from "../../types.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Remove container(s)
|
|
13
|
+
*/
|
|
14
|
+
export async function dockerRm(
|
|
15
|
+
input: DockerRmInput,
|
|
16
|
+
ctx: ProcedureContext
|
|
17
|
+
): Promise<DockerCommandOutput> {
|
|
18
|
+
{
|
|
19
|
+
const args: string[] = ["rm"];
|
|
20
|
+
|
|
21
|
+
if (input.force) args.push("-f");
|
|
22
|
+
if (input.volumes) args.push("-v");
|
|
23
|
+
|
|
24
|
+
args.push(...input.containers.map((c) => dockerArg("container", c)));
|
|
25
|
+
|
|
26
|
+
return runDocker(args, input, ctx);
|
|
27
|
+
}
|
|
28
|
+
}
|