Skip to content

chore(deps): bump github/codeql-action/analyze from 4.37.0 to 4.37.2 #820

chore(deps): bump github/codeql-action/analyze from 4.37.0 to 4.37.2

chore(deps): bump github/codeql-action/analyze from 4.37.0 to 4.37.2 #820

Workflow file for this run

# Integration test workflow (act + gitea testcontainers).
# Triggers:
# push: branches main standalone run on trunk - populates the status badge.
# pull_request gate every PR before merge.
# merge_group runs as a merge-queue gate before merging to main.
# workflow_dispatch manual run against any ref (existing).
#
# This is a ~27min testcontainers run. Path filtering now happens at the job
# level (via the `changes` job using dorny/paths-filter) so the required gate
# context always reports, preventing the required-but-skipped deadlock. The
# concurrency group cancels a superseded run on the same ref so a fast
# follow-up push does not stack two 27min runs. Run locally
# (`go test -v ./e2e/...`) before pushing too.
#
# NOTE: the `name:` below is referenced by fleet-e2e.yaml's workflow_run trigger
# ("Integration (act + gitea)"). Keep the two in sync if this is ever renamed.
name: Integration (act + gitea)
on:
push:
branches: [main]
pull_request:
merge_group:
workflow_dispatch:
inputs:
ref:
description: 'Branch or commit SHA to test (default: main)'
required: false
default: main
timeout:
description: 'Per-package go test timeout (e.g. 60m)'
required: false
default: '60m'
parallel:
description: 'Subtest parallelism (lower = slower but more reliable)'
required: false
default: '1'
shard:
description: 'Run only this single shard index 0-4 (blank = full matrix)'
required: false
default: ''
scenario:
description: 'Run only scenarios whose subtest name matches this -run pattern (blank = all)'
required: false
default: ''
# A superseded run on the same ref is cancelled rather than left to burn a full
# ~27min testcontainers slot. Keyed on github.ref so each branch/PR/tag is its
# own lane; merge_group runs key on their own ref and never collide with main.
concurrency:
group: integration-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
changes:
name: Detect Code Changes
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
code: ${{ steps.compute.outputs.code }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- id: filter
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
with:
filters: |
code:
- 'cmd/**'
- 'e2e/**'
- 'go.mod'
- 'go.sum'
- 'internal/**'
- id: compute
run: |
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "code=true" >> "$GITHUB_OUTPUT"
else
echo "code=${{ steps.filter.outputs.code }}" >> "$GITHUB_OUTPUT"
fi
plan:
name: Plan Shards
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
shards: ${{ steps.compute.outputs.shards }}
steps:
- id: compute
# Build the matrix shard list. A manual `shard` input collapses the
# matrix to that single leg for targeted reruns. A `scenario` input
# without a shard also collapses to a single leg, because the test code
# bypasses sharding when a scenario filter is set and would otherwise run
# the same scenarios on every leg. Otherwise the full set of five shards
# runs. The shard input is validated to one digit 0-4 so it cannot
# inject arbitrary JSON into the matrix expression.
env:
SHARD_INPUT: ${{ github.event.inputs.shard }}
SCENARIO_INPUT: ${{ github.event.inputs.scenario }}
run: |
if [ -n "$SHARD_INPUT" ]; then
case "$SHARD_INPUT" in
[0-4])
echo "shards=[$SHARD_INPUT]" >> "$GITHUB_OUTPUT"
exit 0
;;
*)
echo "Invalid shard input '$SHARD_INPUT'; expected a single index 0-4." >&2
exit 1
;;
esac
fi
if [ -n "$SCENARIO_INPUT" ]; then
echo 'shards=[0]' >> "$GITHUB_OUTPUT"
exit 0
fi
echo 'shards=[0,1,2,3,4]' >> "$GITHUB_OUTPUT"
e2e:
# The scenario suite is split across N runners (one matrix leg per shard).
# Each leg runs its slice serially (E2E_PARALLEL=1) to keep the per-box
# reliability floor, so a single environmental flake fails one short leg
# rather than the whole multi-hour suite. E2E_SHARD_TOTAL must match the
# length of the shard list below; the Go side reads both values from the
# environment and falls back to running everything when they are unset.
name: E2E Tests (shard ${{ matrix.shard }})
needs: [changes, plan]
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
timeout-minutes: 35
strategy:
# One shard's flake must not cancel the others; each is independently
# rerunnable from the failed matrix leg.
fail-fast: false
matrix:
# Computed by the plan job: the full five-shard set, or a single shard
# when the workflow_dispatch `shard` input collapses the matrix.
shard: ${{ fromJSON(needs.plan.outputs.shards) }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# workflow_dispatch: honour the explicit ref input.
# All other triggers (push:tags, merge_group): use the exact SHA
# that triggered the run so we test what GitHub resolved.
ref: ${{ github.event.inputs.ref || github.sha }}
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# The e2e module declares its own toolchain (go 1.24). Drive the
# installed Go straight from e2e/go.mod so the runner always matches
# the module requirement. Pinning a literal version here drifts: when
# it lags the module's `go` directive, `go test` fails immediately
# under GOTOOLCHAIN=local with "go.mod requires go >= 1.24.0".
go-version-file: e2e/go.mod
cache: true
cache-dependency-path: e2e/go.sum
- name: Show runner resources
run: |
echo "=== CPU ==="
nproc
echo "=== Memory ==="
free -h
echo "=== Disk ==="
df -h /
- name: Install gotestsum
# gotestsum drives the rerun-on-failure self-heal: on a failed run it
# reruns only the individual failed scenarios (not the whole shard),
# giving three total attempts per leg before the shard fails.
run: go install gotest.tools/gotestsum@v1.13.0
- name: Run e2e tests
working-directory: e2e
env:
# Each shard runs roughly a fifth of the suite, so 30m of per-package
# headroom is ample. Override per-dispatch as needed.
E2E_TIMEOUT: ${{ github.event.inputs.timeout || '30m' }}
# Cap subtest parallelism. The GitHub runner has 4 cores / ~7.9GB
# RAM. Each scenario spins up gitea + act + N job containers; at
# the default GOMAXPROCS=4, four scenarios concurrently exhaust
# memory and the test process is OOM-killed (silent FAIL with no
# per-test output, see #104). Even at 2 the concurrent container
# load throttles gitea and destabilises act runs, so the default is
# serial (1); raise it per-dispatch only when chasing wall-clock.
E2E_PARALLEL: ${{ github.event.inputs.parallel || '1' }}
# Scenario sharding. The Go side sorts scenarios by name and selects
# those whose position modulo the total equals this index, so the
# union of all legs is the whole suite with no overlap. Keep
# E2E_SHARD_TOTAL equal to the matrix shard-list length.
E2E_SHARD_INDEX: ${{ matrix.shard }}
E2E_SHARD_TOTAL: 5
# Optional single-scenario filter for manual debugging. The test code
# reads it as a regular expression over scenario names and, when set,
# bypasses sharding so one leg runs only the matching scenarios. It is
# consumed only by the Go test process, never by the shell.
E2E_SCENARIO: ${{ github.event.inputs.scenario }}
run: |
# --rerun-fails=2 gives three total attempts and reruns only the
# scenarios that failed; the leg passes if every scenario passes
# within those attempts.
gotestsum \
--format standard-verbose \
--rerun-fails=2 \
--rerun-fails-report rerun-report.txt \
--packages=./... \
-- \
-timeout "$E2E_TIMEOUT" \
-parallel "$E2E_PARALLEL"
# On a retry-exhausted scenario the harness writes the last attempt's raw
# act stdout/stderr to e2e/_artifacts/<scenario>-attempt<N>.log so the
# stack-trace origin survives the CI log retention window. Upload it on
# every run (always()) so the evidence is recoverable whether the job
# failed or a flake was absorbed. The directory may not exist when no
# scenario exhausted its retries; if-no-files-found: ignore keeps that a
# clean no-op rather than a warning.
- name: Upload e2e crash evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
# Per-shard name: upload-artifact rejects duplicate names across
# matrix legs, so each shard writes its own evidence artifact.
name: e2e-crash-evidence-shard-${{ matrix.shard }}
path: e2e/_artifacts/
if-no-files-found: ignore
retention-days: 14
gate:
# This always-run context is the branch-protection required check. It mirrors
# the heavy E2E result when E2E runs and passes cleanly when E2E is correctly
# skipped on non-code changes, avoiding the required-but-skipped deadlock.
# needs.e2e aggregates every shard in the matrix: its result is success only
# when all legs pass and failure if any single shard fails, so this gate
# stays the one required-check identity over the whole sharded suite.
name: Integration Gate
needs: [changes, plan, e2e]
if: always()
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check Integration Status
env:
CHANGES_RESULT: ${{ needs.changes.result }}
PLAN_RESULT: ${{ needs.plan.result }}
E2E_RESULT: ${{ needs.e2e.result }}
run: |
# The detection job must succeed for its `code` output to be trusted.
# If it failed or was cancelled, fail the gate rather than wave the
# change through on a stale/empty signal.
if [ "$CHANGES_RESULT" != "success" ]; then
echo "Integration gate: change-detection result=$CHANGES_RESULT, failing the gate."
exit 1
fi
# The plan job computes the shard matrix. When no code changed it is
# correctly skipped (alongside e2e); any other non-success is a real
# failure that must not be waved through.
if [ "$PLAN_RESULT" != "success" ] && [ "$PLAN_RESULT" != "skipped" ]; then
echo "Integration gate: shard-plan result=$PLAN_RESULT, failing the gate."
exit 1
fi
# E2E success means a code change passed the heavy suite. E2E skipped
# means no code path changed, which is a legitimate pass.
if [ "$E2E_RESULT" = "success" ] || [ "$E2E_RESULT" = "skipped" ]; then
echo "Integration gate: E2E result=$E2E_RESULT, gate passes."
exit 0
fi
echo "Integration gate: E2E result=$E2E_RESULT, failing the gate."
exit 1