diff --git a/.github/workflows/build-main.yml b/.github/workflows/build-main.yml index 4eb7061a..a20e01c0 100644 --- a/.github/workflows/build-main.yml +++ b/.github/workflows/build-main.yml @@ -1,11 +1,9 @@ -name: Maven Build & Test (main) +name: Publish snapshots from main on: push: branches: - main - schedule: - - cron: '0 0 * * *' workflow_dispatch: concurrency: @@ -13,46 +11,140 @@ concurrency: cancel-in-progress: true jobs: - build: + stage: + name: Build, test, and stage Maven artifacts + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: contents: read checks: write - timeout-minutes: 30 + timeout-minutes: 45 steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Set up JDK 25 uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'maven' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_CENTRAL_TOKEN - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - - name: Build with Maven - run: ./mvnw --batch-mode -DskipTests package - - name: Run tests - id: tests - continue-on-error: true + - name: Verify build run: ./mvnw --batch-mode verify - name: Build tests report uses: dorny/test-reporter@v2 if: always() with: name: Maven Tests - path: '**/target/surefire-reports/*.xml' + path: | + **/target/surefire-reports/*.xml + **/target/failsafe-reports/*.xml reporter: java-junit fail-on-error: true - - name: Fail if tests failed - if: steps.tests.outcome == 'failure' - run: exit 1 - - name: Publish SNAPSHOT - if: ${{ success() && github.event_name == 'push' }} - run: ./mvnw --batch-mode -DskipTests -Ppublish-sonatype deploy + - name: Stage Maven artifacts + run: ./mvnw --batch-mode -DskipTests deploy -DaltDeploymentRepository=local::file:target/staging-deploy + - name: Archive Maven staging repository + run: tar -C target -czf target/maven-staging.tar.gz staging-deploy + - name: Upload Maven staging repository + uses: actions/upload-artifact@v7.0.0 + with: + name: maven-staging + path: target/maven-staging.tar.gz + if-no-files-found: error + - name: Upload shaded CLI JAR + uses: actions/upload-artifact@v7.0.0 + with: + name: single-jar + path: cli/target/roseau-[0-9]*.jar + if-no-files-found: error + + assemble-jlink: + name: Assemble jlink ${{ matrix.platform }} + needs: stage + if: github.ref == 'refs/heads/main' + runs-on: ${{ matrix.runner }} + permissions: + contents: read + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - runner: ubuntu-latest + platform: linux-x86_64 + - runner: macos-15-intel + platform: osx-x86_64 + - runner: macos-latest + platform: osx-aarch_64 + - runner: windows-latest + platform: windows-x86_64 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Set up JDK 25 + uses: actions/setup-java@v5 + with: + java-version: '25' + distribution: 'temurin' + cache: 'maven' + - name: Build CLI artifacts + shell: bash + run: ./mvnw --batch-mode -pl cli -am -DskipTests clean package + - name: Assemble jlink archive + shell: bash + run: ./mvnw --batch-mode -N jreleaser:assemble -Djreleaser.config.file=jreleaser.yml -Djreleaser.assemble.jlink.roseau-standalone.jdk.path="$JAVA_HOME" -Djreleaser.assemble.jlink.roseau-standalone.jdk.platform="${{ matrix.platform }}" + - name: Upload jlink archive + uses: actions/upload-artifact@v7.0.0 + with: + name: jlink-${{ matrix.platform }} + path: target/jreleaser/assemble/roseau-standalone/jlink/*.zip + if-no-files-found: error + + publish: + name: Publish Maven snapshots and rolling prerelease + needs: + - stage + - assemble-jlink + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + permissions: + contents: write + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Set up JDK 25 + uses: actions/setup-java@v5 + with: + java-version: '25' + distribution: 'temurin' + cache: 'maven' + - name: Download Maven staging repository + uses: actions/download-artifact@v5 + with: + name: maven-staging + path: target + - name: Restore Maven staging repository + run: tar -C target -xzf target/maven-staging.tar.gz + - name: Download shaded CLI JAR + uses: actions/download-artifact@v5 + with: + name: single-jar + path: cli/target + - name: Download jlink archives + uses: actions/download-artifact@v5 + with: + pattern: jlink-* + merge-multiple: true + path: target/jreleaser/assemble/roseau-standalone/jlink + - name: Publish snapshots with JReleaser + run: ./mvnw --batch-mode -N jreleaser:full-release -Djreleaser.config.file=jreleaser.yml env: - MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }} - MAVEN_CENTRAL_TOKEN: ${{ secrets.NEXUS_PASSWORD }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + JRELEASER_GITHUB_TOKEN: ${{ github.token }} + JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }} + JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + JRELEASER_NEXUS2_SNAPSHOT_DEPLOY_USERNAME: ${{ secrets.NEXUS_USERNAME }} + JRELEASER_NEXUS2_SNAPSHOT_DEPLOY_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 04592ff3..8713c62c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,60 +1,135 @@ -name: Publish release to Sonatype Central +name: Publish release from tag on: - release: - types: [ published ] + push: + tags: + - 'v*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - verify: - name: Verify on ${{ matrix.os }} - runs-on: ${{ matrix.os }} + stage: + name: Build, test, and stage Maven artifacts + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Set up JDK 25 + uses: actions/setup-java@v5 + with: + java-version: '25' + distribution: 'temurin' + cache: 'maven' + - name: Verify build + run: ./mvnw --batch-mode verify + - name: Stage Maven artifacts + run: ./mvnw --batch-mode -DskipTests deploy -DaltDeploymentRepository=local::file:target/staging-deploy + - name: Archive Maven staging repository + run: tar -C target -czf target/maven-staging.tar.gz staging-deploy + - name: Upload Maven staging repository + uses: actions/upload-artifact@v7.0.0 + with: + name: maven-staging + path: target/maven-staging.tar.gz + if-no-files-found: error + - name: Upload shaded CLI JAR + uses: actions/upload-artifact@v7.0.0 + with: + name: single-jar + path: cli/target/roseau-[0-9]*.jar + if-no-files-found: error + + assemble-jlink: + name: Assemble jlink ${{ matrix.platform }} + needs: stage + runs-on: ${{ matrix.runner }} + permissions: + contents: read + timeout-minutes: 30 strategy: fail-fast: false matrix: include: - - os: ubuntu-latest - wrapper: ./mvnw - - os: windows-latest - wrapper: .\mvnw.cmd - timeout-minutes: 30 - permissions: - contents: read + - runner: ubuntu-latest + platform: linux-x86_64 + - runner: macos-15-intel + platform: osx-x86_64 + - runner: macos-latest + platform: osx-aarch_64 + - runner: windows-latest + platform: windows-x86_64 steps: - uses: actions/checkout@v6 - - name: Set up Java 25 + with: + fetch-depth: 0 + - name: Set up JDK 25 uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' cache: 'maven' - - name: Verify build - run: ${{ matrix.wrapper }} --batch-mode verify - env: - # Ensure UTF-8 (Windows might not) - MAVEN_OPTS: -Dfile.encoding=UTF-8 + - name: Build CLI artifacts + shell: bash + run: ./mvnw --batch-mode -pl cli -am -DskipTests clean package + - name: Assemble jlink archive + shell: bash + run: ./mvnw --batch-mode -N jreleaser:assemble -Djreleaser.config.file=jreleaser.yml -Djreleaser.assemble.jlink.roseau-standalone.jdk.path="$JAVA_HOME" -Djreleaser.assemble.jlink.roseau-standalone.jdk.platform="${{ matrix.platform }}" + - name: Upload jlink archive + uses: actions/upload-artifact@v7.0.0 + with: + name: jlink-${{ matrix.platform }} + path: target/jreleaser/assemble/roseau-standalone/jlink/*.zip + if-no-files-found: error publish: - name: Publish new version on Sonatype Central + name: Publish release with JReleaser + needs: + - stage + - assemble-jlink runs-on: ubuntu-latest - needs: verify - if: ${{ needs.verify.result == 'success' }} - timeout-minutes: 30 permissions: - contents: read + contents: write + timeout-minutes: 30 steps: - uses: actions/checkout@v6 - - uses: actions/setup-java@v5 + with: + fetch-depth: 0 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' - server-id: central - server-username: MAVEN_USERNAME - server-password: MAVEN_CENTRAL_TOKEN - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - - name: Publish package - run: ./mvnw --batch-mode -Ppublish-sonatype -DskipTests deploy + cache: 'maven' + - name: Download Maven staging repository + uses: actions/download-artifact@v7.0.0 + with: + name: maven-staging + path: target + - name: Restore Maven staging repository + run: tar -C target -xzf target/maven-staging.tar.gz + - name: Download shaded CLI JAR + uses: actions/download-artifact@v7.0.0 + with: + name: single-jar + path: cli/target + - name: Download jlink archives + uses: actions/download-artifact@v7.0.0 + with: + pattern: jlink-* + merge-multiple: true + path: target/jreleaser/assemble/roseau-standalone/jlink + - name: Publish release with JReleaser + run: ./mvnw --batch-mode -N jreleaser:full-release -Djreleaser.config.file=jreleaser.yml env: - MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }} - MAVEN_CENTRAL_TOKEN: ${{ secrets.NEXUS_PASSWORD }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + JRELEASER_GITHUB_TOKEN: ${{ github.token }} + JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }} + JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + JRELEASER_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + JRELEASER_MAVENCENTRAL_RELEASE_DEPLOY_USERNAME: ${{ secrets.NEXUS_USERNAME }} + JRELEASER_MAVENCENTRAL_RELEASE_DEPLOY_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} diff --git a/cli/pom.xml b/cli/pom.xml index ae984c44..3a05f8b6 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -15,6 +15,16 @@ jar + + + src/main/resources + false + + + src/main/version + true + + org.apache.maven.plugins @@ -24,6 +34,10 @@ org.apache.maven.plugins maven-javadoc-plugin + + org.apache.maven.plugins + maven-source-plugin + org.apache.maven.plugins maven-jar-plugin @@ -37,27 +51,59 @@ org.apache.maven.plugins - maven-assembly-plugin + maven-dependency-plugin + 3.8.1 + + + copy-jlink-dependencies + package + + copy-dependencies + + + runtime + ${project.build.directory}/jlink-jars + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.2 - - + false + ${project.build.directory}/roseau-${project.version}.jar + + + io.github.alien.roseau.cli.RoseauCLI - true - - - true - - - - jar-with-dependencies - + + ${project.name} + ${project.version} + true + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + - make-assembly + shade-distribution package - single + shade diff --git a/cli/src/main/java/io/github/alien/roseau/cli/RoseauCLI.java b/cli/src/main/java/io/github/alien/roseau/cli/RoseauCLI.java index 027c6f39..f367336f 100644 --- a/cli/src/main/java/io/github/alien/roseau/cli/RoseauCLI.java +++ b/cli/src/main/java/io/github/alien/roseau/cli/RoseauCLI.java @@ -18,6 +18,8 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; @@ -351,10 +353,30 @@ static void main(String[] args) { } static final class VersionProvider implements CommandLine.IVersionProvider { + private static final String VERSION_RESOURCE = "/roseau-version.txt"; + @Override public String[] getVersion() { - String impl = Optional.ofNullable(Roseau.class.getPackage().getImplementationVersion()).orElse("0.6.0-SNAPSHOT"); - return new String[]{"Roseau " + impl}; + return new String[]{"Roseau " + resolveVersion()}; + } + + static String resolveVersion() { + return Optional.ofNullable(RoseauCLI.class.getPackage().getImplementationVersion()) + .or(VersionProvider::readVersionResource) + .orElse("unknown"); + } + + private static Optional readVersionResource() { + try (InputStream in = RoseauCLI.class.getResourceAsStream(VERSION_RESOURCE)) { + if (in == null) { + return Optional.empty(); + } + + String version = new String(in.readAllBytes(), StandardCharsets.UTF_8).trim(); + return version.isEmpty() ? Optional.empty() : Optional.of(version); + } catch (IOException e) { + return Optional.empty(); + } } } } diff --git a/cli/src/main/version/roseau-version.txt b/cli/src/main/version/roseau-version.txt new file mode 100644 index 00000000..ad96e7cf --- /dev/null +++ b/cli/src/main/version/roseau-version.txt @@ -0,0 +1 @@ +${project.version} diff --git a/cli/src/test/java/io/github/alien/roseau/cli/RoseauCLITest.java b/cli/src/test/java/io/github/alien/roseau/cli/RoseauCLITest.java index b33f8589..cd0fc08b 100644 --- a/cli/src/test/java/io/github/alien/roseau/cli/RoseauCLITest.java +++ b/cli/src/test/java/io/github/alien/roseau/cli/RoseauCLITest.java @@ -36,6 +36,14 @@ void no_mode() { assertThat(exitCode).isEqualTo(ExitCode.ERROR.code()); } + @Test + void version_uses_build_version() { + var exitCode = cmd.execute("--version"); + + assertThat(out.toString()).contains("Roseau 0.6.0-SNAPSHOT"); + assertThat(exitCode).isEqualTo(ExitCode.SUCCESS.code()); + } + // --- Diffs --- // @Test void simple_source_diff() { diff --git a/combinatorial/pom.xml b/combinatorial/pom.xml index aac1085f..2d2bce17 100644 --- a/combinatorial/pom.xml +++ b/combinatorial/pom.xml @@ -13,6 +13,12 @@ roseau-combinatorial Combinatorial Benchmark + + true + true + true + + @@ -91,4 +97,4 @@ 4.7.7 - \ No newline at end of file + diff --git a/core/pom.xml b/core/pom.xml index b9059a6c..47aca55c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -31,6 +31,10 @@ org.apache.maven.plugins maven-javadoc-plugin + + org.apache.maven.plugins + maven-source-plugin + diff --git a/jreleaser.yml b/jreleaser.yml new file mode 100644 index 00000000..8b7cc654 --- /dev/null +++ b/jreleaser.yml @@ -0,0 +1,89 @@ +project: + name: roseau + description: Fast and accurate API breaking change analysis of Java libraries + longDescription: | + Roseau detects binary and source breaking changes between two versions of a + Java library. It can compare JAR files or source trees and publish reports + suitable for local use, CI, and release automation. + authors: + - Thomas Degueule + - Jean-Remy Falleri + - Corentin Latappy + license: MIT + inceptionYear: 2023 + stereotype: CLI + snapshot: + label: v{{projectVersion}} + links: + homepage: https://github.com/alien-tools/roseau + documentation: https://alien-tools.github.io/roseau/ + bugTracker: https://github.com/alien-tools/roseau/issues + languages: + java: + groupId: io.github.alien-tools + artifactId: roseau-cli + version: 25 + mainClass: io.github.alien.roseau.cli.RoseauCLI + multiProject: true + +release: + github: + owner: alien-tools + name: roseau + overwrite: true + +checksum: + algorithms: + - SHA-256 + +signing: + active: ALWAYS + pgp: + active: ALWAYS + armored: true + verify: true + +deploy: + maven: + pomchecker: + failOnWarning: false + mavenCentral: + release-deploy: + active: RELEASE + url: https://central.sonatype.com/api/v1/publisher + applyMavenCentralRules: true + stagingRepositories: + - target/staging-deploy + nexus2: + snapshot-deploy: + active: SNAPSHOT + snapshotUrl: https://central.sonatype.com/repository/maven-snapshots/ + applyMavenCentralRules: true + snapshotSupported: true + stagingRepositories: + - target/staging-deploy + +distributions: + roseau: + type: SINGLE_JAR + stereotype: CLI + artifacts: + - path: cli/target/roseau-{{projectVersion}}.jar + +assemble: + jlink: + roseau-standalone: + active: ALWAYS + exported: true + stereotype: CLI + executable: roseau + imageName: roseau-{{projectVersion}} + jdeps: + multiRelease: 25 + ignoreMissingDeps: true + targets: + - cli/target/roseau-cli-{{projectVersion}}.jar + mainJar: + path: cli/target/roseau-cli-{{projectVersion}}.jar + jars: + - pattern: cli/target/jlink-jars/*.jar diff --git a/maven-plugin/pom.xml b/maven-plugin/pom.xml index 87481b93..113329a2 100644 --- a/maven-plugin/pom.xml +++ b/maven-plugin/pom.xml @@ -23,6 +23,14 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + + + org.apache.maven.plugins + maven-source-plugin + org.apache.maven.plugins maven-plugin-plugin diff --git a/pom.xml b/pom.xml index 2afedc95..af1c882e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ 25 + 1.23.0 ${java.version} ${java.version} ${java.version} @@ -30,6 +31,12 @@ + + org.jreleaser + jreleaser-maven-plugin + ${jreleaser.version} + false + org.apache.maven.plugins maven-compiler-plugin @@ -66,6 +73,19 @@ + + org.apache.maven.plugins + maven-source-plugin + 3.4.0 + + + attach-sources + + jar-no-fork + + + + org.apache.maven.plugins maven-jar-plugin @@ -75,53 +95,6 @@ - - - publish-sonatype - - - - org.sonatype.central - central-publishing-maven-plugin - 0.10.0 - true - - central - roseau-combinatorial - - - - org.apache.maven.plugins - maven-source-plugin - 3.4.0 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 3.2.8 - - - sign-artifacts - verify - - sign - - - - - - - - - diff --git a/src/jreleaser/assemblers/roseau-standalone/jlink/LICENSE b/src/jreleaser/assemblers/roseau-standalone/jlink/LICENSE new file mode 100644 index 00000000..2f14d305 --- /dev/null +++ b/src/jreleaser/assemblers/roseau-standalone/jlink/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Roseau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/jreleaser/assemblers/roseau-standalone/jlink/README.md.tpl b/src/jreleaser/assemblers/roseau-standalone/jlink/README.md.tpl new file mode 100644 index 00000000..3f499cf9 --- /dev/null +++ b/src/jreleaser/assemblers/roseau-standalone/jlink/README.md.tpl @@ -0,0 +1,16 @@ +# Roseau {{projectVersion}} + +This archive contains the standalone Roseau CLI together with a bundled Java runtime. +No separate Java installation is required. + +## Usage + +- macOS and Linux: `bin/{{distributionExecutable}} --help` +- Windows: `bin\{{distributionExecutable}}.bat --help` + +## Examples + +- Show the CLI version: `bin/{{distributionExecutable}} --version` +- Compare two libraries: `bin/{{distributionExecutable}} --diff --v1 old.jar --v2 new.jar` + +Use the shaded JAR release instead if you need a JVM-based fallback for an unsupported platform.