Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 238 additions & 0 deletions agents_as_skills/ship-mr/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
---
name: ship-mr
description: Full review-to-merge workflow — review code, cross-check Jira, triage pipeline, post comments, approve and auto-merge a GitLab merge request.
---

# Ship MR — Full Review-to-Merge Workflow

You are running the complete merge request workflow: review, triage, comment, and (if clean) approve + auto-merge. Use the Ymir privileged MCP gateway tools throughout.

## Parse arguments

Extract from the user's input:
- `project` — the GitLab project path (e.g. `redhat/centos-stream/rpms/bash`) — **required**
- `mr_iid` — the merge request IID (the number after `!`) — **required**
- `--jira <issue-key>` — optional Jira issue key (e.g. `RHEL-184006`)

If `project` or `mr_iid` is missing, ask the user before proceeding.

If `--jira` is not provided, try to detect the Jira issue key from the MR title, description, or branch name (pattern: `RHEL-\d+`).

---

## GLOBAL COMMENT RULE

Every comment you post via `reply_to_mr_discussion` or `add_merge_request_comment` must end with:

```
🤖 Generated by Ymir
```

---

## PHASE 1: GATHER

Call these tools **in parallel** to minimize latency:

1. `get_merge_request_details` with the MR URL — title, description, source/target branch, merge status
2. `get_mr_changes` — full diff of all changed files (also returns `diff_refs`)
3. `get_mr_discussions` — existing discussion threads (to avoid duplicate comments)
4. `get_mr_pipelines_with_status` — all pipelines and their statuses
5. `get_jira_details` — **if Jira key available:** fetch full issue details
6. `get_jira_pull_requests` — **if Jira key available:** fetch linked MRs

Save the `diff_refs` from `get_mr_changes` — you need `base_sha`, `start_sha`, `head_sha` for inline comments.

**Report to user:**
```
Reviewing MR !<iid>: "<title>" -> <target_branch>
Linked Jira: <issue_key> — "<jira_summary>" [<jira_status>]
```

---

## PHASE 2: ANALYZE CODE

Review every changed file in the diff for:

- **Critical/Major bugs** — logic errors, null dereferences, race conditions, data loss, missing error handling on critical paths
- **Security issues** — injection, hardcoded secrets/tokens, insecure defaults
- **Performance** — N+1 queries, unbounded loops, missing indexes
- **Minor/Nit** — dead code, naming issues, style inconsistencies

**Skip** auto-generated files, lock files, vendored dependencies, and changelog entries.

Classify each finding: `critical`, `major`, `minor`, or `nit`.

Track:
- `blockers` = count of critical + major findings
- `total_findings` = count of all findings

---

## PHASE 2b: CROSS-CHECK WITH JIRA (if Jira issue available)

- Verify the MR changes address what the Jira issue requires
- Flag if the MR only partially implements requirements or adds scope not in Jira
- Note: `jira_completeness` (full/partial/unclear), `jira_scope_creep` (true/false)

---

## PHASE 3: ANALYZE PIPELINE

From the pipelines gathered in Phase 1, identify the **latest pipeline**.

**IMPORTANT:** A parent pipeline may show `success` even when child pipelines have failed. Always check `child_pipelines`. If ANY child pipeline has `status == "failed"`, treat as FAILED.

### If pipeline PASSED (parent and all children):
- `pipeline_ok = true`, `new_regressions = 0`

### If pipeline FAILED:

First check `get_mr_discussions` for developer-posted waivers (waiver language: "waiv", "known issue", "pre-existing", "expected failure").

Then call **in parallel**:
1. `get_pipeline_failed_jobs_deep` with the pipeline ID — get failed jobs, stages, and log tails
2. `compare_mr_test_failures` — separate new regressions from pre-existing failures *(skip if all failures are already waived by developer comments)*

Categorize:
- **Check/build stage failures** — ALWAYS a blocker, never waivable
- **New test regressions** — blocker
- **Pre-existing test failures** — not a blocker (waived)
- **Infrastructure failures** — not a blocker (suggest retry)

Set:
- `pipeline_ok = false` if ANY check/build failure OR new test regression
- `pipeline_ok = true` ONLY if no check/build failures AND all test failures are pre-existing/waived
- `new_regressions` = count of genuinely new failures

### If pipeline RUNNING:
- `pipeline_ok = "running"` — auto-merge can still be set

---

## PHASE 4: POST COMMENTS

### 4a. Post pipeline analysis (if pipeline had failures) — ALWAYS FIRST

From `get_mr_discussions`, find the active (unresolved) pipeline results thread (look for `<!--RESULTS_COMMENT-->` or pipeline ID/URL in the body).

Use `reply_to_mr_discussion` to reply to that thread. Only fall back to `add_merge_request_comment` if no pipeline thread exists.

Format:
```
### Pipeline Analysis — Pipeline #<id>

**New Regressions:** N
**Pre-existing (waived):** N
**Infrastructure (retriable):** N

<details for each new regression: job name, error, suggested fix>
```

### 4b. Post inline code review comments

For each **major or critical** finding, use `create_mr_inline_comment` at the exact file and line. Use `diff_refs` from Phase 1.

Before posting, check existing discussions to avoid duplicates.

Format:
```
**[SEVERITY]** <one-line summary>

<detailed explanation>

**Suggestion:** <how to fix>
```

### 4c. Post minor/nit findings + Jira cross-check as ONE combined note

Use `add_merge_request_comment` with a single combined note:

```
### Code Review — Minor Findings

| # | File | Line | Severity | Issue |
|---|------|------|----------|-------|
| 1 | src/foo.py | 42 | minor | Description |

---

### Jira Cross-Check — <issue_key>: <jira_summary>

| Check | Result |
|-------|--------|
| Jira Status | <status> |
| Priority | <priority> |
| Completeness | full / partial / unclear |
| Scope Creep | none / yes |
```

---

## PHASE 5: DECISION GATE

Evaluate:

| Condition | Check |
|-----------|-------|
| No critical/major code findings | `blockers == 0` |
| Pipeline clean | `pipeline_ok == true` OR `pipeline_ok == "running"` |
| No merge conflicts | MR has no conflicts |
| Not a draft | Title doesn't start with "Draft:" or "WIP:" |

### If ALL conditions pass — SHIP IT

Apply a final confidence check. If there is ANY residual doubt (unverified infrastructure failures, large number of waivers, AI-generated patches), **block instead**.

If confident:

1. **Resolve all unresolved discussions** — call `resolve_mr_discussion` in parallel for each unresolved thread
2. **Post approval comment** via `add_merge_request_comment`:
```
Review Complete — Approved

Code Review: <total_findings> findings (0 blockers)
Pipeline: <passing / all waived / running>
Jira: <issue_key> — <completeness> | <priority>
Verdict: LGTM — approving and setting auto-merge.
```
3. **Approve** via `approve_merge_request`
4. **Set auto-merge** via `set_mr_auto_merge`

### If ANY condition fails — BLOCK

Post via `add_merge_request_comment`:
```
Review Complete — Changes Requested

Code Review: <blockers> blocker(s) found
<list each: file:line — summary>

Pipeline: <N> new regression(s)
<list each: job — error>

Other Blockers:
<if conflicts: "Merge conflicts detected — please rebase">
<if draft: "MR is in draft state">
```

Do NOT approve or set auto-merge.

---

## OUTPUT SUMMARY

End with a dashboard:

```
## /ship-mr Summary: !<iid> "<title>"

| Phase | Result |
|------------------|-------------------------------------------|
| Code Review | N findings (N blockers) |
| Jira Cross-Check | <issue_key>: <completeness> / <priority> |
| Pipeline | passed / N new regressions / waived |
| Comments Posted | N inline + N summary |
| Verdict | Approved + Auto-merge / Blocked |
```
97 changes: 97 additions & 0 deletions agents_as_skills/triage-pipeline/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
name: triage-pipeline
description: Triage CI/CD pipeline failures for a GitLab merge request — analyze failed jobs, compare with previous MRs, categorize regressions vs waived failures, and optionally post a comment.
---

# Triage Pipeline Failures

You are triaging CI/CD pipeline failures for a GitLab merge request using the Ymir privileged MCP gateway tools.

## Parse arguments

Extract from the user's input:
- `project` — the GitLab project path (e.g. `redhat/centos-stream/rpms/bash`)
- `mr_iid` — the merge request IID (the number after `!`)
- `--report` flag — if present, generate a detailed text report
- `--deep` flag — if present, include full log analysis for each failed job
- `--comment` flag — if present, post the triage summary as a reply on the MR

If any required argument is missing, ask the user.

## GLOBAL COMMENT RULE

Every comment body you post via `reply_to_mr_discussion` or `add_merge_request_comment` must end with:

```
🤖 Generated by Ymir
```

---

## Step 1: Get pipeline overview

1. Call `get_mr_pipelines_with_status` with `project` and `mr_iid`
2. Identify the latest pipeline (highest ID)
3. If the latest pipeline status is `success` **and all child pipelines are also successful**, report that and stop.
- **IMPORTANT:** A parent pipeline may show `success` even when child pipelines have failed. Always check `child_pipelines` in the result. If ANY child pipeline has `status == "failed"`, treat the overall pipeline as FAILED and continue.

## Step 2: Get failed job details

Call `get_pipeline_failed_jobs_deep` with the failed pipeline ID to get:
- Job names, stages, and failure reasons
- Log tail output from each failed job
- Any child/downstream pipeline failures

## Step 3: Check for developer-posted waivers

Call `get_mr_discussions` to fetch all discussion threads. Scan for **non-bot human comments** containing waiver language: "waiv", "known issue", "pre-existing", "skip this failure", "ignoring", "expected failure", or similar.

- If **all** failures are covered by developer waivers → treat as waived, skip `compare_mr_test_failures`
- If **some** → treat those as waived, call `compare_mr_test_failures` for the rest
- If **none** → proceed with the full comparison

## Step 4: Compare with previous MR

Call `compare_mr_test_failures` to identify:
- **new_failures** — regressions introduced by this MR (need attention)
- **waived_failures** — failures also present in the previous merged MR (pre-existing, can be waived)
- **fixed** — failures that were present before but now pass

## Step 5: Categorize failures

Group failures into:
- **Check/build failures** (`pre_build`, `check`, `build` stage) — **never waivable**, always a blocker
- **Test failures** — waivable if pre-existing in the previous MR
- **Infrastructure failures** — timeout, runner issues — suggest retry

## Output

Present a structured summary:

```
## Pipeline #<id> — <status>

### New Regressions (action required)
- Job: <name> | Stage: <stage> | Reason: <reason>
Key error: <extracted from log>
Suggested fix: <recommendation>

### Pre-existing / Waived Failures
- Job: <name> — also failed in previous MR (waived)

### Summary
- Total failed jobs: N
- New regressions: N (need fixing)
- Pre-existing: N (waived)
- Infrastructure: N (retry may help)
```

End with actionable recommendations: which jobs to retry, which failures need code fixes, and whether the MR is likely safe to merge despite failures.

## Step 6: Post comment on MR (if --comment flag)

If the user passed `--comment`:
1. From `get_mr_discussions`, find the unresolved discussion thread referencing the pipeline failure (look for `<!--RESULTS_COMMENT-->` or pipeline ID in the body)
2. Use `reply_to_mr_discussion` to reply to that thread with the triage summary
3. If no pipeline results thread exists, fall back to `add_merge_request_comment`
4. Check for duplicate — if a triage reply for the same pipeline ID already exists, skip posting
Loading