From a9636545007c6cf8e6049b7491573aa77b8805db Mon Sep 17 00:00:00 2001 From: Andrey G Date: Fri, 15 May 2026 20:22:07 +0200 Subject: [PATCH] Update release pipeline --- .../publish-build-info-to-jfrog/action.yml | 63 ---- .github/actions/publish-to-github/action.yml | 91 ----- .../actions/publish-to-sonatype/action.yml | 171 ---------- .../stage-release-artifacts/action.yml | 148 -------- ...-release.yml => create-release-bundle.yml} | 98 +++--- .github/workflows/promote-prod.yml | 23 -- .../workflows/promote-to-test-and-stage.yml | 55 +++ .github/workflows/promote.yml | 317 ------------------ ...stage.yml => release-creation-trigger.yml} | 4 +- .../workflows/sonatype-approve-or-delete.yml | 70 ---- 10 files changed, 108 insertions(+), 932 deletions(-) delete mode 100644 .github/actions/publish-build-info-to-jfrog/action.yml delete mode 100644 .github/actions/publish-to-github/action.yml delete mode 100644 .github/actions/publish-to-sonatype/action.yml delete mode 100644 .github/actions/stage-release-artifacts/action.yml rename .github/workflows/{build-release.yml => create-release-bundle.yml} (67%) delete mode 100644 .github/workflows/promote-prod.yml create mode 100644 .github/workflows/promote-to-test-and-stage.yml delete mode 100644 .github/workflows/promote.yml rename .github/workflows/{push-to-stage.yml => release-creation-trigger.yml} (80%) delete mode 100644 .github/workflows/sonatype-approve-or-delete.yml diff --git a/.github/actions/publish-build-info-to-jfrog/action.yml b/.github/actions/publish-build-info-to-jfrog/action.yml deleted file mode 100644 index 45934d1..0000000 --- a/.github/actions/publish-build-info-to-jfrog/action.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Publish build-info to JFrog -description: "Publishes build-info to JFrog" - -inputs: - jfrog-platform-url: - description: "JFrog platform URL" - required: false - default: https://aerospike.jfrog.io - oidc-provider: - description: "OIDC provider name" - required: true - oidc-audience: - description: "ODIC audience" - required: true - build-path: - description: "Path to which build info is to be published" - required: true - variables: - description: "Any additional variables to be published as part of build. The input here should be valid JSON in the form {'env_variable_key': 'env_variable_value'}, .e.g {'SONATYPE_STAGING_BUILD_ID': '070c07e25e937888ed9740ee825afa24bf184722'}" - required: true - -runs: - using: "composite" - steps: - - name: Debug publish to github - shell: bash - run: | - echo "${{ inputs.jfrog-platform-url }}" - echo "${{ inputs.build-path }}" - - - name: Set up JFrog credentials - id: setup-jfrog-cli - uses: step-security/setup-jfrog-cli@a6b41f8338bea0983ddff6bd4ede7d2dcd81e1fa # v4.8.1 - env: - JF_URL: ${{ inputs.jfrog-platform-url }} - JF_PROJECT: database - with: - version: 2.72.2 - oidc-provider-name: ${{ inputs.oidc-provider }} - oidc-audience: ${{ inputs.oidc-audience }} - - # Parsing out env variables and values and setting them in the environment - - name: Set env variables provided with variables - shell: bash - run: | - ENV_VARIABLES='${{ inputs.variables }}' - echo "$ENV_VARIABLES" | jq -r 'to_entries | .[] | "\(.key)=\(.value)"' >> $GITHUB_ENV - - # Pushing build info to JFrog - - name: Upload artifacts - shell: bash - run: | - BUILD_ID=$(echo "${{ inputs.build-path }}" | sed 's/.*_\(.*\)\/.*/\1/') - BUILD_PATH="promote_${BUILD_ID}" - - # record env variables - jf rt bce ${BUILD_PATH} ${{ github.run_number }} - - # record git info - jf rt bag ${BUILD_PATH} ${{ github.run_number }} - - # publish build info - jf rt bp ${BUILD_PATH} ${{ github.run_number }} diff --git a/.github/actions/publish-to-github/action.yml b/.github/actions/publish-to-github/action.yml deleted file mode 100644 index 08c4b13..0000000 --- a/.github/actions/publish-to-github/action.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: Publish artifacts to github -description: "Publish artifacts to github" - -inputs: - staging-folder: - description: "" - required: false - default: staging - target-folder: - description: "" - required: false - default: github - release-notes: - description: "Release notes" - required: true - github-token: - description: "Github auth token" - required: true - artifact-version: - description: "Version of the artifact to release" - required: true - build-name-number: - description: "String containing build name, number and jdk versions" - required: true - -runs: - using: "composite" - steps: - - name: Debug publish to github - shell: bash - run: | - echo "${{ inputs.staging-folder }}" - echo "${{ inputs.target-folder }}" - echo "${{ inputs.artifact-version }}" - echo "${{ inputs.release-notes }}" - echo "${{ inputs.build-name-number }}" - - - id: get-artifact-version - shell: bash - run: | - VERSION="${{ inputs.artifact-version }}" - echo "artifact-version=${VERSION}" >> $GITHUB_OUTPUT - - - name: Create upload archive for github - id: create-artifact - shell: bash - run: | - src="${{ inputs.staging-folder }}" - dest="${{ inputs.target-folder }}" - - find "$src" -type f \ - -exec cp {} "$dest" \; - - # Listing staged artifacts to be uploaded - - id: get-github-release-artifact-names - working-directory: ${{ inputs.target-folder }} - shell: bash - run: | - ARTIFACTS=$(ls | sed "s|^|${{ inputs.target-folder }}/|") - - echo "release-artifacts<> $GITHUB_OUTPUT - echo "${ARTIFACTS}" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Debug show content of the upload archive - shell: bash - run: | - pwd - ls ${{ inputs.target-folder }} | sed 's/^//' - - - name: Debug GitHub publish input - shell: bash - working-directory: ${{ inputs.target-folder }} - run: | - echo "working directory: ${{ inputs.target-folder }}" - echo "tag name: Release ${{ steps.get-artifact-version.outputs.artifact-version }}" - echo "body: Changes for release ${{ steps.get-artifact-version.outputs.artifact-version }}" - echo "body: ${{ inputs.release-notes }}" - echo "files: ${{ steps.get-github-release-artifact-names.outputs.release-artifacts }}" - - - name: Publish release to github - uses: step-security/action-gh-release@5f6a6ab53a5a2c000ff3a16fad038291e5b97ce7 # v2.4.2 - with: - token: ${{ inputs.github-token }} - tag_name: ${{ steps.get-artifact-version.outputs.artifact-version }} - body: | - Changes for release ${{ steps.get-artifact-version.outputs.artifact-version }} - ${{ inputs.release-notes }} - draft: true - prerelease: false - files: ${{ steps.get-github-release-artifact-names.outputs.release-artifacts }} diff --git a/.github/actions/publish-to-sonatype/action.yml b/.github/actions/publish-to-sonatype/action.yml deleted file mode 100644 index e042451..0000000 --- a/.github/actions/publish-to-sonatype/action.yml +++ /dev/null @@ -1,171 +0,0 @@ -name: Publish artifacts to Sonatype -description: "Publishes artifacts to Sonatype" - -inputs: - staging-folder: - description: "Folder to which the artifacts are copied" - required: false - default: staging - target-folder: - description: "Subfolder in the staging folder where the artifacts are copied" - required: false - default: sonatype - publish-user: - description: "Username for publishing to Sonatype" - required: true - publish-password: - description: "Password for publishing to Sonatype" - required: true - validation-max-number-checks: - description: "Number of checks we will conduct to check if the package is validated" - required: true - sonatype-domain-name: - description: "Sonatype domain name" - required: true - build-name-number: - required: true - description: "Build name and number" - artifact-version: - description: "Artifact version" - required: true - -outputs: - maven-central-release-id: - description: Maven central id extracted from staging step to maven central - value: ${{ steps.get-maven-central-release-id.outputs.maven-central-release-id }} - -runs: - using: "composite" - steps: - - name: Debug publish to github - shell: bash - run: | - echo "${{ inputs.staging-folder }}" - echo "${{ inputs.target-folder }}" - echo "${{ inputs.sonatype-domain-name }}" - echo "${{ inputs.build-name-number }}" - echo "${{ inputs.artifact-version }}" - - # For Maven Central we need to filter out the jar-with-dependencies - # as it is not allowed to be uploaded to Maven Central - - name: Copy artifacts with filter to sonatype stage folder - shell: bash - working-directory: ${{ inputs.staging-folder }} - run: | - src="./" - dest=../"${{ inputs.target-folder }}" - - find "$src" -type f \ - \! \( -name "*jar-with-dependencies*" \) \ - -exec cp --parents {} "$dest" \; - - - name: Debug target folder contents - shell: bash - working-directory: ${{ inputs.target-folder }} - run: | - echo "Current directory: $(pwd)" - echo "Contents:" - ls -laR - - # Creates uploadable archive - - name: Create upload archive for sonatype - id: create-artifact - shell: bash - working-directory: ${{ inputs.target-folder }} - run: | - # Use the actual artifact version, not parsed from build-name-number - RELEASE="${{ inputs.artifact-version }}" - # Extract just the build number from build-name-number - RELEASE_BUILD_NUMBER=$(echo "${{ inputs.build-name-number }}" | sed -E 's/.*\/([^/]+)$/\1/') - ARTIFACT_NAME="${RELEASE}_${RELEASE_BUILD_NUMBER}" - - echo "artifact-name=${ARTIFACT_NAME}.zip" >> $GITHUB_OUTPUT - zip -r "${ARTIFACT_NAME}.zip" . - - - name: Debug show content of the upload archive - shell: bash - working-directory: ${{ inputs.target-folder }} - run: | - ARTIFACT_NAME='${{ steps.create-artifact.outputs.artifact-name }}' - unzip -l "${ARTIFACT_NAME}" | tail -n +4 | sort -k4,4 - - # Call to Maven Central to stage the release/artifact - - name: Stage artifacts - id: stage-release - working-directory: ${{ inputs.target-folder }} - shell: bash - run: | - TOKEN=$(printf "${{ inputs.publish-user }}:${{ inputs.publish-password }}" | base64) - ARTIFACT_NAME="${{ steps.create-artifact.outputs.artifact-name }}" - UPLOAD_URL="${{ inputs.sonatype-domain-name }}/api/v1/publisher/upload?publishingType=USER_MANAGED" - - run_curl() { - curl --request POST --silent \ - --header "Authorization: Bearer ${TOKEN}" \ - --form "bundle=@${ARTIFACT_NAME}" \ - "${UPLOAD_URL}" - } - - echo "Uploading artifact '${ARTIFACT_NAME}' to Sonatype using URL '${UPLOAD_URL}'" - DEPLOYMENT_ID=$(run_curl) - - echo "Deployment ID: ${DEPLOYMENT_ID}" - echo "deployment-id=${DEPLOYMENT_ID}" >> $GITHUB_OUTPUT - - # Validation check loop - - name: Check validation - working-directory: ${{ inputs.target-folder }} - shell: bash - run: | - - TOKEN=$(printf "%s:%s" "${{ inputs.publish-user }}" "${{ inputs.publish-password }}" | base64) - DEPLOYMENT_ID="${{ steps.stage-release.outputs.deployment-id }}" - - NUMBER_OF_CHECKS=${{ inputs.validation-max-number-checks }} - - echo "Starting Sonatype validation checks (max: ${NUMBER_OF_CHECKS})" - - for ((i = 1; i <= NUMBER_OF_CHECKS; i++)); do - RESPONSE=$(curl --silent --show-error \ - --request POST \ - --header "Authorization: Bearer ${TOKEN}" \ - "${{ inputs.sonatype-domain-name }}/api/v1/publisher/status?id=${DEPLOYMENT_ID}") - - # Validate JSON and extract deploymentState - SONATYPE_RESPONSE=$(echo "${RESPONSE}" | jq -r '.deploymentState // "NULL"') - - if [[ "${SONATYPE_RESPONSE}" == "FAILED" ]]; then - ERRORS=$(echo "${RESPONSE}" | jq '.errors // "Unknown error"') - echo "Package validation failed." - echo "Errors: ${ERRORS}" - exit 1 - - elif [[ "${SONATYPE_RESPONSE}" == "VALIDATING" || "${SONATYPE_RESPONSE}" == "PENDING" ]]; then - echo "Package validation is not done. Status: ${SONATYPE_RESPONSE}" - - # Exponential backoff - sleep_time=$((2 ** (i - 1))) - echo "Next retry in ${sleep_time} seconds..." - sleep "${sleep_time}" - - elif [[ "${SONATYPE_RESPONSE}" == "VALIDATED" ]]; then - echo "Package successfully validated." - exit 0 - - else - echo "Unknown response from Sonatype: ${SONATYPE_RESPONSE}" - echo "Full payload:" - echo "${RESPONSE}" - fi - done - - echo "Validation timed out after ${NUMBER_OF_CHECKS} attempts." - exit 1 - - # Peculating up the maven central release id - - name: Maven Central release id - working-directory: ${{ inputs.target-folder }} - id: get-maven-central-release-id - shell: bash - run: | - echo "maven-central-release-id=${{ steps.stage-release.outputs.deployment-id }}" >> $GITHUB_OUTPUT diff --git a/.github/actions/stage-release-artifacts/action.yml b/.github/actions/stage-release-artifacts/action.yml deleted file mode 100644 index 734456a..0000000 --- a/.github/actions/stage-release-artifacts/action.yml +++ /dev/null @@ -1,148 +0,0 @@ -name: Stage artifacts for release -description: "Prepare artifacts for publish to various portals" - -inputs: - jfrog-platform-url: - description: "JFrog platform URL" - required: false - default: https://aerospike.jfrog.io - oidc-provider: - description: "OIDC provider name" - required: true - oidc-audience: - description: "ODIC audience" - required: true - staging-folder: - description: "Staging folders. Input should be a JSON array of staging folders" - required: false - default: '["staging","github","sonatype"]' - target-repository: - description: "Target repository in JFROG" - required: false - default: database-maven-dev-local - build-name-number: - description: "Build name and number" - required: true - artifact-version: - description: "Artifact version" - required: true - -runs: - using: "composite" - steps: - - name: Debug stage artifact to github - shell: bash - run: | - echo "${{ inputs.jfrog-platform-url }}" - echo "${{ inputs.artifact-id }}" - echo "${{ inputs.staging-folder }}" - echo "first element ${{ fromJson(inputs.staging-folder)[0] }}" - echo "second element ${{ fromJson(inputs.staging-folder)[1] }}" - echo "third element ${{ fromJson(inputs.staging-folder)[2] }}" - echo "${{ inputs.target-repository }}" - echo "${{ inputs.build-name-number }}" - echo "${{ inputs.artifact-version }}" - - - name: Setup jfrog shell - uses: step-security/setup-jfrog-cli@a6b41f8338bea0983ddff6bd4ede7d2dcd81e1fa # v4.8.1 - env: - JF_URL: ${{ inputs.jfrog-platform-url }} - JF_PROJECT: database - with: - oidc-provider-name: ${{ inputs.oidc-provider }} - oidc-audience: ${{ inputs.oidc-audience }} - - - name: Get info - shell: bash - id: get-build-info - run: | - INPUT=${{ inputs.build-name-number }} - - BUILD_NAME="${INPUT%/*}" # Getting the build name - BUILD_NUMBER="${INPUT#*/}" # Getting build number - - BUILD_INFO=$(jf rt curl "/api/build/${BUILD_NAME}/${BUILD_NUMBER}?project=database" | jq -c ".") - echo build-info="${BUILD_INFO}" >> $GITHUB_OUTPUT - - - name: Get build name - shell: bash - id: get-build-name - run: | - echo build-name=$(echo '${{ steps.get-build-info.outputs.build-info }}' | jq -r '.buildInfo.name') >> $GITHUB_OUTPUT - - - name: Get artifact build info - shell: bash - id: get-artifact-build-info - run: | - BUILD_INFO='${{ steps.get-build-info.outputs.build-info }}' - - ARTIFACT_BUILD_ID=$(echo "${BUILD_INFO}" | jq -r '.buildInfo.modules[] | select(.id | contains("-artifacts")) | .id') - echo "Artifact Build ID: ${ARTIFACT_BUILD_ID}" - - ARTIFACT_BUILD_NUMBER=$(echo "${ARTIFACT_BUILD_ID}" | cut -d'/' -f2) - echo "Artifact Build Number: ${ARTIFACT_BUILD_NUMBER}" - - ARTIFACT_BUILD_INFO=$(jf rt curl "/api/build/java-object-mapper/${ARTIFACT_BUILD_NUMBER}?project=database" | jq -c ".") - echo artifact-build-info="${ARTIFACT_BUILD_INFO}" >> $GITHUB_OUTPUT - - # Extract artifact name from the path (com/aerospike/ARTIFACT_NAME/VERSION/...) - ARTIFACT_NAME=$(echo "${ARTIFACT_BUILD_INFO}" | jq -r '.buildInfo.modules[0].artifacts[0].path' | cut -d'/' -f3) - echo "Artifact Name: ${ARTIFACT_NAME}" - echo artifact-name="${ARTIFACT_NAME}" >> $GITHUB_OUTPUT - - - - name: Create staging folders - shell: bash - run: | - echo '${{ inputs.staging-folder }}' | jq -r '.[]' | while read FOLDER; do - mkdir -p "$FOLDER" - done - - # Download artifacts from JFrog - - name: Download artifacts from JFrog - shell: bash - working-directory: ${{ fromJson(inputs.staging-folder)[0] }} - run: | - BUILD_INFO='${{ steps.get-artifact-build-info.outputs.artifact-build-info }}' - module_names=$(echo "${BUILD_INFO}" | jq -r '.buildInfo.modules[].artifacts[].path' | cut -d'/' -f3 | sort -u) - for module_name in $module_names; do - echo "Downloading artifacts for module: $module_name" - jf rt dl "database-maven-dev-local/com/aerospike/${module_name}/${{ inputs.artifact-version }}/*" --project database . - done - - - name: Debug list downloaded content - shell: bash - working-directory: ${{ fromJson(inputs.staging-folder)[0] }} - run: | - pwd - ls -laR - - # The hashes are generated when the artifacts are published (not part of this build). - # When we promote or run releases we download the artifacts and take the hashes - # which are part of the build info. We don't have sha-512 at the moment. - - name: Get hashes from build_info and generate files - shell: bash - working-directory: ${{ fromJson(inputs.staging-folder)[0] }} - run: | - BUILD_INFO='${{ steps.get-artifact-build-info.outputs.artifact-build-info }}' - - # Process artifacts from build info - echo "Creating checksums from build info..." - echo "${BUILD_INFO}" | jq -c '.buildInfo.modules[].artifacts[]' | while read -r MODULE; do - NAME=$(echo "${MODULE}" | jq -r ".name") - SHA1=$(echo "${MODULE}" | jq -r ".sha1") - SHA256=$(echo "${MODULE}" | jq -r ".sha256") - MD5=$(echo "${MODULE}" | jq -r ".md5") - - FILE_PATH=$(find . -type f -name "${NAME}" | head -n 1) - - if [[ -z "${FILE_PATH}" ]]; then - echo "Warning: Could not find file ${NAME}" - continue - fi - - echo "Creating checksums for: ${FILE_PATH}" - echo "${SHA1}" > "${FILE_PATH}.sha1" - echo "${SHA256}" > "${FILE_PATH}.sha256" - echo "${MD5}" > "${FILE_PATH}.md5" - done diff --git a/.github/workflows/build-release.yml b/.github/workflows/create-release-bundle.yml similarity index 67% rename from .github/workflows/build-release.yml rename to .github/workflows/create-release-bundle.yml index ffc3238..d8a856b 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/create-release-bundle.yml @@ -1,4 +1,4 @@ -name: Build and release +name: Build artifact and create release bundle permissions: id-token: write @@ -37,21 +37,24 @@ jobs: version: ${{ steps.extract.outputs.release-version }} is-snapshot: ${{ steps.extract.outputs.is-snapshot }} - build-packages: + build-sign-deploy: needs: extract-version - uses: aerospike/shared-workflows/.github/workflows/reusable_execute-build.yaml@1af48ee617c69f3ee53d4d63fc933eb4b14e7a12 + uses: aerospike/shared-workflows/.github/workflows/reusable_artifacts-cicd.yaml@1004088a1b5122b9b71a39b40f619f6b50e78d16 with: - runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} - jf-project: ${{ vars.JFROG_PROJECT }} + gh-artifact-directory: build + gh-workflows-ref: 1004088a1b5122b9b71a39b40f619f6b50e78d16 jf-build-name: java-object-mapper - jf-build-id: ${{ github.run_number }}-buildinfo-${{ needs.extract-version.outputs.version }} - gh-checkout-path: shared-workflows - gh-source-path: java-object-mapper - working-directory: java-object-mapper - gh-workflows-ref: 1af48ee617c69f3ee53d4d63fc933eb4b14e7a12 + jf-project: ${{ vars.JFROG_PROJECT }} + oidc-audience: ${{ vars.OIDC_AUDIENCE }} + oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} + version: ${{ needs.extract-version.outputs.version }} + jar-group-id: com.aerospike setup-java: true java-version: 17 java-distribution: "temurin" + gh-source-path: java-object-mapper + gh-retention-days: 1 + runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} build-script: | # Maven build if [ "${{ needs.extract-version.outputs.is-snapshot }}" == "true" ]; then @@ -95,53 +98,54 @@ jobs: fi ls -lar build/ - gh-artifact-directory: build - gh-artifact-name: build-artifacts-${{ needs.extract-version.outputs.version }} - gh-retention-days: 1 - jf-url: https://artifact.aerospike.io - publish-build-info: true - oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} - oidc-audience: ${{ vars.OIDC_AUDIENCE }} - - sign-artifacts: - needs: [ build-packages, extract-version ] - uses: aerospike/shared-workflows/.github/workflows/reusable_sign-artifacts.yaml@main - with: - gh-retention-days: 1 - gh-artifact-name: signed_build-artifacts-${{ needs.extract-version.outputs.version }} - gh-unsigned-artifacts: build-artifacts-${{ needs.extract-version.outputs.version }} - gh-workflows-ref: 1af48ee617c69f3ee53d4d63fc933eb4b14e7a12 secrets: gpg-private-key: ${{ secrets.GPG_SECRET_KEY }} gpg-public-key: ${{ secrets.GPG_PUBLIC_KEY }} gpg-key-pass: ${{ secrets.GPG_PASS }} - deploy-artifacts: - needs: [ sign-artifacts, extract-version ] - uses: aerospike/shared-workflows/.github/workflows/reusable_deploy-artifacts.yaml@1af48ee617c69f3ee53d4d63fc933eb4b14e7a12 - with: - gh-workflows-ref: 1af48ee617c69f3ee53d4d63fc933eb4b14e7a12 - jf-project: ${{ vars.JFROG_PROJECT }} - jf-build-name: java-object-mapper - jf-metadata-build-id: ${{ github.run_number }}-buildinfo - jf-build-id: ${{ github.run_number }} - gh-artifact-name: ${{ needs.sign-artifacts.outputs.gh-artifact-name }} - jar-group-id: com.aerospike - version: ${{ needs.extract-version.outputs.version }} - gh-retention-days: 1 - oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} - oidc-audience: ${{ vars.OIDC_AUDIENCE }} - dry-run: false - create-release-bundle: - needs: [ extract-version, deploy-artifacts ] - uses: aerospike/shared-workflows/.github/workflows/reusable_create-release-bundle.yaml@main + needs: [ extract-version, build-sign-deploy ] + uses: aerospike/shared-workflows/.github/workflows/reusable_create-release-bundle.yaml@1004088a1b5122b9b71a39b40f619f6b50e78d16 with: jf-project: ${{ vars.JFROG_PROJECT }} - jf-build-names: java-object-mapper:${{ github.run_number }} + jf-build-names: ${{ needs.build-sign-deploy.outputs.jf-build-name }}:${{ needs.build-sign-deploy.outputs.jf-build-id }} jf-bundle-name: java-object-mapper - gh-workflows-ref: 1af48ee617c69f3ee53d4d63fc933eb4b14e7a12 + gh-workflows-ref: 1004088a1b5122b9b71a39b40f619f6b50e78d16 version: ${{ needs.extract-version.outputs.version }} oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} oidc-audience: ${{ vars.OIDC_AUDIENCE }} dry-run: false + + promote-to-dev: + needs: [ extract-version, create-release-bundle ] + name: Promote to DEV + runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 + with: + egress-policy: audit + + - name: Setup JFrog CLI + uses: step-security/setup-jfrog-cli@893a92f96c7727242adf0e603c77b1f2a22390e1 # v4.9.1 + env: + JF_URL: ${{ vars.JFROG_PLATFORM_URL }} + JF_PROJECT: ${{ vars.JFROG_PROJECT }} + with: + oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} + oidc-audience: ${{ vars.OIDC_AUDIENCE }} + + - name: Check if snapshot build + run: | + if [[ "${{ needs.extract-version.outputs.is-snapshot }}" == "true" ]]; then + echo "Error: this is a SNAPSHOT build. Snapshots are not promoted." + exit 1 + fi + + - name: Promoting release bundle to DEV + uses: aerospike/shared-workflows/.github/actions/promote-release-bundle@8ec712eafbec26c8db8d1183688a5fd806560a95 # v3.5.0 + with: + bundle-name: java-object-mapper + version: ${{ needs.extract-version.outputs.version }} + environment: DEV + jf-project: ${{ vars.JFROG_PROJECT }} diff --git a/.github/workflows/promote-prod.yml b/.github/workflows/promote-prod.yml deleted file mode 100644 index 5a94e5d..0000000 --- a/.github/workflows/promote-prod.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Promote to Prod - -permissions: - contents: write # For creating releases - id-token: write # For OIDC authentication - -on: - workflow_dispatch: - inputs: - build-number: - type: number - description: Build number used to build artifact to be promoted - -jobs: - promote-from-stage-to-prod: - name: Promote from stage to prod - uses: ./.github/workflows/promote.yml - with: - build-number: ${{ inputs.build-number }} - target-repository: database-maven-dev-local - target-branch: main - source-branch: stage - secrets: inherit diff --git a/.github/workflows/promote-to-test-and-stage.yml b/.github/workflows/promote-to-test-and-stage.yml new file mode 100644 index 0000000..71a4303 --- /dev/null +++ b/.github/workflows/promote-to-test-and-stage.yml @@ -0,0 +1,55 @@ +name: Promote release bundle to TEST and STAGE + +permissions: + id-token: write + +on: + workflow_dispatch: + inputs: + version: + description: Version to be promoted + required: true + type: string + +jobs: + promote-to-test-and-stage: + name: Promote to TEST and to STAGE + runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 + with: + egress-policy: audit + + - name: Check if snapshot build + run: | + VERSION="${{ inputs.version }}" + if [[ "$VERSION" == *"-SNAPSHOT"* ]]; then + echo "Error: Version $VERSION is a SNAPSHOT build. Snapshots are not promoted to TEST/STAGE." + exit 1 + fi + + - name: Setup JFrog CLI + uses: step-security/setup-jfrog-cli@893a92f96c7727242adf0e603c77b1f2a22390e1 # v4.9.1 + env: + JF_URL: ${{ vars.JFROG_PLATFORM_URL }} + JF_PROJECT: ${{ vars.JFROG_PROJECT }} + with: + oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} + oidc-audience: ${{ vars.OIDC_AUDIENCE }} + + - name: Promoting release bundle to TEST + uses: aerospike/shared-workflows/.github/actions/promote-release-bundle@8ec712eafbec26c8db8d1183688a5fd806560a95 # v3.5.0 + with: + bundle-name: java-object-mapper + version: ${{ inputs.version }} + environment: TEST + jf-project: ${{ vars.JFROG_PROJECT }} + + - name: Promoting release bundle to STAGE + uses: aerospike/shared-workflows/.github/actions/promote-release-bundle@8ec712eafbec26c8db8d1183688a5fd806560a95 # v3.5.0 + with: + bundle-name: java-object-mapper + version: ${{ inputs.version }} + environment: STAGE + jf-project: ${{ vars.JFROG_PROJECT }} diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml deleted file mode 100644 index 6d6e0ce..0000000 --- a/.github/workflows/promote.yml +++ /dev/null @@ -1,317 +0,0 @@ -name: Promote - -permissions: - contents: write # For creating releases - id-token: write # For JFrog OIDC authentication - -on: - workflow_call: - inputs: - build-number: - type: string - description: Build number used to build artifact to be promoted - target-repository: - type: string - description: Repository to promote to - target-branch: - type: string - description: Target branch to promote token - jf-target-build: - type: string - description: Target build name - default: java-object-mapper - source-branch: - type: string - required: true - description: Source branch to merge from - secrets: - AEROSPIKE_SA_CICD_USERNAME: - required: true - AEROSPIKE_SA_CICD_PASSWORD: - required: true - CLIENT_BOT_PAT: - required: true - JFROG_OIDC_PROVIDER: - required: true - JFROG_OIDC_AUDIENCE: - required: true - -jobs: - promote: - runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} - outputs: - build-name-number: ${{ steps.get-build-name-number.outputs.build-name-numbers }} - artifact-version: ${{ steps.get-artifact-version.outputs.artifact-version }} - release-notes: ${{ steps.get-release-notes.outputs.release-notes }} - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 - with: - egress-policy: audit - - - name: Debug step - run: | - echo "build-number: ${{ inputs.build-number }}" - echo "target-repository: ${{ inputs.target-repository }}" - echo "target-branch: ${{ inputs.target-branch }}" - echo "jf-target-build: ${{ inputs.jf-target-build }}" - echo "source-branch: ${{ inputs.source-branch }}" - - # Setting up jfrog cli - - name: Setup jfrog shell - uses: step-security/setup-jfrog-cli@a6b41f8338bea0983ddff6bd4ede7d2dcd81e1fa # v4.8.1 - env: - JF_URL: ${{ vars.JFROG_PLATFORM_URL }} - JF_PROJECT: database - with: - oidc-provider-name: ${{ vars.OIDC_PROVIDER_NAME }} - oidc-audience: ${{ vars.OIDC_AUDIENCE }} - - # Needed since we are using actions which are part of the repository - - name: Checkout - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - with: - # Fetch the whole history to prevent unrelated history errors - fetch-depth: "0" - ref: ${{ inputs.target-branch }} - token: ${{ secrets.CLIENT_BOT_PAT }} - - # Getting build info which will allow us to get information about the build we are promoting - - name: Get info - id: get-build-info - run: | - API_PATH="/api/build/${{ inputs.jf-target-build }}/${{ inputs.build-number }}?project=database" - status_code=$(jf rt curl "${API_PATH}" -o /dev/null -s -w "%{http_code}") - - # Exit with 1 unless the request succeeded (HTTP 200) - if [[ "$status_code" -ne 200 ]]; then - echo "ERROR: could not fetch build for build number ${{ inputs.build-number }} (HTTP $status_code)" >&2 - - exit 1 - fi - - echo build-info=$(jf rt curl "${API_PATH}" ) >> $GITHUB_OUTPUT - - # Snapshot builds are not promoted to production - - name: Check if snapshot build - id: check-snapshot - run: | - BUILD_INFO='${{ steps.get-build-info.outputs.build-info }}' - BUILD_ID=$(echo "$BUILD_INFO" | jq -r '.buildInfo.modules[] | select(.id | test("buildinfo")) | .id') - # extracting snapshot from build-nfo name. Not ideal, but we don't have is_snapshot information in JF yet - # Extract version from build ID - # Format: /-buildinfo-_hash - if [[ "$BUILD_ID" =~ buildinfo-([0-9.]+(-SNAPSHOT)?) ]]; then - VERSION="${BASH_REMATCH[1]}" - echo "Parsed version: $VERSION" - else - echo "ERROR: Could not parse version" - fi - - echo "Parsed version: $VERSION" - - if [[ "$VERSION" == *"-SNAPSHOT" ]]; then - echo "Error: Build ${{ inputs.jf-target-build }} with build number ${{ inputs.build-number }} is a SNAPSHOT build. Snapshots are not promoted to production." - # exit 1 - fi - - # Fetching commit hash from the build info. The commit hash is used for SNAPSHOT builds - - name: Get commit hash from repo - id: get-commit-hash - run: | - BUILD_INFO='${{ steps.get-build-info.outputs.build-info }}' - - # Try to get from vcs first - COMMIT_HASH=$(echo "$BUILD_INFO" | jq -r '.buildInfo.vcs[0].revision // empty') - - if [ -z "$COMMIT_HASH" ] || [ "$COMMIT_HASH" == "null" ]; then - # Fallback: extract from module ID - COMMIT_HASH=$(echo "$BUILD_INFO" | jq -r '.buildInfo.modules[0].id' | sed -E 's/.*SNAPSHOT_(.*)$/\1/') - fi - echo "commit-hash=$COMMIT_HASH" >> $GITHUB_OUTPUT - - # Fetching build name for build promotion process. The build name will contain build numbers. - # This command parses json and pulls out the build name - - name: Get build name - id: get-build-name - run: | - echo build-names=$(echo '${{ steps.get-build-info.outputs.build-info }}' | jq -r '.buildInfo.name') >> $GITHUB_OUTPUT - - - name: Debug - run: | - echo "commit-hash: '${{ steps.get-commit-hash.outputs.commit-hash }}'" - echo "build-name: '${{ steps.get-build-name.outputs.build-names }}'" - - # Promoting build to production - - name: Promote build - shell: bash - run: | - BUILD_NAME="${{ steps.get-build-name.outputs.build-names }}" - BUILD_NUMBER="${{ inputs.build-number }}" - - if [ -z "$BUILD_NAME" ]; then - echo "Error: Missing build name" - exit 1 - fi - - echo "Promoting build '$BUILD_NAME' (build #$BUILD_NUMBER) to ${{ inputs.target-repository }}" - jf rt build-promote --copy=true "$BUILD_NAME" "$BUILD_NUMBER" "${{ inputs.target-repository }}" - - # Fetching release notes from commit logs - - name: Generate release notes - id: get-release-notes - run: | - RELEASE_NOTES=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s") - echo "release-notes<> $GITHUB_OUTPUT - echo "${RELEASE_NOTES}" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Debug print release notes - run: | - echo "Changes for release ${{ steps.get-artifact-version.outputs.artifact-version }}" - echo "${{ steps.get-release-notes.outputs.release-notes }}" - - # Fast forward the target branch to the source branch. - # - name: Fast forward - # shell: bash - # run: | - # # Making sure we have latest history in place to be able to fast forward merge - # git status - # git checkout ${{ inputs.source-branch }} - # git checkout ${{ inputs.target-branch }} - # git merge --ff-only ${{ inputs.source-branch }} - # - # # Adding commit message for promotion - # - name: Add tagging message - # uses: stefanzweifel/git-auto-commit-action@v4 - # with: - # commit_message: "Promote to prod [skip ci]" - # commit_author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> - # tagging_message: Promote to PROD - # branch: ${{ inputs.target-branch }} - - # Pushing changes to remote head branch - # This needs updating to create PR instead of direct push - # - name: Upload changes to remote head branch - # shell: bash - # run: git push - - # Passing build-name-numbers and artifact-version to the next job - - name: Get build name with build number - id: get-build-name-number - run: | - echo "DEBUG: inputs.build-number='${{ inputs.build-number }}'" - BUILD_NAME=$(echo '${{ steps.get-build-info.outputs.build-info }}' | jq -r '.buildInfo.name') - BUILD_NUMBER="${{ inputs.build-number }}" - echo "build-name-numbers=${BUILD_NAME}/${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - - name: Get artifact version from JFrog build info - id: get-artifact-version - run: | - BUILD_INFO='${{ steps.get-build-info.outputs.build-info }}' - - VERSION=$(echo "$BUILD_INFO" | jq -r ' - .buildInfo.modules[] - | select(.id | test("-buildinfo-")) - | .id - | capture("-buildinfo-(?[^_]+)") - | .ver - ') - - if [[ -z "$VERSION" ]]; then - echo "ERROR: Could not parse artifact version from JFrog build info!" - exit 1 - fi - - echo "artifact-version=$VERSION" >> $GITHUB_OUTPUT - - - name: Debug show 'build-name-numbers' and 'artifact-version' - run: | - echo "build-name-number: ${{ steps.get-build-name-number.outputs.build-name-numbers }}" - echo "artifact-version: ${{ steps.get-artifact-version.outputs.artifact-version }}" - - - name: Release debug - run: | - GIT_NOTES='${{ steps.get-release-notes.outputs.release-notes }}' - RELEASE_VERSION='${{steps.get-artifact-version.outputs.artifact-version }}' - echo "${RELEASE_VERSION}" - echo "${GIT_NOTES}" - - publish-release-sonatype: - runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} - needs: promote - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 - with: - egress-policy: audit - - # Needed since we are using actions which are part of the repository - - name: Checkout - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - with: - ref: ${{ github.head_ref }} - token: ${{ secrets.CLIENT_BOT_PAT }} - - # Pulling release from JFROG - - uses: ./.github/actions/stage-release-artifacts - with: - oidc-provider: ${{ secrets.JFROG_OIDC_PROVIDER }} - oidc-audience: ${{ secrets.JFROG_OIDC_AUDIENCE }} - target-repository: ${{ inputs.target-repository }} - build-name-number: ${{ needs.promote.outputs.build-name-number }} - artifact-version: ${{ needs.promote.outputs.artifact-version }} - - # Publishing release to Maven Central - - uses: ./.github/actions/publish-to-sonatype - id: publish-to-sonatype - with: - build-name-number: ${{ needs.promote.outputs.build-name-number }} - artifact-version: ${{ needs.promote.outputs.artifact-version }} - publish-user: ${{ secrets.AEROSPIKE_SA_CICD_USERNAME }} - publish-password: ${{ secrets.AEROSPIKE_SA_CICD_PASSWORD }} - validation-max-number-checks: ${{ vars.VALIDATION_MAX_NUMBER_CHECKS }} - sonatype-domain-name: ${{ vars.SONATYPE_DOMAIN_NAME }} - - # Publishing release information to JFrog for aggregation. This information is used later for final release step - # (acknowledgement) to Maven Central - - uses: ./.github/actions/publish-build-info-to-jfrog - with: - oidc-provider: ${{ secrets.JFROG_OIDC_PROVIDER }} - oidc-audience: ${{ secrets.JFROG_OIDC_AUDIENCE }} - build-path: ${{ needs.promote.outputs.build-name-number }} - variables: '{"SONATYPE_STAGING_BUILD_ID":"${{ steps.publish-to-sonatype.outputs.maven-central-release-id }}"}' - - # Not used at the moment - # publish-release-github: - # runs-on: ${{ vars.BUILD_CONTAINER_DISTRO_VERSION }} - # needs: [ promote, publish-release-sonatype ] - # steps: - # - name: Harden the runner (Audit all outbound calls) - # uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 - # with: - # egress-policy: audit - # - # - name: Checkout - # uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - # with: - # ref: ${{ inputs.target-branch }} - # token: ${{ secrets.CLIENT_BOT_PAT }} - # - # - uses: ./.github/actions/stage-release-artifacts - # with: - # oidc-provider: ${{ secrets.JFROG_OIDC_PROVIDER }} - # oidc-audience: ${{ secrets.JFROG_OIDC_AUDIENCE }} - # target-repository: ${{ inputs.target-repository }} - # build-name-number: ${{ needs.promote.outputs.build-name-number }} - # artifact-version: ${{ needs.promote.outputs.artifact-version }} - # staging-folder: '["staging","github"]' - - # Publishing release to GitHub - # Note: this action knows how to process json internally. It expects inputs to be in json format -# - uses: ./.github/actions/publish-to-github -# with: -# release-notes: ${{ needs.promote.outputs.release-notes }} -# github-token: ${{ secrets.CLIENT_BOT_PAT }} -# build-name-number: ${{ needs.promote.outputs.build-name-numbers }} -# artifact-version: ${{ needs.promote.outputs.artifact-version }} diff --git a/.github/workflows/push-to-stage.yml b/.github/workflows/release-creation-trigger.yml similarity index 80% rename from .github/workflows/push-to-stage.yml rename to .github/workflows/release-creation-trigger.yml index 8c366d1..8ee2bac 100644 --- a/.github/workflows/push-to-stage.yml +++ b/.github/workflows/release-creation-trigger.yml @@ -1,4 +1,4 @@ -name: Java Build & Release +name: Trigger Creating Release Bundle permissions: id-token: write packages: write @@ -18,5 +18,5 @@ on: jobs: build-stage: name: Build stage - uses: ./.github/workflows/build-release.yml + uses: ./.github/workflows/create-release-bundle.yml secrets: inherit diff --git a/.github/workflows/sonatype-approve-or-delete.yml b/.github/workflows/sonatype-approve-or-delete.yml deleted file mode 100644 index f786f56..0000000 --- a/.github/workflows/sonatype-approve-or-delete.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: Approve or Delete Sonatype Deployment -run-name: "Sonatype Deployment: ${{ inputs.action }} ${{ inputs.stage-release-id }}" -# https://central.sonatype.org/publish/publish-portal-api/#verify-status-of-the-deployment - -permissions: { } - -on: - workflow_dispatch: - inputs: - stage-release-id: - description: "The Sonatype stage-release-id (UUID)" - required: true - type: string - action: - description: "Action to perform on the deployment: POST = approve, DELETE = discard" - required: true - type: choice - options: - - POST - - DELETE - -jobs: - sonatype-deployment-action: - runs-on: ubuntu-latest - - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 - with: - egress-policy: audit - - - name: Debug Inputs - run: | - echo "Action: ${{ inputs.action }}" - echo "Stage Release ID: ${{ inputs.stage-release-id }}" - - - name: Build Authorization Header - id: auth - run: | - TOKEN=$(printf "%s:%s" "${{ secrets.AEROSPIKE_SA_CICD_USERNAME }}" "${{ secrets.AEROSPIKE_SA_CICD_PASSWORD }}" | base64) - echo "token=$TOKEN" >> $GITHUB_OUTPUT - - - name: Approve/Delete deployment - shell: bash - run: | - ACTION="${{ inputs.action }}" - ID="${{ inputs.stage-release-id }}" - TOKEN="${{ steps.auth.outputs.token }}" - DOMAIN="${{ vars.SONATYPE_DOMAIN_NAME }}" - - echo "Running Sonatype Deployment API call..." - echo "Endpoint: ${DOMAIN}/api/v1/publisher/deployment/${ID}" - - ACTION=$(echo "${{ inputs.action }}" | tr '[:lower:]' '[:upper:]') - - if [[ "$ACTION" != "POST" && "$ACTION" != "DELETE" ]]; then - echo "ERROR: Invalid action '$ACTION' (expected POST or DELETE)" - exit 1 - fi - - echo "→ Executing $ACTION for deployment ID ${ID}" - - RESPONSE=$(curl --fail --show-error --silent \ - --request "$ACTION" \ - --header "Authorization: Bearer ${TOKEN}" \ - "${DOMAIN}/api/v1/publisher/deployment/${ID}" - ) - - echo "Response from Sonatype:" - echo "$RESPONSE"