This repository was archived by the owner on Apr 6, 2026. It is now read-only.
Build and Release #36
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
| name: Build and Release | |
| on: | |
| workflow_dispatch: | |
| env: | |
| DOTNET_VERSION: '9.0.x' | |
| jobs: | |
| build-and-release: | |
| runs-on: windows-latest | |
| if: github.event_name == 'workflow_dispatch' | |
| permissions: | |
| contents: write | |
| pull-requests: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| ref: ${{ github.ref }} | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Restore dependencies | |
| run: dotnet restore YAEP.sln | |
| - name: Build solution | |
| run: dotnet build YAEP.sln --configuration Release --no-restore | |
| - name: Get current version | |
| id: get_version | |
| run: | | |
| $version = Select-String -Path "YAEP.AvaloniaUI\YAEP.AvaloniaUI.csproj" -Pattern '<Version>(\d+)\.(\d+)\.(\d+)</Version>' | ForEach-Object { $_.Matches.Groups[1..3].Value -join '.' } | |
| if ([string]::IsNullOrEmpty($version)) { | |
| $version = "1.0.0" | |
| } | |
| Write-Host "Current version: $version" | |
| echo "CURRENT_VERSION=$version" >> $env:GITHUB_ENV | |
| $parts = $version -split '\.' | |
| echo "MAJOR=$($parts[0])" >> $env:GITHUB_ENV | |
| echo "MINOR=$($parts[1])" >> $env:GITHUB_ENV | |
| echo "PATCH=$($parts[2])" >> $env:GITHUB_ENV | |
| - name: Get last tag | |
| id: get_last_tag | |
| run: | | |
| $ErrorActionPreference = "Continue" | |
| $lastTag = "" | |
| $hasChanges = "false" | |
| # Fetch all tags to ensure we have them | |
| Write-Host "Fetching all tags..." | |
| git fetch --tags --force | |
| # Get the most recent tag (sorted by version), won't fail if no tags exist | |
| $tagOutput = git tag --sort=-version:refname | Select-Object -First 1 | |
| if (-not [string]::IsNullOrWhiteSpace($tagOutput)) { | |
| $lastTag = $tagOutput.Trim() | |
| Write-Host "Found last tag: $lastTag" | |
| # Get the commit SHA that the tag points to (handles both annotated and lightweight tags) | |
| $tagCommit = git rev-parse "$lastTag^{commit}" 2>&1 | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Host "Warning: Could not resolve tag commit: $tagCommit" | |
| Write-Host "Assuming changes exist for safety" | |
| $hasChanges = "true" | |
| } else { | |
| $tagCommit = $tagCommit.Trim() | |
| Write-Host "Tag $lastTag points to commit: $tagCommit" | |
| # Get current HEAD commit | |
| $headCommit = git rev-parse HEAD 2>&1 | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Host "Warning: Could not get HEAD commit" | |
| Write-Host "Assuming changes exist for safety" | |
| $hasChanges = "true" | |
| } else { | |
| $headCommit = $headCommit.Trim() | |
| Write-Host "Current HEAD commit: $headCommit" | |
| # Check if there are commits between tag and HEAD | |
| # Use ^{commit} to dereference annotated tags to their commit | |
| Write-Host "Checking for commits between $lastTag and HEAD..." | |
| $commitCountOutput = git rev-list "$lastTag^{commit}..HEAD" --count 2>&1 | |
| if ($LASTEXITCODE -eq 0) { | |
| if (-not [string]::IsNullOrWhiteSpace($commitCountOutput)) { | |
| $commitCount = [int]$commitCountOutput.Trim() | |
| Write-Host "Commit count: $commitCount" | |
| if ($commitCount -gt 0) { | |
| $hasChanges = "true" | |
| Write-Host "Found $commitCount new commits since last tag" | |
| } else { | |
| Write-Host "No new commits since last tag, skipping version bump and release" | |
| } | |
| } else { | |
| Write-Host "No commit count output, checking if commits exist..." | |
| # Fallback: check if there are any commits at all | |
| $commitList = git rev-list "$lastTag^{commit}..HEAD" 2>&1 | |
| if (-not [string]::IsNullOrWhiteSpace($commitList)) { | |
| $hasChanges = "true" | |
| Write-Host "Found commits between tag and HEAD" | |
| } else { | |
| Write-Host "No new commits since last tag, skipping version bump and release" | |
| } | |
| } | |
| } else { | |
| Write-Host "Warning: git rev-list failed with exit code $LASTEXITCODE" | |
| Write-Host "Output: $commitCountOutput" | |
| Write-Host "Assuming changes exist for safety" | |
| $hasChanges = "true" | |
| } | |
| } | |
| } | |
| } else { | |
| Write-Host "No existing tags found - this will be the first release" | |
| $hasChanges = "true" | |
| } | |
| Write-Host "Last tag: $lastTag (empty if none)" | |
| Write-Host "Has changes: $hasChanges" | |
| echo "has_changes=$hasChanges" >> $env:GITHUB_OUTPUT | |
| echo "LAST_TAG=$lastTag" >> $env:GITHUB_ENV | |
| - name: Increment version | |
| id: increment_version | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| $patch = [int]$env:PATCH + 1 | |
| $newVersion = "$env:MAJOR.$env:MINOR.$patch" | |
| Write-Host "New version: $newVersion" | |
| echo "version=$newVersion" >> $env:GITHUB_OUTPUT | |
| - name: Update version in project files | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| $newVersion = "${{ steps.increment_version.outputs.version }}" | |
| $files = @("YAEP.AvaloniaUI\YAEP.AvaloniaUI.csproj", "YAEP.Interop\YAEP.Interop.csproj") | |
| foreach ($file in $files) { | |
| $content = Get-Content $file -Raw | |
| # Add or update Version property | |
| if ($content -match '<Version>(\d+\.\d+\.\d+)</Version>') { | |
| $content = $content -replace '<Version>(\d+\.\d+\.\d+)</Version>', "<Version>$newVersion</Version>" | |
| } else { | |
| # Add Version property after TargetFramework | |
| $content = $content -replace '(<TargetFramework>.*?</TargetFramework>)', "`$1`n <Version>$newVersion</Version>" | |
| } | |
| # Add or update AssemblyVersion | |
| if ($content -match '<AssemblyVersion>(\d+\.\d+\.\d+\.\d+)</AssemblyVersion>') { | |
| $content = $content -replace '<AssemblyVersion>(\d+\.\d+\.\d+\.\d+)</AssemblyVersion>', "<AssemblyVersion>$newVersion.0</AssemblyVersion>" | |
| } else { | |
| $content = $content -replace '(<Version>.*?</Version>)', "`$1`n <AssemblyVersion>$newVersion.0</AssemblyVersion>" | |
| } | |
| # Add or update FileVersion | |
| if ($content -match '<FileVersion>(\d+\.\d+\.\d+\.\d+)</FileVersion>') { | |
| $content = $content -replace '<FileVersion>(\d+\.\d+\.\d+\.\d+)</FileVersion>', "<FileVersion>$newVersion.0</FileVersion>" | |
| } else { | |
| $content = $content -replace '(<AssemblyVersion>.*?</AssemblyVersion>)', "`$1`n <FileVersion>$newVersion.0</FileVersion>" | |
| } | |
| # Add AssemblyName to YAEP.AvaloniaUI to make executable YAEP.exe | |
| if ($file -like "*YAEP.AvaloniaUI*") { | |
| if (-not ($content -match '<AssemblyName>')) { | |
| $content = $content -replace '(<FileVersion>.*?</FileVersion>)', "`$1`n <AssemblyName>YAEP</AssemblyName>" | |
| } else { | |
| $content = $content -replace '<AssemblyName>.*?</AssemblyName>', "<AssemblyName>YAEP</AssemblyName>" | |
| } | |
| } | |
| Set-Content $file -Value $content -NoNewline | |
| } | |
| - name: Rebuild with new version | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| dotnet build YAEP.sln --configuration Release --no-restore | |
| - name: Publish application | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| dotnet publish YAEP.AvaloniaUI/YAEP.AvaloniaUI.csproj --configuration Release --output ./publish --no-build | |
| - name: Configure Git | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| git config --global user.name "github-actions[bot]" | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Commit version bump | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| git add YAEP.AvaloniaUI/YAEP.AvaloniaUI.csproj YAEP.Interop/YAEP.Interop.csproj | |
| git commit -m "Bump version to ${{ steps.increment_version.outputs.version }}" || exit 0 | |
| - name: Generate release notes | |
| id: generate_release_notes | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| uses: actions/github-script@v7 | |
| env: | |
| LAST_TAG: ${{ env.LAST_TAG }} | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const lastTag = process.env.LAST_TAG; | |
| const params = { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| tag_name: `v${{ steps.increment_version.outputs.version }}`, | |
| }; | |
| // If there's a previous tag, use it for comparison (as per GitHub docs) | |
| if (lastTag && lastTag.trim() !== '') { | |
| params.previous_tag_name = lastTag; | |
| } | |
| const { data: releaseNotes } = await github.rest.repos.generateReleaseNotes(params); | |
| core.setOutput('body', releaseNotes.body); | |
| fs.writeFileSync('CHANGELOG.md', releaseNotes.body); | |
| - name: Create git tag | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| $version = "${{ steps.increment_version.outputs.version }}" | |
| git tag -a "v$version" -m "Release v$version" | |
| git push origin "v$version" | |
| - name: Push version bump commit | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| git push origin main | |
| - name: Create release package | |
| id: create_package | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| run: | | |
| $version = "${{ steps.increment_version.outputs.version }}" | |
| $zipName = "YAEP-v$version.zip" | |
| Compress-Archive -Path ./publish/* -DestinationPath $zipName -Force | |
| Write-Host "Created package: $zipName" | |
| echo "package_name=$zipName" >> $env:GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| if: steps.get_last_tag.outputs.has_changes == 'true' | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: v${{ steps.increment_version.outputs.version }} | |
| name: Release v${{ steps.increment_version.outputs.version }} | |
| body_path: CHANGELOG.md | |
| files: YAEP-v${{ steps.increment_version.outputs.version }}.zip | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |