Sampler.CustomTasks.psm1

#Region './Private/New-WikiSidebarCustom.ps1' -1

function New-WikiSidebarCustom
{
    <#
    .SYNOPSIS
        Creates the Wiki side bar file from the list of markdown files in the path.

    .DESCRIPTION
        Creates the Wiki side bar file from the list of markdown files in the path.

    .PARAMETER ModuleName
        The name of the module to generate a new Wiki Sidebar file for.

    .PARAMETER OutputPath
        The path in which to create the Wiki Sidebar file, e.g. '.\output\WikiContent'.

    .PARAMETER WikiSourcePath
        The path where to find the markdown files that was generated
        by New-DscResourceWikiPage, e.g. '.\output\WikiContent'.

    .PARAMETER BaseName
        The base name of the Wiki Sidebar file. Defaults to '_Sidebar.md'.

    .PARAMETER addHierarchy
        When specified, adds a hierarchical structure to the sidebar based on subdirectories.

    .EXAMPLE
        New-WikiSidebarCustom -ModuleName 'ActiveDirectoryDsc' -OutputPath '.\output\WikiContent' -WikiSourcePath '.\output\WikiContent'

        Creates the Wiki side bar from the list of markdown files in the path.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $ModuleName,

        [Parameter(Mandatory = $true)]
        [System.String]
        $OutputPath,

        [Parameter(Mandatory = $true)]
        [System.String]
        $WikiSourcePath,

        [Parameter()]
        [System.String]
        $BaseName = '_Sidebar.md',

        [Parameter()]
        [switch]$addHierarchy = $false
    )

    $wikiSideBarOutputPath = Join-Path -Path $OutputPath -ChildPath $BaseName
    $wikiSideBarWikiSourcePath = Join-Path -Path $WikiSourcePath -ChildPath $BaseName

    if (-not (Test-Path -Path $wikiSideBarWikiSourcePath))
    {
        Write-Verbose -Message "Generating Wiki Sidebar file '$BaseName'."

        $WikiSidebarContent = @(
            "# $ModuleName Module"
            ' '
        )


        function Add-MarkdownFilesToSidebar
        {
            param (
                [string]$Path,
                [int]$Depth = 0
            )

            $indent = ' ' * $Depth
            $items = Get-ChildItem -Path $Path | Sort-Object { -not $_.PSIsContainer }, Name
            Write-Verbose -Message "$($items.Count) items found in $Path"

            foreach ($item in $items)
            {
                if ($item.PSIsContainer)
                {
                    $WikiSidebarContent += "$indent- **$($item.Name)**`n"
                    Write-Verbose -Message "PSIsContainer: $indent- **$($item.Name)**"
                    Add-MarkdownFilesToSidebar -Path $item.FullName -Depth ($Depth + 1)
                }
                elseif ($item.Extension -eq '.md' -and $item.Name -notmatch '^_.*\.md$')
                {
                    $relativePath = $item.FullName.Substring($OutputPath.Length).TrimStart('\', '/') -replace '\\', '/'
                    $WikiSidebarContent += "$indent- [$($item.BaseName)]($relativePath)`n"
                    Write-Verbose -Message "no PSIsContainer: $indent- [$($item.BaseName)]($relativePath)"
                }
            }
            return $WikiSidebarContent
        }

        $WikiSidebarContent = Add-MarkdownFilesToSidebar -Path $WikiSourcePath

        Out-File -InputObject $WikiSidebarContent -FilePath $wikiSideBarOutputPath -Encoding 'ascii'
    }
}
#EndRegion './Private/New-WikiSidebarCustom.ps1' 102
#Region './Public/Copy-WikiContent.ps1' -1

function Copy-WikiContent
{
    <#
    .SYNOPSIS
        Copies all files from a source directory (recursively) into a destination directory, flattening the structure.

    .DESCRIPTION
        The Copy-WikiContent function copies all files from the specified source directory and its subdirectories
        into the specified destination directory. All files are placed directly in the destination directory,
        and any existing files with the same name will be overwritten.

    .PARAMETER SourcePath
        The path to the source directory containing files to copy.

    .PARAMETER DestinationPath
        The path to the destination directory where files will be copied.

    .EXAMPLE
        Copy-WikiContent -SourcePath "C:\Docs\Wiki" -DestinationPath "C:\Build\WikiFlat"

    .NOTES
        If multiple files with the same name exist in different subdirectories, only the last one copied will remain.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$SourcePath,

        [Parameter(Mandatory = $true)]
        [string]$DestinationPath
    )

    if (-not (Test-Path -Path $DestinationPath))
    {
        New-Item -ItemType Directory -Path $DestinationPath | Out-Null
    }

    # Get all files recursively and copy them flat into the destination directory
    Get-ChildItem -Path $SourcePath -File -Recurse | ForEach-Object {
        $destFile = Join-Path $DestinationPath $_.Name
        Copy-Item -Path $_.FullName -Destination $destFile -Force
    }
}
#EndRegion './Public/Copy-WikiContent.ps1' 44
#Region './Public/New-WikiSidebarFromPs1.ps1' -1

function New-WikiSidebarFromPs1
{
    <#
    .SYNOPSIS
        Generates a wiki sidebar from PowerShell script files.

    .DESCRIPTION
        Creates a Markdown sidebar file that indexes all PowerShell scripts in a directory tree,
        organizing them hierarchically with Home and Commands sections.

    .PARAMETER SourcePathPs1
        The root path containing the PowerShell script files to index.

    .PARAMETER WikiSourcePath
        The output directory where the generated sidebar file will be created.

    .PARAMETER SidebarFile
        The name of the sidebar file to create. Defaults to '_Sidebar.md'.

    .EXAMPLE
        New-WikiSidebarFromPs1 -SourcePathPs1 "C:\Scripts\Public" -WikiSourcePath "C:\Wiki"

    .NOTES
        The function recursively processes all subdirectories and generates a tree-like structure
        in the sidebar file.
    #>

    param(
        [Parameter(Mandatory)]
        [string]$SourcePathPs1,
        [Parameter(Mandatory)]
        [string]$WikiSourcePath,
        [string]$SidebarFile = "_Sidebar.md"
    )

    function Build-Sidebar
    {
        <#
        .SYNOPSIS
            Recursively builds the sidebar content tree structure.

        .DESCRIPTION
            Processes a directory and its subdirectories, creating markdown list entries
            for all PowerShell files and nested directories with proper indentation levels.

        .PARAMETER CurrentPath
            The current directory path to process.

        .PARAMETER Depth
            The current recursion depth for proper indentation. Defaults to 0.

        .EXAMPLE
            Build-Sidebar -CurrentPath "C:\Scripts" -Depth 0
        #>

        param(
            [string]$CurrentPath,
            [int]$Depth = 0
        )
        $indent = ' ' * $Depth
        $sidebar = ""

        # First, the .ps1 files in the current directory
        $files = Get-ChildItem -Path $CurrentPath -Filter *.ps1 -File | Where-Object { $_.Name -notlike '*.local.*' } | Sort-Object Name
        foreach ($file in $files)
        {
            $relPath = $($file.BaseName)
            if ($CurrentPath -ne $SourcePath)
            {
                $relDir = $file.DirectoryName.Substring($SourcePath.Length).TrimStart('\', '/')
                $relPath = "$relDir/$($file.BaseName)" -replace '\\', '/'
            }
            $sidebar += "$indent- [$($file.BaseName)]($($file.BaseName))`n"
        }

        # Then the subdirectories
        $dirs = Get-ChildItem -Path $CurrentPath -Directory | Sort-Object Name
        foreach ($dir in $dirs)
        {
            $sidebar += "$indent- $($dir.Name)`n"
            $sidebar += Build-Sidebar -CurrentPath $dir.FullName -Depth ($Depth + 1)
        }
        return $sidebar
    }

    $sidebar = "[Home](HOME.md)`n`n"
    $sidebar += "### Commands`n`n"
    $sidebar += Build-Sidebar -CurrentPath $SourcePathPs1

    $sidebarFilePath = Join-Path $WikiSourcePath $SidebarFile
    Set-Content -Path $sidebarFilePath -Value $sidebar
}
#EndRegion './Public/New-WikiSidebarFromPs1.ps1' 91
#Region './Public/Update-ChangelogDirect.ps1' -1

function Update-ChangelogDirect
{
    <#
    .SYNOPSIS
        Updates the CHANGELOG.md with the released version and pushes directly to main.

    .DESCRIPTION
        Replaces the [Unreleased] section header in CHANGELOG.md with the current
        release version using the ChangelogManagement module, then commits and pushes
        the change directly to the current branch without opening a pull request.

        Pre-releases are skipped unless UpdateChangelogOnPrerelease is set to $true
        in the GitHubConfig section of build.yaml.

    .PARAMETER ModuleVersion
        The semantic version of the module being released (e.g. '1.2.3').

    .PARAMETER ChangelogPath
        Absolute path to CHANGELOG.md.

    .PARAMETER GitHubToken
        Personal access token used to authenticate the git push.

    .PARAMETER GitUserName
        Git user.name to use for the commit.

    .PARAMETER GitUserEmail
        Git user.email to use for the commit.

    .PARAMETER UpdateChangelogOnPrerelease
        When $false (default), the function exits early if ModuleVersion contains a
        pre-release tag (e.g. '1.2.3-preview1').
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [System.String]
        $ModuleVersion,

        [Parameter(Mandatory)]
        [System.String]
        $ChangelogPath,

        [Parameter()]
        [System.String]
        $GitHubToken = '',

        [Parameter()]
        [System.String]
        $GitUserName = '',

        [Parameter()]
        [System.String]
        $GitUserEmail = '',

        [Parameter()]
        [System.Boolean]
        $UpdateChangelogOnPrerelease = $false
    )

    if (-not $UpdateChangelogOnPrerelease -and $ModuleVersion -match '-')
    {
        Write-Host -Object "Skipping CHANGELOG update for pre-release version '$ModuleVersion' (UpdateChangelogOnPrerelease is false)." -ForegroundColor Yellow
        return
    }

    Write-Host -Object "Updating '$ChangelogPath' for release v$ModuleVersion" -ForegroundColor DarkGray

    Import-Module ChangelogManagement -ErrorAction Stop

    Update-Changelog -ReleaseVersion $ModuleVersion -LinkMode None -Path $ChangelogPath

    git config user.name $GitUserName
    git config user.email $GitUserEmail

    git add $ChangelogPath
    git commit -m "Updating ChangeLog since v$ModuleVersion +semver:skip"

    if ($GitHubToken)
    {
        $remoteUrl = (git remote get-url origin 2>$null).Trim()

        if ($remoteUrl -match 'github\.com[:/](?<owner>[^/]+)/(?<repo>[^/]+?)(?:\.git)?$')
        {
            $tokenUrl = "https://x-access-token`:$GitHubToken@github.com/$($Matches['owner'])/$($Matches['repo']).git"
            git remote set-url origin $tokenUrl
        }
    }

    git push origin HEAD
    if ($LASTEXITCODE -ne 0)
    {
        throw "git push failed with exit code $LASTEXITCODE"
    }
    Write-Host -Object "CHANGELOG.md updated and pushed directly to main for v$ModuleVersion" -ForegroundColor Green
}
#EndRegion './Public/Update-ChangelogDirect.ps1' 98