diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml new file mode 100644 index 0000000..91488bb --- /dev/null +++ b/.github/workflows/pr-tests.yml @@ -0,0 +1,55 @@ +name: PR Unit Tests + +on: + pull_request: + branches: + - "**" + +jobs: + test-gate: + name: PR Test Gate + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + cache: true + cache-dependency-path: | + FluentAAS/**/*.csproj + FluentAAS/global.json + + - name: Locate solution file + id: solution + shell: bash + run: | + SOLUTION=$(find . -maxdepth 5 -name "*.sln" | head -n 1) + if [ -z "$SOLUTION" ]; then + echo "❌ No solution file (*.sln) found in the repo." + exit 1 + fi + echo "SOLUTION_PATH=$SOLUTION" >> $GITHUB_OUTPUT + echo "✅ Found solution: $SOLUTION" + + - name: Restore dependencies + run: dotnet restore "${{ steps.solution.outputs.SOLUTION_PATH }}" + + - name: Build solution + run: dotnet build "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-restore + + # Blocking PR gate: reviewers can see this check and it must pass before merge. + - name: Run unit tests (blocking gate) + run: dotnet test "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-build --verbosity normal --logger "trx;LogFileName=test-results.trx" + + - name: Upload test result artifacts + if: always() + uses: actions/upload-artifact@v7 + with: + name: pr-test-results + path: | + **/TestResults/*.trx + **/test-results.trx diff --git a/.github/workflows/release-nuget.yml b/.github/workflows/release-nuget.yml index 2e73621..cf7cd38 100644 --- a/.github/workflows/release-nuget.yml +++ b/.github/workflows/release-nuget.yml @@ -20,8 +20,50 @@ on: default: "main" jobs: + # Blocking gate: all tests must pass before any packing/publishing can run. + test-gate: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ inputs.ref || github.ref }} + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + cache: true + cache-dependency-path: | + FluentAAS/**/*.csproj + FluentAAS/global.json + + - name: Locate solution file + id: solution + shell: bash + run: | + SOLUTION=$(find . -maxdepth 5 -name "*.sln" | head -n 1) + if [ -z "$SOLUTION" ]; then + echo "❌ No solution file (*.sln) found in the repo." + exit 1 + fi + echo "SOLUTION_PATH=$SOLUTION" >> $GITHUB_OUTPUT + echo "✅ Found solution: $SOLUTION" + + - name: Restore dependencies + run: dotnet restore "${{ steps.solution.outputs.SOLUTION_PATH }}" + + - name: Build solution + run: dotnet build "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-restore + + - name: Test solution (blocking gate) + run: dotnet test "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-build --verbosity normal + build-pack-push: runs-on: ubuntu-latest + needs: test-gate steps: - name: Checkout @@ -85,9 +127,6 @@ jobs: - name: Build solution run: dotnet build "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-restore - - name: Test solution - run: dotnet test "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release --no-build --verbosity normal - - name: Pack NuGet packages run: dotnet pack "${{ steps.solution.outputs.SOLUTION_PATH }}" -c Release -o ./artifacts --no-build /p:PackageVersion=${{ steps.version.outputs.VERSION }} @@ -96,16 +135,16 @@ jobs: run: | shopt -s nullglob packages=(./artifacts/*.nupkg) - + if [ ${#packages[@]} -eq 0 ]; then echo "❌ No NuGet packages found in ./artifacts/" exit 1 fi - + echo "📦 Generated NuGet packages:" VERSION="${{ steps.version.outputs.VERSION }}" ESCAPED_VERSION="${VERSION//./\\.}" - + for pkg in "${packages[@]}"; do filename=$(basename "$pkg") echo " - $filename" @@ -149,4 +188,4 @@ jobs: prerelease: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPOSITORY: ${{ github.repository }} \ No newline at end of file + GITHUB_REPOSITORY: ${{ github.repository }}