Skip to content

feat(ci): test-impact analysis E2E (default-on) + release E2E workflow - #2559

Merged
Aleksei Sviridkin (lexfrei) merged 4 commits into
mainfrom
daniil/e2e-tia-default-with-release
Jun 9, 2026
Merged

feat(ci): test-impact analysis E2E (default-on) + release E2E workflow#2559
Aleksei Sviridkin (lexfrei) merged 4 commits into
mainfrom
daniil/e2e-tia-default-with-release

Conversation

@myasnikovdaniil

@myasnikovdaniil myasnikovdaniil commented May 2, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Adds test-impact analysis (TIA) to the PR E2E workflow so that only bats files affected by the diff are exercised, and a release-time E2E workflow that runs the full suite on every release tag to keep coverage on the shipped code.

1. Test-impact analysis selector — hack/select-e2e.sh

Reads packages/core/platform/sources/*.yaml (the PackageSource dependency graph) and emits the bats files affected by a PR diff. The walk is the same one cozypkg dot renders.

Input Output
packages/apps/postgres/values.yaml postgres
packages/system/postgres-operator/... postgres harbor (transitive)
packages/system/cilium/... full suite (cilium has many transitive *-application dependents)
packages/library/cozy-lib/... full suite (library affects everything)
hack/e2e-install-cozystack.bats full suite (shared install affects all apps)
hack/e2e-apps/redis.bats redis (per-app edit, never escalates)
docs/agents/contributing.md (empty — no E2E impact)
dashboards/gpu/gpu-fleet.json (empty)

Conservative fallbacks:

  • An unrecognised packages/* path or a system source with no *-application descendants escalates to the full suite, so a path inside the graph is never silently dropped.
  • Per-app bats edits are matched before the full-suite trigger, so editing one bats file selects only that app rather than escalating.

2. Default-on TIA + full-e2e opt-out — pull-requests.yaml

  • The Select E2E tests step runs by default and produces apps + skip outputs.
  • Run E2E tests runs unless skip=true (docs / dashboards / *.md only).
  • Adding the full-e2e label skips the selector step (output empty) and falls through to the unchanged full-bats-list path — the safety hatch when reviewers want the full suite on a PR.

3. release-e2e.yaml — full E2E on every release tag

Triggered on v*.*.*, v*.*.*-rc.*, v*.*.*-beta.*, v*.*.*-alpha.*. Builds images + Talos image, then runs the full suite. Independent of tags.yaml's release publish flow — failure here is an alarm, not a release blocker.

This closes the coverage gap left by making PR runs default to TIA: the full suite is now exercised at tag-cut time against the shipped code.

Tests

hack/select-e2e_test.bats covers 11 cases — single app, transitive operator, networking/library full-suite, docs/dashboards skip, kubernetes-application two-bats mapping, shared E2E helper, install bats, per-app bats no-escalation, release-e2e workflow change.

YAML parse verified for both new workflow files.

Workflow injection safety

All ${{ }} contexts that could carry untrusted data (github.base_ref, label arrays) flow through env vars, never directly into shell text. github.workspace is also indirected through WORKSPACE env in the release workflow.

Release note

NONE

Summary by CodeRabbit

  • Chores

    • CI now runs a Test Impact Analysis to pick only affected apps, reducing E2E runtime.
    • Added a release-level E2E workflow that runs full acceptance tests for version tags with deterministic sandboxing, artifact capture, conditional retries, teardown, and report upload.
    • E2E jobs accept selected-apps metadata and support conditional full-suite overrides.
  • Tests

    • New test suite validates selection logic, operator expansion, full-suite escalation, and docs-only/no-op behaviors.

Three changes that compose into a single E2E policy:

1. **Test-impact analysis selector** (`hack/select-e2e.sh`).
   Reads `packages/core/platform/sources/*.yaml` (the PackageSource
   dependency graph also rendered by `cozypkg dot`) and emits the bats
   files affected by a PR diff. Library/core/networking/CI changes,
   shared `hack/*.sh` helpers, the install bats, and the
   `pull-requests` / `release-e2e` workflows trigger the full suite.
   Doc/dashboard/`*.md` diffs select nothing. Per-app bats edits
   select only that app. Anything inside `packages/` with no graph
   entry, or a system source whose graph has no `*-application`
   descendants, falls back to the full suite (conservative).

2. **Default-on TIA in `pull-requests.yaml`** with `full-e2e`
   opt-out. Drops the previous `e2e-tia` opt-in shape — the
   selector's behaviour has been validated, so making it the default
   gives PR runtime savings out of the box. PRs that need the full
   suite (e.g. cross-cutting refactors that the selector can't
   reason about) carry the `full-e2e` label and get the unchanged
   pre-TIA flow. Docs-only PRs (selector emits nothing) skip the
   `Run E2E tests` step entirely.

3. **`release-e2e.yaml`** runs the full suite on every tag push
   (`v*`). Independent of `tags.yaml`'s release publish flow — a
   failure here is an alarm, not a release blocker. Closes the
   coverage gap left by making PR runs use TIA: the full suite is
   now exercised against shipped code at tag-cut time.

Bug fixes vs. the original `feat/select-e2e-script` draft:
- `dashboard/` -> `dashboards/` (path is plural in this repo).
- `hack/e2e-apps/<name>.sh` and `hack/<name>.bats` were silently
  ignored; they now trigger the full suite (test infrastructure
  affecting all apps).
- A path matching the graph but yielding zero `*-application`
  descendants now falls back to the full suite instead of silently
  emitting nothing (system-only changes are no longer silently
  skipped).
- Per-app bats edits are matched before the full-suite pattern, so
  editing one bats file no longer escalates to the full suite.
- Removed the dead `skip_pattern` variable (PCRE syntax that
  `grep -qE` doesn't support; it was never matched).

Tests: `hack/select-e2e_test.bats` covers all 11 cases (the original
6 plus 5 for the bug fixes above).

Workflow inputs are passed via env vars rather than direct `${{ }}`
expansion into shell commands, per workflow injection guidance.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Assisted-By: Claude <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request optimizes the CI pipeline by implementing intelligent test-impact analysis. By analyzing the dependency graph of the project, the system now selectively runs only the necessary E2E tests for a given set of changes, significantly reducing CI time. Additionally, it establishes a robust release-time testing gate to ensure full suite validation on all tagged releases, balancing development velocity with production stability.

Highlights

  • Test-Impact Analysis (TIA) Implementation: Introduced hack/select-e2e.sh to analyze the dependency graph and identify only the E2E tests affected by a PR, enabling default-on TIA.
  • Workflow Optimization: Updated CI workflows to run TIA by default, with a full-e2e label available to opt-out and trigger the full test suite.
  • Release E2E Automation: Added a dedicated release-e2e.yaml workflow to execute the full E2E suite on every tag, ensuring comprehensive coverage for releases.
  • Test Coverage: Added hack/select-e2e_test.bats to verify the selector logic across 11 different scenarios, including dependency escalation and edge cases.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/pull-requests.yaml
    • .github/workflows/release-e2e.yaml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@dosubot dosubot Bot added the size:L label May 2, 2026
@github-actions github-actions Bot added area/ci Issues or PRs related to CI workflows, GitHub Actions, automation kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files labels May 2, 2026
@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a Test Impact Analysis step to PR E2E that diffs against the base ref and selects affected bats apps via a new hack/select-e2e.sh; PR E2E conditionally runs selected or full suites. Adds a new Release E2E workflow that builds release artifacts and runs a full E2E suite on version tag pushes.

Changes

Smart E2E Test Selection

Layer / File(s) Summary
Selection Logic
hack/select-e2e.sh
New POSIX shell selector: reads changed-path list, defines full-suite trigger patterns, builds owners and reverse-deps from packages/core/platform/sources/*.yaml (via yq), maps PackageSource → bats apps (app_to_bats), computes transitive reverse-deps, and emits selected bats apps or the full-suite list.
Selection Tests
hack/select-e2e_test.bats
New Bats tests validating selector outputs: single-app, operator→dependent apps, multiple full-suite escalation triggers (networking/library/scripts/workflow/install), docs/dashboards no-op, Kubernetes → multiple bats targets, and per-app bats edit selection.
PR Workflow Integration
.github/workflows/pull-requests.yaml
Checkout now uses fetch-depth: 0; adds "Select E2E tests" step that diffs origin/${BASE_REF}...HEAD, runs ./hack/select-e2e.sh, sets apps and skip outputs (skipped if full-e2e label present); OpenAPI tests moved after selection; "Run E2E tests" is conditional on steps.select.outputs.skip != 'true' and receives SELECTED_APPS/FULL_E2E, choosing between full or selected bats lists.

Release E2E Workflow

Layer / File(s) Summary
Workflow Metadata & Triggers
.github/workflows/release-e2e.yaml
New Release E2E workflow triggered on tag pushes v*.*.* (including -rc, -beta, -alpha); concurrency scoped to ref.
Build Job
.github/workflows/release-e2e.yaml
build job (self-hosted): checkout with full history/tags, login to OCI registry, make build PUSH=1, build Talos image, upload Talos raw artifact.
E2E Job
.github/workflows/release-e2e.yaml
e2e job (needs: build): download Talos artifact, derive deterministic SANDBOX_NAME, copy repo to /tmp, retry prepare-env up to 3×, install Cozystack, run OpenAPI tests, iterate full E2E across all hack/e2e-apps/*.bats (test-apps-$app), and fail job if any app fails.
Artifacts & Cleanup
.github/workflows/release-e2e.yaml
Always attempts report collection, uploads cozyreport.tgz as artifact, tears down the sandbox, and removes the workspace directory even on failure.

Sequence Diagrams

sequenceDiagram
    actor Developer
    participant GitHub as "GitHub Actions (PR)"
    participant GitCmd as "git diff"
    participant Selector as "hack/select-e2e.sh"
    participant YQ as "yq (sources index)"
    participant E2E as "E2E Test Suite (bats)"

    Developer->>GitHub: Push PR
    GitHub->>GitCmd: Compute diff vs origin/BASE_REF
    GitCmd-->>Selector: List of changed files
    Selector->>YQ: Build owners & reverse-deps indexes
    YQ-->>Selector: Indexes
    Selector->>Selector: Resolve files → PackageSources → transitive deps → map to bats
    Selector-->>GitHub: outputs `apps=<list>` or `skip=true`
    alt skip == 'true'
        GitHub->>GitHub: Skip E2E
    else
        alt full-e2e label present
            GitHub->>E2E: Run all `hack/e2e-apps/*.bats`
        else
            GitHub->>E2E: Run selected bats files (env SELECTED_APPS)
        end
        E2E-->>GitHub: Test results
    end
    GitHub-->>Developer: Workflow result
Loading
sequenceDiagram
    actor Maintainer
    participant GitHub as "GitHub Actions (Release)"
    participant Build as "build job"
    participant Registry as "OCI Registry"
    participant E2E as "e2e job"
    participant Artifacts as "Artifact Storage"
    participant Sandbox as "Sandbox (prepare-env)"

    Maintainer->>GitHub: Push tag v*.*.*
    GitHub->>Build: Start build job
    Build->>Registry: Log in
    Build->>Build: make build PUSH=1
    Build->>Build: Build Talos image
    Build->>Artifacts: Upload Talos raw artifact
    Build-->>GitHub: build complete
    GitHub->>E2E: Start e2e job (needs: build)
    E2E->>Artifacts: Download Talos artifact
    E2E->>Sandbox: Retry prepare-env (up to 3×)
    Sandbox-->>E2E: Sandbox ready
    E2E->>E2E: Install Cozystack & run OpenAPI tests
    E2E->>E2E: For each `hack/e2e-apps/*.bats`: run `test-apps-$app`
    E2E->>Artifacts: Collect cozyreport.tgz
    E2E->>Sandbox: Teardown
    E2E->>E2E: Remove workspace
    E2E-->>GitHub: Exit 0 or 1
    GitHub-->>Maintainer: Workflow result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through diffs with whiskers bright,

I mapped owners, deps, and chose the right light.
Small runs or full, I pick what’s due—
CI hums, reports pack through. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly summarizes the main changes: adding test-impact analysis to E2E runs (with default-on behavior) and introducing a release E2E workflow.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch daniil/e2e-tia-default-with-release

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot dosubot Bot added the area/testing Issues or PRs related to testing (e2e, bats, unit tests) label May 2, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces hack/select-e2e.sh, a script designed to optimize CI runs by identifying and executing only the E2E tests affected by specific code changes, along with a comprehensive test suite in hack/select-e2e_test.bats. The review feedback highlights several opportunities for optimization and robustness: reducing process overhead by batching yq calls and streamlining the all_apps calculation, using exact matching in grep to prevent false positives with hyphenated package names, and ensuring clean output formatting by avoiding trailing spaces.

Comment thread hack/select-e2e.sh Outdated

# Deduplicate; intersect with available bats files.
final_apps=$(echo "$final" | tr ' ' '\n' | sort -u | grep -v '^$' | while read -r app; do
if echo "$all_apps" | grep -qw "$app"; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using grep -w can lead to false positives because characters like - are often treated as word boundaries in many grep implementations. For example, grep -w "postgres" would match postgres-operator. Since all_apps is newline-separated, grep -Fxq is safer as it matches the entire line exactly.

Suggested change
if echo "$all_apps" | grep -qw "$app"; then
if echo "$all_apps" | grep -Fxq "$app"; then

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — switched to grep -Fxq so apps with hyphenated names can never prefix-match each other. Fixed in 6e5379e.

Comment thread hack/select-e2e.sh
Comment on lines +41 to +48
build_owners_index() {
for f in "$SOURCES_DIR"/*.yaml; do
src=$(yq -r '.metadata.name' "$f")
yq -r '.spec.variants[]?.components[]?.path // ""' "$f" | while read -r path; do
if [ -n "$path" ]; then echo "$path $src"; fi
done
done
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function can be significantly optimized by passing all files to a single yq process instead of calling yq twice per file in a loop. This reduces process overhead and improves performance in CI environments.

Suggested change
build_owners_index() {
for f in "$SOURCES_DIR"/*.yaml; do
src=$(yq -r '.metadata.name' "$f")
yq -r '.spec.variants[]?.components[]?.path // ""' "$f" | while read -r path; do
if [ -n "$path" ]; then echo "$path $src"; fi
done
done
}
build_owners_index() {
yq -r '.metadata.name as $n | .spec.variants[]?.components[]?.path | select(. != null and . != "") | . + "\t" + $n' "$SOURCES_DIR"/*.yaml
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Folded into a single yq invocation with -N to suppress the document separator (otherwise yq emits --- between docs and the output picks up stray blank lines). About 30× faster on 91 source files; output is byte-identical to the loop. Fixed in 6e5379e.

Comment thread hack/select-e2e.sh
Comment on lines +51 to +58
build_reverse_deps() {
for f in "$SOURCES_DIR"/*.yaml; do
src=$(yq -r '.metadata.name' "$f")
yq -r '.spec.variants[]?.dependsOn[]? // ""' "$f" | while read -r dep; do
if [ -n "$dep" ]; then echo "$dep $src"; fi
done
done
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to build_owners_index, this function can be optimized by using a single yq call for all files to avoid the overhead of spawning a process for every YAML file.

Suggested change
build_reverse_deps() {
for f in "$SOURCES_DIR"/*.yaml; do
src=$(yq -r '.metadata.name' "$f")
yq -r '.spec.variants[]?.dependsOn[]? // ""' "$f" | while read -r dep; do
if [ -n "$dep" ]; then echo "$dep $src"; fi
done
done
}
build_reverse_deps() {
yq -r '.metadata.name as $n | .spec.variants[]?.dependsOn[]? | select(. != null and . != "") | . + "\t" + $n' "$SOURCES_DIR"/*.yaml
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same treatment as build_owners_index — single yq with -N. Fixed in 6e5379e.

Comment thread hack/select-e2e.sh
full_suite_pattern='^(packages/library/|packages/core/|api/|cmd/|internal/|hack/[^/]+\.sh$|hack/[^/]+\.bats$|hack/e2e-apps/[^/]+\.sh$|Makefile$|\.github/workflows/(pull-requests|release-e2e)\.yaml$)'

# All known per-app bats files
all_apps=$(ls hack/e2e-apps/*.bats 2>/dev/null | xargs -n1 basename | sed 's/\.bats$//')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

The calculation of all_apps can be optimized by avoiding multiple basename processes via xargs. Using sed to strip the path and extension in a single pipeline is more efficient.

Suggested change
all_apps=$(ls hack/e2e-apps/*.bats 2>/dev/null | xargs -n1 basename | sed 's/\.bats$//')
all_apps=$(ls hack/e2e-apps/*.bats 2>/dev/null | sed 's,.*/,,; s/\.bats$//')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping ls hack/e2e-apps/*.bats | xargs -n1 basename | sed 's/\.bats$//' — the intent (extract filename, strip extension) reads more obviously than a chained sed, and the cost on ~16 files is negligible.

Comment thread hack/select-e2e.sh Outdated
done < "$CHANGED"

if [ "$trigger_full" = 1 ]; then
echo "$all_apps" | tr '\n' ' '

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

Using tr '\n' ' ' leaves a trailing space in the output. Using paste -sd ' ' - is a cleaner way to join lines with spaces and is consistent with how it's used later in the script.

Suggested change
echo "$all_apps" | tr '\n' ' '
echo "$all_apps" | paste -sd ' ' -

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to paste -sd ' ' - for consistency with the existing call at line 147. Fixed in 6e5379e.

Comment thread hack/select-e2e.sh Outdated
# silently skip E2E. Fall back to full suite so a path inside the graph is
# never silently dropped.
if [ -z "$final_apps" ]; then
echo "$all_apps" | tr '\n' ' '

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

Use paste to avoid a trailing space in the output for the full suite fallback.

Suggested change
echo "$all_apps" | tr '\n' ' '
echo "$all_apps" | paste -sd ' ' -

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same — paste -sd ' ' -. Fixed in 6e5379e.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
hack/select-e2e.sh (1)

25-25: 💤 Low value

Consider using find instead of ls | xargs for robustness.

While bats filenames in this project are controlled and unlikely to contain special characters, using find would be more robust against edge cases.

♻️ Optional fix
-all_apps=$(ls hack/e2e-apps/*.bats 2>/dev/null | xargs -n1 basename | sed 's/\.bats$//')
+all_apps=$(find hack/e2e-apps -maxdepth 1 -name '*.bats' -exec basename {} .bats \; 2>/dev/null | sort)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/select-e2e.sh` at line 25, Replace the fragile pipeline that builds
all_apps using "ls | xargs | sed" with a robust find-based command: update the
assignment to all_apps (the variable defined in the script) so it uses find to
locate files under hack/e2e-apps with a .bats suffix, prints only the basename
without the extension, and handles missing files without errors; keep the
resulting value format identical (space-separated names) so downstream
references to all_apps continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hack/select-e2e_test.bats`:
- Around line 75-80: The test "per-app bats edit selects only that app, never
escalates" uses an exact string equality check ([ "$output" = "redis" ]) which
can fail due to trailing newlines/whitespace; update the assertion in
hack/select-e2e_test.bats to mirror the postgres fix by comparing a trimmed
output or using a pattern match (e.g., checking that $output contains or matches
"redis") so trailing whitespace/newlines don't cause flakiness, and ensure the
same approach is used in the parallel postgres test for consistency; modify the
assertion in this test (the block starting with `@test` "per-app bats edit selects
only that app, never escalates") accordingly.

---

Nitpick comments:
In `@hack/select-e2e.sh`:
- Line 25: Replace the fragile pipeline that builds all_apps using "ls | xargs |
sed" with a robust find-based command: update the assignment to all_apps (the
variable defined in the script) so it uses find to locate files under
hack/e2e-apps with a .bats suffix, prints only the basename without the
extension, and handles missing files without errors; keep the resulting value
format identical (space-separated names) so downstream references to all_apps
continue to work.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 65c506ce-adba-4b35-8924-97b3c1e54601

📥 Commits

Reviewing files that changed from the base of the PR and between 5786afe and 0788e94.

📒 Files selected for processing (4)
  • .github/workflows/pull-requests.yaml
  • .github/workflows/release-e2e.yaml
  • hack/select-e2e.sh
  • hack/select-e2e_test.bats

Comment thread hack/select-e2e_test.bats
- Use grep -Fxq instead of -w when intersecting with all_apps so apps
  with hyphenated names cannot prefix-match each other.
- Collapse build_owners_index and build_reverse_deps into single yq
  invocations with -N. Output is identical to the per-file loop and
  about 30x faster on the current 91 PackageSource files.
- Use paste -sd ' ' - on the two full-suite emit paths for consistency
  with the post-walk join at line 147.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@dosubot dosubot Bot added size:L and removed size/L This PR changes 100-499 lines, ignoring generated files size:L labels May 2, 2026
@github-actions github-actions Bot removed the size:L label May 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hack/select-e2e.sh`:
- Around line 80-94: The current logic only recognizes
packages/(apps|system|extra) when computing rel and silently ignores other
packages/* paths; change the script so any path matching ^packages/[^/]+/ that
does not produce a mapped rel triggers a full-suite run: after computing rel and
before the final else branch, detect if "$file" matches the packages/* pattern
and if so set trigger_full=1 (instead of ignoring), preserving existing behavior
for when src is found (selected_sources addition using selected_sources and src)
and for non-packages paths.
- Line 25: Replace the fragile ls|xargs pipeline that populates all_apps with a
safe shell glob loop: iterate over the hack/e2e-apps/*.bats pattern, skip
non-matches, extract the base name via parameter expansion (e.g.,
name="${f##*/}" and strip the .bats suffix with "${name%.bats}"), and append
each safe filename to the all_apps variable; update the assignment that
currently uses all_apps=$(ls ... | xargs ... | sed ...) to this loop in
hack/select-e2e.sh so filenames with spaces or leading dashes are handled
correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a576c098-29cc-475d-92e7-d17854014d5b

📥 Commits

Reviewing files that changed from the base of the PR and between 0788e94 and 6e5379e.

📒 Files selected for processing (1)
  • hack/select-e2e.sh

Comment thread hack/select-e2e.sh
full_suite_pattern='^(packages/library/|packages/core/|api/|cmd/|internal/|hack/[^/]+\.sh$|hack/[^/]+\.bats$|hack/e2e-apps/[^/]+\.sh$|Makefile$|\.github/workflows/(pull-requests|release-e2e)\.yaml$)'

# All known per-app bats files
all_apps=$(ls hack/e2e-apps/*.bats 2>/dev/null | xargs -n1 basename | sed 's/\.bats$//')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid parsing ls here.

ls | xargs basename is brittle in sh: filenames with spaces/leading dashes will be mangled, and an empty glob can make the command behave unexpectedly under set -e. Please verify this path with a simple filename that contains whitespace.

🔎 Read-only verification script
#!/bin/sh
set -eu

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT

mkdir -p "$tmp/hack/e2e-apps"
: > "$tmp/hack/e2e-apps/foo bar.bats"
: > "$tmp/hack/e2e-apps/baz.bats"

cd "$tmp"
ls hack/e2e-apps/*.bats 2>/dev/null | xargs -n1 basename | sed 's/\.bats$//'
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 25-25: Use 'find .. -print0 | xargs -0 ..' or 'find .. -exec .. +' to allow non-alphanumeric filenames.

(SC2011)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/select-e2e.sh` at line 25, Replace the fragile ls|xargs pipeline that
populates all_apps with a safe shell glob loop: iterate over the
hack/e2e-apps/*.bats pattern, skip non-matches, extract the base name via
parameter expansion (e.g., name="${f##*/}" and strip the .bats suffix with
"${name%.bats}"), and append each safe filename to the all_apps variable; update
the assignment that currently uses all_apps=$(ls ... | xargs ... | sed ...) to
this loop in hack/select-e2e.sh so filenames with spaces or leading dashes are
handled correctly.

Comment thread hack/select-e2e.sh
Comment on lines +80 to +94
# 4. Component change: lookup in PackageSource graph
rel=$(echo "$file" | sed -nE 's,^packages/(apps|system|extra)/([^/]+)/.*,\1/\2,p')
if [ -n "$rel" ]; then
src=$(echo "$OWNERS" | awk -v p="$rel" -F'\t' '$1==p {print $2}')
if [ -n "$src" ]; then
selected_sources="$selected_sources $src"
trigger_any=1
else
# Inside packages/ but no graph entry — be conservative.
trigger_full=1
fi
fi
# Anything else (e.g. unrelated workflow files, top-level configs) is
# silently ignored.
done < "$CHANGED"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Treat unknown packages/* paths as full-suite triggers.

Right now only packages/apps, packages/system, and packages/extra are mapped into rel. Any future or renamed subtree under packages/ that does not match those prefixes is silently ignored, even though the comment and PR objective say unrecognized packages/* paths should run the full suite.

♻️ Suggested fix
   rel=$(echo "$file" | sed -nE 's,^packages/(apps|system|extra)/([^/]+)/.*,\1/\2,p')
   if [ -n "$rel" ]; then
     src=$(echo "$OWNERS" | awk -v p="$rel" -F'\t' '$1==p {print $2}')
     if [ -n "$src" ]; then
       selected_sources="$selected_sources $src"
       trigger_any=1
     else
       # Inside packages/ but no graph entry — be conservative.
       trigger_full=1
     fi
+  elif echo "$file" | grep -qE '^packages/'; then
+    trigger_full=1
   fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/select-e2e.sh` around lines 80 - 94, The current logic only recognizes
packages/(apps|system|extra) when computing rel and silently ignores other
packages/* paths; change the script so any path matching ^packages/[^/]+/ that
does not produce a mapped rel triggers a full-suite run: after computing rel and
before the final else branch, detect if "$file" matches the packages/* pattern
and if so set trigger_full=1 (instead of ignoring), preserving existing behavior
for when src is found (selected_sources addition using selected_sources and src)
and for non-packages paths.

CI invokes hack/cozytest.sh, a project-local pure-shell harness, not
bats. cozytest does not honor setup()/teardown() and does not provide
bats' run / $status / $output, so the original tests failed with
"TMPDIR: parameter not set" under set -u.

Inline tmpdir creation and an EXIT trap for cleanup in each test.
Replace `run` + `$output` with direct command substitution, and
replace `! grep` (which set -e ignores) with an explicit if-then-exit.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@dosubot dosubot Bot added the size:L label May 3, 2026
@github-actions github-actions Bot added the size/L This PR changes 100-499 lines, ignoring generated files label May 3, 2026
The "Select E2E tests" step runs `git diff --name-only
origin/${BASE_REF}...HEAD` inside the sandbox copy of the workspace.
Without fetch-depth: 0 the e2e job's checkout only resolves a single
commit, so origin/main is missing and the diff aborts with
"ambiguous argument 'origin/main...HEAD': unknown revision".

Mirror the Build job's setup and request full history.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
@dosubot dosubot Bot added size:L and removed size/L This PR changes 100-499 lines, ignoring generated files size:L labels May 3, 2026
@github-actions github-actions Bot removed the size:L label May 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/pull-requests.yaml:
- Around line 256-288: The E2E selector step (name: "Select E2E tests", id:
select) runs after sandbox provisioning and OpenAPI work, so move this
lightweight selector earlier in the workflow (before provisioning/CozyStack
install) and then gate the heavy steps (the "Run OpenAPI tests" step and any
sandbox/provisioning steps) on its output (use steps.select.outputs.skip !=
'true') so those expensive actions are skipped when skip=true; update the
conditions for the provisioning/OpenAPI/E2E steps to reference
steps.select.outputs.skip and ensure the selector still emits "skip" and "apps"
to $GITHUB_OUTPUT.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7ea8f411-21f8-4c23-a462-e5ac39629e14

📥 Commits

Reviewing files that changed from the base of the PR and between 77f80b5 and 4672d88.

📒 Files selected for processing (1)
  • .github/workflows/pull-requests.yaml

Comment on lines +256 to +288
# Test Impact Analysis (TIA): walk the PackageSource graph for the PR
# diff and select only the bats files affected. Runs by default; opt
# out via the `full-e2e` label to run the full suite.
# `skip=true` means nothing to test (docs-only PR).
- name: Select E2E tests
id: select
if: ${{ !contains(github.event.pull_request.labels.*.name, 'full-e2e') }}
env:
BASE_REF: ${{ github.base_ref }}
run: |
cd /tmp/$SANDBOX_NAME
git diff --name-only "origin/${BASE_REF}...HEAD" > /tmp/changed.txt
apps=$(./hack/select-e2e.sh /tmp/changed.txt)
echo "Selected apps: ${apps:-<none>}"
echo "apps=${apps}" >> $GITHUB_OUTPUT
if [ -z "${apps}" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi

- name: Run OpenAPI tests
run: |
cd /tmp/$SANDBOX_NAME
make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-openapi

# ▸ Run E2E tests
# Run E2E tests. With `full-e2e` label the selector is skipped, its
# outputs are empty, the != 'true' guard lets this step run, and the
# full bats list is used. Without the label, the selector decides;
# an empty selection (docs-only) skips this step entirely.
- name: Run E2E tests
id: e2e_tests
if: ${{ steps.select.outputs.skip != 'true' }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Gate the expensive E2E path before provisioning.

skip=true is only computed after sandbox prep, Cozystack install, and OpenAPI have already run, so PRs with no affected bats still consume almost the full E2E job. To get the intended CI savings, move the selector into a lightweight upstream job (or at least before provisioning) and gate the heavy steps on its outputs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pull-requests.yaml around lines 256 - 288, The E2E
selector step (name: "Select E2E tests", id: select) runs after sandbox
provisioning and OpenAPI work, so move this lightweight selector earlier in the
workflow (before provisioning/CozyStack install) and then gate the heavy steps
(the "Run OpenAPI tests" step and any sandbox/provisioning steps) on its output
(use steps.select.outputs.skip != 'true') so those expensive actions are skipped
when skip=true; update the conditions for the provisioning/OpenAPI/E2E steps to
reference steps.select.outputs.skip and ensure the selector still emits "skip"
and "apps" to $GITHUB_OUTPUT.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — fail-safe test-impact selector (over-selects on any uncertainty, never silently drops an app) backed by a release-tag full-suite safety net; matching is precise and the 11-case bats suite covers the key paths.

Business context: PR E2E ran the full suite on every change; this adds diff-based test-impact analysis so a PR only runs the bats files its diff affects, with the full suite preserved at release-tag time so shipped code keeps full coverage.

Verified: the selector is fail-safe in every uncertain case — full_suite_pattern escalates library/core/api/cmd/internal/shared-hack/Makefile/workflow changes to the full suite, an app resolved from the dependency graph that is not a real bats app falls back to the full suite (the explicit "never silently skip" guard), and matching uses anchored grep -qE '^...' and fixed-string whole-line grep -Fxq, not word-boundary matching — so the grep -w concern raised on the thread does not apply to the current code. Per-app bats edits select only that app (checked before the full-suite trigger), which is correct since a bats file is that app's own test. hack/select-e2e_test.bats passes all 11 cases (single app, transitive operator, networking/library full-suite, docs/dashboards skip, two-bats kubernetes-application, shared helper, install bats, per-app no-escalation, release-workflow change). The release-e2e workflow runs independently of the publish flow, so a failure alarms without blocking the release.

Non-blocking: the build_owners_index / all_apps helpers shell out per file; batching into a single yq / basename pass (as suggested on the thread) would speed the selector up, though it runs once per PR so the cost is negligible. The residual gap — app-to-app runtime coupling that has no PackageSource edge — is the one case TIA can miss, and it is exactly what the release-tag full suite is there to catch.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit c961ffe into main Jun 9, 2026
12 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the daniil/e2e-tia-default-with-release branch June 9, 2026 20:51
myasnikovdaniil added a commit that referenced this pull request Jun 25, 2026
Reconcile the parallel-matrix PR build (#2983) with main, which since this branch
diverged landed a competing single-VM build restructure (#2939) and
test-impact-analysis E2E (#2559). Per maintainer decision, #2983's matrix build
supersedes #2939:

- .github/workflows/pull-requests.yaml: keep #2983's
  plan/checks/build(matrix)/build-talos/finalize jobs; keep main's newer
  resolve_assets/e2e (carrying #2559 test-impact E2E). The build->e2e artifact
  interface (pr-patch + talos-image) is identical on both sides, so e2e depends
  on finalize/build-talos with no input rewiring. main's top-level permissions
  and SHA-pinned action refs applied across all jobs.
- All other files merged cleanly (only pull-requests.yaml conflicted).

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci Issues or PRs related to CI workflows, GitHub Actions, automation area/testing Issues or PRs related to testing (e2e, bats, unit tests) kind/feature Categorizes issue or PR as related to a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants