Functions/GitHub-Operations.ps1

# GitHub Operations Functions
# GitHub-CreateRelease, GitHub-Publish

function GitHub-CreateRelease {
    <#
    .SYNOPSIS
    Creates a GitHub release with assets.
     
    .DESCRIPTION
    Creates a GitHub release using the GitHub CLI with specified assets and metadata.
     
    .PARAMETER Repository
    GitHub repository in format "owner/repo" or just "repo" (uses current user).
     
    .PARAMETER Tag
    Release tag (e.g., "v1.0.0").
     
    .PARAMETER Title
    Release title.
     
    .PARAMETER Notes
    Release notes/description.
     
    .PARAMETER Assets
    Array of asset file paths to upload.
     
    .PARAMETER Prerelease
    Mark as prerelease.
     
    .PARAMETER Draft
    Create as draft.
     
    .PARAMETER Target
    Target branch for the release.
     
    .PARAMETER Verbose
    Enable verbose output.
     
    .EXAMPLE
    GitHub-CreateRelease -Repository "myuser/myapp" -Tag "v1.0.0" -Title "Release v1.0.0" -Assets @("app.exe", "app.dll")
     
    .EXAMPLE
    GitHub-CreateRelease -Repository "myapp" -Tag "v1.0.0-beta" -Prerelease -Draft
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Repository,
        
        [Parameter(Mandatory = $true)]
        [string]$Tag,
        
        [string]$Title,
        
        [string]$Notes,
        
        [string[]]$Assets = @(),
        
        [switch]$Prerelease,
        
        [switch]$Draft,
        
        [string]$Target,
        
        [switch]$VerboseOutput
    )
    
    # Check if gh CLI is available
    if (-not (Get-Command gh -ErrorAction SilentlyContinue)) {
        Write-Error "GitHub CLI (gh) is not installed or not in PATH."
        return $false
    }
    
    # Get GitHub username if repository doesn't include owner
    if ($Repository -notlike "*/*") {
        $githubUsername = Get-Username -Service "github"
        if (-not $githubUsername) {
            Write-Error "Could not determine GitHub username"
            return $false
        }
        $Repository = "$githubUsername/$Repository"
    }
    
    try {
        Write-Host "Creating GitHub release..." -ForegroundColor Green
        Write-Host "Repository: $Repository" -ForegroundColor Cyan
        Write-Host "Tag: $Tag" -ForegroundColor Cyan
        
        # Build gh release create command
        $releaseArgs = @("release", "create", $Tag)
        
        if ($Title) {
            $releaseArgs += @("--title", $Title)
        }
        
        if ($Notes) {
            $releaseArgs += @("--notes", $Notes)
        }
        
        if ($Prerelease) {
            $releaseArgs += "--prerelease"
        }
        
        if ($Draft) {
            $releaseArgs += "--draft"
        }
        
        if ($Target) {
            $releaseArgs += @("--target", $Target)
        }
        
        if ($VerboseOutput) {
            $releaseArgs += "--verbose"
        }
        
        # Add assets
        foreach ($asset in $Assets) {
            if (Test-Path $asset) {
                $releaseArgs += $asset
            }
            else {
                Write-Warning "Asset file not found: $asset"
            }
        }
        
        # Add repository
        $releaseArgs += "--repo", $Repository
        
        # Create release
        $releaseOutput = gh $releaseArgs 2>&1 | Out-String
        $releaseExitCode = $LASTEXITCODE
        
        if ($releaseExitCode -eq 0) {
            Write-Host "GitHub release created successfully" -ForegroundColor Green
            if ($releaseOutput) {
                Write-Host "Release output:" -ForegroundColor Cyan
                Write-Host $releaseOutput
            }
            return $true
        }
        else {
            Write-Host "GitHub release creation failed with exit code: $releaseExitCode" -ForegroundColor Red
            if ($releaseOutput) {
                Write-Host "Release output:" -ForegroundColor Yellow
                Write-Host $releaseOutput
            }
            return $false
        }
    }
    catch {
        Write-Error "GitHub release creation failed: $_"
        return $false
    }
}

function GitHub-Publish {
    <#
    .SYNOPSIS
    Publishes a GitHub release with assets in parallel.
     
    .DESCRIPTION
    Creates a GitHub release and uploads assets in parallel for better performance.
     
    .PARAMETER Repository
    GitHub repository in format "owner/repo" or just "repo" (uses current user).
     
    .PARAMETER Tag
    Release tag (e.g., "v1.0.0").
     
    .PARAMETER Title
    Release title.
     
    .PARAMETER Notes
    Release notes/description.
     
    .PARAMETER Assets
    Array of asset file paths to upload.
     
    .PARAMETER Prerelease
    Mark as prerelease.
     
    .PARAMETER Draft
    Create as draft.
     
    .PARAMETER Target
    Target branch for the release.
     
    .PARAMETER Parallel
    Upload assets in parallel (default: true).
     
    .PARAMETER Verbose
    Enable verbose output.
     
    .EXAMPLE
    GitHub-Publish -Repository "myuser/myapp" -Tag "v1.0.0" -Title "Release v1.0.0" -Assets @("app.exe", "app.dll")
     
    .EXAMPLE
    GitHub-Publish -Repository "myapp" -Tag "v1.0.0-beta" -Prerelease -Parallel
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Repository,
        
        [Parameter(Mandatory = $true)]
        [string]$Tag,
        
        [string]$Title,
        
        [string]$Notes,
        
        [string[]]$Assets = @(),
        
        [switch]$Prerelease,
        
        [switch]$Draft,
        
        [string]$Target,
        
        [switch]$Parallel,
        
        [switch]$VerboseOutput
    )
    
    # Check if gh CLI is available
    if (-not (Get-Command gh -ErrorAction SilentlyContinue)) {
        Write-Error "GitHub CLI (gh) is not installed or not in PATH."
        return $false
    }
    
    # Get GitHub username if repository doesn't include owner
    if ($Repository -notlike "*/*") {
        $githubUsername = Get-Username -Service "github"
        if (-not $githubUsername) {
            Write-Error "Could not determine GitHub username"
            return $false
        }
        $Repository = "$githubUsername/$Repository"
    }
    
    try {
        Write-Host "Publishing to GitHub..." -ForegroundColor Green
        Write-Host "Repository: $Repository" -ForegroundColor Cyan
        Write-Host "Tag: $Tag" -ForegroundColor Cyan
        
        # Create release first
        $releaseSuccess = GitHub-CreateRelease -Repository $Repository -Tag $Tag -Title $Title -Notes $Notes -Prerelease:$Prerelease -Draft:$Draft -Target $Target -Verbose:$Verbose
        
        if (-not $releaseSuccess) {
            Write-Error "Failed to create GitHub release"
            return $false
        }
        
        # Upload assets if provided
        if ($Assets.Count -gt 0) {
            Write-Host "Uploading assets..." -ForegroundColor Green
            
            if ($Parallel -or $true) {
                # Upload assets in parallel
                $uploadJobs = @()
                
                foreach ($asset in $Assets) {
                    if (Test-Path $asset) {
                        Write-Host "Starting upload for asset: $asset" -ForegroundColor Yellow
                        $job = Start-Job -ScriptBlock {
                            param($assetPath, $tag, $repo)
                            try {
                                $output = gh release upload $tag $assetPath --repo $repo 2>&1
                                $exitCode = $LASTEXITCODE
                                return @{
                                    Name     = [System.IO.Path]::GetFileName($assetPath)
                                    ExitCode = $exitCode
                                    Output   = $output
                                }
                            }
                            catch {
                                return @{
                                    Name     = [System.IO.Path]::GetFileName($assetPath)
                                    ExitCode = 1
                                    Output   = $_.Exception.Message
                                }
                            }
                        } -ArgumentList $asset, $Tag, $Repository
                        $uploadJobs += $job
                    }
                    else {
                        Write-Warning "Asset file not found: $asset"
                    }
                }
                
                # Wait for all uploads to complete and collect results
                Write-Host "Waiting for all asset uploads to complete..." -ForegroundColor Yellow
                $results = $uploadJobs | Wait-Job | Receive-Job
                
                # Report results
                $successCount = 0
                foreach ($result in $results) {
                    if ($result.ExitCode -eq 0) {
                        Write-Host "Successfully uploaded: $($result.Name)" -ForegroundColor Green
                        $successCount++
                    }
                    else {
                        Write-Host "Failed to upload: $($result.Name)" -ForegroundColor Red
                        if ($result.Output) {
                            Write-Host " Error: $($result.Output)" -ForegroundColor Red
                        }
                    }
                }
                
                # Clean up jobs
                $uploadJobs | Remove-Job
                
                if ($successCount -eq $Assets.Count) {
                    Write-Host "All assets uploaded successfully" -ForegroundColor Green
                    return $true
                }
                else {
                    Write-Host "Some assets failed to upload" -ForegroundColor Yellow
                    return $false
                }
            }
            else {
                # Upload assets sequentially
                $successCount = 0
                foreach ($asset in $Assets) {
                    if (Test-Path $asset) {
                        Write-Host "Uploading asset: $asset" -ForegroundColor Yellow
                        $uploadOutput = gh release upload $Tag $asset --repo $Repository 2>&1
                        $uploadExitCode = $LASTEXITCODE
                        
                        if ($uploadExitCode -eq 0) {
                            Write-Host "Successfully uploaded: $asset" -ForegroundColor Green
                            $successCount++
                        }
                        else {
                            Write-Host "Failed to upload: $asset" -ForegroundColor Red
                            if ($uploadOutput) {
                                Write-Host " Error: $uploadOutput" -ForegroundColor Red
                            }
                        }
                    }
                    else {
                        Write-Warning "Asset file not found: $asset"
                    }
                }
                
                if ($successCount -eq $Assets.Count) {
                    Write-Host "All assets uploaded successfully" -ForegroundColor Green
                    return $true
                }
                else {
                    Write-Host "Some assets failed to upload" -ForegroundColor Yellow
                    return $false
                }
            }
        }
        else {
            Write-Host "No assets to upload" -ForegroundColor Yellow
            return $true
        }
    }
    catch {
        Write-Error "GitHub publish failed: $_"
        return $false
    }
}