@cxi-lmai/ci-agent-platform 3.0.0 ā 3.1.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/README.md +27 -5
- package/package.json +2 -2
- package/payload/INSTALL.md +14 -5
- package/payload/agents/agent-architect.md +1 -1
- package/payload/agents/code-reviewer.md +1 -1
- package/payload/agents/codebase-auditor.md +1 -1
- package/payload/agents/coder.md +3 -3
- package/payload/agents/decomposer.md +1 -1
- package/payload/agents/docs-sync.md +1 -1
- package/payload/agents/e2e-test-writer.md +1 -1
- package/payload/agents/performance-reviewer.md +1 -1
- package/payload/agents/release-mr.md +1 -1
- package/payload/agents/security-reviewer.md +1 -1
- package/payload/agents/test-fix.md +4 -4
- package/payload/agents/test-writer.md +3 -3
- package/payload/agents-omp/agent-architect.md +101 -0
- package/payload/agents-omp/code-reviewer.md +86 -0
- package/payload/agents-omp/codebase-auditor.md +73 -0
- package/payload/agents-omp/coder.md +57 -0
- package/payload/agents-omp/decomposer.md +70 -0
- package/payload/agents-omp/docs-sync.md +114 -0
- package/payload/agents-omp/e2e-test-writer.md +47 -0
- package/payload/agents-omp/migration-reviewer.md +99 -0
- package/payload/agents-omp/orchestrator.md +50 -0
- package/payload/agents-omp/performance-reviewer.md +81 -0
- package/payload/agents-omp/postmortem.md +82 -0
- package/payload/agents-omp/release-mr.md +274 -0
- package/payload/agents-omp/security-reviewer.md +121 -0
- package/payload/agents-omp/test-fix.md +33 -0
- package/payload/agents-omp/test-writer.md +39 -0
- package/payload/ci-templates/claude-pipeline.gitlab-ci.yml +220 -7
- package/payload/ci-templates/github/claude-issue-pipeline.yml +1 -1
- package/payload/ci-templates/github/claude-pipeline.yml +2 -2
- package/payload/ci-templates/github/claude-test-fix.yml +1 -1
- package/payload/ci-templates/scripts/agent-architect.sh +233 -0
- package/payload/ci-templates/scripts/code.sh +35 -35
- package/payload/ci-templates/scripts/codebase-audit.sh +252 -0
- package/payload/ci-templates/scripts/coverage-ratchet.sh +77 -0
- package/payload/ci-templates/scripts/cve-fix.sh +246 -0
- package/payload/ci-templates/scripts/docs-sync.sh +225 -0
- package/payload/ci-templates/scripts/e2e-test-gen.sh +201 -0
- package/payload/ci-templates/scripts/lib/failure-notice.sh +104 -0
- package/payload/ci-templates/scripts/lib/issue-loop.sh +155 -40
- package/payload/ci-templates/scripts/lib/pipeline-common.sh +233 -31
- package/payload/ci-templates/scripts/lib/platform.sh +270 -13
- package/payload/ci-templates/scripts/lib/usage-capture-omp.sh +123 -0
- package/payload/ci-templates/scripts/lib/usage-capture.sh +7 -1
- package/payload/ci-templates/scripts/metrics-snapshot.sh +377 -0
- package/payload/ci-templates/scripts/orchestrate.sh +56 -38
- package/payload/ci-templates/scripts/postmortem.sh +11 -1
- package/payload/ci-templates/scripts/review-fix.sh +23 -12
- package/payload/ci-templates/scripts/review.sh +12 -8
- package/payload/ci-templates/scripts/test-fix.sh +8 -1
- package/payload/skills/agent-architect/SKILL.md +45 -0
- package/payload/skills/codebase-audit/SKILL.md +84 -0
- package/payload/skills/cve-fix/SKILL.md +98 -0
- package/payload/skills/docs-sync/SKILL.md +74 -0
- package/payload/skills/e2e-test-gen/SKILL.md +65 -0
- package/payload/skills/fix-review-findings/SKILL.md +3 -3
- package/payload/skills/fix-tests/SKILL.md +4 -4
- package/payload/skills/implement-issue/SKILL.md +1 -1
- package/payload/skills/init-pipeline-config/SKILL.md +4 -4
- package/payload/skills/postmortem-mr/SKILL.md +1 -1
- package/payload/skills/review-mr/SKILL.md +1 -1
- package/payload/skills/triage-issue/SKILL.md +2 -2
- package/payload/templates/memory-index.template.md +34 -0
- package/payload/templates/pipeline-config.template.md +11 -1
- package/payload/templates/review_suppressions.template.md +55 -0
- package/payload/templates/spec-issue.template.md +39 -7
|
@@ -48,6 +48,7 @@ variables:
|
|
|
48
48
|
# PIPE_PLATFORM is autodetected from GITLAB_CI now, so setting it is optional.
|
|
49
49
|
# It is kept here as an explicit, harmless override.
|
|
50
50
|
PIPE_PLATFORM: "gitlab"
|
|
51
|
+
PIPE_HARNESS: "claude" # "claude" (default, Claude Code CLI) or "omp" (Oh My Pi + OpenRouter)
|
|
51
52
|
PIPE_CONFIG_PATH: ".claude/pipeline-config.md"
|
|
52
53
|
PIPE_CONTEXT_DIR: "build/pipeline"
|
|
53
54
|
|
|
@@ -81,26 +82,83 @@ variables:
|
|
|
81
82
|
PIPE_VERIFY_CMD: "" # compile + unit tests, run after a fix
|
|
82
83
|
PIPE_COMPILE_CMD: "" # compile only (defaults to PIPE_VERIFY_CMD)
|
|
83
84
|
PIPE_TEST_REPORT_GLOB: "" # e.g. build/test-results/**/TEST-*.xml
|
|
85
|
+
PIPE_COVERAGE_RATCHET: "0" # set to "1" to gate MR coverage against the target branch
|
|
86
|
+
PIPE_COVERAGE_REPORT: "" # path to the coverage report generated by the project
|
|
87
|
+
PIPE_COVERAGE_REPORT_KIND: "jacoco" # report parser; only jacoco is currently supported
|
|
84
88
|
PIPE_COVERAGE_SIGNAL: "" # path to a coverage-drop signal file
|
|
89
|
+
# To enable the gate, configure both report and signal paths. Its baseline is
|
|
90
|
+
# the target branch's latest successful pipeline `coverage` value; the
|
|
91
|
+
# project's test job must publish that value (through `coverage:` or a report)
|
|
92
|
+
# or the baseline is 0 and no drop can fire.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# --- CVE remediation (optional) -------------------------------------------
|
|
96
|
+
# A project-local security scanner supplies PIPE_CVE_LIST. The platform does
|
|
97
|
+
# not select a scanner or prescribe its severity filtering.
|
|
98
|
+
PIPE_CVE_FIX: "0" # set to "1" to enable CVE remediation on MR/PR pipelines
|
|
99
|
+
PIPE_DEPENDENCY_MANIFEST: "build.gradle"
|
|
100
|
+
PIPE_CVE_SUPPRESSIONS: "owasp-suppressions.xml"
|
|
101
|
+
|
|
102
|
+
# --- Issue-driven E2E test generation (optional) --------------------------
|
|
103
|
+
# A scheduled run selects test-ready issues. PIPE_E2E_VERIFY_CMD must be the
|
|
104
|
+
# project's explicit E2E command and accept the generated test path as its
|
|
105
|
+
# final argument. This generic template does not choose a framework, runtime
|
|
106
|
+
# image, install command, credentials, or URL.
|
|
107
|
+
PIPE_E2E_TEST_GEN: "0"
|
|
108
|
+
PIPE_LABEL_TESTREADY: "test-ready"
|
|
109
|
+
PIPE_LABEL_E2E_SCOPE: ""
|
|
110
|
+
PIPE_E2E_TEST_DIR: "e2e/tests"
|
|
111
|
+
PIPE_E2E_BASE_URL: ""
|
|
112
|
+
PIPE_E2E_VERIFY_CMD: ""
|
|
113
|
+
|
|
114
|
+
# --- Documentation sync (optional) ----------------------------------------
|
|
115
|
+
PIPE_DOCS_SYNC: "0" # set to "1" to enable the docs-sync job
|
|
116
|
+
PIPE_DOCS_ROOTS: "docs,CLAUDE.md,.claude/memory" # paths docs-sync may edit and commit
|
|
117
|
+
|
|
118
|
+
# --- Codebase audit (optional) ---------------------------------------------
|
|
119
|
+
PIPE_CODEBASE_AUDIT: "0" # set to "1" in a schedule to run the periodic audit
|
|
120
|
+
PIPE_LABEL_AUDIT: "codebase-audit" # label on the findings issue and its auto-fix MR/PR
|
|
121
|
+
|
|
122
|
+
# --- Agent architect (optional) --------------------------------------------
|
|
123
|
+
# A scheduled evidence-backed review of agent definitions. Default to
|
|
124
|
+
# report-only; set this false or 0 only after reviewing a dry-run report.
|
|
125
|
+
PIPE_AGENT_ARCHITECT: "0"
|
|
126
|
+
PIPE_ARCHITECT_WINDOW_DAYS: "7"
|
|
127
|
+
PIPE_ARCHITECT_DRY_RUN: "true"
|
|
128
|
+
PIPE_LABEL_IMPROVEMENT: "pipe-improvement"
|
|
129
|
+
|
|
130
|
+
# --- Metrics aggregation (optional) ---------------------------------------
|
|
131
|
+
PIPE_METRICS_SNAPSHOT: "0" # set to "1" in a schedule to aggregate
|
|
132
|
+
PIPE_METRICS_OUTPUT_DIR: "data/metrics/snapshots"
|
|
133
|
+
PIPE_METRICS_WINDOW_DAYS: "1"
|
|
134
|
+
PIPE_METRICS_COMMIT_REPO: "false" # "true" also commits the snapshot
|
|
135
|
+
PIPE_METRICS_REVIEW_AGENTS: "code-reviewer,review-verdict,review-fix"
|
|
136
|
+
PIPE_METRICS_DEFECT_REVERT: "Reverts !"
|
|
137
|
+
PIPE_METRICS_DEFECT_REGRESSION: "Fixes regression from !"
|
|
138
|
+
PIPE_METRICS_DEFECT_REINTRODUCE: "Reintroduces work from !"
|
|
139
|
+
PIPE_METRICS_SNAPSHOT_DATE: "" # override the snapshot date, replay only
|
|
140
|
+
PIPE_METRICS_RAW_DIR: "" # OFFLINE only: pre-staged records
|
|
141
|
+
PIPE_METRICS_MRS_FILE: "" # OFFLINE only: merge request list
|
|
85
142
|
|
|
86
143
|
# --- Commit subjects (drive the fix-loop cap counters) ---------------------
|
|
87
144
|
PIPE_COMMIT_TESTFIX: "Fix test errors"
|
|
88
145
|
PIPE_COMMIT_REVIEWFIX: "Fix review findings"
|
|
89
146
|
PIPE_COMMIT_COVERAGE: "Add coverage tests"
|
|
147
|
+
PIPE_COMMIT_DOCSSYNC: "Update docs per docs-sync findings"
|
|
148
|
+
PIPE_COMMIT_AUDIT: "docs: apply convention audit findings"
|
|
149
|
+
PIPE_COMMIT_CVEFIX: "Update dependencies to resolve CVEs"
|
|
90
150
|
|
|
91
151
|
# --- Caps + models ---------------------------------------------------------
|
|
92
152
|
PIPE_FIX_LOOP_CAP: "2"
|
|
93
|
-
# Main-loop
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
PIPE_MODEL_TRIAGE: "haiku"
|
|
97
|
-
PIPE_MODEL_CODE: "sonnet"
|
|
98
|
-
PIPE_MODEL_REVIEW: "sonnet"
|
|
153
|
+
# Main-loop models are passed as --model by the active harness. Defaults live
|
|
154
|
+
# in `pipeline-common.sh` under `scripts/lib/`. Users may explicitly set any
|
|
155
|
+
# PIPE_MODEL_* project CI variable. Subagents retain their frontmatter models.
|
|
99
156
|
PIPE_AGENT_ENV_ALLOWLIST: "" # credential-like env names the agent-run build must receive (comma-separated; prefer empty)
|
|
100
157
|
|
|
101
158
|
# --- Result files (defaults live under PIPE_CONTEXT_DIR) --------------------
|
|
102
159
|
PIPE_RESULT_REVIEW: "$PIPE_CONTEXT_DIR/code-review-result.txt"
|
|
103
160
|
PIPE_RESULT_REVIEWFIX: "$PIPE_CONTEXT_DIR/review-fix-result.json"
|
|
161
|
+
PIPE_RESULT_DOCSSYNC: "$PIPE_CONTEXT_DIR/docs-sync.json"
|
|
104
162
|
|
|
105
163
|
# --- Hidden base job: shared config + runtime variable mapping ---------------
|
|
106
164
|
# Maps GitLab's CI_ runtime variables onto the PIPE_ names the scripts read, and
|
|
@@ -125,7 +183,20 @@ variables:
|
|
|
125
183
|
# ship it, plain docker images (node:22-bookworm) do not, so install it
|
|
126
184
|
# here (finding from the GitLab pilot: silent HTTP 400s + exit 127).
|
|
127
185
|
- command -v jq >/dev/null 2>&1 || (apt-get update -qq && apt-get install -y -qq jq)
|
|
128
|
-
-
|
|
186
|
+
# node:22-bookworm does not include xmllint. Install it only for the
|
|
187
|
+
# opt-in ratchet. Unsupported custom-image installation stays non-fatal so
|
|
188
|
+
# coverage-ratchet can issue its explicit missing-tool error when it runs.
|
|
189
|
+
- |
|
|
190
|
+
if [ "$PIPE_COVERAGE_RATCHET" = "1" ] && ! command -v xmllint >/dev/null 2>&1; then
|
|
191
|
+
command -v apt-get >/dev/null 2>&1 &&
|
|
192
|
+
(apt-get update -qq && apt-get install -y -qq libxml2-utils) || true
|
|
193
|
+
fi
|
|
194
|
+
- |
|
|
195
|
+
if [ "$PIPE_HARNESS" = "omp" ]; then
|
|
196
|
+
command -v omp >/dev/null 2>&1 || npm install -g @oh-my-pi/pi-coding-agent
|
|
197
|
+
else
|
|
198
|
+
command -v claude >/dev/null 2>&1 || npm install -g @anthropic-ai/claude-code
|
|
199
|
+
fi
|
|
129
200
|
artifacts:
|
|
130
201
|
paths:
|
|
131
202
|
- $PIPE_CONTEXT_DIR/metrics/
|
|
@@ -173,6 +244,42 @@ review-fix:
|
|
|
173
244
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $PIPE_TARGET_BRANCH && $CI_MERGE_REQUEST_LABELS =~ $PIPE_LABEL_WIP'
|
|
174
245
|
when: on_failure
|
|
175
246
|
|
|
247
|
+
# =============================================================================
|
|
248
|
+
# docs-sync: check whether the MR's code changes need documentation updates.
|
|
249
|
+
# Optional and off by default, because it spends tokens on every MR: enable it
|
|
250
|
+
# by setting PIPE_DOCS_SYNC=1. On a wip MR the agent applies the updates and
|
|
251
|
+
# this job commits and pushes them; on any other MR it posts an advisory
|
|
252
|
+
# comment only. It never gates the pipeline.
|
|
253
|
+
# =============================================================================
|
|
254
|
+
docs-sync:
|
|
255
|
+
extends: .claude-base
|
|
256
|
+
stage: review
|
|
257
|
+
timeout: 30m
|
|
258
|
+
variables:
|
|
259
|
+
GIT_STRATEGY: clone
|
|
260
|
+
script:
|
|
261
|
+
- bash "$PIPE_SCRIPTS_DIR/docs-sync.sh"
|
|
262
|
+
allow_failure: true
|
|
263
|
+
rules:
|
|
264
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $PIPE_TARGET_BRANCH && $PIPE_DOCS_SYNC == "1"'
|
|
265
|
+
|
|
266
|
+
# =============================================================================
|
|
267
|
+
# cve-fix: optionally remediate HIGH/CRITICAL vulnerabilities supplied by a
|
|
268
|
+
# project-local scanner in PIPE_CVE_LIST. The coder only runs on an autonomous
|
|
269
|
+
# MR/PR; human-authored MRs receive a manual-update comment instead.
|
|
270
|
+
# =============================================================================
|
|
271
|
+
cve-fix:
|
|
272
|
+
extends: .claude-base
|
|
273
|
+
stage: review
|
|
274
|
+
timeout: 45m
|
|
275
|
+
variables:
|
|
276
|
+
GIT_STRATEGY: clone
|
|
277
|
+
script:
|
|
278
|
+
- bash "$PIPE_SCRIPTS_DIR/cve-fix.sh"
|
|
279
|
+
allow_failure: true
|
|
280
|
+
rules:
|
|
281
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $PIPE_TARGET_BRANCH && $PIPE_CVE_FIX == "1"'
|
|
282
|
+
|
|
176
283
|
# =============================================================================
|
|
177
284
|
# orchestrate: triage ready issues and fire the coder (issue -> code loop).
|
|
178
285
|
# Runs on a scheduled pipeline that sets PIPE_ORCHESTRATE=1 (kept off by default
|
|
@@ -195,6 +302,45 @@ orchestrate:
|
|
|
195
302
|
- if: '$CI_PIPELINE_SOURCE == "web" && $PIPE_ORCHESTRATE == "1"'
|
|
196
303
|
|
|
197
304
|
# =============================================================================
|
|
305
|
+
# codebase-audit: periodic convention-drift scan. Scans recently merged MRs/PRs
|
|
306
|
+
# and compares patterns against documented conventions via the codebase-auditor
|
|
307
|
+
# agent. Posts findings as an issue labeled $PIPE_LABEL_AUDIT. If the report
|
|
308
|
+
# suggests documentation updates and a push-capable identity is configured,
|
|
309
|
+
# spawns the coder agent to implement them and opens an MR/PR.
|
|
310
|
+
# Opt-in and off by default: enable by setting PIPE_CODEBASE_AUDIT=1 on a
|
|
311
|
+
# separate scheduled pipeline (e.g. monthly).
|
|
312
|
+
# =============================================================================
|
|
313
|
+
codebase-audit:
|
|
314
|
+
extends: .claude-base
|
|
315
|
+
stage: orchestrate
|
|
316
|
+
timeout: 30m
|
|
317
|
+
variables:
|
|
318
|
+
GIT_STRATEGY: clone
|
|
319
|
+
script:
|
|
320
|
+
- bash "$PIPE_SCRIPTS_DIR/codebase-audit.sh"
|
|
321
|
+
allow_failure: true
|
|
322
|
+
rules:
|
|
323
|
+
- if: '$CI_PIPELINE_SOURCE == "schedule" && $PIPE_CODEBASE_AUDIT == "1"'
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# =============================================================================
|
|
327
|
+
# agent-architect: weekly, evidence-backed improvement proposals for shipped
|
|
328
|
+
# agent definitions. Schedule-only and opt-in because it spends model tokens;
|
|
329
|
+
# set DRY_RUN=true for an initial report-only trial.
|
|
330
|
+
# =============================================================================
|
|
331
|
+
agent-architect:
|
|
332
|
+
extends: .claude-base
|
|
333
|
+
stage: review
|
|
334
|
+
timeout: 30m
|
|
335
|
+
variables:
|
|
336
|
+
GIT_STRATEGY: clone
|
|
337
|
+
DRY_RUN: "$PIPE_ARCHITECT_DRY_RUN"
|
|
338
|
+
script:
|
|
339
|
+
- bash "$PIPE_SCRIPTS_DIR/agent-architect.sh"
|
|
340
|
+
allow_failure: true
|
|
341
|
+
rules:
|
|
342
|
+
- if: '$CI_PIPELINE_SOURCE == "schedule" && $PIPE_AGENT_ARCHITECT == "1"'
|
|
343
|
+
# =============================================================================
|
|
198
344
|
# code: implement one issue and open the MR (issue -> code loop).
|
|
199
345
|
# Triggered by orchestrate via the Pipeline Trigger API with CODER_ISSUE and
|
|
200
346
|
# CODER_BRANCH set. The coder agent runs with --dangerously-skip-permissions on
|
|
@@ -211,6 +357,48 @@ code:
|
|
|
211
357
|
rules:
|
|
212
358
|
- if: '$CODER_ISSUE && $CODER_BRANCH'
|
|
213
359
|
|
|
360
|
+
# =============================================================================
|
|
361
|
+
# e2e-test-gen: scheduled, opt-in generation for issues carrying the configured
|
|
362
|
+
# test-ready label (and optional E2E scope label). The project supplies the
|
|
363
|
+
# verification command and any framework/runtime setup through its own CI.
|
|
364
|
+
# =============================================================================
|
|
365
|
+
e2e-test-gen:
|
|
366
|
+
extends: .claude-base
|
|
367
|
+
stage: test
|
|
368
|
+
timeout: 45m
|
|
369
|
+
variables:
|
|
370
|
+
GIT_STRATEGY: clone
|
|
371
|
+
script:
|
|
372
|
+
- bash "$PIPE_SCRIPTS_DIR/e2e-test-gen.sh"
|
|
373
|
+
allow_failure: true
|
|
374
|
+
rules:
|
|
375
|
+
- if: '$CI_PIPELINE_SOURCE == "schedule" && $PIPE_E2E_TEST_GEN == "1"'
|
|
376
|
+
|
|
377
|
+
# =============================================================================
|
|
378
|
+
# coverage-ratchet: optional MR coverage gate. Reads the project's coverage
|
|
379
|
+
# artifact and, for a wip coverage drop, fails into test-fix with its signal.
|
|
380
|
+
# =============================================================================
|
|
381
|
+
coverage-ratchet:
|
|
382
|
+
extends: .claude-base
|
|
383
|
+
stage: test
|
|
384
|
+
needs:
|
|
385
|
+
- job: test
|
|
386
|
+
artifacts: true
|
|
387
|
+
optional: true
|
|
388
|
+
variables:
|
|
389
|
+
GIT_STRATEGY: clone
|
|
390
|
+
script:
|
|
391
|
+
- bash "$PIPE_SCRIPTS_DIR/coverage-ratchet.sh"
|
|
392
|
+
artifacts:
|
|
393
|
+
paths:
|
|
394
|
+
- $PIPE_CONTEXT_DIR/metrics/
|
|
395
|
+
- $PIPE_COVERAGE_SIGNAL
|
|
396
|
+
when: always
|
|
397
|
+
expire_in: 60 days
|
|
398
|
+
rules:
|
|
399
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $PIPE_TARGET_BRANCH && $PIPE_COVERAGE_RATCHET == "1"'
|
|
400
|
+
when: always
|
|
401
|
+
|
|
214
402
|
# =============================================================================
|
|
215
403
|
# test-fix: on failure of YOUR project's `test` job, on a wip MR, fix tests /
|
|
216
404
|
# compilation / coverage. Consumes the test job's artifacts via needs.
|
|
@@ -223,6 +411,9 @@ test-fix:
|
|
|
223
411
|
- job: test
|
|
224
412
|
artifacts: true
|
|
225
413
|
optional: true
|
|
414
|
+
- job: coverage-ratchet
|
|
415
|
+
artifacts: true
|
|
416
|
+
optional: true
|
|
226
417
|
variables:
|
|
227
418
|
GIT_STRATEGY: clone
|
|
228
419
|
script:
|
|
@@ -231,3 +422,25 @@ test-fix:
|
|
|
231
422
|
rules:
|
|
232
423
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $PIPE_TARGET_BRANCH && $CI_MERGE_REQUEST_LABELS =~ $PIPE_LABEL_WIP'
|
|
233
424
|
when: on_failure
|
|
425
|
+
|
|
426
|
+
# =============================================================================
|
|
427
|
+
# metrics-snapshot: aggregates one day of pipeline metrics into a JSON snapshot.
|
|
428
|
+
# Optional and off by default. Enable by setting PIPE_METRICS_SNAPSHOT=1 on a
|
|
429
|
+
# scheduled pipeline. Writes an artifact; set PIPE_METRICS_COMMIT_REPO=true to
|
|
430
|
+
# also commit the snapshot to the target branch.
|
|
431
|
+
# =============================================================================
|
|
432
|
+
metrics-snapshot:
|
|
433
|
+
extends: .claude-base
|
|
434
|
+
stage: orchestrate
|
|
435
|
+
timeout: 30m
|
|
436
|
+
variables:
|
|
437
|
+
GIT_DEPTH: "0"
|
|
438
|
+
script:
|
|
439
|
+
- bash "$PIPE_SCRIPTS_DIR/metrics-snapshot.sh"
|
|
440
|
+
artifacts:
|
|
441
|
+
paths:
|
|
442
|
+
- $PIPE_METRICS_OUTPUT_DIR/
|
|
443
|
+
when: always
|
|
444
|
+
expire_in: 90 days
|
|
445
|
+
rules:
|
|
446
|
+
- if: '$CI_PIPELINE_SOURCE == "schedule" && $PIPE_METRICS_SNAPSHOT == "1"'
|
|
@@ -74,7 +74,7 @@ env:
|
|
|
74
74
|
PIPE_GIT_NAME: ${{ vars.PIPE_GIT_NAME || 'Pipeline Bot' }}
|
|
75
75
|
PIPE_GIT_EMAIL: ${{ vars.PIPE_GIT_EMAIL || 'bot@pipeline.ci' }}
|
|
76
76
|
PIPE_MODEL_TRIAGE: ${{ vars.PIPE_MODEL_TRIAGE || 'haiku' }}
|
|
77
|
-
PIPE_MODEL_CODE: ${{ vars.PIPE_MODEL_CODE || 'sonnet' }}
|
|
77
|
+
PIPE_MODEL_CODE: ${{ vars.PIPE_MODEL_CODE || 'claude-sonnet-5-0' }}
|
|
78
78
|
PIPE_AGENT_ENV_ALLOWLIST: ${{ vars.PIPE_AGENT_ENV_ALLOWLIST || '' }}
|
|
79
79
|
# Runtime mapping onto the PIPE_ names the scripts read.
|
|
80
80
|
PIPE_REPO: ${{ github.repository }}
|
|
@@ -44,8 +44,8 @@ env:
|
|
|
44
44
|
PIPE_COMMIT_REVIEWFIX: ${{ vars.PIPE_COMMIT_REVIEWFIX || 'Fix review findings' }}
|
|
45
45
|
PIPE_GIT_NAME: ${{ vars.PIPE_GIT_NAME || 'Pipeline Bot' }}
|
|
46
46
|
PIPE_GIT_EMAIL: ${{ vars.PIPE_GIT_EMAIL || 'bot@pipeline.ci' }}
|
|
47
|
-
PIPE_MODEL_REVIEW: ${{ vars.PIPE_MODEL_REVIEW || 'sonnet' }}
|
|
48
|
-
PIPE_MODEL_CODE: ${{ vars.PIPE_MODEL_CODE || 'sonnet' }}
|
|
47
|
+
PIPE_MODEL_REVIEW: ${{ vars.PIPE_MODEL_REVIEW || 'claude-sonnet-5-0' }}
|
|
48
|
+
PIPE_MODEL_CODE: ${{ vars.PIPE_MODEL_CODE || 'claude-sonnet-5-0' }}
|
|
49
49
|
PIPE_AGENT_ENV_ALLOWLIST: ${{ vars.PIPE_AGENT_ENV_ALLOWLIST || '' }}
|
|
50
50
|
# Runtime mapping onto the PIPE_ names the scripts read.
|
|
51
51
|
PIPE_REPO: ${{ github.repository }}
|
|
@@ -49,7 +49,7 @@ env:
|
|
|
49
49
|
PIPE_COMMIT_COVERAGE: ${{ vars.PIPE_COMMIT_COVERAGE || 'Add coverage tests' }}
|
|
50
50
|
PIPE_GIT_NAME: ${{ vars.PIPE_GIT_NAME || 'Pipeline Bot' }}
|
|
51
51
|
PIPE_GIT_EMAIL: ${{ vars.PIPE_GIT_EMAIL || 'bot@pipeline.ci' }}
|
|
52
|
-
PIPE_MODEL_CODE: ${{ vars.PIPE_MODEL_CODE || 'sonnet' }}
|
|
52
|
+
PIPE_MODEL_CODE: ${{ vars.PIPE_MODEL_CODE || 'claude-sonnet-5-0' }}
|
|
53
53
|
PIPE_AGENT_ENV_ALLOWLIST: ${{ vars.PIPE_AGENT_ENV_ALLOWLIST || '' }}
|
|
54
54
|
PIPE_TEST_ARTIFACT: ${{ vars.PIPE_TEST_ARTIFACT || 'test-reports' }}
|
|
55
55
|
PIPE_REPO: ${{ github.repository }}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Runner for the opt-in weekly agent-architect job. It collects bounded,
|
|
3
|
+
# forge-neutral evidence; the /agent-architect skill performs the analysis.
|
|
4
|
+
set -e
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
# shellcheck source=lib/pipeline-common.sh
|
|
7
|
+
source "$SCRIPT_DIR/lib/pipeline-common.sh"
|
|
8
|
+
# shellcheck source=lib/issue-loop.sh
|
|
9
|
+
source "$SCRIPT_DIR/lib/issue-loop.sh"
|
|
10
|
+
pipe_defaults
|
|
11
|
+
|
|
12
|
+
ARCHITECT_ENV="$PIPE_CONTEXT_DIR/architect.env"
|
|
13
|
+
CONTEXT_FILE="$PIPE_CONTEXT_DIR/architect-context.md"
|
|
14
|
+
REPORT_FILE="$PIPE_CONTEXT_DIR/architect-report.md"
|
|
15
|
+
PROPOSALS_FILE="$PIPE_CONTEXT_DIR/architect-proposals.json"
|
|
16
|
+
if [ "${DRY_RUN+x}" = x ]; then
|
|
17
|
+
DRY_RUN="$DRY_RUN"
|
|
18
|
+
else
|
|
19
|
+
DRY_RUN="${PIPE_ARCHITECT_DRY_RUN:-true}"
|
|
20
|
+
fi
|
|
21
|
+
WINDOW_DAYS="${PIPE_ARCHITECT_WINDOW_DAYS:-7}"
|
|
22
|
+
|
|
23
|
+
write_marker() {
|
|
24
|
+
printf 'ARCHITECT_STATUS=%s\nARCHITECT_PROPOSALS=%s\nARCHITECT_ISSUES_FILED=%s\n' \
|
|
25
|
+
"$1" "$2" "$3" > "$ARCHITECT_ENV"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if [ "${PIPE_AGENT_ARCHITECT:-0}" != "1" ]; then
|
|
29
|
+
write_marker disabled 0 0
|
|
30
|
+
pipe_log "Agent architect is disabled"
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if ! [[ "$WINDOW_DAYS" =~ ^[1-9][0-9]*$ ]]; then
|
|
35
|
+
write_marker invalid_window 0 0
|
|
36
|
+
pipe_log "ERROR: PIPE_ARCHITECT_WINDOW_DAYS must be a positive integer"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if date --version >/dev/null 2>&1; then
|
|
41
|
+
SINCE=$(date -u -d "$WINDOW_DAYS days ago" '+%Y-%m-%dT%H:%M:%SZ')
|
|
42
|
+
else
|
|
43
|
+
SINCE=$(date -u -v-"$WINDOW_DAYS"d '+%Y-%m-%dT%H:%M:%SZ')
|
|
44
|
+
fi
|
|
45
|
+
WEEK_TAG=$(date -u +%G-W%V)
|
|
46
|
+
|
|
47
|
+
# The updated-since helper has the window semantics the source job needs. It
|
|
48
|
+
# returns both states, so retain only merged MRs/PRs targeting this projectās
|
|
49
|
+
# configured integration branch and cap the prompt input before any per-item IO.
|
|
50
|
+
RECENT_MRS=$(platform_merge_requests_updated_since "$SINCE") || {
|
|
51
|
+
write_marker fetch_failed 0 0
|
|
52
|
+
pipe_log "ERROR: failed to fetch recently updated MRs/PRs"
|
|
53
|
+
exit 1
|
|
54
|
+
}
|
|
55
|
+
MRS=$(jq -c --arg target "$PIPE_TARGET_BRANCH" \
|
|
56
|
+
'[.[] | select(.state == "merged" and .target_branch == $target)] | .[0:30]' <<< "$RECENT_MRS") || {
|
|
57
|
+
write_marker fetch_failed 0 0
|
|
58
|
+
pipe_log "ERROR: unexpected merged MR/PR response"
|
|
59
|
+
exit 1
|
|
60
|
+
}
|
|
61
|
+
MR_COUNT=$(jq -r 'length' <<< "$MRS")
|
|
62
|
+
if ! [[ "$MR_COUNT" =~ ^[0-9]+$ ]]; then
|
|
63
|
+
write_marker fetch_failed 0 0
|
|
64
|
+
pipe_log "ERROR: could not count merged MRs/PRs"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
if [ "$MR_COUNT" = 0 ]; then
|
|
68
|
+
write_marker no_evidence 0 0
|
|
69
|
+
pipe_log "No merged MRs/PRs in the last $WINDOW_DAYS days"
|
|
70
|
+
exit 0
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Stuck issues are current actionable context. Stuck MRs/PRs are selected from
|
|
74
|
+
# the same bounded recent window, so neither evidence source can expand prompt
|
|
75
|
+
# size without a hard limit.
|
|
76
|
+
STUCK_ISSUES=$(issues_by_labels "$PIPE_LABEL_STUCK" "" opened 20) || {
|
|
77
|
+
pipe_log "WARNING: failed to fetch open $PIPE_LABEL_STUCK issues; continuing without them"
|
|
78
|
+
STUCK_ISSUES='[]'
|
|
79
|
+
}
|
|
80
|
+
STUCK_MRS=$(jq -c --arg label "$PIPE_LABEL_STUCK" \
|
|
81
|
+
'[.[] | select((.labels // []) | index($label))] | .[0:20]' <<< "$RECENT_MRS") || STUCK_MRS='[]'
|
|
82
|
+
OPEN_IMPROVEMENTS=$(issues_by_label_created "$PIPE_LABEL_IMPROVEMENT" opened 10) || {
|
|
83
|
+
pipe_log "WARNING: failed to fetch open $PIPE_LABEL_IMPROVEMENT issues; continuing without dedup context"
|
|
84
|
+
OPEN_IMPROVEMENTS='[]'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Resolve the configured bot identity once so automatic comments do not become
|
|
88
|
+
# evidence. A failed lookup merely leaves the filter empty rather than failing a
|
|
89
|
+
# read-only scheduled analysis.
|
|
90
|
+
platform_resolve_bot_user || true
|
|
91
|
+
|
|
92
|
+
MR_EVIDENCE=""
|
|
93
|
+
while IFS= read -r IID; do
|
|
94
|
+
TITLE=$(jq -r --argjson iid "$IID" '.[] | select(.iid == $iid) | .title' <<< "$MRS")
|
|
95
|
+
AUTHOR=$(jq -r --argjson iid "$IID" '.[] | select(.iid == $iid) | .author' <<< "$MRS")
|
|
96
|
+
LABELS=$(jq -r --argjson iid "$IID" '.[] | select(.iid == $iid) | (.labels // []) | join(",")' <<< "$MRS")
|
|
97
|
+
FILES=$(platform_mr_changes "$IID" 15 2>/dev/null | sed 's/^/ /' || true)
|
|
98
|
+
NOTES=$(platform_mr_notes "$IID" 20 asc 2>/dev/null \
|
|
99
|
+
| jq -r --arg bot "${PIPE_BOT_USER:-}" \
|
|
100
|
+
'[.[] | select($bot == "" or .author != $bot)
|
|
101
|
+
| " [" + .author + "]: " + ((.body | gsub("[\\r\\n]+"; " "))[0:200])]
|
|
102
|
+
| .[0:20] | join("\n")' 2>/dev/null || true)
|
|
103
|
+
MR_EVIDENCE="${MR_EVIDENCE}
|
|
104
|
+
### MR/PR !${IID}: ${TITLE}
|
|
105
|
+
Author: ${AUTHOR} | Labels: ${LABELS}
|
|
106
|
+
Changed files:
|
|
107
|
+
${FILES:- (none)}
|
|
108
|
+
Human review comments:
|
|
109
|
+
${NOTES:- (none)}
|
|
110
|
+
"
|
|
111
|
+
done < <(jq -r '.[].iid' <<< "$MRS")
|
|
112
|
+
|
|
113
|
+
STUCK_EVIDENCE=""
|
|
114
|
+
while IFS= read -r IID; do
|
|
115
|
+
TITLE=$(jq -r --argjson iid "$IID" '.[] | select(.iid == $iid) | .title' <<< "$STUCK_ISSUES")
|
|
116
|
+
DESCRIPTION=$(jq -r --argjson iid "$IID" '.[] | select(.iid == $iid) | .description // "(none)"' <<< "$STUCK_ISSUES" | head -c 400)
|
|
117
|
+
STUCK_EVIDENCE="${STUCK_EVIDENCE}
|
|
118
|
+
### Stuck issue #${IID}: ${TITLE}
|
|
119
|
+
${DESCRIPTION}
|
|
120
|
+
"
|
|
121
|
+
done < <(jq -r '.[].iid' <<< "$STUCK_ISSUES")
|
|
122
|
+
while IFS= read -r IID; do
|
|
123
|
+
TITLE=$(jq -r --argjson iid "$IID" '.[] | select(.iid == $iid) | .title' <<< "$STUCK_MRS")
|
|
124
|
+
NOTES=$(platform_mr_notes "$IID" 15 asc 2>/dev/null \
|
|
125
|
+
| jq -r --arg bot "${PIPE_BOT_USER:-}" \
|
|
126
|
+
'[.[] | select($bot == "" or .author != $bot)
|
|
127
|
+
| " [" + .author + "]: " + ((.body | gsub("[\\r\\n]+"; " "))[0:200])]
|
|
128
|
+
| .[0:15] | join("\n")' 2>/dev/null || true)
|
|
129
|
+
STUCK_EVIDENCE="${STUCK_EVIDENCE}
|
|
130
|
+
### Stuck MR/PR !${IID}: ${TITLE}
|
|
131
|
+
Human comments:
|
|
132
|
+
${NOTES:- (none)}
|
|
133
|
+
"
|
|
134
|
+
done < <(jq -r '.[].iid' <<< "$STUCK_MRS")
|
|
135
|
+
|
|
136
|
+
OPEN_CONTEXT=$(jq -r '.[] | "Issue #\(.iid) (\(.created_at[0:10])): \(.title)\n\(.description[0:500])\n---"' <<< "$OPEN_IMPROVEMENTS" 2>/dev/null | head -c 6000 || true)
|
|
137
|
+
rm -f "$ARCHITECT_ENV" "$REPORT_FILE" "$PROPOSALS_FILE"
|
|
138
|
+
{
|
|
139
|
+
echo "# Agent architect context"
|
|
140
|
+
echo
|
|
141
|
+
echo "Time window: last $WINDOW_DAYS days (since $SINCE)"
|
|
142
|
+
echo "Week: $WEEK_TAG"
|
|
143
|
+
echo "Ready label: $PIPE_LABEL_READY"
|
|
144
|
+
echo "Improvement label: $PIPE_LABEL_IMPROVEMENT"
|
|
145
|
+
echo
|
|
146
|
+
echo "## Merged MRs/PRs"
|
|
147
|
+
printf '%s\n' "$MR_EVIDENCE"
|
|
148
|
+
echo "## Stuck items"
|
|
149
|
+
printf '%s\n' "${STUCK_EVIDENCE:-(none)}"
|
|
150
|
+
if [ -n "$OPEN_CONTEXT" ]; then
|
|
151
|
+
echo
|
|
152
|
+
echo "## Already-open improvement issues ā do not re-propose these"
|
|
153
|
+
printf '%s\n' "$OPEN_CONTEXT"
|
|
154
|
+
fi
|
|
155
|
+
} > "$CONTEXT_FILE"
|
|
156
|
+
|
|
157
|
+
REPORT=$(pipe_run_agent agent-architect "/agent-architect" "Agent,Read,Glob,Grep" "$PIPE_MODEL_REVIEW" < /dev/null)
|
|
158
|
+
printf '%s\n' "$REPORT" > "$REPORT_FILE"
|
|
159
|
+
if [ ! -s "$REPORT_FILE" ]; then
|
|
160
|
+
write_marker no_output 0 0
|
|
161
|
+
pipe_failure_log_notice_files "the weekly agent-architect analysis" \
|
|
162
|
+
"review the recent changes and stuck items by hand" \
|
|
163
|
+
"$PIPE_AGENT_STDERR" "$REPORT_FILE" | while IFS= read -r line; do pipe_log "$line"; done
|
|
164
|
+
exit 0
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# Retain at most five complete delimiter blocks. The JSON file keeps body text
|
|
168
|
+
# out of shell words and is also the sole source for issue creation below.
|
|
169
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
170
|
+
write_marker parser_failed 0 0
|
|
171
|
+
pipe_log "WARNING: python3 is unavailable; cannot parse architect proposals"
|
|
172
|
+
exit 0
|
|
173
|
+
fi
|
|
174
|
+
if ! python3 - "$REPORT_FILE" "$PROPOSALS_FILE" <<'PY'
|
|
175
|
+
import json
|
|
176
|
+
import re
|
|
177
|
+
import sys
|
|
178
|
+
|
|
179
|
+
report_path, proposals_path = sys.argv[1:]
|
|
180
|
+
text = open(report_path, encoding="utf-8").read()
|
|
181
|
+
proposals = []
|
|
182
|
+
for block in re.findall(r"<!-- ISSUE-START -->(.*?)<!-- ISSUE-END -->", text, re.S)[:5]:
|
|
183
|
+
title = next((line[7:].strip() for line in block.splitlines() if line.startswith("Title: ")), "")
|
|
184
|
+
if not title or len(title) > 72:
|
|
185
|
+
continue
|
|
186
|
+
proposals.append({"title": title, "body": block.strip()[:8000]})
|
|
187
|
+
with open(proposals_path, "w", encoding="utf-8") as output:
|
|
188
|
+
json.dump(proposals, output)
|
|
189
|
+
PY
|
|
190
|
+
then
|
|
191
|
+
rm -f "$PROPOSALS_FILE"
|
|
192
|
+
write_marker parser_failed 0 0
|
|
193
|
+
pipe_log "WARNING: could not parse architect proposals"
|
|
194
|
+
exit 0
|
|
195
|
+
fi
|
|
196
|
+
if ! jq -e 'type == "array"' "$PROPOSALS_FILE" >/dev/null 2>&1; then
|
|
197
|
+
rm -f "$PROPOSALS_FILE"
|
|
198
|
+
write_marker parser_failed 0 0
|
|
199
|
+
pipe_log "WARNING: architect proposal parser produced invalid output"
|
|
200
|
+
exit 0
|
|
201
|
+
fi
|
|
202
|
+
PROPOSAL_COUNT=$(jq -r 'length' "$PROPOSALS_FILE")
|
|
203
|
+
if [ "$PROPOSAL_COUNT" = 0 ]; then
|
|
204
|
+
write_marker no_proposals 0 0
|
|
205
|
+
pipe_log "No concrete architect proposals"
|
|
206
|
+
exit 0
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
case "$DRY_RUN" in
|
|
210
|
+
false|0) ;;
|
|
211
|
+
*)
|
|
212
|
+
write_marker ok "$PROPOSAL_COUNT" 0
|
|
213
|
+
pipe_log "DRY RUN: $PROPOSAL_COUNT proposal(s), no issues filed"
|
|
214
|
+
cat "$REPORT_FILE"
|
|
215
|
+
exit 0
|
|
216
|
+
;;
|
|
217
|
+
esac
|
|
218
|
+
|
|
219
|
+
issue_ensure_label "$PIPE_LABEL_IMPROVEMENT" "#6F42C1" "Agent improvement proposals"
|
|
220
|
+
ISSUES_FILE="$PIPE_CONTEXT_DIR/architect-issue.md"
|
|
221
|
+
ISSUES_FILED=0
|
|
222
|
+
while IFS= read -r proposal; do
|
|
223
|
+
TITLE=$(jq -r '.title' <<< "$proposal")
|
|
224
|
+
jq -r '.body' <<< "$proposal" > "$ISSUES_FILE"
|
|
225
|
+
ISSUE_IID=$(issue_create_file "$TITLE" "$ISSUES_FILE" "$PIPE_LABEL_READY,$PIPE_LABEL_IMPROVEMENT")
|
|
226
|
+
if [ -n "$ISSUE_IID" ]; then
|
|
227
|
+
ISSUES_FILED=$((ISSUES_FILED + 1))
|
|
228
|
+
pipe_log "Filed architect proposal as #$ISSUE_IID"
|
|
229
|
+
else
|
|
230
|
+
pipe_log "WARNING: could not file architect proposal: $TITLE"
|
|
231
|
+
fi
|
|
232
|
+
done < <(jq -c '.[]' "$PROPOSALS_FILE")
|
|
233
|
+
write_marker ok "$PROPOSAL_COUNT" "$ISSUES_FILED"
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
#
|
|
8
8
|
# Generalized from a single-project original: the delegation prompt and the
|
|
9
9
|
# summary generation moved into the skill, platform calls go through
|
|
10
|
-
# lib/issue-loop.sh, and the coder runs
|
|
10
|
+
# lib/issue-loop.sh, and the coder runs via pipe_run_agent.
|
|
11
11
|
#
|
|
12
|
-
# SECURITY NOTE: the coder agent
|
|
13
|
-
# must edit files and run the build
|
|
14
|
-
# choice for trusted inputs. Run only on an isolated ephemeral
|
|
15
|
-
# the image allows,
|
|
16
|
-
# make arbitrary public issue or
|
|
17
|
-
# boundary. Do not run this job
|
|
12
|
+
# SECURITY NOTE: the coder agent uses the active harness's unattended approval
|
|
13
|
+
# mode because it must edit files and run the build without interaction. This is
|
|
14
|
+
# a deliberate choice for trusted inputs. Run only on an isolated ephemeral
|
|
15
|
+
# runner and, where the image allows, through the harness dispatch's shared
|
|
16
|
+
# unprivileged-user wrapper. This does not make arbitrary public issue or
|
|
17
|
+
# contributor content safe; see the README trust boundary. Do not run this job
|
|
18
|
+
# on a shared or privileged machine.
|
|
18
19
|
set -e
|
|
19
20
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
20
21
|
# shellcheck source=lib/pipeline-common.sh
|
|
@@ -51,7 +52,7 @@ pipe_log "Implementing #$CODER_ISSUE: $ISSUE_TITLE"
|
|
|
51
52
|
|
|
52
53
|
# --- 4. Run the implement-issue skill (delegates to the coder agent) --------
|
|
53
54
|
rm -f "$PIPE_CONTEXT_DIR/implement.env" "$PIPE_CONTEXT_DIR/mr-summary.md"
|
|
54
|
-
|
|
55
|
+
pipe_run_agent coder "/implement-issue" "Agent,Read,Write,Edit,Glob,Grep,Bash" "$PIPE_MODEL_CODE" < /dev/null
|
|
55
56
|
|
|
56
57
|
# --- 5. Authoritative commit count (the runner owns the push decision) -------
|
|
57
58
|
COMMITS=$(git rev-list "origin/$PIPE_TARGET_BRANCH..HEAD" --count 2>/dev/null || echo 0)
|
|
@@ -60,24 +61,21 @@ COMMITS=$(git rev-list "origin/$PIPE_TARGET_BRANCH..HEAD" --count 2>/dev/null ||
|
|
|
60
61
|
# issue_implemented is emitted only when commits exist (E2E finding N-7:
|
|
61
62
|
# emitting it before this check produced the metric for stuck runs too).
|
|
62
63
|
if [ "${COMMITS:-0}" = "0" ]; then
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
$
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
${PIPE_JOB_URL:+CI job: $PIPE_JOB_URL}"
|
|
80
|
-
issue_set_labels "$CODER_ISSUE" "$PIPE_LABEL_STUCK" "$PIPE_LABEL_READY,$PIPE_LABEL_WIP"
|
|
64
|
+
NOTICE_FILE="$PIPE_CONTEXT_DIR/implementation-failure.md"
|
|
65
|
+
{
|
|
66
|
+
printf 'š¤ '
|
|
67
|
+
pipe_failure_notice_files "implementation of issue #$CODER_ISSUE" "implement this issue by hand" \
|
|
68
|
+
"$PIPE_AGENT_STDERR" "$PIPE_CONTEXT_DIR/implement.env"
|
|
69
|
+
} > "$NOTICE_FILE"
|
|
70
|
+
issue_comment_file "$CODER_ISSUE" "$NOTICE_FILE"
|
|
71
|
+
if pipe_is_credit_exhaustion_files "$PIPE_AGENT_STDERR" "$PIPE_CONTEXT_DIR/implement.env"; then
|
|
72
|
+
pipe_log "Coder credit exhausted; #$CODER_ISSUE remains $PIPE_LABEL_READY"
|
|
73
|
+
else
|
|
74
|
+
pipe_log "Coder made no commits, marking #$CODER_ISSUE stuck"
|
|
75
|
+
pipe_metric_event coder issue_stuck \
|
|
76
|
+
"$(jq -n --argjson i "$CODER_ISSUE" '{issue_iid: $i, reason: "no_commits"}')"
|
|
77
|
+
issue_set_labels "$CODER_ISSUE" "$PIPE_LABEL_STUCK" "$PIPE_LABEL_READY,$PIPE_LABEL_WIP"
|
|
78
|
+
fi
|
|
81
79
|
exit 0
|
|
82
80
|
fi
|
|
83
81
|
|
|
@@ -88,25 +86,27 @@ pipe_metric_event coder issue_implemented \
|
|
|
88
86
|
git push -u origin "$CODER_BRANCH"
|
|
89
87
|
|
|
90
88
|
# --- 8. Open the MR/PR ------------------------------------------------------
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
MR_DESC_FILE="$PIPE_CONTEXT_DIR/mr-description.md"
|
|
90
|
+
{
|
|
91
|
+
printf 'Closes #%s\n\n' "$CODER_ISSUE"
|
|
92
|
+
if [ -s "$PIPE_CONTEXT_DIR/mr-summary.md" ]; then
|
|
93
|
+
cat "$PIPE_CONTEXT_DIR/mr-summary.md"
|
|
94
|
+
else
|
|
95
|
+
printf 'Implemented by the ci-agent-platform coder agent.'
|
|
96
|
+
fi
|
|
97
|
+
printf '\n\n---\nš¤ Implemented by the ci-agent-platform coder\n'
|
|
98
|
+
} > "$MR_DESC_FILE"
|
|
93
99
|
|
|
94
100
|
# Inherit the issue labels onto the MR/PR: drop the ready label, add wip.
|
|
95
101
|
MR_LABELS=$( { echo "$ISSUE_LABELS" | tr ',' '\n' | grep -vxF "$PIPE_LABEL_READY" | grep -v '^$'; echo "$PIPE_LABEL_WIP"; } \
|
|
96
102
|
| awk '!seen[$0]++' | paste -sd, - )
|
|
97
103
|
|
|
98
104
|
MR_TITLE="Resolve \"$ISSUE_TITLE\""
|
|
99
|
-
MR_DESC="Closes #$CODER_ISSUE
|
|
100
|
-
|
|
101
|
-
$SUMMARY
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
š¤ Implemented by the ci-agent-platform coder"
|
|
105
105
|
|
|
106
106
|
# Ensure the MR/PR labels exist (repo/project may not have them yet).
|
|
107
107
|
issue_ensure_label "$PIPE_LABEL_WIP" "#3498DB" "Pipeline is working on this change"
|
|
108
108
|
|
|
109
|
-
MR_URL=$(
|
|
109
|
+
MR_URL=$(mr_create_file "$CODER_BRANCH" "$PIPE_TARGET_BRANCH" "$MR_TITLE" "$MR_DESC_FILE" "$MR_LABELS")
|
|
110
110
|
if [ -n "$MR_URL" ]; then
|
|
111
111
|
pipe_log "Opened MR/PR: $MR_URL"
|
|
112
112
|
else
|