From 249a26a78d03c23e9ff8e8f335d443e3bff18b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Matuszny?= Date: Wed, 16 Jul 2025 10:22:18 +0200 Subject: [PATCH 1/4] Add workflow --- .shellspec | 2 +- build-gradle/action.yml | 140 +++++++++++++++ build-gradle/build.sh | 238 +++++++++++++++++++++++++ common/detect-repo-visibility.sh | 45 +++++ sonar-project.properties | 2 +- spec/build-gradle_spec.sh | 294 +++++++++++++++++++++++++++++++ 6 files changed, 719 insertions(+), 2 deletions(-) create mode 100644 build-gradle/action.yml create mode 100755 build-gradle/build.sh create mode 100755 common/detect-repo-visibility.sh create mode 100644 spec/build-gradle_spec.sh diff --git a/.shellspec b/.shellspec index 51c30c9e..66ac560b 100644 --- a/.shellspec +++ b/.shellspec @@ -1,5 +1,5 @@ # kcov (coverage) options ---kcov-options "--include-pattern=build-poetry,get-build-number,pr_cleanup,promote" +--kcov-options "--include-pattern=build-poetry,get-build-number,pr_cleanup,promote,build-gradle" # --kcov-options "--exclude-pattern=.github,.idea,.git" # define minimum coverage (fail otherwise) diff --git a/build-gradle/action.yml b/build-gradle/action.yml new file mode 100644 index 00000000..12d925f1 --- /dev/null +++ b/build-gradle/action.yml @@ -0,0 +1,140 @@ +--- +name: Build Gradle +description: GitHub Action to build, analyze, and deploy a Gradle project with SonarQube integration +inputs: + artifactory-deploy-repo: + description: Name of deployment repository + required: false + default: '' + artifactory-deploy-username: + description: Username to deploy to Artifactory + required: false + default: '' + artifactory-deploy-password: + description: Password to deploy to Artifactory + required: false + default: '' + gradle-args: + description: Additional arguments to pass to Gradle + required: false + default: '' + gradle-version: + description: Gradle version to use for setup-gradle action + required: false + default: '8.1' + deploy-pull-request: + description: Whether to deploy pull request artifacts + required: false + default: 'false' + skip-tests: + description: Whether to skip running tests + required: false + default: 'false' + gradle-wrapper-validation: + description: Whether to validate Gradle wrapper + required: false + default: 'true' + develocity-url: + description: URL for Develocity + required: false + default: https://develocity.sonar.build/ + artifactory-url: + description: URL to Artifactory repository + required: false + default: https://repox.jfrog.io + +outputs: + build-number: + description: The build number used for this build + value: ${{ steps.build.outputs.build-number }} + project-version: + description: The project version from gradle.properties + value: ${{ steps.build.outputs.project-version }} + +runs: + using: composite + steps: + - name: Vault + id: secrets + uses: SonarSource/vault-action-wrapper@d6d745ffdbc82b040df839b903bc33b5592cd6b0 # 3.0.2 + with: + secrets: | + development/kv/data/next url | SONAR_HOST_URL; + development/kv/data/next token | SONAR_TOKEN; + development/kv/data/sign key | SIGN_KEY; + development/kv/data/sign passphrase | PGP_PASSPHRASE; + development/kv/data/sign key_id | SIGN_KEY_ID; + development/kv/data/develocity token | DEVELOCITY_TOKEN; + + - name: Determine repository visibility + id: repo-visibility + shell: bash + env: + GITHUB_TOKEN: ${{ github.token }} + GITHUB_EVENT_REPOSITORY_VISIBILITY: ${{ github.event.repository.visibility }} + run: | + ${{ github.action_path }}/../common/detect-repo-visibility.sh + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + with: + gradle-version: ${{ inputs.gradle-version }} + develocity-access-key: >- + ${{ steps.repo-visibility.outputs.repo-visibility != 'public' && + fromJSON(steps.secrets.outputs.vault).DEVELOCITY_TOKEN || '' }} + develocity-injection-enabled: ${{ steps.repo-visibility.outputs.repo-visibility != 'public' }} + + - name: Build, analyze and deploy + id: build + shell: bash + env: + # GitHub context + PULL_REQUEST: ${{ github.event_name == 'pull_request' && github.event.number || 'false' }} + PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }} + + # Action inputs + ARTIFACTORY_URL: ${{ inputs.artifactory-url }}/artifactory + ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo }} + ARTIFACTORY_DEPLOY_USERNAME: ${{ inputs.artifactory-deploy-username }} + ARTIFACTORY_DEPLOY_PASSWORD: ${{ inputs.artifactory-deploy-password }} + DEPLOY_PULL_REQUEST: ${{ inputs.deploy-pull-request }} + SKIP_TESTS: ${{ inputs.skip-tests }} + GRADLE_ARGS: ${{ inputs.gradle-args }} + + # Vault secrets + SONAR_HOST_URL: ${{ fromJSON(steps.secrets.outputs.vault).SONAR_HOST_URL }} + SONAR_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).SONAR_TOKEN }} + ORG_GRADLE_PROJECT_signingKey: ${{ fromJSON(steps.secrets.outputs.vault).SIGN_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ fromJSON(steps.secrets.outputs.vault).PGP_PASSPHRASE }} + ORG_GRADLE_PROJECT_signingKeyId: ${{ fromJSON(steps.secrets.outputs.vault).SIGN_KEY_ID }} + run: | + ${{ github.action_path }}/build.sh + + - name: Generate workflow summary + if: always() + shell: bash + run: | + echo "## 🏗️ Gradle Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Basic build information + echo "### 📋 Build Information" >> $GITHUB_STEP_SUMMARY + echo "- **Project**: ${GITHUB_REPOSITORY#*/}" >> $GITHUB_STEP_SUMMARY + echo "- **Version**: ${{ steps.build.outputs.project-version || 'Unknown' }}" >> $GITHUB_STEP_SUMMARY + echo "- **Build Number**: ${{ steps.build.outputs.build-number }}" >> $GITHUB_STEP_SUMMARY + echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Deployment information + if [[ -n "${{ inputs.artifactory-deploy-repo }}" ]]; then + echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY + if [[ "${{ steps.build.conclusion }}" == "success" ]]; then + echo "✅ **Artifacts deployed to Artifactory**" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + ARTIFACTORY_BROWSE_URL="${{ inputs.artifactory-url }}/ui/repos/tree/General/${{ inputs.artifactory-deploy-repo }}" + echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY + else + echo "❌ **Deployment failed** (build unsuccessful)" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + fi diff --git a/build-gradle/build.sh b/build-gradle/build.sh new file mode 100755 index 00000000..fbe76aea --- /dev/null +++ b/build-gradle/build.sh @@ -0,0 +1,238 @@ +#!/bin/bash +# Build script for SonarSource Gradle projects. +# Supports building, testing, SonarQube analysis, and Artifactory deployment. +# +# Environment variables: +# - SONAR_HOST_URL: URL of SonarQube server +# - SONAR_TOKEN: access token to send analysis reports to SonarQube +# - ARTIFACTORY_URL: URL to Artifactory repository +# - ARTIFACTORY_DEPLOY_REPO: name of deployment repository +# - ARTIFACTORY_DEPLOY_USERNAME: login to deploy to Artifactory +# - ARTIFACTORY_DEPLOY_PASSWORD: password to deploy to Artifactory +# - ORG_GRADLE_PROJECT_signingKey: OpenPGP key for signing artifacts (private key content) +# - ORG_GRADLE_PROJECT_signingPassword: passphrase of the signing key +# - ORG_GRADLE_PROJECT_signingKeyId: OpenPGP subkey id +# - DEPLOY_PULL_REQUEST: whether to deploy pull request artifacts (default: false) +# - SKIP_TESTS: whether to skip running tests (default: false) +# - GRADLE_ARGS: additional arguments to pass to Gradle + +set -euo pipefail + +: "${GITHUB_REF_NAME:?Required environment variable not set}" +: "${BUILD_NUMBER:?Required environment variable not set}" +: "${GITHUB_RUN_ID:?Required environment variable not set}" +: "${GITHUB_SHA:?Required environment variable not set}" +: "${GITHUB_REPOSITORY:?Required environment variable not set}" + + +command_exists() { + if ! command -v "$1"; then + echo "$1 is not installed." >&2 + return 1 + fi + "$@" +} + +set_build_env() { + export PROJECT=${GITHUB_REPOSITORY#*/} + echo "PROJECT: $PROJECT" + + if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then + PULL_REQUEST=$(jq --raw-output .number "$GITHUB_EVENT_PATH") + PULL_REQUEST_SHA=$(jq --raw-output .pull_request.base.sha "$GITHUB_EVENT_PATH") + else + PULL_REQUEST=false + fi + echo "PULL_REQUEST: $PULL_REQUEST" + export PULL_REQUEST PULL_REQUEST_SHA + + # Set default values + : "${DEPLOY_PULL_REQUEST:=false}" + : "${SKIP_TESTS:=false}" + : "${GRADLE_ARGS:=}" + + echo "Fetching commit history for SonarQube analysis..." + git fetch --unshallow || true + + if [[ -n "${GITHUB_BASE_REF:-}" ]]; then + echo "Fetching base branch: $GITHUB_BASE_REF" + git fetch origin "${GITHUB_BASE_REF}" + fi +} + +set_project_version() { + # Get project version from gradle.properties + if [[ -f "gradle.properties" ]]; then + INITIAL_VERSION=$(grep ^version gradle.properties | awk -F= '{print $2}') + export INITIAL_VERSION + echo "Retrieved INITIAL_VERSION=$INITIAL_VERSION from gradle.properties" + + if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + echo "project-version=$INITIAL_VERSION" >> "$GITHUB_OUTPUT" + echo "build-number=${BUILD_NUMBER}" >> "$GITHUB_OUTPUT" + fi + else + echo "gradle.properties not found, version information may be unavailable" + fi +} + + +build_gradle_args() { + local args=() + + # Base arguments + args+=("--no-daemon" "--info" "--stacktrace" "--console" "plain") + + args+=("build") + + if [[ "$SKIP_TESTS" == "true" ]]; then + args+=("-x" "test") + echo "Skipping tests as requested" + fi + + # SonarQube analysis + if [[ -n "${SONAR_HOST_URL:-}" && -n "${SONAR_TOKEN:-}" ]]; then + args+=("sonar") + args+=("-Dsonar.host.url=$SONAR_HOST_URL") + args+=("-Dsonar.token=$SONAR_TOKEN") + args+=("-Dsonar.analysis.buildNumber=$BUILD_NUMBER") + args+=("-Dsonar.analysis.pipeline=$GITHUB_RUN_ID") + args+=("-Dsonar.analysis.repository=$GITHUB_REPOSITORY") + fi + + # Artifactory deployment + if should_deploy; then + args+=("artifactoryPublish") + fi + + # Build number + args+=("-DbuildNumber=$BUILD_NUMBER") + + # Additional arguments + if [[ -n "$GRADLE_ARGS" ]]; then + read -ra extra_args <<< "$GRADLE_ARGS" + args+=("${extra_args[@]}") + fi + + echo "${args[@]}" +} + +should_deploy() { + local pull_request="${PULL_REQUEST:-false}" + + if [[ "$pull_request" != "false" ]]; then + # For pull requests, deploy only if explicitly enabled + [[ "$DEPLOY_PULL_REQUEST" == "true" ]] + else + [[ "$GITHUB_REF_NAME" == "master" ]] || \ + [[ "$GITHUB_REF_NAME" == branch-* ]] || \ + [[ "$GITHUB_REF_NAME" == dogfood-on-* ]] || \ + [[ "$GITHUB_REF_NAME" == feature/long/* ]] + fi +} + +set_sonar_args() { + local -n args_ref=$1 + local pull_request="${PULL_REQUEST:-false}" + + if [[ -z "${SONAR_HOST_URL:-}" || -z "${SONAR_TOKEN:-}" ]]; then + return 0 + fi + + if [[ "$GITHUB_REF_NAME" == "master" && "$pull_request" == "false" ]]; then + # Master branch analysis + args_ref+=("-Dsonar.projectVersion=$INITIAL_VERSION") + args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") + + elif [[ "$GITHUB_REF_NAME" == branch-* && "$pull_request" == "false" ]]; then + # Maintenance branch analysis + args_ref+=("-Dsonar.branch.name=$GITHUB_REF_NAME") + args_ref+=("-Dsonar.projectVersion=$INITIAL_VERSION") + args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") + + elif [[ "$pull_request" != "false" ]]; then + # Pull request analysis + args_ref+=("-Dsonar.analysis.sha1=$PULL_REQUEST_SHA") + args_ref+=("-Dsonar.analysis.prNumber=$PULL_REQUEST") + + elif [[ "$GITHUB_REF_NAME" == feature/long/* && "$pull_request" == "false" ]]; then + # Long-lived feature branch analysis + args_ref+=("-Dsonar.branch.name=$GITHUB_REF_NAME") + args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") + fi +} + +gradle_build() { + # Setup Gradle + if command_exists gradle; then + GRADLE_CMD="gradle" + elif [[ -f "./gradlew" ]]; then + GRADLE_CMD="./gradlew" + chmod +x ./gradlew + else + echo "Neither gradle nor gradlew found" >&2 + return 1 + fi + + echo "Using Gradle command: $GRADLE_CMD" + export GRADLE_CMD + + # Conditional validation for SonarQube + if [[ -n "${SONAR_HOST_URL:-}" && -z "${SONAR_TOKEN:-}" ]]; then + echo "SONAR_TOKEN is required when SONAR_HOST_URL is set" >&2 + return 1 + fi + + # Conditional validation for Artifactory + if [[ -n "${ARTIFACTORY_DEPLOY_REPO:-}" && ( -z "${ARTIFACTORY_DEPLOY_USERNAME:-}" || -z "${ARTIFACTORY_DEPLOY_PASSWORD:-}" ) ]]; then + echo "ARTIFACTORY_DEPLOY_USERNAME and ARTIFACTORY_DEPLOY_PASSWORD are required when ARTIFACTORY_DEPLOY_REPO is set" >&2 + return 1 + fi + + local gradle_args + read -ra gradle_args <<< "$(build_gradle_args)" + + set_sonar_args gradle_args + + local build_type + local pull_request="${PULL_REQUEST:-false}" + + if [[ "$GITHUB_REF_NAME" == "master" && "$pull_request" == "false" ]]; then + build_type="master branch" + elif [[ "$GITHUB_REF_NAME" == branch-* && "$pull_request" == "false" ]]; then + build_type="maintenance branch" + elif [[ "$pull_request" != "false" ]]; then + build_type="pull request" + elif [[ "$GITHUB_REF_NAME" == dogfood-on-* && "$pull_request" == "false" ]]; then + build_type="dogfood branch" + elif [[ "$GITHUB_REF_NAME" == feature/long/* && "$pull_request" == "false" ]]; then + build_type="long-lived feature branch" + else + build_type="regular build" + fi + + echo "Starting $build_type build..." + echo "Gradle command: $GRADLE_CMD ${gradle_args[*]}" + + if "$GRADLE_CMD" "${gradle_args[@]}"; then + echo "Build completed successfully" + return 0 + else + echo "Build failed" >&2 + return 1 + fi +} + +main() { + command_exists java -version + if command_exists gradle; then + command_exists gradle --version + fi + set_build_env + set_project_version + gradle_build +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/common/detect-repo-visibility.sh b/common/detect-repo-visibility.sh new file mode 100755 index 00000000..55269cf9 --- /dev/null +++ b/common/detect-repo-visibility.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Reusable script to detect GitHub repository visibility +# Returns: public, private, or internal +# +# Usage: ./detect-repo-visibility.sh +# +# Environment variables: +# - GITHUB_TOKEN: GitHub token for API access +# - GITHUB_REPOSITORY: Repository name (e.g., owner/repo) +# - GITHUB_OUTPUT: Path to GitHub Actions output file (optional) + +set -euo pipefail + +detect_repo_visibility() { + local repo_visibility="${GITHUB_EVENT_REPOSITORY_VISIBILITY:-}" + + # Try to get visibility from GitHub event context first + if [[ -n "${repo_visibility}" && "${repo_visibility}" != "null" ]]; then + echo "Repository visibility from event: $repo_visibility" >&2 + else + # Fall back to GitHub API + echo "Fetching repository visibility from GitHub API..." >&2 + repo_visibility=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}" | \ + jq -r '.visibility // "private"') + fi + + echo "Repository visibility: $repo_visibility" >&2 + + # Set GitHub output if GITHUB_OUTPUT is available + if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + echo "repo-visibility=$repo_visibility" >> "$GITHUB_OUTPUT" + fi + + # Return the visibility + echo "$repo_visibility" +} + +# Main execution +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + : "${GITHUB_TOKEN:?Required environment variable not set}" + : "${GITHUB_REPOSITORY:?Required environment variable not set}" + + detect_repo_visibility +fi diff --git a/sonar-project.properties b/sonar-project.properties index 5b18deba..23aaa200 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,7 +4,7 @@ sonar.projectName=ci-github-actions sonar.sourceEncoding=UTF-8 -sonar.sources=build-poetry,get-build-number,pr_cleanup,promote +sonar.sources=build-poetry,get-build-number,pr_cleanup,promote,build-gradle sonar.tests=spec sonar.coverageReportPaths=coverage/coverage_data/sonar_coverage.xml diff --git a/spec/build-gradle_spec.sh b/spec/build-gradle_spec.sh new file mode 100644 index 00000000..da2dfef1 --- /dev/null +++ b/spec/build-gradle_spec.sh @@ -0,0 +1,294 @@ +#!/usr/bin/env bash +eval "$(shellspec - -c) exit 1" + +# Mock external commands +Mock java + echo "java $*" +End +Mock gradle + echo "gradle $*" +End +Mock jq + echo "jq $*" +End +Mock git + echo "git $*" +End +Mock chmod + echo "chmod $*" +End + +# Set up environment variables +export GITHUB_REPOSITORY="my-org/my-repo" +export GITHUB_REF_NAME="master" +export GITHUB_EVENT_NAME="push" +export BUILD_NUMBER="42" +export GITHUB_RUN_ID="12345" +export GITHUB_SHA="abc123" +export GITHUB_OUTPUT=/dev/null +GITHUB_EVENT_PATH=$(mktemp) +export GITHUB_EVENT_PATH +echo '{}' > "$GITHUB_EVENT_PATH" + +Describe 'build.sh' + It 'should not run the main function if the script is sourced' + When run source build-gradle/build.sh + The status should be success + The output should equal "" + End +End + +Include build-gradle/build.sh + +Describe 'command_exists' + It 'should report a tool as not installed' + When call command_exists a_tool_that_does_not_exist + The status should be failure + The error should equal "a_tool_that_does_not_exist is not installed." + End + + It 'should run a tool with arguments when it exists' + When call command_exists echo "hello world" + The status should be success + The line 2 should equal "hello world" + End +End + +Describe 'set_build_env' + It 'should set the default branch and project name' + When call set_build_env + The line 1 should equal "PROJECT: my-repo" + The line 2 should equal "PULL_REQUEST: false" + The line 3 should equal "Fetching commit history for SonarQube analysis..." + The variable PROJECT should equal "my-repo" + The variable PULL_REQUEST should equal "false" + The variable PULL_REQUEST_SHA should be undefined + The variable DEPLOY_PULL_REQUEST should equal "false" + The variable SKIP_TESTS should equal "false" + The variable GRADLE_ARGS should equal "" + End + + It 'should set PULL_REQUEST and PULL_REQUEST_SHA for pull requests' + export GITHUB_EVENT_NAME="pull_request" + echo '{"number": 123, "pull_request": {"base": {"sha": "abc123"}}}' > "$GITHUB_EVENT_PATH" + + Mock jq + if [[ "$*" == "--raw-output .number $GITHUB_EVENT_PATH" ]]; then + echo "123" + elif [[ "$*" == "--raw-output .pull_request.base.sha $GITHUB_EVENT_PATH" ]]; then + echo "abc123" + else + echo "jq $*" + fi + End + + When call set_build_env + The line 1 should equal "PROJECT: my-repo" + The line 2 should equal "PULL_REQUEST: 123" + The line 3 should equal "Fetching commit history for SonarQube analysis..." + The variable PULL_REQUEST should equal "123" + The variable PULL_REQUEST_SHA should equal "abc123" + End +End + +Describe 'set_project_version' + It 'should retrieve version from gradle.properties when it exists' + # Create a temporary gradle.properties file + echo "version=1.2.3" > gradle.properties + + When call set_project_version + The line 1 should equal "Retrieved INITIAL_VERSION=1.2.3 from gradle.properties" + The variable INITIAL_VERSION should equal "1.2.3" + + # Clean up + rm -f gradle.properties + End + + It 'should handle missing gradle.properties file' + # Ensure no gradle.properties exists + rm -f gradle.properties + + When call set_project_version + The line 1 should equal "gradle.properties not found, version information may be unavailable" + The variable INITIAL_VERSION should be undefined + End +End + +Describe 'should_deploy' + It 'should deploy for master branch' + unset PULL_REQUEST + export GITHUB_REF_NAME="master" + + When call should_deploy + The status should be success + End + + It 'should deploy for maintenance branch' + unset PULL_REQUEST + export GITHUB_REF_NAME="branch-1.2" + + When call should_deploy + The status should be success + End + + It 'should deploy for dogfood branch' + unset PULL_REQUEST + export GITHUB_REF_NAME="dogfood-on-next" + + When call should_deploy + The status should be success + End + + It 'should deploy for long-lived feature branch' + unset PULL_REQUEST + export GITHUB_REF_NAME="feature/long/my-feature" + + When call should_deploy + The status should be success + End + + It 'should not deploy for regular feature branch' + unset PULL_REQUEST + export GITHUB_REF_NAME="feature/my-feature" + + When call should_deploy + The status should be failure + End + + It 'should not deploy for pull request by default' + export PULL_REQUEST="123" + export DEPLOY_PULL_REQUEST="false" + + When call should_deploy + The status should be failure + End + + It 'should deploy for pull request when DEPLOY_PULL_REQUEST is true' + export PULL_REQUEST="123" + export DEPLOY_PULL_REQUEST="true" + + When call should_deploy + The status should be success + End +End + +Describe 'build_gradle_args' + It 'should build basic gradle arguments without deployment' + export SKIP_TESTS="false" + unset SONAR_HOST_URL + unset SONAR_TOKEN + export GRADLE_ARGS="" + export PULL_REQUEST="false" + export GITHUB_REF_NAME="feature/test" + + When call build_gradle_args + The line 1 should include "--no-daemon" + The line 1 should include "--info" + The line 1 should include "--stacktrace" + The line 1 should include "--console" + The line 1 should include "plain" + The line 1 should include "build" + The line 1 should include "-DbuildNumber=42" + The line 1 should not include "artifactoryPublish" + End + + It 'should skip tests when SKIP_TESTS is true' + export SKIP_TESTS="true" + unset SONAR_HOST_URL + unset SONAR_TOKEN + export GRADLE_ARGS="" + export PULL_REQUEST="false" + export GITHUB_REF_NAME="feature/test" + + When call build_gradle_args + The line 2 should include "-x" + The line 2 should include "test" + The line 1 should equal "Skipping tests as requested" + End + + It 'should add sonar arguments when SONAR_HOST_URL and SONAR_TOKEN are set' + export SKIP_TESTS="false" + export SONAR_HOST_URL="https://sonar.example.com" + export SONAR_TOKEN="sonar-token" + export GRADLE_ARGS="" + export PULL_REQUEST="false" + export GITHUB_REF_NAME="feature/test" + + When call build_gradle_args + The line 1 should include "sonar" + The line 1 should include "-Dsonar.host.url=https://sonar.example.com" + The line 1 should include "-Dsonar.token=sonar-token" + The line 1 should include "-Dsonar.analysis.buildNumber=42" + The line 1 should include "-Dsonar.analysis.pipeline=12345" + The line 1 should include "-Dsonar.analysis.repository=my-org/my-repo" + End + + It 'should add artifactory publish for master branch' + export SKIP_TESTS="false" + unset SONAR_HOST_URL + unset SONAR_TOKEN + export GRADLE_ARGS="" + export PULL_REQUEST="false" + export GITHUB_REF_NAME="master" + + When call build_gradle_args + The line 1 should include "artifactoryPublish" + End + + It 'should add additional gradle arguments when GRADLE_ARGS is set' + export SKIP_TESTS="false" + unset SONAR_HOST_URL + unset SONAR_TOKEN + export GRADLE_ARGS="--parallel --build-cache" + export PULL_REQUEST="false" + export GITHUB_REF_NAME="feature/test" + + When call build_gradle_args + The line 1 should include "--parallel" + The line 1 should include "--build-cache" + End +End + +Describe 'main' + It 'should call all required functions in order' + Mock command_exists + if [[ "$1" == "java" ]]; then + echo "java version \"1.8.0_281\"" + elif [[ "$1" == "gradle" ]]; then + echo "gradle" + echo "Gradle 7.4.2" + else + echo "$1 is not installed." >&2 + fi + End + + Mock set_build_env + echo "PROJECT: my-repo" + echo "PULL_REQUEST: false" + echo "Fetching commit history for SonarQube analysis..." + End + + Mock set_project_version + echo "Retrieved INITIAL_VERSION=1.0.0 from gradle.properties" + End + + Mock gradle_build + echo "Starting regular build build..." + echo "Build completed successfully" + End + + When call main + The line 1 should equal "java version \"1.8.0_281\"" + The line 2 should equal "gradle" + The line 3 should equal "Gradle 7.4.2" + The line 4 should equal "gradle" + The line 5 should equal "Gradle 7.4.2" + The line 6 should equal "PROJECT: my-repo" + The line 7 should equal "PULL_REQUEST: false" + The line 8 should equal "Fetching commit history for SonarQube analysis..." + The line 9 should equal "Retrieved INITIAL_VERSION=1.0.0 from gradle.properties" + The line 10 should equal "Starting regular build build..." + The line 11 should equal "Build completed successfully" + The status should be success + End +End From 10ce94b8939827c2a2afba8a96d684029ef785ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Matuszny?= Date: Fri, 18 Jul 2025 11:01:15 +0200 Subject: [PATCH 2/4] Improvements post review --- build-gradle/action.yml | 26 ++------ build-gradle/build.sh | 109 +++++++++++-------------------- common/detect-repo-visibility.sh | 45 ------------- 3 files changed, 45 insertions(+), 135 deletions(-) delete mode 100755 common/detect-repo-visibility.sh diff --git a/build-gradle/action.yml b/build-gradle/action.yml index 12d925f1..4571b90d 100644 --- a/build-gradle/action.yml +++ b/build-gradle/action.yml @@ -21,7 +21,7 @@ inputs: gradle-version: description: Gradle version to use for setup-gradle action required: false - default: '8.1' + default: '' deploy-pull-request: description: Whether to deploy pull request artifacts required: false @@ -38,15 +38,12 @@ inputs: description: URL for Develocity required: false default: https://develocity.sonar.build/ - artifactory-url: - description: URL to Artifactory repository + repox-url: + description: URL for Repox required: false default: https://repox.jfrog.io outputs: - build-number: - description: The build number used for this build - value: ${{ steps.build.outputs.build-number }} project-version: description: The project version from gradle.properties value: ${{ steps.build.outputs.project-version }} @@ -66,21 +63,12 @@ runs: development/kv/data/sign key_id | SIGN_KEY_ID; development/kv/data/develocity token | DEVELOCITY_TOKEN; - - name: Determine repository visibility - id: repo-visibility - shell: bash - env: - GITHUB_TOKEN: ${{ github.token }} - GITHUB_EVENT_REPOSITORY_VISIBILITY: ${{ github.event.repository.visibility }} - run: | - ${{ github.action_path }}/../common/detect-repo-visibility.sh - - name: Setup Gradle uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 with: gradle-version: ${{ inputs.gradle-version }} develocity-access-key: >- - ${{ steps.repo-visibility.outputs.repo-visibility != 'public' && + ${{ github.event.repository.visibility != 'public' && fromJSON(steps.secrets.outputs.vault).DEVELOCITY_TOKEN || '' }} develocity-injection-enabled: ${{ steps.repo-visibility.outputs.repo-visibility != 'public' }} @@ -93,7 +81,7 @@ runs: PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }} # Action inputs - ARTIFACTORY_URL: ${{ inputs.artifactory-url }}/artifactory + ARTIFACTORY_URL: ${{ inputs.repox-url }}/artifactory ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo }} ARTIFACTORY_DEPLOY_USERNAME: ${{ inputs.artifactory-deploy-username }} ARTIFACTORY_DEPLOY_PASSWORD: ${{ inputs.artifactory-deploy-password }} @@ -121,7 +109,7 @@ runs: echo "### 📋 Build Information" >> $GITHUB_STEP_SUMMARY echo "- **Project**: ${GITHUB_REPOSITORY#*/}" >> $GITHUB_STEP_SUMMARY echo "- **Version**: ${{ steps.build.outputs.project-version || 'Unknown' }}" >> $GITHUB_STEP_SUMMARY - echo "- **Build Number**: ${{ steps.build.outputs.build-number }}" >> $GITHUB_STEP_SUMMARY + echo "- **Build Number**: ${{ env.BUILD_NUMBER }}" >> $GITHUB_STEP_SUMMARY echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY @@ -131,7 +119,7 @@ runs: if [[ "${{ steps.build.conclusion }}" == "success" ]]; then echo "✅ **Artifacts deployed to Artifactory**" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - ARTIFACTORY_BROWSE_URL="${{ inputs.artifactory-url }}/ui/repos/tree/General/${{ inputs.artifactory-deploy-repo }}" + ARTIFACTORY_BROWSE_URL="${{ inputs.repox-url }}/ui/repos/tree/General/${{ inputs.artifactory-deploy-repo }}" echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY else echo "❌ **Deployment failed** (build unsuccessful)" >> $GITHUB_STEP_SUMMARY diff --git a/build-gradle/build.sh b/build-gradle/build.sh index fbe76aea..e86cf9da 100755 --- a/build-gradle/build.sh +++ b/build-gradle/build.sh @@ -18,12 +18,10 @@ set -euo pipefail -: "${GITHUB_REF_NAME:?Required environment variable not set}" -: "${BUILD_NUMBER:?Required environment variable not set}" -: "${GITHUB_RUN_ID:?Required environment variable not set}" -: "${GITHUB_SHA:?Required environment variable not set}" -: "${GITHUB_REPOSITORY:?Required environment variable not set}" - +: "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_RUN_ID:?}" "${GITHUB_SHA:?}" "${GITHUB_REPOSITORY:?}" +: "${ARTIFACTORY_DEPLOY_REPO:?}" "${ARTIFACTORY_DEPLOY_USERNAME:?}" "${ARTIFACTORY_DEPLOY_PASSWORD:?}" +: "${SONAR_HOST_URL:?}" "${SONAR_TOKEN:?}" "${ORG_GRADLE_PROJECT_signingKey:?}" "${ORG_GRADLE_PROJECT_signingPassword:?}" "${ORG_GRADLE_PROJECT_signingKeyId:?}" +: "${DEPLOY_PULL_REQUEST:?}" "${SKIP_TESTS:?}" command_exists() { if ! command -v "$1"; then @@ -34,22 +32,19 @@ command_exists() { } set_build_env() { + # Set default values + : "${DEPLOY_PULL_REQUEST:=false}" + : "${SKIP_TESTS:=false}" + : "${GRADLE_ARGS:=}" export PROJECT=${GITHUB_REPOSITORY#*/} echo "PROJECT: $PROJECT" - if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then + if is_pull_request; then PULL_REQUEST=$(jq --raw-output .number "$GITHUB_EVENT_PATH") PULL_REQUEST_SHA=$(jq --raw-output .pull_request.base.sha "$GITHUB_EVENT_PATH") else PULL_REQUEST=false fi - echo "PULL_REQUEST: $PULL_REQUEST" - export PULL_REQUEST PULL_REQUEST_SHA - - # Set default values - : "${DEPLOY_PULL_REQUEST:=false}" - : "${SKIP_TESTS:=false}" - : "${GRADLE_ARGS:=}" echo "Fetching commit history for SonarQube analysis..." git fetch --unshallow || true @@ -67,10 +62,7 @@ set_project_version() { export INITIAL_VERSION echo "Retrieved INITIAL_VERSION=$INITIAL_VERSION from gradle.properties" - if [[ -n "${GITHUB_OUTPUT:-}" ]]; then - echo "project-version=$INITIAL_VERSION" >> "$GITHUB_OUTPUT" - echo "build-number=${BUILD_NUMBER}" >> "$GITHUB_OUTPUT" - fi + echo "project-version=$INITIAL_VERSION" >> "$GITHUB_OUTPUT" else echo "gradle.properties not found, version information may be unavailable" fi @@ -118,9 +110,7 @@ build_gradle_args() { } should_deploy() { - local pull_request="${PULL_REQUEST:-false}" - - if [[ "$pull_request" != "false" ]]; then + if is_pull_request; then # For pull requests, deploy only if explicitly enabled [[ "$DEPLOY_PULL_REQUEST" == "true" ]] else @@ -131,62 +121,62 @@ should_deploy() { fi } +get_build_type() { + if [[ "$GITHUB_REF_NAME" == "master" && ! is_pull_request ]]; then + echo "master branch" + elif [[ "$GITHUB_REF_NAME" == branch-* && ! is_pull_request ]]; then + echo "maintenance branch" + elif is_pull_request; then + echo "pull request" + elif [[ "$GITHUB_REF_NAME" == dogfood-on-* && ! is_pull_request ]]; then + echo "dogfood branch" + elif [[ "$GITHUB_REF_NAME" == feature/long/* && ! is_pull_request ]]; then + echo "long-lived feature branch" + else + echo "regular build" + fi +} + set_sonar_args() { local -n args_ref=$1 - local pull_request="${PULL_REQUEST:-false}" if [[ -z "${SONAR_HOST_URL:-}" || -z "${SONAR_TOKEN:-}" ]]; then return 0 fi - if [[ "$GITHUB_REF_NAME" == "master" && "$pull_request" == "false" ]]; then + if [[ "$GITHUB_REF_NAME" == "master" && ! is_pull_request ]]; then # Master branch analysis args_ref+=("-Dsonar.projectVersion=$INITIAL_VERSION") args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") - elif [[ "$GITHUB_REF_NAME" == branch-* && "$pull_request" == "false" ]]; then + elif [[ "$GITHUB_REF_NAME" == branch-* && ! is_pull_request ]]; then # Maintenance branch analysis args_ref+=("-Dsonar.branch.name=$GITHUB_REF_NAME") args_ref+=("-Dsonar.projectVersion=$INITIAL_VERSION") args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") - elif [[ "$pull_request" != "false" ]]; then + elif is_pull_request; then # Pull request analysis args_ref+=("-Dsonar.analysis.sha1=$PULL_REQUEST_SHA") args_ref+=("-Dsonar.analysis.prNumber=$PULL_REQUEST") - elif [[ "$GITHUB_REF_NAME" == feature/long/* && "$pull_request" == "false" ]]; then + elif [[ "$GITHUB_REF_NAME" == feature/long/* && ! is_pull_request ]]; then # Long-lived feature branch analysis args_ref+=("-Dsonar.branch.name=$GITHUB_REF_NAME") args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") fi } +is_pull_request() { + [[ "$GITHUB_EVENT_NAME" == "pull_request" ]] +} + gradle_build() { # Setup Gradle if command_exists gradle; then GRADLE_CMD="gradle" elif [[ -f "./gradlew" ]]; then GRADLE_CMD="./gradlew" - chmod +x ./gradlew - else - echo "Neither gradle nor gradlew found" >&2 - return 1 - fi - - echo "Using Gradle command: $GRADLE_CMD" - export GRADLE_CMD - - # Conditional validation for SonarQube - if [[ -n "${SONAR_HOST_URL:-}" && -z "${SONAR_TOKEN:-}" ]]; then - echo "SONAR_TOKEN is required when SONAR_HOST_URL is set" >&2 - return 1 - fi - - # Conditional validation for Artifactory - if [[ -n "${ARTIFACTORY_DEPLOY_REPO:-}" && ( -z "${ARTIFACTORY_DEPLOY_USERNAME:-}" || -z "${ARTIFACTORY_DEPLOY_PASSWORD:-}" ) ]]; then - echo "ARTIFACTORY_DEPLOY_USERNAME and ARTIFACTORY_DEPLOY_PASSWORD are required when ARTIFACTORY_DEPLOY_REPO is set" >&2 - return 1 fi local gradle_args @@ -194,40 +184,17 @@ gradle_build() { set_sonar_args gradle_args - local build_type - local pull_request="${PULL_REQUEST:-false}" - - if [[ "$GITHUB_REF_NAME" == "master" && "$pull_request" == "false" ]]; then - build_type="master branch" - elif [[ "$GITHUB_REF_NAME" == branch-* && "$pull_request" == "false" ]]; then - build_type="maintenance branch" - elif [[ "$pull_request" != "false" ]]; then - build_type="pull request" - elif [[ "$GITHUB_REF_NAME" == dogfood-on-* && "$pull_request" == "false" ]]; then - build_type="dogfood branch" - elif [[ "$GITHUB_REF_NAME" == feature/long/* && "$pull_request" == "false" ]]; then - build_type="long-lived feature branch" - else - build_type="regular build" - fi + local build_type=$(get_build_type) echo "Starting $build_type build..." echo "Gradle command: $GRADLE_CMD ${gradle_args[*]}" - if "$GRADLE_CMD" "${gradle_args[@]}"; then - echo "Build completed successfully" - return 0 - else - echo "Build failed" >&2 - return 1 - fi + "$GRADLE_CMD" "${gradle_args[@]}" } main() { command_exists java -version - if command_exists gradle; then - command_exists gradle --version - fi + command_exists gradle -version set_build_env set_project_version gradle_build diff --git a/common/detect-repo-visibility.sh b/common/detect-repo-visibility.sh deleted file mode 100755 index 55269cf9..00000000 --- a/common/detect-repo-visibility.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# Reusable script to detect GitHub repository visibility -# Returns: public, private, or internal -# -# Usage: ./detect-repo-visibility.sh -# -# Environment variables: -# - GITHUB_TOKEN: GitHub token for API access -# - GITHUB_REPOSITORY: Repository name (e.g., owner/repo) -# - GITHUB_OUTPUT: Path to GitHub Actions output file (optional) - -set -euo pipefail - -detect_repo_visibility() { - local repo_visibility="${GITHUB_EVENT_REPOSITORY_VISIBILITY:-}" - - # Try to get visibility from GitHub event context first - if [[ -n "${repo_visibility}" && "${repo_visibility}" != "null" ]]; then - echo "Repository visibility from event: $repo_visibility" >&2 - else - # Fall back to GitHub API - echo "Fetching repository visibility from GitHub API..." >&2 - repo_visibility=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ - "https://api.github.com/repos/${GITHUB_REPOSITORY}" | \ - jq -r '.visibility // "private"') - fi - - echo "Repository visibility: $repo_visibility" >&2 - - # Set GitHub output if GITHUB_OUTPUT is available - if [[ -n "${GITHUB_OUTPUT:-}" ]]; then - echo "repo-visibility=$repo_visibility" >> "$GITHUB_OUTPUT" - fi - - # Return the visibility - echo "$repo_visibility" -} - -# Main execution -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - : "${GITHUB_TOKEN:?Required environment variable not set}" - : "${GITHUB_REPOSITORY:?Required environment variable not set}" - - detect_repo_visibility -fi From 96c1b4b32e1ca1656b7075cc95c333e23a56a0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Matuszny?= Date: Fri, 18 Jul 2025 11:19:59 +0200 Subject: [PATCH 3/4] use gradle properties --- build-gradle/build.sh | 41 ++++++++++---------- spec/build-gradle_spec.sh | 78 +++++++++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/build-gradle/build.sh b/build-gradle/build.sh index e86cf9da..7a2b7331 100755 --- a/build-gradle/build.sh +++ b/build-gradle/build.sh @@ -56,18 +56,18 @@ set_build_env() { } set_project_version() { - # Get project version from gradle.properties - if [[ -f "gradle.properties" ]]; then - INITIAL_VERSION=$(grep ^version gradle.properties | awk -F= '{print $2}') - export INITIAL_VERSION - echo "Retrieved INITIAL_VERSION=$INITIAL_VERSION from gradle.properties" - - echo "project-version=$INITIAL_VERSION" >> "$GITHUB_OUTPUT" - else - echo "gradle.properties not found, version information may be unavailable" + current_version=$(gradle properties --no-scan | grep 'version:' | tr -d "[:space:]" | cut -d ":" -f 2) + release_version="${current_version/-SNAPSHOT/}" + if [[ "${release_version}" =~ ^[0-9]+\.[0-9]+$ ]]; then + release_version="${release_version}.0" fi -} + release_version="${release_version}.${BUILD_NUMBER}" + echo "Replacing version $current_version with $release_version" + sed -i.bak "s/$current_version/$release_version/g" gradle.properties + export PROJECT_VERSION=$release_version + echo "project-version=$release_version" >> "$GITHUB_OUTPUT" +} build_gradle_args() { local args=() @@ -122,15 +122,15 @@ should_deploy() { } get_build_type() { - if [[ "$GITHUB_REF_NAME" == "master" && ! is_pull_request ]]; then + if [[ "$GITHUB_REF_NAME" == "master" ]] && ! is_pull_request; then echo "master branch" - elif [[ "$GITHUB_REF_NAME" == branch-* && ! is_pull_request ]]; then + elif [[ "$GITHUB_REF_NAME" == branch-* ]] && ! is_pull_request; then echo "maintenance branch" elif is_pull_request; then echo "pull request" - elif [[ "$GITHUB_REF_NAME" == dogfood-on-* && ! is_pull_request ]]; then + elif [[ "$GITHUB_REF_NAME" == dogfood-on-* ]] && ! is_pull_request; then echo "dogfood branch" - elif [[ "$GITHUB_REF_NAME" == feature/long/* && ! is_pull_request ]]; then + elif [[ "$GITHUB_REF_NAME" == feature/long/* ]] && ! is_pull_request; then echo "long-lived feature branch" else echo "regular build" @@ -144,15 +144,15 @@ set_sonar_args() { return 0 fi - if [[ "$GITHUB_REF_NAME" == "master" && ! is_pull_request ]]; then + if [[ "$GITHUB_REF_NAME" == "master" ]] && ! is_pull_request; then # Master branch analysis - args_ref+=("-Dsonar.projectVersion=$INITIAL_VERSION") + args_ref+=("-Dsonar.projectVersion=$PROJECT_VERSION") args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") - elif [[ "$GITHUB_REF_NAME" == branch-* && ! is_pull_request ]]; then + elif [[ "$GITHUB_REF_NAME" == branch-* ]] && ! is_pull_request; then # Maintenance branch analysis args_ref+=("-Dsonar.branch.name=$GITHUB_REF_NAME") - args_ref+=("-Dsonar.projectVersion=$INITIAL_VERSION") + args_ref+=("-Dsonar.projectVersion=$PROJECT_VERSION") args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") elif is_pull_request; then @@ -160,7 +160,7 @@ set_sonar_args() { args_ref+=("-Dsonar.analysis.sha1=$PULL_REQUEST_SHA") args_ref+=("-Dsonar.analysis.prNumber=$PULL_REQUEST") - elif [[ "$GITHUB_REF_NAME" == feature/long/* && ! is_pull_request ]]; then + elif [[ "$GITHUB_REF_NAME" == feature/long/* ]] && ! is_pull_request; then # Long-lived feature branch analysis args_ref+=("-Dsonar.branch.name=$GITHUB_REF_NAME") args_ref+=("-Dsonar.analysis.sha1=$GITHUB_SHA") @@ -184,7 +184,8 @@ gradle_build() { set_sonar_args gradle_args - local build_type=$(get_build_type) + local build_type + build_type=$(get_build_type) echo "Starting $build_type build..." echo "Gradle command: $GRADLE_CMD ${gradle_args[*]}" diff --git a/spec/build-gradle_spec.sh b/spec/build-gradle_spec.sh index da2dfef1..70d9edf5 100644 --- a/spec/build-gradle_spec.sh +++ b/spec/build-gradle_spec.sh @@ -6,7 +6,11 @@ Mock java echo "java $*" End Mock gradle - echo "gradle $*" + if [[ "$*" == "properties --no-scan" ]]; then + echo "version: 1.2.3-SNAPSHOT" + else + echo "gradle $*" + fi End Mock jq echo "jq $*" @@ -17,6 +21,9 @@ End Mock chmod echo "chmod $*" End +Mock sed + echo "sed $*" +End # Set up environment variables export GITHUB_REPOSITORY="my-org/my-repo" @@ -26,6 +33,16 @@ export BUILD_NUMBER="42" export GITHUB_RUN_ID="12345" export GITHUB_SHA="abc123" export GITHUB_OUTPUT=/dev/null +export ARTIFACTORY_DEPLOY_REPO="test-repo" +export ARTIFACTORY_DEPLOY_USERNAME="test-user" +export ARTIFACTORY_DEPLOY_PASSWORD="test-pass" +export SONAR_HOST_URL="https://sonar.example.com" +export SONAR_TOKEN="test-token" +export ORG_GRADLE_PROJECT_signingKey="test-key" +export ORG_GRADLE_PROJECT_signingPassword="test-pass" +export ORG_GRADLE_PROJECT_signingKeyId="test-id" +export DEPLOY_PULL_REQUEST="false" +export SKIP_TESTS="false" GITHUB_EVENT_PATH=$(mktemp) export GITHUB_EVENT_PATH echo '{}' > "$GITHUB_EVENT_PATH" @@ -58,8 +75,7 @@ Describe 'set_build_env' It 'should set the default branch and project name' When call set_build_env The line 1 should equal "PROJECT: my-repo" - The line 2 should equal "PULL_REQUEST: false" - The line 3 should equal "Fetching commit history for SonarQube analysis..." + The line 2 should equal "Fetching commit history for SonarQube analysis..." The variable PROJECT should equal "my-repo" The variable PULL_REQUEST should equal "false" The variable PULL_REQUEST_SHA should be undefined @@ -84,33 +100,43 @@ Describe 'set_build_env' When call set_build_env The line 1 should equal "PROJECT: my-repo" - The line 2 should equal "PULL_REQUEST: 123" - The line 3 should equal "Fetching commit history for SonarQube analysis..." + The line 2 should equal "Fetching commit history for SonarQube analysis..." The variable PULL_REQUEST should equal "123" The variable PULL_REQUEST_SHA should equal "abc123" End End Describe 'set_project_version' - It 'should retrieve version from gradle.properties when it exists' - # Create a temporary gradle.properties file - echo "version=1.2.3" > gradle.properties + It 'should process version and create release version' + # Create a temporary gradle.properties file for sed to work with + echo "version=1.2.3-SNAPSHOT" > gradle.properties When call set_project_version - The line 1 should equal "Retrieved INITIAL_VERSION=1.2.3 from gradle.properties" - The variable INITIAL_VERSION should equal "1.2.3" + The line 1 should equal "Replacing version 1.2.3-SNAPSHOT with 1.2.3.42" + The variable PROJECT_VERSION should equal "1.2.3.42" # Clean up - rm -f gradle.properties + rm -f gradle.properties gradle.properties.bak End - It 'should handle missing gradle.properties file' - # Ensure no gradle.properties exists - rm -f gradle.properties + It 'should handle version without patch number' + # Create a temporary gradle.properties file for sed to work with + echo "version=1.2-SNAPSHOT" > gradle.properties + + Mock gradle + if [[ "$*" == "properties --no-scan" ]]; then + echo "version: 1.2-SNAPSHOT" + else + echo "gradle $*" + fi + End When call set_project_version - The line 1 should equal "gradle.properties not found, version information may be unavailable" - The variable INITIAL_VERSION should be undefined + The line 1 should equal "Replacing version 1.2-SNAPSHOT with 1.2.0.42" + The variable PROJECT_VERSION should equal "1.2.0.42" + + # Clean up + rm -f gradle.properties gradle.properties.bak End End @@ -156,7 +182,7 @@ Describe 'should_deploy' End It 'should not deploy for pull request by default' - export PULL_REQUEST="123" + export GITHUB_EVENT_NAME="pull_request" export DEPLOY_PULL_REQUEST="false" When call should_deploy @@ -164,7 +190,7 @@ Describe 'should_deploy' End It 'should deploy for pull request when DEPLOY_PULL_REQUEST is true' - export PULL_REQUEST="123" + export GITHUB_EVENT_NAME="pull_request" export DEPLOY_PULL_REQUEST="true" When call should_deploy @@ -269,7 +295,7 @@ Describe 'main' End Mock set_project_version - echo "Retrieved INITIAL_VERSION=1.0.0 from gradle.properties" + echo "Replacing version 1.0.0-SNAPSHOT with 1.0.0.42" End Mock gradle_build @@ -281,14 +307,12 @@ Describe 'main' The line 1 should equal "java version \"1.8.0_281\"" The line 2 should equal "gradle" The line 3 should equal "Gradle 7.4.2" - The line 4 should equal "gradle" - The line 5 should equal "Gradle 7.4.2" - The line 6 should equal "PROJECT: my-repo" - The line 7 should equal "PULL_REQUEST: false" - The line 8 should equal "Fetching commit history for SonarQube analysis..." - The line 9 should equal "Retrieved INITIAL_VERSION=1.0.0 from gradle.properties" - The line 10 should equal "Starting regular build build..." - The line 11 should equal "Build completed successfully" + The line 4 should equal "PROJECT: my-repo" + The line 5 should equal "PULL_REQUEST: false" + The line 6 should equal "Fetching commit history for SonarQube analysis..." + The line 7 should equal "Replacing version 1.0.0-SNAPSHOT with 1.0.0.42" + The line 8 should equal "Starting regular build build..." + The line 9 should equal "Build completed successfully" The status should be success End End From c26f68522a0e0a3588d6a1d6bb6da5ffb0158cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Matuszny?= Date: Fri, 18 Jul 2025 11:45:43 +0200 Subject: [PATCH 4/4] readme and PR sha update --- README.md | 84 +++++++++++++++++++++++++++++++++++++++++ build-gradle/action.yml | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 97b3860f..3691454a 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,90 @@ jobs: - `public-deployer` or `qa-deployer` Artifactory roles for the deployment. - `qa-deployer` Artifactory role for the QA deploy. +## `build-gradle` + +Build and publish a Gradle project with SonarQube analysis and Artifactory deployment. + +### Usage + +_All the `with` parameters are optional and have default values which are shown below._ + +```yaml +name: Build +on: + push: + branches: + - master + - branch-* + pull_request: + merge_group: + workflow_dispatch: + +jobs: + build: + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref_name != github.event.repository.default_branch }} + runs-on: ubuntu-24.04-large + name: Build + permissions: + id-token: write + contents: write + steps: + - uses: SonarSource/ci-github-actions/get-build-number@v1 + - uses: SonarSource/ci-github-actions/build-gradle@v1 + with: + artifactory-deploy-repo: "" # Artifactory repository name + artifactory-deploy-username: "" # Artifactory username + artifactory-deploy-password: "" # Artifactory password + deploy-pull-request: false # Deploy pull request artifacts + skip-tests: false # Skip running tests + gradle-args: "" # Additional Gradle arguments + gradle-version: "" # Gradle version for setup-gradle + # if not provided Gradle Wrapper specified version will be used + gradle-wrapper-validation: true # Validate Gradle wrapper + develocity-url: https://develocity.sonar.build/ # Develocity URL + repox-url: https://repox.jfrog.io # Repox URL +``` + +⚠️ Required GitHub permissions: + +- `id-token: write` +- `contents: write` + +⚠️ Required Vault permissions: + +- `development/kv/data/next`: SonarQube credentials +- `development/kv/data/sign`: Artifact signing credentials +- `development/kv/data/develocity`: Develocity access token + +### Inputs + +- `artifactory-deploy-repo`: Name of deployment repository (optional) +- `artifactory-deploy-username`: Username to deploy to Artifactory (optional) +- `artifactory-deploy-password`: Password to deploy to Artifactory (optional) +- `deploy-pull-request`: Whether to deploy pull request artifacts (default: `false`) +- `skip-tests`: Whether to skip running tests (default: `false`) +- `gradle-args`: Additional arguments to pass to Gradle (optional) +- `gradle-version`: Gradle version to use for setup-gradle action (optional) +- `gradle-wrapper-validation`: Whether to validate Gradle wrapper (default: `true`) +- `develocity-url`: URL for Develocity (default: `https://develocity.sonar.build/`) +- `repox-url`: URL for Repox (default: `https://repox.jfrog.io`) + +### Outputs + +- `project-version`: The project version from gradle.properties + +### Features + +- Automated version management with build numbers +- SonarQube analysis for code quality (credentials from Vault) +- Conditional deployment based on branch patterns +- Automatic artifact signing (credentials from Vault) +- Pull request support with optional deployment +- Develocity integration for build optimization +- Comprehensive build logging and error handling + ## `promote` This action promotes a build in JFrog Artifactory and updates the GitHub status check accordingly. diff --git a/build-gradle/action.yml b/build-gradle/action.yml index 4571b90d..90623d7c 100644 --- a/build-gradle/action.yml +++ b/build-gradle/action.yml @@ -78,7 +78,7 @@ runs: env: # GitHub context PULL_REQUEST: ${{ github.event_name == 'pull_request' && github.event.number || 'false' }} - PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }} + PULL_REQUEST_SHA: ${{ github.event.pull_request.base.sha }} # Action inputs ARTIFACTORY_URL: ${{ inputs.repox-url }}/artifactory