This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch camel-quarkus-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus-examples.git
The following commit(s) were added to refs/heads/camel-quarkus-main by this
push:
new e10cd3a8 Add Scalpel for incremental CI builds
e10cd3a8 is described below
commit e10cd3a8974cde6a62b9e1ef810f5da350a16dde
Author: James Netherton <[email protected]>
AuthorDate: Fri Jun 19 07:22:58 2026 +0100
Add Scalpel for incremental CI builds
Registers Scalpel as a Maven core extension (disabled locally by default
via .mvn/maven.config) and wires it into the CI pipeline so that pull
requests only build and test the modules affected by their changeset.
Changes:
- .mvn/extensions.xml: register eu.maveniverse.maven.scalpel:extension:0.3.4
- .mvn/maven.config: disable Scalpel by default (-Dscalpel.enabled=false)
- .github/workflows/ci-build.yaml:
- Generate a Scalpel report during the examples build (mode=report,
reportFile written outside target/ so clean does not delete it)
- Fetch the PR base branch before the build so Scalpel can find the
merge base in the shallow CI clone
- Skip the fetch (and fall back to a full build) when the PR carries
the ci/disable-incremental label
- Replace the Groovy-based matrix with generate-test-matrix.sh
- Add 'modules' output consumed by JVM and Windows test jobs via -pl
- .github/generate-test-matrix.sh: new script replacing
generate-test-groups.groovy; reads the Scalpel JSON report, distributes
single-module projects round-robin across up to 10 native test groups,
gives multi-module projects a dedicated group, and expands multi-module
paths for the -pl modules list
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
---
.github/generate-test-groups.groovy | 53 --------------------
.github/generate-test-matrix.sh | 96 +++++++++++++++++++++++++++++++++++++
.github/workflows/ci-build.yaml | 24 ++++++----
.mvn/extensions.xml | 8 ++++
.mvn/maven.config | 1 +
5 files changed, 120 insertions(+), 62 deletions(-)
diff --git a/.github/generate-test-groups.groovy
b/.github/generate-test-groups.groovy
deleted file mode 100644
index e4a7e7ec..00000000
--- a/.github/generate-test-groups.groovy
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import groovy.json.JsonOutput;
-
-final int MAX_GROUPS = 10
-final List<Map<String, String>> GROUPS = new ArrayList<>()
-int groupId = 0
-
-// Distribute example projects across a bounded set of test groups and output
as JSON
-new File(".").eachFileRecurse { file ->
- if (file.getName() == "pom.xml" &&
file.getParentFile().getParentFile()?.getName() == ".") {
- if (file.getParentFile().getName() == "saga") {
- // saga is put into a dedicated group as it's a multi-module build
- return
- }
-
- if (GROUPS[groupId] == null) {
- GROUPS[groupId] = [:]
- GROUPS[groupId].name = "group-${String.format("%02d", groupId +
1)}"
- GROUPS[groupId].tests = ""
- }
-
- String separator = GROUPS[groupId].tests == "" ? "" : ","
-
- GROUPS[groupId].tests =
"${GROUPS[groupId].tests}${separator}${file.parentFile.name}"
-
- groupId += 1;
- if (groupId == MAX_GROUPS) {
- groupId = 0
- }
- }
-}
-
-// Add saga to a dedicated group
-GROUPS[MAX_GROUPS] = [:]
-GROUPS[MAX_GROUPS].name = "group-${String.format("%02d", MAX_GROUPS + 1)}"
-GROUPS[MAX_GROUPS].tests = "saga"
-
-print JsonOutput.toJson(["include": GROUPS])
diff --git a/.github/generate-test-matrix.sh b/.github/generate-test-matrix.sh
new file mode 100755
index 00000000..07fbe120
--- /dev/null
+++ b/.github/generate-test-matrix.sh
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Reads a Scalpel report and emits GitHub Actions matrix + modules outputs.
+# Usage: generate-test-matrix.sh <scalpel-report.json>
+# Output lines are in key=value format suitable for >> $GITHUB_OUTPUT.
+
+set -euo pipefail
+
+REPORT="${1:?Usage: $0 <scalpel-report.json>}"
+MAX_GROUPS=10
+
+# Unique top-level modules (first path component of each affected module path)
+ALL=()
+if [ -f "$REPORT" ]; then
+ while IFS= read -r line; do
+ ALL+=("$line")
+ done < <(jq -r '[.affectedModules[] | select(.path != "") | .path |
split("/")[0]] | unique[]' "$REPORT")
+fi
+
+# Fall back to all reactor modules when Scalpel found nothing or wrote no
report
+# (no base branch configured, e.g. a plain push with no PR context)
+if [ ${#ALL[@]} -eq 0 ]; then
+ while IFS= read -r line; do
+ ALL+=("$line")
+ done < <(grep '<module>' pom.xml | sed 's|.*<module>\(.*\)</module>.*|\1|'
| sort)
+fi
+
+# Separate single-module and multi-module projects.
+# Multi-module projects get a dedicated native test group (they run from their
own
+# root directory) and are expanded with sub-modules for the -pl modules list.
+SINGLE=()
+MULTI=()
+for m in "${ALL[@]}"; do
+ if grep -q '<module>' "$m/pom.xml" 2>/dev/null; then
+ MULTI+=("$m")
+ else
+ SINGLE+=("$m")
+ fi
+done
+
+# Round-robin distribution of single-module projects into at most MAX_GROUPS
groups
+GROUP_TESTS=()
+for i in "${!SINGLE[@]}"; do
+ gid=$((i % MAX_GROUPS))
+ if [[ -z "${GROUP_TESTS[$gid]+x}" ]]; then
+ GROUP_TESTS[$gid]="${SINGLE[$i]}"
+ else
+ GROUP_TESTS[$gid]="${GROUP_TESTS[$gid]},${SINGLE[$i]}"
+ fi
+done
+
+# Build matrix JSON include array
+INCLUDE="["
+SEP=""
+for gid in $(echo "${!GROUP_TESTS[@]}" | tr ' ' '\n' | sort -n); do
+ INCLUDE+="${SEP}$(printf '{"name":"group-%02d","tests":"%s"}' $((gid + 1))
"${GROUP_TESTS[$gid]}")"
+ SEP=","
+done
+# Multi-module projects each get their own dedicated group at the end
+NUM_GROUPS=${#GROUP_TESTS[@]}
+for i in "${!MULTI[@]}"; do
+ INCLUDE+="${SEP}$(printf '{"name":"group-%02d","tests":"%s"}'
$((NUM_GROUPS + i + 1)) "${MULTI[$i]}")"
+ SEP=","
+done
+INCLUDE+="]"
+
+# Build expanded module list for -pl: multi-module projects include their
sub-modules
+# so that Maven builds the full project tree rather than just the parent POM.
+EXPANDED=()
+for m in "${ALL[@]}"; do
+ EXPANDED+=("$m")
+ if grep -q '<module>' "$m/pom.xml" 2>/dev/null; then
+ while IFS= read -r submod; do
+ [ -n "$submod" ] && EXPANDED+=("$m/$submod")
+ done < <(grep '<module>' "$m/pom.xml" | sed
's|.*<module>\(.*\)</module>.*|\1|')
+ fi
+done
+
+echo "matrix={\"include\":${INCLUDE}}"
+echo "modules=$(IFS=,; echo "${EXPANDED[*]}")"
diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml
index 3f083a1a..b5ff8dea 100644
--- a/.github/workflows/ci-build.yaml
+++ b/.github/workflows/ci-build.yaml
@@ -57,6 +57,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-itest-matrix.outputs.matrix }}
+ modules: ${{ steps.set-itest-matrix.outputs.modules }}
steps:
- name: Set up JDK 17
uses: actions/setup-java@v5
@@ -103,13 +104,22 @@ jobs:
license:check \
net.revelc.code.formatter:formatter-maven-plugin:validate \
net.revelc.code:impsort-maven-plugin:check
+ - name: Fetch base branch for Scalpel
+ if: github.event_name == 'pull_request' &&
!contains(github.event.pull_request.labels.*.name, 'ci/disable-incremental')
+ run: git fetch --unshallow origin ${{ github.base_ref }}
- name: Build Camel Quarkus Examples
run: |
- ./mvnw ${MAVEN_ARGS} clean install -DskipTests -Dquarkus.build.skip
+ ./mvnw ${MAVEN_ARGS} clean install -DskipTests -Dquarkus.build.skip \
+ -Dscalpel.enabled=true \
+ -Dscalpel.mode=report \
+ -Dscalpel.reportFile=${{ runner.temp }}/scalpel-report.json
- name: Fail if there are uncommitted changes
shell: bash
run: |
[[ -z $(git status --porcelain) ]] || { echo 'There are uncommitted
changes'; git status; exit 1; }
+ - name: Setup Integration Test Matrix
+ id: set-itest-matrix
+ run: bash .github/generate-test-matrix.sh '${{ runner.temp
}}/scalpel-report.json' >> $GITHUB_OUTPUT
- name: Tar Maven Repo
shell: bash
run: |
@@ -120,12 +130,6 @@ jobs:
name: maven-repo
path: ${{ runner.temp }}/maven-repo.tar.zst
retention-days: 1
- - name: Setup Integration Test Matrix
- id: set-itest-matrix
- run: |
- sudo apt install groovy -y --no-install-recommends
- TEST_GROUPS=$(groovy .github/generate-test-groups.groovy)
- echo "matrix=${TEST_GROUPS}" >> $GITHUB_OUTPUT
integration-tests:
name: Integration Tests - ${{matrix.name}}
@@ -214,7 +218,8 @@ jobs:
- name: Integration Tests
shell: bash
run: |
- ./mvnw ${MAVEN_ARGS} clean test
+ ./mvnw ${MAVEN_ARGS} clean test \
+ -pl ${{ needs.initial-mvn-install.outputs.modules }}
- name: Fail if there are uncommitted changes
shell: bash
run: |
@@ -248,7 +253,8 @@ jobs:
- name: Integration Tests
shell: bash
run: |
- ./mvnw ${MAVEN_ARGS} -Dskip-testcontainers-tests clean test
+ ./mvnw ${MAVEN_ARGS} -Dskip-testcontainers-tests clean test \
+ -pl ${{ needs.initial-mvn-install.outputs.modules }}
- name: Fail if there are uncommitted changes
shell: bash
run: |
diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
new file mode 100644
index 00000000..fb9b1d4b
--- /dev/null
+++ b/.mvn/extensions.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extensions>
+ <extension>
+ <groupId>eu.maveniverse.maven.scalpel</groupId>
+ <artifactId>extension</artifactId>
+ <version>0.3.4</version>
+ </extension>
+</extensions>
diff --git a/.mvn/maven.config b/.mvn/maven.config
new file mode 100644
index 00000000..351e49e2
--- /dev/null
+++ b/.mvn/maven.config
@@ -0,0 +1 @@
+-Dscalpel.enabled=false