name: Build and Release

on:
  push:
    branches:
      - main
      - develop
    tags:
      - 'release@*'
  pull_request:
    branches:
      - main
      - develop

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  quality-gates:
    name: Quality gates
    runs-on: ubuntu-latest

    steps:
      - name: Check out repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Validate Gradle wrapper
        uses: gradle/actions/wrapper-validation@v4

      - name: Set up Temurin JDK 21
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'

      - name: Set up Gradle caching and instrumentation
        uses: gradle/actions/setup-gradle@v4

      - name: Verify reproducibility inputs
        shell: bash
        run: |
          set -euo pipefail
          test -f gradle.lockfile
          test -f gradle.properties
          test -f gradle/verification-metadata.xml

      - name: Execute build, tests, PMD, coverage, Javadoc, distribution packaging, and SBOM generation
        run: ./gradlew --no-daemon clean ciRelease distZip pmdMain javadoc jacocoCiReleaseReport :cyclonedxDirectBom

      - name: Upload SBOM
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: |
            build/reports/sbom/radixor-sbom.json
            build/reports/sbom/radixor-sbom.xml
          if-no-files-found: error
          retention-days: 14

      - name: Upload test reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-reports
          path: |
            build/reports/tests
            build/test-results
          if-no-files-found: warn
          retention-days: 14

      - name: Upload PMD reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: pmd-reports
          path: build/reports/pmd
          if-no-files-found: warn
          retention-days: 14

      - name: Upload coverage reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: coverage-reports
          path: |
            build/reports/jacoco/jacocoCiReleaseReport/html
            build/reports/jacoco/jacocoCiReleaseReport/jacocoCiReleaseReport.xml
          if-no-files-found: warn
          retention-days: 14

      - name: Upload Javadoc
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: javadoc
          path: build/docs/javadoc
          if-no-files-found: warn
          retention-days: 14

      - name: Upload benchmark reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: benchmark-reports
          path: build/reports/jmh
          if-no-files-found: ignore
          retention-days: 14

      - name: Upload distribution archives
        if: success()
        uses: actions/upload-artifact@v4
        with:
          name: distributions
          path: build/distributions/*.zip
          if-no-files-found: error
          retention-days: 14

  release:
    name: Publish tagged distribution
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/release@')
    runs-on: ubuntu-latest
    needs: quality-gates
    permissions:
      contents: write

    steps:
      - name: Check out repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Validate Gradle wrapper
        uses: gradle/actions/wrapper-validation@v4

      - name: Set up Temurin JDK 21
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'

      - name: Set up Gradle caching and instrumentation
        uses: gradle/actions/setup-gradle@v4

      - name: Verify reproducibility inputs
        shell: bash
        run: |
          set -euo pipefail
          test -f gradle.lockfile
          test -f gradle.properties
          test -f gradle/verification-metadata.xml

      - name: Validate exact core release tag
        run: ./tools/parse-model-release-tag.sh "${GITHUB_REF_NAME}" .

      - name: Build release inputs, signed Maven bundle, and SBOM
        env:
          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
          SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
        run: ./gradlew --no-daemon clean ciRelease distZip pmdMain javadoc jacocoCiReleaseReport :cyclonedxDirectBom centralBundle

      - name: Generate release changelog
        shell: bash
        run: |
          set -euo pipefail
          chmod +x ./tools/generate-release-notes.sh
          mkdir -p build/generated/release-notes
          ./tools/generate-release-notes.sh "${GITHUB_REF_NAME}" > build/generated/release-notes/CHANGELOG.md

      - name: Package release distribution
        run: ./gradlew --no-daemon distZip

      - name: Publish bundle to Maven Central
        shell: bash
        env:
          CENTRAL_BEARER_TOKEN: ${{ secrets.CENTRAL_BEARER_TOKEN }}
        run: ./tools/publish-central-bundle.sh "$(ls build/central-bundle/*.zip)" "org.egothor:radixor:${GITHUB_REF_NAME#release@}"

      - name: Publish GitHub release assets
        uses: softprops/action-gh-release@v2
        with:
          body_path: build/generated/release-notes/CHANGELOG.md
          files: |
            build/distributions/*.zip
            build/reports/sbom/radixor-sbom.json
            build/reports/sbom/radixor-sbom.xml
            build/central-bundle/*.zip
