---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.

name: Qodana

on:
  pull_request:
    branches: [master, nightly]
    types: [opened, synchronize, reopened]
  push:
    branches: [master, nightly]
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  qodana_initial_check:
    name: Qodana Initial Check
    permissions:
      actions: write  # required to use workflow dispatch on fork PRs
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Prepare
        id: prepare
        run: |
          # check the branch variable
          if [ "${{ github.event_name }}" == "push" ]
          then
            echo "This is a PUSH event"
            # use the branch name
            destination=${{ github.ref_name }}
            target=${{ github.ref_name }}
          else
            echo "This is a PR event"
            # use the PR number
            destination=${{ github.event.pull_request.number }}
            target=${{ github.event.pull_request.base.ref }}
          fi

          echo "checkout_repo=$checkout_repo" >> $GITHUB_OUTPUT
          echo "checkout_ref=$checkout_ref" >> $GITHUB_OUTPUT
          echo "destination=$destination" >> $GITHUB_OUTPUT
          echo "target=$target" >> $GITHUB_OUTPUT

          # prepare urls
          base=https://${{ github.repository_owner }}.github.io
          report_url=${base}/qodana-reports/${{ github.event.repository.name }}/${destination}
          echo "report_url=$report_url" >> $GITHUB_OUTPUT

          # build matrix
          files=$(find . -type f -iname "qodana*.yaml")

          echo "files: ${files}"

          # do not quote to keep this as a single line
          echo files=${files} >> $GITHUB_OUTPUT

          MATRIX_COMBINATIONS=""
          REPORTS_MARKDOWN=""
          for FILE in ${files}; do
            # extract the language from file name after `qodana-` and before `.yaml`
              language=$(echo $FILE | sed -r -z -e 's/(\.\/)*.*\/(qodana.yaml)/default/gm')
            if [[ $language != "default" ]]; then
              language=$(echo $FILE | sed -r -z -e 's/(\.\/)*.*qodana-(.*).yaml/\2/gm')
            fi
            MATRIX_COMBINATIONS="$MATRIX_COMBINATIONS {\"file\": \"$FILE\", \"language\": \"$language\"},"
            REPORTS_MARKDOWN="$REPORTS_MARKDOWN <br> - [${language}](${report_url}/${language})"
          done

          # removes the last character (i.e. comma)
          MATRIX_COMBINATIONS=${MATRIX_COMBINATIONS::-1}

          # setup matrix for later jobs
          matrix=$((
            echo "{ \"include\": [$MATRIX_COMBINATIONS] }"
          ) | jq -c .)

          echo $matrix
          echo $matrix | jq .
          echo "matrix=$matrix" >> $GITHUB_OUTPUT

          echo "reports_markdown=$REPORTS_MARKDOWN" >> $GITHUB_OUTPUT

      - name: Setup initial notification inputs
        id: inputs
        if: >-
          startsWith(github.event_name, 'pull_request') &&
          steps.prepare.outputs.files != ''
        run: |
          # workflow logs
          workflow_url_a=https://github.com/${{ github.repository_owner }}/${{ github.event.repository.name }}
          workflow_url=${workflow_url_a}/actions/runs/${{ github.run_id }}

          # multiline message
          message=$(cat <<- EOF
            :warning: **Qodana is checking this PR** :warning:
            Live results available [here](${workflow_url})
          EOF
          )

          # escape json control characters
          message=$(jq -n --arg message "$message" '$message' | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')

          secondary_inputs=$(echo '{
            "issue_message": "'"${message}"'",
            "issue_message_id": "'"qodana"'",
            "issue_number": "'"${{ github.event.number }}"'",
            "issue_repo_owner": "'"${{ github.repository_owner }}"'",
            "issue_repo_name": "'"${{ github.event.repository.name }}"'"
          }' | jq -r .)

          #escape json control characters
          secondary_inputs=$(jq -n --arg secondary_inputs "$secondary_inputs" '$secondary_inputs' \
            | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')

          echo $secondary_inputs

          # secondary input as string, not JSON
          # todo - change dispatch_ref to master instead of nightly
          primary_inputs=$(echo '{
            "dispatch_repository": "'"${{ github.repository_owner }}/.github"'",
            "dispatch_workflow": "'"dispatch-issue-comment.yml"'",
            "dispatch_ref": "'"nightly"'",
            "dispatch_inputs": "'"${secondary_inputs}"'"
          }' | jq -c .)

          echo $primary_inputs
          echo $primary_inputs | jq .
          echo "primary_inputs=$primary_inputs" >> $GITHUB_OUTPUT

      - name: Workflow Dispatch
        if: >-
          startsWith(github.event_name, 'pull_request') &&
          steps.prepare.outputs.files != ''
        uses: benc-uk/workflow-dispatch@v1.2.2
        continue-on-error: true  # this might error if the workflow is not found, but we still want to run the next job
        with:
          ref: ${{ github.base_ref || github.ref_name }}  # base ref for PR and branch name for push
          workflow: dispatcher.yml
          inputs: ${{ steps.inputs.outputs.primary_inputs }}
          token: ${{ github.token }}

    outputs:
      destination: ${{ steps.prepare.outputs.destination }}
      target: ${{ steps.prepare.outputs.target }}
      files: ${{ steps.prepare.outputs.files }}
      reports_markdown: ${{ steps.prepare.outputs.reports_markdown }}
      matrix: ${{ steps.prepare.outputs.matrix }}

  qodana:
    if: ${{ needs.qodana_initial_check.outputs.files != '' }}
    needs: [qodana_initial_check]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.qodana_initial_check.outputs.matrix) }}
    name: Qodana-Scan-${{ matrix.language }}
    continue-on-error: true
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          submodules: recursive

      - name: Get baseline
        id: baseline
        run: |
          # check if destination is not an integer
          if ! [[ "${{ needs.qodana_initial_check.outputs.destination }}" =~ ^[0-9]+$ ]]
          then
            echo "Running for a branch update"
            echo "baseline_args=" >> $GITHUB_OUTPUT
          else
            echo "Running for a PR"

            sarif_file=qodana.sarif.json
            repo=${{ github.event.repository.name }}
            target=${{ needs.qodana_initial_check.outputs.target }}
            language=${{ matrix.language }}

            baseline_file="${repo}/${target}/${language}/results/${sarif_file}"
            baseline_file_url="https://lizardbyte.github.io/qodana-reports/${baseline_file}"

            # don't fail if file does not exist
            wget ${baseline_file_url} || true

            # check if file exists
            if [ -f ${sarif_file} ]
            then
              echo "baseline exists"
              echo "baseline_args=--baseline,${sarif_file}" >> $GITHUB_OUTPUT
            else
              echo "baseline does not exist"
              echo "baseline_args=" >> $GITHUB_OUTPUT
            fi
          fi

      - name: Rename Qodana config file
        id: rename
        run: |
          # rename the file
          if [ "${{ matrix.file }}" != "./qodana.yaml" ]
          then
            mv -f ${{ matrix.file }} ./qodana.yaml
          fi

      - name: Qodana
        id: qodana
        continue-on-error: true  # ensure dispatch-qodana job is run
        uses: JetBrains/qodana-action@v2023.2.1
        with:
          additional-cache-hash: ${{ github.ref }}-${{ matrix.language }}
          artifact-name: qodana-${{ matrix.language }}  # yamllint disable-line rule:line-length
          args: '--print-problems,${{ steps.baseline.outputs.baseline_args }}'
          pr-mode: false
          upload-result: true
          use-caches: true

      - name: Set output status
        id: status
        run: |
          # check if qodana failed
          echo "qodana_status=${{ steps.qodana.outcome }}" >> $GITHUB_OUTPUT

    outputs:
      qodana_status: ${{ steps.status.outputs.qodana_status }}

  dispatch-qodana:
    # trigger qodana-reports to download artifacts from the matrix runs
    needs: [qodana_initial_check, qodana]
    runs-on: ubuntu-latest
    name: Dispatch Qodana
    permissions:
      actions: write  # required to use workflow dispatch on fork PRs
    if: ${{ needs.qodana_initial_check.outputs.files != '' }}
    steps:
      - name: Setup qodana publish inputs
        id: inputs
        run: |
          # get the artifacts
          artifacts=${{ toJson(steps.artifacts.outputs.result) }}
          artifacts=$(echo $artifacts | jq -c .)

          # get the target branch
          target=${{ needs.qodana_initial_check.outputs.target }}

          # get the destination branch
          destination=${{ needs.qodana_initial_check.outputs.destination }}

          # client payload
          secondary_inputs=$(echo '{
            "destination": "'"${destination}"'",
            "ref": "'"${{ github.ref }}"'",
            "repo": "'"${{ github.repository }}"'",
            "repo_name": "'"${{ github.event.repository.name }}"'",
            "run_id": "'"${{ github.run_id }}"'",
            "reports_markdown": "'"${{ needs.qodana_initial_check.outputs.reports_markdown }}"'",
            "status": "'"${{ needs.qodana.outputs.qodana_status }}"'"
          }' | jq -r .)

          #escape json control characters
          secondary_inputs=$(jq -n --arg secondary_inputs "$secondary_inputs" '$secondary_inputs' \
            | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')

          echo $secondary_inputs

          primary_inputs=$(echo '{
            "dispatch_repository": "'"${{ github.repository_owner }}/qodana-reports"'",
            "dispatch_workflow": "'"dispatch-qodana.yml"'",
            "dispatch_ref": "'"master"'",
            "dispatch_inputs": "'"$secondary_inputs"'"
          }' | jq -c .)

          echo $primary_inputs
          echo $primary_inputs | jq .
          echo "primary_inputs=$primary_inputs" >> $GITHUB_OUTPUT

      - name: Workflow Dispatch
        uses: benc-uk/workflow-dispatch@v1.2.2
        continue-on-error: true  # this might error if the workflow is not found, but we don't want to fail the workflow
        with:
          ref: ${{ github.base_ref || github.ref_name }}  # base ref for PR and branch name for push
          workflow: dispatcher.yml
          inputs: ${{ steps.inputs.outputs.primary_inputs }}
          token: ${{ github.token }}
