Skip to content

feat(ci): run integration suites under an ES→OS migration phase (#36320) - #36500

Merged
fabrizzio-dotCMS merged 13 commits into
mainfrom
issue-36320-phased-integration-suite
Jul 28, 2026
Merged

feat(ci): run integration suites under an ES→OS migration phase (#36320)#36500
fabrizzio-dotCMS merged 13 commits into
mainfrom
issue-36320-phased-integration-suite

Conversation

@fabrizzio-dotCMS

@fabrizzio-dotCMS fabrizzio-dotCMS commented Jul 9, 2026

Copy link
Copy Markdown
Member

Proposed Changes

Makes it possible to run the full integration battery under a chosen ES→OS migration phase — on a single phase or swept across all three — locally, per-PR, on-demand, and automatically on a schedule. Contributes to #36320 ("Make it possible to run MainSuite Tests in all 3 phases").

The opensearch-phase-suite Maven profile already existed (two clusters ES @9207 + OS 3.x @9201, sets DOT_FEATURE_FLAG_OPEN_SEARCH_PHASE, inherits the base suite includes). This PR wires that capability into every layer of the tooling. It does not change any product code, and default (phase 0) behavior is untouched everywhere.

Four ways to run a phased battery

Path Trigger Scope
Local just test-integration-phase <N> / test-integration-phase-per-suite <N> single phase
Per-PR (opt-in) PR label OpenSearch:Phase-<N> single phase
On-demand Nightly workflow_dispatchopensearch_phase dropdown (none/1/2/3/1,2/1,3/2,3/all) single phase, subset, or sweep
Automatic New weekly scheduled workflow (Sun 06:00 UTC) sweep (all 3)

Local (justfile)

  • test-integration-phase <N> [TEST] — full battery in a single JVM (one docker bring-up), or a narrowed run with a test arg.
  • test-integration-phase-per-suite <N> — iterates the MainSuite/Junit5 suites one at a time (forkCount=1) under phase <N>, giving attributable per-suite pass/fail plus a summary (non-zero exit if any suite fails). This is the local triage tool for de-ES-ifying the ITs. (renamed from test-integration-phase-all — the sweep is per-suite, not per-phase.)

CI — shared engine (cicd_comp_test-phase.yml)

  • New opensearch_phase input now accepts a single phase (2), a comma-list subset (1,2, 1,3, 2,3), the full list (1,2,3), or the alias all (= 1,2,3). The parser expands all, splits on commas, keeps values matching ^[1-3]$, dedupes and sorts.
  • The matrix generator fans each integration MainSuite/Junit5 entry out once per requested phase, appending -Dopensearch.phase=<N> and suffixing name / stage_name per phase so job labels and the resulting build-reports-<stage_name> artifacts stay unique. The OpenSearch Upgrade Suite is never phased (it already drives OS via -Dopensearch.upgrade.test; combining the two profiles would collide their endpoint config).
  • fail-fast is conditional — derived from "phase off" ('' / none / 0), not an exact-match list — so ANY active run (single phase, a subset like 1,2, or all) disables fast-fail and every suite/phase runs to completion with per-phase attribution. (Fixes a latent mismatch where a comma-list subset would otherwise have left fast-fail on.)
  • No-op when off: empty / none / 0 yields an empty phase list → the matrix is byte-for-byte identical to today. Verified against the other callers that don't opt in (cicd_2-merge-queue, cicd_3-trunk, cicd_5-lts).

CI — per-PR (cicd_1-pr.yml)

  • A PR carrying an OpenSearch:Phase-<N> label runs the integration battery under that phase (mirrors the existing PR: docker image label pattern). No label → phase 0 (current behavior). (The label family was aligned with the repo's OpenSearch area label — see Repo labels below.)

CI — on-demand (cicd_4-nightly.yml)

  • workflow_dispatch opensearch_phase dropdown: default none (clearer than 0), options none/1/2/3/1,2/1,3/2,3/all.
  • Any active value (single phase, subset, or all) skips the deployment job — a build exercised under a non-default migration phase is never promoted. The skip guard is derived from "phase off" so subsets are covered. The scheduled nightly (03:18) is unaffected: it runs with none → phase 0 + deploy as today.

CI — automatic (cicd_scheduled_opensearch-phase-sweep.yml, new)

  • Weekly (Sun 06:00 UTC, off-peak and clear of the daily nightly): sweeps the integration battery across all 3 phases automatically, so migration-flow regressions are caught without any developer opting a PR in.
  • Test-only: initialize → build → test → finalize → report. No deploy, no CLI build. Only the integration test type is enabled (other suites don't vary by phase). workflow_dispatch also allows picking a single phase or a subset (1,2/1,3/2,3).
  • Serialized via a concurrency group (cancel-in-progress: false): only one sweep runs at a time — a manual dispatch fired while the weekly run is going is queued rather than run in parallel (a sweep is expensive and its result matters).
  • Scheduled triggers only fire from the default branch, so it stays dormant until merged to main.

Repo labels (created out-of-band)

  • Renamed the area label OpenSearch-MigrationOpenSearch (assignments preserved; nothing references it in code).
  • Created the CI-trigger family OpenSearch:Phase-1 / -2 / -3 used by the per-PR trigger.

Checklist

  • YAML validated; matrix-generation logic simulated against the real test-matrix.yml: none/''/0 → 7 entries / 0 phased (unchanged); 2 → 6 phased + upgrade untouched; 1,2 → 12 phased; all → 18 phased + upgrade, all 19 stage_names unique (no artifact collision). fail-fast and deploy-skip guards verified across all values.
  • Shared-engine change confirmed no-op for callers that don't pass opensearch_phase (merge-queue, trunk, lts).
  • Smoke-verified locally: just test-integration-phase 1 ContentletIndexAPIImplTest brings up both clusters, bootstraps OS under PHASE_1_DUAL_WRITE_ES_READS, and runs the suite.
  • No product code changed (CI/tooling only).

Notes for reviewers

  • The OpenSearch:Phase-<N> labels already exist in the repo (created alongside this PR) so the per-PR trigger is selectable.
  • Impact of the new scheduled workflow on other jobs is minimal: it's independent and test-only (no shared state, no deploy, per-run artifacts); the only shared surface is cicd_comp_test-phase.yml, whose change is a verified no-op when the phase is off. The material cost is ~19 long integration jobs once a week, off-peak Sunday (no cron collision with the pentest/rolling-tags/nightly schedules).

Related: #36320, PR #36268 / #36266 (added the opensearch-phase-suite profile).

This PR fixes: #36320

Enable running the full integration battery under a chosen ES→OS migration
phase, both locally and in CI. The opensearch-phase-suite Maven profile already
exists (two clusters + DOT_FEATURE_FLAG_OPEN_SEARCH_PHASE); this wires it into
the day-to-day tooling.

- justfile: new `test-integration-phase-all <N>` iterates the MainSuite/Junit5
  suites one at a time (forkCount=1) under a phase, yielding attributable
  per-suite pass/fail for triage; document that `test-integration-phase <N>`
  (no test) already runs the full battery in a single JVM.
- cicd_comp_test-phase.yml: new `opensearch_phase` input; setup-matrix appends
  `-Dopensearch.phase=<N>` to integration MainSuite/Junit5 entries only (never
  the OpenSearch Upgrade Suite, which already drives OS). Passed via env to the
  github-script to avoid injection. Empty/'0' = off; only 1/2/3 activate.
- cicd_1-pr.yml: derive the phase from a `PR: opensearch phase <N>` label so a
  PR can run the whole suite under a phase on demand.
- cicd_4-nightly.yml: workflow_dispatch `opensearch_phase` choice input; phase
  1/2/3 skips deployment (test-only run).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @fabrizzio-dotCMS's task in 6m 19s —— View job


Code Review — phased integration suite (CI/tooling only)

  • Read the full diff against origin/main
  • Cross-checked the notify-slack action contract, test-matrix.yml, and the other callers of cicd_comp_test-phase.yml
  • Reviewed matrix fan-out, fail-fast/deploy-skip guards, and the new sweep workflow

New Issues

  • 🟡 Medium: .github/workflows/cicd_scheduled_opensearch-phase-sweep.yml:128-130 — The notify-scout payload is wrapped in literal double quotes. The notify-slack action (with the default json: 'false') renders the payload as "text": ${{ toJSON(inputs.payload) }} — it re-encodes the string to JSON itself. Every other caller in the repo (cicd_6-release.yml:431, cicd_comp_deployment-phase.yml:341, etc.) passes raw markdown with no surrounding quotes. Here the leading " and trailing " are part of the payload text, so toJSON escapes them and the Slack message renders with stray " characters at the start and end (":x: *OpenSearch Phase Sweep failed*run_id>"). Drop the two " so it matches the convention:

    payload: |
      :x: *OpenSearch Phase Sweep failed* — phase(s) `${{ inputs.opensearch_phase || 'all' }}`
      *Run:* <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.run_id }}>

    Fix this →

Everything else checks out. Specifically verified:

  • No-op when off: rawPhase empty/none/0phaseList empty → matrix identical to today; the else branch pushes the unmodified testEntry. Callers that never pass opensearch_phase (merge-queue, trunk, lts) get the '' default → unchanged.
  • Upgrade suite exclusion is correct: phaseable is gated on test_type === 'integration' and !maven_args.includes('opensearch.upgrade.test'); the upgrade suite's base_maven_args carries -Dopensearch.upgrade.test=true (test-matrix.yml:93), so it's never phased.
  • fail-fast guard (cicd_comp_test-phase.yml:235) and deploy-skip guard (cicd_4-nightly.yml:191) are both derived from "phase off" ('' | none | 0), so comma-list subsets like 1,2 correctly disable fast-fail and skip deploy. The == '' branch also covers the scheduled-cron case where inputs is empty (defaults aren't applied on schedule), so the nightly still deploys.
  • Script-injection safe: opensearch_phase reaches the github-script step via the OPENSEARCH_PHASE env var, not string interpolation.
  • notify-scout firing: if: failure() with needs: [initialize, build, test] — a skipped build (artifacts reused) is not a failure, and a failing matrix job propagates through the reusable test job, so it triggers as intended.

The \ No newline at end of file on the new workflow is cosmetic — not worth blocking.
· issue-36320-phased-integration-suite

…tion-phase-per-suite

The recipe sweeps every integration suite one at a time under a single phase;
"-all" wrongly implied it ran all phases. "-per-suite" names what it does: the
per-suite split is the axis, not the phase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align the integration-battery phase trigger with the repo's OpenSearch label
family (the area label was renamed OpenSearch-Migration -> OpenSearch). The
labels OpenSearch:Phase-1/2/3 now exist in the repo; the workflow reads them
instead of the old "PR: opensearch phase <N>" strings. No behavior change:
no label -> phase 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the phased-run capability from a single phase to a multi-phase sweep,
driven from the nightly workflow_dispatch dropdown.

- test-phase matrix generator: opensearch_phase now accepts a single phase
  ('2'), a comma list ('1,2,3') or the alias 'all'. Each phaseable integration
  entry (MainSuite/Junit5, never the OpenSearch Upgrade Suite) is fanned out
  once per phase, with name/stage_name suffixed so job labels and the resulting
  build-reports-<stage_name> artifacts stay unique. Empty/'none'/'0' -> no
  fan-out (phase-0 behavior byte-for-byte unchanged).
- test-phase fail-fast is now conditional: kept true for normal runs, false for
  a phased sweep (1/2/3/all) so every suite/phase runs to completion and
  failures are attributable per phase.
- nightly: opensearch_phase dropdown default is now 'none' (clearer than '0'),
  with an 'all' option to sweep 1,2,3 on demand. Deploy is skipped for any
  active phase value (1/2/3/all) — test-only runs never deploy.

Simulated against the real test-matrix.yml: none/''/0 -> 7 entries/0 phased;
'2' -> 6 phased + upgrade untouched; all -> 18 phased + upgrade, all 19
stage_names unique (no artifact collision).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Weekly workflow (Sun 06:00 UTC) that runs the integration battery under every
ES→OS migration phase automatically — the automated counterpart to the opt-in
"OpenSearch:Phase-<N>" PR label and the manual nightly dropdown.

- Reuses cicd_comp_test-phase.yml with opensearch_phase=all -> 6 suites × 3
  phases = 18 phased jobs (fail-fast off, per-phase attribution), Upgrade Suite
  untouched. Only the integration test type is enabled (others don't vary by
  phase). workflow_dispatch lets you pick a single phase or 'all'.
- Deliberately NO deploy / NO CLI build: a build exercised under a non-default
  migration phase must never be promoted. Cadence is off-peak and clear of the
  03:18 daily nightly.
- Scheduled triggers only fire from the default branch, so this stays dormant
  until merged to main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prevent two phase sweeps (the weekly schedule + a manual dispatch) from running
in parallel and doubling runner load. cancel-in-progress: false lets the running
sweep finish and queues the new one, since each sweep is expensive and its result
matters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread .github/workflows/cicd_comp_test-phase.yml
…hase-off

Addresses review feedback (run only a subset of phases, e.g. 1 and 2).

- test-phase fail-fast: derive from "phase off" (''/none/0) instead of an
  exact-match ["1","2","3","all"] list, so a comma-list subset like '1,2'
  (which the matrix generator already fans out) also disables fast-fail and
  keeps per-phase attribution. Fixes the latent mismatch flagged in review.
- nightly: add subset options 1,2 / 1,3 / 2,3 to the opensearch_phase dropdown,
  and switch the deploy-skip guard to the same phase-off logic so a subset run
  is correctly treated as test-only (never deployed).
- scheduled sweep: add the same subset options to its manual dispatch dropdown.

Simulated: ''/none/0 -> 0 phased, fail-fast on, deploy proceeds; '1,2' -> 12
phased jobs, fail-fast off, deploy skipped; 'all' -> 18 phased, deploy skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread .github/workflows/cicd_scheduled_opensearch-phase-sweep.yml Outdated
Add a failure-only notify-scout job to the scheduled sweep that posts to
#team-scout (CQNF9PCFQ) via the notify-slack action, in addition to the
existing #log-core-cicd report. Payload names the failing phase(s) and links
the run. The Slack bot must be a member of #team-scout or the step errors with
not_in_channel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mergify

mergify Bot commented Jul 28, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Merged via the queue into main with commit b05eb43 Jul 28, 2026
70 checks passed
@fabrizzio-dotCMS
fabrizzio-dotCMS deleted the issue-36320-phased-integration-suite branch July 28, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : CI/CD PR changes GitHub Actions/workflows OpenSearch

Projects

Status: No status

3 participants