name: stacks-blockchain-api

on:
  push:
    branches:
      - '**'
    tags-ignore:
      - '**'
    paths-ignore:
      - '**/CHANGELOG.md'
      - '**/package.json'
  pull_request:
  workflow_dispatch:

jobs:
  notify-start:
    runs-on: ubuntu-latest
    # Only run on non-PR events or only PRs that aren't from forks
    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
    outputs:
      slack_message_id: ${{ steps.slack.outputs.message_id }}
    steps:
      - name: Notify slack start
        if: success()
        id: slack
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
        uses: voxmedia/github-action-slack-notify-build@v1.1.2
        with:
          channel: devops-notify
          status: STARTING
          color: warning
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
          check-latest: true

      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          path: |
            ~/.npm
            node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - name: Install deps
        run: npm install --audit=false

      - name: Lint ESLint
        run: npm run lint:eslint

      - name: Lint Prettier
        run: npm run lint:prettier

  lint-docs:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./docs
    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
          check-latest: true

      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          path: |
            ~/.npm
            node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - name: Install deps
        run: npm install --audit=false

      - name: Build schema & docs
        run: npm run build

      - name: Validate generated types
        run: tsc index.d.ts

      - name: Lint JSON
        run: npm run lint:json

      - name: Lint YAML
        run: npm run lint:yaml

      - name: Validate schemas
        run: npm run validate:schemas

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
          check-latest: true

      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          path: |
            ~/.npm
            node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - name: Install deps
        run: npm install --audit=false

      - name: Setup env vars
        run: echo "STACKS_CORE_EVENT_HOST=http://0.0.0.0" >> $GITHUB_ENV

      - name: Setup integration environment
        run: |
          sudo ufw disable
          npm run devenv:deploy -- -d
          npm run devenv:logs -- --no-color &> docker-compose-logs.txt &

      - name: Run tests
        run: npm run test

      - name: Print integration environment logs
        run: cat docker-compose-logs.txt
        if: failure()

      - name: Teardown integration environment
        run: npm run devenv:stop
        if: always()

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v1
        if: always()

  test-bns:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
          check-latest: true

      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          path: |
            ~/.npm
            node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - name: Install deps
        run: npm install --audit=false

      - name: Setup env vars
        run: echo "STACKS_CORE_EVENT_HOST=http://0.0.0.0" >> $GITHUB_ENV

      - name: Setup integration environment
        run: |
          sudo ufw disable
          npm run devenv:deploy -- -d
          npm run devenv:logs -- --no-color &> docker-compose-logs.txt &

      - name: Run bns tests
        run: npm run test:bns

      - name: Print integration environment logs
        run: cat docker-compose-logs.txt
        if: failure()

      - name: Teardown integration environment
        run: npm run devenv:stop
        if: always()

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v1
        if: always()

  test-rosetta:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
          check-latest: true

      - name: Cache node modules
        uses: actions/cache@v2
        env:
          cache-name: cache-node-modules
        with:
          path: |
            ~/.npm
            node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - name: Install deps
        run: npm install --audit=false

      - name: Setup env vars
        run: echo "STACKS_CORE_EVENT_HOST=http://0.0.0.0" >> $GITHUB_ENV

      - name: Setup integration environment
        run: |
          sudo ufw disable
          npm run devenv:deploy -- -d
          npm run devenv:logs -- --no-color &> docker-compose-logs.txt &

      - name: Run tests
        run: npm run test:rosetta

      - name: Print integration environment logs
        run: cat docker-compose-logs.txt
        if: failure()

      - name: Teardown integration environment
        run: npm run devenv:stop
        if: always()

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v1
        if: always()

  test-tokens:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js
        uses: actions/setup-node@v1
        with:
          node-version: '14.x'

      - name: Install deps
        run: npm install

      - name: Setup env vars
        run: echo "STACKS_CORE_EVENT_HOST=http://0.0.0.0" >> $GITHUB_ENV

      - name: Setup integration environment
        run: |
          sudo ufw disable
          npm run devenv:deploy -- -d
          npm run devenv:logs -- --no-color &> docker-compose-logs.txt &

      - name: Run tokens tests
        run: npm run test:tokens

      - name: Print integration environment logs
        run: cat docker-compose-logs.txt
        if: failure()

      - name: Teardown integration environment
        run: npm run devenv:stop
        if: always()

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v1
        if: always()

  build-publish:
    runs-on: ubuntu-latest
    needs:
      - test
      - test-rosetta
      - lint
      - lint-docs
    steps:
      - uses: actions/checkout@v2
        with:
          token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}

      - name: Semantic Release
        uses: cycjimmy/semantic-release-action@v2.5.0
        id: semantic
        # Only run on non-PR events or only PRs that aren't from forks
        if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          SEMANTIC_RELEASE_PACKAGE: ${{ github.workflow }}
        with:
          extra_plugins: |
            @semantic-release/changelog
            @semantic-release/git
            semantic-release-slack-bot
            @semantic-release/exec

      - name: Build/Tag/Push Image
        uses: docker/build-push-action@v1
        with:
          repository: blockstack/${{ github.workflow }}
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}
          tags: ${{ steps.semantic.outputs.new_release_version }}
          tag_with_ref: true
          add_git_labels: true
          # Only push if (there's a new release on main branch, or if building a non-main branch) and (Only run on non-PR events or only PRs that aren't from forks)
          push: ${{ (github.ref != 'refs/heads/master' || steps.semantic.outputs.new_release_version != '') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}

      - name: Build/Tag/Push standalone Image
        uses: docker/build-push-action@v1
        with:
          dockerfile: follower.Dockerfile
          repository: blockstack/${{ github.workflow }}-standalone
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}
          tags: ${{ steps.semantic.outputs.new_release_version }}
          tag_with_ref: true
          add_git_labels: true
          # Only push if (there's a new release on main branch, or if building a non-main branch) and (Only run on non-PR events or only PRs that aren't from forks)
          push: ${{ (github.ref != 'refs/heads/master' || steps.semantic.outputs.new_release_version != '') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}

  notify-end:
    runs-on: ubuntu-latest
    needs:
      - notify-start
      - lint
      - lint-docs
      - test
      - test-rosetta
      - build-publish
    # Only run on non-PR events or only PRs that aren't from forks
    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
    steps:
      - name: Notify slack success
        if: needs.notify-start.result != 'failure' && needs.lint.result != 'failure' && needs.lint-docs.result != 'failure' && needs.test.result != 'failure' && needs.build-publish.result != 'failure'
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
        uses: voxmedia/github-action-slack-notify-build@v1.1.2
        with:
          message_id: ${{ needs.notify-start.outputs.slack_message_id }}
          channel: devops-notify
          status: SUCCESS
          color: good

      - name: Notify slack fail
        if: needs.notify-start.result == 'failure' || needs.lint.result == 'failure' || needs.lint-docs.result == 'failure' || needs.test.result == 'failure' || needs.build-publish.result == 'failure'
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
        uses: voxmedia/github-action-slack-notify-build@v1.1.2
        with:
          message_id: ${{ needs.notify-start.outputs.slack_message_id }}
          channel: devops-notify
          status: FAILED
          color: danger
