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
83 changes: 75 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- main
- develop
- 2.0-dev
pull_request:
# Run CI for any incoming PR regardless of the base branch so
# feature branches targeting `develop` (e.g. v1.7 prep) also
Expand Down Expand Up @@ -41,10 +42,53 @@ jobs:
"-Dtest=EnginePdfBoundaryTest,CanonicalTemplateComposerPdfBoundaryTest,PdfRenderInterfaceGuardTest,DocumentationCoverageTest,DocumentationExamplesTest,CanonicalSurfaceGuardTest,TemplateComposeApiTest,VersionConsistencyGuardTest" \
test

changes:
# Path-based change detection for selective CI on pull requests. Emits the
# reverse-dependency flags the heavy jobs gate on: `code` (any build input),
# `core` (the root graph-compose-core module — drives japicmp), and `perf`
# (modules the smoke benchmark exercises). Pushes/dispatch bypass these gates.
name: Detect changed paths
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
core: ${{ steps.filter.outputs.core }}
perf: ${{ steps.filter.outputs.perf }}
steps:
- name: Check out repository
uses: actions/checkout@v7

- name: Detect changed module paths
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- '**/*.java'
- '**/pom.xml'
- '**/src/main/resources/**'
- '**/src/test/resources/**'
- '.mvn/**'
- 'mvnw'
- 'mvnw.cmd'
- '.github/workflows/ci.yml'
core:
- 'src/**'
- 'pom.xml'
perf:
- 'src/**'
- 'render-pdf/**'
- 'templates/**'
- 'benchmarks/**'
- 'pom.xml'

build-and-test:
name: Build and run tests (JDK ${{ matrix.java }})
if: github.event_name != 'schedule'
needs: architecture-and-documentation-guards
# Selective CI: on a pull request, skip the heavy reactor build + JDK matrix
# when only docs / non-build files changed (`code` is false). Pushes to the
# integration branches and manual dispatch always run the full gate.
if: github.event_name != 'schedule' && (github.event_name != 'pull_request' || needs.changes.outputs.code == 'true')
needs: [architecture-and-documentation-guards, changes]
runs-on: ubuntu-latest
strategy:
# Don't cancel sibling matrix jobs on the first failure — a
Expand Down Expand Up @@ -87,8 +131,9 @@ jobs:

examples-generation:
name: Examples Generation Smoke Test
if: github.event_name != 'schedule'
needs: build-and-test
# Follows build-and-test: skipped for a docs-only PR, runs otherwise.
if: github.event_name != 'schedule' && (github.event_name != 'pull_request' || needs.changes.outputs.code == 'true')
needs: [build-and-test, changes]
runs-on: ubuntu-latest
env:
JAVA_TOOL_OPTIONS: -Djava.awt.headless=true
Expand Down Expand Up @@ -174,8 +219,10 @@ jobs:

binary-compat:
name: Binary Compatibility (japicmp vs pom baseline)
if: github.event_name == 'pull_request'
needs: architecture-and-documentation-guards
# japicmp diffs the graph-compose-core public surface, so it only matters
# when the core module (root `src/**` or `pom.xml`) changed.
if: github.event_name == 'pull_request' && needs.changes.outputs.core == 'true'
needs: [architecture-and-documentation-guards, changes]
runs-on: ubuntu-latest
env:
JAVA_TOOL_OPTIONS: -Djava.awt.headless=true
Expand Down Expand Up @@ -211,8 +258,10 @@ jobs:

perf-smoke:
name: Performance Smoke Check
if: github.event_name == 'pull_request'
needs: architecture-and-documentation-guards
# The smoke benchmark only exercises core + render-pdf + templates (built via
# the benchmarks module), so skip it when none of those changed.
if: github.event_name == 'pull_request' && needs.changes.outputs.perf == 'true'
needs: [architecture-and-documentation-guards, changes]
runs-on: ubuntu-latest
env:
JAVA_TOOL_OPTIONS: -Djava.awt.headless=true
Expand Down Expand Up @@ -278,6 +327,24 @@ jobs:
path: benchmarks/target/surefire-reports/**
if-no-files-found: ignore

ci-gate:
name: CI Gate
# Single stable status check aggregating the selective jobs above. Green when
# every job that ran succeeded; a job legitimately skipped by the path filter
# counts as success. Point branch protection at "CI Gate" (plus the always-run
# "Architecture and Documentation Guards") instead of the individual, sometimes
# -skipped matrix legs so a docs-only PR is never left waiting on a check that
# never reports.
if: always() && github.event_name != 'schedule'
needs: [architecture-and-documentation-guards, build-and-test, examples-generation, binary-compat, perf-smoke]
runs-on: ubuntu-latest
steps:
- name: Fail if any required job failed
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: |
echo "A required CI job failed or was cancelled: ${{ join(needs.*.result, ', ') }}"
exit 1

benchmark-diff:
name: Weekly Benchmark Diff
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
Expand Down
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,14 @@ GraphCompose follows a fork → feature branch → pull request flow. Exte
This runs the architecture-and-documentation guards plus the full test suite. The same gate runs in CI on every PR.
5. **Push** your feature branch to your fork and open a pull request against `develop` on `DemchaAV/GraphCompose`. Reference any related issue and describe the user-visible change in the PR body.
6. **CI runs automatically.** Active jobs:
- `Architecture and Documentation Guards` — fast canonical / engine-boundary guard tests, fail-first gate
- `Architecture and Documentation Guards` — fast canonical / engine-boundary guard tests, fail-first gate (always runs)
- `Build and run tests (JDK 17)`, `(JDK 21)`, `(JDK 25)` — full `mvnw verify` in parallel matrix across the supported JVMs
- `Examples Generation Smoke Test` — regenerates all 54 runnable examples and uploads the PDFs as a CI artifact
- `Binary Compatibility` — PR-only japicmp diff of the `graph-compose-core` surface
- `Performance Smoke Check` — PR-only coarse benchmark to catch performance regressions
- `CI Gate` — single aggregate status check that is green when every job that ran passed

**Selective on pull requests:** a `dorny/paths-filter` step skips the heavy jobs when a PR touches nothing that affects the build — a **docs-only PR runs the guards only**; `Binary Compatibility` runs only when the core module changed, and the `Performance Smoke Check` only when core / render-pdf / templates changed. Pushes to `2.0-dev` / `main` (and manual dispatch) always run the full gate. Point branch protection at **`CI Gate`** + **`Architecture and Documentation Guards`** rather than the individual matrix legs, so a docs-only PR is not left waiting on a skipped check.

The PR cannot merge into a protected branch until all required checks are green.
7. **Address review comments**, then squash any fixup commits before merge. The maintainer merges through GitHub once review is complete.
Expand Down
Loading