Skip to content

Create Release Candidate #194

Create Release Candidate

Create Release Candidate #194

name: Create Release Candidate
on:
workflow_dispatch:
inputs:
release_type:
description: 'Type of release increment (patch, minor, major)'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
jobs:
build:
runs-on: windows-latest
permissions:
contents: write
outputs:
new_version: ${{ steps.get_version.outputs.new_version }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
fetch-tags: true
- name: Get Latest Tag and Git Log
shell: bash
run: |
LATEST_TAG=$(git tag | grep -v '\-rc\.' | sort -V | tail -n 1)
echo "Latest Tag: $LATEST_TAG"
GIT_LOG=$(git log "${LATEST_TAG}..HEAD" --no-merges --oneline)
echo "Git Log:"
echo "$GIT_LOG"
echo "GIT_LOG<<EOF" >> $GITHUB_ENV
echo "$GIT_LOG" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('Frontend/bun.lock') }}
restore-keys: bun-${{ runner.os }}-
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/packages.lock.json') }}
restore-keys: nuget-${{ runner.os }}-
- name: Display Git Log
shell: bash
run: |
echo "Git Log since last tag:"
echo "$GIT_LOG"
- name: Generate Release Notes
id: generate_release_notes
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
# --- Debug: Show jq info ---
echo "ℹ️ Using jq from path: $(which jq)"
echo "ℹ️ jq version: $(jq --version)"
# --- Debug: Show raw input ---
echo "📜 Raw GIT_LOG:"
echo "$GIT_LOG"
echo ""
# Use pre-installed Chocolatey jq
export PATH="/c/ProgramData/Chocolatey/bin:$PATH"
# Define system prompt
SYSTEM_PROMPT="You are a helpful assistant who creates user-friendly release notes for open-source applications such as games and clip recorders. Your task is to transform raw update logs into concise and easy-to-understand release notes. Use a casual, direct tone and avoid overly technical language and details that are not important for the end user. Please merge changes if you think they are the same method/function that changed. Avoid wrapping the final release notes in a Markdown code block. Non techy and do not include things like chore or refactor if it doesn't do anything for the user! Do not include the text Release Notes in the beginning. Do not say thanks in the end. Also, "
# --- Debug: Show escaped content ---
echo "🔧 Escaping content..."
ESCAPED_SYSTEM=$(jq -Rs . <<< "$SYSTEM_PROMPT")
ESCAPED_LOG=$(jq -Rs . <<< "$GIT_LOG")
echo "🔒 Escaped System Prompt:"
echo "$ESCAPED_SYSTEM"
echo ""
echo "🔒 Escaped Git Log:"
echo "$ESCAPED_LOG"
echo ""
# Build JSON payload
JSON_PAYLOAD=$(jq -n \
--arg model "gpt-4o" \
--argjson system "$ESCAPED_SYSTEM" \
--argjson log "$ESCAPED_LOG" \
'{
"model": $model,
"messages": [
{"role": "system", "content": $system},
{"role": "user", "content": $log}
]
}')
# --- Debug: Show final payload ---
echo "📦 JSON Payload:"
echo "$JSON_PAYLOAD"
echo ""
# Make API call
echo "📡 Making API request to OpenAI..."
RESPONSE=$(curl -s -X POST "https://api.openai.com/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d "$JSON_PAYLOAD")
# --- Debug: Show raw response ---
echo "📨 Raw API Response:"
echo "$RESPONSE"
echo ""
# Extract release notes
RELEASE_NOTES=$(echo "$RESPONSE" | jq -r '.choices[0].message.content')
# --- Debug: Show final output ---
echo "🎉 Generated Release Notes:"
echo "$RELEASE_NOTES"
echo ""
- name: Determine Version
id: get_version
shell: pwsh
run: |
# Get the highest final release version (exclude RCs, sort by semver)
$latestFinalTag = (git tag | Where-Object { $_ -notmatch '-rc\.' } | Sort-Object { [version]($_ -replace '^v', '') } | Select-Object -Last 1) -replace '^v', ''
if (-not $latestFinalTag) {
$latestFinalTag = "0.0.0"
}
Write-Host "Latest final release: $latestFinalTag"
$releaseType = "${{ github.event.inputs.release_type }}"
# Calculate what the next version would be based on release type
$versionParts = $latestFinalTag.Split('.')
$major = [int]$versionParts[0]
$minor = [int]$versionParts[1]
$patch = [int]$versionParts[2]
switch ($releaseType) {
"major" { $major++; $minor=0; $patch=0 }
"minor" { $minor++; $patch=0 }
"patch" { $patch++ }
}
$nextBaseVersion = "$major.$minor.$patch"
Write-Host "Next base version would be: $nextBaseVersion"
# Check if there are existing RCs for this next version
$existingRCs = git tag | Where-Object { $_ -match "^v$([regex]::Escape($nextBaseVersion))-rc\.(\d+)$" }
if ($existingRCs) {
# Find the highest RC number
$highestRC = $existingRCs | ForEach-Object {
if ($_ -match '-rc\.(\d+)$') { [int]$Matches[1] }
} | Sort-Object | Select-Object -Last 1
$rcNumber = $highestRC + 1
Write-Host "Found existing RCs, highest is rc.$highestRC, creating rc.$rcNumber"
} else {
$rcNumber = 1
Write-Host "No existing RCs for $nextBaseVersion, starting at rc.1"
}
$newVersion = "$nextBaseVersion-rc.$rcNumber"
Write-Host "New version: $newVersion"
echo "new_version=$newVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8
echo "new_version=$newVersion" >> $env:GITHUB_OUTPUT
- name: Configure Git User
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
shell: pwsh
- name: Install vpk as .NET Global Tool
run: |
dotnet tool install -g vpk
$env:PATH += ";$env:USERPROFILE\.dotnet\tools"
shell: pwsh
- name: Update Frontend version
working-directory: ./Frontend
shell: pwsh
run: |
$content = Get-Content package.json -Raw
$packageJson = Get-Content package.json -Raw | ConvertFrom-Json
$packageJson.version = $env:new_version
$packageJson | ConvertTo-Json -Depth 100 | Set-Content package.json -NoNewline
Write-Host "Updated version: $(Select-String -Path package.json -Pattern 'version')"
- name: Install Frontend dependencies
working-directory: ./Frontend
run: bun install --frozen-lockfile
- name: Build Frontend
working-directory: ./Frontend
run: bun run build
- name: Move Frontend Build to Resources/wwwroot
run: |
$source = "./Frontend/dist"
$destination = "./Resources/wwwroot"
if (-Not (Test-Path -Path $destination)) { New-Item -ItemType Directory -Path $destination -Force }
Remove-Item -Path "$destination\*" -Recurse -Force
Copy-Item -Path "$source\*" -Destination $destination -Recurse -Force
shell: pwsh
- name: Publish the App
run: dotnet publish -c Release --self-contained -r win-x64 -o publish
shell: pwsh
- name: Package with vpk
run: vpk pack -u Segra -v ${{ env.new_version }} -p ./publish -e Segra.exe -o ./output --packTitle "Segra" --noPortable
shell: pwsh
- name: Create a Git Tag
run: |
git tag v${{ env.new_version }}
git push origin v${{ env.new_version }}
shell: pwsh
- name: Upload Release Artifact
uses: actions/upload-artifact@v4
with:
name: Segra
path: ./output
retention-days: 1
pre-release:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download Build Artifact
uses: actions/download-artifact@v4
with:
name: Segra
- name: Create GitHub Release (Pre-Release)
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.build.outputs.new_version }}
name: "Release v${{ needs.build.outputs.new_version }}"
prerelease: true
files: |
./Segra-win-Setup.exe
./RELEASES
./releases.win.json
./assets.win.json
./Segra-${{ needs.build.outputs.new_version }}-full.nupkg