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
155 changes: 155 additions & 0 deletions .github/workflows/javac-matcher-build-tools.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
name: javac problem matcher with Maven & Gradle

# The javac problem matcher registered by setup-java (##[add-matcher] java.json)
# only understands javac's *native* diagnostic format:
#
# File.java:12: warning|error: message
#
# (matcher regex, owner=javac: ^([^:]+):(\d+): (warning|error): (.+?)$)
#
# This workflow demonstrates how the two major build tools interact with it:
#
# * Gradle passes javac diagnostics through unchanged, so they DO match the
# matcher and show up as GitHub annotations.
# * The Maven compiler plugin reformats diagnostics to
# [WARNING] /path/File.java:[line,col] message
# which does NOT match the matcher, so Maven builds are NOT annotated even
# though the compiler reports the same warnings/errors.
#
# Each job captures the build log and asserts the number of matcher-format lines,
# so the workflow is self-verifying (not just visual). Open a run and compare the
# Gradle job's Annotations panel (populated) with the Maven job's (empty).

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read

env:
# Exact javac matcher regex from actions/setup-java .github/java.json, as a
# POSIX ERE for grep. [^:]+ = file (no colon), then :line:, then severity.
MATCHER_RE: '^[^:]+:[0-9]+: (warning|error): .+$'

jobs:
gradle-is-annotated:
name: 'Gradle build IS annotated - ${{ matrix.os }}'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- name: Set up Java (registers the javac problem matcher)
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
with:
distribution: temurin
java-version: '21'

- name: Gradle compile with warnings (matcher should annotate them)
working-directory: javac-matcher-gradle
shell: bash
run: |
set -euo pipefail
# compileJava emits warnings but succeeds; tee so the matcher sees the log too.
./gradlew --no-daemon --console=plain clean compileJava 2>&1 | tee warn.log
hits=$(grep -Ec "$MATCHER_RE" warn.log || true)
echo "matcher-format lines: $hits"
if [ "$hits" -lt 1 ]; then
echo "::error::expected Gradle warnings in native javac format (matcher would annotate)"
exit 1
fi
echo "OK: $hits Gradle warning line(s) match the javac matcher -> annotated"

- name: Gradle compile with errors (matcher should annotate them)
id: compile
continue-on-error: true
working-directory: javac-matcher-gradle
shell: bash
run: ./gradlew --no-daemon --console=plain compileErrorsJava 2>&1 | tee err.log

- name: Confirm Gradle errors failed the build and match the matcher
working-directory: javac-matcher-gradle
shell: bash
run: |
set -euo pipefail
echo "compile outcome: ${{ steps.compile.outcome }}"
if [ "${{ steps.compile.outcome }}" != "failure" ]; then
echo "::error::expected Gradle compileErrorsJava to fail"
exit 1
fi
hits=$(grep -Ec "$MATCHER_RE" err.log || true)
echo "matcher-format lines: $hits"
if [ "$hits" -lt 1 ]; then
echo "::error::expected Gradle errors in native javac format (matcher would annotate)"
exit 1
fi
echo "OK: $hits Gradle error line(s) match the javac matcher -> annotated"

maven-is-not-annotated:
name: 'Maven build is NOT annotated - ${{ matrix.os }}'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- name: Set up Java (registers the javac problem matcher)
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
with:
distribution: temurin
java-version: '21'

- name: Maven compile with warnings (matcher must NOT annotate them)
working-directory: javac-matcher-maven
shell: bash
run: |
set -euo pipefail
mvn -B clean compile 2>&1 | tee warn.log
matcher=$(grep -Ec "$MATCHER_RE" warn.log || true)
diags=$(grep -Ec '\.java:\[[0-9]+,[0-9]+\]' warn.log || true)
echo "matcher-format lines: $matcher (expect 0), maven [line,col] diagnostics: $diags (expect >0)"
if [ "$diags" -lt 1 ]; then
echo "::error::expected the Maven compiler to report warnings ([WARNING] File.java:[l,c] ...)"
exit 1
fi
if [ "$matcher" -ne 0 ]; then
echo "::error::Maven output unexpectedly matched the javac matcher"
exit 1
fi
echo "OK: Maven reported $diags warning(s), but 0 lines match the matcher -> not annotated"

- name: Maven compile with errors (fails; matcher must NOT annotate them)
id: compile
continue-on-error: true
working-directory: javac-matcher-maven
shell: bash
run: mvn -B -Perrors clean compile 2>&1 | tee err.log

- name: Confirm Maven errors failed the build but were not matcher-annotated
working-directory: javac-matcher-maven
shell: bash
run: |
set -euo pipefail
echo "compile outcome: ${{ steps.compile.outcome }}"
if [ "${{ steps.compile.outcome }}" != "failure" ]; then
echo "::error::expected Maven -Perrors compile to fail"
exit 1
fi
matcher=$(grep -Ec "$MATCHER_RE" err.log || true)
diags=$(grep -Ec '\.java:\[[0-9]+,[0-9]+\]' err.log || true)
echo "matcher-format lines: $matcher (expect 0), maven [line,col] diagnostics: $diags (expect >0)"
if [ "$diags" -lt 1 ]; then
echo "::error::expected the Maven compiler to report errors ([ERROR] File.java:[l,c] ...)"
exit 1
fi
if [ "$matcher" -ne 0 ]; then
echo "::error::Maven error output unexpectedly matched the javac matcher"
exit 1
fi
echo "OK: Maven reported $diags error(s) in the log, but 0 lines match the matcher -> not annotated"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
target/
*.class
.gradle/
build/
*.log
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,28 @@ Both are expected to pass: together they document exactly what changed.
- `.github/workflows/` — one workflow per feature, each running on Ubuntu, Windows and macOS.
- `maven-sample-project/` — a tiny Maven project with one external dependency, used by
`maven-args.yml` to prove that transfer-progress logs are suppressed by default.
- `javac-matcher/` — standalone `.java` sources (warnings + errors) compiled directly with
`javac` by `javac-problem-matcher.yml`.
- `javac-matcher-maven/` / `javac-matcher-gradle/` — the same warning/error sources built
through Maven and Gradle, used by `javac-matcher-build-tools.yml` (below).

## javac problem matcher vs build tools

The `javac` problem matcher registered by setup-java only understands javac's **native**
diagnostic format (`File.java:12: warning|error: message`). Whether your build gets
annotated therefore depends on the build tool:

| Build tool | Compiler output | Matched by `javac` matcher? |
|------------|-----------------|-----------------------------|
| Direct `javac` | `File.java:12: warning: …` | ✅ annotated |
| **Gradle** | `File.java:12: warning: …` (passed through) | ✅ annotated |
| **Maven** (compiler plugin) | `[WARNING] /path/File.java:[12,5] …` | ❌ not annotated |

[`javac-matcher-build-tools.yml`](.github/workflows/javac-matcher-build-tools.yml) proves
this by capturing each build log and asserting the number of matcher-format lines (0 for
Maven, >0 for Gradle) — so it fails loudly if the behavior ever changes.

## Running


Push to `main`, open a PR, or trigger any workflow manually via **workflow_dispatch**.
33 changes: 33 additions & 0 deletions javac-matcher-gradle/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
plugins {
id 'java'
}

// Exercises the javac problem matcher registered by setup-java when the build is
// driven by Gradle. Gradle passes javac diagnostics through in their native form
// "/path/File.java:line: warning|error: message", which the matcher regex
// ^([^:]+):(\d+): (warning|error): (.+?)$ DOES match, so Gradle builds ARE
// annotated. See .github/workflows/javac-matcher-build-tools.yml.
//
// ./gradlew compileJava -> compiles the warning sources (succeeds, warns)
// ./gradlew compileErrorsJava -> compiles the failing sources (fails)

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

sourceSets {
// Failing sources live in their own source set so they can be compiled in a
// dedicated step without breaking the (successful) warning compilation.
errors {
java {
srcDir 'src/errors/java'
}
}
}

tasks.withType(JavaCompile).configureEach {
options.compilerArgs += ['-Xlint:all']
options.deprecation = true
}
Binary file not shown.
9 changes: 9 additions & 0 deletions javac-matcher-gradle/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading