Functions/Dotnet-Build.ps1

# .NET Build Functions
# Dotnet-Build, Dotnet-Publish, Dotnet-Clean

function Dotnet-Build {
    <#
    .SYNOPSIS
    Builds a .NET project with specified configuration and architecture.
     
    .DESCRIPTION
    Builds a .NET project using dotnet build with various configuration options.
     
    .PARAMETER ProjectPath
    Path to the .NET project file (.csproj) or solution file (.sln).
     
    .PARAMETER Configuration
    Build configuration (Debug, Release, etc.).
     
    .PARAMETER Architecture
    Target architecture (win-x64, win-x86, linux-x64, etc.).
     
    .PARAMETER Framework
    Target framework (net8.0, net7.0, etc.).
     
    .PARAMETER OutputPath
    Output directory for build artifacts.
     
    .PARAMETER Clean
    Clean before building.
     
    .PARAMETER Verbose
    Enable verbose output.
     
    .EXAMPLE
    Dotnet-Build -ProjectPath "MyProject.csproj" -Configuration "Release" -Architecture "win-x64"
     
    .EXAMPLE
    Dotnet-Build -ProjectPath "MySolution.sln" -Configuration "Debug" -Clean -Verbose
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectPath,
        
        [ValidateSet("Debug", "Release", "ReleaseOptimized", "ReleaseMinimal")]
        [string]$Configuration = "Release",
        
        [string]$Architecture = "win-x64",
        
        [string]$Framework,
        
        [string]$OutputPath,
        
        [switch]$Clean,
        
        [switch]$VerboseOutput
    )
    
    if (-not (Test-Path $ProjectPath)) {
        Write-Error "Project file not found: $ProjectPath"
        return $false
    }
    
    try {
        # Clean if requested
        if ($Clean) {
            Write-Host "Cleaning project..." -ForegroundColor Yellow
            dotnet clean $ProjectPath -c $Configuration
            if ($LASTEXITCODE -ne 0) {
                Write-Warning "Clean failed, continuing with build..."
            }
        }
        
        # Build the project
        Write-Host "Building $ProjectPath..." -ForegroundColor Green
        Write-Host "Configuration: $Configuration" -ForegroundColor Cyan
        Write-Host "Architecture: $Architecture" -ForegroundColor Cyan
        
        $buildArgs = @("build", $ProjectPath, "-c", $Configuration, "-r", $Architecture)
        
        if ($Framework) {
            $buildArgs += @("-f", $Framework)
            Write-Host "Framework: $Framework" -ForegroundColor Cyan
        }
        
        if ($OutputPath) {
            $buildArgs += @("-o", $OutputPath)
            Write-Host "Output: $OutputPath" -ForegroundColor Cyan
        }
        
        if ($VerboseOutput) {
            $buildArgs += "--verbosity", "detailed"
        }
        
        $buildOutput = dotnet $buildArgs 2>&1
        $buildExitCode = $LASTEXITCODE
        
        if ($buildExitCode -eq 0) {
            Write-Host "Build completed successfully" -ForegroundColor Green
            return $true
        }
        else {
            Write-Host "Build failed with exit code: $buildExitCode" -ForegroundColor Red
            Write-Host "Build output:" -ForegroundColor Yellow
            Write-Host $buildOutput
            return $false
        }
    }
    catch {
        Write-Error "Build failed: $_"
        return $false
    }
}

function Dotnet-Publish {
    <#
    .SYNOPSIS
    Publishes a .NET project with specified configuration and architecture.
     
    .DESCRIPTION
    Publishes a .NET project using dotnet publish with various configuration options.
     
    .PARAMETER ProjectPath
    Path to the .NET project file (.csproj) or solution file (.sln).
     
    .PARAMETER Configuration
    Build configuration (Debug, Release, etc.).
     
    .PARAMETER Architecture
    Target architecture (win-x64, win-x86, linux-x64, etc.).
     
    .PARAMETER Framework
    Target framework (net8.0, net7.0, etc.).
     
    .PARAMETER OutputPath
    Output directory for published artifacts.
     
    .PARAMETER SelfContained
    Create self-contained deployment.
     
    .PARAMETER SingleFile
    Create single-file deployment.
     
    .PARAMETER Trimmed
    Enable trimming for smaller deployment.
     
    .PARAMETER Clean
    Clean before publishing.
     
    .PARAMETER Verbose
    Enable verbose output.
     
    .EXAMPLE
    Dotnet-Publish -ProjectPath "MyProject.csproj" -Configuration "Release" -Architecture "win-x64" -SelfContained
     
    .EXAMPLE
    Dotnet-Publish -ProjectPath "MyProject.csproj" -Configuration "Release" -SingleFile -Trimmed
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectPath,
        
        [ValidateSet("Debug", "Release", "ReleaseOptimized", "ReleaseMinimal")]
        [string]$Configuration = "Release",
        
        [string]$Architecture = "win-x64",
        
        [string]$Framework,
        
        [string]$OutputPath,
        
        [switch]$SelfContained,
        
        [switch]$SingleFile,
        
        [switch]$Trimmed,
        
        [switch]$Clean,
        
        [switch]$VerboseOutput
    )
    
    if (-not (Test-Path $ProjectPath)) {
        Write-Error "Project file not found: $ProjectPath"
        return $false
    }
    
    try {
        # Clean if requested
        if ($Clean) {
            Write-Host "Cleaning project..." -ForegroundColor Yellow
            dotnet clean $ProjectPath -c $Configuration
            if ($LASTEXITCODE -ne 0) {
                Write-Warning "Clean failed, continuing with publish..."
            }
        }
        
        # Publish the project
        Write-Host "Publishing $ProjectPath..." -ForegroundColor Green
        Write-Host "Configuration: $Configuration" -ForegroundColor Cyan
        Write-Host "Architecture: $Architecture" -ForegroundColor Cyan
        
        $publishArgs = @("publish", $ProjectPath, "-c", $Configuration, "-r", $Architecture)
        
        if ($Framework) {
            $publishArgs += @("-f", $Framework)
            Write-Host "Framework: $Framework" -ForegroundColor Cyan
        }
        
        if ($OutputPath) {
            $publishArgs += @("-o", $OutputPath)
            Write-Host "Output: $OutputPath" -ForegroundColor Cyan
        }
        
        if ($SelfContained) {
            $publishArgs += "--self-contained", "true"
            Write-Host "Self-contained: true" -ForegroundColor Cyan
        }
        else {
            $publishArgs += "--self-contained", "false"
        }
        
        if ($SingleFile) {
            $publishArgs += "/p:PublishSingleFile=true"
            Write-Host "Single file: true" -ForegroundColor Cyan
        }
        
        if ($Trimmed) {
            $publishArgs += "/p:PublishTrimmed=true"
            Write-Host "Trimmed: true" -ForegroundColor Cyan
        }
        
        if ($Verbose) {
            $publishArgs += "--verbosity", "detailed"
        }
        
        # Add release optimizations
        if ($Configuration -eq "Release") {
            $publishArgs += @(
                "/p:OptimizeImplicitlyTriggeredBuild=true",
                "/p:EnableCompressionInSingleFile=true",
                "/p:DebugType=None",
                "/p:DebugSymbols=false"
            )
            
            # Additional optimizations for standalone builds
            if ($SelfContained) {
                $publishArgs += @(
                    "/p:TrimMode=link",
                    "/p:EnableUnsafeBinaryFormatterSerialization=false",
                    "/p:EnableUnsafeUTF7Encoding=false",
                    "/p:EventSourceSupport=false",
                    "/p:HttpActivityPropagationSupport=false",
                    "/p:InvariantGlobalization=true",
                    "/p:MetadataUpdaterSupport=false"
                )
            }
        }
        
        $publishOutput = dotnet $publishArgs 2>&1
        $publishExitCode = $LASTEXITCODE
        
        if ($publishExitCode -eq 0) {
            Write-Host "Publish completed successfully" -ForegroundColor Green
            
            # Try to extract output path from publish output
            $lines = $publishOutput -split "`n"
            foreach ($line in $lines) {
                if ($line -match ".* -> (.+\\publish\\)$") {
                    $extractedPath = $matches[1].Trim()
                    Write-Host "Published to: $extractedPath" -ForegroundColor Green
                    return $extractedPath
                }
            }
            
            return $true
        }
        else {
            Write-Host "Publish failed with exit code: $publishExitCode" -ForegroundColor Red
            Write-Host "Publish output:" -ForegroundColor Yellow
            Write-Host $publishOutput
            return $false
        }
    }
    catch {
        Write-Error "Publish failed: $_"
        return $false
    }
}

function Dotnet-Clean {
    <#
    .SYNOPSIS
    Cleans a .NET project build artifacts.
     
    .DESCRIPTION
    Removes build artifacts from a .NET project using dotnet clean.
     
    .PARAMETER ProjectPath
    Path to the .NET project file (.csproj) or solution file (.sln).
     
    .PARAMETER Configuration
    Build configuration to clean (Debug, Release, etc.).
     
    .PARAMETER Verbose
    Enable verbose output.
     
    .EXAMPLE
    Dotnet-Clean -ProjectPath "MyProject.csproj" -Configuration "Release"
     
    .EXAMPLE
    Dotnet-Clean -ProjectPath "MySolution.sln" -Verbose
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectPath,
        
        [ValidateSet("Debug", "Release", "ReleaseOptimized", "ReleaseMinimal")]
        [string]$Configuration = "Release",
        
        [switch]$VerboseOutput
    )
    
    if (-not (Test-Path $ProjectPath)) {
        Write-Error "Project file not found: $ProjectPath"
        return $false
    }
    
    try {
        Write-Host "Cleaning $ProjectPath..." -ForegroundColor Yellow
        Write-Host "Configuration: $Configuration" -ForegroundColor Cyan
        
        $cleanArgs = @("clean", $ProjectPath, "-c", $Configuration)
        
        if ($Verbose) {
            $cleanArgs += "--verbosity", "detailed"
        }
        
        $cleanOutput = dotnet $cleanArgs 2>&1
        $cleanExitCode = $LASTEXITCODE
        
        if ($cleanExitCode -eq 0) {
            Write-Host "Clean completed successfully" -ForegroundColor Green
            return $true
        }
        else {
            Write-Host "Clean failed with exit code: $cleanExitCode" -ForegroundColor Red
            Write-Host "Clean output:" -ForegroundColor Yellow
            Write-Host $cleanOutput
            return $false
        }
    }
    catch {
        Write-Error "Clean failed: $_"
        return $false
    }
}

function Set-DotnetVersion {
    <#
    .SYNOPSIS
    Sets the version in .NET project files (csproj and AssemblyInfo.cs).
     
    .DESCRIPTION
    Updates version information in both .csproj files and AssemblyInfo.cs files for .NET projects.
     
    .PARAMETER ProjectPath
    Path to the .NET project directory.
     
    .PARAMETER Version
    Version string to set.
     
    .PARAMETER Backup
    Create backup files before modifying.
     
    .EXAMPLE
    Set-DotnetVersion -ProjectPath "C:\MyProject" -Version "1.2.3.4"
     
    .EXAMPLE
    Set-DotnetVersion -ProjectPath "C:\MyProject" -Version "1.2.3.4" -Backup
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectPath,
        
        [Parameter(Mandatory = $true)]
        [string]$Version,
        
        [switch]$Backup
    )
    
    try {
        $allFiles = @()
        
        # Find all .csproj files
        $csprojFiles = Get-ChildItem $ProjectPath -Filter "*.csproj" -Recurse
        $allFiles += $csprojFiles
        
        # Find all AssemblyInfo.cs files
        $assemblyInfoFiles = Get-ChildItem $ProjectPath -Filter "AssemblyInfo.cs" -Recurse
        $allFiles += $assemblyInfoFiles
        
        # Use Set-Version with all .NET version patterns
        $patterns = @(
            '<Version>([^<]+)</Version>',
            '<FileVersion>([^<]+)</FileVersion>',
            'AssemblyVersion\("([^"]+)"\)',
            'AssemblyFileVersion\("([^"]+)"\)'
        )
        
        $results = @()
        foreach ($pattern in $patterns) {
            $result = Set-Version -Files $allFiles.FullName -Pattern $pattern -NewVersion $Version -Backup:$Backup
            if ($result.Success) {
                $results += $result.Results
            }
        }
        
        return @{
            Success = $true
            Results = $results
            Version = $Version
        }
    }
    catch {
        Write-Error "Failed to set .NET version: $_"
        return @{
            Success = $false
            Error   = $_.Exception.Message
        }
    }
}

function Bump-DotnetVersion {
    <#
    .SYNOPSIS
    Bumps the version in .NET project files (csproj and AssemblyInfo.cs).
     
    .DESCRIPTION
    Increments version information in both .csproj files and AssemblyInfo.cs files for .NET projects.
    Supports major, minor, patch, and build number increments.
     
    .PARAMETER ProjectPath
    Path to the .NET project directory.
     
    .PARAMETER BumpType
    Type of version bump: Major, Minor, Patch, Build.
     
    .PARAMETER Backup
    Create backup files before modifying.
     
    .EXAMPLE
    Bump-DotnetVersion -ProjectPath "C:\MyProject" -BumpType "Patch"
     
    .EXAMPLE
    Bump-DotnetVersion -ProjectPath "C:\MyProject" -BumpType "Build" -Backup
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectPath,
        
        [ValidateSet("Major", "Minor", "Patch", "Build")]
        [string]$BumpType = "Build",
        
        [switch]$Backup
    )
    
    try {
        # Find AssemblyInfo.cs files for version detection
        $assemblyInfoFiles = Get-ChildItem $ProjectPath -Filter "AssemblyInfo.cs" -Recurse
        if ($assemblyInfoFiles.Count -eq 0) {
            throw "No AssemblyInfo.cs files found in $ProjectPath"
        }
        
        # Use Bump-Version with AssemblyVersion pattern to get the new version
        $result = Bump-Version -Files $assemblyInfoFiles.FullName -Pattern 'AssemblyVersion\("([^"]+)"\)' -Backup:$Backup
        
        if (-not $result.Success) {
            throw "Failed to bump AssemblyVersion: $($result.Error)"
        }
        
        # Parse the new version and apply it to all .NET version patterns
        $newVersion = $result.NewVersion
        
        # Now use Set-DotnetVersion to apply the new version to all .NET files
        $setResult = Set-DotnetVersion -ProjectPath $ProjectPath -Version $newVersion -Backup:$false
        
        if ($setResult.Success) {
            return @{
                Success    = $true
                OldVersion = $result.OldVersion
                NewVersion = $newVersion
                Version    = $newVersion
                Results    = $setResult.Results
            }
        }
        else {
            return $setResult
        }
    }
    catch {
        Write-Error "Failed to bump .NET version: $_"
        return @{
            Success = $false
            Error   = $_.Exception.Message
        }
    }
}