GitHub Scheduled Event Processor

name: GitHub Scheduled Event Processor

on:
  schedule:
    # These are generated/confirmed using https://crontab.cronhub.io/
    # Close stale issues, runs every day at 1am - CloseStaleIssues
    - cron: '0 1 * * *'
    # Identify stale pull requests, every Friday at 5am - IdentifyStalePullRequests
    - cron: '0 5 * * FRI'
    # Close stale pull requests, every 6 hours at 02:30 AM, 08:30 AM, 02:30 PM and 08:30 PM - CloseStalePullRequests
    - cron: '30 2,8,14,20 * * *'
    # Identify stale issues, every 6 hours at 03:30 AM, 09:30 AM, 03:30 PM and 09:30 PM - IdentifyStaleIssues
    - cron: '30 3,9,15,21 * * *'
    # Close addressed issues, every 6 hours at 04:30 AM, 10:30 AM, 04:30 PM and 10:30 PM - CloseAddressedIssues
    - cron: '30 4,10,16,22 * * *'
    # Lock closed issues, every 6 hours at 05:30 AM, 11:30 AM, 05:30 PM and 11:30 PM - LockClosedIssues
    - cron: '30 5,11,17,23 * * *'
    # Enforce max life of issues, every M,W,F at 10:00 AM PST - EnforceMaxLifeOfIssues
    # Note: GitHub uses UTC, to run at 10am PST, the cron task needs to be 6pm (1800 hours) UTC
    #       When scheduling for multiple days the numeric days 0-6 (0=Sunday) must be used.
    - cron: '0 18 * * 1,3,5'
# This removes all unnecessary permissions, the ones needed will be set below.
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
permissions: {}

jobs:
  event-handler:
    permissions:
      issues: write
      pull-requests: write
    name: Handle ${{ github.event.schedule }} ${{ github.event.action }} event
    runs-on: ubuntu-latest
    steps:
      # To run github-event-processor built from source, for testing purposes, uncomment everything
      # in between the Start/End-Build From Source comments and comment everything in between the
      # Start/End-Install comments
      # Start-Install
      - name: Install GitHub Event Processor
        run: >
          dotnet tool install
          Azure.Sdk.Tools.GitHubEventProcessor
          --version 1.0.0-dev.20240610.2
          --add-source https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json
          --global
        shell: bash
      # End-Install

      # Testing checkout of sources from the Azure/azure-sdk-tools repository
      # The ref: is the SHA from the pull request in that repository or the
      # refs/pull/<PRNumber>/merge for the latest on any given PR. If the repository
      # is a fork eg. <User>/azure-sdk-tools then the repository down below will
      # need to point to that fork
      # Start-Build
      # - name: Checkout tools repo for GitHub Event Processor sources
      #   uses: actions/checkout@v3
      #   with:
      #     repository: Azure/azure-sdk-tools
      #     path: azure-sdk-tools
      #     ref: <refs/pull/<PRNumber>/merge> or <sha>

      # - name: Build and install GitHubEventProcessor from sources
      #   run: |
      #     dotnet pack
      #     dotnet tool install --global --prerelease --add-source ../../../artifacts/packages/Debug Azure.Sdk.Tools.GitHubEventProcessor
      #   shell: bash
      #   working-directory: azure-sdk-tools/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor
      # End-Build

      - name: Close Stale Issues Scheduled Event
        if: github.event.schedule == '0 1 * * *'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json CloseStaleIssues
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Identify Stale PullRequests Scheduled Event
        if: github.event.schedule == '0 5 * * FRI'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json IdentifyStalePullRequests
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Close Stale PullRequests Scheduled Event
        if: github.event.schedule == '30 2,8,14,20 * * *'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json CloseStalePullRequests
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Identify Stale Issues Scheduled Event
        if: github.event.schedule == '30 3,9,15,21 * * *'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json IdentifyStaleIssues
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Close Addressed Issues Scheduled Event
        if: github.event.schedule == '30 4,10,16,22 * * *'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json CloseAddressedIssues
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Lock Closed Issues Scheduled Event
        if: github.event.schedule == '30 5,11,17,23 * * *'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json LockClosedIssues
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Enforce Max Life of Issues Scheduled Event
        if: github.event.schedule == '0 18 * * 1,3,5'
        run: |
          cat > payload.json << 'EOF'
          ${{ toJson(github.event) }}
          EOF
          github-event-processor ${{ github.event_name }} payload.json EnforceMaxLifeOfIssues
        shell: bash
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


Node: PR Checks

##
# Copyright (C) 2022-2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

name: "Node: PR Checks"
on:
  workflow_dispatch:
  pull_request:
    types:
      - opened
      - reopened
      - synchronize

defaults:
  run:
    shell: bash

concurrency:
  group: pr-checks-${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

jobs:
  build:
    name: Code
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    with:
      enable-spotless-check: false
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  dependency-check:
    name: Dependency (Module Info)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - build
    with:
      custom-job-label: "Check"
      enable-dependency-check: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  spotless:
    name: Spotless
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - build
    with:
      custom-job-label: "Check"
      enable-unit-tests: false
      enable-spotless-check: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  unit-tests:
    name: Unit Tests
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}
      codacy-project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
      codecov-token: ${{ secrets.CODECOV_TOKEN }}

  hapi-tests-misc:
    name: HAPI Tests (Misc)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-misc: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  hapi-tests-crypto:
    name: HAPI Tests (Crypto)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-crypto: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  hapi-tests-token:
    name: HAPI Tests (Token)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-token: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  hapi-tests-smart-contract:
    name: HAPI Tests (Smart Contract)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-smart-contract: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  hapi-tests-time-consuming:
    name: HAPI Tests (Time Consuming)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-time-consuming: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  hapi-tests-restart:
    name: HAPI Tests (Restart)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-restart: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  hapi-tests-nd-reconnect:
    name: HAPI Tests (Node Death Reconnect)
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-hapi-tests-nd-reconnect: true
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  abbreviated-panel:
    name: JRS Panel
    uses: ./.github/workflows/zxc-jrs-regression.yaml
    needs:
      - dependency-check
      - spotless
    if: ${{ github.event_name != 'pull_request' || (github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository) }}
    with:
      custom-job-name: "Platform SDK"
      panel-config: "configs/suites/GCP-PRCheck-Abbrev-4N.json"
      branch-name: ${{ github.head_ref || github.ref_name }}
      base-branch-name: ${{ github.base_ref || '' }}
      slack-results-channel: "regression-test"
      slack-summary-channel: "regression-test"
      use-branch-for-slack-channel: false
    secrets:
      access-token: ${{ secrets.PLATFORM_GH_ACCESS_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}
      jrs-ssh-user-name: ${{ secrets.PLATFORM_JRS_SSH_USER_NAME }}
      jrs-ssh-key-file: ${{ secrets.PLATFORM_JRS_SSH_KEY_FILE }}
      gcp-project-number: ${{ secrets.PLATFORM_GCP_PROJECT_NUMBER }}
      gcp-sa-key-contents: ${{ secrets.PLATFORM_GCP_KEY_FILE }}
      slack-api-token: ${{ secrets.PLATFORM_SLACK_API_TOKEN }}
      grafana-agent-username: ${{ secrets.GRAFANA_AGENT_USERNAME }}
      grafana-agent-password: ${{ secrets.GRAFANA_AGENT_PASSWORD }}

  hedera-node-jrs-panel:
    name: Hedera Node JRS Panel
    uses: ./.github/workflows/zxc-jrs-regression.yaml
    needs:
      - dependency-check
      - spotless
    if: ${{ github.event_name != 'pull_request' || (github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository) }}
    with:
      custom-job-name: "Network Error Tests"
      branch-name: ${{ github.head_ref || github.ref_name }}
      hedera-tests-enabled: true
      use-branch-for-slack-channel: false
      panel-config: "configs/services/suites/daily/GCP-Daily-Services-Comp-NetError-4N-1C.json"
    secrets:
      access-token: ${{ secrets.PLATFORM_GH_ACCESS_TOKEN }}
      jrs-ssh-user-name: ${{ secrets.PLATFORM_JRS_SSH_USER_NAME }}
      jrs-ssh-key-file: ${{ secrets.PLATFORM_JRS_SSH_KEY_FILE }}
      gcp-project-number: ${{ secrets.PLATFORM_GCP_PROJECT_NUMBER }}
      gcp-sa-key-contents: ${{ secrets.PLATFORM_GCP_KEY_FILE }}
      slack-api-token: ${{ secrets.PLATFORM_SLACK_API_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}
      grafana-agent-username: ${{ secrets.GRAFANA_AGENT_USERNAME }}
      grafana-agent-password: ${{ secrets.GRAFANA_AGENT_PASSWORD }}

  snyk-scan:
    name: Snyk Scan
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    needs:
      - dependency-check
      - spotless
    if: ${{ github.event_name != 'pull_request' || (github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository) }}
    with:
      custom-job-label: Standard
      enable-unit-tests: false
      enable-snyk-scan: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}
      snyk-token: ${{ secrets.SNYK_TOKEN }}

  gradle-determinism:
    name: Gradle Determinism
    uses: ./.github/workflows/zxc-verify-gradle-build-determinism.yaml
    needs:
      - dependency-check
      - spotless
    if: ${{ github.event_name != 'pull_request' || (github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository) }}
    with:
      ref: ${{ github.event.inputs.ref || '' }}
      java-distribution: temurin
      java-version: 21.0.1
    secrets:
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}

  docker-determinism:
    name: Docker Determinism
    uses: ./.github/workflows/zxc-verify-docker-build-determinism.yaml
    needs:
      - dependency-check
      - spotless
    if: ${{ github.event_name != 'pull_request' || (github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name == github.repository) }}
    with:
      ref: ${{ github.event.inputs.ref || '' }}
      java-distribution: temurin
      java-version: 21.0.1
    secrets:
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}


Node: Build Application

##
# Copyright (C) 2022-2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

name: "Node: Build Application"
on:
  workflow_dispatch:
    inputs:
      enable-unit-tests:
        description: "Unit Testing Enabled"
        type: boolean
        required: false
        default: true
      enable-integration-tests:
        description: "Integration Testing Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests:
        description: "HAPI Testing Enabled"
        type: boolean
        required: false
        default: false
      enable-e2e-tests:
        description: "E2E Testing Enabled"
        type: boolean
        required: false
        default: false
      enable-spotless-check:
        description: "Spotless Check Enabled"
        type: boolean
        required: false
        default: false
      enable-snyk-scan:
        description: "Snyk Scan Enabled"
        type: boolean
        required: false
        default: false
      java-version:
        description: "Java JDK Version:"
        type: string
        required: false
        default: "21.0.1"
      java-distribution:
        description: "Java JDK Distribution:"
        type: string
        required: false
        default: "temurin"
  push:
    branches:
      - develop
      - main
      - 'release/*'

defaults:
  run:
    shell: bash

jobs:
  code:
    name: Code
    uses: ./.github/workflows/node-zxc-compile-application-code.yaml
    with:
      java-version: ${{ github.event.inputs.java-version || '21.0.1' }}
      java-distribution: ${{ github.event.inputs.java-distribution || 'temurin' }}
      enable-unit-tests: ${{ github.event_name == 'push' || github.event.inputs.enable-unit-tests == 'true' }}
      enable-integration-tests: ${{ github.event.inputs.enable-integration-tests == 'true' }}
      enable-hapi-tests-misc: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-hapi-tests-crypto: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-hapi-tests-token: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-hapi-tests-smart-contract: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-hapi-tests-time-consuming: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-hapi-tests-restart: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-hapi-tests-nd-reconnect: ${{ github.event.inputs.enable-hapi-tests == 'true' }}
      enable-e2e-tests: ${{ github.event.inputs.enable-e2e-tests == 'true' }}
      enable-spotless-check: ${{ github.event.inputs.enable-spotless-check == 'true' }}
      enable-snyk-scan: ${{ github.event_name == 'push' || github.event.inputs.enable-snyk-scan == 'true' }}
      enable-network-log-capture: true
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      snyk-token: ${{ secrets.SNYK_TOKEN }}
      codacy-project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
      gradle-cache-username: ${{ secrets.GRADLE_CACHE_USERNAME }}
      gradle-cache-password: ${{ secrets.GRADLE_CACHE_PASSWORD }}
      codecov-token: ${{ secrets.CODECOV_TOKEN }}


ZXF: Deploy Production Release

##
# Copyright (C) 2022-2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

name: "ZXF: Deploy Production Release"
on:
  push:
    branches:
      - develop
    tags:
      - "v[0-9]+.[0-9]+.[0-9]+-?*"

defaults:
  run:
    shell: bash

jobs:
  prepare-tag-release:
    name: Prepare Release [Tag]
    runs-on: [self-hosted, Linux, medium, ephemeral]
    if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
    outputs:
      version: ${{ steps.tag.outputs.version }}
      prerelease: ${{ steps.tag.outputs.prerelease }}
    steps:
      - 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}"

      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Verify HAPI version
        run: |
          TAG_MAJOR="$(semver get major "${{ github.ref_name }}")"
          TAG_MINOR="$(semver get minor "${{ github.ref_name }}")"
          HAPI_VERSION=$(grep "val hapiProtoVersion = " settings.gradle.kts | sed -E 's/.+ = "(.+)"/\1/')
          HAPI_MAJOR="$(semver get major ${HAPI_VERSION})"
          HAPI_MINOR="$(semver get minor ${HAPI_VERSION})"
          if [[ "${TAG_MAJOR}" != "${HAPI_MAJOR}" || "${TAG_MINOR}" != "${HAPI_MINOR}" ]]; then
             echo "::error title=HAPI Version Mismatch::The tag version (${TAG_MAJOR}.${TAG_MINOR}) does not match the hapiProtoVersion (${HAPI_MAJOR}.${HAPI_MINOR}) specified in settings.gradle.kts"
             exit 1
          else
             echo "The tag version (${TAG_MAJOR}.${TAG_MINOR}) matches the hapiProtoVersion (${HAPI_MAJOR}.${HAPI_MINOR}) specified in settings.gradle.kts"
          fi

  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' }}
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      bucket-name: ${{ secrets.RELEASE_ARTIFACT_BUCKET_NAME }}
      cdn-bucket-name: ${{ secrets.CDN_ARTIFACT_BUCKET_NAME }}
      svcs-ossrh-username: ${{ secrets.SVCS_OSSRH_USERNAME }}
      svcs-ossrh-password: ${{ secrets.SVCS_OSSRH_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.PLATFORM_SLACK_RELEASE_WEBHOOK }}
      jenkins-integration-url: ${{ secrets.RELEASE_JENKINS_INTEGRATION_URL }}
      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 }}

  release-branch:
    name: Release [Branch]
    uses: ./.github/workflows/node-zxc-build-release-artifact.yaml
    if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/v') }}
    with:
      version-policy: branch-commit
      trigger-env-deploy: integration
      release-profile: DevelopCommit
    secrets:
      access-token: ${{ secrets.GITHUB_TOKEN }}
      bucket-name: ${{ secrets.RELEASE_ARTIFACT_BUCKET_NAME }}
      cdn-bucket-name: ${{ secrets.CDN_ARTIFACT_BUCKET_NAME }}
      svcs-ossrh-username: ${{ secrets.SVCS_OSSRH_USERNAME }}
      svcs-ossrh-password: ${{ secrets.SVCS_OSSRH_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.PLATFORM_SLACK_RELEASE_WEBHOOK }}
      jenkins-integration-url: ${{ secrets.RELEASE_JENKINS_INTEGRATION_URL }}
      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 }}


ZXC: [Node] Deploy Release Artifacts

##
# Copyright (C) 2022-2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

name: "ZXC: [Node] Deploy Release Artifacts"
on:
  workflow_call:
    inputs:
      # Valid version policies are as follows: specified, branch-commit, adhoc-commit
      version-policy:
        description: "Version Policy:"
        type: string
        required: true
      # Valid options are none, integration, and preview
      trigger-env-deploy:
        description: "Deploy to Environment:"
        type: string
        required: true
        default: "none"
      # Valid release profiles are as follows:
      # - none
      # - AdhocCommit
      # - DevelopCommit
      # - DevelopDailySnapshot
      # - DevelopSnapshot
      # - PrereleaseChannel
      release-profile:
        description: "Release Profile:"
        type: string
        required: true
        default: "none"
      new-version:
        description: "New Version:"
        type: string
        required: false
      dry-run-enabled:
        description: "Perform Dry Run"
        type: boolean
        required: false
        default: false
      java-distribution:
        description: "Java JDK Distribution:"
        type: string
        required: false
        default: "temurin"
      java-version:
        description: "Java JDK Version:"
        type: string
        required: false
        default: "21.0.1"
      gradle-version:
        description: "Gradle Version:"
        type: string
        required: false
        default: "wrapper"

    secrets:
      access-token:
        required: true
      bucket-name:
        required: true
      cdn-bucket-name:
        required: true
      svcs-ossrh-username:
        required: true
      svcs-ossrh-password:
        required: true
      svcs-gpg-key-contents:
        required: true
      svcs-gpg-key-passphrase:
        required: true
      sdk-ossrh-username:
        required: true
      sdk-ossrh-password:
        required: true
      sdk-gpg-key-contents:
        required: true
      sdk-gpg-key-passphrase:
        required: true
      slack-webhook-url:
        required: true
      jf-url:
        required: true
      jf-user-name:
        required: true
      jf-docker-registry:
        required: true
      jf-access-token:
        required: true
      jenkins-integration-url:
        required: false

defaults:
  run:
    shell: bash

env:
  LC_ALL: C.UTF-8
  DOCKER_MANIFEST_GENERATOR: .github/workflows/support/scripts/generate-docker-artifact-baseline.sh
  DOCKER_MANIFEST_PATH: ${{ github.workspace }}/.manifests/docker
  SKOPEO_VERSION: v1.14.0

permissions:
  id-token: write
  contents: read

jobs:
  validate:
    name: Validate
    runs-on: [ self-hosted, Linux, large, ephemeral ]
    outputs:
      branch-name: ${{ steps.parameters.outputs.branch-name }}
      branch-name-lower: ${{ steps.parameters.outputs.branch-name-lower }}
      branch-name-safe: ${{ steps.parameters.outputs.branch-name-safe }}
      commit-prefix: ${{ steps.parameters.outputs.commit-prefix }}
      commit-id: ${{ steps.parameters.outputs.commit-id }}
      commit-id-short: ${{ steps.parameters.outputs.commit-id-short }}
      version: ${{ steps.effective-version.outputs.number }}
      version-prefix: ${{ steps.effective-version.outputs.prefix }}
      prerelease: ${{ steps.effective-version.outputs.prerelease }}
    steps:
      - 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: Verify Workflow Parameters
        id: parameters
        run: |
          BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
          BRANCH_NAME="${BRANCH_NAME##origin/}"
          BRANCH_NAME_LOWER="$(echo "${BRANCH_NAME}" | tr '[:upper:]' '[:lower:]')"
          BRANCH_NAME_SAFE="$(echo "${BRANCH_NAME_LOWER}" | tr '/' '-' | tr '_' '.')"

          COMMIT_PREFIX="adhoc"
          [[ "${{ inputs.version-policy }}" == "branch-commit" ]] && COMMIT_PREFIX="${BRANCH_NAME_SAFE}"

          echo "branch-name=${BRANCH_NAME}" >>"${GITHUB_OUTPUT}"
          echo "branch-name-lower=${BRANCH_NAME_LOWER}" >>"${GITHUB_OUTPUT}"
          echo "branch-name-safe=${BRANCH_NAME_SAFE}" >>"${GITHUB_OUTPUT}"
          echo "commit-prefix=${COMMIT_PREFIX}" >>"${GITHUB_OUTPUT}"
          echo "commit-id=${{ github.sha }}" >>"${GITHUB_OUTPUT}"
          echo "commit-id-short=$(echo "${{ github.sha }}" | cut -c1-8)" >>"${GITHUB_OUTPUT}"

      - name: Verify Version Update (As Specified)
        if: ${{ inputs.version-policy == 'specified' && !cancelled() && !failure() }}
        run: |
          VALID_VERSION="$(semver validate "${{ inputs.new-version }}")"

          if [[ "${VALID_VERSION}" != "valid" ]]; then
            echo "::error title=Version Error::The supplied new-version parameter (${{ inputs.new-version }}) is invalid and does not conform to the semantic versioning specifications."
            exit 2
          fi

      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Setup Java
        uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
        with:
          distribution: ${{ inputs.java-distribution }}
          java-version: ${{ inputs.java-version }}

      - name: Setup Gradle
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}

      - name: Gradle Update Version (As Specified)
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        if: ${{ inputs.version-policy == 'specified' && !cancelled() && !failure() }}
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: versionAsSpecified -PnewVersion=${{ inputs.new-version }} --scan

      - name: Gradle Update Version (Branch Commit)
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        if: ${{ inputs.version-policy != 'specified' && !cancelled() && !failure() }}
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: versionAsPrefixedCommit -PcommitPrefix=${{ steps.parameters.outputs.commit-prefix }} --scan

      - name: Compute Final Effective Version
        id: effective-version
        run: |
          EFF_VERSION="$(./gradlew showVersion --quiet | tr -d '[:space:]')"
          PRERELEASE_SUFFIX="$(semver get prerel "${EFF_VERSION}")"
          PRERELEASE="false"
          [[ -n "${PRERELEASE_SUFFIX}" ]] && PRERELEASE="true"

          MAJOR_VERSION="$(semver get major "${EFF_VERSION}")"
          MINOR_VERSION="$(semver get minor "${EFF_VERSION}")"

          echo "number=${EFF_VERSION}" >>"${GITHUB_OUTPUT}"
          echo "prefix=${MAJOR_VERSION}.${MINOR_VERSION}" >>"${GITHUB_OUTPUT}"
          echo "prerelease=${PRERELEASE}" >>"${GITHUB_OUTPUT}"

      - name: Cache Build Version
        uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
        with:
          path: version.txt
          key: node-build-version-${{ steps.effective-version.outputs.number }}-${{ github.sha }}

  build-artifact:
    name: Build Artifact
    runs-on: [self-hosted, Linux, large, ephemeral]
    needs:
      - validate
    steps:
      - name: Install Deterministic Zip Tooling
        run: |
          echo "::group::Download Binary"
          sudo curl -L -o /usr/local/bin/deterministic-zip https://github.com/timo-reymann/deterministic-zip/releases/download/1.2.0/deterministic-zip_linux-amd64
          echo "::endgroup::"
          echo "::group::Change Binary Permissions"
          sudo chmod -v +x /usr/local/bin/deterministic-zip
          echo "::endgroup::"
          echo "::group::Show Binary Version Info"
          deterministic-zip --version
          echo "::endgroup::"

      - name: Install JSON Tools
        run: |
          if ! command -v jq >/dev/null 2>&1; then
            echo "::group::Setup JQ Command"
            sudo apt update
            sudo apt install -y jq
            echo "::endgroup::"
          fi

          JQ_VERSION="$(jq --version)"
          if [[ "${JQ_VERSION}" != "jq-1.6" ]]; then
            echo "::group::Updating JQ Version"
            sudo apt update
            sudo apt upgrade -y jq
            echo "::endgroup::"
          fi

          if ! command -v tee >/dev/null 2>&1; then
            echo "::group::Setup Tee Command"
            sudo apt update
            sudo apt install -y coreutils
            echo "::endgroup::"
          fi

          echo "::group::Show JQ Version"
          jq --version
          echo "::endgroup::"

      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2
        if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}
        with:
          workload_identity_provider: "projects/235822363393/locations/global/workloadIdentityPools/hedera-builds-pool/providers/hedera-builds-gh-actions"
          service_account: "hedera-artifact-builds@devops-1-254919.iam.gserviceaccount.com"

      - name: Setup Google Cloud SDK
        uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200 # v2.1.0
        if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}

      - name: Setup Java
        uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
        with:
          distribution: ${{ inputs.java-distribution }}
          java-version: ${{ inputs.java-version }}

      - name: Setup Gradle
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}

      - name: Restore Build Version
        uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
        with:
          fail-on-cache-miss: true
          path: version.txt
          key: node-build-version-${{ needs.validate.outputs.version }}-${{ github.sha }}

      - name: Cache Build Artifacts
        uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
        with:
          path: ~/artifact-build
          key: node-build-artifacts-${{ needs.validate.outputs.version }}-${{ github.sha }}

      - name: Gradle Assemble
        id: gradle-build
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: assemble --scan

      - name: Gradle Version Summary
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: githubVersionSummary --scan

      - name: Stage Artifact Build Folder
        id: artifact-staging
        run: |
          BUILD_BASE_DIR="${HOME}/artifact-build"
          mkdir -p "${BUILD_BASE_DIR}/data/lib"
          mkdir -p "${BUILD_BASE_DIR}/data/apps"

          cp -f hedera-node/data/lib/*.jar "${BUILD_BASE_DIR}/data/lib"
          cp -f hedera-node/data/apps/*.jar "${BUILD_BASE_DIR}/data/apps"
          cp -f hedera-node/configuration/update/immediate.sh "${BUILD_BASE_DIR}"
          cp -f hedera-node/configuration/update/during-freeze.sh "${BUILD_BASE_DIR}"

          echo "folder=${BUILD_BASE_DIR}" >>"${GITHUB_OUTPUT}"

      - name: Write Artifact Version Descriptor
        working-directory: ${{ steps.artifact-staging.outputs.folder }}
        run: |
          printf "VERSION=%s\nCOMMIT=%s\nDATE=%s" "${{ needs.validate.outputs.version }}" "${{ needs.validate.outputs.commit-id-short }}" "$(date -u)" | tee VERSION

      - name: Create Artifact Archive
        id: artifact-release
        working-directory: ${{ steps.artifact-staging.outputs.folder }}
        run: |
          POLICY="${{ inputs.version-policy }}"
          ARTIFACT_BASE_DIR="${HOME}/artifact-release"
          mkdir -p "${ARTIFACT_BASE_DIR}"

          if [[ "${POLICY}" == "branch-commit"  ]]; then
            ARTIFACT_NAME="build-${{ needs.validate.outputs.branch-name-safe }}-${{ needs.validate.outputs.commit-id-short }}"
          else
            ARTIFACT_NAME="build-v${{ needs.validate.outputs.version }}"
          fi

          ARTIFACT_FILE="${ARTIFACT_BASE_DIR}/${ARTIFACT_NAME}.zip"
          deterministic-zip -D -vr "${ARTIFACT_FILE}" *

          echo "folder=${ARTIFACT_BASE_DIR}" >>"${GITHUB_OUTPUT}"
          echo "name=${ARTIFACT_NAME}" >>"${GITHUB_OUTPUT}"
          echo "file=${ARTIFACT_FILE}" >>"${GITHUB_OUTPUT}"

      - name: Compute SHA Hash
        working-directory: ${{ steps.artifact-release.outputs.folder }}
        run: |
          ARTIFACT_NAME="${{ steps.artifact-release.outputs.name }}"
          sha384sum "${ARTIFACT_NAME}.zip" | tee "${ARTIFACT_NAME}.sha384"

      - name: Upload Artifacts (DevOps GCP Bucket)
        uses: google-github-actions/upload-cloud-storage@22121cd842b0d185e042e28d969925b538c33d77 # v2.1.0
        if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}
        with:
          path: ${{ steps.artifact-release.outputs.folder }}
          destination: ${{ secrets.bucket-name }}
          parent: false

      - name: Upload Artifacts (CDN Bucket)
        uses: google-github-actions/upload-cloud-storage@22121cd842b0d185e042e28d969925b538c33d77 # v2.1.0
        if: ${{ inputs.dry-run-enabled != true && needs.validate.outputs.prerelease != 'true' && !cancelled() && !failure() }}
        with:
          path: ${{ steps.artifact-release.outputs.folder }}
          destination: ${{ secrets.cdn-bucket-name }}/node/software/v${{ needs.validate.outputs.version-prefix }}/
          parent: false

      - name: Notify Jenkins of Release (Integration)
        id: jenkins-integration
        uses: fjogeleit/http-request-action@0bd00a33db6f82063a3c6befd41f232f61d66583 # v1.15.2
        if: ${{ inputs.dry-run-enabled != true && inputs.trigger-env-deploy == 'integration' && !cancelled() && !failure() }}
        with:
          url: ${{ secrets.jenkins-integration-url }}
          data: ${{ toJSON(github.event) }}

      - name: Display Jenkins Payload
        env:
          JSON_RESPONSE: ${{ steps.jenkins-integration.outputs.response || steps.jenkins-preview.outputs.response }}
        if: ${{ inputs.trigger-env-deploy == 'integration' }}
        run: |
          jq '.' <<<"${JSON_RESPONSE}"
          printf "### Jenkins Response Payload\n\`\`\`json\n%s\n\`\`\`\n" "$(jq '.' <<<"${JSON_RESPONSE}")" >>"${GITHUB_STEP_SUMMARY}"

      - name: Check for Jenkins Failures (Integration)
        if: ${{ inputs.trigger-env-deploy == 'integration' }}
        env:
          JSON_RESPONSE: ${{ steps.jenkins-integration.outputs.response }}
        run: |
          INTEGRATION_TRIGGERED="$(jq '.jobs."build-upgrade-integration".triggered' <<<"${JSON_RESPONSE}")"
          DOCKER_TRIGGERED="$(jq '.jobs."build-upgrade-integration-docker".triggered' <<<"${JSON_RESPONSE}")"

          if [[ "${INTEGRATION_TRIGGERED}" != true ]]; then
            echo "::error title=Jenkins Trigger Failure::Failed to trigger the 'build-upgrade-integration' job via the Jenkins 'integration' pipeline!"
            exit 1
          fi

          if [[ "${DOCKER_TRIGGERED}" != true ]]; then
            echo "::error title=Jenkins Trigger Failure::Failed to trigger the 'build-upgrade-integration-docker' job via the Jenkins 'integration' pipeline!"
            exit 1
          fi

  local-node-images:
    name: Publish Local Node Images
    runs-on: [ self-hosted, Linux, large, ephemeral ]
    needs:
      - validate
      - build-artifact
    steps:
      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Authenticate to Google Cloud
        id: google-auth
        uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2
        if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}
        with:
          token_format: 'access_token'
          workload_identity_provider: "projects/235822363393/locations/global/workloadIdentityPools/hedera-builds-pool/providers/hedera-builds-gh-actions"
          service_account: "swirlds-automation@hedera-registry.iam.gserviceaccount.com"

      - name: Set Image Registry
        id: set-registry
        run: |
         DOCKER_REGISTRY="gcr.io"
         [[ "${{ inputs.version-policy }}" == "branch-commit" ]] && DOCKER_REGISTRY="us-docker.pkg.dev"
         echo "docker-registry=${DOCKER_REGISTRY}" >>"${GITHUB_OUTPUT}"

         DOCKER_TAG_BASE="gcr.io/hedera-registry"
         if [[ "${{ inputs.version-policy }}" == "branch-commit" && "${{ inputs.dry-run-enabled }}" != true ]]; then
            DOCKER_TAG_BASE="us-docker.pkg.dev/swirlds-registry/local-node"
         elif [[ "${{ inputs.dry-run-enabled }}" == true ]]; then
            DOCKER_TAG_BASE="localhost:5000"
         fi

         echo "docker-tag-base=${DOCKER_TAG_BASE}" >>"${GITHUB_OUTPUT}"

      - name: Setup QEmu Support
        uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0

      - name: Setup Docker Buildx Support
        uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
        with:
          driver-opts: network=host

      - name: Setup Local Docker Registry
        if: ${{ inputs.dry-run-enabled == true && !cancelled() && !failure() }}
        run: docker run -d -p 5000:5000 --restart=always --name registry registry:latest

      - name: Docker Login
        uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
        if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}
        with:
          registry: ${{ steps.set-registry.outputs.docker-registry }}
          username: oauth2accesstoken
          password: ${{ steps.google-auth.outputs.access_token }}

      - name: Restore Build Artifacts
        uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
        with:
          fail-on-cache-miss: true
          path: ~/artifact-build
          key: node-build-artifacts-${{ needs.validate.outputs.version }}-${{ github.sha }}

      - name: Stage SDK Artifacts
        run: |
          mkdir -p hedera-node/infrastructure/docker/containers/local-node/main-network-node/sdk
          cp -rvf ~/artifact-build/* hedera-node/infrastructure/docker/containers/local-node/main-network-node/sdk/

      - name: Build Haveged Image
        uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
        with:
          push: true
          platforms: linux/amd64,linux/arm64
          context: hedera-node/infrastructure/docker/containers/local-node/network-node-haveged
          tags: ${{ steps.set-registry.outputs.docker-tag-base }}/network-node-haveged:${{ needs.validate.outputs.version }}

      - name: Build Base Image
        uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
        with:
          push: true
          platforms: linux/amd64,linux/arm64
          context: hedera-node/infrastructure/docker/containers/local-node/network-node-base
          tags: ${{ steps.set-registry.outputs.docker-tag-base }}/network-node-base:${{ needs.validate.outputs.version }}

      - name: Build Network Node Image
        uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
        with:
          push: true
          platforms: linux/amd64,linux/arm64
          build-args: |
           IMAGE_TAG=${{ needs.validate.outputs.version }}
           IMAGE_PREFIX=${{ steps.set-registry.outputs.docker-tag-base }}/
          context: hedera-node/infrastructure/docker/containers/local-node/main-network-node
          tags: ${{ steps.set-registry.outputs.docker-tag-base }}/main-network-node:${{ needs.validate.outputs.version }}

      - name: Render Job Summary
        run: |
          NETWORK_NODE_BASE_LINK="Not Applicable"
          NETWORK_NODE_HAVEGED_LINK="Not Applicable"
          NETWORK_NODE_MAIN_LINK="Not Applicable"

          if [[ "${{ inputs.dry-run-enabled }}" != true ]]; then
            NETWORK_NODE_BASE_LINK="[GCP Console](https://${{ steps.set-registry.outputs.docker-tag-base }}/network-node-base:${{ needs.validate.outputs.version }})"
            NETWORK_NODE_HAVEGED_LINK="[GCP Console](https://${{ steps.set-registry.outputs.docker-tag-base }}/network-node-haveged:${{ needs.validate.outputs.version }})"
            NETWORK_NODE_MAIN_LINK="[GCP Console](https://${{ steps.set-registry.outputs.docker-tag-base }}/main-network-node:${{ needs.validate.outputs.version }})"
          fi

          printf "### Published Docker Images\n" >> "${GITHUB_STEP_SUMMARY}"
          printf "| Image Name | Version | URL | Supported Architectures |\n" >> "${GITHUB_STEP_SUMMARY}"
          printf "| ---------- | ------- | --- | ----------------------- |\n" >> "${GITHUB_STEP_SUMMARY}"
          printf "| %s | %s | %s | %s |\n" \
            "${{ steps.set-registry.outputs.docker-tag-base }}/network-node-base" \
            "${{ needs.validate.outputs.version }}" \
            "${NETWORK_NODE_BASE_LINK}" \
            "linux/amd64, linux/arm64" >> "${GITHUB_STEP_SUMMARY}"

          printf "| %s | %s | %s | %s |\n" \
            "${{ steps.set-registry.outputs.docker-tag-base }}/network-node-haveged" \
            "${{ needs.validate.outputs.version }}" \
            "${NETWORK_NODE_HAVEGED_LINK}" \
            "linux/amd64, linux/arm64" >> "${GITHUB_STEP_SUMMARY}"

          printf "| %s | %s | %s | %s |\n" \
            "${{ steps.set-registry.outputs.docker-tag-base }}/main-network-node" \
            "${{ needs.validate.outputs.version }}" \
            "${NETWORK_NODE_MAIN_LINK}" \
            "linux/amd64, linux/arm64" >> "${GITHUB_STEP_SUMMARY}"

          printf "\n\n" >> "${GITHUB_STEP_SUMMARY}"

  gcp-production-image:
    name: Publish Production Image
    uses: ./.github/workflows/zxc-publish-production-image.yaml
    needs:
      - validate
      - build-artifact
    with:
      version: ${{ needs.validate.outputs.version }}
      version-policy: ${{ inputs.version-policy }}
      dry-run-enabled: ${{ inputs.dry-run-enabled }}
      registry-name: gcp
      custom-job-name: "Publish Production Image (GCP)"
    secrets:
      jf-url: ${{ secrets.jf-url }}
      jf-user-name: ${{ secrets.jf-user-name }}
      jf-docker-registry: ${{ secrets.jf-docker-registry }}
      jf-access-token: ${{ secrets.jf-access-token }}

  jfr-production-image:
    name: Publish Production Image
    uses: ./.github/workflows/zxc-publish-production-image.yaml
    needs:
      - validate
      - build-artifact
    with:
      version: ${{ needs.validate.outputs.version }}
      version-policy: ${{ inputs.version-policy }}
      dry-run-enabled: ${{ inputs.dry-run-enabled }}
      registry-name: jfrog
      custom-job-name: "Publish Production Image (JFrog)"
    secrets:
      jf-url: ${{ secrets.jf-url }}
      jf-user-name: ${{ secrets.jf-user-name }}
      jf-docker-registry: ${{ secrets.jf-docker-registry }}
      jf-access-token: ${{ secrets.jf-access-token }}

  validate-production-image:
    name: Validate Production Image
    runs-on: [ self-hosted, Linux, large, ephemeral ]
    needs:
      - gcp-production-image
      - jfr-production-image
    if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}
    steps:
      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Authenticate to Google Cloud
        id: google-auth
        uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2
        with:
          token_format: 'access_token'
          workload_identity_provider: "projects/235822363393/locations/global/workloadIdentityPools/hedera-builds-pool/providers/hedera-builds-gh-actions"
          service_account: "swirlds-automation@hedera-registry.iam.gserviceaccount.com"

      - name: Setup JFrog CLI
        uses: jfrog/setup-jfrog-cli@d82fe26823e1f25529250895d5673f65b02af085 # v4.0.1
        env:
          JF_URL: ${{ secrets.jf-url }}
          JF_ACCESS_TOKEN: ${{ secrets.jf-access-token }}

      - name: Show JFrog Config
        run: jfrog config show

      - name: Verify JFrog Connectivity
        run: jfrog rt ping

      - name: Docker Login (GCP)
        uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
        with:
          registry: ${{ needs.gcp-production-image.outputs.docker-registry }}
          username: oauth2accesstoken
          password: ${{ steps.google-auth.outputs.access_token }}

      - name: Docker Login (JFrog)
        uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
        with:
          registry: ${{ needs.jfr-production-image.outputs.docker-registry }}
          username: ${{ secrets.jf-user-name }}
          password: ${{ secrets.jf-access-token }}

      - name: Create Manifest Directories
        run: |
          mkdir -p "${DOCKER_MANIFEST_PATH}/gcp"
          mkdir -p "${DOCKER_MANIFEST_PATH}/jfrog"

      - name: Generate GCP Manifest
        id: gcp
        env:
          MANIFEST_PATH: ${{ env.DOCKER_MANIFEST_PATH }}/gcp
          DOCKER_REGISTRY: ${{ needs.gcp-production-image.outputs.docker-image-prefix }}
          DOCKER_TAG: ${{ needs.gcp-production-image.outputs.docker-image-tag }}
        run: ${{ env.DOCKER_MANIFEST_GENERATOR }}

      - name: Generate JFrog Manifest
        id: jfrog
        env:
          MANIFEST_PATH: ${{ env.DOCKER_MANIFEST_PATH }}/jfrog
          DOCKER_REGISTRY: ${{ needs.jfr-production-image.outputs.docker-image-prefix }}
          DOCKER_TAG: ${{ needs.jfr-production-image.outputs.docker-image-tag }}
        run: ${{ env.DOCKER_MANIFEST_GENERATOR }}

      - name: Validate Layers (linux/amd64)
        run: |
          if ! diff -u "${{ steps.gcp.outputs.path }}/linux-amd64.layers.json" "${{ steps.jfrog.outputs.path }}/linux-amd64.layers.json" >/dev/null 2>&1; then
           echo "::group::Layer Differences"
           diff -u "${{ steps.gcp.outputs.path }}/linux-amd64.layers.json" "${{ steps.jfrog.outputs.path }}/linux-amd64.layers.json"
           echo "::endgroup::"
           exit 1
          fi

      - name: Validate Layers (linux/arm64)
        run: |
          if ! diff -u "${{ steps.gcp.outputs.path }}/linux-arm64.layers.json" "${{ steps.jfrog.outputs.path }}/linux-arm64.layers.json" >/dev/null 2>&1; then
           echo "::group::Layer Differences"
           diff -u "${{ steps.gcp.outputs.path }}/linux-arm64.layers.json" "${{ steps.jfrog.outputs.path }}/linux-arm64.layers.json"
           echo "::endgroup::"
           exit 1
          fi

      - name: Validate Full Manifest (linux/amd64)
        run: |
          if ! diff -u "${{ steps.gcp.outputs.path }}/linux-amd64.comparable.json" "${{ steps.jfrog.outputs.path }}/linux-amd64.comparable.json" >/dev/null 2>&1; then
           echo "::group::Layer Differences"
           diff -u "${{ steps.gcp.outputs.path }}/linux-amd64.comparable.json" "${{ steps.jfrog.outputs.path }}/linux-amd64.comparable.json"
           echo "::endgroup::"
           exit 1
          fi

      - name: Validate Full Manifest (linux/arm64)
        run: |
          if ! diff -u "${{ steps.gcp.outputs.path }}/linux-arm64.comparable.json" "${{ steps.jfrog.outputs.path }}/linux-arm64.comparable.json" >/dev/null 2>&1; then
           echo "::group::Layer Differences"
           diff -u "${{ steps.gcp.outputs.path }}/linux-arm64.comparable.json" "${{ steps.jfrog.outputs.path }}/linux-arm64.comparable.json"
           echo "::endgroup::"
           exit 1
          fi

      - name: Upload Manifests
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ (steps.gcp.outcome == 'success' || steps.jfrog.outcome == 'success') && !cancelled() && always() }}
        with:
          name: Production Image Manifests
          path: ${{ env.DOCKER_MANIFEST_PATH }}

  publish:
    name: Publish to ${{ inputs.version-policy == 'specified' && 'Maven Central' || 'GCP Registry' }}
    runs-on: [ self-hosted, Linux, large, ephemeral ]
    needs:
      - validate
    if: ${{ inputs.release-profile != 'none' }}
    steps:
      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Install GnuPG Tools
        if: ${{ inputs.dry-run-enabled != true }}
        run: |
          if ! command -v gpg2 >/dev/null 2>&1; then
            echo "::group::Updating APT Repository Indices"
              sudo apt update
            echo "::endgroup::"
            echo "::group::Installing GnuPG Tools"
              sudo apt install -y gnupg2
            echo "::endgroup::"
          fi

      - name: Import GPG key
        id: gpg_key
        uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
        with:
          gpg_private_key: ${{ secrets.sdk-gpg-key-contents }}
          passphrase: ${{ secrets.sdk-gpg-key-passphrase }}
          git_config_global: true
          git_user_signingkey: true
          git_commit_gpgsign: true
          git_tag_gpgsign: true

      - name: Authenticate to Google Cloud
        id: google-auth
        uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2
        with:
          workload_identity_provider: "projects/229164983194/locations/global/workloadIdentityPools/registry-identity-pool/providers/gh-provider"
          service_account: "artifact-deployer@swirlds-registry.iam.gserviceaccount.com"

      - name: Setup Google Cloud SDK
        uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200 # v2.1.0
        if: ${{ inputs.dry-run-enabled != true && !cancelled() && !failure() }}

      - name: Setup Java
        uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
        with:
          distribution: ${{ inputs.java-distribution }}
          java-version: ${{ inputs.java-version }}

      - name: Setup Gradle
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}

      - name: Restore Build Version
        uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
        with:
          fail-on-cache-miss: true
          path: version.txt
          key: node-build-version-${{ needs.validate.outputs.version }}-${{ github.sha }}

      - name: Gradle Assemble
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: assemble --scan

      - name: Gradle Version Summary
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: githubVersionSummary --scan

      - name: Stage SDK Release Archives
        working-directory: platform-sdk
        run: |
          SDK_RELEASE_DIR="${HOME}/sdk-release"
          SDK_ARCHIVE_DIR="${HOME}/sdk-archives"
          COMMIT_SHA="${{ needs.validate.outputs.commit-id-short }}"

          #if [[ "${{ steps.archive-cache.outputs.cache-hit }}" == true ]]; then
          #  echo "::group::Removing Existing Archive Cache Items"
          #  rm -rvf "${SDK_ARCHIVE_DIR}"/*
          #  echo "::endgroup::"
          #fi

          echo "::group::Creating Release Directories"
            [[ -f "${SDK_RELEASE_DIR}" ]] || mkdir -p "${SDK_RELEASE_DIR}"
            [[ -f "${SDK_ARCHIVE_DIR}" ]] || mkdir -p "${SDK_ARCHIVE_DIR}"
          echo "::endgroup::"

          echo "::group::Staging Release Files"
            cp -Rvf sdk/* "${SDK_RELEASE_DIR}"
            rm -vf "${SDK_RELEASE_DIR}/log4j2.xml"
            rm -vf "${SDK_RELEASE_DIR}/settings.txt"
            rm -vf "${SDK_RELEASE_DIR}/test_cases.sh"
            rm -rvf "${SDK_RELEASE_DIR}/target"
            rm -rvf "${SDK_RELEASE_DIR}/testing"
            rm -rvf "${SDK_RELEASE_DIR}/kernels"
            rm -rvf "${SDK_RELEASE_DIR}/data/configs"

            cat "sdk/config.txt" | \
              perl -0777 -pe 's/# \*\* BEGIN REMOVE FROM SDK RELEASES \*\*.*# \*\* END REMOVE FROM SDK RELEASES \*\*//igs' \
                > "${SDK_RELEASE_DIR}/config.txt"
          echo "::endgroup::"

          echo "::group::Rendering Settings File"
            SETTINGS_CONTENTS="loadKeysFromPfxFiles, false\n"
            SETTINGS_CONTENTS+="requireStateLoad, false\n"
            SETTINGS_CONTENTS+="csvOutputFolder, data/stats\n"
            SETTINGS_CONTENTS+="csvFileName, DemoStats\n"

            echo -e "${SETTINGS_CONTENTS}" >"${SDK_RELEASE_DIR}/settings.txt"
          echo "::endgroup::"

          LIB_ARCHIVE_FILE="${SDK_ARCHIVE_DIR}/platform-sdk-libs-v${{ needs.validate.outputs.version }}-${COMMIT_SHA}.zip"
          APPS_ARCHIVE_FILE="${SDK_ARCHIVE_DIR}/platform-sdk-apps-v${{ needs.validate.outputs.version }}-${COMMIT_SHA}.zip"
          PUBLIC_ARCHIVE_FILE="${SDK_ARCHIVE_DIR}/platform-sdk-public-v${{ needs.validate.outputs.version }}-${COMMIT_SHA}.zip"

          echo "::group::Building Release Archives"
            cd "${SDK_RELEASE_DIR}" || exit "${?}"
            zip -r "${LIB_ARCHIVE_FILE}" data/lib
            zip -r "${APPS_ARCHIVE_FILE}" data/apps

            # remove testing tools (if present) before building the public release artifact
            rm -vf data/apps/*TestingTool.jar || true
            zip -r "${PUBLIC_ARCHIVE_FILE}" *
          echo "::endgroup::"

          echo "::group::Sign Release Archives"
            cd "${SDK_ARCHIVE_DIR}" || exit "${?}"
            sha256sum "${LIB_ARCHIVE_FILE}" >"${LIB_ARCHIVE_FILE}.sha256"
            sha256sum "${APPS_ARCHIVE_FILE}" >"${APPS_ARCHIVE_FILE}.sha256"
            sha256sum "${PUBLIC_ARCHIVE_FILE}" >"${PUBLIC_ARCHIVE_FILE}.sha256"

            gpg --output "${LIB_ARCHIVE_FILE}.asc" --detach-sig "${LIB_ARCHIVE_FILE}"
            gpg --output "${APPS_ARCHIVE_FILE}.asc" --detach-sig "${APPS_ARCHIVE_FILE}"
            gpg --output "${PUBLIC_ARCHIVE_FILE}.asc" --detach-sig "${PUBLIC_ARCHIVE_FILE}"

            gpg --output "${LIB_ARCHIVE_FILE}.sha256.asc" --detach-sig "${LIB_ARCHIVE_FILE}.sha256"
            gpg --output "${APPS_ARCHIVE_FILE}.sha256.asc" --detach-sig "${APPS_ARCHIVE_FILE}.sha256"
            gpg --output "${PUBLIC_ARCHIVE_FILE}.sha256.asc" --detach-sig "${PUBLIC_ARCHIVE_FILE}.sha256"
          echo "::endgroup::"

      - name: Gradle Publish to ${{ inputs.version-policy == 'specified' && 'Maven Central' || 'Google Artifact Registry' }} (${{ inputs.release-profile }})
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        if: ${{ inputs.dry-run-enabled != true && inputs.release-profile != 'none' && !cancelled() && !failure() }}
        env:
          OSSRH_USERNAME: ${{ secrets.sdk-ossrh-username }}
          OSSRH_PASSWORD: ${{ secrets.sdk-ossrh-password }}
        with:
          gradle-version: ${{ inputs.gradle-version }}
          arguments: "release${{ inputs.release-profile }} --scan -PpublishSigningEnabled=true --no-configuration-cache"

      - name: Upload SDK Release Archives
        if: ${{ inputs.dry-run-enabled != true && inputs.version-policy == 'specified' && !cancelled() && !failure() }}
        env:
          RELEASE_TAG: v${{ needs.validate.outputs.version }}
        run: |
          SDK_ARCHIVE_DIR="${HOME}/sdk-archives"
          gsutil -m cp -r "${SDK_ARCHIVE_DIR}"/* gs://platform-sdk-ci-release-artifacts/${RELEASE_TAG}/

  send-notifications:
    name: Send Release Notifications
    runs-on: [ self-hosted, Linux, large, ephemeral ]
    needs:
      - validate
      - local-node-images
      - validate-production-image
      - publish
    if: ${{ inputs.dry-run-enabled != true && inputs.version-policy == 'specified' && !cancelled() && !failure() }}
    steps:
      - name: Determine Notification Parameters
        id: parameters
        run: |
          ARTIFACT_URL="https://repo1.maven.org/maven2/com/swirlds/swirlds-platform-core/${{ needs.validate.outputs.version }}/"
          ARTIFACT_LINK_NAME="MC Availability Check"
          ARTIFACT_REGISTRY="Maven Central"

          if [[ "${{ inputs.release-profile }}" == "PrereleaseChannel" ]]; then
            ARTIFACT_URL="https://console.cloud.google.com/artifacts/maven/swirlds-registry/us/maven-prerelease-channel/com.swirlds:swirlds-platform-core/${{ needs.validate.outputs.version }}?project=swirlds-registry"
            ARTIFACT_LINK_NAME="GCP Registry"
            ARTIFACT_REGISTRY="GCP Artifact Registry"
          fi

          echo "artifact-url=${ARTIFACT_URL}" >>"${GITHUB_OUTPUT}"
          echo "artifact-name=${ARTIFACT_LINK_NAME}" >>"${GITHUB_OUTPUT}"
          echo "artifact-registry=${ARTIFACT_REGISTRY}" >>"${GITHUB_OUTPUT}"

      - name: Send Slack Notification (Maven Central)
        uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
        env:
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
          SLACK_WEBHOOK_URL: ${{ secrets.slack-webhook-url }}
        with:
          payload: |
            {
              "attachments": [
                  {
                    "color": "#b7f350",
                    "blocks": [
                      {
                        "type": "header",
                        "text": {
                          "type": "plain_text",
                          "text": ":dvd: Node Software Release v${{ needs.validate.outputs.version }}",
                          "emoji": true
                        }
                      },
                      {
                        "type": "section",
                        "fields": [
                          {
                            "type": "mrkdwn",
                            "text": "*Deployment Channel:*"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "*Deployment Status Check:*"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "${{ steps.parameters.outputs.artifact-registry }}"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "<${{ steps.parameters.outputs.artifact-url }}|${{ steps.parameters.outputs.artifact-name }}>"
                          }
                        ]
                      },
                      {
                        "type": "section",
                        "fields": [
                          {
                            "type": "mrkdwn",
                            "text": "*Source Branch:*"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "*Short Commit ID:*"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "<${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }}|${{ github.ref_name }}>"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "`${{ needs.validate.outputs.commit-id-short }}`"
                          }
                        ]
                      },
                      {
                        "type": "section",
                        "fields": [
                          {
                            "type": "mrkdwn",
                            "text": "*Gradle Version Number:*"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "*Release Notes:*"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "`${{ needs.validate.outputs.version }}`"
                          },
                          {
                            "type": "mrkdwn",
                            "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/v${{ needs.validate.outputs.version }}|v${{ needs.validate.outputs.version }}>"
                          }
                        ]
                      },
                      {
                        "type": "divider"
                      },
                      {
                        "type": "context",
                        "elements": [
                          {
                            "type": "mrkdwn",
                            "text": ":warning: Artifacts may not be immediately available in Maven Central. Please verify existence of the artifacts using the link provided above."
                          }
                        ]
                      }
                    ]
                  }
                ]
              }


ZXC: [Node] Compile Application Code

##
# Copyright (C) 2022-2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

name: "ZXC: [Node] Compile Application Code"
on:
  workflow_call:
    inputs:
      enable-unit-tests:
        description: "Unit Testing Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-misc:
        description: "HAPI Testing (misc) Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-crypto:
        description: "HAPI Testing (crypto) Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-token:
        description: "HAPI Testing (token) Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-smart-contract:
        description: "HAPI Testing (smart contract) Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-time-consuming:
        description: "HAPI Testing (time consuming) Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-restart:
        description: "HAPI Testing (restart) Enabled"
        type: boolean
        required: false
        default: false
      enable-hapi-tests-nd-reconnect:
        description: "HAPI Testing (node death reconnect) Enabled"
        type: boolean
        required: false
        default: false
      enable-spotless-check:
        description: "Spotless Check Enabled"
        type: boolean
        required: false
        default: false
      enable-dependency-check:
        description: "Dependency Scope Check Enabled"
        type: boolean
        required: false
        default: false
      enable-snyk-scan:
        description: "Snyk Scan Enabled"
        type: boolean
        required: false
        default: false
      enable-network-log-capture:
        description: "Network Log Capture Enabled"
        type: boolean
        required: false
        default: false
      java-distribution:
        description: "Java JDK Distribution:"
        type: string
        required: false
        default: "temurin"
      java-version:
        description: "Java JDK Version:"
        type: string
        required: false
        default: "21.0.1"
      node-version:
        description: "NodeJS Version:"
        type: string
        required: false
        default: "16"
      custom-job-label:
        description: "Custom Job Label:"
        type: string
        required: false
        default: "Compiles"

    secrets:
      access-token:
        description: "The Github access token used to checkout the repository, submodules, and make GitHub API calls."
        required: true
      gradle-cache-username:
        description: "The username used to authenticate with the Gradle Build Cache Node."
        required: true
      gradle-cache-password:
        description: "The password used to authenticate with the Gradle Build Cache Node."
        required: true
      snyk-token:
        description: "The Snyk access token is used by Snyk to analyze the code for vulnerabilities "
        required: false
      codacy-project-token:
        description: "The Codacy project token used to report code coverage."
        required: false
      codecov-token:
        description: "The Codecov token used to report code coverage."
        required: false

defaults:
  run:
    shell: bash

permissions:
  id-token: write
  actions: read
  pull-requests: write
  statuses: write
  checks: write
  contents: read

env:
  GRADLE_CACHE_USERNAME: ${{ secrets.gradle-cache-username }}
  GRADLE_CACHE_PASSWORD: ${{ secrets.gradle-cache-password }}
  GRADLE_EXEC: cgexec -g cpu,memory:gradle-${{ github.run_id }} --sticky ionice -c 2 -n 2 nice -n 19 ./gradlew
  CG_EXEC: cgexec -g cpu,memory:gradle-${{ github.run_id }} --sticky ionice -c 2 -n 2 nice -n 19

jobs:
  compile:
    name: ${{ inputs.custom-job-label || 'Compiles' }}
    runs-on: [self-hosted, Linux, large, ephemeral]
    steps:
      - name: Checkout Code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Expand Shallow Clone for and Spotless
        if: ${{ (inputs.enable-unit-tests || inputs.enable-spotless-check) && !cancelled() }}
        run: git fetch --unshallow --no-recurse-submodules

      - name: Setup Java
        uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
        with:
          distribution: ${{ inputs.java-distribution }}
          java-version: ${{ inputs.java-version }}

      - name: Setup Gradle
        uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
        with:
          cache-read-only: false

      - name: Setup NodeJS
        uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
        with:
          node-version: ${{ inputs.node-version }}

      - name: Setup Control Groups
        run: |
          echo "::group::Get System Configuration"
            USR_ID="$(id -un)"
            GRP_ID="$(id -gn)"
            GRADLE_MEM_LIMIT="30064771072"
            AGENT_MEM_LIMIT="2147483648"
            GRADLE_GROUP_NAME="gradle-${{ github.run_id }}"
            AGENT_GROUP_NAME="agent-${{ github.run_id }}"
          echo "::endgroup::"

          echo "::group::Install Control Group Tools"
            if ! command -v cgcreate >/dev/null 2>&1; then
              sudo apt-get update
              sudo apt-get install -y cgroup-tools
            fi
          echo "::endgroup::"

          echo "::group::Create Control Groups"
            sudo cgcreate -g cpu,memory:${GRADLE_GROUP_NAME} -a ${USR_ID}:${GRP_ID} -t ${USR_ID}:${GRP_ID}
            sudo cgcreate -g cpu,memory:${AGENT_GROUP_NAME} -a ${USR_ID}:${GRP_ID} -t ${USR_ID}:${GRP_ID}
          echo "::endgroup::"

          echo "::group::Set Control Group Limits"
            cgset -r cpu.shares=768 ${GRADLE_GROUP_NAME}
            cgset -r cpu.shares=500 ${AGENT_GROUP_NAME}
            cgset -r memory.limit_in_bytes=${GRADLE_MEM_LIMIT} ${GRADLE_GROUP_NAME}
            cgset -r memory.limit_in_bytes=${AGENT_MEM_LIMIT} ${AGENT_GROUP_NAME}
            cgset -r memory.memsw.limit_in_bytes=${GRADLE_MEM_LIMIT} ${GRADLE_GROUP_NAME}
            cgset -r memory.memsw.limit_in_bytes=${AGENT_MEM_LIMIT} ${AGENT_GROUP_NAME}
          echo "::endgroup::"

          echo "::group::Move Runner Processes to Control Groups"
            sudo cgclassify --sticky -g cpu,memory:${AGENT_GROUP_NAME} $(pgrep 'Runner.Listener' | tr '\n' ' ')
            sudo cgclassify -g cpu,memory:${AGENT_GROUP_NAME} $(pgrep 'Runner.Worker' | tr '\n' ' ')
          echo "::endgroup::"

      - name: Compile
        id: gradle-build
        run: ${GRADLE_EXEC} assemble --scan

      - name: Spotless Check
        if: ${{ inputs.enable-spotless-check && !cancelled() }}
        run: ${GRADLE_EXEC} spotlessCheck --scan

      - name: Gradle Dependency Scopes Check
        if: ${{ inputs.enable-dependency-check && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        run: ${GRADLE_EXEC} checkAllModuleInfo --scan --continue

      - name: Unit Testing
        id: gradle-test
        if: ${{ inputs.enable-unit-tests && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        run: ${GRADLE_EXEC} :reports:testCodeCoverageReport -x :test-clients:test --continue --scan

      - name: Publish Unit Test Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-unit-tests && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: Unit Test Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/build/test-results/test/TEST-*.xml"

      - name: Upload Unit Test Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-unit-tests && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: Unit Test Report
          path: "**/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: HAPI Testing (Misc)
        id: gradle-hapi-misc
        if: ${{ inputs.enable-hapi-tests-misc && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestMisc --scan --no-daemon

      - name: Publish HAPI Test (Misc) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-misc && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Misc) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Misc) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-misc && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: HAPI Test (Misc) Reports
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (Misc) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-misc && inputs.enable-network-log-capture && steps.gradle-hapi-misc.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Misc) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
          retention-days: 7

      - name: HAPI Testing (Crypto)
        id: gradle-hapi-crypto
        if: ${{ inputs.enable-hapi-tests-crypto && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestCrypto --scan

      - name: Publish HAPI Test (Crypto) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-crypto && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Crypto) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Crypto) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-crypto && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: HAPI Test (Crypto) Report
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (crypto) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-crypto && inputs.enable-network-log-capture && steps.gradle-hapi-crypto.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Crypto) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
          retention-days: 7

      - name: HAPI Testing (Token)
        id: gradle-hapi-token
        if: ${{ inputs.enable-hapi-tests-token && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestToken --scan

      - name: Publish HAPI Test (Token) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-token && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Token) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Token) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-token && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: HAPI Test (Token) Report
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (Token) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-token && inputs.enable-network-log-capture && steps.gradle-hapi-token.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Token) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
          retention-days: 7

      - name: HAPI Testing (Smart Contract)
        id: gradle-hapi-smart-contract
        if: ${{ inputs.enable-hapi-tests-smart-contract && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestSmartContract --scan

      - name: Publish HAPI Test (Smart Contract) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-smart-contract && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Smart Contract) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Smart Contract) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-smart-contract && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: HAPI Test (Smart Contract) Report
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (Smart Contract) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-smart-contract && inputs.enable-network-log-capture && steps.gradle-hapi-smart-contract.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Smart Contract) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
          retention-days: 7

      - name: HAPI Testing (Time Consuming)
        id: gradle-hapi-time-consuming
        if: ${{ inputs.enable-hapi-tests-time-consuming && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestTimeConsuming --scan

      - name: Publish HAPI Test (Time Consuming) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-time-consuming && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Time Consuming) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Time Consuming) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-time-consuming && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: HAPI Test (Time Consuming) Report
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (Time Consuming) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-time-consuming && inputs.enable-network-log-capture && steps.gradle-hapi-time-consuming.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Time Consuming) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
          retention-days: 7

      - name: HAPI Testing (Restart)
        id: gradle-hapi-restart
        if: ${{ inputs.enable-hapi-tests-restart && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestRestart --scan

      - name: Publish HAPI Test (Restart) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-restart && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Restart) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Restart) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-restart && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          name: HAPI Test (Restart) Report
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (Restart) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-restart && inputs.enable-network-log-capture && steps.gradle-hapi-restart.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Restart) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
            hedera-node/test-clients/build/hapi-test/*.log
          retention-days: 7

      - name: HAPI Testing (Node Death Reconnect)
        id: gradle-hapi-nd-reconnect
        if: ${{ inputs.enable-hapi-tests-nd-reconnect && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        env:
          LC_ALL: en.UTF-8
          LANG: en_US.UTF-8
        run: ${GRADLE_EXEC} hapiTestNDReconnect --scan

      - name: Publish HAPI Test (Node Death Reconnect) Report
        uses: EnricoMi/publish-unit-test-result-action@30eadd5010312f995f0d3b3cff7fe2984f69409e # v2.16.1
        if: ${{ inputs.enable-hapi-tests-nd-reconnect && steps.gradle-build.conclusion == 'success' && !cancelled() }}
        with:
          check_name: 'Node: HAPI Test (Node Death Reconnect) Results'
          check_run_disabled: false
          json_thousands_separator: ','
          junit_files: "**/test-clients/build/test-results/test/TEST-*.xml"

      - name: Upload HAPI Test (Node Death Reconnect) Report Artifacts
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-nd-reconnect && steps.gradle-build.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Node Death Reconnect) Report
          path: "**/test-clients/build/test-results/test/TEST-*.xml"
          retention-days: 7

      - name: Upload HAPI Test (Node Death Reconnect) Network Logs
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-hapi-tests-nd-reconnect && inputs.enable-network-log-capture && steps.gradle-hapi-nd-reconnect.conclusion == 'failure' && !cancelled() }}
        with:
          name: HAPI Test (Node Death Reconnect) Network Logs
          path: |
            hedera-node/test-clients/build/hapi-test/**/output/**
            hedera-node/test-clients/build/hapi-test/*.log
          retention-days: 7

      - name: Publish To Codecov
        if: ${{ inputs.enable-unit-tests && !cancelled() }}
        uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0
        env:
          CODECOV_TOKEN: ${{ secrets.codecov-token }}
        with:
          files: gradle/reports/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml

      - name: Publish to Codacy
        env:
          CODACY_PROJECT_TOKEN: ${{ secrets.codacy-project-token }}
        if: ${{ inputs.enable-unit-tests && !cancelled() }}
        run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -l Java -r gradle/reports/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml

      - name: Upload Test Reports
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
        if: ${{ inputs.enable-unit-tests && !cancelled() }}
        with:
          name: Test Reports
          path: "**/build/reports/tests/**"

      - name: Disable Gradle Configuration Cache
        if: >-
          ${{
            inputs.enable-snyk-scan &&
            steps.gradle-build.conclusion == 'success' &&
            (
              github.event.pull_request.head.repo.full_name == github.repository ||
              github.event_name == 'push' ||
              github.event_name == 'workflow_dispatch'
            ) &&
            !cancelled()
          }}
        run: sed -i 's/^org.gradle.configuration-cache=.*$/org.gradle.configuration-cache=false/' gradle.properties

      - name: Setup Snyk
        env:
          SNYK_TOKEN: ${{ secrets.snyk-token }}
        if: >-
          ${{
            inputs.enable-snyk-scan &&
            steps.gradle-build.conclusion == 'success' &&
            (
              github.event.pull_request.head.repo.full_name == github.repository ||
              github.event_name == 'push' ||
              github.event_name == 'workflow_dispatch'
            ) &&
            !cancelled()
          }}
        run: ${CG_EXEC} npm install -g snyk snyk-to-html @wcj/html-to-markdown-cli

      - name: Snyk Scan
        id: snyk
        env:
          SNYK_TOKEN: ${{ secrets.snyk-token }}
        if: >-
          ${{
            inputs.enable-snyk-scan &&
            steps.gradle-build.conclusion == 'success' &&
            (
              github.event.pull_request.head.repo.full_name == github.repository ||
              github.event_name == 'push' ||
              github.event_name == 'workflow_dispatch'
            ) &&
            !cancelled()
          }}
        run: ${CG_EXEC} snyk test --all-sub-projects --severity-threshold=high --policy-path=.snyk --json-file-output=snyk-test.json

      - name: Snyk Code
        id: snyk-code
        env:
          SNYK_TOKEN: ${{ secrets.snyk-token }}
        if: >-
          ${{
            inputs.enable-snyk-scan &&
            steps.gradle-build.conclusion == 'success' &&
            (
              github.event.pull_request.head.repo.full_name == github.repository ||
              github.event_name == 'push' ||
              github.event_name == 'workflow_dispatch'
            ) &&
            !cancelled()
          }}
        run: ${CG_EXEC} snyk code test --severity-threshold=high --json-file-output=snyk-code.json

      - name: Publish Snyk Results
        if: >-
          ${{
            inputs.enable-snyk-scan &&
            steps.gradle-build.conclusion == 'success' &&
            (
              github.event.pull_request.head.repo.full_name == github.repository ||
              github.event_name == 'push' ||
              github.event_name == 'workflow_dispatch'
            ) &&
            !cancelled()
          }}
        run: |
          if [[ -f "snyk-test.json" && -n "$(cat snyk-test.json | tr -d '[:space:]')" ]]; then
            snyk-to-html -i snyk-test.json -o snyk-test.html --summary
            html-to-markdown snyk-test.html -o snyk
            cat snyk/snyk-test.html.md >> $GITHUB_STEP_SUMMARY
          fi

          if [[ -f "snyk-code.json" && -n "$(cat snyk-code.json | tr -d '[:space:]')" ]]; then
            snyk-to-html -i snyk-code.json -o snyk-code.html --summary
            html-to-markdown snyk-code.html -o snyk
            cat snyk/snyk-code.html.md >> $GITHUB_STEP_SUMMARY
          fi

      - name: Check Snyk Files
        if: ${{ always() }}
        run: |
          echo "::group::Snyk File List"
            ls -lah snyk* || true
          echo "::endgroup::"

          echo "::group::Snyk Test Contents"
            cat snyk-test.json || true
          echo "::endgroup::"

          echo "::group::Snyk Code Contents"
            cat snyk-code.json || true
          echo "::endgroup::"