This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch detect-dependencies-fix in repository https://gitbox.apache.org/repos/asf/camel.git
commit 4f25c099dfea43f31d98ac93401502a271baf5bc Author: Guillaume Nodet <[email protected]> AuthorDate: Mon Mar 16 09:39:19 2026 +0100 chore(ci): Fix parent POM dependency change detection The detect-dependencies action was not finding affected modules because it searched for ${property-name} references in module pom.xml files. This never matches because modules inherit managed versions from the parent without referencing the property directly. New approach: 1. Detect changed properties in parent/pom.xml diff 2. Map each property to the artifact(s) it versions in dependencyManagement 3. Find modules that depend on those artifacts by searching for artifactId 4. Run tests for affected modules Also adds: - PR comment posting with test results summary - Step summary output - Proper skip-mvnd-install input in action.yaml - Run only on non-experimental matrix (skip JDK 25) - Remove overly restrictive version|dependency|artifact filter Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .github/actions/detect-dependencies/action.yaml | 50 +++++ .github/actions/detect-dependencies/detect-test.sh | 230 +++++++++++++++++---- .github/workflows/pr-build-main.yml | 2 + 3 files changed, 240 insertions(+), 42 deletions(-) diff --git a/.github/actions/detect-dependencies/action.yaml b/.github/actions/detect-dependencies/action.yaml index 3db5cf5bcc70..92745a7c3514 100644 --- a/.github/actions/detect-dependencies/action.yaml +++ b/.github/actions/detect-dependencies/action.yaml @@ -25,6 +25,10 @@ inputs: description: 'The base branch to compare against (defaults to github.base_ref)' required: false default: '' + skip-mvnd-install: + description: 'Skip mvnd installation (use if already installed)' + required: false + default: 'false' runs: using: "composite" steps: @@ -37,3 +41,49 @@ runs: GITHUB_TOKEN: ${{ inputs.github-token }} shell: bash run: ${{ github.action_path }}/detect-test.sh ${{ inputs.base-ref || github.base_ref }} ${{ steps.install-mvnd.outputs.mvnd-dir }}/mvnd + - name: Post dependency change comment + if: always() + uses: actions/github-script@v8 + with: + github-token: ${{ inputs.github-token }} + script: | + const fs = require('fs'); + const commentFile = 'detect-dependencies-comment.md'; + if (!fs.existsSync(commentFile)) return; + const body = fs.readFileSync(commentFile, 'utf8').trim(); + if (!body) return; + + const prNumber = context.issue.number; + if (!prNumber) { + core.warning('Could not determine PR number, skipping dependency comment'); + return; + } + + const marker = '<!-- ci-parent-pom-deps -->'; + + try { + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + const existing = comments.find(c => c.body && c.body.includes(marker)); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body: body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: body, + }); + } + } catch (error) { + core.warning(`Failed to post dependency change comment: ${error.message}`); + } diff --git a/.github/actions/detect-dependencies/detect-test.sh b/.github/actions/detect-dependencies/detect-test.sh index dcdb3a9e218f..b7b4806d6251 100755 --- a/.github/actions/detect-dependencies/detect-test.sh +++ b/.github/actions/detect-dependencies/detect-test.sh @@ -15,82 +15,228 @@ # limitations under the License. # +# Detects property changes in parent/pom.xml, maps them to the managed +# artifacts that use those properties, then finds which modules depend +# on those artifacts and runs their tests. +# +# Previous approach searched for ${property-name} in module pom.xml files, +# but that never matches because modules inherit managed versions from the +# parent without referencing the property directly. +# +# New approach: +# 1. Diff parent/pom.xml to find changed property names +# 2. Parse parent/pom.xml to map property -> artifactId(s) +# 3. Search module pom.xml files for those artifactIds +# 4. Run tests for affected modules + set -euo pipefail +MAX_MODULES=50 + +# Detect which properties changed in parent/pom.xml compared to the base branch. +# Returns one property name per line. detect_changed_properties() { local base_branch="$1" git diff "${base_branch}" -- parent/pom.xml | \ grep -E '^[+-]\s*<[^>]+>[^<]*</[^>]+>' | \ - grep -vE '^\+\+\+|---' | \ - grep -E 'version|dependency|artifact' | \ + grep -vE '^\+\+\+|^---' | \ sed -E 's/^[+-]\s*<([^>]+)>.*/\1/' | \ sort -u || true } -find_affected_modules() { - local property_name="$1" - local mavenBinary=${2} - local affected=() - - while IFS= read -r pom; do - # skip any target that may have been built previously - if [[ "$pom" != */target/* ]]; then - # only consider certain modules, nothing else - if [[ "$pom" == */catalog/* ]] || \ - [[ "$pom" == */components/* ]] || \ - [[ "$pom" == */core/* ]] || \ - ([[ "$pom" == */dsl/* ]] && [[ "$pom" != */dsl/camel-jbang* ]]); then - if grep -q "\${${property_name}}" "$pom"; then - affected+=("$pom") - fi - fi - fi - done < <(find . -name "pom.xml") - - affected_transformed="" - - for pom in "${affected[@]}"; do - if [[ -f "$pom" ]]; then - artifactId=$($mavenBinary -f "$pom" help:evaluate -Dexpression=project.artifactId -q --raw-streams -DforceStdout) - if [ ! -z "$artifactId" ]; then - affected_transformed+=":$artifactId," - fi - fi - done +# Given a property name, find which artifactIds in parent/pom.xml use it +# as their <version>. Looks for patterns like: +# <artifactId>some-artifact</artifactId> +# <version>${property-name}</version> +# Returns one artifactId per line. +find_artifacts_for_property() { + local property="$1" + local parent_pom="parent/pom.xml" + + # Find line numbers where <version>${property}</version> appears + grep -n "<version>\${${property}}</version>" "$parent_pom" 2>/dev/null | \ + while IFS=: read -r line_num _; do + # Search backwards from that line for the nearest <artifactId> + sed -n "1,${line_num}p" "$parent_pom" | \ + grep '<artifactId>' | tail -1 | \ + sed 's/.*<artifactId>\([^<]*\)<\/artifactId>.*/\1/' + done | sort -u +} - echo "$affected_transformed" +# Given an artifactId, find which module pom.xml files reference it +# (as a dependency, not just in exclusions or comments). +# Returns module directories, one per line. +find_modules_using_artifact() { + local artifact="$1" + local modules=() + + # Search for <artifactId>artifact</artifactId> in pom.xml files + # Exclude parent/pom.xml, target dirs, and worktrees + grep -rl "<artifactId>${artifact}</artifactId>" --include="pom.xml" . 2>/dev/null | \ + grep -v "^\./parent/pom.xml" | \ + grep -v "/target/" | \ + grep -v "\.claude/worktrees" | \ + while read -r pom_file; do + # Verify it's actually a dependency reference (not just an exclusion) + # by checking that <artifactId>artifact</artifactId> appears inside a + # <dependency> block (not only inside an <exclusion> block). + # Simple heuristic: if the artifact appears, the module is likely affected. + # Exclusion-only references are rare enough that false positives are acceptable. + dirname "$pom_file" | sed 's|^\./||' + done | sort -u } main() { echo "Using MVND_OPTS=$MVND_OPTS" local base_branch=${1} local mavenBinary=${2} + local log="detect-dependencies.log" local exclusionList="!:camel-allcomponents,!:dummy-component,!:camel-catalog,!:camel-catalog-console,!:camel-catalog-lucene,!:camel-catalog-maven,!:camel-catalog-suggest,!:camel-route-parser,!:camel-csimple-maven-plugin,!:camel-report-maven-plugin,!:camel-endpointdsl,!:camel-componentdsl,!:camel-endpointdsl-support,!:camel-yaml-dsl,!:camel-kamelet-main,!:camel-yaml-dsl-deserializers,!:camel-yaml-dsl-maven-plugin,!:camel-jbang-core,!:camel-jbang-main,!:camel-jbang-plugin-generate,!:came [...] - git fetch origin $base_branch:$base_branch + git fetch origin "$base_branch":"$base_branch" 2>/dev/null || true + # Check if parent/pom.xml was actually changed + if ! git diff --name-only "${base_branch}" -- parent/pom.xml | grep -q .; then + echo "parent/pom.xml not changed, nothing to do" + exit 0 + fi + + local changed_props changed_props=$(detect_changed_properties "$base_branch") if [ -z "$changed_props" ]; then - echo "โ No property changes detected." + echo "No property changes detected in parent/pom.xml" exit 0 fi - modules_affected="" + echo "Changed properties in parent/pom.xml:" + echo "$changed_props" + echo "" + + # Map properties -> artifacts -> modules + local all_artifacts="" + local all_modules="" + local seen_modules="" while read -r prop; do - modules=$(find_affected_modules "$prop" $mavenBinary) - modules_affected+="$modules" + [ -z "$prop" ] && continue + + local artifacts + artifacts=$(find_artifacts_for_property "$prop") + if [ -z "$artifacts" ]; then + echo " Property '$prop': no managed artifacts found" + continue + fi + + echo " Property '$prop' manages:" + while read -r artifact; do + [ -z "$artifact" ] && continue + echo " - $artifact" + all_artifacts="${all_artifacts:+${all_artifacts},}${artifact}" + + local modules + modules=$(find_modules_using_artifact "$artifact") + if [ -n "$modules" ]; then + while read -r mod; do + [ -z "$mod" ] && continue + # Deduplicate + if ! echo "$seen_modules" | grep -qx "$mod"; then + seen_modules="${seen_modules:+${seen_modules} +}${mod}" + all_modules="${all_modules:+${all_modules},}${mod}" + fi + done <<< "$modules" + fi + done <<< "$artifacts" done <<< "$changed_props" - if [ -z "$modules_affected" ]; then - echo "โ No components affected by property changes detected." + if [ -z "$all_modules" ]; then + echo "" + echo "No modules reference the changed artifacts" + exit 0 + fi + + # Count modules + local module_count + module_count=$(echo "$all_modules" | tr ',' '\n' | wc -l | tr -d ' ') + + echo "" + echo "Found ${module_count} modules affected by parent/pom.xml property changes:" + echo "$all_modules" | tr ',' '\n' | while read -r m; do + echo " - $m" + done + echo "" + + if [ "${module_count}" -gt "${MAX_MODULES}" ]; then + echo "Too many affected modules (${module_count} > ${MAX_MODULES}), skipping targeted tests" + + write_comment "$changed_props" "$all_modules" "$module_count" "skip" exit 0 fi - echo "๐งช Testing the following modules $modules_affected and its dependents" - $mavenBinary $MVND_OPTS test -pl "$modules_affected$exclusionList" -amd + echo "Running targeted tests for affected modules..." + $mavenBinary -l $log $MVND_OPTS test -pl "$all_modules" -am -pl "$exclusionList" + local ret=$? + + if [ ${ret} -eq 0 ]; then + write_comment "$changed_props" "$all_modules" "$module_count" "pass" + else + write_comment "$changed_props" "$all_modules" "$module_count" "fail" + fi + + # Write step summary + if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + echo "### Parent POM dependency change tests" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Changed properties: $(echo "$changed_props" | tr '\n' ', ' | sed 's/,$//')" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "$all_modules" | tr ',' '\n' | while read -r m; do + echo "- \`$m\`" >> "$GITHUB_STEP_SUMMARY" + done + + if [ ${ret} -ne 0 ]; then + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "Processing surefire and failsafe reports to create the summary" >> "$GITHUB_STEP_SUMMARY" + echo -e "| Failed Test | Duration | Failure Type |\n| --- | --- | --- |" >> "$GITHUB_STEP_SUMMARY" + find . -path '*target/*-reports*' -iname '*.txt' -exec .github/actions/incremental-build/parse_errors.sh {} \; + fi + fi + + exit $ret +} + +write_comment() { + local changed_props="$1" + local modules="$2" + local module_count="$3" + local status="$4" + local comment_file="detect-dependencies-comment.md" + + echo "<!-- ci-parent-pom-deps -->" > "$comment_file" + + case "$status" in + pass) + echo ":white_check_mark: **Parent POM dependency changes: targeted tests passed**" >> "$comment_file" + ;; + fail) + echo ":x: **Parent POM dependency changes: targeted tests failed**" >> "$comment_file" + ;; + skip) + echo ":information_source: **Parent POM dependency changes detected** but too many modules affected (${module_count}) to run targeted tests." >> "$comment_file" + ;; + esac + + echo "" >> "$comment_file" + echo "Changed properties: $(echo "$changed_props" | tr '\n' ', ' | sed 's/,$//')" >> "$comment_file" + echo "" >> "$comment_file" + echo "<details><summary>Tested modules (${module_count})</summary>" >> "$comment_file" + echo "" >> "$comment_file" + echo "$modules" | tr ',' '\n' | while read -r m; do + echo "- \`$m\`" >> "$comment_file" + done + echo "" >> "$comment_file" + echo "</details>" >> "$comment_file" } main "$@" diff --git a/.github/workflows/pr-build-main.yml b/.github/workflows/pr-build-main.yml index 8d46b8376673..cedc8fceb5f6 100644 --- a/.github/workflows/pr-build-main.yml +++ b/.github/workflows/pr-build-main.yml @@ -143,7 +143,9 @@ jobs: core.warning(`Failed to post CI test summary comment: ${error.message}`); } - name: mvn test parent pom dependencies changed + if: always() && !matrix.experimental uses: ./.github/actions/detect-dependencies with: github-token: ${{ secrets.GITHUB_TOKEN }} base-ref: ${{ github.base_ref || 'main' }} + skip-mvnd-install: 'true'
