diff --git a/.github/actions/jdk-setup/action.yml b/.github/actions/jdk-setup/action.yml index 1201744..e81775f 100644 --- a/.github/actions/jdk-setup/action.yml +++ b/.github/actions/jdk-setup/action.yml @@ -1,10 +1,46 @@ name: "JDK Setup" +description: "Set up Temurin JDK 21 with Maven dependency caching" +inputs: + server-id: + description: "Maven settings.xml server id for Maven Central authentication." + required: false + default: '' + server-username: + description: "Environment variable name for the Maven Central username." + required: false + default: '' + server-password: + description: "Environment variable name for the Maven Central password." + required: false + default: '' + gpg-private-key: + description: "GPG private key to import for artifact signing." + required: false + default: '' + gpg-passphrase: + description: "Environment variable name for the GPG passphrase." + required: false + default: '' runs: using: "composite" steps: - - name: Set up JDK 8 - uses: actions/setup-java@v4 + - name: Set up JDK 21 + if: ${{ inputs.server-id == '' }} + uses: actions/setup-java@v5 with: java-version: '21' distribution: 'temurin' cache: maven + + - name: Set up JDK 21 with Maven Central credentials + if: ${{ inputs.server-id != '' }} + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + server-id: ${{ inputs.server-id }} + server-username: ${{ inputs.server-username }} + server-password: ${{ inputs.server-password }} + gpg-private-key: ${{ inputs.gpg-private-key }} + gpg-passphrase: ${{ inputs.gpg-passphrase }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7a45c23 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,83 @@ +name: Release to Maven Central + +on: + push: + tags: ['plugin-*'] # release tags are prefixed with "plugin-" + +permissions: + contents: read + +concurrency: + group: release-deploy + cancel-in-progress: false + +env: + MAVEN_COMMAND: ./mvnw + MAVEN_CLI_COMMON: "-e -B" + +jobs: + release: + runs-on: ubuntu-latest + timeout-minutes: 120 + environment: release + outputs: + version: ${{ steps.resolve.outputs.version }} + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - uses: ./.github/actions/jdk-setup + with: + server-id: central-publish + server-username: CENTRAL_USERNAME + server-password: CENTRAL_TOKEN + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + + # Guard against a mistyped tag releasing the wrong version: the POM is the + # source of truth for what gets deployed, so the tag must encode exactly that + # version. The resolved version also titles the GitHub Release below. + - name: Verify tag matches project version + id: resolve + env: + TAG: ${{ github.ref_name }} + run: | + version="$(${{ env.MAVEN_COMMAND }} help:evaluate -Dexpression=project.version -q -DforceStdout)" + expected="plugin-${version}" + if [ "$TAG" != "$expected" ]; then + echo "::error::Tag '$TAG' does not match project version (expected '$expected'). Refusing to release." + exit 1 + fi + echo "version=${version}" >> "$GITHUB_OUTPUT" + + # Tests already ran during release:prepare. + - name: Deploy release to Maven Central + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: ${{ env.MAVEN_COMMAND }} ${{ env.MAVEN_CLI_COMMON }} deploy -Prelease -DskipTests + + # Publish a GitHub Release for the tag once the Central deploy succeeds. Notes are + # auto-generated by the GitHub Release Notes API from merged PRs/commits since the + # previous tag. Isolated from the deploy job so contents:write is not granted while + # GPG keys and Central credentials are in scope. + github-release: + needs: release + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: write # required to create the GitHub Release + steps: + - name: Create GitHub Release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} # via env to avoid script injection + VERSION: ${{ needs.release.outputs.version }} + run: | + gh release create "$TAG" \ + --repo "${{ github.repository }}" \ + --title "$VERSION" \ + --generate-notes \ + --verify-tag