Skip to content
Merged
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
185 changes: 108 additions & 77 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ parameters:
orbs:
go: circleci/go@1.8.0
gcp-cli: circleci/gcp-cli@3.0.1
slack: circleci/slack@5.1.1
slack: circleci/slack@6.0.0
shellcheck: circleci/shellcheck@3.2.0
codecov: codecov/codecov@5.0.3
utils: ethereum-optimism/circleci-utils@1.0.20
Expand Down Expand Up @@ -356,6 +356,11 @@ jobs:
resource_class: <<# parameters.use_circleci_runner >>xlarge<</ parameters.use_circleci_runner >><<^ parameters.use_circleci_runner >>ethereum-optimism/latitude-1<</ parameters.use_circleci_runner >>
steps:
- checkout-from-workspace
- run:
name: Lint/Vet/Build op-acceptance-tests/cmd
working_directory: op-acceptance-tests
command: |
just cmd-check
- run:
name: Setup Kurtosis
command: |
Expand Down Expand Up @@ -1454,6 +1459,11 @@ jobs:
name: Download Go dependencies
working_directory: op-acceptance-tests
command: go mod download
- run:
name: Lint/Vet/Build op-acceptance-tests/cmd
working_directory: op-acceptance-tests
command: |
just cmd-check
# Persist schedule name into env var
- run:
name: Persist schedule name into env var
Expand Down Expand Up @@ -1550,6 +1560,11 @@ jobs:
name: Download Go dependencies
working_directory: op-acceptance-tests
command: go mod download
- run:
name: Lint/Vet/Build op-acceptance-tests/cmd
working_directory: op-acceptance-tests
command: |
just cmd-check
# Prepare the test environment
- run:
name: Prepare test environment (compile tests and cache build results)
Expand Down Expand Up @@ -1635,36 +1650,22 @@ jobs:
name: Download Go dependencies
working_directory: op-acceptance-tests
command: go mod download
- run:
name: Lint/Vet/Build op-acceptance-tests/cmd
working_directory: op-acceptance-tests
command: |
just cmd-check
- run:
name: Calculate iterations for worker
command: |
# Get total iterations and worker info from CircleCI parallelism
TOTAL_ITER=<< pipeline.parameters.flake-shake-iterations >>
WORKERS=${CIRCLE_NODE_TOTAL}
WORKER_ID=$((CIRCLE_NODE_INDEX + 1))

# Calculate how many iterations each worker should run
ITER_PER_WORKER=$((TOTAL_ITER / WORKERS))
REMAINDER=$((TOTAL_ITER % WORKERS))

# Distribute the remainder (first $REMAINDER workers get one extra iteration)
if [ $WORKER_ID -le $REMAINDER ]; then
ITER_COUNT=$((ITER_PER_WORKER + 1))
else
ITER_COUNT=$ITER_PER_WORKER
fi

echo "Worker $WORKER_ID running $ITER_COUNT of $TOTAL_ITER iterations"
echo "export FLAKE_SHAKE_ITERATIONS=$ITER_COUNT" >> $BASH_ENV
echo "export FLAKE_SHAKE_WORKER_ID=$WORKER_ID" >> $BASH_ENV
bash ./op-acceptance-tests/scripts/ci_flake_shake_calc_iterations.sh << pipeline.parameters.flake-shake-iterations >>
- run:
name: Run flake-shake iterations
no_output_timeout: 2h
working_directory: op-acceptance-tests
command: |
OUTPUT_DIR="logs/flake-shake-results-worker-${FLAKE_SHAKE_WORKER_ID}"
mkdir -p "$OUTPUT_DIR"

op-acceptor \
--validators ./acceptance-tests.yaml \
--gate << parameters.gate >> \
Expand All @@ -1689,6 +1690,11 @@ jobs:
- checkout-from-workspace
- attach_workspace:
at: .
- run:
name: Lint/Vet/Build op-acceptance-tests/cmd
working_directory: op-acceptance-tests
command: |
just cmd-check
- run:
name: Build flake-shake aggregator
working_directory: op-acceptance-tests
Expand All @@ -1706,67 +1712,84 @@ jobs:
- run:
name: Generate summary
command: |
if [ -f final-report/flake-shake-report.json ]; then
echo "=== Flake-Shake Results ==="
STABLE=$(jq '[.tests[] | select(.recommendation == "STABLE")] | length' final-report/flake-shake-report.json)
UNSTABLE=$(jq '[.tests[] | select(.recommendation == "UNSTABLE")] | length' final-report/flake-shake-report.json)
echo "✅ STABLE: $STABLE tests"
echo "⚠️ UNSTABLE: $UNSTABLE tests"
if [ "$UNSTABLE" -gt 0 ]; then
echo "Unstable tests:"
jq -r '.tests[] | select(.recommendation == "UNSTABLE") | " - \(.test_name) (\(.pass_rate)%)"' final-report/flake-shake-report.json
fi
# Write daily summary (include stable and unstable tests)
jq '{date, gate, total_runs, iterations,
totals: {
stable: ([.tests[] | select(.recommendation=="STABLE")] | length),
unstable: ([.tests[] | select(.recommendation=="UNSTABLE")] | length)
},
stable_tests: [
.tests[] | select(.recommendation=="STABLE") |
{test_name, package, total_runs, pass_rate}
],
unstable_tests: [
.tests[] | select(.recommendation=="UNSTABLE") |
{test_name, package, total_runs, passes, failures, pass_rate}
]
}' final-report/flake-shake-report.json > final-report/daily-summary.json

# Write promotion readiness (100% pass)
jq '{ready: [.tests[] | select(.recommendation=="STABLE") | {test_name, package, total_runs, pass_rate, avg_duration, min_duration, max_duration}]}' final-report/flake-shake-report.json > final-report/promotion-ready.json

# Export UNSTABLE_COUNT for later steps
echo "export UNSTABLE_COUNT=$UNSTABLE" >> $BASH_ENV
else
echo "ERROR: No report found"
exit 1
bash ./op-acceptance-tests/scripts/ci_flake_shake_generate_summary.sh final-report/flake-shake-report.json final-report
- store_artifacts:
path: ./final-report
destination: flake-shake-report

op-acceptance-tests-flake-shake-promote:
machine:
image: ubuntu-2404:current
resource_class: large
steps:
- checkout-from-workspace
- run:
name: Lint/Vet/Build op-acceptance-tests/cmd
working_directory: op-acceptance-tests
command: |
just cmd-check
- run:
name: Build flake-shake promoter
working_directory: op-acceptance-tests
command: |
go mod download
go build -o ../flake-shake-promoter ./cmd/flake-shake-promoter/main.go
- run:
name: Set GH_TOKEN
command: |
if [ -n "${GITHUB_TOKEN_GOVERNANCE:-}" ]; then
echo "export GH_TOKEN=${GITHUB_TOKEN_GOVERNANCE}" >> "$BASH_ENV"
fi
- run:
name: Prepare Discord owner mentions
name: Validate GH_TOKEN is present
command: |
# Build owner mentions for unstable tests
OWNERS_FILE=$(mktemp)
# Iterate over unstable tests and resolve owners from YAML metadata
jq -r '.tests[] | select(.recommendation=="UNSTABLE") | [.package, .test_name] | @tsv' final-report/flake-shake-report.json | while IFS=$'\t' read -r PKG NAME; do
OWNER=$(yq -r \
".gates[] | select(.id==\"flake-shake\") | .tests[] | select(.package==\"${PKG}\" and ((.name // \"\")==\"${NAME}\")) | (.metadata.owner // \"\")" \
op-acceptance-tests/acceptance-tests.yaml)
if [ -n "$OWNER" ]; then echo "$OWNER" >> "$OWNERS_FILE"; fi
done
if [ -s "$OWNERS_FILE" ]; then
# unique list and prefix with @ for readability
OWNERS=$(sort -u "$OWNERS_FILE" | sed 's/^/@/')
echo "Resolved owners:" $OWNERS
echo "export EXTRA_DISCORD_MENTIONS=\"$OWNERS\"" >> $BASH_ENV
else
echo "No owners resolved"
if [ -z "${GH_TOKEN:-}" ]; then
echo "GH_TOKEN is required for PR creation" >&2
exit 1
fi
- discord-notification-failures-on-develop:
message: "Flake-Shake report is ready. See artifacts for details."
mentions: "$EXTRA_DISCORD_MENTIONS"
- run:
name: Run flake-shake promoter
command: |
./flake-shake-promoter \
--org ethereum-optimism \
--repo optimism \
--branch "<< pipeline.git.branch >>" \
--workflow scheduled-flake-shake \
--report-job op-acceptance-tests-flake-shake-report \
--days 3 \
--gate flake-shake \
--min-runs 300 \
--max-failure-rate 0.01 \
--min-age-days 3 \
--dry-run=false \
--require-clean-24h \
--out ./final-promotion \
--verbose
- store_artifacts:
path: ./final-report
destination: flake-shake-report
path: ./final-promotion
destination: flake-shake-promotion
- run:
name: Prepare Slack message (promotion candidates)
command: |
bash ./op-acceptance-tests/scripts/ci_flake_shake_prepare_slack.sh ./final-promotion/promotion-ready.json
- run:
name: Slack - Sending Notification
command: |
set -euo pipefail
# The Slack orb conditionals evaluate at compile time; guard at runtime instead.
if [ -z "${SLACK_BLOCKS_PAYLOAD:-}" ] || [ "${SLACK_BLOCKS_PAYLOAD}" = "[]" ]; then
echo "SLACK_BLOCKS is empty or doesn't exist. Skipping it..."
exit 0
fi
echo "$SLACK_BLOCKS_PAYLOAD" | jq '.' > /tmp/blocks.json
jq -c '{blocks: .}' /tmp/blocks.json > /tmp/slack_template.json
echo 'export SLACK_TEMPLATE=$(cat /tmp/slack_template.json)' >> $BASH_ENV
- slack/notify:
channel: notify-ci-failures
event: always
retries: 1
retry_delay: 3
template: SLACK_TEMPLATE

sanitize-op-program:
docker:
Expand Down Expand Up @@ -2953,6 +2976,14 @@ workflows:
- op-acceptance-tests-flake-shake-report:
requires:
- op-acceptance-tests-flake-shake
- op-acceptance-tests-flake-shake-promote:
requires:
- op-acceptance-tests-flake-shake-report
context:
- circleci-repo-readonly-authenticated-github-token
- circleci-repo-optimism
- circleci-api-token
- slack

scheduled-preimage-reproducibility:
when:
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
github.com/go-task/slim-sprig/v3 v3.0.0
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/go-cmp v0.7.0
github.com/google/go-github/v55 v55.0.0
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
Expand Down Expand Up @@ -67,6 +68,7 @@ require (
golang.org/x/crypto v0.36.0
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
golang.org/x/mod v0.22.0
golang.org/x/oauth2 v0.25.0
golang.org/x/sync v0.14.0
golang.org/x/term v0.30.0
golang.org/x/text v0.25.0
Expand All @@ -82,6 +84,7 @@ require (
git.sr.ht/~sbinet/gg v0.6.0 // indirect
github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
github.com/adrg/xdg v0.4.0 // indirect
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
Expand All @@ -97,6 +100,7 @@ require (
github.com/campoy/embedmd v1.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
Expand Down Expand Up @@ -144,6 +148,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect
github.com/graph-gophers/graphql-go v1.3.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lpr
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
Expand Down Expand Up @@ -106,6 +108,7 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY=
github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
Expand Down Expand Up @@ -136,6 +139,9 @@ github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
Expand Down Expand Up @@ -355,7 +361,11 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 h1:Ep/joEub9YwcjRY6ND3+Y/w0ncE540RtGatVhtZL0/Q=
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -1056,6 +1066,8 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
34 changes: 23 additions & 11 deletions op-acceptance-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,21 +212,14 @@ gates:
tests:
- package: github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/yourtest
timeout: 10m
metadata:
target_gate: base # Where to promote once stable
metatada:
owner: stefano
```

### Understanding Reports

Flake-shake generates comprehensive reports in two formats:
- **`flake-shake-report.json`**: Machine-readable results for automation
- **`flake-shake-report.html`**: Human-friendly visualization with charts

Reports include:
- **Pass rate**: Percentage of successful runs per test
- **Timing statistics**: Min/avg/max execution duration
- **Failure patterns**: First few failure logs for debugging
- **Stability recommendation**: STABLE or UNSTABLE classification
Flake-shake stores a daily summary artifact per run:
- **`final-report/daily-summary.json`**: Aggregated counts of stable/unstable tests and per-test pass/fail tallies.

### CI Integration

Expand All @@ -235,6 +228,25 @@ In CI, flake-shake runs tests across multiple parallel workers:
- Results are aggregated using the `flake-shake-aggregator` tool
- Reports are stored as CircleCI artifacts

### Automated Promotion (Promoter CLI)

We provide a small CLI that aggregates the last N daily summaries from CircleCI and proposes YAML edits to promote stable tests out of the `flake-shake` gate:

```bash
export CIRCLE_API_TOKEN=... # CircleCI API token (read artifacts)
go build -o ./op-acceptance-tests/flake-shake-promoter ./op-acceptance-tests/cmd/flake-shake-promoter/main.go
./op-acceptance-tests/flake-shake-promoter \
--org ethereum-optimism --repo optimism --branch develop \
--workflow scheduled-flake-shake --report-job op-acceptance-tests-flake-shake-report \
--days 3 --gate flake-shake --min-runs 300 --max-failure-rate 0.01 --min-age-days 3 \
--out ./final-promotion --dry-run
```

Outputs written to `--out`:
- `aggregate.json`: Per-test aggregated totals across days
- `promotion-ready.json`: Candidates and skip reasons
- `promotion.yaml`: Proposed edits to `op-acceptance-tests/acceptance-tests.yaml`

### Promotion Criteria

Tests should remain in flake-shake until they demonstrate consistent stability:
Expand Down
Loading