name: "Backend CI"

on:
  workflow_dispatch:
  push:
    branches:
      - dev
    tags:
      - "v*"
    paths:
      - "src/backend/**"
      - "tests/backend/**"
  pull_request:
    branches:
      - main
      - test
      - dev
    paths:
      - "src/backend/**"
      - "tests/backend/**"
      - ".github/workflows/backend-ci.yml"
    types: [opened, reopened, labeled, synchronize, ready_for_review]

# Sets permissions of the GITHUB_TOKEN to allow creating checks and updating PR
permissions:
  contents: read
  checks: write
  pull-requests: write
  actions: read # for super-linter
  statuses: write # for super-linter

# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
  group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
  cancel-in-progress: true

env:
  DOTNET_VERSION: "8.0.x"
  BACKEND_SOLUTION_PATH: "src/backend"
  BACKEND_SOLUTION_FILE: "Backend.sln"
  WORKFLOW_SHORT_NAME: "backend-ci"
  WORKFLOW_AGENT_PATH: "/home/runner/work/test/test/"

jobs:
  build:
    runs-on: ubuntu-latest
    if: ${{ github.event.pull_request.draft == false }}
    defaults:
      run:
        working-directory: ${{ env.BACKEND_SOLUTION_PATH }}
    steps:
      - name: checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # used by GitVersion to find the most recent tag outside of this branch

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - uses: actions/cache@v4
        id: nuget-cache
        with:
          path: ~/.nuget/packages
          key: nuget-${{ hashFiles('**/packages.lock.json') }}

      - name: dotnet restore
        run: dotnet restore --locked-mode ${{ env.BACKEND_SOLUTION_FILE }}

      - name: dotnet tool restore
        run: dotnet tool restore

      - name: Build
        id: dotnet-build
        run: |
          dotnet build ${{ env.BACKEND_SOLUTION_FILE }} -c Release --no-restore --nologo -consoleLoggerParameters:NoSummary -verbosity:quiet 1>build.out 2>&1 || (exit 0)
          grep "): error " build.out > build.err || (exit 0)

          if [ ! -s build.err ]
          then
            echo "## ✅ Build successful" > build.md
          else
            # Reformat error output as github error annotations
            error_regex="(.+)\(([0-9]+),([0-9]+)\): error (.+) \[(.+)\]"
            # Capture groups: 1=file path 2=line 3=character 4=warn: message 5=project path
            cat build.err | while read line
            do
              if [[ $line =~ $error_regex ]]; then
                echo "::error file=${BASH_REMATCH[1]},line=${BASH_REMATCH[2]}::${BASH_REMATCH[4]}"
              fi
            done

            cat build.err | sed 's|${{ env.WORKFLOW_AGENT_PATH }}|| ; s|${{ env.WORKFLOW_AGENT_PATH }}||' > build.md
            sed -i '/^$/d' build.md             # removes empty lines
            sed -i -e 's/^/- ❌ /' build.md     # prefix with markdown list item and cross mark emoji
            echo "## ❌ The following build issues should be fixed:" | cat - build.md > build.md.temp && mv build.md.temp build.md
          fi

          echo "result<<EOF"$'\n'"$(cat build.md)"$'\n'EOF >> $GITHUB_OUTPUT
          cat build.md >> $GITHUB_STEP_SUMMARY

          if [ -s build.err ]
          then
            exit 1
          fi

      - name: "Create or Update PR Comment"
        uses: im-open/update-pr-comment@v1.2.2
        if: ${{ always() && github.event_name == 'pull_request' }}
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-build-results"
          comment-content: ${{ steps.dotnet-build.outputs.result }}

      - name: Create Todo Comments
        uses: gkampitakis/github-action-todo-commenter@v1
        if: ${{ github.event_name == 'pull_request' }}
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          review-message: "Please take a look :eyes:"
          tags: "TODO:,FIXME:,BUG:"

      # # TODO: move?
      # - name: Super-linter
      #   uses: super-linter/super-linter@v6.4.1
      #   env:
      #     # To report GitHub Actions status checks
      #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      #     CREATE_LOG_FILE: true
      #     LOG_FILE: super-linter.out
      #     DISABLE_ERRORS: true

      # - run: |
      #     ls -la ${{ env.WORKFLOW_AGENT_PATH }}
      #     sudo cat ${{ env.WORKFLOW_AGENT_PATH }}super-linter.out >> $GITHUB_STEP_SUMMARY

      - name: WebApi Tests
        run: dotnet test ../../tests/backend/WebApi.Tests --no-restore --collect:"XPlat Code Coverage" --logger "trx;LogFileName=test-results.trx" /p:CollectCoverage=true /p:CoverletOutput="../../tests/backend/WebApi.Tests/TestResults/" /p:CoverletOutputFormat=cobertura
        continue-on-error: true

      #- uses: hwinther/test-reporter@dotnet-nunit # TODO: set back to original once nunit is supported: dorny/test-reporter@v1
      - uses: dorny/test-reporter@v1
        id: test-reporter
        with:
          name: "WebApi Tests"
          path: "tests/backend/WebApi.Tests/TestResults/test-results.trx"
          reporter: dotnet-trx # dotnet-nunit
          fail-on-error: false

      - name: Generate report for all tests
        id: reportgenerator
        run: |
          dotnet reportgenerator -reports:"../../tests/backend/**/TestResults/**/coverage.cobertura.xml" -targetdir:"../../tests/backend/CoverageReport" -reporttypes:"Html;Cobertura;MarkdownSummaryGithub;Badges"
          cat ../../tests/backend/CoverageReport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY
          echo "markdown<<EOF" >> $GITHUB_OUTPUT
          cat ../../tests/backend/CoverageReport/SummaryGithub.md >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
          # TODO: commit the badges for README.md

      - name: "Create or Update PR Comment"
        uses: im-open/update-pr-comment@v1.2.2
        if: ${{ always() && github.event_name == 'pull_request' }}
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-reportgenerator"
          comment-content: ${{ steps.reportgenerator.outputs.markdown }}${{ steps.test-reporter.outputs.conclusion }}

      - name: Code Coverage Report
        uses: irongut/CodeCoverageSummary@v1.3.0
        with:
          filename: "tests/backend/CoverageReport/Cobertura.xml"
          badge: true
          fail_below_min: false
          format: markdown
          hide_branch_rate: false
          hide_complexity: true
          indicators: true
          output: both
          thresholds: "60 80"

      - name: Create output variable
        id: code-coverage-summary
        run: |
          cat ../../code-coverage-results.md >> $GITHUB_STEP_SUMMARY
          echo "markdown<<EOF" >> $GITHUB_OUTPUT
          cat ../../code-coverage-results.md >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: "Create or Update PR Comment"
        uses: im-open/update-pr-comment@v1.2.2
        if: ${{ always() && github.event_name == 'pull_request' }}
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-CodeCoverageSummary"
          comment-content: ${{ steps.code-coverage-summary.outputs.markdown }}

      - name: Stryker
        id: stryker
        run: |
          dotnet stryker --reporter "html" --reporter "json" --reporter "markdown" --solution Backend.sln --output StrykerOutput
          cp -r StrykerOutput/reports StrykerReports
          cat StrykerReports/mutation-report.md >> $GITHUB_STEP_SUMMARY
          echo "markdown<<EOF" >> $GITHUB_OUTPUT
          cat StrykerReports/mutation-report.md >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - uses: actions/upload-artifact@v4
        with:
          name: StrykerReports
          path: ${{ env.BACKEND_SOLUTION_PATH }}/StrykerReports

      - name: "Create or Update PR Comment"
        uses: im-open/update-pr-comment@v1.2.2
        if: ${{ always() && github.event_name == 'pull_request' }}
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-Stryker"
          comment-content: ${{ steps.stryker.outputs.markdown }}

      - name: Inspect code
        uses: muno92/resharper_inspectcode@v1
        if: ${{ github.event_name == 'pull_request' }}
        with:
          workingDirectory: ${{ env.BACKEND_SOLUTION_PATH }}
          solutionPath: Backend.sln
          dotnetVersion: ${{ env.DOTNET_VERSION }}
          failOnIssue: false
          solutionWideAnalysis: true
          include: |
            **.cs
          ignoreIssueType: PropertyCanBeMadeInitOnly.Global