Skip to main content

flaky-test-catcher

Detects broken and flaky acceptance tests from recent CI failures on main and opens structured GitHub issues for automated remediation. Follow this skill strictly when analyzing CI failures.

Informations de source

Dépôt
elastic/terraform-provider-elasticstack
Dernière activité de la source
5 mai 2026 à 10:47
Langue détectée de SKILL.md
anglais
Étoiles
210
Forks
155

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
flaky-test-catcher
description
Detects broken and flaky acceptance tests from recent CI failures on main and opens structured GitHub issues for automated remediation. Follow this skill strictly when analyzing CI failures.
# Flaky Test Catcher — Analysis Protocol ## 1. Overview / Purpose This skill defines the end-to-end protocol for detecting broken and flaky acceptance tests by analyzing recent CI failures on `main`, then opening structured GitHub issues so that automated remediation workflows can address the root causes. You **must** follow this protocol strictly. Do not improvise or skip steps. ## 2. Inputs from pre-activation context The workflow pre-activation step has already computed all run-level data. Do **not** re-query GitHub for run lists or issue counts. Use the values injected into your prompt: | Variable | Meaning | |---|---| | `failed_run_ids` | JSON array of run IDs of failed `test.yml` runs on `main` in the last 3 days | | `total_run_count` | Count of completed runs with meaningful conclusions (success, failure, timed\_out, neutral, action\_required) — cancelled runs excluded | | `open_issues` | Current count of open `flaky-test` issues | | `issue_slots_available` | How many new issues you may create (max 3) | Parse `failed_run_ids` as a JSON array immediately. Example: `["12345678","87654321"]`. ## 3. Fetching job logs For each run ID in `failed_run_ids`: ### 3.1 List jobs for the run ``` gh api /repos/{owner}/{repo}/actions/runs/{run_id}/jobs?per_page=100 ``` Replace `{owner}` and `{repo}` with the values from the repository's GitHub remote (visible in `git remote get-url origin`). ### 3.2 Filter to relevant failing jobs From the returned `jobs` array, keep only jobs where **both** conditions hold: - `conclusion == "failure"` - The job name contains `Matrix Acceptance Test` (this is the job group that runs acceptance tests) Ignore infrastructure jobs (e.g. lint, build, generate) — they do not produce `--- FAIL:` lines. ### 3.3 Fetch the log for each failing job The GitHub API log endpoint returns a ZIP archive. Use the `gh` CLI to stream plain-text logs for a job: ```bash gh run view --job {job_id} --log | grep '^--- FAIL:' ``` **Log size warning**: Job logs can be very large (10 MB+). Do **not** load the full log into context. Instead: - Stream the log output through `grep` so only matching lines are retained. - Scan only for lines matching the `--- FAIL:` pattern (see §4). - Use `grep -B3 -A3` or similar when you also need surrounding context for the "Sample Failure Output" issue section. - Capture a small surrounding context (3–5 lines before/after each `--- FAIL:` line) for the "Sample Failure Output" issue section. ### 3.4 Pagination If a job list response has 100 items and there may be more, check the `Link` header for a `next` page URL and repeat the request. In practice, a single run rarely has more than 100 jobs. ## 4. `--- FAIL:` extraction pattern Scan each log for lines that match this exact pattern: ``` ^--- FAIL: TestName (timing) ``` Examples of matching lines: ``` --- FAIL: TestAccResourceAgentConfiguration_alternateEnvironment (12.34s) --- FAIL: TestAccSomeResource_basic (0.45s) ``` **Rules:** - The line must start with `--- FAIL:` (three hyphens, a space, `FAIL:`, a space). - The test name follows Go test naming: `TestAcc...` with optional underscore-separated sub-name. - Extract **only the test function name** — strip the timing suffix `(12.34s)`. - **Ignore** bare `FAIL` lines without the `---` prefix; those are package-level failure markers, not individual test failures. Collect all extracted test names across all runs and all jobs. A test may appear multiple times (once per run where it failed) — track counts. **Same-run deduplication**: If the same test name appears in multiple failing jobs within a single run (e.g. multiple shards both failing the same test), count it **only once** for that run. Deduplication is by run ID, not job ID — use a set per run when accumulating test names. ## 5. Fail-rate formula and thresholds For each unique test name: ``` fail_rate = fail_count / total_run_count ``` Where: - `fail_count` = number of distinct run IDs in which this test appeared as `--- FAIL:` - `total_run_count` = the value from pre-activation context (already excludes cancelled runs) | Classification | Condition | Action | |---|---|---| | **Broken** | `fail_rate == 1.0` (fails in 100% of runs) | Create issue | | **Flaky** | `fail_rate >= 0.20` and `< 1.0` | Create issue | | **Noise** | `fail_rate < 0.20` | Ignore — do not create issues | ## 6. Base-test-name grouping rule Extract the **base test name** from each test function name using this rule: > Take the substring from the beginning up to (but not including) the first underscore `_`. Pattern: `TestAcc[^_]+` Examples: | Full test name | Base test name | |---|---| | `TestAccResourceAgentConfiguration_alternateEnvironment` | `TestAccResourceAgentConfiguration` | | `TestAccResourceAgentConfiguration_minimal` | `TestAccResourceAgentConfiguration` | | `TestAccResourceAgentConfiguration` | `TestAccResourceAgentConfiguration` | | `TestAccSomeResource_basic` | `TestAccSomeResource` | **One issue per base test name.** All scenario variants (subtests/suffixes) belonging to the same base name are consolidated into a single issue. List each specific variant inside the issue body. **Fallback for non-`TestAcc` tests**: All acceptance tests in this project follow the `TestAcc` prefix convention. If a non-`TestAcc` test name appears in the logs, treat everything up to the first `_` (or the full name if no `_`) as the base name. ## 7. Commit analysis steps For each base test name that will receive an issue, investigate whether any recent commit may already address the failure: ### 7.1 Find the oldest failing run timestamp From the `failed_run_ids` list, identify the oldest run's `created_at` timestamp. You can get metadata for a single run: ``` gh api /repos/{owner}/{repo}/actions/runs/{run_id} ``` Take the minimum `created_at` across all failed runs. ### 7.2 Fetch commits on `main` since that timestamp ``` gh api "/repos/{owner}/{repo}/commits?sha=main&since={timestamp}&per_page=50" ``` Replace `{timestamp}` with the ISO 8601 value from step 7.1 (e.g. `2024-01-15T12:00:00Z`). ### 7.3 For each commit, check relevance For each commit returned: **a. Commit message relevance** — does it reference any of: - The base test name (e.g. `TestAccResourceAgentConfiguration`) - The resource name (derive from the test name, e.g. `agent_configuration` → `AgentConfiguration`) - Keywords: `fix`, `flaky`, `test`, `revert` **b. Changed file relevance** — fetch the full commit detail to get changed file paths: ``` gh api /repos/{owner}/{repo}/commits/{sha} ``` Check if any file in `files[].filename` matches patterns like: - `*_test.go` files whose name contains a token from the resource name - Files in the same Go package directory as the test ### 7.4 Include findings in issue body - If a relevant commit is found: ``` ⚠️ may already be addressed in `{short_sha}` — {one-line message summary} ``` - If no relevant commits found: ``` No recent commits appear to address this failure. ``` Frame the analysis as "has this been fixed yet?" — not as blame attribution. **Do not suppress issue creation**: Even if a fix commit is found, always proceed with creating the issue and include the fix-detection note in the Commit Analysis section. The issue serves as the remediation trigger regardless. ## 8. Issue deduplication Before creating an issue for a base test name, check whether one already exists: ``` gh api "/repos/{owner}/{repo}/issues?labels=flaky-test&state=open&per_page=100" ``` - Inspect each returned issue's `title`. - The **full rendered title** for flaky-test issues is: `[flaky-test] {BaseTestName}` (the `[flaky-test] ` prefix is applied automatically by the `create-issue` safe output). When checking for duplicates, compare against this full title as it appears in GitHub. - If an **exact title match** exists, skip creating a new issue for that base test name. - Do **not** re-query or recalculate `issue_slots_available`; use only the value from pre-activation. - If the response contains exactly 100 results, check for a `next` link in the `Link` response header and repeat the request for subsequent pages until all open issues are fetched. ## 9. Required issue body sections **Issue title**: Pass only `{BaseTestName}` to the `create-issue` safe output — the `[flaky-test] ` prefix is added automatically. Every issue you create must contain exactly these 5 sections in this order: ```markdown ## Broken Tests List each test function name (including scenario suffix) that failed in 100% of runs: - ❌ `TestAccResourceFoo_basic` — failed in 5/5 runs ## Flaky Tests List each test function name that failed in ≥ 20% but < 100% of runs, with the observed rate: - ⚠️ `TestAccResourceFoo_update` — failed in 3/5 runs (60%) - ⚠️ `TestAccResourceFoo_import` — failed in 1/5 runs (20%) ## Commit Analysis {Output from §7. Either a ⚠️ note about a possible fix commit, or the "No recent commits" message. Include commit SHA, message, and affected file paths when relevant.} ## Sample Failure Output {Short excerpt (5–15 lines) of the actual log output surrounding a `--- FAIL:` line. Include any immediately preceding error messages for context.} ## Affected Stack Versions {List the Elastic Stack versions / matrix dimension values (e.g. Elasticsearch version, Kibana version) from the failing job names or log metadata. If not determinable, write "Unknown — not present in log output".} ``` **Formatting rules:** - Use `❌` for broken tests (100% fail rate). - Use `⚠️` for flaky tests (20%–99% fail rate), and always include the fraction and percentage. - Keep "Sample Failure Output" to the most informative excerpt; do not paste hundreds of lines. **Cap enforcement**: Before creating each issue, verify that the number of issues created so far in this run has not reached `issue_slots_available`. Stop creating issues once the cap is reached, even if additional base test names remain. ## 10. Noop conditions Call `noop` with a descriptive explanation (do not create any issues) when **any** of these conditions holds: 1. **All failures already have open issues** — every qualifying base test name matched an existing open `flaky-test` issue during deduplication; nothing new to open. 2. **All failures are below the 20% threshold** — every observed `--- FAIL:` test has `fail_rate < 0.20`; there are no broken or flaky tests to report. 3. **No `--- FAIL:` patterns found** — none of the logs for the provided `failed_run_ids` contained a `--- FAIL:` line; the CI failures were likely infrastructure failures (network timeouts, setup errors, etc.) rather than test logic failures. When calling `noop`, state which condition applied and include basic counts (e.g. "3 failures observed, all below 20% threshold"). ## Summary of execution order 1. Parse `failed_run_ids` from pre-activation context. 2. For each run ID: list jobs → filter to failing `Matrix Acceptance Test` jobs → fetch and scan logs for `--- FAIL:` lines. 3. Aggregate per-test fail counts across all runs. 4. Apply fail-rate thresholds; discard noise (`< 20%`). 5. Group surviving tests by base test name. 6. Deduplicate against existing open `flaky-test` issues. 7. For each remaining base test name (up to `issue_slots_available`): run commit analysis, then create an issue with all 5 required sections. 8. If no issues were created, call `noop`.
Voir sur GitHub