name: Release

on:
  push:
    branches:
      - master

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    # map the step outputs to job outputs
    outputs:
      use_builder: ${{ steps.packages.outputs.use_builder }}
      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 }}
      proxyd: ${{ steps.packages.outputs.proxyd }}
      rpc-proxy: ${{ steps.packages.outputs.rpc-proxy }}
      hardhat-node: ${{ steps.packages.outputs.hardhat-node }}

    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
        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 12.x
        uses: actions/setup-node@master
        with:
          node-version: 12.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: Publish To NPM or Create Release Pull Request
        uses: changesets/action@master
        id: changesets
        with:
          publish: yarn release
        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
        if: steps.changesets.outputs.published == 'true'
        run: |
          node ops/scripts/ci-versions.js ${{ toJSON(steps.changesets.outputs.publishedPackages) }}

  # 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.release.outputs.l2geth }}
    needs: release
    if: needs.release.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.release.outputs.l2geth }},ethereumoptimism/l2geth:latest

      - name: Publish op_exporter
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.op_exporter
          push: true
          tags: ethereumoptimism/op_exporter:${{ needs.release.outputs.l2geth }}

      - name: Publish rpc-proxy
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.rpc-proxy
          push: true
          tags: ethereumoptimism/rpc-proxy:${{ needs.release.outputs.l2geth }},ethereumoptimism/rpc-proxy:latest

  gas-oracle:
    name: Publish Gas Oracle Version ${{ needs.release.outputs.gas-oracle }}
    needs: release
    if: needs.release.outputs.gas-oracle != ''
    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 Gas Oracle
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./ops/docker/Dockerfile.gas-oracle
          push: true
          tags: ethereumoptimism/gas-oracle:${{ needs.release.outputs.gas-oracle }},ethereumoptimism/gas-oracle:latest

  hardhat-node:
    name: Publish Hardhat Node ${{ needs.release.outputs.hardhat-node }}
    needs: release
    if: needs.release.hardhat-node != ''
    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 Hardhat Node
        uses: docker/build-push-action@v2
        with:
          context: ./ops/docker/hardhat
          file: ./Dockerfile
          push: true
          tags: ethereumoptimism/hardhat-node:${{ needs.release.outputs.gas-oracle }},ethereumoptimism/hardhat-node:latest

  proxyd:
    name: Publish proxyd Version ${{ needs.release.outputs.proxyd }}
    needs: release
    if: needs.release.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 env
        run: |
          echo "GITDATE=$(date)" >> $GITHUB_ENV"

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: ./go/proxyd
          file: ./Dockerfile
          push: true
          tags: ethereumoptimism/proxyd:${{ needs.release.outputs.proxyd }},ethereumoptimism/proxyd:latest
          build-args: |
            GITCOMMIT=$GITHUB_SHA
            GITDATE=$GITDATE

  rpc-proxy:
    name: Publish rpc-proxy Version ${{ needs.release.outputs.rpc-proxy }}
    needs: release
    if: needs.release.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: Set env
        run: |
          echo "GITDATE=$(date)" >> $GITHUB_ENV"

      - 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.release.outputs.rpc-proxy }},ethereumoptimism/rpc-proxy:latest

  # pushes the base builder image to dockerhub
  builder:
    name: Prepare/Publish the base builder image for the services ${{ needs.release.outputs.builder }}
    needs: release
    # Build the builder if a dep of the builder has an update or if the builder
    # has had its version bumped. TODO: remove the left hand side once tagged
    # releases of the builder are released so that pulled builder images are
    # used
    if: ${{ needs.release.outputs.use_builder == 'true' || needs.release.outputs.builder != '' }}
    runs-on: ubuntu-latest
    # we re-output the variables so that the child jobs can access them
    outputs:
      builder: ${{ needs.release.outputs.builder || 'latest' }}
      batch-submitter: ${{ needs.release.outputs.batch-submitter }}
      message-relayer: ${{ needs.release.outputs.message-relayer }}
      data-transport-layer: ${{ needs.release.outputs.data-transport-layer }}
      contracts: ${{ needs.release.outputs.contracts }}
      integration-tests: ${{ needs.release.outputs.integration-tests }}
      replica-healthcheck: ${{ needs.release.outputs.replica-healthcheck }}

    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.monorepo
          push: true
          tags: ethereumoptimism/builder:latest

  message-relayer:
    name: Publish Message Relayer Version ${{ needs.builder.outputs.message-relayer }}
    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.message-relayer }},ethereumoptimism/message-relayer:latest
          build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}

  batch-submitter:
    name: Publish Batch Submitter Version ${{ needs.builder.outputs.batch-submitter }}
    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.batch-submitter }},ethereumoptimism/batch-submitter:latest
          build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}

  data-transport-layer:
    name: Publish Data Transport Layer Version ${{ needs.builder.outputs.data-transport-layer }}
    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.data-transport-layer }},ethereumoptimism/data-transport-layer:latest
          build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}

  contracts:
    name: Publish Deployer Version ${{ needs.builder.outputs.contracts }}
    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.contracts }},ethereumoptimism/deployer:latest
          build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}

  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.integration-tests }},ethereumoptimism/integration-tests:latest
          build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}

  replica-healthcheck:
    name: Publish Replica Healthcheck Version ${{ needs.builder.outputs.replica-healthcheck }}
    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.replica-healthcheck }},ethereumoptimism/replica-healthcheck:latest
          build-args: BUILDER_TAG=${{ needs.builder.outputs.builder }}
