name: Build, test, analyze and publish

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]
    paths-ignore:
      - '**/*.md'
      - '**/*.png'
  workflow_dispatch:

jobs:

  # Run linter to ensure new code respect coding rules
  lint:
    name: Lint code
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: 15
      - name: Setup metrics
        run: npm ci
      - name: Check contributions requirements
        run: npm test -- ci.test.js --noStackTrace
      - name: Run linter
        run: npm run linter

  # Build docker image from branch and run tests
  build:
    name: Build and test
    runs-on: ubuntu-latest
    needs: [ lint ]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Format code with dprint
        run: |
          curl -fsSL https://dprint.dev/install.sh | sh
          cp /home/runner/.dprint/bin/dprint /usr/local/bin/dprint
          npm install -g eslint
          dprint fmt --config .github/config/dprint.json
          npm run format
      - name: Build lowlighter/metrics:${{ github.head_ref || 'master' }}
        run: docker build -t lowlighter/metrics:$(echo ${{ github.head_ref || 'master' }} | sed 's/\//-/g') .
      - name: Run tests
        run: docker run --workdir=/metrics --entrypoint="" lowlighter/metrics:$(echo ${{ github.head_ref || 'master' }} | sed 's/\//-/g') npm test -- metrics.test.js

  # Run CodeQL on branch
  analyze:
    name: Analyze code
    runs-on: ubuntu-latest
    needs: [ lint ]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Setup CodeQL
        uses: github/codeql-action/init@v1
        with:
          languages: javascript
          config-file: ./.github/config/codeql.yml
      - name: Analyze code
        uses: github/codeql-action/analyze@v1

  # Format code
  format:
    name: Format code
    runs-on: ubuntu-latest
    needs: [ build, analyze ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Dprint
        run: |
          curl -fsSL https://dprint.dev/install.sh | sh
          cp /home/runner/.dprint/bin/dprint /usr/local/bin/dprint
          npm install -g eslint
      - name: Checkout master
        run: git checkout master
      - name: Format code
        run: |
          dprint fmt --config .github/config/dprint.json
          npm run format
      - name: Publish formatted code
        run: |
          set +e
          git status
          git add --update
          git commit -m "Auto-format code"
          git push
          set -e

  # Update plugins and template indexes, along with README.md
  update-indexes:
    name: Publish rebuilt metrics indexes
    runs-on: ubuntu-latest
    needs: [ build, analyze, format ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Setup NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: 15
      - name: Setup metrics
        run: npm ci
      - name: Publish rebuild metrics indexes
        run: npm run index -- publish

  # Rebase main branch on master
  update-main:
    name: Rebase main on master
    runs-on: ubuntu-latest
    needs: [ update-indexes ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: 15
      - name: Checkout main
        run: git checkout main
      - name: Rebase main on master
        run: git merge master
      - name: Push main
        run: git push origin main

  # Build docker image from master and publish it to GitHub registry
  docker-master:
    name: Publish master to GitHub registry
    runs-on: ubuntu-latest
    needs: [ update-indexes ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Login to GitHub registry
        run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      - name: Build docker image
        run: docker build -t ghcr.io/lowlighter/metrics:master .
      - name: Publish to GitHub registry
        run: docker push ghcr.io/lowlighter/metrics:master
      - name: Tag docker image (beta) and publish to GitHub registry
        run: |
          set +e
          METRICS_VERSION=$(cat package.json | grep -Po '(?<="version": ")\d+[.]\d+(?=[.]0-beta")')
          METRICS_VERSION_BETA="$METRICS_VERSION-beta"
          set -e
          if [[ "$METRICS_VERSION_BETA" != "v-beta" ]]; then
            echo "Beta version: v$METRICS_VERSION_BETA"
            docker tag ghcr.io/lowlighter/metrics:master ghcr.io/lowlighter/metrics:$(echo "v$METRICS_VERSION_BETA")
            docker push ghcr.io/lowlighter/metrics:$(echo "v$METRICS_VERSION_BETA")
          fi
      - name: Tag docker image (main) and publish to GitHub registry
        run: |
          docker tag ghcr.io/lowlighter/metrics:master ghcr.io/lowlighter/metrics:main
          docker push ghcr.io/lowlighter/metrics:main

  # Test lowlighter/metrics@master
  action-master-test:
    name: Test lowlighter/metrics@master
    runs-on: ubuntu-latest
    needs: [ docker-master ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    steps:
      - name: Run tests
        uses: lowlighter/metrics@master
        with:
          token: MOCKED_TOKEN
          plugins_errors_fatal: yes
          dryrun: yes
          use_mocked_data: yes
          verify: yes
          use_prebuilt_image: no

  # Build docker image from master and publish it to GitHub registry with release tag
  docker-release:
    name: Publish release to GitHub registry
    runs-on: ubuntu-latest
    needs: [ action-master-test ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[release]')
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Login to GitHub registry
        run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      - name: Pull docker image (master)
        run: docker pull ghcr.io/lowlighter/metrics:master
      - name: Tag docker image (release)
        run: docker tag ghcr.io/lowlighter/metrics:master ghcr.io/lowlighter/metrics:$(echo '${{ github.event.head_commit.message }}' | grep -Po 'v\d+[.]\d+')
      - name: Publish release to GitHub registry
        run: docker push ghcr.io/lowlighter/metrics:$(echo '${{ github.event.head_commit.message }}' | grep -Po 'v\d+[.]\d+')
      - name: Tag docker image (latest)
        run: docker tag ghcr.io/lowlighter/metrics:master ghcr.io/lowlighter/metrics:latest
      - name: Publish latest to GitHub registry
        run: docker push ghcr.io/lowlighter/metrics:latest

  # Rebase latest branch on master
  update-latest:
    name: Rebase latest on master
    runs-on: ubuntu-latest
    needs: [ docker-release ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[release]')
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: 15
      - name: Setup metrics
        run: npm ci
      - name: Checkout latest
        run: git checkout latest
      - name: Rebase latest on master
        run: git merge master
      - name: Push latest
        run: git push origin latest

  # Test lowlighter/metrics@latest
  action-latest-test:
    name: Test lowlighter/metrics@latest
    runs-on: ubuntu-latest
    needs: [ update-latest ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[release]')
    steps:
      - name: Run tests
        uses: lowlighter/metrics@latest
        with:
          token: MOCKED_TOKEN
          plugins_errors_fatal: yes
          dryrun: yes
          use_mocked_data: yes
          verify: yes

  # Publish GitHub release
  publish-release:
    name: Publish release
    runs-on: ubuntu-latest
    needs: [ action-latest-test ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[release]')
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Setup NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: 15
      - name: Setup metrics
        run: npm ci
      - name: Publish release
        run: node .github/release.mjs
        env:
          GITHUB_TOKEN: ${{ github.token }}
          GITHUB_REPOSITORY: ${{ github.repository }}
          GITHUB_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}

  # Deploy to metrics.lecoq.io
  deploy-master:
    name: Deploy lowlighter/metrics@master
    runs-on: ubuntu-latest
    needs: [ action-master-test ]
    if: github.event_name == 'push' && github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[deploy]')
    steps:
      - name: Deploy web instance
        run: "curl -H 'Content-Type: application/json' --data '${{ secrets.WEB_DEPLOY_TOKEN }}' -X POST https://deploy.metrics.lecoq.io"
