ZXF: Deploy Production Release #6535
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-License-Identifier: Apache-2.0 | |
| name: "ZXF: Deploy Production Release" | |
| on: | |
| push: | |
| tags: | |
| - "v[0-9]+.[0-9]+.[0-9]+-?*" | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| required: true | |
| description: "Git Reference (branch, tag, or commit SHA)" | |
| ref-name: | |
| required: true | |
| description: "Git Reference Name (branch name or tag name)" | |
| dry-run-enabled: | |
| required: false | |
| default: false | |
| type: boolean | |
| description: "Specify that this is a test run which will skip certain steps." | |
| defaults: | |
| run: | |
| shell: bash | |
| permissions: | |
| id-token: write | |
| contents: write | |
| actions: read | |
| jobs: | |
| prepare-tag-release: | |
| name: Prepare Release [Tag] | |
| runs-on: hl-cn-default-lin-sm | |
| if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | |
| outputs: | |
| version: ${{ steps.tag.outputs.version }} | |
| prerelease: ${{ steps.tag.outputs.prerelease }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 | |
| with: | |
| egress-policy: audit | |
| - name: Install Semantic Version Tools | |
| run: | | |
| echo "::group::Download SemVer Binary" | |
| sudo curl -L -o /usr/local/bin/semver https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver | |
| echo "::endgroup::" | |
| echo "::group::Change SemVer Binary Permissions" | |
| sudo chmod -v +x /usr/local/bin/semver | |
| echo "::endgroup::" | |
| echo "::group::Show SemVer Binary Version Info" | |
| semver --version | |
| echo "::endgroup::" | |
| - name: Extract Tag Version | |
| id: tag | |
| run: | | |
| RELEASE_VERSION="$(semver get release "${{ github.ref_name }}")" | |
| PRERELEASE_VERSION="$(semver get prerel "${{ github.ref_name }}")" | |
| FINAL_VERSION="${RELEASE_VERSION}" | |
| PRERELEASE_FLAG="false" | |
| [[ -n "${PRERELEASE_VERSION}" ]] && FINAL_VERSION="${RELEASE_VERSION}-${PRERELEASE_VERSION}" | |
| [[ -n "${PRERELEASE_VERSION}" ]] && PRERELEASE_FLAG="true" | |
| echo "version=${FINAL_VERSION}" >>"${GITHUB_OUTPUT}" | |
| echo "prerelease=${PRERELEASE_FLAG}" >>"${GITHUB_OUTPUT}" | |
| release-tag: | |
| name: Release [Tag] | |
| uses: ./.github/workflows/node-zxc-build-release-artifact.yaml | |
| needs: | |
| - prepare-tag-release | |
| with: | |
| version-policy: specified | |
| new-version: ${{ needs.prepare-tag-release.outputs.version }} | |
| trigger-env-deploy: none | |
| release-profile: ${{ needs.prepare-tag-release.outputs.prerelease == 'true' && 'PrereleaseChannel' || 'MavenCentral' }} | |
| ref: ${{ github.ref }} | |
| ref-name: ${{ github.ref_name }} | |
| secrets: | |
| access-token: ${{ secrets.GITHUB_TOKEN }} | |
| bucket-name: ${{ secrets.RELEASE_ARTIFACT_BUCKET_NAME }} | |
| cdn-bucket-name: ${{ secrets.CDN_ARTIFACT_BUCKET_NAME }} | |
| central-publishing-username: ${{ secrets.CENTRAL_PUBLISHING_USERNAME }} | |
| central-publishing-password: ${{ secrets.CENTRAL_PUBLISHING_PASSWORD }} | |
| svcs-gpg-key-contents: ${{ secrets.SVCS_GPG_KEY_CONTENTS }} | |
| svcs-gpg-key-passphrase: ${{ secrets.SVCS_GPG_KEY_PASSPHRASE }} | |
| sdk-ossrh-username: ${{ secrets.PLATFORM_OSSRH_USERNAME }} | |
| sdk-ossrh-password: ${{ secrets.PLATFORM_OSSRH_PASSWORD }} | |
| sdk-gpg-key-contents: ${{ secrets.PLATFORM_GPG_KEY_CONTENTS }} | |
| sdk-gpg-key-passphrase: ${{ secrets.PLATFORM_GPG_KEY_PASSPHRASE }} | |
| slack-webhook-url: ${{ secrets.SLACK_CITR_BUILD_PROMOTION_WEBHOOK }} | |
| jf-url: ${{ vars.JF_URL }} | |
| jf-docker-registry: ${{ vars.JF_DOCKER_REGISTRY }} | |
| jf-user-name: ${{ vars.JF_USER_NAME }} | |
| jf-access-token: ${{ secrets.JF_ACCESS_TOKEN }} | |
| update-hedera-protobufs: | |
| name: Update Hedera Protobufs | |
| runs-on: hl-cn-default-lin-sm | |
| needs: | |
| - prepare-tag-release | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout Hiero Consensus Node Code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| token: ${{ secrets.GH_ACCESS_TOKEN }} | |
| ref: ${{ inputs.ref }} | |
| fetch-depth: "0" | |
| - name: Checkout Hedera Protobufs Code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| token: ${{ secrets.PROTOBUFS_GH_ACCESS_TOKEN }} | |
| fetch-depth: "0" | |
| repository: hashgraph/hedera-protobufs | |
| path: hedera-protobufs | |
| - name: Install rsync | |
| run: sudo apt update && sudo apt -y install rsync | |
| - name: Update the folders owned by Services | |
| working-directory: hedera-protobufs | |
| run: | | |
| git push --delete origin v${{ needs.prepare-tag-release.outputs.version }} || true | |
| git tag --delete v${{ needs.prepare-tag-release.outputs.version }} || true | |
| rsync -a --delete ../hapi/hedera-protobuf-java-api/src/main/proto/services/ services/ | |
| - name: Import GPG key for commit signoff | |
| id: gpg_import | |
| uses: step-security/ghaction-import-gpg@c86c374c0659a6c2d1284bccf8af889e73ce8fe0 # v6.3.0 | |
| with: | |
| gpg_private_key: ${{ secrets.PROTOBUFS_GPG_KEY_CONTENTS }} | |
| passphrase: ${{ secrets.PROTOBUFS_GPG_KEY_PASSPHRASE }} | |
| git_user_signingkey: true | |
| git_commit_gpgsign: true | |
| git_tag_gpgsign: true | |
| - name: Add & Commit | |
| uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4 | |
| with: | |
| cwd: "hedera-protobufs" | |
| author_name: swirlds-eng-automation | |
| author_email: ${{ secrets.PROTOBUFS_GPG_USER_EMAIL }} | |
| commit: --signoff | |
| message: "ci: Copied recent protobuf changes from hedera-services" | |
| new_branch: "update-recent-protobuf-changes-${{ github.run_number }}" | |
| tag: 'v${{ needs.prepare-tag-release.outputs.version }} -s -m "Hedera Protobufs v${{ needs.prepare-tag-release.outputs.version }}" -u "${{ steps.gpg_import.outputs.keyid }}"' | |
| release-branch: | |
| name: Release [Branch] | |
| uses: ./.github/workflows/node-zxc-build-release-artifact.yaml | |
| if: ${{ github.event_name == 'workflow_dispatch' }} | |
| with: | |
| version-policy: branch-commit | |
| trigger-env-deploy: integration | |
| release-profile: DevelopCommit | |
| ref: ${{ inputs.ref }} | |
| ref-name: ${{ inputs.ref-name }} | |
| dry-run-enabled: ${{ inputs.dry-run-enabled }} | |
| secrets: | |
| access-token: ${{ secrets.GITHUB_TOKEN }} | |
| bucket-name: ${{ secrets.RELEASE_ARTIFACT_BUCKET_NAME }} | |
| cdn-bucket-name: ${{ secrets.CDN_ARTIFACT_BUCKET_NAME }} | |
| central-publishing-username: ${{ secrets.CENTRAL_PUBLISHING_USERNAME }} | |
| central-publishing-password: ${{ secrets.CENTRAL_PUBLISHING_PASSWORD }} | |
| svcs-gpg-key-contents: ${{ secrets.SVCS_GPG_KEY_CONTENTS }} | |
| svcs-gpg-key-passphrase: ${{ secrets.SVCS_GPG_KEY_PASSPHRASE }} | |
| sdk-ossrh-username: ${{ secrets.PLATFORM_OSSRH_USERNAME }} | |
| sdk-ossrh-password: ${{ secrets.PLATFORM_OSSRH_PASSWORD }} | |
| sdk-gpg-key-contents: ${{ secrets.PLATFORM_GPG_KEY_CONTENTS }} | |
| sdk-gpg-key-passphrase: ${{ secrets.PLATFORM_GPG_KEY_PASSPHRASE }} | |
| slack-webhook-url: ${{ secrets.SLACK_CITR_BUILD_PROMOTION_WEBHOOK }} | |
| jf-url: ${{ vars.JF_URL }} | |
| jf-docker-registry: ${{ vars.JF_DOCKER_REGISTRY }} | |
| jf-user-name: ${{ vars.JF_USER_NAME }} | |
| jf-access-token: ${{ secrets.JF_ACCESS_TOKEN }} | |
| deploy-xts-ci-trigger: | |
| name: Trigger XTS CI Flow | |
| runs-on: hl-cn-default-lin-sm | |
| needs: | |
| - release-branch | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout Code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: "0" | |
| ref: ${{ inputs.ref }} | |
| token: ${{ secrets.GH_ACCESS_TOKEN }} | |
| - name: Check Prep XTS Job State | |
| id: check-xts-job | |
| if: ${{ needs.release-branch.result == 'success' }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| JOB_ENABLED="true" | |
| JOB_STATE=$(gh workflow list --all --json name,state | jq -r '.[]|select(.name=="ZXF: Prepare Extended Test Suite")|.state') | |
| [[ "${JOB_STATE}" == "disabled_manually" ]] && JOB_ENABLED="false" | |
| echo "enabled=${JOB_ENABLED}" >> "${GITHUB_OUTPUT}" | |
| - name: Trigger ZXF Prepare Extended Test Suite | |
| if: ${{ needs.release-branch.result == 'success' && steps.check-xts-job.outputs.enabled == 'true' }} | |
| uses: step-security/workflow-dispatch@b4c1dc0afa074d0b4f0e653d3b80d4b2798599aa # v1.2.7 | |
| with: | |
| workflow: .github/workflows/zxf-prepare-extended-test-suite.yaml | |
| repo: hiero-ledger/hiero-consensus-node # ensure we are executing in the hiero-ledger org | |
| ref: main # ensure we are always using the workflow definition from the main branch | |
| token: ${{ secrets.GH_ACCESS_TOKEN }} | |
| inputs: '{ | |
| "ref": "${{ inputs.ref }}", | |
| "dry-run-enabled": "${{ inputs.dry-run-enabled }}" | |
| }' | |
| deploy-integration-ci-trigger: | |
| name: Trigger Deploy Integration Flow | |
| runs-on: hl-cn-default-lin-sm | |
| needs: | |
| - release-branch | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout Code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: "0" | |
| ref: ${{ inputs.ref }} | |
| token: ${{ secrets.GH_ACCESS_TOKEN }} | |
| - name: Check Integration Job State | |
| id: check-integration-job | |
| if: ${{ needs.release-branch.result == 'success' && !cancelled() }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| JOB_ENABLED="true" | |
| JOB_STATE=$(gh workflow list --all --json name,state --limit 200 | jq -r '.[]|select(.name=="ZXF: [Node] Deploy Integration Network Release")|.state') | |
| [[ "${JOB_STATE}" == "disabled_manually" ]] && JOB_ENABLED="false" | |
| echo "enabled=${JOB_ENABLED}" >> "${GITHUB_OUTPUT}" | |
| - name: Trigger ZXF Deploy Integration | |
| if: >- | |
| ${{ | |
| inputs.dry-run-enabled == false && | |
| needs.release-branch.result == 'success' && | |
| steps.check-integration-job.outputs.enabled == 'true' && | |
| !cancelled() | |
| }} | |
| uses: step-security/workflow-dispatch@b4c1dc0afa074d0b4f0e653d3b80d4b2798599aa # v1.2.7 | |
| with: | |
| workflow: .github/workflows/node-zxf-deploy-integration.yaml | |
| repo: hiero-ledger/hiero-consensus-node # ensure we are executing in the hiero-ledger org | |
| ref: main # ensure we are always using the workflow definition from the main branch | |
| token: ${{ secrets.GH_ACCESS_TOKEN }} | |
| report-failures: | |
| name: Report Production Release Failures | |
| runs-on: hl-cn-default-lin-sm | |
| needs: | |
| - release-branch | |
| - deploy-xts-ci-trigger | |
| if: | |
| ${{ github.event_name == 'workflow_dispatch' && inputs.dry-run-enabled == false && | |
| (needs.release-branch.result != 'success' || needs.deploy-xts-ci-trigger.result != 'success') && | |
| !cancelled() }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout Code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: "0" | |
| ref: ${{ inputs.ref }} | |
| token: ${{ secrets.GH_ACCESS_TOKEN }} | |
| - name: Collect run logs in a log file | |
| continue-on-error: true | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} | |
| run: | | |
| for job_id in $(gh run view ${{ github.run_id }} --json jobs --jq '.jobs | map(.databaseId) | .[0:-1] | .[]'); do | |
| echo "Fetching logs for job $job_id..." | |
| current_job_name=$(gh run view ${{ github.run_id }} --json jobs | jq --argjson job_id "$job_id" -r '.jobs[] | select(.databaseId == $job_id) | .name') | |
| echo "Logs for job $current_job_name :" >> run.log | |
| gh api \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| /repos/hiero-ledger/hiero-consensus-node/actions/jobs/$job_id/logs >> run.log | |
| done | |
| - name: Upload log as artifact | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| continue-on-error: true | |
| with: | |
| path: run.log | |
| - name: Get Commit Information | |
| id: fetch-commit-info | |
| continue-on-error: true | |
| run: | | |
| echo "commit-hash=${{ inputs.ref }}" >> "${GITHUB_OUTPUT}" | |
| echo "commit-author=$(git show -s --format='%an <%ae>' ${{ inputs.ref }})" >> "${GITHUB_OUTPUT}" | |
| echo "commit-email=$(git show -s --format='%ae' ${{ inputs.ref }})" >> "${GITHUB_OUTPUT}" | |
| - name: Find Commit Author in Slack | |
| id: find-commit-author-slack | |
| continue-on-error: true | |
| env: | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_CITR_BOT_TOKEN }} | |
| EMAIL: ${{ steps.fetch-commit-info.outputs.commit-email }} | |
| run: | | |
| SLACK_USER_ID=$(curl -s -X GET "https://slack.com/api/users.list" \ | |
| -H "Authorization: Bearer ${SLACK_BOT_TOKEN}" | jq -r --arg email "${EMAIL}" \ | |
| '.members[] | select((.profile.email // "" | ascii_downcase) == ($email | ascii_downcase)) | .name') | |
| if [[ -z "${SLACK_USER_ID}" || "${SLACK_USER_ID}" == "null" ]]; then | |
| echo "No Slack user found for email: ${EMAIL}" | |
| SLACK_USER_ID="No matching slack user found" | |
| else | |
| echo "Found slack user for email: ${EMAIL}" | |
| SLACK_USER_ID="<@${SLACK_USER_ID}>" | |
| fi | |
| echo "slack-user-id=${SLACK_USER_ID}" >> "${GITHUB_OUTPUT}" | |
| - name: Build Rootly Summary | |
| id: rootly-summary | |
| run: | | |
| title="Deploy Production Release job failed (${{ inputs.ref-name }} - ${{ inputs.ref }})." | |
| echo "title=${title}" >> "${GITHUB_OUTPUT}" | |
| { | |
| echo 'summary<<EOF' | |
| echo "------------------------------------" | |
| echo "Status of each jobs:" | |
| echo "- Release [Branch]: ${{ needs.release-branch.result }}" | |
| echo "- Deploy XTS CI Trigger: ${{ needs.deploy-xts-ci-trigger.result }}" | |
| echo "------------------------------------" | |
| echo "Commit information:" | |
| echo "- Author: ${{ steps.fetch-commit-info.outputs.commit-author }}" | |
| echo "- Commit: <${{ github.server_url }}/${{ github.repository }}/commit/${{ steps.fetch-commit-info.outputs.commit-hash }}>" | |
| echo "- Workflow: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>" | |
| echo EOF | |
| } >> "${GITHUB_OUTPUT}" | |
| - name: Log Rootly Summary | |
| run: | | |
| echo "## Rootly Summary:" | |
| echo "### Title: ${{ steps.rootly-summary.outputs.title }}" >> "${GITHUB_STEP_SUMMARY}" | |
| echo "${{ steps.rootly-summary.outputs.summary }}" >> "${GITHUB_STEP_SUMMARY}" | |
| echo "### Rootly Service" >> "${GITHUB_STEP_SUMMARY}" | |
| echo "${{ steps.set-rootly-service.outputs.service }}" >> "${GITHUB_STEP_SUMMARY}" | |
| - name: Create Rootly Alert | |
| id: create-rootly-alert | |
| uses: pandaswhocode/rootly-alert-action@fdae1529e5aed62040016accf719a0ceb7dae57f # v1.0.0 | |
| continue-on-error: true | |
| with: | |
| api_key: ${{ secrets.ROOTLY_API_TOKEN }} | |
| summary: "${{ steps.rootly-summary.outputs.title }}" | |
| details: "${{ steps.rootly-summary.outputs.summary }}" | |
| notification_target_type: "Service" | |
| notification_target: "CI/CD Workflows" | |
| set_as_noise: "false" | |
| alert_urgency: "High" | |
| external_id: ${{ github.run_id }} | |
| external_url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| environments: "CITR" | |
| - name: Build Slack Payload Message | |
| id: payload | |
| run: | | |
| cat <<EOF > slack_payload.json | |
| { | |
| "attachments": [ | |
| { | |
| "color": "#FF0000", | |
| "blocks": [ | |
| { | |
| "type": "header", | |
| "text": { | |
| "type": "plain_text", | |
| "text": ":exclamation: Hiero Consensus Node - Deploy Production Release Failure Report", | |
| "emoji": true | |
| } | |
| }, | |
| { | |
| "type": "divider" | |
| }, | |
| { | |
| "type": "section", | |
| "text": { | |
| "type": "mrkdwn", | |
| "text": "*Deploy Production Release job resulted in failure on `main`. See status below.*" | |
| }, | |
| "fields": [ | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Release [Branch]*: ${{ needs.release-branch.result }}" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Deploy XTS CI Trigger*: ${{ needs.deploy-xts-ci-trigger.result }}" | |
| } | |
| ] | |
| }, | |
| { | |
| "type": "divider" | |
| }, | |
| { | |
| "type": "section", | |
| "text": { | |
| "type": "mrkdwn", | |
| "text": "*Workflow and Commit Information*" | |
| }, | |
| "fields": [ | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Source Commit*:" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "<${{ github.server_url }}/${{ github.repository }}/commit/${{ steps.fetch-commit-info.outputs.commit-hash }}>" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Commit author*:" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "${{ steps.fetch-commit-info.outputs.commit-author }}" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Slack user*:" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "${{ steps.find-commit-author-slack.outputs.slack-user-id }}" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Workflow run ID*:" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": " ${{ github.run_id }}" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "*Workflow run URL*:" | |
| }, | |
| { | |
| "type": "mrkdwn", | |
| "text": "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| EOF | |
| - name: Report failure (slack citr-failures) | |
| uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52 # v2.1.0 | |
| with: | |
| webhook: ${{ secrets.SLACK_CITR_FAILURES_WEBHOOK }} | |
| webhook-type: incoming-webhook | |
| payload-templated: true | |
| payload-file-path: slack_payload.json |