name: main

on:
  workflow_dispatch:
  push:
    branches:
      - prime
    tags:
      - "*"
  pull_request:
    branches:
      - prime

env:
  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
  DOTNET_NOLOGO: true
  DOTNET_CLI_TELEMETRY_OPTOUT: true

jobs:
  format:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install .NET
        uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0

      # Build the project separately to discern between build and format errors
      - name: Build
        run: >
          dotnet build
          -p:CSharpier_Bypass=true
          --configuration Release

      - name: Verify formatting
        id: verify
        run: >
          dotnet build
          -t:CSharpierFormat
          --configuration Release
          --no-restore

      - name: Report issues
        if: ${{ failure() && steps.verify.outcome == 'failure' }}
        run: echo "::error title=Bad formatting::Formatting issues detected. Please build the solution locally to fix them."

  recurring-scrape-smoke:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install jq
        run: sudo apt-get update && sudo apt-get install -y jq

      - name: Run recurring scrape smoke tests
        run: |
          chmod +x scripts/*.sh scripts/tests/*.sh
          DCE_MIN_FREE_MB=0 ./scripts/run-all-smokes.sh

  test:
    # Tests need access to secrets, so we can't run them against PRs because of limited trust
    if: ${{ github.event_name != 'pull_request' }}

    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install .NET
        uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0

      - name: Run tests
        env:
          DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
        run: >
          dotnet test
          -p:CSharpier_Bypass=true
          --configuration Release
          --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
          --collect:"XPlat Code Coverage"
          --
          RunConfiguration.CollectSourceInformation=true
          DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover

      - name: Upload coverage
        uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  pack:
    strategy:
      matrix:
        app:
          - DiscordChatExporter.Cli
          - DiscordChatExporter.Gui
        rid:
          - win-arm64
          - win-x86
          - win-x64
          - linux-arm
          - linux-arm64
          - linux-musl-x64
          - linux-x64
          - osx-arm64
          - osx-x64
        include:
          - app: DiscordChatExporter.Cli
            asset: DiscordChatExporter.Cli
          - app: DiscordChatExporter.Gui
            # GUI assets aren't suffixed, unlike the CLI assets
            asset: DiscordChatExporter

    runs-on: ${{ startsWith(matrix.rid, 'win-') && 'windows-latest' || startsWith(matrix.rid, 'osx-') && 'macos-latest' || 'ubuntu-latest' }}
    timeout-minutes: 10

    permissions:
      actions: write
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install .NET
        uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0

      - name: Publish app
        run: >
          dotnet publish ${{ matrix.app }}
          -p:Version=${{ github.ref_type == 'tag' && github.ref_name || format('999.9.9-ci-{0}', github.sha) }}
          -p:CSharpier_Bypass=true
          -p:EncryptionSalt=${{ secrets.ENCRYPTION_SALT || 'HimalayanPinkSalt' }}
          -p:PublishMacOSBundle=${{ startsWith(matrix.rid, 'osx-') }}
          --output ${{ matrix.app }}/bin/publish/
          --configuration Release
          --runtime ${{ matrix.rid }}
          --self-contained

      - name: Upload app binaries
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: ${{ matrix.asset }}.${{ matrix.rid }}
          path: ${{ matrix.app }}/bin/publish/
          if-no-files-found: error

  release:
    if: ${{ github.ref_type == 'tag' }}

    needs:
      - format
      - test
      - pack

    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      contents: write

    steps:
      - name: Create release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: >
          gh release create ${{ github.ref_name }}
          --repo ${{ github.event.repository.full_name }}
          --title ${{ github.ref_name }}
          --generate-notes
          --verify-tag

  deploy:
    needs: release

    strategy:
      matrix:
        app:
          - DiscordChatExporter.Cli
          - DiscordChatExporter.Gui
        rid:
          - win-arm64
          - win-x86
          - win-x64
          - linux-arm
          - linux-arm64
          - linux-musl-x64
          - linux-x64
          - osx-arm64
          - osx-x64
        include:
          - app: DiscordChatExporter.Cli
            asset: DiscordChatExporter.Cli
          - app: DiscordChatExporter.Gui
            # GUI assets aren't suffixed, unlike the CLI assets
            asset: DiscordChatExporter

    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      actions: read
      contents: write

    steps:
      - name: Download app binaries
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: ${{ matrix.asset }}.${{ matrix.rid }}
          path: ${{ matrix.app }}/

      - name: Set permissions
        if: ${{ !startsWith(matrix.rid, 'win-') }}
        run: |
          [ -f ${{ matrix.app }}/${{ matrix.asset }} ] && chmod +x ${{ matrix.app }}/${{ matrix.asset }} || true

          # macOS bundle
          [ -f ${{ matrix.app }}/${{ matrix.asset }}.app/Contents/MacOS/${{ matrix.asset }} ] && chmod +x ${{ matrix.app }}/${{ matrix.asset }}.app/Contents/MacOS/${{ matrix.asset }} || true

      - name: Create package
        # Change into the artifacts directory to avoid including the directory itself in the zip archive
        working-directory: ${{ matrix.app }}/
        run: zip -r ../${{ matrix.asset }}.${{ matrix.rid }}.zip .

      - name: Upload release asset
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: >
          gh release upload ${{ github.ref_name }}
          ${{ matrix.asset }}.${{ matrix.rid }}.zip
          --repo ${{ github.event.repository.full_name }}

  notify:
    needs: deploy
    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      contents: read

    steps:
      - name: Notify Discord
        uses: tyrrrz/action-http-request@25f132e48dea89c0f6b7955398270b506e1d51cb # 1.1.4
        with:
          url: ${{ secrets.DISCORD_WEBHOOK }}
          method: POST
          headers: |
            Content-Type: application/json; charset=UTF-8
          body: |
            {
              "avatar_url": "https://raw.githubusercontent.com/${{ github.event.repository.full_name }}/${{ github.ref_name }}/favicon.png",
              "content": "[**${{ github.event.repository.name }}**](<${{ github.event.repository.html_url }}>) v${{ github.ref_name }} has been released!"
            }
          retry-count: 5
