name: Publish release candidate

# only one can tun at a time
concurrency: cd-publish-rc

# See for rationale https://github.com/ChainSafe/lodestar/blob/unstable/RELEASE.md
on:
  push:
    tags:
      - v*

jobs:
  tag:
    name: Check tag
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Get tag
        id: get_tag
        run: echo "tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT

      - name: Get previous tag
        id: get_prev_tag
        run: node scripts/get_prev_tag.js
        env:
          CURRENT_TAG: ${{ steps.get_tag.outputs.tag }}
          IGNORE_PATTERN: rc

      - name: Determine release type
        id: is_rc
        run: scripts/release/assert_valid_rc.sh
        env:
          TAG: ${{ steps.get_tag.outputs.tag }}

    outputs:
      is_rc: ${{ steps.is_rc.outputs.is_rc }}
      version: ${{ steps.is_rc.outputs.version }}
      tag: ${{ steps.get_tag.outputs.tag }}
      prev_tag: ${{ steps.get_prev_tag.outputs.prev_tag }}

  npm:
    name: Publish to NPM & Github
    runs-on: ubuntu-latest
    needs: tag
    if: needs.tag.outputs.is_rc == 'true'
    steps:
      # <common-build> - Uses YAML anchors in the future
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0 # Needs full depth for changelog generation
      - uses: actions/setup-node@v2
        with:
          node-version: 18
      - name: Node.js version
        id: node
        run: echo "v8CppApiVersion=$(node --print "process.versions.modules")" >> $GITHUB_OUTPUT
      - name: Restore dependencies
        uses: actions/cache@master
        id: cache-deps
        with:
          path: |
            node_modules
            packages/*/node_modules
          key: ${{ runner.os }}-${{ steps.node.outputs.v8CppApiVersion }}-${{ hashFiles('**/yarn.lock', '**/package.json') }}
      - name: Install & build
        if: steps.cache-deps.outputs.cache-hit != 'true'
        run: yarn install --frozen-lockfile --ignore-optional && yarn build
      - name: Build
        run: yarn build
        if: steps.cache-deps.outputs.cache-hit == 'true'
      # </common-build>

      - name: Generate changelog
        run: node scripts/generate_changelog_simple.js ${{ needs.tag.outputs.prev_tag }} ${{ needs.tag.outputs.tag }} CHANGELOG.md

      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ needs.tag.outputs.tag }}
          body_path: "CHANGELOG.md"
          release_name: Release ${{ needs.tag.outputs.tag }}
          prerelease: true

      - name: Change and commit version
        # Write version before publishing so it's picked up by `lerna publish from-package`.
        # It must also be committed to ensure a clean git tree, otherwise `lerna publish` errors.
        # This "temp" commit doesn't change the actually release commit which is captured above.
        # git-data is also correct, since it's generated at build time, before `lerna version` run.
        run: |
          node_modules/.bin/lerna version ${{ needs.tag.outputs.version }} \
          --force-publish \
          --exact \
          --yes \
          --no-git-tag-version

          git config user.name 'temp'
          git config user.email 'temp@github.com'
          git commit -am "${{ needs.tag.outputs.version }}"

      # From https://github.com/lerna/lerna/issues/2404
      - run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Publish to npm registry
        run: yarn run release:publish --dist-tag rc
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      # In case of failure
      - name: Rollback on failure
        if: failure()
        uses: author/action-rollback@9ec72a6af74774e00343c6de3e946b0901c23013
        with:
          id: ${{ steps.create_release.outputs.id }}
          tag: ${{ needs.tag.outputs.tag }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  docker:
    name: Publish to Docker Hub
    runs-on: ubuntu-latest
    needs: [tag, npm]
    if: needs.tag.outputs.is_rc == 'true'
    steps:
      - uses: actions/checkout@v2
      - run: scripts/await-release.sh ${{ needs.tag.outputs.tag }} rc 900
      # https://github.com/docker/setup-qemu-action
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      # https://github.com/docker/setup-buildx-action
      - 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_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and push
        run: >
          docker buildx build . --push
          --tag chainsafe/lodestar:rc
          --tag chainsafe/lodestar:${{ needs.tag.outputs.tag }}
          --platform linux/amd64,linux/arm64
          --build-arg COMMIT=$(git rev-parse HEAD)

      - run: docker run chainsafe/lodestar:${{ needs.tag.outputs.tag }} --help
      # Display history to know byte size of each layer
      # Image is available only because of the previous `docker run` command
      - run: docker image history chainsafe/lodestar:${{ needs.tag.outputs.tag }}

      - name: Build and push custom Grafana
        run: >
          docker buildx build ./docker/grafana/ --push
          --file ./docker/grafana/Dockerfile
          --build-context dashboards=./dashboards
          --tag chainsafe/lodestar-grafana:${{ needs.tag.outputs.tag }}
          --platform linux/amd64,linux/arm64

      - name: Build and push custom Prometheus
        run: >
          docker buildx build ./docker/prometheus/ --push
          --file ./docker/prometheus/Dockerfile
          --tag chainsafe/lodestar-prometheus:${{ needs.tag.outputs.tag }}
          --platform linux/amd64,linux/arm64
