From 9bbb930f74b040b07e337006c0f44fe3fe141698 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 2 Jan 2019 17:54:52 +0100 Subject: [PATCH] Fixed use of parameters Parameters like `-Raw` can be shorten with `-r` which is a valid parameter for a git command --- BuildHelpers/Public/Get-BuildVariable.ps1 | 16 +- BuildHelpers/Public/Get-BuildVariables.ps1 | 235 +++++++++++++++++++++ BuildHelpers/Public/Get-GitChangedFile.ps1 | 6 +- BuildHelpers/Public/Invoke-Git.ps1 | 159 ++++++-------- Tests/BuildHelpers.Tests.ps1 | 3 +- 5 files changed, 308 insertions(+), 111 deletions(-) create mode 100644 BuildHelpers/Public/Get-BuildVariables.ps1 diff --git a/BuildHelpers/Public/Get-BuildVariable.ps1 b/BuildHelpers/Public/Get-BuildVariable.ps1 index 08357c1..5917c6c 100644 --- a/BuildHelpers/Public/Get-BuildVariable.ps1 +++ b/BuildHelpers/Public/Get-BuildVariable.ps1 @@ -142,7 +142,7 @@ function Get-BuildVariable { { # Using older than 1.6.3 in your build system? Yuck # Thanks to earl: http://stackoverflow.com/a/1418022/3067642 - $BuildBranch = Invoke-Git @IGParams -Arguments "rev-parse --abbrev-ref HEAD" + $BuildBranch = (Invoke-Git @IGParams -Arguments "rev-parse --abbrev-ref HEAD").Output } } @@ -156,42 +156,42 @@ function Get-BuildVariable { 'CI_COMMIT_SHA' { if($WeCanGit) { - Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )" + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output break } # Gitlab 9.0+ - thanks to mipadi http://stackoverflow.com/a/3357357/3067642 } 'CI_BUILD_REF' { if($WeCanGit) { - Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )" + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output break } # Gitlab 8.x - thanks to mipadi http://stackoverflow.com/a/3357357/3067642 } 'GIT_COMMIT' { if($WeCanGit) { - Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )" + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output break } # Jenkins - thanks to mipadi http://stackoverflow.com/a/3357357/3067642 } 'BUILD_SOURCEVERSION' { if($WeCanGit) { - Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )" + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output break } # VSTS (https://www.visualstudio.com/en-us/docs/build/define/variables#) } 'BUILD_VCS_NUMBER' { if($WeCanGit) { - Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )" + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output break } # Teamcity https://confluence.jetbrains.com/display/TCD10/Predefined+Build+Parameters } 'BAMBOO_REPOSITORY_REVISION_NUMBER' { if($WeCanGit) { - Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )" + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output break } # Bamboo https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html } @@ -204,7 +204,7 @@ function Get-BuildVariable { { if($WeCanGit) { - $CommitMessage = Invoke-Git @IGParams -Arguments "log --format=%B -n 1" + $CommitMessage = (Invoke-Git @IGParams -Arguments "log --format=%B -n 1").Output } } diff --git a/BuildHelpers/Public/Get-BuildVariables.ps1 b/BuildHelpers/Public/Get-BuildVariables.ps1 new file mode 100644 index 0000000..07f3c12 --- /dev/null +++ b/BuildHelpers/Public/Get-BuildVariables.ps1 @@ -0,0 +1,235 @@ +function Get-BuildVariables { + <# + .SYNOPSIS + Normalize build system variables + + .FUNCTIONALITY + CI/CD + + .DESCRIPTION + Normalize build system variables + + Each build system exposes common variables it's own unique way, if at all. + This function was written to enable more portable builds, and + to avoid tightly coupling your build scripts with your build system + + Gathers from: + AppVeyor + GitLab CI + Jenkins + Teamcity + VTFS + Bamboo + GoCD + Travis CI + + For Teamcity the VCS Checkout Mode needs to be to checkout files on agent. + Since TeamCity 10.0, this is the default setting for the newly created build configurations. + + Git needs to be available on the agent for this. + + Produces: + BuildSystem: Build system we're running under + ProjectPath: Project root for cloned repo + BranchName: git branch for this build + CommitMessage: git commit message for this build + BuildNumber: Build number provided by the CI system + + .PARAMETER Path + Path to project root. Defaults to the current working path + + .PARAMETER GitPath + Path to git. Defaults to git (i.e. git is in $ENV:PATH) + + .NOTES + We assume you are in the project root, for several of the fallback options + + .EXAMPLE + Get-BuildVariables + + .LINK + https://github.com/RamblingCookieMonster/BuildHelpers + + .LINK + Get-ProjectName + + .LINK + Set-BuildEnvironment + + .LINK + about_BuildHelpers + #> + [cmdletbinding()] + param( + $Path = $PWD.Path, + [validatescript({ + if(-not (Get-Command $_ -ErrorAction SilentlyContinue)) + { + throw "Could not find command at GitPath [$_]" + } + $true + })] + $GitPath = 'git' + ) + + $Path = ( Resolve-Path $Path ).Path + $Environment = Get-Item ENV: + if(!$PSboundParameters.ContainsKey('GitPath')) { + $GitPath = (Get-Command $GitPath -ErrorAction SilentlyContinue)[0].Path + } + + $WeCanGit = ( (Test-Path $( Join-Path $Path .git )) -and (Get-Command $GitPath -ErrorAction SilentlyContinue) ) + if($WeCanGit) + { + $IGParams = @{ + Path = $Path + GitPath = $GitPath + } + } + $tcProperties = Get-TeamCityProperties # Teamcity has limited ENV: values but dumps the build configuration in a properties file. + + # Determine the build system: + $BuildSystem = switch ($Environment.Name) + { + 'APPVEYOR_BUILD_FOLDER' { 'AppVeyor'; break } + 'GITLAB_CI' { 'GitLab CI' ; break } + 'JENKINS_URL' { 'Jenkins'; break } + 'BUILD_DEFINITIONNAME' { 'VSTS'; break } + 'TEAMCITY_VERSION' { 'Teamcity'; break } + 'BAMBOO_BUILDKEY' { 'Bamboo'; break } + 'GOCD_SERVER_URL' { 'GoCD'; break } + 'TRAVIS' { 'Travis CI'; break } + } + if(-not $BuildSystem) + { + $BuildSystem = 'Unknown' + } + + # Find the build folder based on build system + $BuildRoot = switch ($Environment.Name) + { + 'APPVEYOR_BUILD_FOLDER' { (Get-Item -Path "ENV:$_").Value; break } # AppVeyor + 'CI_PROJECT_DIR' { (Get-Item -Path "ENV:$_").Value; break } # GitLab CI + 'WORKSPACE' { (Get-Item -Path "ENV:$_").Value; break } # Jenkins Jenkins... seems generic. + 'SYSTEM_DEFAULTWORKINGDIRECTORY' { (Get-Item -Path "ENV:$_").Value; break } # VSTS (Visual studio team services) + 'BAMBOO_BUILD_WORKING_DIRECTORY' { (Get-Item -Path "ENV:$_").Value; break } # Bamboo + 'TRAVIS_BUILD_DIR' { (Get-Item -Path "ENV:$_").Value; break } # Travis CI + } + if(-not $BuildRoot) + { + if ($BuildSystem -eq 'Teamcity') { + $BuildRoot = $tcProperties['teamcity.build.checkoutDir'] + } else { + # Assumption: this function is defined in a file at the root of the build folder + $BuildRoot = $Path + } + } + + # Find the git branch + $BuildBranch = switch ($Environment.Name) + { + 'APPVEYOR_REPO_BRANCH' { (Get-Item -Path "ENV:$_").Value; break } # AppVeyor + 'CI_COMMIT_REF_NAME' { (Get-Item -Path "ENV:$_").Value; break } # GitLab CI 9.0+ + 'CI_BUILD_REF_NAME' { (Get-Item -Path "ENV:$_").Value; break } # GitLab CI 8.x + 'GIT_BRANCH' { (Get-Item -Path "ENV:$_").Value; break } # Jenkins + 'BUILD_SOURCEBRANCHNAME' { (Get-Item -Path "ENV:$_").Value; break } # VSTS + 'BAMBOO_REPOSITORY_GIT_BRANCH' { (Get-Item -Path "ENV:$_").Value; break } # Bamboo + 'TRAVIS_BRANCH' { (Get-Item -Path "ENV:$_").Value; break } # Travis CI + } + if(-not $BuildBranch) + { + if($WeCanGit) + { + # Using older than 1.6.3 in your build system? Yuck + # Thanks to earl: http://stackoverflow.com/a/1418022/3067642 + $BuildBranch = (Invoke-Git @IGParams -Arguments "rev-parse --abbrev-ref HEAD").Output + } + } + + # Find the git commit message + $CommitMessage = switch ($Environment.Name) + { + 'APPVEYOR_REPO_COMMIT_MESSAGE' { + "$env:APPVEYOR_REPO_COMMIT_MESSAGE $env:APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED".TrimEnd() + break + } + 'CI_COMMIT_SHA' { + if($WeCanGit) + { + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output + break + } # Gitlab 9.0+ - thanks to mipadi http://stackoverflow.com/a/3357357/3067642 + } + 'CI_BUILD_REF' { + if($WeCanGit) + { + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output + break + } # Gitlab 8.x - thanks to mipadi http://stackoverflow.com/a/3357357/3067642 + } + 'GIT_COMMIT' { + if($WeCanGit) + { + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output + break + } # Jenkins - thanks to mipadi http://stackoverflow.com/a/3357357/3067642 + } + 'SYSTEM_TEAMPROJECT' { + if($WeCanGit) + { + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output + break + } # VSTS (https://www.visualstudio.com/en-us/docs/build/define/variables#) + } + 'BUILD_VCS_NUMBER' { + if($WeCanGit) + { + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output + break + } # Teamcity https://confluence.jetbrains.com/display/TCD10/Predefined+Build+Parameters + } + 'BAMBOO_REPOSITORY_REVISION_NUMBER' { + if($WeCanGit) + { + (Invoke-Git @IGParams -Arguments "log --format=%B -n 1 $( (Get-Item -Path "ENV:$_").Value )").Output + break + } # Bamboo https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html + } + 'TRAVIS_COMMIT_MESSAGE' { + "$env:TRAVIS_COMMIT_MESSAGE" + break + } + } + if(-not $CommitMessage) + { + if($WeCanGit) + { + $CommitMessage = (Invoke-Git @IGParams -Arguments "log --format=%B -n 1").Output + } + } + + # Build number + $BuildNumber = switch ($Environment.Name) + { + 'APPVEYOR_BUILD_NUMBER' { (Get-Item -Path "ENV:$_").Value; break } # AppVeyor + 'CI_JOB_ID' { (Get-Item -Path "ENV:$_").Value; break } # GitLab CI 9.0+ - not perfect https://gitlab.com/gitlab-org/gitlab-ce/issues/3691 + 'CI_BUILD_ID' { (Get-Item -Path "ENV:$_").Value; break } # GitLab CI 8.x - not perfect https://gitlab.com/gitlab-org/gitlab-ce/issues/3691 + 'BUILD_NUMBER' { (Get-Item -Path "ENV:$_").Value; break } # Jenkins, Teamcity ... seems generic. + 'BUILD_BUILDNUMBER' { (Get-Item -Path "ENV:$_").Value; break } # VSTS + 'BAMBOO_BUILDNUMBER' { (Get-Item -Path "ENV:$_").Value; break } # Bamboo + 'GOCD_PIPELINE_COUNTER' { (Get-Item -Path "ENV:$_").Value; break } # GoCD + 'TRAVIS_BUILD_NUMBER' { (Get-Item -Path "ENV:$_").Value; break } # Travis CI + } + if(-not $BuildNumber) + { + $BuildNumber = 0 + } + + [pscustomobject]@{ + BuildSystem = $BuildSystem + ProjectPath = $BuildRoot + BranchName = $BuildBranch + CommitMessage = $CommitMessage + BuildNumber = $BuildNumber + } +} diff --git a/BuildHelpers/Public/Get-GitChangedFile.ps1 b/BuildHelpers/Public/Get-GitChangedFile.ps1 index 49f852c..382bdb4 100644 --- a/BuildHelpers/Public/Get-GitChangedFile.ps1 +++ b/BuildHelpers/Public/Get-GitChangedFile.ps1 @@ -62,7 +62,7 @@ function Get-GitChangedFile { [switch]$Resolve ) $Path = (Resolve-Path $Path).Path - $GitPathRaw = Invoke-Git rev-parse --show-toplevel -Path $Path + $GitPathRaw = (Invoke-Git rev-parse --show-toplevel -Path $Path).Output Write-Verbose "Found git root [$GitPathRaw]" $GitPath = Resolve-Path $GitPathRaw if(Test-Path $GitPath) @@ -76,14 +76,14 @@ function Get-GitChangedFile { if(-not $PSBoundParameters.ContainsKey('Commit')) { - $Commit = Invoke-Git rev-parse HEAD -Path $GitPath + $Commit = (Invoke-Git rev-parse HEAD -Path $GitPath).Output } if(-not $Commit) { return } - [string[]]$Files = Invoke-Git "diff-tree --no-commit-id --name-only -r $Commit" -Path $GitPath + [string[]]$Files = (Invoke-Git diff-tree --no-commit-id --name-only -r $Commit -Path $GitPath).Output if($Files.Count -gt 0) { $Params = @{Collection = $Files} diff --git a/BuildHelpers/Public/Invoke-Git.ps1 b/BuildHelpers/Public/Invoke-Git.ps1 index 3cd55f2..6248ce3 100644 --- a/BuildHelpers/Public/Invoke-Git.ps1 +++ b/BuildHelpers/Public/Invoke-Git.ps1 @@ -1,119 +1,80 @@ Function Invoke-Git { <# - .SYNOPSIS - Wrapper to invoke git and return streams + .SYNOPSIS + Wrapper to invoke git and return streams - .FUNCTIONALITY - CI/CD + .FUNCTIONALITY + CI/CD - .DESCRIPTION - Wrapper to invoke git and return streams + .DESCRIPTION + Wrapper to invoke git and return streams - .PARAMETER Arguments - If specified, call git with these arguments. + .PARAMETER Arguments + If specified, call git with these arguments. - This takes a positional argument and accepts all value afterwards for a more natural 'git-esque' use. + This takes a positional argument and accepts all value afterwards for a more natural 'git-esque' use. - .PARAMETER Path - Working directory to launch git within. Defaults to current location + .PARAMETER Path + Working directory to launch git within. Defaults to current location - .PARAMETER RedirectStandardError - Whether to capture standard error. Defaults to $true + .PARAMETER GitPath + Path to git. Defaults to git (i.e. git is in $ENV:PATH) - .PARAMETER RedirectStandardOutput - Whether to capture standard output. Defaults to $true + .EXAMPLE + Invoke-Git rev-parse HEAD - .PARAMETER UseShellExecute - See System.Diagnostics.ProcessStartInfo. Defaults to $false + # Get the current commit hash for HEAD - .PARAMETER Raw - If specified, return an object with the command, output, and error properties. + .EXAMPLE + Invoke-Git rev-parse HEAD -path C:\sc\PSStackExchange - Without Raw or Quiet, we return output if there's output, and we write an error if there are errors + # Get the current commit hash for HEAD for the repo located at C:\sc\PSStackExchange - .PARAMETER Split - If specified, split output and error on this. Defaults to `n + .LINK + https://github.com/RamblingCookieMonster/BuildHelpers - .PARAMETER Quiet - If specified, do not return output + .LINK + about_BuildHelpers + #> + [cmdletbinding()] + param( + [parameter(Position = 0, + ValueFromRemainingArguments = $true)] + $Arguments, - .PARAMETER GitPath - Path to git. Defaults to git (i.e. git is in $ENV:PATH) + $Path = $PWD.Path, - .EXAMPLE - Invoke-Git rev-parse HEAD - - # Get the current commit hash for HEAD - - .EXAMPLE - Invoke-Git rev-parse HEAD -path C:\sc\PSStackExchange - - # Get the current commit hash for HEAD for the repo located at C:\sc\PSStackExchange - - .LINK - https://github.com/RamblingCookieMonster/BuildHelpers - - .LINK - about_BuildHelpers - #> - [cmdletbinding()] - param( - [parameter(Position = 0, - ValueFromRemainingArguments = $true)] - $Arguments, - - $Path = $PWD.Path, - - [switch]$Quiet, - - [switch]$Raw, - - [validatescript({ - if(-not (Get-Command $_ -ErrorAction SilentlyContinue)) - { - throw "Could not find command at GitPath [$_]" - } - $true - })] - [string]$GitPath = 'git' - ) - - $Path = (Resolve-Path $Path).Path - if(!$PSBoundParameters.ContainsKey('GitPath')) { - $GitPath = (Get-Command $GitPath -ErrorAction Stop)[0].Path - } - - $result = & $GitPath $Arguments 2>&1 - - if(-not $Quiet) { - $output = [pscustomobject]@{ - Command = "$GitPath $Arguments" - Output = "" - Error = "" - } - if ($result.writeErrorStream) - { - $output.Error = $result.Exception.Message -join "`n" - } - else + [validatescript({ + if(-not (Get-Command $_ -ErrorAction SilentlyContinue)) { - $output.Output = $result -join "`n" + throw "Could not find command at GitPath [$_]" } + $true + })] + [string]$GitPath = 'git' + ) + + $Path = (Resolve-Path $Path).Path + if(!$PSBoundParameters.ContainsKey('GitPath')) { + $GitPath = (Get-Command $GitPath -ErrorAction Stop)[0].Path + } - if($Raw) - { - $output - } - else - { - if ($result.writeErrorStream) - { - $output.Error - } - else - { - $output.Output - } - } - } + Push-Location $Path + $result = & $GitPath $Arguments 2>&1 + Pop-Location + + $output = [pscustomobject]@{ + Command = "$GitPath $Arguments" + Output = "" + Error = "" + } + if ($result.writeErrorStream) + { + $output.Error = $result.Exception.Message + } + else + { + $output.Output = $result } + $output +} diff --git a/Tests/BuildHelpers.Tests.ps1 b/Tests/BuildHelpers.Tests.ps1 index 4138b37..c6b499a 100644 --- a/Tests/BuildHelpers.Tests.ps1 +++ b/Tests/BuildHelpers.Tests.ps1 @@ -259,6 +259,7 @@ Describe 'Get-GitChangedFile' { It 'Should find files changed in a specified commit in this repo' { $Output = Get-GitChangedFile -Commit 01b3931e6ed5d3d16cbcae25fcf98d185c1375b7 -ErrorAction SilentlyContinue -Include README* + Write-Host ($Output | Out-String) @($Output).count | Should Be 1 @($Output)[0] | Should BeLike "*BuildHelpers\README.md" } @@ -274,7 +275,7 @@ Describe 'Get-GitChangedFile' { Describe 'Invoke-Git' { Context 'This repository' { It 'Should find the root of the BuildHelpers repo' { - Invoke-Git rev-parse --show-toplevel -Path $PSScriptRoot | Should BeLike "*BuildHelpers" + (Invoke-Git rev-parse --show-toplevel -Path $PSScriptRoot).Output | Should BeLike "*BuildHelpers" } }