diff --git a/.github/workflows/000-user-official-release.yaml b/.github/workflows/000-user-official-release.yaml new file mode 100644 index 0000000000..3cc52d2c34 --- /dev/null +++ b/.github/workflows/000-user-official-release.yaml @@ -0,0 +1,163 @@ +# SPDX-License-Identifier: Apache-2.0 +name: "000: [USER] Official Release" + +on: + workflow_dispatch: + inputs: + dry-run-enabled: + description: "Perform Dry Run" + type: boolean + required: false + default: false + +defaults: + run: + shell: bash + +permissions: + id-token: write + packages: write + contents: read + pull-requests: read + issues: read + +env: + REGISTRY: ghcr.io + +jobs: + semantic-release: + name: Publish Official Release of Hedera Transaction Tool + runs-on: transaction-tools-linux-medium + outputs: + # We extract the version from the VERSION file created by .releaserc + version: ${{ steps.extract-version.outputs.version }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + token: ${{ secrets.GH_ACCESS_TOKEN }} + + - name: Install GnuPG Tools + 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 + uses: step-security/ghaction-import-gpg@69c854a83c7f79463f8bdf46772ab09826c560cd # v6.3.1 + with: + git_commit_gpgsign: true + git_user_signingkey: true + git_tag_gpgsign: false + git_config_global: true + gpg_private_key: ${{ secrets.GPG_KEY_CONTENTS }} + passphrase: ${{ secrets.GPG_KEY_PASSPHRASE }} + + - name: Setup Node + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22 + + - name: Install Semantic Release + if: ${{ github.event_name == 'workflow_dispatch' && !cancelled() && !failure() }} + run: | + npm install -g semantic-release@24.2.0 @semantic-release/git@10.0.1 @semantic-release/github@11.0.1 \ + @semantic-release/exec@6.0.3 semantic-release-helm3@2.9.3 \ + conventional-changelog-conventionalcommits@8.0.0 \ + @commitlint/cli@19.5.0 @commitlint/config-conventional@19.5.0 \ + marked-mangle@1.1.10 marked-gfm-heading-id@4.1.1 semantic-release-conventional-commits@3.0.0 + + # Both actual and dry-run semantic-release will output the new version + # in the logs but actual release should also publish a tag&release on GitHub + # The helm charts are published to the GitHub artifact registry + # as part of the release process (configured in .releaserc) + - name: Run Semantic Release + if: ${{ !cancelled() && !failure() }} + env: + GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} + GIT_AUTHOR_NAME: ${{ steps.gpg.outputs.name}} + GIT_AUTHOR_EMAIL: ${{ steps.gpg.outputs.email}} + GIT_COMMITTER_NAME: ${{ steps.gpg.outputs.name}} + GIT_COMMITTER_EMAIL: ${{ steps.gpg.outputs.email}} + run: | + if [[ "${{ inputs.dry-run-enabled }}" == "true" ]]; then + echo "Dry Running semantic-release now..." + npx semantic-release --dry-run + else + echo "Running semantic-release now..." + npx semantic-release --debug + fi + + - name: Extract Version Output + id: extract-version + run: | + # The .releaserc 'verifyRelease' step writes the version to a file named VERSION + if [[ -f VERSION ]]; then + VER=$(cat VERSION | tr -d '[:space:]') + echo "::notice::New version is: $VER" + echo "version=$VER" >> $GITHUB_OUTPUT + else + echo "::warning::No new version file output by semantic release." + fi + + build-and-push-docker: + name: Build and Push Docker Images + if: ${{ inputs.dry-run-enabled != true && needs.semantic-release.outputs.version != '' }} + needs: semantic-release + uses: ./.github/workflows/300-flow-docker-images.yaml + with: + ref: v${{ needs.semantic-release.outputs.version }} + + helm-publish: + name: Helm Chart Publish + needs: [semantic-release, build-and-push-docker] + if: ${{ inputs.dry-run-enabled != true && needs.semantic-release.outputs.version != '' }} + runs-on: transaction-tools-linux-medium + steps: + - name: Harden Runner + uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + token: ${{ secrets.GH_ACCESS_TOKEN }} + + - name: Setup Helm + uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 + with: + version: "v3.12.3" + + - name: Helm Registry Login + run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ${{ env.REGISTRY }} --username ${{ github.actor }} --password-stdin + + - name: Package and Push Chart + run: | + # 1. Update dependencies + helm dependency update charts/transaction-tool + + # 2. Package + helm package charts/transaction-tool + + # 3. Push + CHART_FILE="transaction-tool-${{ needs.semantic-release.outputs.version }}.tgz" + + if [[ -f "$CHART_FILE" ]]; then + echo "Pushing $CHART_FILE to GitHub Registry..." + helm push "$CHART_FILE" oci://${{ env.REGISTRY }}/hashgraph/hedera-transaction-tool + else + echo "::error::Chart file $CHART_FILE was not found." + exit 1 + fi diff --git a/.github/workflows/001-flow-pull-request-formatting.yaml b/.github/workflows/001-flow-pull-request-formatting.yaml new file mode 100644 index 0000000000..070df952ab --- /dev/null +++ b/.github/workflows/001-flow-pull-request-formatting.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: Apache-2.0 +name: "001: [FLOW] PR Formatting" +on: + pull_request_target: + types: + - assigned + - unassigned + - labeled + - unlabeled + - opened + - reopened + - edited + - converted_to_draft + - ready_for_review + - review_requested + - review_request_removed + - locked + - unlocked + - synchronize + +defaults: + run: + shell: bash + +permissions: + statuses: write + +jobs: + title-check: + name: Title Check + runs-on: network-node-linux-medium + steps: + - name: Harden Runner + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 + with: + egress-policy: audit + + - name: Check PR Title + uses: step-security/action-semantic-pull-request@bc0cf74f5be4ce34accdec1ae908dff38dc5def1 # v6.1.1 + env: + GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} + + assignee-check: + name: Assignee Check + runs-on: network-node-linux-medium + steps: + - name: Harden Runner + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 + with: + egress-policy: audit + + - name: Check Assignee + if: ${{ github.event.pull_request.assignees == null || github.event.pull_request.assignees[0] == null }} + run: | + echo "Assignee is not set. Failing the workflow." + exit 1 diff --git a/.github/workflows/300-flow-docker-images.yaml b/.github/workflows/300-flow-docker-images.yaml new file mode 100644 index 0000000000..f83c8cf9d4 --- /dev/null +++ b/.github/workflows/300-flow-docker-images.yaml @@ -0,0 +1,126 @@ +name: "300: [FLOW] Docker Images" + +on: + workflow_call: + inputs: + ref: + required: true + type: string + description: 'Git ref to checkout (tag or sha)' + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + packages: write + attestations: write + id-token: write + +env: + REGISTRY: ghcr.io + +jobs: + # Runs on workflow_call (used by semantic release) + build-and-push-release-images: + if: github.event_name == 'workflow_call' + runs-on: transaction-tools-linux-medium + strategy: + fail-fast: false + matrix: + image: [api, chain, notifications] + defaults: + run: + working-directory: back-end/apps/${{ matrix.image }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + ref: ${{ inputs.ref }} + + - name: Log in to the Container registry + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # 3.5.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # 5.9.0 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # 6.18.0 + with: + context: back-end/ + file: back-end/apps/${{ matrix.image }}/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 + with: + subject-name: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true + + # Runs on push to main or manual trigger - only publishes latest tag + build-and-push-latest-image: + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + runs-on: transaction-tools-linux-medium + strategy: + fail-fast: false + matrix: + image: [api, chain, notifications] + defaults: + run: + working-directory: back-end/apps/${{ matrix.image }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Log in to the Container registry + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # 3.5.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # 5.9.0 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} + tags: type=raw,value=latest + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # 6.18.0 + with: + context: back-end/ + file: back-end/apps/${{ matrix.image }}/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 + with: + subject-name: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/test-backend.yaml b/.github/workflows/301-flow-test-backend.yaml similarity index 93% rename from .github/workflows/test-backend.yaml rename to .github/workflows/301-flow-test-backend.yaml index 9f76804e2f..7e1269610c 100644 --- a/.github/workflows/test-backend.yaml +++ b/.github/workflows/301-flow-test-backend.yaml @@ -1,4 +1,4 @@ -name: Test Backend +name: "301: [FLOW] Test Backend" on: push: @@ -41,7 +41,7 @@ jobs: egress-policy: audit - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Install pnpm uses: step-security/action-setup@3d419c73e38e670dbffe349ffff26dd13c164640 # v4.2.0 diff --git a/.github/workflows/test-frontend.yaml b/.github/workflows/302-flow-test-frontend.yaml similarity index 95% rename from .github/workflows/test-frontend.yaml rename to .github/workflows/302-flow-test-frontend.yaml index 688aecd328..3b69250b02 100644 --- a/.github/workflows/test-frontend.yaml +++ b/.github/workflows/302-flow-test-frontend.yaml @@ -1,4 +1,4 @@ -name: Test Frontend +name: "302: [FLOW] Test Frontend" on: push: @@ -32,7 +32,7 @@ jobs: egress-policy: audit - name: Checkout Code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Set up Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 @@ -89,7 +89,7 @@ jobs: egress-policy: audit - name: Checkout Code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Set up Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 @@ -190,7 +190,7 @@ jobs: egress-policy: audit - name: Checkout Code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Set up Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 diff --git a/.github/workflows/publish-docker-images.yaml b/.github/workflows/publish-docker-images.yaml deleted file mode 100644 index 0434c7e2b3..0000000000 --- a/.github/workflows/publish-docker-images.yaml +++ /dev/null @@ -1,65 +0,0 @@ -name: Create and publish Transaction Tool Docker images - -on: - push: - tags: - - 'v*' - workflow_dispatch: - -permissions: - contents: read - packages: write - attestations: write - id-token: write - -env: - REGISTRY: ghcr.io - -jobs: - build-and-push-image: - runs-on: transaction-tools-linux-medium - strategy: - fail-fast: false - matrix: - image: [api, chain, notifications] - defaults: - run: - working-directory: back-end/apps/${{ matrix.image }} - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 - with: - egress-policy: audit - - - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - - name: Log in to the Container registry - uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # 3.5.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # 5.9.0 - with: - images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} - - - name: Build and push Docker image - id: push - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # 6.18.0 - with: - context: back-end/ - file: back-end/apps/${{ matrix.image }}/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Generate artifact attestation - uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 - with: - subject-name: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.image }} - subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000000..a896a753fb --- /dev/null +++ b/.releaserc @@ -0,0 +1,96 @@ +{ + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits" + } + ], + [ + "semantic-release-helm3", + { + "chartPath": "./charts/transaction-tool" + } + ], + "@semantic-release/git", + "@semantic-release/github" + ], + "verifyRelease": [ + [ + "@semantic-release/exec", + { "cmd": "echo ${nextRelease.version} > VERSION" } + ] + ], + "prepare": [ + [ + "@semantic-release/exec", + { + "prepareCmd": "for dir in back-end back-end/apps/api back-end/apps/chain back-end/apps/notifications front-end; do (cd $dir && npm version ${nextRelease.version} --no-git-tag-version --allow-same-version); done" + } + ], + [ + "semantic-release-helm3", + { + "chartPath": "./charts/transaction-tool" + } + ], + [ + "@semantic-release/git", + { + "assets": [ + "charts/transaction-tool/Chart.yaml", + "back-end/package.json", + "back-end/apps/api/package.json", + "back-end/apps/chain/package.json", + "back-end/apps/notifications/package.json", + "front-end/package.json" + ], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\nSigned-off-by: swirlds-automation " + } + ] + ], + "publish": [ + [ + "@semantic-release/github" + ] + ], + "branches":[ + { + "name": "main" + }, + { + "name": "release/([0-9]+).([0-9]+)", + "channel": "${name.replace(/release\\//g, '').split('.')[0]}.${name.replace(/release\\//g, '').split('.')[1]}.x", + "range": "${name.replace(/release\\//g, '').split('.')[0]}.${name.replace(/release\\//g, '').split('.')[1]}.x" + }, + { + "name": "alpha/*", + "prerelease": "alpha", + "channel": "alpha" + }, + { + "name": "ci/*", + "prerelease": "alpha", + "channel": "alpha" + }, + { + "name": "beta/*", + "prerelease": "beta", + "channel": "beta" + }, + { + "name": "rc/*", + "prerelease": "rc", + "channel": "rc" + }, + { + "name": "resd-455" + } + ] +}