RVR.AZPipelineTools.psm1

# To be deprecated
# You should not use this function anymore. My advise is to generate the manifest manually and update the version
# dynamically using: Update-ModuleManifest -ModuleVersion $(GitVersion.MajorMinorPatch).
# This allows the pipeline yml file to be more standardised.

function New-RVRModuleManifest {
    <#
       .SYNOPSIS
       This function creates a new PowerShell module manifest.
     
       .DESCRIPTION
       This function creates a new PowerShell module manifest.
 
       It's merely a wrapper around new-ModuleManifest with some parameters preset.
     
       .PARAMETER ModuleName
       The name of the module.
 
       .PARAMETER ModuleVersion
       The module version.
 
       .PARAMETER Description
       The description of the module.
 
       .PARAMETER Author
       The author of the module
 
       .PARAMETER ReleaseNotes
       The releaseNotes
 
       .PARAMETER FunctionsToExport
       The functions that this module will export. Please do not use wildcards.
 
       .PARAMETER DscResourcesToExport
       The DSC Resources that this module will export. Please do not use wildcards.
     
       .EXAMPLE
       The example below will create a new manifest for this module.
 
       PS> New-RVRModuleManifest -Verbose -ModuleName $modulename -ModuleVersion '0.0.1' -Description 'Sample Description' -FunctionsToExport 'New-RVRModuleManifest', 'New-RVRModulePesterTestScript'
     
    #>


    [CmdletBinding(SupportsShouldProcess)]
    
    param(
        [parameter(Mandatory)]
        [string]$ModuleName,
        
        [parameter(Mandatory)]
        $ModuleVersion,
        
        [parameter(Mandatory)]
        [string]$Description,

        $Author = "Robert van Reems",

        $ReleaseNotes = "Some things changed",

        $FunctionsToExport, 

        $DscResourcesToExport
    )

    Begin{
        # Display some troubleshoot info
        Write-Verbose "My Invocation info:
         
        MyCommand: $($MyInvocation.MyCommand)
        ScriptName: $($MyInvocation.ScriptName)
        PSScriptRoot: $($MyInvocation.PSScriptRoot)
        PSCommandPath: $($MyInvocation.PSCommandPath)
        InvocationName: $($MyInvocation.InvocationName)
        "

        Write-Warning 'This module is to be depricated.'

        # Some vars
        $ModulePath = ".\$ModuleName"

        # Apend disclaimer to the description
        $Description += "
 
        **********************************************************************************************************************
        DISCLAIMER
 
        THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
        KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
        PARTICULAR PURPOSE
        ************************************************************************************************************************* "

    }

    Process{
        #Generate the module manifest
        Write-Verbose 'Generating the module manifest'


        If ($PSCmdlet.ShouldProcess("$ModuleName")) { 
            New-ModuleManifest -Path ($ModulePath + "\" + "$ModuleName" + ".psd1") -ModuleVersion $ModuleVersion `
                -PowerShellVersion 5.0 `
                -Description $Description `
                -Author $author `
                -ReleaseNotes $releaseNotes `
                -RootModule "$($ModuleName + '.psm1')" `
                -DscResourcesToExport '' `
                -FunctionsToExport $FunctionsToExport `
                -CmdletsToExport "" `
                -AliasesToExport ""
        }
    }

    End{
        Write-Verbose "$($MyInvocation.MyCommand) ends normally"
    }
}

function New-RVRModulePesterTestScript{
    <#
       .SYNOPSIS
       Installs severall Pester test scripts to your Azure build pipeline.
     
       .DESCRIPTION
       This function contains some precanned Pester test scripts that you might use in Azure build pipeline.
       At the moment of writing it contains:
       - PS Script analyzer tests
       - Module validation tests
 
       I Expect to add more tests in time.
 
       The function copies the tests to folder .\PesterTestScripts. You may use this folder for your own custom tests
      
       .EXAMPLE
       Just run the command
 
       PS> New-RVRModulePesterTestScript
    #>

    
    [CmdletBinding(SupportsShouldProcess)]
    
    param(
        
    )

    Begin{
        # Display some troubleshoot info
        Write-Verbose "My Invocation info:
         
        MyCommand: $($MyInvocation.MyCommand)
        ScriptName: $($MyInvocation.ScriptName)
        PSScriptRoot: $($MyInvocation.PSScriptRoot)
        PSCommandPath: $($MyInvocation.PSCommandPath)
        InvocationName: $($MyInvocation.InvocationName)
        "


        #Some vars
        $PesterTestScriptFolderPath = ".\PesterTestScripts"
        $PesterTestScriptSourcesFolderPath = "$PSScriptRoot\PesterTestScriptSources\"

        try{
            # Create the PesterTestScriptFolder if it doesn't allready exists
            if(-not (Test-Path $PesterTestScriptFolderPath) ){
                Write-Verbose "Creating folder $PesterTestScriptFolderPath"

                If ($PSCmdlet.ShouldProcess("Create new folder $PesterTestScriptFolderPath")) { 
                    New-Item -Path $PesterTestScriptFolderPath -ItemType Directory | Out-Null
                }
            }
        }
        catch{
            throw "Unexpected fatal error: $_"
            exit
        }
    }

    Process{
        Write-Verbose 'Coping Pester Test scripts'

        try{
            Write-Verbose "Copying contents of $PesterTestScriptSourcesFolderPath to $PesterTestScriptFolderPath"
            If ($PSCmdlet.ShouldProcess("Copying contents of $PesterTestScriptSourcesFolderPath to $PesterTestScriptFolderPath")) { 
                Copy-Item -Path "$PesterTestScriptSourcesFolderPath\*.ps1" -Destination $PesterTestScriptFolderPath 
            }
        }
        catch{
            throw "Failed to Copy items from $PesterTestScriptSourcesFolderPath to $PesterTestScriptFolderPath. With error: $_"
            exit
        }
    }

    End{
        Write-Verbose "$($MyInvocation.MyCommand) ends normally"
    }
}

function New-RVRNugetSpec {

    <#
       .SYNOPSIS
       This function creates a new nuget Specfile.
     
       .DESCRIPTION
       This function creates a new nuget Specfile. This is used to package this module to a .nuget package.
     
       .PARAMETER ModuleName
       The name of the module.
 
       .PARAMETER ModuleVersion
       The module version.
 
       .PARAMETER Description
       The description of the module.
 
       .PARAMETER Author
       The author of the module
 
       .PARAMETER ReleaseNotes
       The releaseNotes
     
       .EXAMPLE
       The example below will create a new nuget specfile for this module.
 
       PS> New-RVRNugetSpec -ModuleName $ModuleName -ModuleVersion 0.0.1 -Description 'sample text' -Author 'Robert van Reems' -ReleaseNotes 'first release'
     
    #>


    [CmdletBinding(SupportsShouldProcess)]

    param(
        [parameter(Mandatory)]
        [string]$ModuleName,
        
        [parameter(Mandatory)]
        $ModuleVersion,
        
        [parameter(Mandatory)]
        [string]$Description,

        $Author = "Robert van Reems",

        $ReleaseNotes = "Some things changed"
    )

    If ($PSCmdlet.ShouldProcess("$ModuleName")) { 

        # remove old specfile
        if (Test-Path ( ".\" + $ModuleName + ".nuspec" ) ) {
            Remove-Item (".\" + $ModuleName + ".nuspec" )
        }

        $NugetSpecContent = "<?xml version=`"1.0`"?>
        <package >
        <metadata>
            <id>$ModuleName</id>
            <version>$ModuleVersion</version>
            <authors>$author</authors>
            <owners>$author</owners>
            <requireLicenseAcceptance>false</requireLicenseAcceptance>
            <description>$Description</description>
            <releaseNotes>$releaseNotes</releaseNotes>
            <copyright>Copyright 2019</copyright>
            <tags>Tag1 Tag2</tags>
            <dependencies>
            </dependencies>
        </metadata>
        </package>
        "


        # Create the nuspec file
        New-Item -Path (".\" + $ModuleName + ".nuspec" )

        Add-Content -Path (".\" + $ModuleName + ".nuspec" ) $NugetSpecContent
        #endregion
    }
}

function Get-MDSection {
    <#
       .SYNOPSIS
       Returns all sections from a MarkDown file.
     
       .DESCRIPTION
        Returns all sections from a MarkDown file. A section is the text between the headings.
 
        Take the text below as an example The text from '# Project Title' until '## Getting Started' is considered to be a single section.
 
            # Project Title
 
            This PowerShell module provide functionality for the Azure Build pipeline I'm using to build my PowerShell modules.
            It's my goal to create a build pipeline without any static variables in the Azure build pipeline .yaml file.
 
            The Azure build pipeline variables should be used as well as the information from the Markdown files (README.md) as
            information source to build the pipeline. For example the version, author and description.
 
            ## Getting Started
 
 
        The function takes multiple lines to return a section. You'll need to pipe at least severall lines to it.
 
       .PARAMETER line
       The line to analyse
     
       .EXAMPLE
        Pipe the output from Get-content of a README.md file to Get-MDSection
 
        PS > get-content .\README.md | Get-MDSection
 
        HeadingName Text
        ----------- ----
        Project Title This PowerShell module provide functionality for the Azure Build pipeline I'm using to build my PowerShell modules....
        Getting Started These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the pro..
        ...
 
    #>


    param(
        [parameter(ValueFromPipeline)] $line
    )

    Begin{
        $returnObj = $null


        class MDSection {
            [string]$HeadingName
            [string]$Text
        
            MDSection([string]$HeadingName){
        
                $this.HeadingName = $HeadingName.TrimStart('# ')
            }
        
            AddText([string]$Text){
        
                # Skip the first incomming text if it's an empty string
                if(($null -eq $this.Text) -and ("" -eq $Text) ){
                    # skip this line
                }
                else{
                    $this.Text += ($Text + "`n")
                }
            }
        }
    }

    Process{
        # Expect the first input line to be the Title
        if($line -match '^#'){
            
            # return previous object
            $returnObj

            # Create a new object to work on
            $returnObj = [MdSection]::new($line)
        }
        Else{
            # Add the text to the custom object
            # $returnObj.Text += ($line + "`n")
            $returnObj.AddText($line)
        }
    }

    end{
        # return the last object
        $returnObj
    }
}