PwSh.Fw.BuildHelpers.psm1
$Script:PWSHFW_BUILDHELPERS_DIR = $PSScriptRoot <# .SYNOPSIS Create a new project.yml file .DESCRIPTION Create an empty project.yml file at the location of your choice. Preferably in the root of your new project workspace. .PARAMETER Path Existing path to write project.yml file .PARAMETER PassThru If specified, return the content of the project object instead of the absolute location of the file .EXAMPLE $project = New-ProjectFile -PassThru .NOTES General notes #> function New-ProjectFile { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')][OutputType([String], [boolean])]Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path, [switch]$PassThru ) Begin { # Write-EnterFunction } Process { $Project = [PSCustomObject]@{ Name = "name" Version = "1.0.0" Authors = @("you") Owner = "you" LicenseURL = "https//path/to/your/licence/file" Description = "short description of your project" ReleaseNotes = "" Copyright = "" Depends = @() } If (Test-Path $Path) { if ($PSCmdlet.ShouldProcess("ShouldProcess?")) { $Project | ConvertTo-Yaml | Set-Content $Path/project.yml -Encoding utf8 } } else { Write-Error "'$Path' not found." return $false } if ($PassThru) { return $Project } else { return (Resolve-Path "$Path/project.yml").Path } } End { # Write-LeaveFunction } } <# .SYNOPSIS Test if a project is compliant with BuildHelpers modules .DESCRIPTION Check the completeness of a project to be used with BuildHelpers modules. .PARAMETER Path The root path of the project to test .EXAMPLE Test-ProjectStructure -Path c:\projects\myNewProject .NOTES General notes #> function Test-ProjectStructure { [CmdletBinding()][OutputType([boolean])]Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path ) Begin { # Write-EnterFunction } Process { $rc = $true if (Test-Path $Path -PathType Container) { Write-Host -ForegroundColor Green "[+] $Path exist" } else { Write-Host -ForegroundColor Red "[-] $Path does not exist" $rc = $false } foreach ($f in @('project.yml', 'CHANGELOG.md', 'README.md', 'LICENSE', 'VERSION')) { if (Test-Path $Path/$f -PathType Leaf) { Write-Host -ForegroundColor Green "[+] $((Resolve-Path $Path/$f).Path) exist" } else { Write-Host -ForegroundColor Red "[-] $((Resolve-Path $Path/$f).Path) does not exist" $rc = $false } } return $rc } End { # Write-LeaveFunction } } <# .SYNOPSIS Get changelog in a object form .DESCRIPTION Slice CHANGELOG file and build a hashtable with each version of a changelog. .PARAMETER Path Path to the CHANGELOG file .EXAMPLE Get-ProjectChangelog -Path ./CHANGELOG.md .NOTES Each new version must follow the https://keepachangelog.com/ format. That is : ## [1.0.0] If this pattern is not applied, please ask for a request, or fix your changelog format #> function Get-ProjectChangelog { [CmdletBinding()][OutputType([hashtable])]Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path ) Begin { Write-EnterFunction $TMP = [system.io.path]::GetTempPath() } Process { $h = @{} if (fileExist $Path) { # CHANGELOG is present $CHANGELOG = Resolve-Path $Path # parse CHANGELOG.md # below command line explained : # Get-Content $CHANGELOG | Select-String -NotMatch -Pattern '(?ms)^$' --> get CHANGELOG content without empty lines # -replace "^## ", "`n## " --> add empty lines only before h2 title level (## in markdown). This way, we got proper paragraph from ## tag to next empty line (Get-Content $CHANGELOG | Select-String -NotMatch -Pattern '(?ms)^$') -replace "^## ", "`n## " | Out-File $TMP/changelog.tmp # To extract correct §, we need to read the file with -Raw parameter # (?ms) sets regex options m (treats ^ and $ as line anchors) and s (makes . match \n (newlines) too`. # ^## .*? matches any line starting with ## and any subsequent characters *non-greedily* (non-greedy is '.*?' set of characters at the end of pattern). # -AllMatches to get... well... all mathes # [1] because the last changelog is allways [1] from array of matches. [0] is ## [Unreleased] $MESSAGES = Get-Content -Raw $TMP/changelog.tmp | Select-String -Pattern '(?ms)^## .*?^$' -AllMatches # edevel("MESSAGES = " + $MESSAGES.Matches[0]) # reduce title level to render more readable in github release page # $MESSAGE = ($MESSAGES.Matches[0]) -replace "# ", "## " -replace "'", "``" -replace "unreleased", "$VERSION" # Write-Debug "MESSAGE = $MESSAGE" foreach ($msg in $MESSAGES.Matches) { if ($msg.value -match "^## \[(.*)\]") { $version = $Matches[1] $h.Add($version, $msg.Value) } } } else { eerror "Changelog file at '$Path' not found. See https://keepachangelog.com/en/1.0.0/ to begin." return $null } return $h } End { Write-LeaveFunction } } <# .SYNOPSIS Load project data into an object .DESCRIPTION Load static and dynamic data from project.yml but also from VERSION and CHANGELOG files .PARAMETER Path Path to the project .EXAMPLE Get-Project -Path /my/awsome/project .NOTES General notes #> function Get-Project { [CmdletBinding()][OutputType([Object])]Param ( [Parameter(Mandatory = $false, ValueFromPipeLine = $true)][string]$Path = (Get-Location) ) Begin { Write-EnterFunction } Process { if ((Test-ProjectStructure -Path $Path) -eq $false) { return $null } # compute BUILD number and BRANCH name $BUILD = 0 $BRANCH = "develop" # APPVEYOR: honor appveyor build number if ($null -ne $env:APPVEYOR_BUILD_NUMBER) { $BUILD = $env:APPVEYOR_BUILD_NUMBER} if ($null -ne $env:APPVEYOR_REPO_BRANCH) { $BRANCH = $env:APPVEYOR_REPO_BRANCH} # TRAVIS: honor travis-ci build number if ($null -ne $env:TRAVIS_BUILD_NUMBER) { $BUILD = $env:TRAVIS_BUILD_NUMBER} if ($null -ne $env:TRAVIS_BRANCH) { $BRANCH = $env:TRAVIS_BRANCH} # GITLAB: honor gitlab-ci pipeline project's build number if ($null -ne $env:CI_PIPELINE_IID) { $BUILD = $env:CI_PIPELINE_IID} if ($null -ne $env:CI_COMMIT_BRANCH) { $BRANCH = $env:CI_COMMIT_BRANCH } # get project from project.yml $project = Get-Content $Path/project.yml -Raw | ConvertFrom-Yaml $project.Root = (Resolve-Path $Path).Path # compute Version : # master branch is x.y.z.# # other branches are x.y.z-pre# if ($BRANCH -eq "master") { $project.version = "$(Get-Content $Path/VERSION).$($BUILD)" $project.PreRelease = "" } else { $project.Version = (Get-Content $Path/VERSION) if ($BUILD -lt 10) { $project.PreRelease = "-pre0$($BUILD)" } else { $project.PreRelease = "-pre$($BUILD)" } } # fill releasenotes with changelog $changelog = Get-ProjectChangelog -Path $Path/CHANGELOG.md if ($changelog.ContainsKey($project.version)) { $project.releasenotes = $changelog[$project.version] } elseif ($changelog.ContainsKey("unreleased")) { $project.releasenotes = $changelog["unreleased"] } return $project } End { Write-LeaveFunction } } |