Skip to main content

follow-pr

Monitor the current PR's GitLab pipeline to completion, then report success, auto-fix, or investigate a failure. Use when the user asks to follow, babysit, watch, or wait on a PR/pipeline, or just after pushing to / creating a PR.

Quellinformationen

Repository
DataDog/datadog-agent
Letzte Quellaktivität
9. Oktober 2026 um 14:52
Erkannte Sprache von SKILL.md
Englisch
Sterne
3.759
Forks
1.506

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
4 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
follow-pr
description
Monitor the current PR's GitLab pipeline to completion, then report success, auto-fix, or investigate a failure. Use when the user asks to follow, babysit, watch, or wait on a PR/pipeline, or just after pushing to / creating a PR.
argument-hint
[<ref> | --pipeline <id>] [--fix-mode autofix|no-autofix|ask] [--max-fix-cycles N] [--policy TEXT]
model
sonnet
# Follow PR Watch the latest Gitlab CI pipeline for the current PR to a terminal state, report the outcome, and — for failures reliably caused by this PR — autonomously fix and push bounded ones under the resolved autonomy policy while investigating the rest locally. **Owning team:** `@DataDog/agent-devx` ## Step 0: Ensure correct environment The appropriate tool for this usecase is `ddgl`, and more specifically `ddgl attach`. Check if `ddgl` is available - `which ddgl`. If so, move to [Step 1](#step-1-determine-the-target). Otherwise, use a dev env as specified below. ### Ensuring a dev env First, check if you are running in a dev env: `test -f /.started` will exit 0 if so. If you are in an outdated devenv without `ddgl`, stop and notify the user to recreate his dev env. Otherwise, check for the existence of a dev env by using `dda env dev show`. **If there are existing dev envs**: - Check if the current repo is properly mounted into that env (`repos` and `extra_(mount|volume)_specs` fields) - Check the current state of that dev env. If the environment is already started and contains the right repo, move to [the next step](#using-a-dev-env). Otherwise, create one by using `./scripts/create_devenv.sh`, then use the environment ID printed by the script in subsequent commands. ### Using a dev env To run commands inside a dev env, use the following template: ```bash dda env dev run --id <dev-env-id> -- [command] ``` Watch out for space-splitting. For example: ```bash dda env dev run --id follow-pr-attach-7C2C42F6 -- ddgl attach --detail=normal --follow --plain ``` ## Step 1: Determine the target Determine the ref to follow - either the user passed it in explicitly, or use the current branch (`git branch --show-current`). > If the user provided a direct pipeline ID, skip to [Step 3](#step-3-resolve-the-autonomy-policy). ## Step 2: Attach the label to the PR Make sure the open PR for that ref, if any, carries the `follow-pr` label: ```bash .agents/skills/follow-pr/scripts/label_pr.sh <ref> ``` The script tries every authenticated `gh` account (the PR may live in either the `DataDog` or `ddoghq` org) and prints a single `ok:` or `skipped:` line. Labeling is best-effort: whatever the result, continue to [Step 3](#step-3-resolve-the-autonomy-policy). ## Step 3: Resolve the autonomy policy Before starting the monitoring loop, resolve how this run should handle failures caused by the PR's own code: ```bash python3 .agents/skills/follow-pr/scripts/config.py resolve \ [--mode <from --fix-mode arg>] [--max-fix-cycles <from arg>] [--policy <from arg>] ``` Pass through any `--fix-mode`, `--max-fix-cycles`, or policy text given in this invocation; otherwise the script falls back to environment variables, then worktree-local config, then global config, then its own default (`autofix`). > If the config ended up resolving using only the default values, suggest the user create a global/local config file with the settings he just chose for future invocations. Check the script contents to get the appropriate paths and formats. - **Resolved mode is `autofix` or `no-autofix`:** report the resolved mode, cycle budget, and whether a custom policy is active, then continue to [Step 4](#step-4-start-monitoring). - **Resolved mode is `ask`, or the script errors:** ask the user directly, before monitoring starts, whether PR-caused failures this run should be fixed and pushed (`autofix`) or only investigated locally (`no-autofix`). Offer to persist the answer (worktree-local or global config) if they don't want to be asked again; otherwise use it for this run only. Keep the resolved mode, cycle budget (default `2`), and policy text in context — you'll pass them straight through as `--mode`/`--max-fix-cycles`/`--policy` to subskills that might need it. ## Step 4: Start monitoring All pipeline discovery, polling, follow/rebind, and timeout handling is covered by the internals of `ddgl attach`. Do not implement a second polling loop or persist monitoring state of your own. Check whether you have a long-lived monitoring tool available, one that can run a command in the background and forward each stdout line as it arrives, without a timeout of its own (e.g. Claude Code's `Monitor` tool). **With such a tool:** start it on ```bash ddgl attach --plain --follow --detail=full [--ref <ref> | --pipeline <id>] ``` and wait for a `[FINAL]` line — no `--timeout` needed. **Without one:** run it in the foreground, bounded so the invocation cannot outlive your own harness timeout: ```bash ddgl attach --plain --follow --detail=full --timeout 600 [--ref <ref> | --pipeline <id>] ``` If the `[FINAL]` line reports a timeout (not a pipeline outcome), start an identical invocation again. This is safe: `attach` is stateless and each invocation begins with a fresh snapshot of the pipeline. > NOTE: If the pipeline is already terminal or does not exist when you start monitoring, the user might have just pushed and the pipeline is still waiting to be created. > In this case, wait for 60 seconds and then re-attempt monitoring. The `--follow` argument will make sure `ddgl attach` always monitors the latest pipeline for the ref. ## Step 5: Interpret the output You may see: - `[POLL]` - rollup summary after a changed poll tick (jobs done/total, stage, failure count). Informational only. - `[INFO]` - an informational log from `ddgl` itself. - `[PIPE]` - a change in the pipeline status. - `[JOB]` - a job finished running and changed state. - `[FINAL]` - the terminal, authoritative outcome. Treat this line as the source of truth regardless of the command's exit code — it names the pipeline id, terminal status, and, on failure, the failed job names. ## Step 6: Act on the outcome - **Pipeline Success:** stop monitoring and report the pipeline succeeded, using the [final report](#final-report) template. - **Some job failed, but the pipeline is still running**: Most jobs on `datadog-agent` CI retry once automatically on any failure (`.gitlab-ci.yml`'s default `retry: max: 1, when: always`), so a first-attempt failure alone isn't yet evidence of anything — GitLab will retry it once. A minority of jobs (most e2e, Windows, macOS — `.retry_only_infra_failure`) retry only on GitLab's infra-flavoured `failure_reason` values, so a `script_failure` there gets no automatic retry at all and is worth a closer look sooner. Unit test, linter, and build failures are less likely to be flakes regardless of policy. If you're unsure which policy a job is on: `grep -rn '<job-name>' .gitlab/ .gitlab-ci.yml`. Otherwise, ask the user whether to continue monitoring, or if this job failure is already a problem. In the latter case, move to [Step 7](#step-7-follow-up-on-failures). - **Pipeline failed or canceled:** Stop monitoring, report the status, and move to [Step 7](#step-7-follow-up-on-failures). - **Timeout `[FINAL]`:** re-invoke `ddgl attach` as in [Step 4](#step-4-start-monitoring); this is not a true terminal outcome. - **Unexpected error** (from `ddgl` itself, or from the monitoring tool): report what happened. Do not attempt a recovery action. ## Step 7: follow-up on failures Invoke `/triage-ci-failure` on the pipeline id from the `[FINAL]` line; it returns one `CI triage result` block per failed job. Route each block by its `Blame` field — never by whether `Incident` happens to be `none`, since that value alone doesn't tell you the job wasn't PR-caused: - **`upstream`:** if `Incident` is active and still breaking, continue to [Step 8](#step-8-watch-an-unresolved-incident) and wait it out. If `stable` or `resolved`, tell the user it's safe to rebase onto `main` and re-run — say plainly that `stable` is a weaker signal than `resolved` (the fix may still be in progress). If no incident is declared at all, say CI looks broken on `main` with nothing declared for it — worth surfacing loudly. Investigation ends here for that job. - **`infra` or `flake`:** report the verdict and its suggested action (typically a retry, citing the evidence `/triage-ci-failure` gave you). Investigation ends here for that job. - **`inconclusive`:** report the evidence and the two most likely readings. Investigation ends here for that job. - **`pr-code`:** collect every `pr-code` block from this pipeline. Before invoking the handler, check for repeats against every push made earlier in this same run: 1. If any `Failure signature` matches one from an earlier push, that fix didn't work — tell `/handle-pr-ci-failure` explicitly that this failure already survived one autonomous attempt, so it treats that root cause as blocked rather than reattempting it as `safe`. 2. If the fix-cycle budget is already fully consumed, tell `/handle-pr-ci-failure` it has no push budget left this run, so it should investigate every root cause without committing or pushing, same as `no-autofix`. 3. Otherwise, nothing to flag — invoke it normally. Either way, invoke `/handle-pr-ci-failure` once with all of this pipeline's `pr-code` blocks together, passing `--mode`/`--max-fix-cycles`/`--policy` set to the values resolved in [Step 3](#step-3-resolve-the-autonomy-policy). Continue to [Step 9](#step-9-decide-whether-to-keep-going) with its result. ## Step 8: watch an unresolved incident Only entered when `/triage-ci-failure` reported an incident that's still **active and breaking** for a failed job — this is the other half of watching a PR through: the pipeline is red because of something outside the PR, and it will stay red until that something changes. Poll the incident on an interval (a few minutes is reasonable; don't busy-loop): ```bash .agents/skills/triage-ci-failure/scripts/incidents.py timeline <IR-nnnnn> ``` Watch for a state transition off `active` — to `stable` (a rollback or workaround has likely landed; rebasing is probably safe even if the root cause isn't fully fixed yet) or `resolved`/`completed` (the stronger signal). Once either happens, confirm recovery before telling the user to act — check that the job is passing again on `main`: ```bash pup cicd events aggregate \ --query='ci_level:job @ci.pipeline.name:DataDog/datadog-agent @git.branch:main @ci.job.name:"<job name>"' \ --compute=count --group-by='@ci.status' --from='2h' ``` Once `main` is clean, tell the user it's time to rebase onto `main` and re-run. ## Step 9: decide whether to keep going Read `/handle-pr-ci-failure`'s result block: - **`Outcome: pushed`:** record its `Failure signatures` and increment the cycle count — [Step 7](#step-7-follow-up-on-failures) needs both for the repeat/budget checks on the *next* pipeline. Go back to [Step 4](#step-4-start-monitoring) to watch the replacement pipeline at the `Pushed SHA` regardless of whether the budget is now exhausted; you still need to confirm this fix actually worked before you can stop. Return here through Step 7 once it finishes. - **`Outcome: committed-not-pushed`:** report the local commit and the remaining complex root cause(s) blocking a push using the [final report](#final-report) template, then stop and let the user decide. - **`Outcome: needs-user` or `blocked`:** report the evidence and the specific question `/handle-pr-ci-failure` asked for using the [final report](#final-report) template, then stop. Every trip back through this loop re-runs `/triage-ci-failure` from scratch on the new pipeline — never reuse an earlier verdict for a different pipeline. ## Final report Whenever you stop for good — pipeline succeeded, an upstream/infra/flake verdict ended investigation, or `/handle-pr-ci-failure` returned anything other than a fresh `pushed`, close with this block instead of ad hoc prose: ```text Follow-PR report Pipeline: <final pipeline id> (<SHA>) Status: succeeded | failed | needs-user Fixes pushed: <count> — <commit SHAs, or none> Cycles consumed: <N>/<max_fix_cycles> Remaining issues: <summary, or none> User decision needed: <question, or none> End follow-PR report ``` ## Examples - A missed rename breaks a lint job. `/triage-ci-failure` returns one `pr-code` block; `/handle-pr-ci-failure` classifies it `safe`, fixes it, verifies with `dda inv linter.go`, commits, and pushes. Step 9 sees `Outcome: pushed` (cycle 1 of 2), goes back to Step 4, and the replacement pipeline goes green. - A test fails intermittently under `-race`. `/handle-pr-ci-failure` classifies it `complex`, reproduces it locally, tries two distinct hypotheses, and stops with `Outcome: needs-user` and an uncommitted candidate diff — nothing is pushed. - A pushed fix's replacement pipeline fails again with the same `Failure signature`. Step 7 recognizes the repeat before invoking the handler, tells it not to reattempt a fix, and it investigates instead — no second push happens.
Auf GitHub ansehen