name: Build and Test

on:
  push:
    branches: ["master", "feature/*"]
    tags: ["v*", "plugin-api-v*"]
  pull_request_target:
    branches: ["master"]

permissions:
  actions: read
  checks: write
  contents: read
  statuses: write

jobs:
  determineVersionNumber:
    name: Determine Version Number
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.generateVersion.outputs.version }}
      plugin-api-version: ${{ steps.generateVersion.outputs.plugin-api-version }}

    steps:
      - name: Checkout action file
        uses: actions/checkout@v4
        with:
          sparse-checkout: .github/actions/checkout/action.yml
          sparse-checkout-cone-mode: false

      - name: Checkout
        uses: ./.github/actions/checkout

      - name: Generate Version Number
        id: generateVersion
        shell: pwsh
        run: |
          foreach ($tagPrefix in @("", "plugin-api-")) {
            $describe = git describe --long --tags --always --match "$($tagPrefix)v*"
            if ($describe -match "^$($tagPrefix)v?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)-(?<offset>\d+)-g(?<hash>[a-f0-9]+)`$") {
              if ([int]::Parse($Matches.offset) -eq 0) {
                $version = "$($Matches.major).$($Matches.minor).$($Matches.patch)"
              } else {
                $version = "$($Matches.major).$($Matches.minor).$([int]::Parse($Matches.patch) + 1)-dev.$($Matches.offset)+$($Matches.hash)"
              }
            } else {
              $version = "0.0.0-dev.$(git rev-list HEAD --count)+$describe"
            }
            Write-Host "Generated version number$(if ($tagPrefix -eq '') { '' } else { " $tagPrefix" } ): $version"
            echo "$($tagPrefix)version=$($version)" >> $Env:GITHUB_OUTPUT
          }

  buildOnLinux:
    name: Build on Linux
    runs-on: ubuntu-latest
    needs: [determineVersionNumber]

    steps:
      - name: Checkout action file
        uses: actions/checkout@v4
        with:
          sparse-checkout: .github/actions/checkout/action.yml
          sparse-checkout-cone-mode: false

      - name: Checkout
        uses: ./.github/actions/checkout

      - name: Create DLL
        uses: ./.github/actions/create-dll
        with:
          version: ${{ needs.determineVersionNumber.outputs.version }}

      - name: Upload NuGetForUnity dlls
        uses: actions/upload-artifact@v4
        with:
          name: NuGetForUnity-dlls
          path: |
            ./src/NuGetForUnity.CreateDll/bin/Release/NugetForUnity.dll
            ./src/NuGetForUnity.CreateDll/bin/Release/NuGetForUnity.PluginAPI.dll
            ./src/NuGetForUnity.CreateDll/bin/Release/NuGetForUnity.PluginAPI.xml
          if-no-files-found: error

      - name: Check if files in NuGetForUnity.PluginAPI changed
        if: github.event_name == 'pull_request_target'
        id: changedPluginApiCode
        uses: tj-actions/changed-files@v42
        with:
          files: |
            src/NuGetForUnity.PluginAPI/**.cs

      - name: Check if NuGetForUnity.PluginAPI.dll is updated
        if: github.event_name == 'pull_request_target'
        id: changedPluginApiDll
        uses: tj-actions/changed-files@v42
        with:
          files: |
            src/NuGetForUnity/Editor/PluginAPI/NuGetForUnity.PluginAPI.dll

      - name: Fail if source code of NuGetForUnity.PluginAPI has changed but NuGetForUnity.PluginAPI.dll is not updated / changed
        if: |
          github.event_name == 'pull_request_target' &&
          steps.changedPluginApiCode.outputs.any_changed == 'true' &&
          steps.changedPluginApiDll.outputs.any_changed == 'false'
        shell: bash
        run: |
          echo "One or more *.cs files in the src/NuGetForUnity.PluginAPI folder were changed"
          echo "but 'src/NuGetForUnity/Editor/PluginAPI/NuGetForUnity.PluginAPI.dll' was not updated"
          exit 1

  packageOnLinux:
    name: Create .unitypackage on Linux
    runs-on: ubuntu-latest
    needs: [buildOnLinux, determineVersionNumber]

    steps:
      - name: Checkout action file
        uses: actions/checkout@v4
        with:
          sparse-checkout: .github/actions/checkout/action.yml
          sparse-checkout-cone-mode: false

      - name: Checkout
        uses: ./.github/actions/checkout

      - name: Download NuGetForUnity dlls
        uses: actions/download-artifact@v4
        with:
          name: NuGetForUnity-dlls
          path: ./src/NuGetForUnity.Packager/Assets/NuGet/Editor

      - name: Unity - Packager (build .unitypackage)
        uses: game-ci/unity-builder@v2.1.2
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          # Platform that the build should target.
          targetPlatform: StandaloneWindows64
          # Version of unity to use for building the project. Use "auto" to get from your ProjectSettings/ProjectVersion.txt
          unityVersion: auto
          # Relative path to the project to be built.
          projectPath: ./src/NuGetForUnity.Packager
          # Path to a Namespace.Class.StaticMethod to run to perform the build.
          buildMethod: NugetForUnity.Export.Execute
          # custom versioning
          versioning: "Custom"
          version: ${{ needs.determineVersionNumber.outputs.version }}

      - name: Upload UnityPackage
        uses: actions/upload-artifact@v4
        with:
          name: NuGetForUnity.${{ needs.determineVersionNumber.outputs.version }}.unitypackage
          path: ./src/NuGetForUnity.Packager/NugetForUnity.unitypackage
          if-no-files-found: error

  packageNuGetPackages:
    name: Pack .NET Core Global Tool (CLI) and PluginAPI
    runs-on: ubuntu-latest
    needs: [determineVersionNumber]

    steps:
      - name: Checkout action file
        uses: actions/checkout@v4
        with:
          sparse-checkout: .github/actions/checkout/action.yml
          sparse-checkout-cone-mode: false

      - name: Checkout
        uses: ./.github/actions/checkout

      - name: Setup dotnet
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "8.0.x"

      - name: Build and pack .NET Core Global Tool
        run: >-
          dotnet pack ./src/NuGetForUnity.Cli/NuGetForUnity.Cli.csproj --nologo -c Release -o .
          -p:Version=${{ needs.determineVersionNumber.outputs.version }} -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
          -p:ContinuousIntegrationBuild=true

      - name: Build and pack NuGetForUnity.PluginAPI
        run: >-
          dotnet pack ./src/NuGetForUnity.PluginAPI/NuGetForUnity.PluginAPI.csproj --nologo -c Release -o .
          -p:Version=${{ needs.determineVersionNumber.outputs.plugin-api-version }} -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
          -p:ContinuousIntegrationBuild=true

      - name: publish the NuGetForUnity.Cli NuGet package
        if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
        run: >-
          dotnet nuget push ./NuGetForUnity.Cli.${{ needs.determineVersionNumber.outputs.version }}.nupkg --api-key ${{ secrets.NUGET_API_TOKEN }}
          --source https://api.nuget.org/v3/index.json

      - name: publish the NuGetForUnity.PluginAPI NuGet package
        if: github.ref_type == 'tag' && startsWith(github.ref_name, 'plugin-api-v')
        run: >-
          dotnet nuget push ./NuGetForUnity.PluginAPI.${{ needs.determineVersionNumber.outputs.plugin-api-version }}.nupkg --api-key ${{ secrets.NUGET_API_TOKEN }}
          --source https://api.nuget.org/v3/index.json

      - name: Upload NuGet packages
        uses: actions/upload-artifact@v4
        with:
          name: NuGetForUnity-NuGetPackages
          path: |
            ./NuGetForUnity.Cli.*.nupkg
            ./NuGetForUnity.PluginAPI.*.nupkg
          if-no-files-found: error

  testUbuntu:
    name: Test on Linux
    runs-on: ubuntu-latest
    steps:
      - name: Checkout action file
        uses: actions/checkout@v4
        with:
          sparse-checkout: .github/actions/checkout/action.yml
          sparse-checkout-cone-mode: false

      - name: Checkout
        uses: ./.github/actions/checkout

      - name: Unity - Run tests
        uses: game-ci/unity-test-runner@v2.1.1
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          projectPath: src/NuGetForUnity.Tests
          githubToken: ${{ secrets.GITHUB_TOKEN }}
          testMode: EditMode

  runTestProjectsOnLinux:
    name: Run test projects on Linux
    runs-on: ubuntu-latest
    needs: [packageNuGetPackages, determineVersionNumber]
    strategy:
      fail-fast: false
      matrix:
        projectPath:
          - src/TestProjects/ImportAndUseNuGetPackages
          - src/TestProjects/ImportAndUseNuGetPackages2021

    steps:
      - name: Checkout action file
        uses: actions/checkout@v4
        with:
          sparse-checkout: .github/actions/checkout/action.yml
          sparse-checkout-cone-mode: false

      - name: Checkout
        uses: ./.github/actions/checkout

      - name: Download NuGetForUnity.Cli NuGet package
        uses: actions/download-artifact@v4
        with:
          name: NuGetForUnity-NuGetPackages
          path: .

      - name: Install NuGetForUnity.Cli Tool
        run: dotnet tool install --add-source . NuGetForUnity.Cli --version ${{ needs.determineVersionNumber.outputs.version }}

      - name: Restore NuGet packages using NuGetForUnity.Cli
        run: dotnet nugetforunity restore '${{ matrix.projectPath }}'

      - name: Unity - Build project ${{ matrix.projectPath }}
        uses: game-ci/unity-builder@v3.1.0
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          # Platform that the build should target.
          targetPlatform: StandaloneWindows64
          # Relative path to the project to be built.
          projectPath: ${{ matrix.projectPath }}
          # disable versioning
          versioning: "None"
