Fix release workflow output detection #3
Workflow file for this run
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
| # (260405Ch) Build ReciProSetup on v* tag push and publish a GitHub Release using the latest Version.cs history line | |
| name: Build And Release Installer | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: windows-2022 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Setup .NET 10 | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Restore managed dependencies | |
| shell: pwsh | |
| run: dotnet restore ReciPro\ReciPro.csproj | |
| - name: Read release info from Version.cs | |
| id: version_info | |
| shell: pwsh | |
| run: | | |
| $versionFile = "ReciPro\Version.cs" | |
| $content = Get-Content $versionFile -Raw | |
| $historyRegex = [regex]::Matches($content, 'ver[^\r\n"]+') | |
| if ($historyRegex.Count -eq 0) { | |
| throw "Could not find a release history line in $versionFile." | |
| } | |
| $latestHistory = $historyRegex[0].Value.Trim() | |
| if ($latestHistory -notmatch '^ver(?<Version>[0-9][0-9A-Za-z\.\-_]*)') { | |
| throw "Could not parse version number from history line: $latestHistory" | |
| } | |
| $historyTag = "v$($Matches.Version)" | |
| $tagName = "${{ github.ref_name }}" | |
| if ($historyTag -ne $tagName) { | |
| throw "Tag '$tagName' does not match Version.cs latest history '$historyTag'." | |
| } | |
| $releaseTitle = "ReciPro $tagName" | |
| $notesPath = Join-Path $env:RUNNER_TEMP "release-notes.txt" | |
| @( | |
| $latestHistory | |
| "" | |
| "Built automatically from tag $tagName." | |
| ) | Set-Content -Path $notesPath -Encoding UTF8 | |
| "latest_history=$latestHistory" >> $env:GITHUB_OUTPUT | |
| "release_title=$releaseTitle" >> $env:GITHUB_OUTPUT | |
| "notes_path=$notesPath" >> $env:GITHUB_OUTPUT | |
| - name: Disable out-of-proc setup project build | |
| shell: pwsh | |
| run: | | |
| # (260405Ch) Force installer builds to run in-proc so devenv does not return before MSI generation completes. | |
| $visualStudioRoot = "HKCU:\Software\Microsoft\VisualStudio" | |
| $configKeys = Get-ChildItem $visualStudioRoot -ErrorAction SilentlyContinue | | |
| Where-Object { $_.PSChildName -like '17.0*_Config' -or $_.PSChildName -like '18.0*_Config' } | |
| if ($configKeys.Count -eq 0) { | |
| Write-Warning "No Visual Studio *_Config registry keys were found under $visualStudioRoot." | |
| } | |
| foreach ($configKey in $configKeys) { | |
| $msbuildKey = Join-Path $configKey.PSPath "MSBuild" | |
| if (-not (Test-Path $msbuildKey)) { | |
| New-Item -Path $msbuildKey -Force | Out-Null | |
| } | |
| New-ItemProperty -Path $msbuildKey -Name DisableOutOfProcBuild -PropertyType DWord -Value 1 -Force | Out-Null | |
| Write-Host "Set DisableOutOfProcBuild=1 at $msbuildKey" | |
| } | |
| - name: Build installer with Visual Studio | |
| shell: pwsh | |
| run: | | |
| $devenv = (& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -property productPath).Trim() | |
| if (-not $devenv) { | |
| throw "devenv.exe was not found." | |
| } | |
| & $devenv "ReciPro.sln" /Build "Release|x64" /Project "ReciProSetup\ReciProSetup.vdproj" | |
| if ($LASTEXITCODE -ne 0) { | |
| exit $LASTEXITCODE | |
| } | |
| - name: Confirm installer outputs | |
| id: installer_outputs | |
| shell: pwsh | |
| run: | | |
| # (260405Ch) Some environments materialize setup project outputs slightly after devenv returns, so wait and locate them dynamically. | |
| $requiredNames = @("ReciProSetup.msi", "setup.exe") | |
| $foundFiles = @{} | |
| $deadline = (Get-Date).AddMinutes(2) | |
| do { | |
| Get-ChildItem -Path . -Recurse -File -ErrorAction SilentlyContinue | | |
| Where-Object { $requiredNames -contains $_.Name } | | |
| ForEach-Object { $foundFiles[$_.Name] = $_.FullName } | |
| $missingFiles = $requiredNames | Where-Object { -not $foundFiles.ContainsKey($_) } | |
| if ($missingFiles.Count -eq 0) { | |
| break | |
| } | |
| Start-Sleep -Seconds 2 | |
| } while ((Get-Date) -lt $deadline) | |
| $missingFiles = $requiredNames | Where-Object { -not $foundFiles.ContainsKey($_) } | |
| if ($missingFiles.Count -gt 0) { | |
| Write-Host "Located installer-like files:" | |
| Get-ChildItem -Path . -Recurse -File -ErrorAction SilentlyContinue | | |
| Where-Object { $_.Extension -eq ".msi" -or $_.Name -eq "setup.exe" } | | |
| Select-Object FullName, Length, LastWriteTime | |
| throw "Required output was not found: $($missingFiles -join ', ')" | |
| } | |
| "msi_path=$($foundFiles['ReciProSetup.msi'])" >> $env:GITHUB_OUTPUT | |
| "bootstrapper_path=$($foundFiles['setup.exe'])" >> $env:GITHUB_OUTPUT | |
| - name: Upload workflow artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ReciPro-installer-${{ github.ref_name }} | |
| path: | | |
| ${{ steps.installer_outputs.outputs.msi_path }} | |
| ${{ steps.installer_outputs.outputs.bootstrapper_path }} | |
| - name: Create GitHub Release | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh release create "${{ github.ref_name }}" ` | |
| "${{ steps.installer_outputs.outputs.msi_path }}" ` | |
| "${{ steps.installer_outputs.outputs.bootstrapper_path }}" ` | |
| --verify-tag ` | |
| --title "${{ steps.version_info.outputs.release_title }}" ` | |
| --notes-file "${{ steps.version_info.outputs.notes_path }}" |