name: Publish Packages (canary)

on:
  # enable users to manually trigger with workflow_dispatch
  workflow_dispatch:
    inputs:
      customImageName:
        description: 'Custom Docker Image Tag (keep empty for git hash)'
        required: false
        default: '0.0.0-rc-0'

jobs:
  canary-publish:
    name: Publish Packages (canary)
    runs-on: ubuntu-latest
    # map the step outputs to job outputs
    outputs:
      builder: ${{ steps.packages.outputs.builder }}
      l2geth: ${{ steps.packages.outputs.l2geth }}
      batch-submitter: ${{ steps.packages.outputs.batch-submitter }}
      message-relayer: ${{ steps.packages.outputs.message-relayer }}
      data-transport-layer: ${{ steps.packages.outputs.data-transport-layer }}
      contracts: ${{ steps.packages.outputs.contracts }}
      gas-oracle: ${{ steps.packages.outputs.gas-oracle }}
      replica-healthcheck: ${{ steps.packages.outputs.replica-healthcheck }}
      hardhat-node: ${{ steps.packages.outputs.hardhat-node }}
      canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }}
      proxyd: ${{ steps.packages.outputs.proxyd }}
      rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }}
      op-exporter : ${{ steps.packages.outputs.op-exporter }}
      l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}

    steps:
      - name: Check out source code
        uses: actions/checkout@v2
        with:
          # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
          fetch-depth: 0

      - name: Setup Node.js 16.x
        uses: actions/setup-node@master
        with:
          node-version: 16.x

      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        run: echo "::set-output name=dir::$(yarn cache dir)"

      - uses: actions/cache@v2
        id: yarn-cache
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-

      - name: Install Dependencies
        run: yarn

      - name: Build
        run: yarn build

      - name: Setup Canary Snapshot
        run: yarn changeset version --snapshot

      - name: Publish To NPM
        uses: changesets/action@master
        id: changesets
        with:
          publish: yarn changeset publish --tag canary
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

      # Conditional on the release being executed, we unbundle the publishedPackages to specific
      # job outputs
      - name: Get version tags from each published version
        id: packages
        run: |
          node ops/scripts/ci-versions.js ${{ toJSON(steps.changesets.outputs.publishedPackages) }}

      - name: Docker Image Name
        id: docker-image-name
        run: |
          if [ ${CUSTOM_IMAGE_NAME} == '' ]
          then
              echo "::set-output name=canary-docker-tag::${GITHUB_SHA::8}"
          else
              echo "::set-output name=canary-docker-tag::prerelease-${CUSTOM_IMAGE_NAME}"
          fi
        env:
          CUSTOM_IMAGE_NAME: ${{ github.event.inputs.customImageName }}

  # The below code is duplicated, would be ideal if we could use a matrix with a
  # key/value being dynamically generated from the `publishedPackages` output
  # while also allowing for parallelization (i.e. `l2geth` not depending on `builder`)
  # and all jobs executing in parallel once `builder` is built
  l2geth:
    name: Publish L2Geth Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.l2geth != ''
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Publish L2Geth
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.geth
          push: true
          tags: ethereumoptimism/l2geth:${{ needs.canary-publish.outputs.canary-docker-tag }}

  gas-oracle:
    name: Publish Gas Oracle ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.gas-oracle != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.gas-oracle
          push: true
          tags: ethereumoptimism/gas-oracle:${{ needs.canary-publish.outputs.canary-docker-tag }}

  hardhat-node:
    name: Publish Hardhat Node ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.hardhat-node != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: ./ops/docker/hardhat
          file: ./ops/docker/hardhat/Dockerfile
          push: true
          tags: ethereumoptimism/hardhat-node:${{ needs.canary-publish.outputs.canary-docker-tag }}

  builder:
    name: Prepare the base builder image for the services
    needs: canary-publish
    runs-on: ubuntu-latest
    # we re-output the variables so that the child jobs can access them
    outputs:
      batch-submitter: ${{ needs.canary-publish.outputs.batch-submitter }}
      message-relayer: ${{ needs.canary-publish.outputs.message-relayer }}
      data-transport-layer: ${{ needs.canary-publish.outputs.data-transport-layer }}
      contracts: ${{ needs.canary-publish.outputs.contracts }}
      integration-tests: ${{ needs.canary-publish.outputs.integration-tests }}
      replica-healthcheck: ${{ needs.canary-publish.outputs.replica-healthcheck }}
      canary-docker-tag: ${{ needs.canary-publish.outputs.canary-docker-tag }}

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.monorepo
          push: true
          tags: ethereumoptimism/builder:${{ needs.canary-publish.outputs.canary-docker-tag }}

  message-relayer:
    name: Publish Message Relayer Version ${{ needs.builder.outputs.canary-docker-tag }}
    needs: builder
    if: needs.builder.outputs.message-relayer != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.message-relayer
          push: true
          tags: ethereumoptimism/message-relayer:${{ needs.builder.outputs.canary-docker-tag }}
          build-args: BUILDER_TAG=${{ needs.builder.outputs.canary-docker-tag }}

  batch-submitter:
    name: Publish Batch Submitter Version ${{ needs.builder.outputs.canary-docker-tag }}
    needs: builder
    if: needs.builder.outputs.batch-submitter != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.batch-submitter
          push: true
          tags: ethereumoptimism/batch-submitter:${{ needs.builder.outputs.canary-docker-tag }}
          build-args: BUILDER_TAG=${{ needs.builder.outputs.canary-docker-tag }}

  data-transport-layer:
    name: Publish Data Transport Layer Version ${{ needs.builder.outputs.canary-docker-tag }}
    needs: builder
    if: needs.builder.outputs.data-transport-layer != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.data-transport-layer
          push: true
          tags: ethereumoptimism/data-transport-layer:${{ needs.builder.outputs.canary-docker-tag }}
          build-args: BUILDER_TAG=${{ needs.builder.outputs.canary-docker-tag }}

  contracts:
    name: Publish Deployer Version ${{ needs.builder.outputs.canary-docker-tag }}
    needs: builder
    if: needs.builder.outputs.contracts != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.deployer
          push: true
          tags: ethereumoptimism/deployer:${{ needs.builder.outputs.canary-docker-tag }}
          build-args: BUILDER_TAG=${{ needs.builder.outputs.canary-docker-tag }}

  integration_tests:
    name: Publish Integration tests ${{ needs.builder.outputs.integration-tests }}
    needs: builder
    if: needs.builder.outputs.integration-tests != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.integration-tests
          push: true
          tags: ethereumoptimism/integration-tests:${{ needs.builder.outputs.canary-docker-tag }}
          build-args: BUILDER_TAG=${{ needs.builder.outputs.canary-docker-tag }}

  replica-healthcheck:
    name: Publish Data Transport Layer Version ${{ needs.builder.outputs.canary-docker-tag }}
    needs: builder
    if: needs.builder.outputs.replica-healthcheck != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.replica-healthcheck
          push: true
          tags: ethereumoptimism/replica-healthcheck:${{ needs.builder.outputs.canary-docker-tag }}
          build-args: BUILDER_TAG=${{ needs.builder.outputs.canary-docker-tag }}

  proxyd:
    name: Publish proxyd Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.proxyd != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Set build args
        id: build_args
        run: |
          echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
          echo ::set-output name=GITVERSION::$(jq -r .version ./go/proxyd/package.json)
          echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./go/proxyd/Dockerfile
          push: true
          tags: ethereumoptimism/proxyd:${{ needs.canary-publish.outputs.proxyd }}
          build-args: |
            GITDATE=${{ steps.build_args.outputs.GITDATE }}
            GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
            GITVERSION=${{ steps.build_args.outputs.GITVERSION }}

  op-exporter:
    name: Publish op-exporter Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.op-exporter != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Set build args
        id: build_args
        run: |
          echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
          echo ::set-output name=GITVERSION::$(jq -r .version ./go/op-exporter/package.json)
          echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.op-exporter
          push: true
          tags: ethereumoptimism/op-exporter:${{ needs.canary-publish.outputs.op-exporter }}
          build-args: |
            GITDATE=${{ steps.build_args.outputs.GITDATE }}
            GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
            GITVERSION=${{ steps.build_args.outputs.GITVERSION }}

  l2geth-exporter:
    name: Publish l2geth-exporter Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.l2geth-exporter != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Set build args
        id: build_args
        run: |
          echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
          echo ::set-output name=GITVERSION::$(jq -r .version ./go/l2geth-exporter/package.json)
          echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.l2geth-exporter
          push: true
          tags: ethereumoptimism/l2geth-exporter:${{ needs.canary-publish.outputs.l2geth-exporter }}
          build-args: |
            GITDATE=${{ steps.build_args.outputs.GITDATE }}
            GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
            GITVERSION=${{ steps.build_args.outputs.GITVERSION }}

  rpc-proxy:
    name: Publish rpc-proxy Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
    needs: canary-publish
    if: needs.canary-publish.outputs.rpc-proxy != ''
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
          password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.rpc-proxy
          push: true
          tags: ethereumoptimism/rpc-proxy:${{ needs.canary-publish.outputs.rpc-proxy }}
