name: (CD) Publish docker + s3

on:
  workflow_call:
    inputs:
      projects:
        required: true
        type: string

jobs:
  publish-dist:
    strategy:
      fail-fast: false
      matrix:
        app: ${{ fromJSON(inputs.projects) }}
    name: ${{ matrix.app }}
    runs-on: ubuntu-22.04
    timeout-minutes: 25
    steps:
      - name: Check out code
        uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}

      - name: Init variables
        run: |
          echo IS_PR=false >> $GITHUB_ENV
          echo IS_MAINNET_RELEASE=false >> $GITHUB_ENV
          echo IS_TESTNET_RELEASE=false >> $GITHUB_ENV
          echo IS_IPFS_RELEASE=false >> $GITHUB_ENV
          echo IS_S3_RELEASE=false >> $GITHUB_ENV
          echo IS_DEV_IMAGE=false >> $GITHUB_ENV

      - name: Is dev image
        if: ${{ contains(github.ref, 'develop') && github.event_name == 'push' && matrix.app == 'trading' }}
        run: |
          echo IS_DEV_IMAGE=true >> $GITHUB_ENV

      - name: Is PR
        if: ${{ github.event_name == 'pull_request' }}
        run: |
          echo IS_PR=true >> $GITHUB_ENV

      - name: Is mainnet release
        if: ${{ contains(github.ref, 'release/mainnet') && !contains(github.ref, 'mirror') }}
        run: |
          echo IS_MAINNET_RELEASE=true >> $GITHUB_ENV

      - name: Is testnet release
        if: ${{ contains(github.ref, 'release/testnet') }}
        run: |
          echo IS_TESTNET_RELEASE=true >> $GITHUB_ENV

      - name: Is IPFS Release
        if: ${{ matrix.app == 'trading' && github.event_name == 'push' && ( env.IS_MAINNET_RELEASE == 'true' || env.IS_TESTNET_RELEASE == 'true' ) }}
        run: |
          echo IS_IPFS_RELEASE=true >> $GITHUB_ENV

      - name: Is S3 Release
        if: ${{ env.IS_IPFS_RELEASE == 'false' && github.event_name == 'push' }}
        run: |
          echo IS_S3_RELEASE=true >> $GITHUB_ENV

      - name: Set up QEMU
        id: quemu
        uses: docker/setup-qemu-action@v2

      - name: Available platforms
        run: echo ${{ steps.qemu.outputs.platforms }}

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

      - name: Log in to the Container registry (ghcr)
        if: ${{ env.IS_PR == 'true' }}
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Log in to the Container registry (docker hub)
        uses: docker/login-action@v2
        if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true' }}
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version-file: '.nvmrc'
          # https://stackoverflow.com/questions/61010294/how-to-cache-yarn-packages-in-github-actions
          cache: yarn

      - name: Cache node modules
        uses: actions/cache@v3
        with:
          path: node_modules
          key: ${{ runner.os }}-cache-node-modules-${{ hashFiles('yarn.lock') }}

      # https://docs.github.com/en/actions/learn-github-actions/contexts
      - name: Define dist variables
        if: ${{ github.event_name == 'push' }}
        run: |
          python3 tools/ci/define-dist-variables.py --github-ref="${{ github.ref }}" --app="${{ matrix.app }}"

      - name: Verify script result
        if: ${{ github.event_name == 'push' }}
        run: |
          echo "BUCKET_NAME=${{ env.BUCKET_NAME }}"
          echo "ENV_NAME=${{ env.ENV_NAME }}"

      - name: Build local dist
        run: |
          envCmd=""
          if [[ ! -z "${{ env.ENV_NAME }}" ]]; then
            envCmd="yarn env-cmd -f ./apps/${{ matrix.app }}/.env.${{ env.ENV_NAME }}"
          fi

          if [ "${{ matrix.app }}" = "trading" ]; then
            $envCmd yarn nx export trading || (yarn install && $envCmd yarn nx export trading)
            DIST_LOCATION=dist/apps/trading/exported
          elif [ "${{ matrix.app }}" = "ui-toolkit" ]; then
            NODE_ENV=production yarn nx run ui-toolkit:build-storybook
            DIST_LOCATION=dist/storybook/ui-toolkit
          elif [ "${{ matrix.app }}" = "static" ]; then
            yarn nx build static || (yarn install && yarn nx build static)
          else
            $envCmd yarn nx build ${{ matrix.app }} || (yarn install && $envCmd yarn nx build ${{ matrix.app }})
          fi
          if [[ -z "$DIST_LOCATION" ]]; then
            DIST_LOCATION=dist/apps/${{ matrix.app }}
          fi
          mv $DIST_LOCATION dist-result
          tree dist-result

      - name: Build and export to local Docker
        id: docker_build
        uses: docker/build-push-action@v3
        with:
          context: .
          file: docker/node-outside-docker.Dockerfile
          load: true
          build-args: |
            APP=${{ matrix.app }}
            ENV_NAME=${{ env.ENV_NAME }}
          tags: |
            ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local

      - name: Image digest
        if: ${{ env.IS_PR == 'true' }}
        run: echo ${{ steps.docker_build.outputs.digest }}

      - name: Sanity check docker image
        run: |
          echo "Check ipfs-hash"
          docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash
          docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local cat /ipfs-hash > ${{ matrix.app }}-ipfs-hash
          echo "List html directory"
          docker run --rm ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:local sh -c 'apk add --update tree; tree /usr/share/nginx/html'

      - name: Publish dist as docker image (ghcr)
        uses: docker/build-push-action@v3
        continue-on-error: true
        id: ghcr-push
        if: ${{ env.IS_PR == 'true' }}
        with:
          context: .
          file: docker/node-outside-docker.Dockerfile
          push: true
          build-args: |
            APP=${{ matrix.app }}
            ENV_NAME=${{ env.ENV_NAME }}
          tags: |
            ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}

      - name: Publish dist as docker image (docker hub)
        uses: docker/build-push-action@v3
        continue-on-error: true
        id: dockerhub-push
        if: ${{ env.IS_IPFS_RELEASE == 'true' || env.IS_DEV_IMAGE == 'true'  }}
        with:
          context: .
          file: docker/node-outside-docker.Dockerfile
          push: true
          build-args: |
            APP=${{ matrix.app }}
            ENV_NAME=${{ env.ENV_NAME }}
          tags: |
            vegaprotocol/${{ matrix.app }}:${{ github.sha }}
            vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || env.IS_DEV_IMAGE == 'true' && 'develop' || '' }}

      - name: Publish dist as docker image (ghcr - retry)
        uses: docker/build-push-action@v3
        if: ${{ steps.ghcr-push.outcome == 'failure' }}
        with:
          context: .
          file: docker/node-outside-docker.Dockerfile
          push: true
          build-args: |
            APP=${{ matrix.app }}
            ENV_NAME=${{ env.ENV_NAME }}
          tags: |
            ghcr.io/vegaprotocol/frontend/${{ matrix.app }}:${{ github.event.pull_request.head.sha || github.sha }}

      - name: Publish dist as docker image (docker hub - retry)
        uses: docker/build-push-action@v3
        if: ${{ steps.dockerhub-push.outcome == 'failure' }}
        with:
          context: .
          file: docker/node-outside-docker.Dockerfile
          push: true
          build-args: |
            APP=${{ matrix.app }}
            ENV_NAME=${{ env.ENV_NAME }}
          tags: |
            vegaprotocol/${{ matrix.app }}:${{ github.sha }}
            vegaprotocol/${{ matrix.app }}:${{ env.IS_MAINNET_RELEASE == 'true' && 'mainnet' || env.IS_TESTNET_RELEASE == 'true' && 'testnet' || '' }}

      # bucket creation in github.com/vegaprotocol/terraform//frontend
      - name: Publish dist to s3
        uses: jakejarvis/s3-sync-action@master
        # s3 releases are not happening for trading on mainnet - it's IPFS
        if: ${{ env.IS_S3_RELEASE == 'true' }}
        with:
          args: --acl private --follow-symlinks --delete
        env:
          AWS_S3_BUCKET: ${{ env.BUCKET_NAME }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: 'eu-west-1'
          SOURCE_DIR: 'dist-result'

      - name: Install aws CLI
        if: ${{ env.IS_S3_RELEASE == 'true' }}
        uses: unfor19/install-aws-cli-action@master

      - name: Perform cache invalidation
        if: ${{ env.IS_S3_RELEASE == 'true' }}
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: 'eu-west-1'
        run: |
          echo "Looking for distribution for bucket: ${{ env.BUCKET_NAME }}"
          id=$(aws cloudfront list-distributions | jq -Mrc '.DistributionList.Items | .[] | select(.DefaultCacheBehavior.TargetOriginId == "${{ env.BUCKET_NAME }}") | .Id')
          echo "Found id is: ${id}"
          aws cloudfront create-invalidation --distribution-id $id --paths "/*"

      - name: Add preview label
        uses: actions-ecosystem/action-add-labels@v1
        if: ${{ env.IS_PR == 'true' }}
        with:
          labels: ${{ matrix.app }}-preview
          number: ${{ github.event.number }}

      - name: Trigger fleek deployment
        # release to ipfs happens only on mainnet (represented by main branch) for trading
        if: ${{ env.IS_IPFS_RELEASE == 'true' }}
        run: |
          if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
            # display info about app
            curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
              -H "Content-Type: application/json" \
              -d '{"query": "query{getSiteById(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id latestDeploy{id status}}}"}' \
              https://api.fleek.co/graphql

            # trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
            curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
              -H "Content-Type: application/json" \
              -d '{"query": "mutation{triggerDeploy(siteId:\"f8f2e051-f18e-49e6-b876-0a39369dc0d8\"){id status}}"}' \
              https://api.fleek.co/graphql

          elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
            # display info about app
            curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
              -H "Content-Type: application/json" \
              -d '{"query": "query{getSiteById(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id latestDeploy{id status}}}"}' \
              https://api.fleek.co/graphql

            # trigger new deployment as base image is always set to vegaprotocol/trading:mainnet
            curl --fail -H "Authorization: ${{ secrets.FLEEK_API_KEY }}" \
              -H "Content-Type: application/json" \
              -d '{"query": "mutation{triggerDeploy(siteId:\"79baaeca-1952-4ae7-a256-f668cfc1d68e\"){id status}}"}' \
              https://api.fleek.co/graphql
          fi

      - name: Check out ipfs-redirect
        if: ${{ env.IS_IPFS_RELEASE == 'true' }}
        uses: actions/checkout@v3
        with:
          repository: 'vegaprotocol/ipfs-redirect'
          path: 'ipfs-redirect'
          fetch-depth: '0'
          token: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}

      - name: Update interstitial page to point to the new console
        if: ${{ env.IS_IPFS_RELEASE == 'true' }}
        env:
          GH_TOKEN: ${{ secrets.VEGA_CI_BOT_GITHUB_TOKEN }}
        run: |
          # set CID
          curl -L https://dist.ipfs.tech/kubo/v0.20.0/kubo_v0.20.0_linux-amd64.tar.gz -o kubo.tgz
          tar -xzf kubo.tgz
          export PATH="$PATH:$PWD/kubo"
          which ipfs
          new_hash=$(cat ${{ matrix.app }}-ipfs-hash)
          new_cid=$(ipfs cid format -v 1 -b base32 $new_hash)

          (
            cd ipfs-redirect

            # configure git
            git status
            cat .git/config
            git config --global user.email "vega-ci-bot@vega.xyz"
            git config --global user.name "vega-ci-bot"

            # update CID files
            if [[ "${{ env.IS_MAINNET_RELEASE }}" = "true" ]]; then
              echo $new_hash > cidv0-mainnet.txt
              echo $new_cid > cidv1-mainnet.txt
              git add cidv0-mainnet.txt cidv1-mainnet.txt
            elif [[ "${{ env.IS_TESTNET_RELEASE }}" = "true" ]]; then
              echo $new_hash > cidv0-fairground.txt
              echo $new_cid > cidv1-fairground.txt
              git add cidv0-fairground.txt cidv1-fairground.txt
            fi

            # create commit
            commit_msg="Automated hash update from ${{ github.ref }}"
            git commit -m "$commit_msg"
            git push -u origin "main"
          )
