Build and Publish Patchright .NET #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Patchright .NET Build and Publish Workflow | |
| # | |
| # This workflow: | |
| # 1. Checks if a new Playwright .NET version is available | |
| # 2. Checks for the latest compatible Patchright driver version | |
| # 3. Builds the Patchright .NET package | |
| # 4. Creates a GitHub release with the NuGet package | |
| # 5. Publishes to NuGet.org | |
| name: Build and Publish Patchright .NET | |
| on: | |
| # Run daily at 8:00 AM UTC | |
| schedule: | |
| - cron: '0 8 * * *' | |
| # Allow manual trigger with optional force build | |
| workflow_dispatch: | |
| inputs: | |
| force_build: | |
| description: 'Force build even if versions match' | |
| required: false | |
| default: false | |
| type: boolean | |
| driver_update_release: | |
| description: 'Release for driver update only (bumps patch version)' | |
| required: false | |
| default: false | |
| type: boolean | |
| skip_nuget_publish: | |
| description: 'Skip publishing to NuGet.org' | |
| required: false | |
| default: false | |
| type: boolean | |
| # Ensure only one workflow runs at a time | |
| concurrency: | |
| group: build-and-publish | |
| cancel-in-progress: false | |
| env: | |
| DOTNET_VERSION: '10.0.x' | |
| DOTNET_NOLOGO: true | |
| DOTNET_CLI_TELEMETRY_OPTOUT: true | |
| jobs: | |
| # Job 1: Check versions and determine if build is needed | |
| check-versions: | |
| name: Check Versions | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_build: ${{ steps.compare.outputs.should_build }} | |
| is_driver_update: ${{ steps.compare.outputs.is_driver_update }} | |
| playwright_version: ${{ steps.versions.outputs.playwright_version }} | |
| playwright_major_minor: ${{ steps.versions.outputs.playwright_major_minor }} | |
| patchright_version: ${{ steps.versions.outputs.patchright_version }} | |
| driver_version: ${{ steps.versions.outputs.driver_version }} | |
| driver_available: ${{ steps.versions.outputs.driver_available }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Get versions | |
| id: versions | |
| uses: ./.github/actions/get-versions | |
| - name: Compare versions | |
| id: compare | |
| run: | | |
| PLAYWRIGHT="${{ steps.versions.outputs.playwright_version }}" | |
| PATCHRIGHT="${{ steps.versions.outputs.patchright_version }}" | |
| DRIVER="${{ steps.versions.outputs.driver_version }}" | |
| DRIVER_AVAILABLE="${{ steps.versions.outputs.driver_available }}" | |
| PLAYWRIGHT_MAJOR_MINOR="${{ steps.versions.outputs.playwright_major_minor }}" | |
| FORCE="${{ github.event.inputs.force_build }}" | |
| DRIVER_UPDATE="${{ github.event.inputs.driver_update_release }}" | |
| echo "Force build: $FORCE" | |
| echo "Playwright .NET version : $PLAYWRIGHT" | |
| echo "Patchright .NET version : $PATCHRIGHT" | |
| echo "Patchright Driver version : $DRIVER" | |
| echo "Driver available for $PLAYWRIGHT_MAJOR_MINOR: $DRIVER_AVAILABLE" | |
| echo "Driver update release: $DRIVER_UPDATE" | |
| # Function to compare semantic versions | |
| version_gt() { | |
| test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1" | |
| } | |
| # Check if we need to build | |
| NEEDS_BUILD=false | |
| IS_DRIVER_UPDATE=false | |
| if [ "$DRIVER_UPDATE" = "true" ]; then | |
| echo "Driver update release requested - will bump patch version" | |
| NEEDS_BUILD=true | |
| IS_DRIVER_UPDATE=true | |
| elif [ "$FORCE" = "true" ]; then | |
| echo "Force build requested" | |
| NEEDS_BUILD=true | |
| elif version_gt "$PLAYWRIGHT" "$PATCHRIGHT"; then | |
| echo "New Playwright version available: $PLAYWRIGHT > $PATCHRIGHT" | |
| NEEDS_BUILD=true | |
| else | |
| echo "Patchright is up to date" | |
| fi | |
| echo "is_driver_update=$IS_DRIVER_UPDATE" >> $GITHUB_OUTPUT | |
| # If we need to build, verify driver is available | |
| if [ "$NEEDS_BUILD" = "true" ]; then | |
| if [ "$DRIVER_AVAILABLE" != "true" ]; then | |
| echo "" | |
| echo "::error::Cannot build: No compatible Patchright driver found for version $PLAYWRIGHT_MAJOR_MINOR" | |
| echo "::error::The Patchright driver needs to be released for version $PLAYWRIGHT_MAJOR_MINOR.x before we can build." | |
| echo "" | |
| echo "Waiting for driver release at: https://github.com/Kaliiiiiiiiii-Vinyzu/patchright/releases" | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| echo "driver_missing=true" >> $GITHUB_OUTPUT | |
| exit 1 | |
| else | |
| echo "✓ Compatible driver found: $DRIVER" | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| echo "driver_missing=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| echo "driver_missing=false" >> $GITHUB_OUTPUT | |
| fi | |
| # Job 2: Build the package | |
| build: | |
| name: Build Patchright .NET | |
| needs: check-versions | |
| if: needs.check-versions.outputs.should_build == 'true' | |
| runs-on: windows-latest | |
| outputs: | |
| package_version: ${{ steps.get_version.outputs.version }} | |
| package_path: ${{ steps.find_package.outputs.path }} | |
| package_name: ${{ steps.find_package.outputs.name }} | |
| steps: | |
| - name: Checkout repository | |
| id: checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET SDK | |
| id: setup_dotnet | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Run build script | |
| id: build | |
| run: .\build.ps1 -Cleanup -DriverVersion ${{ needs.check-versions.outputs.driver_version }} | |
| - name: Bump patch version for driver update | |
| if: needs.check-versions.outputs.is_driver_update == 'true' | |
| run: | | |
| $versionPropsPath = "playwright-dotnet/src/Common/Version.props" | |
| [xml]$xml = Get-Content $versionPropsPath | |
| # Get current version and bump patch | |
| $currentVersion = $xml.Project.PropertyGroup.AssemblyVersion | |
| $versionParts = $currentVersion -split '\.' | |
| $major = [int]$versionParts[0] | |
| $minor = [int]$versionParts[1] | |
| $patch = [int]$versionParts[2] + 1 | |
| $newVersion = "$major.$minor.$patch" | |
| Write-Host "Bumping version for driver update: $currentVersion -> $newVersion" -ForegroundColor Cyan | |
| # Update all version elements | |
| $xml.Project.PropertyGroup.AssemblyVersion = $newVersion | |
| $xml.Save($versionPropsPath) | |
| # Rebuild with new version | |
| Write-Host "Rebuilding with new version..." -ForegroundColor Cyan | |
| Push-Location playwright-dotnet | |
| try { | |
| dotnet build --configuration Release ./src/Playwright.sln | |
| dotnet pack --no-build --configuration Release --output ../nuget ./src/Playwright/Playwright.csproj | |
| } | |
| finally { | |
| Pop-Location | |
| } | |
| Write-Host "✓ Version bumped and rebuilt" -ForegroundColor Green | |
| - name: Get package version | |
| id: get_version | |
| run: | | |
| $versionPropsPath = "playwright-dotnet/src/Common/Version.props" | |
| [xml]$xml = Get-Content $versionPropsPath | |
| $version = $xml.Project.PropertyGroup.AssemblyVersion | |
| Write-Host "Package version: $version" | |
| echo "version=$version" >> $env:GITHUB_OUTPUT | |
| - name: Find NuGet package | |
| id: find_package | |
| run: | | |
| $package = Get-ChildItem -Path nuget -Filter "*.nupkg" | Select-Object -First 1 | |
| if (-not $package) { | |
| Write-Error "No NuGet package found in nuget directory" | |
| exit 1 | |
| } | |
| Write-Host "Found package: $($package.Name)" | |
| echo "path=$($package.FullName)" >> $env:GITHUB_OUTPUT | |
| echo "name=$($package.Name)" >> $env:GITHUB_OUTPUT | |
| - name: Upload NuGet package artifact | |
| id: upload_nuget_package | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nuget-package | |
| path: nuget/*.nupkg | |
| retention-days: 30 | |
| - name: Upload patch file artifact | |
| id: upload_patch_file | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: patch-file | |
| path: patchright.patch | |
| retention-days: 30 | |
| # Job 3: Create GitHub Release | |
| release: | |
| name: Create GitHub Release | |
| needs: [check-versions, build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download NuGet package artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: nuget-package | |
| path: nuget | |
| - name: Download patch file artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: patch-file | |
| path: . | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.build.outputs.package_version }} | |
| name: v${{ needs.build.outputs.package_version }} | |
| body: | | |
| ## Patchright .NET v${{ needs.build.outputs.package_version }} | |
| ${{ github.event.inputs.skip_nuget_publish == 'true' && '> ⚠️ **NOT PUBLISHED TO NUGET** - This release has not been published to NuGet.org yet. The package is only available as a download from this release.' || format('[](https://www.nuget.org/packages/Patchright/{0})', needs.build.outputs.package_version) }} | |
| ${{ needs.check-versions.outputs.is_driver_update == 'true' && '> **Driver Update Release** - This is a patch release to update the Patchright driver version.' || '' }} | |
| This release is based on [Playwright .NET v${{ needs.check-versions.outputs.playwright_version }}](https://github.com/microsoft/playwright-dotnet/releases/tag/v${{ needs.check-versions.outputs.playwright_version }}). | |
| ${{ needs.check-versions.outputs.driver_available == 'true' && format('Driver version: {0}', needs.check-versions.outputs.driver_version) || '' }} | |
| ### Installation | |
| ${{ github.event.inputs.skip_nuget_publish == 'true' && '> ⚠️ This version is not available on NuGet yet. Download the `.nupkg` file from this release to install manually.' || '' }} | |
| ```sh | |
| dotnet add package Patchright --version ${{ needs.build.outputs.package_version }} | |
| ``` | |
| Or via NuGet Package Manager: | |
| ```sh | |
| Install-Package Patchright -Version ${{ needs.build.outputs.package_version }} | |
| ``` | |
| ### What's Changed | |
| ${{ needs.check-versions.outputs.is_driver_update == 'true' && format('- Driver update release for Playwright .NET v{0}', needs.check-versions.outputs.playwright_version) || format('- Updated to Playwright .NET v{0}', needs.check-versions.outputs.playwright_version) }} | |
| ${{ needs.check-versions.outputs.driver_available == 'true' && format('- Updated Patchright driver to v{0}', needs.check-versions.outputs.driver_version) || '' }} | |
| ### Files | |
| - `${{ needs.build.outputs.package_name }}` - NuGet package | |
| - `patchright.patch` - Patch file applied to Playwright .NET | |
| files: | | |
| nuget/*.nupkg | |
| patchright.patch | |
| draft: false | |
| prerelease: ${{ github.event.inputs.skip_nuget_publish == 'true' }} | |
| generate_release_notes: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Job 4: Publish to NuGet.org | |
| publish-nuget: | |
| name: Publish to NuGet.org | |
| needs: [build] | |
| if: github.event.inputs.skip_nuget_publish != 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download NuGet package artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: nuget-package | |
| path: nuget | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Publish to NuGet.org | |
| run: | | |
| PACKAGE=$(ls nuget/*.nupkg | head -1) | |
| echo "Publishing package: $PACKAGE" | |
| dotnet nuget push "$PACKAGE" \ | |
| --api-key ${{ secrets.NUGET_API_KEY }} \ | |
| --source https://api.nuget.org/v3/index.json \ | |
| --skip-duplicate | |
| - name: Publish complete | |
| run: | | |
| echo "✓ Package published to NuGet.org successfully!" | |
| echo "View at: https://www.nuget.org/packages/Patchright" | |
| # Job 5: Notify on failure | |
| notify-failure: | |
| name: Notify on Failure | |
| needs: [check-versions, build, release, publish-nuget] | |
| if: failure() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Create failure issue | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const title = `Build failed on ${new Date().toISOString().split('T')[0]}`; | |
| const body = ` | |
| ## Build Failure Report | |
| The automated build workflow failed. Please investigate. | |
| **Workflow Run:** [View Details](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) | |
| **Triggered by:** ${context.eventName} | |
| Please check the workflow logs for more details. | |
| `; | |
| // Check if a similar issue already exists | |
| const issues = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| labels: 'build-failure' | |
| }); | |
| const existingIssue = issues.data.find(i => i.title.startsWith('Build failed on')); | |
| if (!existingIssue) { | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: title, | |
| body: body, | |
| labels: ['build-failure', 'automated'] | |
| }); | |
| } |