From 5047c7505b7280b2c2c56180b900af242d8e3a7f Mon Sep 17 00:00:00 2001 From: Julien Carsique Date: Mon, 16 Mar 2026 10:00:33 +0100 Subject: [PATCH 1/2] BUILD-10591 Leverage JFrog CLI summary in build-npm, build-yarn, build-poetry and promote Generate the JFrog CLI job summary explicitly rather than relying on the setup-jfrog-cli post-step, which fails and conflicts with the CLI. **JFrog CLI configuration fixes (build-npm, build-yarn, build-poetry, config-npm, promote)**: - Add --url flag to 'jf config add repox' with the JFrog Platform URL (base URL without '/artifactory') - Add 'jf config use repox' (or 'deploy' for maven) after 'jf config add' to explicitly activate the server configuration - In promote.sh and build scripts, suppress 'jf config remove repox' output (redirect to /dev/null) - Make ARTIFACTORY_URL required (via :?) in promote.sh **JFrog CLI command summary (all build actions + promote)**: - Set JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR in build step env so JFrog CLI writes command summary data during execution - build-maven/deploy-artifacts.sh: also set JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR in the Artifacts upload step **Generate workflow summary (all build actions)**: - Merge JFrog CLI summary generation into 'Generate workflow summary' step (remove the separate 'Generate JFrog CLI summary' step) - Add JFrog summary support to build-maven (when mixed-privacy=true, using 'jf config use deploy') and build-gradle - Rework summary format: extract Published Modules from JFrog markdown.md (bold module names and multi-line
 file tree blocks) into a collapsible 
block - Change build URL link text from 'Browse artifacts in Artifactory' to 'Browse build `name:number` in Artifactory' **promote/action.yml**: - Add repox-url and repox-artifactory-url inputs (forwarded from callers) - Add ARTIFACTORY_URL env var to the Promote artifacts step **Other**: - Upgrade renovatebot/pre-commit-hooks to 43.76.3 in .pre-commit-config.yaml - Fix trailing spaces in deprecation warning messages (cache/action.yml, config-npm/action.yml, build-npm/action.yml, build-yarn/action.yml) - Minor doc fix in build-maven/build.sh and promote/promote.sh - Update spec tests to match new command signatures and line counts (100% coverage) Co-Authored-By: Claude Sonnet 4.6 --- .pre-commit-config.yaml | 2 +- README.md | 16 +++++---- build-gradle/action.yml | 5 +-- build-maven/action.yml | 26 ++++++++++++-- build-maven/build.sh | 2 +- build-maven/deploy-artifacts.sh | 11 +++--- build-npm/action.yml | 26 ++++++++++++-- build-npm/build.sh | 3 +- build-npm/mise.local.toml | 6 +++- build-poetry/action.yml | 24 +++++++++++-- build-poetry/build.sh | 8 +++-- build-poetry/mise.local.toml | 6 +++- build-yarn/action.yml | 25 ++++++++++++-- build-yarn/build.sh | 9 ++--- build-yarn/mise.local.toml | 6 +++- cache/action.yml | 2 +- config-npm/action.yml | 2 +- config-npm/mise.local.toml | 6 +++- config-npm/npm_config.sh | 2 +- mise.toml | 5 ++- promote/action.yml | 9 +++++ promote/mise.local.toml | 6 +++- promote/promote.sh | 14 ++++---- spec/build-maven_deploy-artifacts_spec.sh | 10 +++--- spec/build-npm_spec.sh | 2 +- spec/build-poetry_spec.sh | 42 ++++++++++++----------- spec/build-yarn_spec.sh | 21 ++++++------ spec/config-npm_spec.sh | 4 +-- spec/promote_spec.sh | 8 ++--- 29 files changed, 216 insertions(+), 92 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a885a572..def65c16 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: hooks: - id: markdownlint - repo: https://github.com/renovatebot/pre-commit-hooks - rev: 731b86757c909f5eb4753ce1e743c64bd18f5ea8 # 37.418.1 + rev: 99eaa5b893df4f917fe21b5705cc42f28cb3d842 # 43.76.3 hooks: - id: renovate-config-validator - repo: https://github.com/rhysd/actionlint diff --git a/README.md b/README.md index 3a52dc36..67b95939 100644 --- a/README.md +++ b/README.md @@ -1227,13 +1227,15 @@ promote: ### Inputs -| Input | Description | Default | -|---------------------------|---------------------------------------------------------------------------------------------------------------------------|---------------------| -| `promote-pull-request` | Whether to promote pull request artifacts. Requires `deploy-pull-request` input to be set to `true` in the build action | `false` | -| `multi-repo` | If true, promotes to public and private repositories. For projects with both public and private artifacts | (optional) | -| `artifactory-deploy-repo` | Repository to deploy to. If not set, it will be retrieved from the build info | (optional) | -| `artifactory-target-repo` | Target repository for the promotion. If not set, it will be determined based on the branch type and the deploy repository | (optional) | -| `build-name` | Name of the JFrog build to promote. | `` | +| Input | Description | Default | +|---------------------------|---------------------------------------------------------------------------------------------------------------------------|--------------------------| +| `repox-url` | URL for Repox | `https://repox.jfrog.io` | +| `repox-artifactory-url` | URL for Repox Artifactory API (overrides repox-url/artifactory if provided) | (optional) | +| `promote-pull-request` | Whether to promote pull request artifacts. Requires `deploy-pull-request` input to be set to `true` in the build action | `false` | +| `multi-repo` | If true, promotes to public and private repositories. For projects with both public and private artifacts | (optional) | +| `artifactory-deploy-repo` | Repository to deploy to. If not set, it will be retrieved from the build info | (optional) | +| `artifactory-target-repo` | Target repository for the promotion. If not set, it will be determined based on the branch type and the deploy repository | (optional) | +| `build-name` | Name of the JFrog build to promote. | `` | ### Outputs diff --git a/build-gradle/action.yml b/build-gradle/action.yml index b1ea809a..4b40e05b 100644 --- a/build-gradle/action.yml +++ b/build-gradle/action.yml @@ -121,6 +121,7 @@ runs: (github.event.repository.visibility == 'public' && 'public-deployer' || 'qa-deployer') }} run: | echo "ARTIFACTORY_DEPLOYER_ROLE=${ARTIFACTORY_DEPLOYER_ROLE}" >> "$GITHUB_ENV" + - uses: SonarSource/vault-action-wrapper@3d5c87cb535e4a2c7a09adcbcfdefa751854dee3 # 3.3.0 id: secrets with: @@ -199,7 +200,7 @@ runs: shell: bash run: | build_name="${GITHUB_REPOSITORY#*/}" - echo "## 🏗️ Gradle Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY + echo "## 🏗 Gradle Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY if [[ "${{ steps.build.conclusion }}" == "success" ]]; then echo "✅ **Build SUCCESS**" >> $GITHUB_STEP_SUMMARY else @@ -215,5 +216,5 @@ runs: if [[ "${{ steps.build.outputs.deployed }}" == true ]]; then echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" - echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY + echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY fi diff --git a/build-maven/action.yml b/build-maven/action.yml index c4a4d32c..cb23b41a 100644 --- a/build-maven/action.yml +++ b/build-maven/action.yml @@ -212,6 +212,7 @@ runs: ARTIFACTORY_PRIVATE_DEPLOY_REPO: ${{ steps.params.outputs.ARTIFACTORY_PRIVATE_DEPLOY_REPO }} ARTIFACTORY_PRIVATE_DEPLOY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_PRIVATE_DEPLOY_ACCESS_TOKEN }} INSTALLED_ARTIFACTS: ${{ steps.build.outputs.installed-artifacts }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary run: $ACTION_PATH_BUILD_MAVEN/deploy-artifacts.sh - name: Cleanup Maven repository before caching @@ -235,9 +236,13 @@ runs: - name: Generate workflow summary if: always() && inputs.generate-summary != 'false' shell: bash + env: + ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || + format('{0}/artifactory', inputs.repox-url) }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary run: | build_name="${GITHUB_REPOSITORY#*/}" - echo "## 🏗️ Maven Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY + echo "## 🏗 Maven Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY if [[ "${{ steps.build.conclusion }}" == "success" ]]; then echo "✅ **Build SUCCESS**" >> $GITHUB_STEP_SUMMARY else @@ -253,5 +258,22 @@ runs: if [[ "${{ steps.build.outputs.deployed }}" == true ]]; then echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" - echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY + echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY + jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + if [[ -d "$jf_summary_dir" ]]; then + jf config use deploy + jf generate-summary-markdown + if [[ -f "${jf_summary_dir}/markdown.md" ]]; then + { + echo "" + echo "
" + echo "Published Modules" + echo "" + grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' + echo "" + awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,"
"){p=0}' "${jf_summary_dir}/markdown.md" + echo "" + } >> "$GITHUB_STEP_SUMMARY" + fi + fi fi diff --git a/build-maven/build.sh b/build-maven/build.sh index 614bb89b..0f2f70a7 100755 --- a/build-maven/build.sh +++ b/build-maven/build.sh @@ -12,7 +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. -# - ARTIFACTORY_URL: Artifactory repository URL +# - ARTIFACTORY_URL: URL to Artifactory repository # - ARTIFACTORY_ACCESS_TOKEN: Access token to read Repox repositories # - ARTIFACTORY_DEPLOY_REPO: Deployment repository name. Required by maven-enforcer-plugin in SonarSource parent POM. # - ARTIFACTORY_DEPLOY_USERNAME: Username used by artifactory-maven-plugin diff --git a/build-maven/deploy-artifacts.sh b/build-maven/deploy-artifacts.sh index e4faa321..c39de774 100755 --- a/build-maven/deploy-artifacts.sh +++ b/build-maven/deploy-artifacts.sh @@ -32,22 +32,23 @@ build_name="${GITHUB_REPOSITORY#*/}" pushd "$MAVEN_CONFIG/repository" echo "::group::Configure JFrog deployment" -jfrog config add deploy --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" -jfrog config use deploy +jf config remove deploy > /dev/null 2>&1 || true # Ignore inexistent configuration +jf config add deploy --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" +jf config use deploy echo "::endgroup::" echo "::group::Deploy public artifacts" echo "Deploying public artifacts..." for artifact in "${public_artifacts[@]}"; do - jfrog rt u --build-name "$build_name" --build-number "$BUILD_NUMBER" "$artifact" "${ARTIFACTORY_DEPLOY_REPO}" + jf rt u --build-name "$build_name" --build-number "$BUILD_NUMBER" "$artifact" "${ARTIFACTORY_DEPLOY_REPO}" done echo "::endgroup::" echo "::group::Deploy private artifacts" echo "Deploying private artifacts..." -jfrog config edit deploy --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_PRIVATE_DEPLOY_ACCESS_TOKEN" +jf config edit deploy --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_PRIVATE_DEPLOY_ACCESS_TOKEN" for artifact in "${private_artifacts[@]}"; do - jfrog rt u --build-name "$build_name" --build-number "$BUILD_NUMBER" "$artifact" "${ARTIFACTORY_PRIVATE_DEPLOY_REPO}" + jf rt u --build-name "$build_name" --build-number "$BUILD_NUMBER" "$artifact" "${ARTIFACTORY_PRIVATE_DEPLOY_REPO}" done echo "::endgroup::" diff --git a/build-npm/action.yml b/build-npm/action.yml index 9ba4fd41..e809e337 100644 --- a/build-npm/action.yml +++ b/build-npm/action.yml @@ -110,7 +110,7 @@ runs: echo "ARTIFACTORY_DEPLOYER_ROLE=${ARTIFACTORY_DEPLOYER_ROLE}" >> "$GITHUB_ENV" cp "$ACTION_PATH_BUILD_NPM/mise.local.toml" mise.local.toml if [[ "$CACHE_NPM" != "true" ]]; then - echo "::warning::The \`cache-npm\` input is deprecated and will be removed in future releases. " \ + echo "::warning::The \`cache-npm\` input is deprecated and will be removed in future releases." \ "Use \`disable-caching\` instead." >&2 fi @@ -168,6 +168,8 @@ runs: SQC_EU_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).SQC_EU_TOKEN }} SQC_US_URL: ${{ fromJSON(steps.secrets.outputs.vault).SQC_US_URL }} SQC_US_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).SQC_US_TOKEN }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary + # JFROG_CLI_GITHUB_TOKEN: working-directory: ${{ inputs.working-directory }} run: $ACTION_PATH_BUILD_NPM/build.sh @@ -197,9 +199,10 @@ runs: env: ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || format('{0}/artifactory', inputs.repox-url) }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary run: | build_name="${GITHUB_REPOSITORY#*/}" - echo "## 📦 NPM Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY + echo "## 🏗 NPM Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY if [[ "${{ steps.build.conclusion }}" == "success" ]]; then echo "✅ **Build SUCCESS**" >> $GITHUB_STEP_SUMMARY else @@ -215,5 +218,22 @@ runs: if [[ "${{ steps.build.outputs.deployed }}" == true ]]; then echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" - echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY + echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY + jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + if [[ -d "$jf_summary_dir" ]]; then + jf config use repox + jf generate-summary-markdown + if [[ -f "${jf_summary_dir}/markdown.md" ]]; then + { + echo "" + echo "
" + echo "Published Modules" + echo "" + grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' + echo "" + awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" + echo "
" + } >> "$GITHUB_STEP_SUMMARY" + fi + fi fi diff --git a/build-npm/build.sh b/build-npm/build.sh index a8e1d091..12680b28 100755 --- a/build-npm/build.sh +++ b/build-npm/build.sh @@ -100,7 +100,8 @@ sonar_scanner_implementation() { jfrog_npm_publish() { echo "Configuring JFrog and NPM repositories..." jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" + jf config use repox jf npm-config --repo-resolve "npm" --repo-deploy "$ARTIFACTORY_DEPLOY_REPO" export PROJECT="${GITHUB_REPOSITORY#*/}" diff --git a/build-npm/mise.local.toml b/build-npm/mise.local.toml index 255706ed..c942c6d3 100644 --- a/build-npm/mise.local.toml +++ b/build-npm/mise.local.toml @@ -1,3 +1,7 @@ [tools] -jfrog-cli = "2.77.0" +jfrog-cli = "2.96.0" jq = "1.8.1" + +[env] +JFROG_CLI_AVOID_NEW_VERSION_WARNING = "true" +JFROG_CLI_ENV_EXCLUDE = "*password*;*secret*;*key*;*token*;*auth*;*credential*" diff --git a/build-poetry/action.yml b/build-poetry/action.yml index 8ebc7f8b..e9ce2f5b 100644 --- a/build-poetry/action.yml +++ b/build-poetry/action.yml @@ -105,6 +105,7 @@ runs: echo "ARTIFACTORY_READER_ROLE=${ARTIFACTORY_READER_ROLE}" >> "$GITHUB_ENV" echo "ARTIFACTORY_DEPLOYER_ROLE=${ARTIFACTORY_DEPLOYER_ROLE}" >> "$GITHUB_ENV" cp "$ACTION_PATH_BUILD_POETRY/mise.local.toml" mise.local.toml + - uses: ./.actions/get-build-number id: get_build_number with: @@ -164,6 +165,7 @@ runs: SQC_US_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).SQC_US_TOKEN }} SONAR_PLATFORM: ${{ inputs.sonar-platform }} RUN_SHADOW_SCANS: ${{ inputs.run-shadow-scans }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary run: | cd "${{ inputs.working-directory }}" "$ACTION_PATH_BUILD_POETRY/build.sh" @@ -186,9 +188,10 @@ runs: env: ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || format('{0}/artifactory', inputs.repox-url) }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary run: | build_name="${GITHUB_REPOSITORY#*/}" - echo "## 📦 Poetry Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY + echo "## 🏗 Poetry Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY if [[ "${{ steps.build.conclusion }}" == "success" ]]; then echo "✅ **Build SUCCESS**" >> $GITHUB_STEP_SUMMARY else @@ -204,5 +207,22 @@ runs: if [[ "${{ steps.build.outputs.deployed }}" == true ]]; then echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" - echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY + echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY + jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + if [[ -d "$jf_summary_dir" ]]; then + jf config use repox + jf generate-summary-markdown + if [[ -f "${jf_summary_dir}/markdown.md" ]]; then + { + echo "" + echo "
" + echo "Published Modules" + echo "" + grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' + echo "" + awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" + echo "
" + } >> "$GITHUB_STEP_SUMMARY" + fi + fi fi diff --git a/build-poetry/build.sh b/build-poetry/build.sh index a922d618..04bfc879 100755 --- a/build-poetry/build.sh +++ b/build-poetry/build.sh @@ -263,14 +263,16 @@ get_build_config() { } jfrog_poetry_install() { - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" + jf config use repox jf poetry-config --server-id-resolve repox --repo-resolve "$ARTIFACTORY_PYPI_REPO" jf poetry install --build-name="$PROJECT" --build-number="$BUILD_NUMBER" } jfrog_poetry_publish() { - jf config remove repox - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" + jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" + jf config use repox project_name=$(poetry version | awk '{print $1}') pushd dist jf rt upload ./ "$ARTIFACTORY_DEPLOY_REPO/$project_name/$PROJECT_VERSION/" --module="$project_name:$PROJECT_VERSION" \ diff --git a/build-poetry/mise.local.toml b/build-poetry/mise.local.toml index 2b1cde01..7c5a49cc 100644 --- a/build-poetry/mise.local.toml +++ b/build-poetry/mise.local.toml @@ -1,2 +1,6 @@ [tools] -jfrog-cli = "2.77.0" +jfrog-cli = "2.96.0" + +[env] +JFROG_CLI_AVOID_NEW_VERSION_WARNING = "true" +JFROG_CLI_ENV_EXCLUDE = "*password*;*secret*;*key*;*token*;*auth*;*credential*" diff --git a/build-yarn/action.yml b/build-yarn/action.yml index 5367b14b..34e5ddf8 100644 --- a/build-yarn/action.yml +++ b/build-yarn/action.yml @@ -112,7 +112,7 @@ runs: echo "ARTIFACTORY_DEPLOYER_ROLE=${ARTIFACTORY_DEPLOYER_ROLE}" >> "$GITHUB_ENV" cp "$ACTION_PATH_BUILD_YARN/mise.local.toml" mise.local.toml if [[ "$CACHE_YARN" != "true" ]]; then - echo "::warning::The \`cache-yarn\` input is deprecated and will be removed in future releases. " \ + echo "::warning::The \`cache-yarn\` input is deprecated and will be removed in future releases." \ "Use \`disable-caching\` instead." >&2 fi @@ -175,6 +175,7 @@ runs: SQC_US_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).SQC_US_TOKEN }} SONAR_PLATFORM: ${{ inputs.sonar-platform }} RUN_SHADOW_SCANS: ${{ inputs.run-shadow-scans }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary working-directory: ${{ inputs.working-directory }} run: $ACTION_PATH_BUILD_YARN/build.sh @@ -196,9 +197,10 @@ runs: env: ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || format('{0}/artifactory', inputs.repox-url) }} + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary run: | build_name="${GITHUB_REPOSITORY#*/}" - echo "## 📦 Yarn Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY + echo "## 🏗 Yarn Build Summary (\`${GITHUB_JOB}\`)" >> $GITHUB_STEP_SUMMARY if [[ "${{ steps.build.conclusion }}" == "success" ]]; then echo "✅ **Build SUCCESS**" >> $GITHUB_STEP_SUMMARY else @@ -214,5 +216,22 @@ runs: if [[ "${{ steps.build.outputs.deployed }}" == true ]]; then echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" - echo "🔗 **[Browse artifacts in Artifactory](${ARTIFACTORY_BROWSE_URL})**" >> $GITHUB_STEP_SUMMARY + echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY + jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + if [[ -d "$jf_summary_dir" ]]; then + jf config use repox + jf generate-summary-markdown + if [[ -f "${jf_summary_dir}/markdown.md" ]]; then + { + echo "" + echo "
" + echo "Published Modules" + echo "" + grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' + echo "" + awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" + echo "
" + } >> "$GITHUB_STEP_SUMMARY" + fi + fi fi diff --git a/build-yarn/build.sh b/build-yarn/build.sh index 9ae46bcf..7b521416 100755 --- a/build-yarn/build.sh +++ b/build-yarn/build.sh @@ -103,8 +103,8 @@ npmRegistries: npmAlwaysAuth: true npmAuthToken: "${ARTIFACTORY_ACCESS_TOKEN}" EOF - jf config remove repox > /dev/null 2>&1 || true # Do not log if the repox config were not present - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" + jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" jf config use repox jf npm-config --repo-resolve "npm" } @@ -172,8 +172,9 @@ sonar_scanner_implementation() { jfrog_yarn_publish() { echo "::debug::Configuring JFrog and NPM repositories..." - jf config remove repox > /dev/null 2>&1 || true # Do not log if the repox config were not present - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" + jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_DEPLOY_ACCESS_TOKEN" + jf config use repox jf npm-config --repo-resolve "npm" --repo-deploy "$ARTIFACTORY_DEPLOY_REPO" # Create a local tarball and preserve it for attestation diff --git a/build-yarn/mise.local.toml b/build-yarn/mise.local.toml index 255706ed..c942c6d3 100644 --- a/build-yarn/mise.local.toml +++ b/build-yarn/mise.local.toml @@ -1,3 +1,7 @@ [tools] -jfrog-cli = "2.77.0" +jfrog-cli = "2.96.0" jq = "1.8.1" + +[env] +JFROG_CLI_AVOID_NEW_VERSION_WARNING = "true" +JFROG_CLI_ENV_EXCLUDE = "*password*;*secret*;*key*;*token*;*auth*;*credential*" diff --git a/cache/action.yml b/cache/action.yml index d9ebc028..8685c992 100644 --- a/cache/action.yml +++ b/cache/action.yml @@ -33,7 +33,7 @@ runs: - id: warning shell: bash run: | - echo "::warning:: This action is deprecated and will be removed in future releases. " \ + echo "::warning:: This action is deprecated and will be removed in future releases." \ "Please migrate to using the SonarSource/gh-action_cache action directly." >&2 - uses: SonarSource/gh-action_cache@957cb1f6f70956976b834546bf09839080b5bb00 # v1.2.3 diff --git a/config-npm/action.yml b/config-npm/action.yml index f6307c7d..06336838 100644 --- a/config-npm/action.yml +++ b/config-npm/action.yml @@ -83,7 +83,7 @@ runs: echo "ARTIFACTORY_READER_ROLE=${ARTIFACTORY_READER_ROLE}" >> "$GITHUB_ENV" if [[ "$CACHE_NPM" != "true" ]]; then - echo "::warning::The \`cache-npm\` input is deprecated and will be removed in future releases. " \ + echo "::warning::The \`cache-npm\` input is deprecated and will be removed in future releases." \ "Use \`disable-caching\` instead." >&2 fi diff --git a/config-npm/mise.local.toml b/config-npm/mise.local.toml index 255706ed..c942c6d3 100644 --- a/config-npm/mise.local.toml +++ b/config-npm/mise.local.toml @@ -1,3 +1,7 @@ [tools] -jfrog-cli = "2.77.0" +jfrog-cli = "2.96.0" jq = "1.8.1" + +[env] +JFROG_CLI_AVOID_NEW_VERSION_WARNING = "true" +JFROG_CLI_ENV_EXCLUDE = "*password*;*secret*;*key*;*token*;*auth*;*credential*" diff --git a/config-npm/npm_config.sh b/config-npm/npm_config.sh index b06df30e..dc66d4ba 100755 --- a/config-npm/npm_config.sh +++ b/config-npm/npm_config.sh @@ -19,7 +19,7 @@ registry=${ARTIFACTORY_URL}/api/npm/npm ${ARTIFACTORY_URL#https:}/api/npm/:_authToken=${ARTIFACTORY_ACCESS_TOKEN} EOF jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" jf config use repox jf npm-config --repo-resolve "npm" return 0 diff --git a/mise.toml b/mise.toml index 2250405f..e87554e0 100644 --- a/mise.toml +++ b/mise.toml @@ -2,5 +2,8 @@ pre-commit = "4.2.0" shellcheck = "0.10.0" shellspec = "0.28.1" -jfrog-cli = "2.77.0" +jfrog-cli = "2.96.0" "npm:markdownlint-cli" = "0.39.0" + +[env] +JFROG_CLI_ENV_EXCLUDE = "*password*;*secret*;*key*;*token*;*auth*;*credential*" diff --git a/promote/action.yml b/promote/action.yml index 72659e19..586ac239 100644 --- a/promote/action.yml +++ b/promote/action.yml @@ -2,6 +2,12 @@ name: Promote description: GitHub Action to promote a project inputs: + repox-url: + description: URL for Repox + default: https://repox.jfrog.io + repox-artifactory-url: + description: URL for Repox Artifactory API (overrides repox-url/artifactory if provided) + default: '' promote-pull-request: description: Whether to promote pull request artifacts. Requires `deploy-pull-request` input to be set to `true` in the build action. default: 'false' @@ -41,6 +47,7 @@ runs: shell: bash run: | cp "$ACTION_PATH_PROMOTE/mise.local.toml" mise.local.toml + - uses: ./.actions/get-build-number with: host-actions-root: ${{ steps.set-path.outputs.host_actions_root }} @@ -56,6 +63,8 @@ runs: - name: Promote artifacts shell: bash env: + ARTIFACTORY_URL: ${{ inputs.repox-artifactory-url != '' && inputs.repox-artifactory-url || + format('{0}/artifactory', inputs.repox-url) }} ARTIFACTORY_PROMOTE_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_PROMOTE_ACCESS_TOKEN }} GITHUB_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} diff --git a/promote/mise.local.toml b/promote/mise.local.toml index 2b1cde01..7c5a49cc 100644 --- a/promote/mise.local.toml +++ b/promote/mise.local.toml @@ -1,2 +1,6 @@ [tools] -jfrog-cli = "2.77.0" +jfrog-cli = "2.96.0" + +[env] +JFROG_CLI_AVOID_NEW_VERSION_WARNING = "true" +JFROG_CLI_ENV_EXCLUDE = "*password*;*secret*;*key*;*token*;*auth*;*credential*" diff --git a/promote/promote.sh b/promote/promote.sh index d54fa093..fbdf9df4 100755 --- a/promote/promote.sh +++ b/promote/promote.sh @@ -2,6 +2,7 @@ # Regular way to promote a project build: JFrog Artifactory build promotion, and GitHub status check update # # Required environment variables (must be explicitly provided): +# - ARTIFACTORY_URL: URL to Artifactory repository # - ARTIFACTORY_PROMOTE_ACCESS_TOKEN: Access token to promote builds # - BUILD_NUMBER: Build number (e.g. 42) # - BUILD_NAME: Name of the JFrog Artifactory build (e.g. sonar-dummy) @@ -16,7 +17,6 @@ # - GITHUB_JOB: The job_id of the current job, used for generating workflow summary # # Optional user customization: -# - ARTIFACTORY_URL: Repox URL. # - DEFAULT_BRANCH: Default branch (e.g. main), defaults to the repository configuration # - MULTI_REPO_PROMOTE: If true, promotes to multiple repositories (default: false) # - ARTIFACTORY_DEPLOY_REPO: Repository to deploy to. If not set, it will be retrieved from the build info. @@ -34,7 +34,7 @@ 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:?}" "${BUILD_NAME:?}" +: "${ARTIFACTORY_URL:?}" "${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:?}" : "${MULTI_REPO_PROMOTE:=false}" "${ARTIFACTORY_DEPLOY_REPO:=}" "${ARTIFACTORY_TARGET_REPO:=}" "${PROMOTE_PULL_REQUEST:=false}" @@ -68,8 +68,9 @@ check_branch() { } jfrog_config_repox() { - jf config remove repox - jf config add repox --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_PROMOTE_ACCESS_TOKEN" + jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration + jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_PROMOTE_ACCESS_TOKEN" + jf config use repox } get_target_repos() { @@ -185,7 +186,6 @@ jfrog_promote() { generate_workflow_summary() { local build_url="${ARTIFACTORY_URL%/*}/ui/builds/${BUILD_NAME}/${BUILD_NUMBER}/" - cat >> "$GITHUB_STEP_SUMMARY" <" - The line 30 should equal "jf poetry install --build-name=my-repo --build-number=42" - The line 31 should equal "::endgroup::" - The line 32 should equal "::group::Build project" - The line 34 should equal "poetry build" - The line 35 should equal "::endgroup::" - The line 36 should equal "=== Build completed successfully ===" + The line 28 should equal "jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token dummy access token" + The line 29 should equal "jf config use repox" + The line 30 should equal "jf poetry-config --server-id-resolve repox --repo-resolve " + The line 31 should equal "jf poetry install --build-name=my-repo --build-number=42" + The line 32 should equal "::endgroup::" + The line 33 should equal "::group::Build project" + The line 35 should equal "poetry build" + The line 36 should equal "::endgroup::" + The line 37 should equal "=== Build completed successfully ===" End End @@ -304,8 +305,9 @@ Describe 'jfrog_poetry_install()' It 'installs Poetry dependencies using JFrog CLI' When call jfrog_poetry_install The line 1 should include "jf config add repox" - The line 2 should include "jf poetry-config" - The line 3 should include "jf poetry install" + The line 2 should include "jf config use repox" + The line 3 should include "jf poetry-config" + The line 4 should include "jf poetry install" End End @@ -360,8 +362,8 @@ Describe 'build_poetry()' The line 21 should equal 'poetry run pysonar -Dsonar.host.url=https://next.sonarqube.com -Dsonar.token=next-token -Dsonar.analysis.buildNumber=42 -Dsonar.analysis.pipeline=dummy-run-id -Dsonar.analysis.repository=my-org/my-repo' The line 22 should equal '::endgroup::' The line 23 should equal '::group::Publish to Artifactory' - The line 24 should equal 'jf config remove repox' - The line 25 should equal 'jf config add repox --artifactory-url https://dummy.repox --access-token ' + The line 24 should equal 'jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token ' + The line 25 should equal 'jf config use repox' The line 26 should include '/dist' The line 27 should equal 'jf rt upload ./ /poetry/1.0.0.42/ --module=poetry:1.0.0.42 --build-name=my-repo --build-number=42' The line 29 should equal 'jf rt build-collect-env my-repo 42' @@ -435,8 +437,8 @@ Describe 'build_poetry()' The line 22 should equal 'poetry run pysonar -Dsonar.host.url=https://next.sonarqube.com -Dsonar.token=next-token -Dsonar.analysis.buildNumber=42 -Dsonar.analysis.pipeline=dummy-run-id -Dsonar.analysis.repository=my-org/my-repo -Dsonar.analysis.prNumber=123' The line 23 should equal '::endgroup::' The line 24 should equal "::group::Publish to Artifactory" - The line 25 should equal "jf config remove repox" - The line 26 should equal "jf config add repox --artifactory-url https://dummy.repox --access-token " + The line 25 should equal "jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token " + The line 26 should equal "jf config use repox" The line 27 should include "/dist" The line 28 should equal "jf rt upload ./ /poetry/1.0.0.42/ --module=poetry:1.0.0.42 --build-name=my-repo --build-number=42" The line 30 should equal "jf rt build-collect-env my-repo 42" @@ -576,8 +578,8 @@ Describe 'build_poetry()' The line 15 should equal 'run_sonar_analysis()' The line 16 should equal "=== Sonar platform set to 'none'. Skipping Sonar analysis." The line 17 should equal '::group::Publish to Artifactory' - The line 18 should equal 'jf config remove repox' - The line 19 should equal 'jf config add repox --artifactory-url https://dummy.repox --access-token ' + The line 18 should equal 'jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token ' + The line 19 should equal 'jf config use repox' The line 20 should include '/dist' The line 21 should equal 'jf rt upload ./ /poetry/1.0.0.42/ --module=poetry:1.0.0.42 --build-name=my-repo --build-number=42' The line 23 should equal 'jf rt build-collect-env my-repo 42' @@ -612,7 +614,7 @@ Describe 'build_poetry()' fi End Mock jf - echo "jf version 2.77.0" + echo "jf version 2.96.0" End Mock git case "$*" in @@ -627,7 +629,7 @@ Describe 'build_poetry()' The output should include "jq-1.8.1" The output should include "Python 3.11.0" The output should include "Poetry (version 1.8.0)" - The output should include "jf version 2.77.0" + The output should include "jf version 2.96.0" The output should include "=== Build completed successfully ===" End @@ -647,7 +649,7 @@ Describe 'build_poetry()' fi End Mock jf - echo "jf version 2.77.0" + echo "jf version 2.96.0" End Mock git case "$*" in diff --git a/spec/build-yarn_spec.sh b/spec/build-yarn_spec.sh index 7e48d7ed..f945b126 100755 --- a/spec/build-yarn_spec.sh +++ b/spec/build-yarn_spec.sh @@ -13,7 +13,7 @@ End Mock jf case "$*" in - "--version") echo "jf version 2.77.0" ;; + "--version") echo "jf version 2.96.0" ;; "rt build-publish test-project 42") echo '{"buildInfoUiUrl": "https://repox.jfrog.io/ui/builds/test-project/42/123456/published"}' ;; *) echo "jf $*" ;; esac @@ -258,17 +258,18 @@ Describe 'build-yarn/build.sh' export PROJECT="test" When call jfrog_yarn_publish The status should be success - The lines of output should equal 10 + The lines of output should equal 11 The line 1 should include "Configuring JFrog" The line 2 should include "jf config" - The line 3 should include "jf npm-config" - The line 4 should include "Creating local tarball for attestation" - The line 5 should include "yarn pack" - The line 6 should include "Publishing Yarn package" - The line 7 should include "jf npm publish" - The line 8 should include "jf rt build-collect-env" - The line 9 should include "Publishing build info" - The line 10 should include "jf rt build-publish" + The line 3 should include "jf config use repox" + The line 4 should include "jf npm-config" + The line 5 should include "Creating local tarball for attestation" + The line 6 should include "yarn pack" + The line 7 should include "Publishing Yarn package" + The line 8 should include "jf npm publish" + The line 9 should include "jf rt build-collect-env" + The line 10 should include "Publishing build info" + The line 11 should include "jf rt build-publish" End End diff --git a/spec/config-npm_spec.sh b/spec/config-npm_spec.sh index 8fd4c444..00b32ae8 100755 --- a/spec/config-npm_spec.sh +++ b/spec/config-npm_spec.sh @@ -18,7 +18,7 @@ End Mock jf if [[ "$*" == "--version" ]]; then - echo "jf version 2.77.0" + echo "jf version 2.96.0" else echo "jf $*" fi @@ -98,7 +98,7 @@ Describe 'set_build_env()' The contents of file "$HOME/.npmrc" should include "registry=https://repox.jfrog.io/artifactory/api/npm/npm" The contents of file "$HOME/.npmrc" should include "//repox.jfrog.io/artifactory/api/npm/:_authToken=reader-token" The line 1 should include "Configuring JFrog and NPM repositories" - The line 2 should equal "jf config add repox --artifactory-url https://repox.jfrog.io/artifactory --access-token reader-token" + The line 2 should equal "jf config add repox --url https://repox.jfrog.io/artifactory --artifactory-url https://repox.jfrog.io/artifactory --access-token reader-token" The line 3 should equal "jf config use repox" The line 4 should equal "jf npm-config --repo-resolve npm" End diff --git a/spec/promote_spec.sh b/spec/promote_spec.sh index 09344d2d..ea76728f 100755 --- a/spec/promote_spec.sh +++ b/spec/promote_spec.sh @@ -107,8 +107,8 @@ Describe 'promote/promote.sh' The line 7 should include "jf" The line 8 should equal "::endgroup::" The line 9 should equal "::group::Configure promotion" - The line 10 should equal "jf config remove repox" - The line 11 should equal "jf config add repox --artifactory-url https://dummy.repox --access-token dummy promote token" + The line 10 should equal "jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token dummy promote token" + The line 11 should equal "jf config use repox" The line 12 should equal "::endgroup::" The line 13 should equal "::group::Promote build artifacts" The line 14 should equal "Promoting build dummy-project/$BUILD_NUMBER (version: 1.2.3.42)" @@ -181,8 +181,8 @@ End Describe 'jfrog_config_repox()' It 'configures Repox using JFrog CLI' When call jfrog_config_repox - The line 1 should equal "jf config remove repox" - The line 2 should start with "jf config add repox" + The line 1 should equal "jf config add repox --url https://dummy.repox --artifactory-url https://dummy.repox --access-token dummy promote token" + The line 2 should equal "jf config use repox" End End From cf1efac1f22a1ee4559a174971731e739b29e1bb Mon Sep 17 00:00:00 2001 From: Julien Carsique Date: Thu, 19 Mar 2026 09:54:35 +0100 Subject: [PATCH 2/2] BUILD-10591 Extract JFrog CLI summary into shared/generate-jfrog-summary.sh Deduplicate the 16-line JFrog CLI summary extraction block that was copy-pasted verbatim across build-npm, build-yarn, build-poetry, and build-maven action.yml files. - Add shared/generate-jfrog-summary.sh accepting as $1 - Replace each inline block with "$ACTION_PATH_SHARED/generate-jfrog-summary.sh" repox|deploy - Add spec/shared_generate-jfrog-summary_spec.sh with 9 test cases - Fix config-npm spec: --url strips /artifactory suffix (${ARTIFACTORY_URL%/artifactory*}) Co-Authored-By: Claude Sonnet 4.6 --- build-maven/action.yml | 18 +--- build-npm/action.yml | 18 +--- build-poetry/action.yml | 18 +--- build-poetry/build.sh | 1 + build-yarn/action.yml | 18 +--- shared/generate-jfrog-summary.sh | 30 ++++++ spec/config-npm_spec.sh | 2 +- spec/shared_generate-jfrog-summary_spec.sh | 111 +++++++++++++++++++++ 8 files changed, 147 insertions(+), 69 deletions(-) create mode 100755 shared/generate-jfrog-summary.sh create mode 100644 spec/shared_generate-jfrog-summary_spec.sh diff --git a/build-maven/action.yml b/build-maven/action.yml index cb23b41a..c81fd848 100644 --- a/build-maven/action.yml +++ b/build-maven/action.yml @@ -259,21 +259,5 @@ runs: echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY - jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" - if [[ -d "$jf_summary_dir" ]]; then - jf config use deploy - jf generate-summary-markdown - if [[ -f "${jf_summary_dir}/markdown.md" ]]; then - { - echo "" - echo "
" - echo "Published Modules" - echo "" - grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' - echo "" - awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" - echo "
" - } >> "$GITHUB_STEP_SUMMARY" - fi - fi + "$ACTION_PATH_BUILD_MAVEN/../shared/generate-jfrog-summary.sh" deploy fi diff --git a/build-npm/action.yml b/build-npm/action.yml index e809e337..532c22a4 100644 --- a/build-npm/action.yml +++ b/build-npm/action.yml @@ -219,21 +219,5 @@ runs: echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY - jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" - if [[ -d "$jf_summary_dir" ]]; then - jf config use repox - jf generate-summary-markdown - if [[ -f "${jf_summary_dir}/markdown.md" ]]; then - { - echo "" - echo "
" - echo "Published Modules" - echo "" - grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' - echo "" - awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" - echo "
" - } >> "$GITHUB_STEP_SUMMARY" - fi - fi + "$ACTION_PATH_BUILD_NPM/../shared/generate-jfrog-summary.sh" repox fi diff --git a/build-poetry/action.yml b/build-poetry/action.yml index e9ce2f5b..8b3b2887 100644 --- a/build-poetry/action.yml +++ b/build-poetry/action.yml @@ -208,21 +208,5 @@ runs: echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY - jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" - if [[ -d "$jf_summary_dir" ]]; then - jf config use repox - jf generate-summary-markdown - if [[ -f "${jf_summary_dir}/markdown.md" ]]; then - { - echo "" - echo "
" - echo "Published Modules" - echo "" - grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' - echo "" - awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" - echo "
" - } >> "$GITHUB_STEP_SUMMARY" - fi - fi + "$ACTION_PATH_BUILD_POETRY/../shared/generate-jfrog-summary.sh" repox fi diff --git a/build-poetry/build.sh b/build-poetry/build.sh index 04bfc879..c7488545 100755 --- a/build-poetry/build.sh +++ b/build-poetry/build.sh @@ -263,6 +263,7 @@ get_build_config() { } jfrog_poetry_install() { + jf config remove repox > /dev/null 2>&1 || true # Ignore inexistent configuration jf config add repox --url "${ARTIFACTORY_URL%/artifactory*}" --artifactory-url "$ARTIFACTORY_URL" --access-token "$ARTIFACTORY_ACCESS_TOKEN" jf config use repox jf poetry-config --server-id-resolve repox --repo-resolve "$ARTIFACTORY_PYPI_REPO" diff --git a/build-yarn/action.yml b/build-yarn/action.yml index 34e5ddf8..33f30251 100644 --- a/build-yarn/action.yml +++ b/build-yarn/action.yml @@ -217,21 +217,5 @@ runs: echo "### 🚀 Deployment" >> $GITHUB_STEP_SUMMARY ARTIFACTORY_BROWSE_URL="${ARTIFACTORY_URL%/*}/ui/builds/$build_name/$BUILD_NUMBER" echo "🐸 [Browse build \`${build_name}:${BUILD_NUMBER}\` in Artifactory](${ARTIFACTORY_BROWSE_URL})" >> $GITHUB_STEP_SUMMARY - jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" - if [[ -d "$jf_summary_dir" ]]; then - jf config use repox - jf generate-summary-markdown - if [[ -f "${jf_summary_dir}/markdown.md" ]]; then - { - echo "" - echo "
" - echo "Published Modules" - echo "" - grep -E '^\*\*[^*]+\*\*$' "${jf_summary_dir}/markdown.md" | sed 's/^\*\*\(.*\)\*\*$/- `\1`/' - echo "" - awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" - echo "
" - } >> "$GITHUB_STEP_SUMMARY" - fi - fi + "$ACTION_PATH_BUILD_YARN/../shared/generate-jfrog-summary.sh" repox fi diff --git a/shared/generate-jfrog-summary.sh b/shared/generate-jfrog-summary.sh new file mode 100755 index 00000000..410f14f7 --- /dev/null +++ b/shared/generate-jfrog-summary.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Generate JFrog CLI build summary and append Published Modules to GitHub step summary. +# +# Usage: generate-jfrog-summary.sh +# Arguments: +# jf-server-id: JFrog CLI server ID to use (e.g. 'repox' or 'deploy') +# GitHub Actions auto-provided: +# JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: directory where JFrog CLI writes summary data +# GITHUB_STEP_SUMMARY: path to the GitHub step summary file + +set -euo pipefail + +: "${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR:?}" "${GITHUB_STEP_SUMMARY:?}" + +jf_server_id="${1:?Usage: generate-jfrog-summary.sh }" +jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + +if [[ -d "$jf_summary_dir" ]]; then + jf config use "$jf_server_id" + jf generate-summary-markdown || true + if [[ -f "${jf_summary_dir}/markdown.md" ]]; then + # shellcheck disable=SC2129 # individual redirects needed for kcov instrumentation + printf '\n
\nPublished Modules\n\n' >> "$GITHUB_STEP_SUMMARY" + # shellcheck disable=SC2016 # backticks in sed replacement are literal, not shell expansion + sed -n 's/^\*\*\([^*][^*]*\)\*\*$/- `\1`/p' "${jf_summary_dir}/markdown.md" >> "$GITHUB_STEP_SUMMARY" + printf '\n' >> "$GITHUB_STEP_SUMMARY" + awk 'index($0,"
") && !index($0,"
"){p=1} p{print} index($0,""){p=0}' "${jf_summary_dir}/markdown.md" >> "$GITHUB_STEP_SUMMARY" + echo "
" >> "$GITHUB_STEP_SUMMARY" + fi +fi diff --git a/spec/config-npm_spec.sh b/spec/config-npm_spec.sh index 00b32ae8..3d40b8ad 100755 --- a/spec/config-npm_spec.sh +++ b/spec/config-npm_spec.sh @@ -98,7 +98,7 @@ Describe 'set_build_env()' The contents of file "$HOME/.npmrc" should include "registry=https://repox.jfrog.io/artifactory/api/npm/npm" The contents of file "$HOME/.npmrc" should include "//repox.jfrog.io/artifactory/api/npm/:_authToken=reader-token" The line 1 should include "Configuring JFrog and NPM repositories" - The line 2 should equal "jf config add repox --url https://repox.jfrog.io/artifactory --artifactory-url https://repox.jfrog.io/artifactory --access-token reader-token" + The line 2 should equal "jf config add repox --url https://repox.jfrog.io --artifactory-url https://repox.jfrog.io/artifactory --access-token reader-token" The line 3 should equal "jf config use repox" The line 4 should equal "jf npm-config --repo-resolve npm" End diff --git a/spec/shared_generate-jfrog-summary_spec.sh b/spec/shared_generate-jfrog-summary_spec.sh new file mode 100644 index 00000000..631d95bb --- /dev/null +++ b/spec/shared_generate-jfrog-summary_spec.sh @@ -0,0 +1,111 @@ +#!/bin/bash +eval "$(shellspec - -c) exit 1" + +Mock jf + echo "jf $*" +End + +Describe 'shared/generate-jfrog-summary.sh' + setup() { + JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR=$(mktemp -d) + export JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR + GITHUB_STEP_SUMMARY=$(mktemp) + export GITHUB_STEP_SUMMARY + return 0 + } + cleanup() { + rm -rf "$JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR" + rm -f "$GITHUB_STEP_SUMMARY" + return 0 + } + BeforeEach 'setup' + AfterEach 'cleanup' + + It 'does nothing when summary directory does not exist' + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The output should equal "" + The contents of file "$GITHUB_STEP_SUMMARY" should equal "" + End + + It 'does nothing when markdown.md is absent' + mkdir -p "${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The line 1 should equal "jf config use repox" + The line 2 should equal "jf generate-summary-markdown" + The contents of file "$GITHUB_STEP_SUMMARY" should equal "" + End + + It 'fails when server-id argument is missing' + When run script shared/generate-jfrog-summary.sh + The status should not be success + The stderr should include "Usage: generate-jfrog-summary.sh" + End + + Describe 'with markdown.md' + setup_markdown() { + jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + mkdir -p "$jf_summary_dir" + cat > "${jf_summary_dir}/markdown.md" <<'EOF' +**sonarsource:my-lib:1.0.0** +link +
📦 my-repo-qa
+└── 📁 my-lib
+    └── 📄 my-lib-1.0.0.jar
+
+EOF + return 0 + } + Before 'setup_markdown' + + It 'uses the given server ID' + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The line 1 should equal "jf config use repox" + The line 2 should equal "jf generate-summary-markdown" + End + + It 'uses deploy server ID when specified' + When run script shared/generate-jfrog-summary.sh deploy + The status should be success + The line 1 should equal "jf config use deploy" + End + + It 'appends Published Modules details block to GITHUB_STEP_SUMMARY' + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The line 1 should equal "jf config use repox" + The line 2 should equal "jf generate-summary-markdown" + The contents of file "$GITHUB_STEP_SUMMARY" should include "
" + The contents of file "$GITHUB_STEP_SUMMARY" should include "Published Modules" + The contents of file "$GITHUB_STEP_SUMMARY" should include "
" + End + + It 'extracts bold module names as backtick list items' + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The line 1 should equal "jf config use repox" + The contents of file "$GITHUB_STEP_SUMMARY" should include "- \`sonarsource:my-lib:1.0.0\`" + End + + It 'extracts multi-line pre blocks' + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The line 1 should equal "jf config use repox" + The contents of file "$GITHUB_STEP_SUMMARY" should include "
"
+      The contents of file "$GITHUB_STEP_SUMMARY" should include "my-lib-1.0.0.jar"
+      The contents of file "$GITHUB_STEP_SUMMARY" should include "
" + End + + It 'skips inline pre tags' + jf_summary_dir="${JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR}/jfrog-command-summary" + printf '**mod:art:1.0**\n
inline
\n
\nmulti\n
\n' > "${jf_summary_dir}/markdown.md" + When run script shared/generate-jfrog-summary.sh repox + The status should be success + The line 1 should equal "jf config use repox" + The contents of file "$GITHUB_STEP_SUMMARY" should not include "
inline
" + The contents of file "$GITHUB_STEP_SUMMARY" should include "multi" + End + End +End