@zgeoff/atc 3.2.0 → 3.3.1

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 (68) hide show
  1. package/README.md +6 -0
  2. package/package.json +4 -3
  3. package/src/build-own-daemon-process.ts +16 -0
  4. package/src/build-restart-failure.ts +24 -0
  5. package/src/cli.ts +96 -0
  6. package/src/client/boot-daemon.ts +5 -32
  7. package/src/collect-restart-env.ts +18 -0
  8. package/src/collect-restart-plan.ts +157 -0
  9. package/src/daemon/daemon.ts +7 -3
  10. package/src/daemon-process.ts +12 -0
  11. package/src/find-restart-unit.ts +45 -0
  12. package/src/format-restart-preflight.ts +74 -0
  13. package/src/format-restart-report.ts +45 -0
  14. package/src/is-daemon-command-line.ts +33 -0
  15. package/src/is-daemon-process.ts +33 -0
  16. package/src/parse-daemon-flags.ts +33 -0
  17. package/src/parse-mismatch-build.ts +19 -0
  18. package/src/parse-restart-result.ts +65 -0
  19. package/src/parse-systemd-unit.ts +25 -0
  20. package/src/read-daemon-process.ts +50 -0
  21. package/src/read-fleet-snapshot.ts +37 -0
  22. package/src/read-restart-result.ts +17 -0
  23. package/src/read-stored-fleet-file.ts +74 -0
  24. package/src/read-stored-rows.ts +36 -0
  25. package/src/remove-restart-result.ts +11 -0
  26. package/src/restart-daemon.ts +149 -0
  27. package/src/restart-plan.ts +33 -0
  28. package/src/run-daemon-restart-worker.ts +77 -0
  29. package/src/run-daemon-restart.ts +228 -0
  30. package/src/run-systemctl.ts +33 -0
  31. package/src/shared/build-atc-command.ts +13 -0
  32. package/src/shared/config.ts +5 -0
  33. package/src/shared/find-pid-file-pid.ts +15 -0
  34. package/src/shared/get-build.ts +4 -3
  35. package/src/shared/is-process-alive.ts +21 -0
  36. package/src/shared/spawn-atc-detached.ts +34 -0
  37. package/src/start-replacement-daemon.ts +31 -0
  38. package/src/stop-daemon-process.ts +46 -0
  39. package/src/store/state-store.ts +2 -2
  40. package/src/test-utils/can-bind-addresses.ts +19 -0
  41. package/src/test-utils/create-migrated-state-db.ts +38 -0
  42. package/src/test-utils/env-originals.ts +6 -0
  43. package/src/test-utils/fixture-dir-provider.ts +131 -0
  44. package/src/test-utils/fixture-imp-port.ts +1692 -0
  45. package/src/test-utils/get-agent-entry.ts +17 -0
  46. package/src/test-utils/get-gateway-config.ts +18 -0
  47. package/src/test-utils/isolate-home.ts +60 -0
  48. package/src/test-utils/read-json-record.ts +20 -0
  49. package/src/test-utils/remove-env-overrides.ts +18 -0
  50. package/src/test-utils/run-legacy-daemon.ts +38 -0
  51. package/src/test-utils/run-listener-daemon.ts +51 -0
  52. package/src/test-utils/run-mcp-authorization.ts +118 -0
  53. package/src/test-utils/run-source-daemon.ts +110 -0
  54. package/src/test-utils/setup-fake-systemd.ts +125 -0
  55. package/src/test-utils/setup-mcp-http.ts +126 -0
  56. package/src/test-utils/setup-temp-dir.ts +33 -0
  57. package/src/test-utils/spawn-named-session.ts +27 -0
  58. package/src/test-utils/start-cut-proxy.ts +175 -0
  59. package/src/test-utils/start-git-http-server.ts +102 -0
  60. package/src/test-utils/start-legacy-daemon.ts +111 -0
  61. package/src/test-utils/subscribe-to-socket-lines.ts +60 -0
  62. package/src/test-utils/update-env.ts +19 -0
  63. package/src/test-utils/wait-for.ts +38 -0
  64. package/src/verify-restored-fleet.ts +191 -0
  65. package/src/wait-for-replacement.ts +112 -0
  66. package/src/write-restart-result.ts +17 -0
  67. /package/src/{daemon → shared}/claim-daemon-lock.ts +0 -0
  68. /package/src/{daemon → shared}/load-listener-tokens.ts +0 -0
@@ -0,0 +1,131 @@
1
+ import { mkdir } from 'node:fs/promises';
2
+ import type {
3
+ CommandResult,
4
+ CommandSpec,
5
+ ExecutionCapabilities,
6
+ ExecutionCapability,
7
+ ExecutionProvider,
8
+ HarnessHandle,
9
+ HarnessSpec,
10
+ } from '../daemon/execution-provider';
11
+ import { LocalPTYProvider } from '../daemon/local-pty-provider';
12
+
13
+ // One provider operation, in the order the daemon called it.
14
+ type FixtureCall =
15
+ | { readonly op: 'transfer'; readonly dir: string; readonly bytes: number }
16
+ | { readonly op: 'run'; readonly argv: readonly string[]; readonly cwd: string };
17
+
18
+ interface FixtureDirOptions {
19
+ // Capabilities the provider declares as missing.
20
+ readonly lacking?: readonly ExecutionCapability[];
21
+
22
+ // Runs once an archive is unpacked, before the transfer resolves, so a
23
+ // test can change what landed on the host or hold the transfer open.
24
+ readonly afterTransfer?: (dir: string) => Promise<void>;
25
+ }
26
+
27
+ /**
28
+ * An execution provider for tests whose host is a directory tree the test
29
+ * owns: a transfer unpacks the archive with tar into the directory it is
30
+ * given, and a command runs as a child process in its working directory.
31
+ * Paths pass through unchanged, so a test points them into its own temp
32
+ * tree. Every transfer and command is recorded in `calls`. Harnesses start
33
+ * on a local pseudo-terminal, and each one's spec is recorded in
34
+ * `harnesses`.
35
+ */
36
+ export class FixtureDirProvider implements ExecutionProvider {
37
+ readonly kind = 'fixture-dir';
38
+
39
+ readonly remote = false;
40
+
41
+ readonly capabilities: ExecutionCapabilities;
42
+
43
+ readonly calls: FixtureCall[] = [];
44
+
45
+ // Every harness the provider started, as the daemon specified it.
46
+ readonly harnesses: HarnessSpec[] = [];
47
+
48
+ private readonly afterTransfer: ((dir: string) => Promise<void>) | undefined;
49
+
50
+ private readonly terminals = new LocalPTYProvider();
51
+
52
+ constructor(options: FixtureDirOptions = {}) {
53
+ const lacking = new Set(options.lacking);
54
+
55
+ this.capabilities = {
56
+ spawn: !lacking.has('spawn'),
57
+ attach: !lacking.has('attach'),
58
+ input: !lacking.has('input'),
59
+ resize: !lacking.has('resize'),
60
+ kill: !lacking.has('kill'),
61
+ transfer: !lacking.has('transfer'),
62
+ run: !lacking.has('run'),
63
+ headless: false,
64
+ suspend: false,
65
+ destroy: false,
66
+ };
67
+
68
+ this.afterTransfer = options.afterTransfer;
69
+ }
70
+
71
+ readonly prepareHost = (): Promise<void> => Promise.resolve();
72
+
73
+ readonly spawnHarness = (spec: HarnessSpec): HarnessHandle => {
74
+ this.harnesses.push(spec);
75
+
76
+ return this.terminals.spawnHarness(spec);
77
+ };
78
+
79
+ // oxlint-disable-next-line prefer-readonly-parameter-types -- archive bytes have no readonly form
80
+ readonly transferArchive = async (archive: Uint8Array, dir: string): Promise<void> => {
81
+ this.calls.push({ op: 'transfer', dir, bytes: archive.byteLength });
82
+
83
+ await mkdir(dir, { recursive: true });
84
+
85
+ const proc = Bun.spawn(['tar', '-x', '-f', '-', '-C', dir], {
86
+ stdin: archive,
87
+ stdout: 'ignore',
88
+ stderr: 'pipe',
89
+ });
90
+
91
+ const [stderr, exitCode] = await Promise.all([new Response(proc.stderr).text(), proc.exited]);
92
+
93
+ if (exitCode !== 0) {
94
+ throw new Error(`tar exited ${exitCode} unpacking into ${dir}: ${stderr}`);
95
+ }
96
+
97
+ await this.afterTransfer?.(dir);
98
+ };
99
+
100
+ readonly runCommand = async (spec: CommandSpec): Promise<CommandResult> => {
101
+ this.calls.push({ op: 'run', argv: spec.argv, cwd: spec.cwd });
102
+
103
+ // The command inherits the daemon's environment as it stands now, which
104
+ // a spawn without an env option would take only from process start.
105
+ const proc = Bun.spawn([...spec.argv], {
106
+ cwd: spec.cwd,
107
+ env: process.env,
108
+ stdin: 'ignore',
109
+ stdout: 'pipe',
110
+ stderr: 'pipe',
111
+ });
112
+
113
+ const [stdout, stderr, exitCode] = await Promise.all([
114
+ new Response(proc.stdout).text(),
115
+ new Response(proc.stderr).text(),
116
+ proc.exited,
117
+ ]);
118
+
119
+ return { exitCode, stdout, stderr };
120
+ };
121
+
122
+ // The host is the test's own directory tree, which neither sleeps nor
123
+ // goes away.
124
+ readonly suspendHost = (host: string): Promise<void> =>
125
+ Promise.reject(new Error(`the fixture-dir provider cannot suspend host ${host}`));
126
+
127
+ readonly destroyHost = (host: string): Promise<void> =>
128
+ Promise.reject(new Error(`the fixture-dir provider cannot destroy host ${host}`));
129
+
130
+ readonly dispose = (): void => {};
131
+ }