name: joystream-node-docker

on: push

env:
  REPOSITORY: joystream/node
  KEY_NAME: joystream-github-action-key

jobs:
  push-amd64:
    name: Build joystream/node Docker image for amd64
    runs-on: ubuntu-latest
    outputs:
      tag_shasum: ${{ steps.compute_shasum.outputs.shasum }}
      image_exists: ${{ steps.compute_main_image_exists.outputs.image_exists }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - uses: actions/setup-node@v1
        with:
          node-version: '14.x'

      - id: compute_shasum
        name: Compute runtime code shasum
        run: |
          export RUNTIME_CODE_SHASUM=`scripts/runtime-code-shasum.sh`
          echo "::set-output name=shasum::${RUNTIME_CODE_SHASUM}"

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Check if we have already have the manifest on Dockerhub
        id: compute_main_image_exists
        # Will output 0 if image exists and 1 if does not exists
        run: |
          export IMAGE_EXISTS=$(docker manifest inspect ${{ env.REPOSITORY }}:${{ steps.compute_shasum.outputs.shasum }} > /dev/null ; echo $?)
          echo "::set-output name=image_exists::${IMAGE_EXISTS}"

      - name: Check if we have pre-built image on Dockerhub
        id: compute_image_exists
        # Will output 0 if image exists and 1 if does not exists
        run: |
          export IMAGE_EXISTS=$(docker manifest inspect ${{ env.REPOSITORY }}:${{ steps.compute_shasum.outputs.shasum }}-amd64 > /dev/null ; echo $?)
          echo "::set-output name=image_exists::${IMAGE_EXISTS}"

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: joystream-node.Dockerfile
          platforms: linux/amd64
          push: true
          tags: ${{ env.REPOSITORY }}:${{ steps.compute_shasum.outputs.shasum }}-amd64
        if: ${{ steps.compute_image_exists.outputs.image_exists == 1 }}

  push-arm:
    name: Build joystream/node Docker image for arm
    runs-on: ubuntu-latest
    strategy:
      matrix:
        platform: ['linux/arm64', 'linux/arm/v7']
        include:
          - platform: 'linux/arm64'
            platform_tag: 'arm64'
            file: 'joystream-node.Dockerfile'
          - platform: 'linux/arm/v7'
            platform_tag: 'arm'
            file: 'joystream-node-armv7.Dockerfile'
    env:
      STACK_NAME: build-joystream-node-docker-ga-${{ github.run_number }}-${{ matrix.platform_tag }}
    steps:
      - name: Extract branch name
        shell: bash
        run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
        id: extract_branch

      - name: Checkout
        uses: actions/checkout@v2

      - uses: actions/setup-node@v1
        with:
          node-version: '14.x'

      - name: Install Ansible dependencies
        run: pipx inject ansible-core boto3 botocore

      - id: compute_shasum
        name: Compute runtime code shasum
        run: |
          export RUNTIME_CODE_SHASUM=`scripts/runtime-code-shasum.sh`
          echo "::set-output name=shasum::${RUNTIME_CODE_SHASUM}"

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Check if we have pre-built image on Dockerhub
        id: compute_image_exists
        # Will output 0 if image exists and 1 if does not exists
        run: |
          export IMAGE_EXISTS=$(docker manifest inspect ${{ env.REPOSITORY }}:${{ steps.compute_shasum.outputs.shasum }}-${{ matrix.platform_tag }} > /dev/null ; echo $?)
          echo "::set-output name=image_exists::${IMAGE_EXISTS}"

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
        if: ${{ steps.compute_image_exists.outputs.image_exists == 1 }}

      - name: Deploy to AWS CloudFormation
        uses: aws-actions/aws-cloudformation-github-deploy@v1
        id: deploy_stack
        with:
          name: ${{ env.STACK_NAME }}
          template: devops/aws/cloudformation/single-instance-docker.yml
          no-fail-on-empty-changeset: '1'
          parameter-overrides: 'KeyName=${{ env.KEY_NAME }},EC2AMI=ami-00d1ab6b335f217cf,EC2InstanceType=t4g.xlarge'
        if: ${{ steps.compute_image_exists.outputs.image_exists == 1 }}

      - name: Run playbook
        uses: dawidd6/action-ansible-playbook@v2
        with:
          playbook: build-arm64-playbook.yml
          directory: devops/aws
          requirements: requirements.yml
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          inventory: |
            [all]
            ${{ steps.deploy_stack.outputs.PublicIp }}
          options: |
            --extra-vars "git_repo=https://github.com/${{ github.repository }} \
                          branch_name=${{ steps.extract_branch.outputs.branch }} \
                          docker_username=${{ secrets.DOCKERHUB_USERNAME }} \
                          docker_password=${{ secrets.DOCKERHUB_PASSWORD }} \
                          tag_name=${{ steps.compute_shasum.outputs.shasum }}-${{ matrix.platform_tag }} \
                          repository=${{ env.REPOSITORY }} dockerfile=${{ matrix.file }} \
                          platform=${{ matrix.platform }}"
        if: ${{ steps.compute_image_exists.outputs.image_exists == 1 }}

      - name: Delete CloudFormation Stack
        if: always()
        continue-on-error: true
        run: |
          echo "Deleting ${{ env.STACK_NAME }} stack"
          aws cloudformation delete-stack --stack-name ${{ env.STACK_NAME }}
          echo "Waiting for ${{ env.STACK_NAME }} to be deleted..."
          aws cloudformation wait stack-delete-complete --stack-name ${{ env.STACK_NAME }}

  push-manifest:
    name: Create manifest using both the arch images
    needs: [push-amd64, push-arm]
    # Only run this job if the image does not exist with tag equal to the shasum
    if: needs.push-amd64.outputs.image_exists == 1
    runs-on: ubuntu-latest
    env:
      TAG_SHASUM: ${{ needs.push-amd64.outputs.tag_shasum }}
    steps:
      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}

      - name: Create manifest for multi-arch images
        run: |
          # get artifacts from previous steps
          IMAGE=${{ env.REPOSITORY }}:${{ env.TAG_SHASUM }}
          echo $IMAGE
          docker pull $IMAGE-amd64
          docker pull $IMAGE-arm64
          docker pull $IMAGE-arm
          docker manifest create $IMAGE $IMAGE-amd64 $IMAGE-arm64 $IMAGE-arm
          docker manifest annotate $IMAGE $IMAGE-amd64 --arch amd64
          docker manifest annotate $IMAGE $IMAGE-arm64 --arch arm64
          docker manifest annotate $IMAGE $IMAGE-arm --arch arm
          docker manifest push $IMAGE

      - name: Create manifest with latest tag for master
        if: github.ref == 'refs/heads/master'
        run: |
          IMAGE=${{ env.REPOSITORY }}:${{ env.TAG_SHASUM }}
          LATEST_TAG=${{ env.REPOSITORY }}:latest
          docker manifest create $LATEST_TAG $IMAGE-amd64 $IMAGE-arm64 $IMAGE-arm
          docker manifest annotate $LATEST_TAG $IMAGE-amd64 --arch amd64
          docker manifest annotate $LATEST_TAG $IMAGE-arm64 --arch arm64
          docker manifest annotate $LATEST_TAG $IMAGE-arm --arch arm
          docker manifest push $LATEST_TAG
