diff --git a/.github/actions/push/action.yaml b/.github/actions/push/action.yaml new file mode 100644 index 000000000..486a2223d --- /dev/null +++ b/.github/actions/push/action.yaml @@ -0,0 +1,215 @@ +--- +name: Docker build and push + +on: + workflow_call: + inputs: + environment: + required: true + type: string + dockerfile: + required: false + type: string + default: "Dockerfile" + build-args: + required: false + type: string + role-to-assume: + required: true + type: string + role-session-name: + required: true + type: string + aws-region: + required: true + type: string + sandbox-semver: + required: false + type: boolean + default: false + semver-level: + required: false + type: string + default: patch + git-release-tag: + required: false + type: string + push-git-tag: + required: false + type: boolean + default: true + ghcr-semver-only-tag: + required: false + type: boolean + default: false + go-mod-cache-path: + required: false + type: string + default: "" + go-build-cache-path: + required: false + type: string + default: "" + secrets: + github-token: + required: true + +# this is used by github OIDC to assume the admin role later on +permissions: # see this: https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs + id-token: write # This is required for requesting the JWT + contents: write # This is required for actions/checkout + +jobs: + docker_build_tag_push: + name: Build docker image and tag for ${{ inputs.environment }} + environment: + name: ${{ inputs.environment }} + url: ${{ inputs.url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + submodules: false + token: ${{ secrets.github-token }} + ref: ${{ inputs.git-release-tag }} + + - name: configure aws credentials + id: aws-credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ inputs.role-to-assume }} + role-session-name: ${{ inputs.role-session-name }} + aws-region: ${{ inputs.aws-region }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.github-token }} + + - name: Login to Amazon ECR + id: login-ecr + uses: docker/login-action@v2 + with: + registry: ${{ steps.aws-credentials.outputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository }}/s + github-token: ${{ secrets.github-token }} + + - name: Set env vars + run: | + echo BUILD_TIMESTAMP="$(date +%s)" >> $GITHUB_ENV + echo REPOSITORY_NAME="$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV + echo TAG_NAME="$(echo ${{ github.ref }} | cut -d / -f3-)" >> $GITHUB_ENV + echo SHORT_SHA="$(git rev-parse --short HEAD)" >> $GITHUB_ENV + + - name: Get latest tag + run: echo tag="$(git tag --sort=v:refname | tail -n 1)" >> $GITHUB_OUTPUT + id: get-latest-tag + + - name: Bump semver patch + uses: immutable/im-shared-action-bump-semver@v1 + id: bump-semver + with: + current_version: ${{ steps.get-latest-tag.outputs.tag }} + level: ${{ inputs.semver-level }} + + - name: Build tags + id: build-tags + run: | + if [[ ${{ inputs.environment }} == "prod" && ${{ inputs.push-git-tag }} == "true" ]]; then # Prod and auto-increment git tag + echo GHCR_TAG="ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:prod-${{ steps.bump-semver.outputs.new_version }}" >> $GITHUB_ENV + echo ECR_TAG="${{ steps.aws-credentials.outputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/${{ env.REPOSITORY_NAME }}:prod-${{ steps.bump-semver.outputs.new_version }}" >> $GITHUB_ENV + elif [[ ${{ inputs.environment }} == "prod" ]]; then # Prod and use current latest tag + echo GHCR_TAG="ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:prod-${{ inputs.git-release-tag }}" >> $GITHUB_ENV + echo ECR_TAG="${{ steps.aws-credentials.outputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/${{ env.REPOSITORY_NAME }}:prod-${{ inputs.git-release-tag }}" >> $GITHUB_ENV + elif [[ ${{ inputs.sandbox-semver }} == "true" && ${{ inputs.environment }} == "sandbox" ]]; then # Sandbox and use current tag for semver + echo GHCR_TAG="ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:sandbox-${{ inputs.git-release-tag }}" >> $GITHUB_ENV + echo ECR_TAG="${{ steps.aws-credentials.outputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/${{ env.REPOSITORY_NAME }}:sandbox-${{ inputs.git-release-tag }}" >> $GITHUB_ENV + elif [[ ${{ inputs.environment }} == "sandbox" ]]; then # Sandbox standard tagging + echo GHCR_TAG="ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:sandbox-${{ env.BUILD_TIMESTAMP }}-git.${{ env.SHORT_SHA }}" >> $GITHUB_ENV + echo ECR_TAG="${{ steps.aws-credentials.outputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/${{ env.REPOSITORY_NAME }}:sandbox-${{ env.BUILD_TIMESTAMP }}-git.${{ env.SHORT_SHA }}" >> $GITHUB_ENV + elif [[ ${{ inputs.environment }} == "dev" ]]; then # Dev standard tagging + echo GHCR_TAG="ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:develop-${{ env.BUILD_TIMESTAMP }}-git.${{ env.SHORT_SHA }}" >> $GITHUB_ENV + echo ECR_TAG="${{ steps.aws-credentials.outputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/${{ env.REPOSITORY_NAME }}:develop-${{ env.BUILD_TIMESTAMP }}-git.${{ env.SHORT_SHA }}" >> $GITHUB_ENV + fi + + - name: Combine tags + id: combine-tags + run: | + docker_tags="${{ env.GHCR_TAG }},${{ env.ECR_TAG }}" + if [[ -n "${{ inputs.git-release-tag }}" && ${{ inputs.ghcr-semver-only-tag }} ]]; then + ghcr_semver_only_tag="ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:${{ inputs.git-release-tag }}" + docker_tags="$docker_tags,$ghcr_semver_only_tag" + fi + echo "docker_tags=$docker_tags" >> $GITHUB_ENV + + - name: Echo GITHUB_ENV variable + run: echo $GITHUB_ENV + + - name: Restore Go mod (pkg) + if: ${{ inputs.go-mod-cache-path != '' }} + uses: actions/cache/restore@v3 + with: + path: | + ${{ inputs.go-mod-cache-path }} + key: ${{ runner.os }}-gomod-${{ hashFiles('**/go.sum') }}-${{ github.sha }}-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-gomod-${{ hashFiles('**/go.sum') }}-${{ github.sha }}- + ${{ runner.os }}-gomod-${{ hashFiles('**/go.sum') }}- + ${{ runner.os }}-gomod- + + - name: Restore Go build (test) + if: ${{ inputs.go-build-cache-path != '' }} + uses: actions/cache/restore@v3 + with: + path: | + ${{ inputs.go-build-cache-path }} + key: ${{ runner.os }}-gobuild-${{ hashFiles('**/go.sum') }}-${{ github.sha }}-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-gobuild-${{ hashFiles('**/go.sum') }}-${{ github.sha }}- + ${{ runner.os }}-gobuild-${{ hashFiles('**/go.sum') }}- + ${{ runner.os }}-gobuild- + + - name: Set up Docker Context for buildx + id: buildx-context + run: | + docker context create builders + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + with: + version: latest + endpoint: builders + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64 + file: ${{ inputs.dockerfile }} + push: true + build-args: ${{ inputs.build-args }} + tags: ${{ env.docker_tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:cache + cache-to: type=registry,ref=ghcr.io/${{ github.repository }}/${{ env.REPOSITORY_NAME }}:cache,mode=max + provenance: false + + - if: ${{ inputs.environment == 'prod' && inputs.push-git-tag }} + name: Push semver patch + run: | + tag=${{ steps.bump-semver.outputs.new_version }} + message='${{ steps.bump-semver.outputs.new_version }}' + git config user.name "${GITHUB_ACTOR}" + git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" + git tag -a "${tag}" -m "${message}" + git push origin "${tag}" diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index af1d7861f..ce8166b2b 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -13,7 +13,7 @@ permissions: # see this: https://docs.github.com/en/actions/using-jobs/assigning jobs: dev_docker_build_push: if: ${{ github.ref == 'refs/heads/main' }} - uses: immutable/im-shared-github-actions/.github/workflows/docker-build-tag-push.yml@v1.3.1 + uses: ./.github/actions/push with: environment: dev dockerfile: "Dockerfile" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..b6b39a8c3 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,131 @@ +name: Release +run-name: Publish release ${{ github.event.release.tag_name }} + +# Cluster permissions +permissions: + # this is used by github OIDC to assume the admin role later on + id-token: write # This is required for requesting the JWT + contents: write # This is required for actions/checkout + +on: + release: + types: [released] + branches: [main] + +jobs: + dev_validate: + name: "Devnet: E2E" + runs-on: general-runner + environment: dev + steps: + - uses: actions/checkout@v4 + - name: Cache modules + uses: ./.github/actions/cache/golang + - uses: ./.github/actions/e2e + with: + rpc: https://rpc.dev.immutable.com + priv_key: ${{ secrets.ZKEVM_FUNDED_PRIV_KEY }} + + setup: + name: Setup + runs-on: ubuntu-latest + outputs: + tag_name: ${{ steps.get-tag-for-release.outputs.TAG_NAME }} + repo_name: ${{ steps.get-repository-name.outputs.REPOSITORY_NAME }} + steps: + - name: Extract tag name for the release + id: get-tag-for-release + run: echo "TAG_NAME=$(echo ${GITHUB_REF} | sed 's/refs\/tags\///')" >> $GITHUB_OUTPUT + + - name: Extract repository name + id: get-repository-name + run: echo "REPOSITORY_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_OUTPUT + + - name: Print tag being deployed + run: echo "The tag name being deployed is ${{ steps.get-tag-for-release.outputs.TAG_NAME }}. This tag will be checked out before building and tagging docker image." + + sandbox_docker_build_push: + name: "Testnet: Release" + needs: [setup, dev_validate] + uses: ./.github/actions/push + with: + environment: sandbox + dockerfile: "Dockerfile" + role-to-assume: "arn:aws:iam::783421985614:role/immutable-nonprod-docker-image-push" + role-session-name: "go-ethereum-immutable-nonprod-docker-image-push" + aws-region: "us-east-2" + sandbox-semver: true + push-git-tag: false + git-release-tag: ${{ needs.setup.outputs.tag_name }} + ghcr-semver-only-tag: false # prod release to deploy non-prefixed image + secrets: + github-token: ${{ secrets.PLATFORM_SA_GITHUB_TOKEN }} + + sandbox_images: + name: "Testnet: Rollout" + runs-on: general-runner + environment: sandbox + timeout-minutes: 10 # Job will loop until images are up to date + needs: [setup, sandbox_docker_build_push] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: configure aws credentials (nonprod) + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::783421985614:role/immutable-nonprod-cluster-operations + aws-region: us-east-2 + - uses: azure/setup-kubectl@v3.2 + - name: Configure kubectl + run: | + aws eks update-kubeconfig \ + --name sandbox \ + --region us-east-2 \ + - name: Wait for Rollout + shell: bash + run: ./.github/scripts/wait_images.sh sandbox sandbox-${{ needs.setup.outputs.tag_name }} + + sandbox_validate: + name: "Testnet: E2E" + runs-on: ubuntu-20-04-4-cores + needs: [setup, sandbox_docker_build_push, sandbox_images] + environment: sandbox + steps: + - uses: actions/checkout@v4 + - name: Cache modules + uses: ./.github/actions/cache/golang + - uses: ./.github/actions/e2e + with: + rpc: https://rpc.testnet.immutable.com + priv_key: ${{ secrets.ZKEVM_FUNDED_PRIV_KEY }} + + prod_docker_build_push: + name: "Mainnet: Release" + runs-on: ubuntu-latest + environment: prod + needs: [setup, sandbox_docker_build_push, sandbox_images, sandbox_validate] + steps: + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.PLATFORM_SA_GITHUB_TOKEN }} + - name: Promote sandbox image to prod + id: promote-sandbox-to-prod + shell: bash + run: | + sandbox_image="ghcr.io/${{ github.repository }}/${{ needs.setup.outputs.repo_name }}:sandbox-${{ needs.setup.outputs.tag_name }}" + prod_image="ghcr.io/${{ github.repository }}/${{ needs.setup.outputs.repo_name }}:prod-${{ needs.setup.outputs.tag_name }}" + no_prefix_image="ghcr.io/${{ github.repository }}/${{ needs.setup.outputs.repo_name }}:${{ needs.setup.outputs.tag_name }}" + latest_image="ghcr.io/${{ github.repository }}/${{ needs.setup.outputs.repo_name }}:latest" + + docker pull "$sandbox_image" + docker tag "$sandbox_image" "$prod_image" + docker tag "$sandbox_image" "$no_prefix_image" + docker tag "$sandbox_image" "$latest_image" + docker push "$prod_image" + docker push "$no_prefix_image" + docker push "$latest_image"