diff --git a/.github/workflows/build-gradle-g8.yml b/.github/workflows/build-gradle-g8.yml index 75807463..eab2c04f 100644 --- a/.github/workflows/build-gradle-g8.yml +++ b/.github/workflows/build-gradle-g8.yml @@ -147,8 +147,6 @@ env: jobs: build-server: runs-on: [ appdev-selfhosted-al2023 ] - outputs: - sonar-inputs-artifact: ${{ steps.set_sonar_artifact.outputs.name }} steps: - uses: actions/checkout@v3 with: @@ -324,34 +322,24 @@ jobs: env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - - name: Generate JaCoCo reports for Sonar + # Same job/workspace as Build — reuses classes, coverage inputs, and Gradle state. + # Fully-qualified ref required: local ./ paths resolve to the caller repo, not this one. + - name: SonarCloud analysis if: inputs.sonar_enabled - uses: gradle/gradle-build-action@v2 + uses: genesislcap/appdev-workflows/sonarcloud@develop with: - arguments: jacocoTestReport ${{ env.CACHE_OPTS }} --stacktrace -Pversion=${{ env.BUILD_VERSION }} -PpushToCache=${{ env.GRADLE_GENESIS_PUSH_TO_CACHE }} -PdisableRemoteCache=${{ env.GRADLE_GENESIS_DISABLE_REMOTE_CACHE }} ${{ inputs.server-build-gradle-arguments }} - build-root-directory: "${{ inputs.working-directory }}/server" - cache-disabled: true - - - name: Upload Sonar inputs - if: inputs.sonar_enabled - uses: actions/upload-artifact@v4 - with: - name: sonar-inputs-${{ github.run_id }} - retention-days: 1 - if-no-files-found: error - path: | - ${{ inputs.working-directory }}/server/**/build/classes/** - ${{ inputs.working-directory }}/server/**/build/generated/** - ${{ inputs.working-directory }}/server/**/build/reports/** - ${{ inputs.working-directory }}/server/**/build/test-results/** - ${{ inputs.working-directory }}/server/**/build/jacoco/** - ${{ inputs.working-directory }}/server/build/**/reports/** - ${{ inputs.working-directory }}/server/build/**/jacoco/** - - - name: Record Sonar inputs artifact name - if: inputs.sonar_enabled - id: set_sonar_artifact - run: echo "name=sonar-inputs-${{ github.run_id }}" >> "$GITHUB_OUTPUT" + working-directory: ${{ inputs.working-directory }} + server-path: server + java_version: ${{ inputs.java_version }} + gradle-arguments: >- + ${{ env.CACHE_OPTS }} + --stacktrace + -Pversion=${{ env.BUILD_VERSION }} + -PpushToCache=${{ env.GRADLE_GENESIS_PUSH_TO_CACHE }} + -PdisableRemoteCache=${{ env.GRADLE_GENESIS_DISABLE_REMOTE_CACHE }} + ${{ inputs.server-build-gradle-arguments }} + sonar-token: ${{ secrets.JENKINSGENESIS_SONAR }} + github-token: ${{ github.token }} - name: Check Auth Permissions task id: auth_permissions_task @@ -511,28 +499,6 @@ jobs: SLACK_MESSAGE: The server build for ${{ github.workflow }} passed https://github.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/actions/runs/${{ github.run_id }} SLACK_CHANNEL: ${{ env.REPO_NAME }}-build-notifications - sonar: - name: SonarCloud Analysis - needs: build-server - if: ${{ inputs.sonar_enabled }} - uses: ./.github/workflows/sonarcloud.yml - with: - branch: ${{ inputs.branch }} - version: ${{ inputs.version }} - working-directory: ${{ inputs.working-directory }} - server-path: server - node_version: ${{ inputs.node_version }} - REGISTRY_URL: ${{ inputs.REGISTRY_URL }} - SCOPE: ${{ inputs.SCOPE }} - sonar-inputs-artifact: ${{ needs.build-server.outputs.sonar-inputs-artifact }} - secrets: - GPR_READ_TOKEN: ${{ secrets.GPR_READ_TOKEN }} - GRADLE_PROPERTIES: ${{ secrets.GRADLE_PROPERTIES }} - JFROG_USERNAME: ${{ secrets.JFROG_USERNAME }} - JFROG_EMAIL: ${{ secrets.JFROG_EMAIL }} - JFROG_PASSWORD: ${{ secrets.JFROG_PASSWORD }} - JENKINSGENESIS_SONAR: ${{ secrets.JENKINSGENESIS_SONAR }} - tag-jiras: needs: build-server if: inputs.update-jira diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml deleted file mode 100644 index ae7e4b48..00000000 --- a/.github/workflows/sonarcloud.yml +++ /dev/null @@ -1,249 +0,0 @@ -name: SonarCloud - -on: - workflow_call: - inputs: - branch: - description: Branch or ref to analyse - required: false - type: string - version: - description: Application version - required: false - type: string - working-directory: - description: Project working directory - required: false - type: string - default: '.' - server-path: - description: Path containing the server Gradle wrapper (relative to working-directory) - required: false - type: string - default: 'server' - project_java_version: - description: Java version used to compile and test the application - required: false - type: string - default: '17' - node_version: - description: Node.js version required by the project - required: false - type: string - default: '20.x' - REGISTRY_URL: - description: Only used by older versions of Genesis Framework - required: false - type: string - SCOPE: - description: NPM scope used with REGISTRY_URL - required: false - type: string - sonar-inputs-artifact: - description: >- - Optional artifact name containing classes/coverage/test results from a prior build. - When set, prepare-analysis skips re-running tests and reuses this artifact. - required: false - type: string - default: '' - secrets: - GPR_READ_TOKEN: - required: true - GRADLE_PROPERTIES: - required: true - JFROG_USERNAME: - required: true - JFROG_EMAIL: - required: true - JFROG_PASSWORD: - required: true - JENKINSGENESIS_SONAR: - required: true - -env: - NODE_AUTH_TOKEN: ${{ secrets.GPR_READ_TOKEN }} - SONAR_ARTIFACT_NAME: ${{ inputs.sonar-inputs-artifact != '' && inputs.sonar-inputs-artifact || format('sonar-inputs-{0}', github.run_id) }} - SERVER_DIR: ${{ inputs.working-directory == '.' && inputs.server-path || format('{0}/{1}', inputs.working-directory, inputs.server-path) }} - -jobs: - prepare-analysis: - name: Prepare Sonar inputs - if: ${{ inputs.sonar-inputs-artifact == '' }} - runs-on: [appdev-selfhosted-al2023] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ inputs.branch }} - - name: Set up project JDK - uses: actions/setup-java@v4 - with: - java-version: ${{ inputs.project_java_version }} - distribution: temurin - - name: Configure Node - if: ${{ !inputs.REGISTRY_URL }} - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node_version }} - - name: Configure Node if using JFrog npm packages - if: ${{ inputs.REGISTRY_URL }} - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node_version }} - registry-url: ${{ inputs.REGISTRY_URL }} - scope: ${{ inputs.SCOPE }} - - name: Restore gradle.properties and setup - working-directory: ${{ inputs.working-directory }} - shell: bash - env: - GRADLE_PROPERTIES: ${{ secrets.GRADLE_PROPERTIES }} - run: | - set -euo pipefail - mkdir -p "${HOME}/.gradle" - echo "GRADLE_USER_HOME=${HOME}/.gradle" >> "${GITHUB_ENV}" - { - echo "genesisArtifactoryUser=${{ secrets.JFROG_USERNAME }}" - echo "genesisArtifactoryPassword=${{ secrets.JFROG_PASSWORD }}" - echo "systemProp.org.gradle.internal.http.connectionTimeout=180000" - echo "systemProp.org.gradle.internal.http.socketTimeout=180000" - echo "dockerUrl=genesisglobal-docker-internal.jfrog.io" - echo "dockerUsername=${{ secrets.JFROG_USERNAME }}" - echo "dockerPassword=${{ secrets.JFROG_PASSWORD }}" - echo "dockerEmail=${{ secrets.JFROG_EMAIL }}" - echo "genesis-home=../.genesis-home" - echo "deploy-plugin-mode=local" - } > "${HOME}/.gradle/gradle.properties" - if [ -n "${GRADLE_PROPERTIES:-}" ]; then - printf '%s\n' "${GRADLE_PROPERTIES}" >> "${HOME}/.gradle/gradle.properties" - fi - chmod +x ./gradlew - chmod +x "./${{ inputs.server-path }}/gradlew" - chmod -R +rx "./${{ inputs.server-path }}" - cat "${HOME}/.gradle/gradle.properties" >> ./gradle.properties - RELEASE_VERSION="$(echo '${{ inputs.version }}' | sed 's/\//-/g')" - echo "RELEASE_VERSION=${RELEASE_VERSION}" >> "${GITHUB_ENV}" - BUILD_FILE="${{ inputs.server-path }}/build.gradle.kts" - if [ -n "${RELEASE_VERSION}" ] && [ -f "${BUILD_FILE}" ]; then - sed -E -i "s/^[[:space:]]{4}version = \".+\"/ version = \"${RELEASE_VERSION}\"/g" "${BUILD_FILE}" - fi - - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 - with: - cache-disabled: true - - name: Run tests and generate coverage - working-directory: ${{ env.SERVER_DIR }} - shell: bash - run: | - set -euo pipefail - ./gradlew test jacocoTestReport --no-configuration-cache --stacktrace - - name: Upload Sonar inputs - uses: actions/upload-artifact@v4 - with: - name: ${{ env.SONAR_ARTIFACT_NAME }} - retention-days: 1 - if-no-files-found: error - path: | - ${{ env.SERVER_DIR }}/**/build/classes/** - ${{ env.SERVER_DIR }}/**/build/generated/** - ${{ env.SERVER_DIR }}/**/build/reports/** - ${{ env.SERVER_DIR }}/**/build/test-results/** - ${{ env.SERVER_DIR }}/**/build/jacoco/** - ${{ env.SERVER_DIR }}/build/**/reports/** - ${{ env.SERVER_DIR }}/build/**/jacoco/** - - sonar-analysis: - name: SonarCloud analysis - needs: prepare-analysis - # Prepare is skipped when the caller already uploaded Sonar inputs; still run analysis. - if: ${{ !cancelled() && (needs.prepare-analysis.result == 'success' || (needs.prepare-analysis.result == 'skipped' && inputs.sonar-inputs-artifact != '')) }} - runs-on: [appdev-selfhosted-al2023] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ inputs.branch }} - # Project toolchain JDK must be present even with skipCompile — Gradle still - # configures compileJava and resolves dependencies against languageVersion. - - name: Set up project JDK - uses: actions/setup-java@v4 - with: - java-version: ${{ inputs.project_java_version }} - distribution: temurin - - name: Set up JDK 21 for Sonar - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: temurin - - name: Configure Node - if: ${{ !inputs.REGISTRY_URL }} - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node_version }} - - name: Configure Node if using JFrog npm packages - if: ${{ inputs.REGISTRY_URL }} - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node_version }} - registry-url: ${{ inputs.REGISTRY_URL }} - scope: ${{ inputs.SCOPE }} - - name: Restore gradle.properties and setup - working-directory: ${{ inputs.working-directory }} - shell: bash - env: - GRADLE_PROPERTIES: ${{ secrets.GRADLE_PROPERTIES }} - run: | - set -euo pipefail - mkdir -p "${HOME}/.gradle" - echo "GRADLE_USER_HOME=${HOME}/.gradle" >> "${GITHUB_ENV}" - { - echo "genesisArtifactoryUser=${{ secrets.JFROG_USERNAME }}" - echo "genesisArtifactoryPassword=${{ secrets.JFROG_PASSWORD }}" - echo "systemProp.org.gradle.internal.http.connectionTimeout=180000" - echo "systemProp.org.gradle.internal.http.socketTimeout=180000" - echo "dockerUrl=genesisglobal-docker-internal.jfrog.io" - echo "dockerUsername=${{ secrets.JFROG_USERNAME }}" - echo "dockerPassword=${{ secrets.JFROG_PASSWORD }}" - echo "dockerEmail=${{ secrets.JFROG_EMAIL }}" - echo "genesis-home=../.genesis-home" - echo "deploy-plugin-mode=local" - } > "${HOME}/.gradle/gradle.properties" - if [ -n "${GRADLE_PROPERTIES:-}" ]; then - printf '%s\n' "${GRADLE_PROPERTIES}" >> "${HOME}/.gradle/gradle.properties" - fi - if [ -f ./gradlew ]; then - chmod +x ./gradlew - fi - if [ -f "./${{ inputs.server-path }}/gradlew" ]; then - chmod +x "./${{ inputs.server-path }}/gradlew" - fi - if [ -d "./${{ inputs.server-path }}" ]; then - chmod -R +rx "./${{ inputs.server-path }}" - fi - cat "${HOME}/.gradle/gradle.properties" >> ./gradle.properties - RELEASE_VERSION="$(echo '${{ inputs.version }}' | sed 's/\//-/g')" - BUILD_FILE="${{ inputs.server-path }}/build.gradle.kts" - if [ -n "${RELEASE_VERSION}" ] && [ -f "${BUILD_FILE}" ]; then - sed -E -i "s/^[[:space:]]{4}version = \".+\"/ version = \"${RELEASE_VERSION}\"/g" "${BUILD_FILE}" - fi - - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 - with: - cache-disabled: true - - name: Download Sonar inputs - uses: actions/download-artifact@v4 - with: - name: ${{ env.SONAR_ARTIFACT_NAME }} - path: ${{ github.workspace }} - - name: Run SonarCloud analysis - working-directory: ${{ env.SERVER_DIR }} - shell: bash - env: - SONAR_TOKEN: ${{ secrets.JENKINSGENESIS_SONAR }} - GITHUB_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - ./gradlew sonar --no-configuration-cache --stacktrace \ - -Dsonar.gradle.skipCompile=true \ - -Dsonar.token="${SONAR_TOKEN}" diff --git a/sonarcloud/action.yaml b/sonarcloud/action.yaml new file mode 100644 index 00000000..e690ac6e --- /dev/null +++ b/sonarcloud/action.yaml @@ -0,0 +1,67 @@ +name: SonarCloud analysis +description: > + Run JaCoCo coverage and SonarCloud analysis in the current job workspace. + Intended to run after a Gradle build so classes/test results are already present + (no artifact upload/download). + +inputs: + working-directory: + description: Project working directory + required: false + default: '.' + server-path: + description: Path containing the server Gradle project (relative to working-directory) + required: false + default: 'server' + java_version: + description: Project JDK to restore after Sonar (Sonar itself runs on JDK 21) + required: false + default: '17' + gradle-arguments: + description: Extra Gradle flags/properties (cache opts, -Pversion, etc.) + required: false + default: '' + sonar-token: + description: SonarCloud token + required: true + github-token: + description: GitHub token for PR decoration (optional) + required: false + default: '' + +runs: + using: composite + steps: + - name: Generate JaCoCo reports + uses: gradle/gradle-build-action@v2 + with: + arguments: jacocoTestReport --no-configuration-cache ${{ inputs.gradle-arguments }} + build-root-directory: ${{ inputs.working-directory }}/${{ inputs.server-path }} + cache-disabled: true + + # Set to 21 temporarily as Sonar stopped support Java 17 + - name: Set up Java 21 for Sonar + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: temurin + + - name: Run SonarCloud analysis + uses: gradle/gradle-build-action@v2 + env: + SONAR_TOKEN: ${{ inputs.sonar-token }} + GITHUB_TOKEN: ${{ inputs.github-token }} + with: + arguments: >- + sonar --no-configuration-cache + ${{ inputs.gradle-arguments }} + -Dsonar.gradle.skipCompile=true + -Dsonar.token=${{ inputs.sonar-token }} + build-root-directory: ${{ inputs.working-directory }}/${{ inputs.server-path }} + cache-disabled: true + + - name: Restore project JDK + uses: actions/setup-java@v4 + with: + java-version: ${{ inputs.java_version }} + distribution: temurin