.github/templates/scripts/Create-GitHubRelease.ps1

<#
.SYNOPSIS
    Creates a complete GitHub release using K.PSGallery.Smartagr.
 
.DESCRIPTION
    Creates a complete semantic release with smart tags using the proven
    Draft → Smart Tags → Publish strategy from K.PSGallery.Smartagr.
     
    Falls back to gh CLI if Smartagr is not available.
 
.PARAMETER Version
    Semantic version without 'v' prefix (e.g., "1.2.3").
 
.PARAMETER BumpType
    Type of version bump (major/minor/patch/manual).
 
.PARAMETER ModuleName
    Name of the PowerShell module.
 
.PARAMETER Repository
    GitHub repository in format "owner/repo".
 
.OUTPUTS
    Sets GITHUB_OUTPUT variables: release-created, release-tag, release-url
 
.EXAMPLE
    ./Create-GitHubRelease.ps1 -Version "1.2.3" -BumpType "patch" -ModuleName "MyModule" -Repository "owner/repo"
 
.NOTES
    Platform-independent PowerShell script for GitHub Actions workflows.
    Uses K.PSGallery.Smartagr for release management.
#>


[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [string]$Version,
    
    [Parameter(Mandatory = $true)]
    [string]$BumpType,
    
    [Parameter(Mandatory = $true)]
    [string]$ModuleName,
    
    [Parameter(Mandatory = $true)]
    [string]$Repository
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$releaseTag = "v$Version"

Write-Output "Creating release $releaseTag for $ModuleName"

# ─────────────────────────────────────────────────────────────────────────────
# Try Smartagr first (preferred method)
# ─────────────────────────────────────────────────────────────────────────────
$smartagrAvailable = $false
try {
    if (Get-Command -Name 'New-SmartRelease' -ErrorAction SilentlyContinue) {
        $smartagrAvailable = $true
    }
} catch {
    # Smartagr not available
}

if ($smartagrAvailable) {
    Write-Output "Using K.PSGallery.Smartagr for release creation"
    
    # Generate release notes for PowerShell module
    $timestamp = (Get-Date).ToUniversalTime().ToString('MMMM dd, yyyy \a\t HH:mm UTC')
    $releaseNotes = @"
## 🎉 Release $releaseTag
 
> **$BumpType** release • Released on $timestamp
 
### 📦 Quick Access
- 📁 [Source Code](https://github.com/$Repository)
- 🏷️ [This Release](https://github.com/$Repository/releases/tag/$releaseTag)
 
### 🚀 Installation
``````powershell
Install-Module -Name $ModuleName -RequiredVersion $Version
``````
 
---
*Auto-generated release*
"@


    # New-SmartRelease handles: Draft → Smart Tags → Publish
    $result = New-SmartRelease -TargetVersion $releaseTag -ReleaseNotes $releaseNotes -PushToRemote -Force
    
    if ($result.Success) {
        $releaseUrl = $result.ReleaseUrl
        
        # Set outputs
        "release-created=true" >> $env:GITHUB_OUTPUT
        "release-tag=$releaseTag" >> $env:GITHUB_OUTPUT
        "release-url=$releaseUrl" >> $env:GITHUB_OUTPUT
        
        Write-Output "✅ Release created successfully via Smartagr"
        Write-Output " Tags created: $($result.TagsCreated -join ', ')"
        Write-Output " URL: $releaseUrl"
    } else {
        throw "Smartagr release failed: $($result.GitHubReleaseResult.ErrorMessage)"
    }
} else {
    # ─────────────────────────────────────────────────────────────────────────────
    # Fallback: gh CLI (when Smartagr not available)
    # ─────────────────────────────────────────────────────────────────────────────
    Write-Output "Smartagr not available, using gh CLI fallback"
    
    $timestamp = (Get-Date).ToUniversalTime().ToString('MMMM dd, yyyy \a\t HH:mm UTC')
    $releaseNotes = @"
## 🎉 Release $releaseTag
 
> **$BumpType** release • Released on $timestamp
 
### 🚀 Installation
``````powershell
Install-Module -Name $ModuleName -RequiredVersion $Version
``````
 
---
*Auto-generated release*
"@


    Set-Content -Path 'release_notes.md' -Value $releaseNotes -Encoding utf8NoBOM

    # Delete existing release if exists
    try {
        $null = gh release view $releaseTag 2>&1
        if ($LASTEXITCODE -eq 0) {
            Write-Output "⚠️ Release exists - deleting and recreating"
            gh release delete $releaseTag --yes 2>$null
            git tag -d $releaseTag 2>$null
            git push origin --delete $releaseTag 2>$null
            Start-Sleep -Seconds 2
        }
    } catch {
        # Release doesn't exist, continue
    }

    # Determine if prerelease
    $isPrerelease = $Version -match '(alpha|beta|rc|preview|pre)'
    $title = if ($isPrerelease) { "🧪 Prerelease $releaseTag" } else { "🚀 $ModuleName $releaseTag" }

    # ─────────────────────────────────────────────────────────────────────────────
    # Step 1: Create base tag FIRST (required for smart tags to reference)
    # ─────────────────────────────────────────────────────────────────────────────
    Write-Output "Creating base tag $releaseTag"
    
    # Configure git
    git config user.name "github-actions[bot]"
    git config user.email "github-actions[bot]@users.noreply.github.com"
    
    # Create and push base tag
    git tag -a $releaseTag -m "Release $releaseTag"
    git push origin $releaseTag
    
    if ($LASTEXITCODE -ne 0) {
        throw "Failed to create base tag $releaseTag"
    }

    # ─────────────────────────────────────────────────────────────────────────────
    # Step 2: Create GitHub Release (Draft)
    # ─────────────────────────────────────────────────────────────────────────────
    Write-Output "Creating draft release"
    
    $ghArgs = @(
        'release', 'create', $releaseTag,
        '--title', $title,
        '--notes-file', 'release_notes.md',
        '--generate-notes',
        '--draft'
    )

    if ($isPrerelease) {
        $ghArgs += '--prerelease'
    }

    & gh @ghArgs

    if ($LASTEXITCODE -ne 0) {
        throw "Failed to create GitHub release via gh CLI"
    }

    # ─────────────────────────────────────────────────────────────────────────────
    # Step 3: Create Smart Tags (v1, v1.2, latest)
    # ─────────────────────────────────────────────────────────────────────────────
    Write-Output "Creating smart tags"
    
    $versionParts = $Version -split '\.'
    $major = "v$($versionParts[0])"
    $minor = "v$($versionParts[0]).$($versionParts[1])"
    
    # Create/move smart tags pointing to base tag
    foreach ($smartTag in @($major, $minor, 'latest')) {
        # Delete existing tag if exists
        git tag -d $smartTag 2>$null
        git push origin --delete $smartTag 2>$null
        
        # Create new tag pointing to release tag
        git tag -f $smartTag $releaseTag
        git push origin $smartTag --force
        
        Write-Output " Created smart tag: $smartTag -> $releaseTag"
    }

    # ─────────────────────────────────────────────────────────────────────────────
    # Step 4: Publish Release
    # ─────────────────────────────────────────────────────────────────────────────
    Write-Output "Publishing release"
    
    if ($isPrerelease) {
        gh release edit $releaseTag --draft=false
    } else {
        gh release edit $releaseTag --draft=false --latest
    }

    if ($LASTEXITCODE -ne 0) {
        throw "Failed to publish GitHub release"
    }

    $releaseUrl = "https://github.com/$Repository/releases/tag/$releaseTag"

    # Set outputs
    "release-created=true" >> $env:GITHUB_OUTPUT
    "release-tag=$releaseTag" >> $env:GITHUB_OUTPUT
    "release-url=$releaseUrl" >> $env:GITHUB_OUTPUT
    
    Write-Output "✅ Release created via gh CLI fallback"
    Write-Output " Base tag: $releaseTag"
    Write-Output " Smart tags: $major, $minor, latest"
    Write-Output " URL: $releaseUrl"
}