From 79a8c88456df13e53063ac5f8e93533b333a3c06 Mon Sep 17 00:00:00 2001 From: Julien Carsique Date: Thu, 12 Mar 2026 14:04:23 +0100 Subject: [PATCH] BUILD-10586 Fix inconsistencies between actions inputs, outputs and behaviors - Add `deploy` input to build-npm, build-yarn, build-poetry (consistent with build-maven/build-gradle) - Enable deployment on long-lived feature branches (feature/long/*) for npm/yarn/poetry - Add `disable-caching` input to build-npm, build-yarn, config-npm; deprecate `cache-npm`/`cache-yarn` - Add `should_scan()` to build-gradle to filter SonarQube analysis by branch type - Add CONFIG_NPM_COMPLETED idempotency guard to config-npm (consistent with config-gradle/config-maven) - Condition Artifactory deploy token vault secret on deploy being enabled - Align shadow scan warning to GitHub Actions ::warning stderr format across all actions - Align run-shadow-scans description and sh header documentation across all build actions - Fix artifactory-deploy-repo description in build-npm (private-qa was incorrectly named public-qa) - Update README: deployment strategy table, input tables, remove resolved known bugs and TODOs - Code style: consolidate parameter validation, fix readonly declarations, align sh header labels Co-Authored-By: Claude Sonnet 4.6 --- README.md | 26 ++++---- build-gradle/action.yml | 4 +- build-gradle/build.sh | 38 ++++++------ build-maven/build.sh | 19 ++---- build-npm/action.yml | 19 ++++-- build-npm/build.sh | 32 +++++----- build-poetry/action.yml | 8 ++- build-poetry/build.sh | 35 +++++++---- build-yarn/action.yml | 19 ++++-- build-yarn/build.sh | 32 +++++----- config-gradle/set_gradle_project_version.sh | 4 +- config-maven/set_maven_project_version.sh | 4 +- config-npm/action.yml | 29 +++++++-- config-npm/npm_set_project_version.sh | 3 +- pr_cleanup/cleanup.sh | 7 +-- promote/promote.sh | 15 ++--- spec/build-gradle_spec.sh | 68 +++++++++++++++++++++ spec/build-npm_spec.sh | 20 +++++- spec/build-poetry_spec.sh | 15 ++++- spec/build-yarn_spec.sh | 18 +++++- 20 files changed, 282 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index f5964a8..e5fd6fc 100644 --- a/README.md +++ b/README.md @@ -439,7 +439,8 @@ jobs: | `artifactory-reader-role` | Suffix for the Artifactory reader role in Vault | `private-reader` for private repos, `public-reader` for public repos | | `artifactory-deployer-role` | Suffix for the Artifactory deployer role in Vault | `qa-deployer` for private repos, `public-deployer` for public repos | | `artifactory-deploy-repo` | Deployment repository | `sonarsource-pypi-private-qa` for private repositories, `sonarsource-pypi-public-qa` for public repos | -| `deploy-pull-request` | Whether to deploy pull request artifacts | `false` | +| `deploy` | Whether to deploy on master, maintenance, dogfood and long-lived branches | `true` | +| `deploy-pull-request` | Whether to also deploy pull request artifacts. If `deploy` is `false`, this has no effect | `false` | | `poetry-virtualenvs-path` | Path to the Poetry virtual environments, relative to GitHub workspace | `.cache/pypoetry/virtualenvs` | | `poetry-cache-dir` | Path to the Poetry cache directory, relative to GitHub workspace | `.cache/pypoetry` | | `repox-url` | URL for Repox | `https://repox.jfrog.io` | @@ -867,7 +868,8 @@ See also [`get-build-number`](#get-build-number) input environment variables. |---------------------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------| | `working-directory` | Relative path under github.workspace to execute the build in | `.` | | `artifactory-reader-role` | Suffix for the Artifactory reader role in Vault | `private-reader` for private repos, `public-reader` for public repos | -| `cache-npm` | Whether to cache NPM dependencies | `true` | +| `disable-caching` | Whether to disable NPM caching entirely | `false` | +| `cache-npm` | Deprecated. Use `disable-caching: 'true'` instead | `true` | | `repox-url` | URL for Repox | `https://repox.jfrog.io` | | `repox-artifactory-url` | URL for Repox Artifactory API (overrides repox-url/artifactory if provided) | (optional) | @@ -962,9 +964,11 @@ See also [`config-npm`](#config-npm) input environment variables. | `artifactory-reader-role` | Suffix for the Artifactory reader role in Vault | `private-reader` for private repos, `public-reader` for public repos | | `artifactory-deployer-role` | Suffix for the Artifactory deployer role in Vault | `qa-deployer` for private repos, `public-deployer` for public repos | | `artifactory-deploy-repo` | Deployment repository | `sonarsource-npm-private-qa` for private repos, `sonarsource-npm-public-qa` for public repos | -| `deploy-pull-request` | Whether to deploy pull request artifacts | `false` | +| `deploy` | Whether to deploy on master, maintenance, dogfood and long-lived branches | `true` | +| `deploy-pull-request` | Whether to also deploy pull request artifacts. If `deploy` is `false`, this has no effect | `false` | | `skip-tests` | Whether to skip running tests | `false` | -| `cache-npm` | Whether to cache NPM dependencies | `true` | +| `disable-caching` | Whether to disable NPM caching entirely | `false` | +| `cache-npm` | Deprecated. Use `disable-caching: 'true'` instead | `true` | | `repox-url` | URL for Repox | `https://repox.jfrog.io` | | `repox-artifactory-url` | URL for Repox Artifactory API (overrides repox-url/artifactory if provided) | (optional) | | `sonar-platform` | SonarQube primary platform - 'next', 'sqc-eu', or 'sqc-us' | `next` | @@ -1062,9 +1066,11 @@ jobs: | `artifactory-reader-role` | Suffix for the Artifactory reader role in Vault | `private-reader` for private repos, `public-reader` for public repos | | `artifactory-deployer-role` | Suffix for the Artifactory deployer role in Vault | `qa-deployer` for private repos, `public-deployer` for public repos | | `artifactory-deploy-repo` | Deployment repository | `sonarsource-private-qa` for private repositories, `sonarsource-public-qa` for public repos | -| `deploy-pull-request` | Whether to deploy pull request artifacts | `false` | +| `deploy` | Whether to deploy on master, maintenance, dogfood and long-lived branches | `true` | +| `deploy-pull-request` | Whether to also deploy pull request artifacts. If `deploy` is `false`, this has no effect | `false` | | `skip-tests` | Whether to skip running tests | `false` | -| `cache-yarn` | Whether to cache Yarn dependencies | `true` | +| `disable-caching` | Whether to disable Yarn caching entirely | `false` | +| `cache-yarn` | Deprecated. Use `disable-caching: 'true'` instead | `true` | | `repox-url` | URL for Repox | `https://repox.jfrog.io` | | `repox-artifactory-url` | URL for Repox Artifactory API (overrides repox-url/artifactory if provided) | (optional) | | `sonar-platform` | SonarQube primary platform - 'next', 'sqc-eu', 'sqc-us', or 'none'. Use 'none' to skip sonar scans | `next` | @@ -1372,16 +1378,12 @@ concrete deploy and scan behavior is implemented in each build script: | Maintenance (`branch-*`) | yes | yes | | Pull request | optional | yes | | Dogfood (`dogfood-on-*`) | yes | no | -| Long-lived feature (`feature/long/*`) | yes ¹ | yes | +| Long-lived feature (`feature/long/*`) | yes | yes | | Other branches | no | no | - Pull request deployment requires `deploy-pull-request: 'true'`. - SonarQube analysis also requires `sonar-platform` to be set (not `none`). -- ¹ `build-maven` and `build-gradle` only; `build-npm`, `build-yarn`, and `build-poetry` do not deploy on long-lived feature branches. -- `build-maven` and `build-gradle` support a `deploy: 'false'` input to override deployment regardless of branch. `build-npm`, - `build-yarn`, and `build-poetry` do not have this input (TODO: add for consistency). -- **`build-gradle` known bug**: SonarQube analysis is not filtered by branch type. When `sonar-platform ≠ none`, analysis runs on all - branches, including dogfood and other branches (unlike all other build actions). +- All build actions support a `deploy: 'false'` input to override deployment regardless of branch. --- diff --git a/build-gradle/action.yml b/build-gradle/action.yml index 1f29e63..8334af7 100644 --- a/build-gradle/action.yml +++ b/build-gradle/action.yml @@ -25,8 +25,8 @@ inputs: description: SonarQube primary platform (next, sqc-eu, sqc-us, or none). Use 'none' to skip sonar scans. default: next run-shadow-scans: - description: If true, run SonarQube analysis on all three platforms (next, sqc-eu, sqc-us). - If false, run analysis on the platform specified with sonar-platform. + description: If true, run sonar scanner on all 3 platforms using the provided URL and token. + If false, run on the platform provided by sonar-platform. When enabled, the sonar-platform setting is ignored. default: 'false' provenance: description: Whether to generate provenance attestation for built artifacts diff --git a/build-gradle/build.sh b/build-gradle/build.sh index 7a4e17f..5499a69 100755 --- a/build-gradle/build.sh +++ b/build-gradle/build.sh @@ -12,6 +12,7 @@ # - SQC_EU_URL: URL of SonarQube server for sqc-eu platform # - SQC_EU_TOKEN: Access token to send analysis reports to SonarQube for sqc-eu platform # - RUN_SHADOW_SCANS: If true, run sonar scanner on all 3 platforms. If false, run on the platform provided by SONAR_PLATFORM. +# When enabled, SONAR_PLATFORM is ignored. # - CURRENT_VERSION: Current project version as in gradle.properties # - ARTIFACTORY_ACCESS_TOKEN: Access token to read Repox repositories # - ARTIFACTORY_DEPLOY_REPO: Name of deployment repository @@ -48,25 +49,18 @@ set -euo pipefail # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_ACCESS_TOKEN:?}" -: "${ARTIFACTORY_DEPLOY_REPO:?}" -: "${DEPLOY:=true}" +: "${ARTIFACTORY_ACCESS_TOKEN:?}" "${ARTIFACTORY_DEPLOY_REPO:?}" "${DEPLOY:=true}" "${DEPLOY_PULL_REQUEST:=false}" "${RUN_SHADOW_SCANS:?}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_RUN_ID:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" "${GITHUB_SHA:?}" -: "${GITHUB_OUTPUT:?}" -: "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" -: "${RUN_SHADOW_SCANS:?}" +: "${GITHUB_OUTPUT:?}" "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" "${CURRENT_VERSION:?}" if [[ "$DEPLOY" != "false" && "$RUN_SHADOW_SCANS" != "true" ]]; then : "${ARTIFACTORY_DEPLOY_USERNAME:?}" "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" fi -: "${CURRENT_VERSION:?}" if [[ "${SONAR_PLATFORM:?}" != "none" ]]; then : "${NEXT_URL:?}" "${NEXT_TOKEN:?}" "${SQC_US_URL:?}" "${SQC_US_TOKEN:?}" "${SQC_EU_URL:?}" "${SQC_EU_TOKEN:?}" fi : "${ORG_GRADLE_PROJECT_signingKey:?}" "${ORG_GRADLE_PROJECT_signingPassword:?}" "${ORG_GRADLE_PROJECT_signingKeyId:?}" -: "${DEPLOY_PULL_REQUEST:=false}" -export DEPLOY_PULL_REQUEST -: "${SKIP_TESTS:=false}" -: "${GRADLE_ARGS:=}" +: "${SKIP_TESTS:=false}" "${GRADLE_ARGS:=}" +export DEPLOY DEPLOY_PULL_REQUEST SKIP_TESTS GRADLE_ARGS git_fetch_unshallow() { if [ "$SONAR_PLATFORM" = "none" ]; then @@ -112,6 +106,14 @@ should_deploy() { fi } +should_scan() { + if [[ "$SONAR_PLATFORM" = "none" ]]; then + return 1 + fi + is_default_branch || is_maintenance_branch || is_pull_request || is_long_lived_feature_branch + return $? +} + build_gradle_args() { local args=() @@ -216,19 +218,15 @@ gradle_build() { echo "Sonar Platform: ${SONAR_PLATFORM}" echo "Run Shadow Scans: ${RUN_SHADOW_SCANS}" - if [[ "$SONAR_PLATFORM" == "none" ]]; then + if should_scan; then + # Build with sonar analysis via orchestrator + # shellcheck disable=SC2119 + orchestrate_sonar_platforms + else # Build without sonar - call gradle_build_and_analyze directly echo "::group::Gradle build" gradle_build_and_analyze echo "::endgroup::" - else - # Build with sonar analysis via orchestrator - # TODO BUILD-10586: sonar analysis is not filtered by branch type here — it runs on all branches - # (including dogfood and other branches) when sonar-platform != none. This differs from - # build-maven/build-npm/build-yarn/build-poetry which skip sonar on dogfood/other branches. - # Should add a should_scan() guard consistent with the other build scripts. - # shellcheck disable=SC2119 - orchestrate_sonar_platforms fi } diff --git a/build-maven/build.sh b/build-maven/build.sh index c02ce37..d342c3b 100755 --- a/build-maven/build.sh +++ b/build-maven/build.sh @@ -14,7 +14,7 @@ # - RUN_SHADOW_SCANS: If true, run sonar scanner on all 3 platforms. If false, run on the platform provided by SONAR_PLATFORM. # - ARTIFACTORY_URL: Artifactory repository URL # - ARTIFACTORY_ACCESS_TOKEN: Access token to read Repox repositories -# - ARTIFACTORY_DEPLOY_REPO: Deployment repository name +# - ARTIFACTORY_DEPLOY_REPO: Deployment repository name. Required by maven-enforcer-plugin in SonarSource parent POM. # - ARTIFACTORY_DEPLOY_USERNAME: Username used by artifactory-maven-plugin # - ARTIFACTORY_DEPLOY_PASSWORD: Access token to deploy to the repository # - CURRENT_VERSION: Current project version as in pom.xml @@ -45,26 +45,17 @@ set -euo pipefail # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_URL:?}" -# Required by maven-enforcer-plugin in SonarSource parent POM -: "${ARTIFACTORY_DEPLOY_REPO:?}" -: "${DEPLOY:=true}" -: "${CURRENT_VERSION:?}" +: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_DEPLOY_REPO:?}" "${DEPLOY:=true}" "${DEPLOY_PULL_REQUEST:=false}" "${RUN_SHADOW_SCANS:?}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_RUN_ID:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" -: "${GITHUB_SHA:?}" -: "${GITHUB_OUTPUT:?}" -: "${RUNNER_OS:?}" -: "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" +: "${GITHUB_SHA:?}" "${GITHUB_OUTPUT:?}" "${RUNNER_OS:?}" "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" "${CURRENT_VERSION:?}" if [[ "${SONAR_PLATFORM:?}" != "none" ]]; then : "${NEXT_URL:?}" "${NEXT_TOKEN:?}" "${SQC_US_URL:?}" "${SQC_US_TOKEN:?}" "${SQC_EU_URL:?}" "${SQC_EU_TOKEN:?}" fi -: "${RUN_SHADOW_SCANS:?}" if [[ "$DEPLOY" != "false" && "$RUN_SHADOW_SCANS" != "true" ]]; then : "${ARTIFACTORY_DEPLOY_USERNAME:?}" "${ARTIFACTORY_DEPLOY_PASSWORD:?}" fi -: "${DEPLOY_PULL_REQUEST:=false}" : "${USER_MAVEN_ARGS:=}" -export ARTIFACTORY_URL DEPLOY_PULL_REQUEST +export DEPLOY DEPLOY_PULL_REQUEST USER_MAVEN_ARGS readonly DEPLOYED_OUTPUT_KEY="deployed" # FIXME Workaround for SonarSource parent POM; it can be removed after releases of parent 73+ and parent-oss 84+ @@ -136,7 +127,7 @@ should_deploy() { } should_scan() { - if [ "$SONAR_PLATFORM" = "none" ]; then + if [[ "$SONAR_PLATFORM" = "none" ]]; then return 1 fi is_default_branch || is_maintenance_branch || is_pull_request || is_long_lived_feature_branch diff --git a/build-npm/action.yml b/build-npm/action.yml index 811415c..808cbc9 100644 --- a/build-npm/action.yml +++ b/build-npm/action.yml @@ -14,17 +14,24 @@ inputs: `public-deployer` for public repositories. default: '' artifactory-deploy-repo: - description: Deployment repository. Defaults to `sonarsource-npm-public-qa` for private repositories, and `sonarsource-npm-public-qa` + description: Deployment repository. Defaults to `sonarsource-npm-private-qa` for private repositories, and `sonarsource-npm-public-qa` for public repositories. default: '' + deploy: + description: Whether to deploy on master, maintenance, dogfood and long-lived branches. + default: 'true' deploy-pull-request: - description: Whether to deploy pull request artifacts + description: Whether to also deploy pull request artifacts. If deploy is 'false', this has no effect. default: 'false' skip-tests: description: Whether to skip running tests default: 'false' + disable-caching: + description: Whether to disable NPM caching entirely + default: 'false' cache-npm: - description: Whether to cache NPM dependencies + description: >- + Deprecated. Use `disable-caching` instead. Whether to cache NPM dependencies. default: 'true' repox-url: description: URL for Repox @@ -37,7 +44,7 @@ inputs: default: next run-shadow-scans: description: If true, run sonar scanner on all 3 platforms using the provided URL and token. - If false, run on the platform provided by SONAR_PLATFORM. + If false, run on the platform provided by sonar-platform. When enabled, the sonar-platform setting is ignored. default: 'false' build-name: description: Name of the build to publish. Defaults to the repository name. @@ -115,6 +122,7 @@ runs: repox-url: ${{ inputs.repox-url }} repox-artifactory-url: ${{ inputs.repox-artifactory-url }} working-directory: ${{ inputs.working-directory }} + disable-caching: ${{ inputs.disable-caching }} cache-npm: ${{ inputs.cache-npm }} - uses: SonarSource/vault-action-wrapper@3d5c87cb535e4a2c7a09adcbcfdefa751854dee3 # 3.3.0 @@ -128,7 +136,7 @@ runs: ${{ inputs.sonar-platform != 'none' && 'development/kv/data/sonarqube-us token | SQC_US_TOKEN;' || '' }} ${{ inputs.sonar-platform != 'none' && 'development/kv/data/sonarcloud url | SQC_EU_URL;' || '' }} ${{ inputs.sonar-platform != 'none' && 'development/kv/data/sonarcloud token | SQC_EU_TOKEN;' || '' }} - development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_DEPLOYER_ROLE }} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN; + ${{ inputs.deploy != 'false' && inputs.run-shadow-scans != 'true' && format('development/artifactory/token/{{REPO_OWNER_NAME_DASH}}-{0} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN;', env.ARTIFACTORY_DEPLOYER_ROLE) || '' }} # yamllint enable rule:line-length - name: Build, test, analyze and deploy id: build @@ -145,6 +153,7 @@ runs: ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo != '' && inputs.artifactory-deploy-repo || (github.event.repository.visibility == 'public' && 'sonarsource-npm-public-qa' || 'sonarsource-npm-private-qa') }} ARTIFACTORY_DEPLOY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_DEPLOY_ACCESS_TOKEN }} + DEPLOY: ${{ inputs.deploy }} DEPLOY_PULL_REQUEST: ${{ inputs.deploy-pull-request }} SKIP_TESTS: ${{ inputs.skip-tests }} diff --git a/build-npm/build.sh b/build-npm/build.sh index f392e32..38b01f9 100755 --- a/build-npm/build.sh +++ b/build-npm/build.sh @@ -2,7 +2,7 @@ # Build script for SonarSource NPM projects. # Supports building, testing, SonarQube analysis, and JFrog Artifactory deployment. # -# Required environment variables (must be explicitly provided): +# Required inputs (must be explicitly provided): # - BUILD_NUMBER: Build number for versioning # - BUILD_NAME: Name of the JFrog Artifactory build (e.g. sonar-dummy) # - SONAR_PLATFORM: SonarQube primary platform (next, sqc-eu, sqc-us, or none). Use 'none' to skip sonar scans. @@ -13,6 +13,7 @@ # - SQC_EU_URL: URL of SonarQube server for sqc-eu platform # - SQC_EU_TOKEN: Access token to send analysis reports to SonarQube for sqc-eu platform # - RUN_SHADOW_SCANS: If true, run sonar scanner on all 3 platforms. If false, run on the platform provided by SONAR_PLATFORM. +# When enabled, SONAR_PLATFORM is ignored. # - ARTIFACTORY_URL: URL to Artifactory repository # - ARTIFACTORY_DEPLOY_ACCESS_TOKEN: Access token to deploy to Artifactory # - ARTIFACTORY_DEPLOY_REPO: Name of deployment repository @@ -30,6 +31,7 @@ # - GITHUB_BASE_REF: Base branch for pull requests (only during pull_request events) # # Optional user customization: +# - DEPLOY: Whether to deploy (default: true) # - DEPLOY_PULL_REQUEST: Whether to deploy pull request artifacts (default: false) # - SKIP_TESTS: Whether to skip running tests (default: false) # - SQ_SCANNER_VERSION: Version of sonarqube-scanner to use (default: 4.3.0) @@ -41,19 +43,17 @@ set -euo pipefail # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_URL:?}" -: "${ARTIFACTORY_DEPLOY_REPO:?}" "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" +: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_DEPLOY_REPO:?}" "${DEPLOY:=true}" "${DEPLOY_PULL_REQUEST:=false}" "${RUN_SHADOW_SCANS:?}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_RUN_ID:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" "${GITHUB_SHA:?}" -: "${GITHUB_OUTPUT:?}" -: "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" -: "${RUN_SHADOW_SCANS:?}" +: "${GITHUB_OUTPUT:?}" "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" +if [[ "$DEPLOY" != "false" && "$RUN_SHADOW_SCANS" != "true" ]]; then + : "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" +fi if [[ "${SONAR_PLATFORM:?}" != "none" ]]; then : "${NEXT_URL:?}" "${NEXT_TOKEN:?}" "${SQC_US_URL:?}" "${SQC_US_TOKEN:?}" "${SQC_EU_URL:?}" "${SQC_EU_TOKEN:?}" fi -: "${DEPLOY_PULL_REQUEST:=false}" "${SKIP_TESTS:=false}" -export DEPLOY_PULL_REQUEST SKIP_TESTS -: "${BUILD_NAME:?}" "${PROJECT_VERSION:?}" "${CURRENT_VERSION:?}" -: "${SQ_SCANNER_VERSION:=4.3.0}" +: "${SKIP_TESTS:=false}" "${BUILD_NAME:?}" "${PROJECT_VERSION:?}" "${CURRENT_VERSION:?}" "${SQ_SCANNER_VERSION:=4.3.0}" +export DEPLOY DEPLOY_PULL_REQUEST SKIP_TESTS SQ_SCANNER_VERSION git_fetch_unshallow() { if [ "$SONAR_PLATFORM" = "none" ]; then @@ -123,9 +123,6 @@ jfrog_npm_publish() { } # Determine build configuration based on branch type -# TODO BUILD-10586: this function does not support a DEPLOY env var to override deployment (unlike build-maven and build-gradle). -# Should add a DEPLOY=${DEPLOY:=true} check consistent with those build scripts. -# Note: unlike build-maven and build-gradle, long-lived feature branches (feature/long/*) do not deploy here. get_build_config() { local enable_sonar enable_deploy local sonar_args=() @@ -162,7 +159,7 @@ get_build_config() { elif is_long_lived_feature_branch && ! is_pull_request; then echo "======= Build long-lived feature branch =======" enable_sonar=true - enable_deploy=false + enable_deploy=true sonar_args=("-Dsonar.branch.name=${GITHUB_REF_NAME}") else @@ -171,9 +168,14 @@ get_build_config() { enable_deploy=false fi + # Disable deployment when explicitly requested + if [[ "${DEPLOY}" != "true" ]]; then + enable_deploy=false + fi + # Disable deployment when shadow scans are enabled to prevent duplicate artifacts if [[ "${RUN_SHADOW_SCANS}" = "true" ]]; then - echo "======= Shadow scans enabled - disabling deployment to prevent duplicate artifacts =======" + echo "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" >&2 enable_deploy=false fi diff --git a/build-poetry/action.yml b/build-poetry/action.yml index 8b3f613..0520bb5 100644 --- a/build-poetry/action.yml +++ b/build-poetry/action.yml @@ -17,8 +17,11 @@ inputs: description: Deployment repository. Defaults to `sonarsource-pypi-private-qa` for private repositories, and `sonarsource-pypi-public-qa` for public repositories. default: '' + deploy: + description: Whether to deploy on master, maintenance, dogfood and long-lived branches. + default: 'true' deploy-pull-request: - description: Whether to deploy pull request artifacts. Set to `false` if not using the promote action. + description: Whether to also deploy pull request artifacts. If deploy is 'false', this has no effect. default: 'false' poetry-virtualenvs-path: description: Path to the Poetry virtual environments, relative to GitHub workspace. The folder is cached only if it is a subdirectory of @@ -128,7 +131,7 @@ runs: ${{ inputs.sonar-platform != 'none' && 'development/kv/data/sonarcloud url | SQC_EU_URL;' || '' }} ${{ inputs.sonar-platform != 'none' && 'development/kv/data/sonarcloud token | SQC_EU_TOKEN;' || '' }} development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN; - development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_DEPLOYER_ROLE }} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN; + ${{ inputs.deploy != 'false' && inputs.run-shadow-scans != 'true' && format('development/artifactory/token/{{REPO_OWNER_NAME_DASH}}-{0} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN;', env.ARTIFACTORY_DEPLOYER_ROLE) || '' }} # yamllint enable rule:line-length - name: Build, Analyze and deploy id: build @@ -142,6 +145,7 @@ runs: # Action inputs ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || format('{0}/artifactory', inputs.repox-url) }} + DEPLOY: ${{ inputs.deploy }} DEPLOY_PULL_REQUEST: ${{ inputs.deploy-pull-request }} ARTIFACTORY_PYPI_REPO: ${{ inputs.public == 'true' && 'sonarsource-pypi' || 'sonarsource-pypi' }} # FIXME: sonarsource-pypi-public ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo != '' && inputs.artifactory-deploy-repo || diff --git a/build-poetry/build.sh b/build-poetry/build.sh index fd7c918..8aadb3a 100755 --- a/build-poetry/build.sh +++ b/build-poetry/build.sh @@ -11,7 +11,7 @@ # - ARTIFACTORY_DEPLOY_ACCESS_TOKEN: Access token to deploy to the repository # - DEFAULT_BRANCH: Default branch name (e.g. main) # - PULL_REQUEST: Pull request number (e.g. 1234) or empty string -# - SONAR_PLATFORM: SonarQube primary platform (next, sqc-eu, or sqc-us) +# - SONAR_PLATFORM: SonarQube primary platform (next, sqc-eu, sqc-us, or none). Use 'none' to skip sonar scans. # - NEXT_URL: URL of SonarQube server for next platform # - NEXT_TOKEN: Access token to send analysis reports to SonarQube for next platform # - SQC_US_URL: URL of SonarQube server for sqc-us platform @@ -19,6 +19,7 @@ # - SQC_EU_URL: URL of SonarQube server for sqc-eu platform # - SQC_EU_TOKEN: Access token to send analysis reports to SonarQube for sqc-eu platform # - RUN_SHADOW_SCANS: If true, run sonar scanner on all 3 platforms. If false, run on the platform provided by SONAR_PLATFORM. +# When enabled, SONAR_PLATFORM is ignored. # # GitHub Actions auto-provided: # - GITHUB_REF_NAME: Git branch name @@ -32,6 +33,7 @@ # - GITHUB_BASE_REF: Base branch for pull requests (only during pull_request events) # # Optional user customization: +# - DEPLOY: Whether to deploy (default: true) # - DEPLOY_PULL_REQUEST: Whether to deploy pull request artifacts (default: false) # # Auto-derived by script: @@ -43,18 +45,17 @@ set -euo pipefail # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_URL:?}" -: "${ARTIFACTORY_PYPI_REPO:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" "${ARTIFACTORY_DEPLOY_REPO:?}" "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" +: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_PYPI_REPO:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" +: "${ARTIFACTORY_DEPLOY_REPO:?}" "${DEPLOY:=true}" "${DEPLOY_PULL_REQUEST:=false}" "${RUN_SHADOW_SCANS:?}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" "${GITHUB_EVENT_PATH:?}" -: "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" -: "${GITHUB_ENV:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_SHA:?}" "${GITHUB_RUN_ID:?}" -# Only validate sonar credentials if platform is not 'none' +: "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" "${GITHUB_ENV:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_SHA:?}" "${GITHUB_RUN_ID:?}" if [[ "${SONAR_PLATFORM:?}" != "none" ]]; then : "${NEXT_URL:?}" "${NEXT_TOKEN:?}" "${SQC_US_URL:?}" "${SQC_US_TOKEN:?}" "${SQC_EU_URL:?}" "${SQC_EU_TOKEN:?}" fi -: "${RUN_SHADOW_SCANS:?}" -: "${DEPLOY_PULL_REQUEST:=false}" -export ARTIFACTORY_URL DEPLOY_PULL_REQUEST +if [[ "$DEPLOY" != "false" && "$RUN_SHADOW_SCANS" != "true" ]]; then + : "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" +fi +export DEPLOY DEPLOY_PULL_REQUEST # Unshallow and fetch all commit history for SonarQube analysis and issue assignment git_fetch_unshallow() { @@ -193,9 +194,6 @@ set_project_version() { } # Determine build configuration based on branch type -# TODO BUILD-10586: this function does not support a DEPLOY env var to override deployment (unlike build-maven and build-gradle). -# Should add a DEPLOY=${DEPLOY:=true} check consistent with those build scripts. -# Note: unlike build-maven and build-gradle, long-lived feature branches (feature/long/*) do not deploy here. get_build_config() { local enable_sonar enable_deploy local sonar_args=() @@ -235,7 +233,7 @@ get_build_config() { elif is_long_lived_feature_branch && ! is_pull_request; then echo "======= Build long-lived feature branch =======" enable_sonar=true - enable_deploy=false + enable_deploy=true sonar_args=("-Dsonar.branch.name=${GITHUB_REF_NAME}") else @@ -244,6 +242,17 @@ get_build_config() { enable_deploy=false fi + # Disable deployment when explicitly requested + if [[ "${DEPLOY}" != "true" ]]; then + enable_deploy=false + fi + + # Disable deployment when shadow scans are enabled to prevent duplicate artifacts + if [[ "${RUN_SHADOW_SCANS}" = "true" ]]; then + echo "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" >&2 + enable_deploy=false + fi + # Export the configuration for use by build_poetry export BUILD_ENABLE_SONAR="$enable_sonar" export BUILD_ENABLE_DEPLOY="$enable_deploy" diff --git a/build-yarn/action.yml b/build-yarn/action.yml index 667d8e3..7a1e100 100644 --- a/build-yarn/action.yml +++ b/build-yarn/action.yml @@ -20,14 +20,22 @@ inputs: description: Deployment repository. Defaults to `sonarsource-private-qa` for private repositories, and `sonarsource-public-qa` for public repositories. default: '' + deploy: + description: Whether to deploy on master, maintenance, dogfood and long-lived branches. + default: 'true' deploy-pull-request: - description: Whether to deploy pull request artifacts + description: Whether to also deploy pull request artifacts. If deploy is 'false', this has no effect. default: 'false' skip-tests: description: Whether to skip running tests default: 'false' + disable-caching: + description: Whether to disable Yarn caching entirely + default: 'false' cache-yarn: - description: Whether to cache Yarn dependencies + description: >- + Deprecated. Use `disable-caching: 'true'` instead. + Whether to cache Yarn dependencies. default: 'true' repox-url: description: URL for Repox @@ -40,7 +48,7 @@ inputs: default: next run-shadow-scans: description: If true, run sonar scanner on all 3 platforms using the provided URL and token. - If false, run on the platform provided by SONAR_PLATFORM. + If false, run on the platform provided by sonar-platform. When enabled, the sonar-platform setting is ignored. default: 'false' provenance: description: Whether to generate provenance attestation for built artifacts @@ -112,7 +120,7 @@ runs: - name: Cache Yarn dependencies uses: SonarSource/gh-action_cache@957cb1f6f70956976b834546bf09839080b5bb00 # v1.2.3 - if: ${{ inputs.cache-yarn == 'true' }} + if: ${{ inputs.cache-yarn == 'true' && inputs.disable-caching != 'true' }} with: path: | ~/.yarn @@ -132,7 +140,7 @@ runs: ${{ inputs.sonar-platform != 'none' && 'development/kv/data/sonarcloud token | SQC_EU_TOKEN;' || '' }} development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} username | ARTIFACTORY_USERNAME; development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN; - development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_DEPLOYER_ROLE }} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN; + ${{ inputs.deploy != 'false' && inputs.run-shadow-scans != 'true' && format('development/artifactory/token/{{REPO_OWNER_NAME_DASH}}-{0} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN;', env.ARTIFACTORY_DEPLOYER_ROLE) || '' }} # yamllint enable rule:line-length - name: Build, test, analyze and deploy @@ -151,6 +159,7 @@ runs: ARTIFACTORY_USERNAME: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_USERNAME }} ARTIFACTORY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_ACCESS_TOKEN }} ARTIFACTORY_DEPLOY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_DEPLOY_ACCESS_TOKEN }} + DEPLOY: ${{ inputs.deploy }} DEPLOY_PULL_REQUEST: ${{ inputs.deploy-pull-request }} SKIP_TESTS: ${{ inputs.skip-tests }} diff --git a/build-yarn/build.sh b/build-yarn/build.sh index d66f4f9..d1d7bd9 100755 --- a/build-yarn/build.sh +++ b/build-yarn/build.sh @@ -4,7 +4,7 @@ # # Required inputs (must be explicitly provided): # - BUILD_NUMBER: Build number for versioning -# - SONAR_PLATFORM: SonarQube primary platform (next, sqc-eu, or sqc-us) +# - SONAR_PLATFORM: SonarQube primary platform (next, sqc-eu, sqc-us, or none). Use 'none' to skip sonar scans. # - NEXT_URL: URL of SonarQube server for next platform # - NEXT_TOKEN: Access token to send analysis reports to SonarQube for next platform # - SQC_US_URL: URL of SonarQube server for sqc-us platform @@ -12,6 +12,7 @@ # - SQC_EU_URL: URL of SonarQube server for sqc-eu platform # - SQC_EU_TOKEN: Access token to send analysis reports to SonarQube for sqc-eu platform # - RUN_SHADOW_SCANS: If true, run sonar scanner on all 3 platforms. If false, run on the platform provided by SONAR_PLATFORM. +# When enabled, SONAR_PLATFORM is ignored. # - ARTIFACTORY_URL: URL to Artifactory repository # - ARTIFACTORY_USERNAME: Username that matches the access token to read Repox repositories # - ARTIFACTORY_ACCESS_TOKEN: Access token to read Repox repositories @@ -31,6 +32,7 @@ # - GITHUB_BASE_REF: Base branch for pull requests (only during pull_request events) # # Optional user customization: +# - DEPLOY: Whether to deploy (default: true) # - DEPLOY_PULL_REQUEST: Whether to deploy pull request artifacts (default: false) # - SKIP_TESTS: Whether to skip running tests (default: false) # @@ -45,19 +47,17 @@ PACKAGE_JSON="package.json" # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_URL:?}" -: "${ARTIFACTORY_USERNAME:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" -: "${ARTIFACTORY_DEPLOY_REPO:?}" "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" +: "${ARTIFACTORY_URL:?}" "${ARTIFACTORY_USERNAME:?}" "${ARTIFACTORY_ACCESS_TOKEN:?}" +: "${ARTIFACTORY_DEPLOY_REPO:?}" "${DEPLOY:=true}" "${DEPLOY_PULL_REQUEST:=false}" "${RUN_SHADOW_SCANS:?}" "${SKIP_TESTS:=false}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_RUN_ID:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" "${GITHUB_SHA:?}" -: "${GITHUB_OUTPUT:?}" -: "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" -: "${RUN_SHADOW_SCANS:?}" +: "${GITHUB_OUTPUT:?}" "${PULL_REQUEST?}" "${DEFAULT_BRANCH:?}" "${SQ_SCANNER_VERSION:=4.3.0}" +if [[ "$DEPLOY" != "false" && "$RUN_SHADOW_SCANS" != "true" ]]; then + : "${ARTIFACTORY_DEPLOY_ACCESS_TOKEN:?}" +fi if [[ "${SONAR_PLATFORM:?}" != "none" ]]; then : "${NEXT_URL:?}" "${NEXT_TOKEN:?}" "${SQC_US_URL:?}" "${SQC_US_TOKEN:?}" "${SQC_EU_URL:?}" "${SQC_EU_TOKEN:?}" fi -: "${DEPLOY_PULL_REQUEST:=false}" "${SKIP_TESTS:=false}" -export ARTIFACTORY_URL DEPLOY_PULL_REQUEST SKIP_TESTS -: "${SQ_SCANNER_VERSION:=4.3.0}" +export DEPLOY DEPLOY_PULL_REQUEST SKIP_TESTS SQ_SCANNER_VERSION git_fetch_unshallow() { if [ "$SONAR_PLATFORM" = "none" ]; then @@ -193,9 +193,6 @@ jfrog_yarn_publish() { } # Determine build configuration based on branch type -# TODO BUILD-10586: this function does not support a DEPLOY env var to override deployment (unlike build-maven and build-gradle). -# Should add a DEPLOY=${DEPLOY:=true} check consistent with those build scripts. -# Note: unlike build-maven and build-gradle, long-lived feature branches (feature/long/*) do not deploy here. get_build_config() { local enable_sonar enable_deploy local sonar_args=() @@ -232,7 +229,7 @@ get_build_config() { elif is_long_lived_feature_branch && ! is_pull_request; then echo "======= Build long-lived feature branch =======" enable_sonar=true - enable_deploy=false + enable_deploy=true sonar_args=("-Dsonar.branch.name=${GITHUB_REF_NAME}") else @@ -241,9 +238,14 @@ get_build_config() { enable_deploy=false fi + # Disable deployment when explicitly requested + if [[ "${DEPLOY}" != "true" ]]; then + enable_deploy=false + fi + # Disable deployment when shadow scans are enabled to prevent duplicate artifacts if [[ "${RUN_SHADOW_SCANS}" = "true" ]]; then - echo "======= Shadow scans enabled - disabling deployment to prevent duplicate artifacts =======" + echo "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" >&2 enable_deploy=false fi diff --git a/config-gradle/set_gradle_project_version.sh b/config-gradle/set_gradle_project_version.sh index ee8625e..495f689 100755 --- a/config-gradle/set_gradle_project_version.sh +++ b/config-gradle/set_gradle_project_version.sh @@ -10,11 +10,11 @@ # # Optional user customization: # - CURRENT_VERSION and PROJECT_VERSION: If both are set, they will be used as-is and no version update will be performed. +# - SKIP: If true, the script will skip setting the project version and outputting the current version. Defaults to false. set -euo pipefail -: "${BUILD_NUMBER:?}" -: "${GITHUB_OUTPUT:?}" "${GITHUB_ENV:?}" "${SKIP:=false}" +: "${BUILD_NUMBER:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_ENV:?}" "${SKIP:=false}" # shellcheck source=SCRIPTDIR/../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" diff --git a/config-maven/set_maven_project_version.sh b/config-maven/set_maven_project_version.sh index a0680fe..998419d 100755 --- a/config-maven/set_maven_project_version.sh +++ b/config-maven/set_maven_project_version.sh @@ -10,11 +10,11 @@ # # Optional user customization: # - CURRENT_VERSION and PROJECT_VERSION: If both are set, they will be used as-is and no version update will be performed. +# - SKIP: If true, the script will skip setting the project version and outputting the current version. Defaults to false. set -euo pipefail -: "${BUILD_NUMBER:?}" -: "${GITHUB_OUTPUT:?}" "${GITHUB_ENV:?}" "${SKIP:=false}" +: "${BUILD_NUMBER:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_ENV:?}" "${SKIP:=false}" # shellcheck source=SCRIPTDIR/../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" diff --git a/config-npm/action.yml b/config-npm/action.yml index 31f1f84..2930c6e 100644 --- a/config-npm/action.yml +++ b/config-npm/action.yml @@ -9,8 +9,13 @@ inputs: description: Suffix for the Artifactory reader role in Vault. Defaults to `private-reader` for private repositories, and `public-reader` for public repositories. default: '' + disable-caching: + description: Whether to disable NPM caching entirely + default: 'false' cache-npm: - description: Whether to cache NPM dependencies + description: >- + Deprecated. Use `disable-caching: 'true'` instead. + Whether to cache NPM dependencies. default: 'true' repox-url: description: URL for Repox @@ -75,7 +80,15 @@ runs: with: version: 2026.3.7 + - id: config-npm-completed + if: env.CONFIG_NPM_COMPLETED != '' + shell: bash + run: | + echo "Action already called by $CONFIG_NPM_COMPLETED, execution skipped." + echo "skip=true" >> $GITHUB_OUTPUT + - uses: SonarSource/vault-action-wrapper@3d5c87cb535e4a2c7a09adcbcfdefa751854dee3 # 3.3.0 + if: steps.config-npm-completed.outputs.skip != 'true' id: secrets with: secrets: | @@ -83,6 +96,7 @@ runs: development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN; - name: Configure NPM authentication + if: steps.config-npm-completed.outputs.skip != 'true' shell: bash env: ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || @@ -99,7 +113,7 @@ runs: - name: Sanitize workflow name for cache key id: sanitize_workflow - if: ${{ inputs.cache-npm == 'true' }} + if: steps.config-npm-completed.outputs.skip != 'true' && inputs.disable-caching != 'true' && inputs.cache-npm == 'true' shell: bash env: WORKFLOW_NAME: ${{ github.workflow }} @@ -107,7 +121,7 @@ runs: - name: Cache NPM dependencies uses: SonarSource/gh-action_cache@957cb1f6f70956976b834546bf09839080b5bb00 # v1.2.3 - if: ${{ inputs.cache-npm == 'true' }} + if: steps.config-npm-completed.outputs.skip != 'true' && inputs.disable-caching != 'true' && inputs.cache-npm == 'true' with: path: ~/.npm key: npm-${{ runner.os }}-${{ steps.sanitize_workflow.outputs.workflow_name }}-${{ hashFiles('**/package-lock.json') }} @@ -115,6 +129,7 @@ runs: - name: Check for package.json id: check_package_json + if: steps.config-npm-completed.outputs.skip != 'true' shell: bash working-directory: ${{ inputs.working-directory }} run: | @@ -127,14 +142,20 @@ runs: - uses: ./.actions/get-build-number id: get_build_number + if: steps.config-npm-completed.outputs.skip != 'true' with: host-actions-root: ${{ steps.setup.outputs.host_actions_root }} - name: Update project version and set current-version and project-version variables id: set_version - if: ${{ steps.check_package_json.outputs.exists == 'true' }} + if: steps.config-npm-completed.outputs.skip != 'true' && steps.check_package_json.outputs.exists == 'true' shell: bash env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} working-directory: ${{ inputs.working-directory }} run: $ACTION_PATH_CONFIG_NPM/npm_set_project_version.sh + + - name: Set Config NPM completed + if: steps.config-npm-completed.outputs.skip != 'true' + shell: bash + run: echo "CONFIG_NPM_COMPLETED=$GITHUB_ACTION" >> "$GITHUB_ENV" diff --git a/config-npm/npm_set_project_version.sh b/config-npm/npm_set_project_version.sh index 9b35ab4..684411f 100755 --- a/config-npm/npm_set_project_version.sh +++ b/config-npm/npm_set_project_version.sh @@ -18,8 +18,7 @@ PACKAGE_JSON="package.json" # shellcheck source=SCRIPTDIR/../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${BUILD_NUMBER:?}" -: "${GITHUB_OUTPUT:?}" "${GITHUB_ENV:?}" +: "${BUILD_NUMBER:?}" "${GITHUB_OUTPUT:?}" "${GITHUB_ENV:?}" check_version_format() { local version="$1" diff --git a/pr_cleanup/cleanup.sh b/pr_cleanup/cleanup.sh index a6a6ac7..e845287 100755 --- a/pr_cleanup/cleanup.sh +++ b/pr_cleanup/cleanup.sh @@ -1,17 +1,14 @@ #!/bin/bash # Cleanup caches and artifacts for a pull request in a GitHub repository. # Required environment variables: -# GH_TOKEN - GitHub token with actions:write permission for cache and artifact deletion +# GH_TOKEN - GitHub token with actions:write permission for cache and artifact deletion. Used by gh CLI # CACHE_REF - Cache reference in the format "refs/pull//merge" # GITHUB_REPOSITORY - Repository name with owner (e.g. "owner/repo") # GITHUB_HEAD_REF - Head branch reference of the pull request set -euo pipefail -: "${GH_TOKEN:?Required environment variable not set}" # used by gh CLI -: "${CACHE_REF:?Required environment variable not set}" -: "${GITHUB_REPOSITORY:?Required environment variable not set}" -: "${GITHUB_HEAD_REF:?Required environment variable not set}" +: "${GH_TOKEN:?}" "${CACHE_REF:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_HEAD_REF:?}" CURDIR=$(dirname "$0") readonly CACHE_LIST_LIMIT=100000 diff --git a/promote/promote.sh b/promote/promote.sh index 0b6f124..d54fa09 100755 --- a/promote/promote.sh +++ b/promote/promote.sh @@ -34,18 +34,15 @@ set -euo pipefail # shellcheck source=../shared/common-functions.sh source "$(dirname "${BASH_SOURCE[0]}")/../shared/common-functions.sh" -: "${ARTIFACTORY_URL:="https://repox.jfrog.io/artifactory"}" -: "${ARTIFACTORY_PROMOTE_ACCESS_TOKEN:?}" +: "${ARTIFACTORY_URL:="https://repox.jfrog.io/artifactory"}" "${ARTIFACTORY_PROMOTE_ACCESS_TOKEN:?}" "${BUILD_NAME:?}" : "${GITHUB_REF_NAME:?}" "${BUILD_NUMBER:?}" "${GITHUB_REPOSITORY:?}" "${GITHUB_EVENT_NAME:?}" "${GITHUB_EVENT_PATH:?}" "${GITHUB_TOKEN:?}" : "${GITHUB_SHA:?}" "${GITHUB_JOB:?}" -GH_API_VERSION_HEADER="X-GitHub-Api-Version: 2022-11-28" +: "${MULTI_REPO_PROMOTE:=false}" "${ARTIFACTORY_DEPLOY_REPO:=}" "${ARTIFACTORY_TARGET_REPO:=}" "${PROMOTE_PULL_REQUEST:=false}" +readonly MULTI_REPO_SRC_PRIVATE=sonarsource-private-qa +readonly MULTI_REPO_SRC_PUBLIC=sonarsource-public-qa +readonly GH_API_VERSION_HEADER="X-GitHub-Api-Version: 2022-11-28" BUILD_INFO_FILE=$(mktemp) rm -f "$BUILD_INFO_FILE" -: "${BUILD_NAME:?}" - -: "${MULTI_REPO_PROMOTE:=false}" "${ARTIFACTORY_DEPLOY_REPO:=}" "${ARTIFACTORY_TARGET_REPO:=}" "${PROMOTE_PULL_REQUEST:=false}" -MULTI_REPO_SRC_PRIVATE=sonarsource-private-qa -MULTI_REPO_SRC_PUBLIC=sonarsource-public-qa set_build_env() { : "${DEFAULT_BRANCH:=$(gh repo view --json defaultBranchRef --jq ".defaultBranchRef.name")}" @@ -171,8 +168,8 @@ jfrog_promote() { status='it-passed-pr' fi - export PROJECT_VERSION : "${PROJECT_VERSION:=$(get_build_info_property PROJECT_VERSION)}" + export PROJECT_VERSION if [[ "${MULTI_REPO_PROMOTE}" == "true" ]]; then local targetRepo1 targetRepo2 diff --git a/spec/build-gradle_spec.sh b/spec/build-gradle_spec.sh index dddfb9f..b11b900 100755 --- a/spec/build-gradle_spec.sh +++ b/spec/build-gradle_spec.sh @@ -305,6 +305,50 @@ Describe 'get_build_type' End +Describe 'should_scan' + It 'returns true for default branch' + When call should_scan + The status should be success + End + + It 'returns true for maintenance branch' + export GITHUB_REF_NAME="branch-1.0" + When call should_scan + The status should be success + End + + It 'returns true for pull request' + export GITHUB_EVENT_NAME="$GITHUB_EVENT_NAME_PR" + export GITHUB_REF_NAME="$GITHUB_REF_NAME_PR" + When call should_scan + The status should be success + End + + It 'returns true for long-lived feature branch' + export GITHUB_REF_NAME="feature/long/my-feature" + When call should_scan + The status should be success + End + + It 'returns false for dogfood branch' + export GITHUB_REF_NAME="dogfood-on-main" + When call should_scan + The status should be failure + End + + It 'returns false for regular feature branch' + export GITHUB_REF_NAME="feature/test" + When call should_scan + The status should be failure + End + + It 'returns false when sonar platform is none' + export SONAR_PLATFORM="none" + When call should_scan + The status should be failure + End +End + Describe 'gradle_build' It 'executes gradle build successfully' export GRADLE_ARGS="" @@ -347,6 +391,30 @@ Describe 'gradle_build' rm -f gradle-mock gradle.properties End + + It 'calls gradle_build_and_analyze directly for dogfood branch (no sonar)' + export GITHUB_REF_NAME="dogfood-on-main" + export SONAR_PLATFORM="next" + export GRADLE_ARGS="" + + echo "version=1.0-SNAPSHOT" > gradle.properties + echo '#!/bin/bash' > gradle-mock + echo 'echo "Gradle executed with: $*"' >> gradle-mock + chmod +x gradle-mock + export GRADLE_CMD="./gradle-mock" + + Mock get_build_type + echo "dogfood branch" + End + + When call gradle_build + The output should include "Starting dogfood branch build" + The output should include "Gradle executed with:" + The output should not include "=== ORCHESTRATOR:" + The stderr should include "::warning title=No artifacts found::" + + rm -f gradle-mock gradle.properties + End End Describe 'sonar_scanner_implementation()' diff --git a/spec/build-npm_spec.sh b/spec/build-npm_spec.sh index 3bd7534..071f478 100755 --- a/spec/build-npm_spec.sh +++ b/spec/build-npm_spec.sh @@ -76,6 +76,7 @@ export GITHUB_RUN_ID="12345" export GITHUB_SHA="abc123" export NEXT_TOKEN="next-token" export NEXT_URL="https://next.sonarqube.com" +export DEPLOY="true" export PULL_REQUEST="false" export RUN_SHADOW_SCANS="false" export SKIP_TESTS="false" @@ -262,7 +263,7 @@ Describe 'build_npm()' The output should not include "SonarQube scanner" End - It 'builds long-lived feature branch without deploy' + It 'builds long-lived feature branch with deploy' export GITHUB_REF_NAME="feature/long/test-feature" export GITHUB_EVENT_NAME="push" export BUILD_NUMBER="42" @@ -271,7 +272,18 @@ Describe 'build_npm()' The output should include "======= Build long-lived feature branch =======" The output should include "Installing npm dependencies..." The output should include "npx -- @sonar/scan" - The output should not include "DEBUG: JFrog operations" + The variable BUILD_ENABLE_DEPLOY should equal "true" + End + + It 'skips deploy when DEPLOY is false' + export GITHUB_REF_NAME="main" + export GITHUB_EVENT_NAME="push" + export BUILD_NUMBER="42" + export DEPLOY="false" + When call build_npm + The status should be success + The output should include "======= Building main branch =======" + The variable BUILD_ENABLE_DEPLOY should equal "false" End It 'builds other branches without sonar or deploy' @@ -356,7 +368,8 @@ Describe 'get_build_config()' export BUILD_NUMBER="42" When call get_build_config The status should be success - The output should include "======= Shadow scans enabled - disabling deployment to prevent duplicate artifacts =======" + The output should include "======= Building main branch =======" + The stderr should include "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" The variable BUILD_ENABLE_DEPLOY should equal "false" The variable BUILD_ENABLE_SONAR should equal "true" End @@ -390,5 +403,6 @@ Describe 'build_npm()' The output should include "Sonar Platform: next" The output should include "shadow scan enabled" The output should not include "DEBUG: JFrog operations" + The stderr should include "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" End End diff --git a/spec/build-poetry_spec.sh b/spec/build-poetry_spec.sh index 582ece7..4146439 100755 --- a/spec/build-poetry_spec.sh +++ b/spec/build-poetry_spec.sh @@ -38,6 +38,7 @@ export SQC_US_URL="https://sonarqube-us.com" export SQC_US_TOKEN="sqc-us-token" export SQC_EU_URL="https://sonarcloud.io" export SQC_EU_TOKEN="sqc-eu-token" +export DEPLOY="true" export RUN_SHADOW_SCANS="false" # Constant outputs (exported so mocks run in subshells can access it) @@ -459,7 +460,7 @@ Describe 'build_poetry()' The variable BUILD_ENABLE_SONAR should equal "false" End - It 'disables deploy on long-lived branch' + It 'enables deploy on long-lived branch' export GITHUB_REF_NAME="feature/long/test" When call build_poetry @@ -472,9 +473,20 @@ Describe 'build_poetry()' The line 7 should equal '======= Build long-lived feature branch =======' The status should be success The variable BUILD_ENABLE_SONAR should equal "true" + The variable BUILD_ENABLE_DEPLOY should equal "true" The variable BUILD_SONAR_ARGS should equal "-Dsonar.branch.name=feature/long/test" End + It 'disables deploy when DEPLOY is false' + export GITHUB_REF_NAME="main" + export DEPLOY="false" + + When call build_poetry + The status should be success + The output should include "======= Building main branch =======" + The variable BUILD_ENABLE_DEPLOY should equal "false" + End + It 'enables deploy and scan on maintenance branch' export GITHUB_REF_NAME="branch-1.2" @@ -542,6 +554,7 @@ Describe 'build_poetry()' The line 36 should equal 'poetry run pysonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.token=sqc-eu-token -Dsonar.analysis.buildNumber=42 -Dsonar.analysis.pipeline=dummy-run-id -Dsonar.analysis.repository=my-org/my-repo' The line 37 should equal '::endgroup::' The line 38 should equal '=== Completed Sonar analysis on all platforms ===' + The stderr should include "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" The status should be success End diff --git a/spec/build-yarn_spec.sh b/spec/build-yarn_spec.sh index f96de2d..7e48d7e 100755 --- a/spec/build-yarn_spec.sh +++ b/spec/build-yarn_spec.sh @@ -64,6 +64,7 @@ export SQC_US_URL="https://sonarqube-us.example.com" export SQC_US_TOKEN="sqc-us-token" export SQC_EU_URL="https://sonarcloud.io" export SQC_EU_TOKEN="sqc-eu-token" +export DEPLOY="true" export DEPLOY_PULL_REQUEST="false" SKIP_TESTS="false" DEFAULT_BRANCH="main" PULL_REQUEST="" common_setup() { @@ -351,7 +352,8 @@ Describe 'build-yarn/build.sh' export RUN_SHADOW_SCANS="true" When call get_build_config The status should be success - The output should include "======= Shadow scans enabled - disabling deployment to prevent duplicate artifacts =======" + The output should include "======= Building main branch =======" + The stderr should include "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" The variable BUILD_ENABLE_DEPLOY should equal "false" The variable BUILD_ENABLE_SONAR should equal "true" End @@ -381,6 +383,7 @@ Describe 'build-yarn/build.sh' The output should include "Sonar Platform: next" The output should include "shadow scan enabled" The output should not include "JFrog operations" + The stderr should include "::warning title=Deployment disabled::Shadow scans enabled - disabling deployment" End End @@ -420,11 +423,22 @@ Describe 'build-yarn/build.sh' The stderr should include "::warning title=No artifacts found::" End - It 'builds long-lived feature branch' + It 'builds long-lived feature branch with deploy' export GITHUB_REF_NAME="feature/long/test" GITHUB_EVENT_NAME="push" PROJECT="test" When call build_yarn The status should be success The output should include "======= Build long-lived feature branch =======" + The variable BUILD_ENABLE_DEPLOY should equal "true" + The stderr should include "::warning title=No artifacts found::" + End + + It 'skips deploy when DEPLOY is false' + export GITHUB_REF_NAME="main" GITHUB_EVENT_NAME="push" PROJECT="test" + export DEPLOY="false" + When call build_yarn + The status should be success + The output should include "======= Building main branch =======" + The variable BUILD_ENABLE_DEPLOY should equal "false" End End