pipeline-worker 0.1.20 → 0.1.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/README.md +4 -0
- package/dist/agent/claude.js +87 -65
- package/dist/agent/claude.js.map +1 -1
- package/dist/agent/copilot.js +19 -14
- package/dist/agent/copilot.js.map +1 -1
- package/dist/cli.js +48 -48
- package/dist/cli.js.map +1 -1
- package/dist/config/detectChecks.js +30 -15
- package/dist/config/detectChecks.js.map +1 -1
- package/dist/config/loader.js +30 -15
- package/dist/config/loader.js.map +1 -1
- package/dist/forge/github.d.ts +0 -7
- package/dist/forge/github.js +13 -19
- package/dist/forge/github.js.map +1 -1
- package/dist/forge/gitlab.d.ts +0 -6
- package/dist/forge/gitlab.js +8 -17
- package/dist/forge/gitlab.js.map +1 -1
- package/dist/forge/shared.d.ts +9 -0
- package/dist/forge/shared.js +27 -0
- package/dist/forge/shared.js.map +1 -0
- package/dist/git/commit.d.ts +0 -1
- package/dist/git/commit.js +0 -4
- package/dist/git/commit.js.map +1 -1
- package/dist/git/resolveProjectPath.d.ts +0 -6
- package/dist/git/resolveProjectPath.js +1 -1
- package/dist/git/resolveProjectPath.js.map +1 -1
- package/dist/git/worktree.d.ts +0 -7
- package/dist/git/worktree.js +42 -25
- package/dist/git/worktree.js.map +1 -1
- package/dist/mcp/server.js +8 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/process/signalCleanup.d.ts +15 -0
- package/dist/process/signalCleanup.js +19 -0
- package/dist/process/signalCleanup.js.map +1 -0
- package/dist/state/lock.d.ts +0 -6
- package/dist/state/lock.js +36 -21
- package/dist/state/lock.js.map +1 -1
- package/dist/state/runState.js +1 -0
- package/dist/state/runState.js.map +1 -1
- package/dist/toon/envelope.js +30 -17
- package/dist/toon/envelope.js.map +1 -1
- package/dist/ui/sessions.js +26 -8
- package/dist/ui/sessions.js.map +1 -1
- package/dist/ui/steps.d.ts +2 -13
- package/dist/ui/steps.js +7 -1
- package/dist/ui/steps.js.map +1 -1
- package/dist/version/autoUpdate.d.ts +27 -0
- package/dist/version/autoUpdate.js +75 -0
- package/dist/version/autoUpdate.js.map +1 -0
- package/dist/workflow/orchestrate.js +130 -96
- package/dist/workflow/orchestrate.js.map +1 -1
- package/dist/workflow/runChecks.js +2 -0
- package/dist/workflow/runChecks.js.map +1 -1
- package/dist/workflow/updateChangelog.js +43 -28
- package/dist/workflow/updateChangelog.js.map +1 -1
- package/dist/workflow/watchPipeline.d.ts +0 -19
- package/dist/workflow/watchPipeline.js +115 -87
- package/dist/workflow/watchPipeline.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ Polling is plain REST and costs zero agent tokens; the agent is invoked only whe
|
|
|
28
28
|
npm install -g pipeline-worker
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
This installs two equivalent commands, `pipeline-worker` and the shorter `pw` — use whichever you prefer (e.g. `pw run --ticket PROJ-123`).
|
|
32
|
+
|
|
31
33
|
## Quick start
|
|
32
34
|
|
|
33
35
|
Set these once in your shell profile (`~/.zshrc` / `~/.bashrc`) and every
|
|
@@ -122,6 +124,8 @@ A stage with no command (`—`) is skipped. If no toolchain is detected and no c
|
|
|
122
124
|
| `pipeline-worker sessions [--branch <name>]` | List every persisted run in this repo, or show one run's full step-by-step timeline |
|
|
123
125
|
| `pipeline-worker update` | Install the latest release from npm (`npm install -g pipeline-worker@latest`) |
|
|
124
126
|
|
|
127
|
+
Before doing any work, `pipeline-worker run` checks npm for a newer published version and installs it automatically if the locally installed one is out of date (the update takes effect on the next run). This check is best-effort: if npm is unreachable or the install fails, the run proceeds anyway on whatever version is already installed.
|
|
128
|
+
|
|
125
129
|
Every time a run hands a turn to Claude Code or the Copilot CLI (resolving a conflict, capturing intent, fixing a failed pipeline), the output includes that turn's duration and an `agent session: <id>` line — `claude --resume <id>` (or `copilot --resume <id>`) opens the same session later to see exactly what it did and why. Copilot CLI has no way to report the session id it picked for itself, so pipeline-worker assigns one via `--name` instead and reports that.
|
|
126
130
|
|
|
127
131
|
## How the fix loop stays bounded
|
package/dist/agent/claude.js
CHANGED
|
@@ -54,82 +54,104 @@ function formatStreamBlock(label, raw) {
|
|
|
54
54
|
const dropped = trimmed.length - MAX_ERROR_OUTPUT_CHARS;
|
|
55
55
|
return `--- ${label} ---\n[... ${dropped} chars truncated, showing last ${MAX_ERROR_OUTPUT_CHARS} ...]\n${trimmed.slice(-MAX_ERROR_OUTPUT_CHARS)}`;
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
function describeCause(err) {
|
|
58
|
+
if (err.signal)
|
|
59
|
+
return `killed by signal ${err.signal}`;
|
|
60
|
+
if (err.code !== undefined && err.code !== null)
|
|
61
|
+
return `exited with code ${err.code}`;
|
|
62
|
+
return 'failed with no exit code or signal reported';
|
|
63
|
+
}
|
|
64
|
+
function hasMeaningfulOutput(err) {
|
|
65
|
+
return !!(err.stdout && err.stdout.trim().length > 0) || !!(err.stderr && err.stderr.trim().length > 0);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Falls back to the underlying Node error message only when neither captured
|
|
69
|
+
* stream has content — typical of spawn-time failures like ENOENT, where the
|
|
70
|
+
* message is the only context we have.
|
|
71
|
+
*/
|
|
72
|
+
function underlyingMessageLine(err) {
|
|
73
|
+
if (err.message && err.message.trim().length > 0 && !hasMeaningfulOutput(err)) {
|
|
74
|
+
return `(underlying: ${err.message.trim()})`;
|
|
67
75
|
}
|
|
68
|
-
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
export function formatProcessError(err) {
|
|
79
|
+
const lines = [`claude ${describeCause(err)}.`];
|
|
69
80
|
for (const [label, raw] of [['stdout', err.stdout], ['stderr', err.stderr]]) {
|
|
70
81
|
const block = formatStreamBlock(label, raw);
|
|
71
82
|
if (block)
|
|
72
83
|
lines.push(block);
|
|
73
84
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const hasStdout = !!(err.stdout && err.stdout.trim().length > 0);
|
|
78
|
-
const hasStderr = !!(err.stderr && err.stderr.trim().length > 0);
|
|
79
|
-
if (err.message && err.message.trim().length > 0 && !hasStdout && !hasStderr) {
|
|
80
|
-
lines.push(`(underlying: ${err.message.trim()})`);
|
|
81
|
-
}
|
|
85
|
+
const underlying = underlyingMessageLine(err);
|
|
86
|
+
if (underlying)
|
|
87
|
+
lines.push(underlying);
|
|
82
88
|
return lines.join('\n');
|
|
83
89
|
}
|
|
90
|
+
// fallow-ignore-next-line complexity
|
|
91
|
+
function buildClaudeArgs(opts) {
|
|
92
|
+
const args = [
|
|
93
|
+
'-p',
|
|
94
|
+
'--output-format', 'json',
|
|
95
|
+
'--permission-mode', opts.permissionMode ?? 'acceptEdits',
|
|
96
|
+
];
|
|
97
|
+
if (opts.jsonSchema) {
|
|
98
|
+
args.push('--json-schema', JSON.stringify(opts.jsonSchema));
|
|
99
|
+
}
|
|
100
|
+
if (opts.allowedTools?.length) {
|
|
101
|
+
args.push('--allowedTools', ...opts.allowedTools);
|
|
102
|
+
}
|
|
103
|
+
if (opts.mcpConfigPath) {
|
|
104
|
+
args.push('--mcp-config', opts.mcpConfigPath);
|
|
105
|
+
}
|
|
106
|
+
if (opts.model) {
|
|
107
|
+
args.push('--model', opts.model);
|
|
108
|
+
}
|
|
109
|
+
return args;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Spawns `claude` and pipes the prompt to its stdin. Kept as one atomic
|
|
113
|
+
* function: `.child.stdin` must be grabbed synchronously between creating
|
|
114
|
+
* the execFileAsync invocation and awaiting it, so this sequence can't be
|
|
115
|
+
* split across function boundaries without breaking that ordering.
|
|
116
|
+
*/
|
|
117
|
+
async function runClaudeProcess(args, opts) {
|
|
118
|
+
try {
|
|
119
|
+
const invocation = execFileAsync('claude', args, {
|
|
120
|
+
cwd: opts.cwd,
|
|
121
|
+
timeout: AGENT_INVOKE_TIMEOUT_MS,
|
|
122
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
123
|
+
});
|
|
124
|
+
// stdin is always a pipe here since stdio isn't overridden in execFileAsync's options.
|
|
125
|
+
writePromptToStdin(invocation.child.stdin, opts.prompt);
|
|
126
|
+
const result = await invocation;
|
|
127
|
+
return result.stdout;
|
|
128
|
+
}
|
|
129
|
+
catch (rawErr) {
|
|
130
|
+
const err = rawErr;
|
|
131
|
+
throw new Error(formatProcessError(err));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function parseClaudeResult(stdout, start) {
|
|
135
|
+
try {
|
|
136
|
+
// duration_ms/session_id come straight from the CLI's own JSON envelope
|
|
137
|
+
// (see the module comment's `claude -p --output-format json` sample);
|
|
138
|
+
// falling back to our own wall-clock reading only covers the
|
|
139
|
+
// never-observed case where that envelope omits duration_ms.
|
|
140
|
+
const parsed = JSON.parse(stdout);
|
|
141
|
+
return { text: parsed.result ?? stdout, raw: parsed, sessionId: parsed.session_id, durationMs: parsed.duration_ms ?? Date.now() - start };
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// --output-format json should always produce parseable JSON; fall back
|
|
145
|
+
// to the raw stream rather than throwing, since the invocation itself succeeded.
|
|
146
|
+
return { text: stdout, durationMs: Date.now() - start };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
84
149
|
export const claudeAdapter = {
|
|
85
150
|
async invoke(opts) {
|
|
86
|
-
const args =
|
|
87
|
-
'-p',
|
|
88
|
-
'--output-format', 'json',
|
|
89
|
-
'--permission-mode', opts.permissionMode ?? 'acceptEdits',
|
|
90
|
-
];
|
|
91
|
-
if (opts.jsonSchema) {
|
|
92
|
-
args.push('--json-schema', JSON.stringify(opts.jsonSchema));
|
|
93
|
-
}
|
|
94
|
-
if (opts.allowedTools?.length) {
|
|
95
|
-
args.push('--allowedTools', ...opts.allowedTools);
|
|
96
|
-
}
|
|
97
|
-
if (opts.mcpConfigPath) {
|
|
98
|
-
args.push('--mcp-config', opts.mcpConfigPath);
|
|
99
|
-
}
|
|
100
|
-
if (opts.model) {
|
|
101
|
-
args.push('--model', opts.model);
|
|
102
|
-
}
|
|
151
|
+
const args = buildClaudeArgs(opts);
|
|
103
152
|
const start = Date.now();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const invocation = execFileAsync('claude', args, {
|
|
107
|
-
cwd: opts.cwd,
|
|
108
|
-
timeout: AGENT_INVOKE_TIMEOUT_MS,
|
|
109
|
-
maxBuffer: 64 * 1024 * 1024,
|
|
110
|
-
});
|
|
111
|
-
// stdin is always a pipe here since stdio isn't overridden in execFileAsync's options.
|
|
112
|
-
writePromptToStdin(invocation.child.stdin, opts.prompt);
|
|
113
|
-
const result = await invocation;
|
|
114
|
-
stdout = result.stdout;
|
|
115
|
-
}
|
|
116
|
-
catch (rawErr) {
|
|
117
|
-
const err = rawErr;
|
|
118
|
-
throw new Error(formatProcessError(err));
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
// duration_ms/session_id come straight from the CLI's own JSON envelope
|
|
122
|
-
// (see the module comment's `claude -p --output-format json` sample);
|
|
123
|
-
// falling back to our own wall-clock reading only covers the
|
|
124
|
-
// never-observed case where that envelope omits duration_ms.
|
|
125
|
-
const parsed = JSON.parse(stdout);
|
|
126
|
-
return { text: parsed.result ?? stdout, raw: parsed, sessionId: parsed.session_id, durationMs: parsed.duration_ms ?? Date.now() - start };
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
// --output-format json should always produce parseable JSON; fall back
|
|
130
|
-
// to the raw stream rather than throwing, since the invocation itself succeeded.
|
|
131
|
-
return { text: stdout, durationMs: Date.now() - start };
|
|
132
|
-
}
|
|
153
|
+
const stdout = await runClaudeProcess(args, opts);
|
|
154
|
+
return parseClaudeResult(stdout, start);
|
|
133
155
|
},
|
|
134
156
|
};
|
|
135
157
|
//# sourceMappingURL=claude.js.map
|
package/dist/agent/claude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/agent/claude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAsE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAWpC;;;;GAIG;AACH;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAa,EAAE,GAAuB;IAC/D,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;QAC7C,OAAO,OAAO,KAAK,SAAS,OAAO,EAAE,CAAC;IACxC,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,sBAAsB,CAAC;IACxD,OAAO,OAAO,KAAK,cAAc,OAAO,kCAAkC,sBAAsB,UAAU,OAAO,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC;AACrJ,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/agent/claude.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/copilot.js
CHANGED
|
@@ -46,22 +46,27 @@ function extractJsonObject(text) {
|
|
|
46
46
|
const end = text.lastIndexOf('}');
|
|
47
47
|
return start !== -1 && end > start ? text.slice(start, end + 1) : text;
|
|
48
48
|
}
|
|
49
|
+
/** Embeds a JSON-Schema instruction in the prompt text — Copilot CLI has no native structured-output flag (see module comment). */
|
|
50
|
+
function buildCopilotPrompt(prompt, jsonSchema) {
|
|
51
|
+
if (!jsonSchema)
|
|
52
|
+
return prompt;
|
|
53
|
+
return `${prompt}\n\nRespond with ONLY a single JSON object matching this JSON Schema — no prose, no code fences:\n${JSON.stringify(jsonSchema)}`;
|
|
54
|
+
}
|
|
55
|
+
/** Warns about the two AgentInvokeOptions Copilot CLI has no per-invocation flag for (see module comment). */
|
|
56
|
+
function warnUnsupportedOptions(opts) {
|
|
57
|
+
if (opts.mcpConfigPath) {
|
|
58
|
+
console.error('pipeline-worker: copilot CLI has no per-invocation MCP config flag; ignoring it. ' +
|
|
59
|
+
'Register the server in ~/.copilot/mcp-config.json to give copilot forge access.');
|
|
60
|
+
}
|
|
61
|
+
if (opts.model) {
|
|
62
|
+
console.error(`pipeline-worker: copilot CLI has no per-invocation model flag; ignoring the configured model "${opts.model}". ` +
|
|
63
|
+
"Switch copilot's model via its own /model command or config instead.");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
49
66
|
export const copilotAdapter = {
|
|
50
67
|
async invoke(opts) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
prompt +=
|
|
54
|
-
'\n\nRespond with ONLY a single JSON object matching this JSON Schema — no prose, no code fences:\n' +
|
|
55
|
-
JSON.stringify(opts.jsonSchema);
|
|
56
|
-
}
|
|
57
|
-
if (opts.mcpConfigPath) {
|
|
58
|
-
console.error('pipeline-worker: copilot CLI has no per-invocation MCP config flag; ignoring it. ' +
|
|
59
|
-
'Register the server in ~/.copilot/mcp-config.json to give copilot forge access.');
|
|
60
|
-
}
|
|
61
|
-
if (opts.model) {
|
|
62
|
-
console.error(`pipeline-worker: copilot CLI has no per-invocation model flag; ignoring the configured model "${opts.model}". ` +
|
|
63
|
-
"Switch copilot's model via its own /model command or config instead.");
|
|
64
|
-
}
|
|
68
|
+
const prompt = buildCopilotPrompt(opts.prompt, opts.jsonSchema);
|
|
69
|
+
warnUnsupportedOptions(opts);
|
|
65
70
|
const sessionName = `pipeline-worker-${randomUUID()}`;
|
|
66
71
|
const start = Date.now();
|
|
67
72
|
const invocation = execFileAsync('copilot', ['-s', '--no-ask-user', '--allow-all-tools', '--allow-all-paths', '--name', sessionName], {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agent/copilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAsE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,0FAA0F;AAC1F,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzE,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agent/copilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAsE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,0FAA0F;AAC1F,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzE,CAAC;AAED,mIAAmI;AACnI,SAAS,kBAAkB,CAAC,MAAc,EAAE,UAAmB;IAC7D,IAAI,CAAC,UAAU;QAAE,OAAO,MAAM,CAAC;IAC/B,OAAO,GAAG,MAAM,qGAAqG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;AACpJ,CAAC;AAED,8GAA8G;AAC9G,SAAS,sBAAsB,CAAC,IAAwB;IACtD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CACX,mFAAmF;YACjF,iFAAiF,CACpF,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,iGAAiG,IAAI,CAAC,KAAK,KAAK;YAC9G,sEAAsE,CACzE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,KAAK,CAAC,MAAM,CAAC,IAAwB;QACnC,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,WAAW,GAAG,mBAAmB,UAAU,EAAE,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,aAAa,CAC9B,SAAS,EACT,CAAC,IAAI,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,WAAW,CAAC,EACxF;YACE,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,OAAO,EAAE,uBAAuB;YAChC,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CACF,CAAC;QACF,uFAAuF;QACvF,kBAAkB,CAAC,UAAU,CAAC,KAAK,CAAC,KAAM,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC;QAEpC,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE;YACjE,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC/B,CAAC;IACJ,CAAC;CACF,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { spawn } from 'node:child_process';
|
|
6
5
|
import { Command } from 'commander';
|
|
6
|
+
import { ensureLatestVersion, installVersion } from './version/autoUpdate.js';
|
|
7
7
|
import { runWorkflow } from './workflow/orchestrate.js';
|
|
8
8
|
import { watchPipeline } from './workflow/watchPipeline.js';
|
|
9
9
|
import { startServer } from './mcp/server.js';
|
|
@@ -14,6 +14,45 @@ import { loadRunState, listRunStates, recordEvent } from './state/runState.js';
|
|
|
14
14
|
import { printSessionList, printSessionDetail } from './ui/sessions.js';
|
|
15
15
|
import { isWorktreeOnBranch, checkoutExistingBranch, removeWorktree } from './git/worktree.js';
|
|
16
16
|
import { buildEnvelope, errorEnvelope } from './toon/envelope.js';
|
|
17
|
+
import { makeIdempotentCleanup, registerExitSignals } from './process/signalCleanup.js';
|
|
18
|
+
/** Loads persisted state for `branch`, or prints an error and exits(1) if there's nothing resumable (no state file, or no MR/PR recorded yet). */
|
|
19
|
+
function loadResumableState(repoRoot, branch) {
|
|
20
|
+
const state = loadRunState(repoRoot, branch);
|
|
21
|
+
if (!state || state.mrIid === undefined) {
|
|
22
|
+
console.error(`pipeline-worker: no resumable run found for branch ${branch} (no merge request recorded yet).`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
return state;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The worktree from the crashed run is almost always already gone by this
|
|
29
|
+
* point (orchestrate.ts's `finally` removes it on any exception, and on
|
|
30
|
+
* SIGINT/SIGTERM) — reuse it only in the narrow case it survived (e.g. a
|
|
31
|
+
* SIGKILL), otherwise recreate it from the branch's current state on origin.
|
|
32
|
+
*/
|
|
33
|
+
async function resolveResumeWorktree(repoRoot, state) {
|
|
34
|
+
const worktreePath = (await isWorktreeOnBranch(state.worktreePath, state.branch))
|
|
35
|
+
? state.worktreePath
|
|
36
|
+
: await checkoutExistingBranch(repoRoot, state.branch);
|
|
37
|
+
if (worktreePath !== state.worktreePath) {
|
|
38
|
+
state.worktreePath = worktreePath;
|
|
39
|
+
recordEvent(repoRoot, state, `Recreated worktree at ${worktreePath}`);
|
|
40
|
+
}
|
|
41
|
+
return worktreePath;
|
|
42
|
+
}
|
|
43
|
+
async function runResumeWatch(forge, config, agent, worktreePath, state, repoRoot, cleanup) {
|
|
44
|
+
try {
|
|
45
|
+
await watchPipeline(forge, config, agent, worktreePath, state.branch, state.targetBranch, state.mrIid, state, repoRoot);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
+
recordEvent(repoRoot, state, `Resume failed: ${message}`, 'error');
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await cleanup();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
17
56
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
57
|
const pkg = JSON.parse(readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
|
19
58
|
const program = new Command();
|
|
@@ -25,6 +64,7 @@ program
|
|
|
25
64
|
.option('--ticket <id>', 'ticket/issue id to interpolate into the configured branchPattern\'s {ticket} placeholder')
|
|
26
65
|
.action(async (opts) => {
|
|
27
66
|
try {
|
|
67
|
+
await ensureLatestVersion(pkg.name, pkg.version);
|
|
28
68
|
await runWorkflow(process.cwd(), { ticket: opts.ticket });
|
|
29
69
|
}
|
|
30
70
|
catch (error) {
|
|
@@ -51,49 +91,16 @@ program
|
|
|
51
91
|
.action(async (opts) => {
|
|
52
92
|
try {
|
|
53
93
|
const repoRoot = process.cwd();
|
|
54
|
-
const state =
|
|
55
|
-
if (!state || state.mrIid === undefined) {
|
|
56
|
-
console.error(`pipeline-worker: no resumable run found for branch ${opts.branch} (no merge request recorded yet).`);
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
94
|
+
const state = loadResumableState(repoRoot, opts.branch);
|
|
59
95
|
const config = loadConfig(repoRoot);
|
|
60
96
|
const forge = createForge(config);
|
|
61
97
|
const agent = selectAgent(config);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// survived (e.g. a SIGKILL), otherwise recreate it from the branch's
|
|
66
|
-
// current state on origin.
|
|
67
|
-
const worktreePath = (await isWorktreeOnBranch(state.worktreePath, state.branch))
|
|
68
|
-
? state.worktreePath
|
|
69
|
-
: await checkoutExistingBranch(repoRoot, state.branch);
|
|
70
|
-
if (worktreePath !== state.worktreePath) {
|
|
71
|
-
state.worktreePath = worktreePath;
|
|
72
|
-
recordEvent(repoRoot, state, `Recreated worktree at ${worktreePath}`);
|
|
73
|
-
}
|
|
74
|
-
let cleanedUp = false;
|
|
75
|
-
const cleanup = async () => {
|
|
76
|
-
if (cleanedUp)
|
|
77
|
-
return;
|
|
78
|
-
cleanedUp = true;
|
|
79
|
-
await removeWorktree(repoRoot, worktreePath);
|
|
80
|
-
};
|
|
81
|
-
const onSignal = (exitCode) => {
|
|
98
|
+
const worktreePath = await resolveResumeWorktree(repoRoot, state);
|
|
99
|
+
const { cleanup } = makeIdempotentCleanup(() => removeWorktree(repoRoot, worktreePath));
|
|
100
|
+
registerExitSignals((exitCode) => {
|
|
82
101
|
void cleanup().then(() => process.exit(exitCode));
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
process.once('SIGTERM', () => onSignal(143));
|
|
86
|
-
try {
|
|
87
|
-
await watchPipeline(forge, config, agent, worktreePath, state.branch, state.targetBranch, state.mrIid, state, repoRoot);
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
-
recordEvent(repoRoot, state, `Resume failed: ${message}`, 'error');
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
finally {
|
|
95
|
-
await cleanup();
|
|
96
|
-
}
|
|
102
|
+
});
|
|
103
|
+
await runResumeWatch(forge, config, agent, worktreePath, state, repoRoot, cleanup);
|
|
97
104
|
console.log(`pipeline-worker: resumed run finished with phase "${state.phase}".`);
|
|
98
105
|
}
|
|
99
106
|
catch (error) {
|
|
@@ -137,14 +144,7 @@ program
|
|
|
137
144
|
.action(async () => {
|
|
138
145
|
console.log(`pipeline-worker: currently v${pkg.version}, installing latest via npm install -g ${pkg.name}@latest ...`);
|
|
139
146
|
try {
|
|
140
|
-
await
|
|
141
|
-
// stdio: 'inherit' streams npm's own progress/errors straight to the
|
|
142
|
-
// user's terminal rather than buffering it — an install can take a
|
|
143
|
-
// while and users expect to see npm's usual output live.
|
|
144
|
-
const npm = spawn('npm', ['install', '-g', `${pkg.name}@latest`], { stdio: 'inherit' });
|
|
145
|
-
npm.on('error', reject);
|
|
146
|
-
npm.on('exit', (code) => (code === 0 ? resolve() : reject(new Error(`npm install exited with code ${code}`))));
|
|
147
|
-
});
|
|
147
|
+
await installVersion(pkg.name, 'latest');
|
|
148
148
|
}
|
|
149
149
|
catch (error) {
|
|
150
150
|
console.error('pipeline-worker update failed:', error instanceof Error ? error.message : error);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ const DOTNET_SOLUTION_SUFFIXES = ['.sln', '.slnx'];
|
|
|
11
11
|
const DOTNET_PROJECT_SUFFIXES = [...DOTNET_SOLUTION_SUFFIXES, '.csproj', '.fsproj', '.vbproj'];
|
|
12
12
|
const PYTHON_MARKERS = ['pyproject.toml', 'setup.py', 'requirements.txt'];
|
|
13
13
|
/** Maps each stage to `npm run <script>` only for scripts the repo declares. */
|
|
14
|
+
// fallow-ignore-next-line complexity
|
|
14
15
|
function detectNode(repoRoot) {
|
|
15
16
|
let scripts;
|
|
16
17
|
try {
|
|
@@ -34,6 +35,7 @@ function detectNode(repoRoot) {
|
|
|
34
35
|
* Detected via a .csharpierignore file at the root OR a 'csharpier' entry
|
|
35
36
|
* in .config/dotnet-tools.json (the standard local tools manifest).
|
|
36
37
|
*/
|
|
38
|
+
// fallow-ignore-next-line complexity
|
|
37
39
|
function hasCsharpier(repoRoot) {
|
|
38
40
|
if (existsSync(join(repoRoot, '.csharpierignore')))
|
|
39
41
|
return true;
|
|
@@ -63,33 +65,38 @@ function detectDotnet(repoRoot, slnSubdir) {
|
|
|
63
65
|
const test = existsSync(join(repoRoot, 'run-tests')) ? './run-tests Unit' : 'dotnet test';
|
|
64
66
|
return { language: 'dotnet', build, lint, test };
|
|
65
67
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return detectNode(repoRoot);
|
|
68
|
+
/** .sln/.csproj directly at the repo root. */
|
|
69
|
+
function detectDotnetAtRoot(repoRoot) {
|
|
69
70
|
let rootEntries = [];
|
|
70
71
|
try {
|
|
71
72
|
rootEntries = readdirSync(repoRoot);
|
|
72
73
|
}
|
|
73
74
|
catch {
|
|
74
75
|
// Unreadable root: fall through to unknown, honoring loader.ts's never-throw contract.
|
|
76
|
+
return undefined;
|
|
75
77
|
}
|
|
76
|
-
// .sln/.csproj at the repo root
|
|
77
78
|
if (rootEntries.some((name) => DOTNET_PROJECT_SUFFIXES.some((suffix) => name.endsWith(suffix)))) {
|
|
78
79
|
return detectDotnet(repoRoot);
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
/** .sln in a src/ subdirectory — a common layout where source lives one level down. */
|
|
84
|
+
function detectDotnetInSrc(repoRoot) {
|
|
81
85
|
const srcDir = join(repoRoot, 'src');
|
|
82
|
-
if (existsSync(srcDir))
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
// Ignore readdir errors on the src/ subdirectory.
|
|
86
|
+
if (!existsSync(srcDir))
|
|
87
|
+
return undefined;
|
|
88
|
+
try {
|
|
89
|
+
const srcEntries = readdirSync(srcDir);
|
|
90
|
+
if (srcEntries.some((name) => DOTNET_SOLUTION_SUFFIXES.some((suffix) => name.endsWith(suffix)))) {
|
|
91
|
+
return detectDotnet(repoRoot, 'src');
|
|
91
92
|
}
|
|
92
93
|
}
|
|
94
|
+
catch {
|
|
95
|
+
// Ignore readdir errors on the src/ subdirectory.
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
function detectGoOrPython(repoRoot) {
|
|
93
100
|
if (existsSync(join(repoRoot, 'go.mod'))) {
|
|
94
101
|
return { language: 'go', build: 'go build ./...', lint: 'go vet ./...', test: 'go test ./...' };
|
|
95
102
|
}
|
|
@@ -97,6 +104,14 @@ export function detectChecks(repoRoot) {
|
|
|
97
104
|
// No universal python build/lint step; pytest is the de-facto test runner.
|
|
98
105
|
return { language: 'python', build: '', lint: '', test: 'pytest' };
|
|
99
106
|
}
|
|
100
|
-
return
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
// fallow-ignore-next-line complexity
|
|
110
|
+
export function detectChecks(repoRoot) {
|
|
111
|
+
if (existsSync(join(repoRoot, 'package.json')))
|
|
112
|
+
return detectNode(repoRoot);
|
|
113
|
+
return (detectDotnetAtRoot(repoRoot) ??
|
|
114
|
+
detectDotnetInSrc(repoRoot) ??
|
|
115
|
+
detectGoOrPython(repoRoot) ?? { language: 'unknown', build: '', lint: '', test: '' });
|
|
101
116
|
}
|
|
102
117
|
//# sourceMappingURL=detectChecks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detectChecks.js","sourceRoot":"","sources":["../../src/config/detectChecks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,wBAAwB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACnD,MAAM,uBAAuB,GAAG,CAAC,GAAG,wBAAwB,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAC/F,MAAM,cAAc,GAAG,CAAC,gBAAgB,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAE1E,gFAAgF;AAChF,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,OAAgC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/F,OAAO,GAAG,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA+B,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5F,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;QACvE,yEAAyE;QACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC9F,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;QAChD,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE;QAC7C,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;KAC1C,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,QAAgB;IACpC,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChE,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACrE,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAwC,CAAC;QACzG,OAAO,WAAW,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,QAAgB,EAAE,SAAkB;IACxD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;IAEvE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC;QACjC,CAAC,CAAC,iDAAiD;QACnD,CAAC,CAAC,mCAAmC,CAAC;IAExC,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,aAAa,CAAC;IAE1F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"detectChecks.js","sourceRoot":"","sources":["../../src/config/detectChecks.ts"],"names":[],"mappings":"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"}
|
package/dist/config/loader.js
CHANGED
|
@@ -36,6 +36,7 @@ const DEFAULT_CONFIG = {
|
|
|
36
36
|
updateChangelog: false,
|
|
37
37
|
};
|
|
38
38
|
/** Loads <repoRoot>/.env into process.env; already-set variables always win. */
|
|
39
|
+
// fallow-ignore-next-line complexity
|
|
39
40
|
function loadDotEnv(repoRoot) {
|
|
40
41
|
const envPath = join(repoRoot, '.env');
|
|
41
42
|
if (!existsSync(envPath))
|
|
@@ -61,6 +62,7 @@ function positiveNumber(value, fallback) {
|
|
|
61
62
|
return Number.isFinite(num) && num > 0 ? num : fallback;
|
|
62
63
|
}
|
|
63
64
|
/** Parses "true"/"false" (case-insensitive), falling back when unset or unrecognized. */
|
|
65
|
+
// fallow-ignore-next-line complexity
|
|
64
66
|
function boolean(value, fallback) {
|
|
65
67
|
if (typeof value === 'boolean')
|
|
66
68
|
return value;
|
|
@@ -88,9 +90,9 @@ function resolveProjectId(value, fallback) {
|
|
|
88
90
|
const num = Number(value);
|
|
89
91
|
return Number.isFinite(num) && num > 0 ? num : value;
|
|
90
92
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
/** Warns once when no toolchain was auto-detected and none of the build/lint/test env overrides are set — checks will otherwise silently be skipped. */
|
|
94
|
+
// fallow-ignore-next-line complexity
|
|
95
|
+
function warnIfToolchainUndetected(repoRoot, detected) {
|
|
94
96
|
if (detected.language === 'unknown' &&
|
|
95
97
|
process.env.PIPELINE_WORKER_BUILD === undefined &&
|
|
96
98
|
process.env.PIPELINE_WORKER_LINT === undefined &&
|
|
@@ -98,9 +100,10 @@ export function loadConfig(repoRoot) {
|
|
|
98
100
|
console.error(`Warning: could not detect the toolchain of ${repoRoot}; build/lint/test will be skipped. ` +
|
|
99
101
|
'Set PIPELINE_WORKER_BUILD / PIPELINE_WORKER_LINT / PIPELINE_WORKER_TEST to configure them explicitly.');
|
|
100
102
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
}
|
|
104
|
+
/** Auto-detects a string path from repoBase when no project id is configured yet; the env var override (numeric or string path) always wins. */
|
|
105
|
+
// fallow-ignore-next-line complexity
|
|
106
|
+
function resolveGitlabProjectId(repoRoot, repoBase) {
|
|
104
107
|
let resolvedProjectId = DEFAULT_CONFIG.gitlab.projectId;
|
|
105
108
|
if (!resolvedProjectId && repoBase) {
|
|
106
109
|
try {
|
|
@@ -111,18 +114,30 @@ export function loadConfig(repoRoot) {
|
|
|
111
114
|
console.error(`Warning: ${message}`);
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
|
-
|
|
117
|
+
return resolveProjectId(process.env.PIPELINE_WORKER_GITLAB_PROJECT_ID, resolvedProjectId);
|
|
118
|
+
}
|
|
119
|
+
function buildGitlabSection(repoRoot, repoBase) {
|
|
120
|
+
return {
|
|
121
|
+
host: process.env.PIPELINE_WORKER_GITLAB_HOST || DEFAULT_CONFIG.gitlab.host,
|
|
122
|
+
projectId: resolveGitlabProjectId(repoRoot, repoBase),
|
|
123
|
+
repoBase,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function buildGithubSection(repoRoot) {
|
|
127
|
+
return {
|
|
128
|
+
repo: process.env.PIPELINE_WORKER_GITHUB_REPO || detectGithubRepo(repoRoot) || DEFAULT_CONFIG.github.repo,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export function loadConfig(repoRoot) {
|
|
132
|
+
loadDotEnv(repoRoot);
|
|
133
|
+
const detected = detectChecks(repoRoot);
|
|
134
|
+
warnIfToolchainUndetected(repoRoot, detected);
|
|
135
|
+
const repoBase = process.env.PIPELINE_WORKER_GITLAB_REPO_BASE;
|
|
115
136
|
return {
|
|
116
137
|
agent: pickName(process.env.PIPELINE_WORKER_AGENT, AGENT_NAMES, DEFAULT_CONFIG.agent),
|
|
117
138
|
forge: pickName(process.env.PIPELINE_WORKER_FORGE, FORGE_NAMES, DEFAULT_CONFIG.forge),
|
|
118
|
-
gitlab:
|
|
119
|
-
|
|
120
|
-
projectId,
|
|
121
|
-
repoBase,
|
|
122
|
-
},
|
|
123
|
-
github: {
|
|
124
|
-
repo: process.env.PIPELINE_WORKER_GITHUB_REPO || detectGithubRepo(repoRoot) || DEFAULT_CONFIG.github.repo,
|
|
125
|
-
},
|
|
139
|
+
gitlab: buildGitlabSection(repoRoot, repoBase),
|
|
140
|
+
github: buildGithubSection(repoRoot),
|
|
126
141
|
build: stringOr(process.env.PIPELINE_WORKER_BUILD, detected.build),
|
|
127
142
|
lint: stringOr(process.env.PIPELINE_WORKER_LINT, detected.lint),
|
|
128
143
|
test: stringOr(process.env.PIPELINE_WORKER_TEST, detected.test),
|