From 4b7bf182e0f790f937827c8b6e9be35fdf9875ca Mon Sep 17 00:00:00 2001 From: marcmy <21000174+marcmy@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:01:53 -0400 Subject: [PATCH] Add build and release workflow --- .github/workflows/build-release.yml | 191 ++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 .github/workflows/build-release.yml diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 00000000..0f5008ec --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,191 @@ +name: Build and Release + +on: + pull_request: + branches: + - master + push: + branches: + - master + tags: + - "v*" + workflow_dispatch: + inputs: + release_tag: + description: "Optional tag to create a release from the selected ref (for example: v4.0.0-beta.7-marc.1)" + required: false + type: string + prerelease: + description: "Mark a manually created release as a prerelease" + required: false + default: true + type: boolean + +permissions: + contents: read + +env: + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + PROJECT_PATH: CompactGUI/CompactGUI.vbproj + RUNTIME_IDENTIFIER: win-x64 + +jobs: + build: + name: Build Windows x64 + runs-on: windows-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Restore + run: dotnet restore $env:PROJECT_PATH + + - name: Publish self-contained executable + shell: pwsh + run: | + $publishDir = Join-Path $env:RUNNER_TEMP "compactgui-publish" + Remove-Item $publishDir -Recurse -Force -ErrorAction SilentlyContinue + + dotnet publish $env:PROJECT_PATH ` + --configuration Release ` + --runtime $env:RUNTIME_IDENTIFIER ` + --self-contained true ` + --no-restore ` + --output $publishDir ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true ` + -p:DebugType=None ` + -p:DebugSymbols=false + + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + + $exe = Join-Path $publishDir "CompactGUI.exe" + if (-not (Test-Path $exe)) { + throw "Publish completed without producing CompactGUI.exe" + } + + - name: Package artifacts + shell: pwsh + run: | + $publishDir = Join-Path $env:RUNNER_TEMP "compactgui-publish" + $packageDir = Join-Path $env:RUNNER_TEMP "compactgui-package" + $artifactDir = Join-Path $env:RUNNER_TEMP "compactgui-artifacts" + + Remove-Item $packageDir, $artifactDir -Recurse -Force -ErrorAction SilentlyContinue + New-Item $packageDir, $artifactDir -ItemType Directory -Force | Out-Null + + Copy-Item (Join-Path $publishDir "CompactGUI.exe") $packageDir + Copy-Item "LICENSE" $packageDir + + @( + "Repository: $env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY" + "Commit: $env:GITHUB_SHA" + "Ref: $env:GITHUB_REF" + "Runtime: $env:RUNTIME_IDENTIFIER" + ) | Set-Content (Join-Path $packageDir "BUILD-INFO.txt") -Encoding utf8 + + $zipPath = Join-Path $artifactDir "CompactGUI-win-x64.zip" + Compress-Archive -Path (Join-Path $packageDir "*") -DestinationPath $zipPath -CompressionLevel Optimal + Copy-Item (Join-Path $publishDir "CompactGUI.exe") (Join-Path $artifactDir "CompactGUI.exe") + + Get-ChildItem $artifactDir -File | + Sort-Object Name | + ForEach-Object { + $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant() + "$hash *$($_.Name)" + } | Set-Content (Join-Path $artifactDir "SHA256SUMS.txt") -Encoding ascii + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: CompactGUI-win-x64 + path: ${{ runner.temp }}/compactgui-artifacts/* + if-no-files-found: error + retention-days: 14 + + release: + name: Publish GitHub release + needs: build + if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download release assets + uses: actions/download-artifact@v4 + with: + name: CompactGUI-win-x64 + path: release-assets + + - name: Resolve release tag + id: release + shell: bash + env: + MANUAL_TAG: ${{ inputs.release_tag }} + MANUAL_PRERELEASE: ${{ inputs.prerelease }} + run: | + if [[ "$GITHUB_REF" == refs/tags/* ]]; then + tag="${GITHUB_REF#refs/tags/}" + else + tag="$MANUAL_TAG" + fi + + if [[ -z "$tag" || "$tag" != v* ]]; then + echo "Release tags must start with v (for example: v4.0.0-beta.7-marc.1)." >&2 + exit 1 + fi + + prerelease=false + if [[ "$tag" == *-* ]] || [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" && "$MANUAL_PRERELEASE" == "true" ]]; then + prerelease=true + fi + + echo "tag=$tag" >> "$GITHUB_OUTPUT" + echo "prerelease=$prerelease" >> "$GITHUB_OUTPUT" + + - name: Create or update release + shell: bash + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.release.outputs.tag }} + PRERELEASE: ${{ steps.release.outputs.prerelease }} + run: | + if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + gh release upload "$TAG" release-assets/* --clobber --repo "$GITHUB_REPOSITORY" + exit 0 + fi + + release_args=( + release create "$TAG" + release-assets/* + --repo "$GITHUB_REPOSITORY" + --title "CompactGUI $TAG" + --generate-notes + ) + + if git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null 2>&1; then + release_args+=(--verify-tag) + else + release_args+=(--target "$GITHUB_SHA") + fi + + if [[ "$PRERELEASE" == "true" ]]; then + release_args+=(--prerelease) + fi + + gh "${release_args[@]}"