Skip to content

Commit

Permalink
[Invoke-Git] Return Object & Change to Public Function (#80)
Browse files Browse the repository at this point in the history
- `Invoke-Git` 
  - Converted to public function.
  - Updated to use `System.Diagnostics.Process` for improved error handling.
  - Returns object, allowing caller to process result.
  • Loading branch information
phbits committed Jun 26, 2021
1 parent 27e84f3 commit c75f492
Show file tree
Hide file tree
Showing 8 changed files with 332 additions and 104 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Get-MofSchemaObject`
- Refactored to reduce code duplication when adding functions for supporting
composite resources.
- Converted `Invoke-Git` cmdlet to use `System.Diagnostics.Process` for improved error handling.
- `Get-ClassResourceCommentBasedHelp`
- Renamed this function to `Get-CommentBasedHelp` so that it made sense to
use with composite DSC resources.
- Enabled the function to extract the comment block if it is not at the top
of the script file to support composite resources.
- Updated code to pass newly added quality checks.
- `Invoke-Git`
- Converted to public function.
- Updated to use `System.Diagnostics.Process` for improved error handling.
- Returns object, allowing caller to process result.

### Fixed

Expand Down
29 changes: 12 additions & 17 deletions source/Private/Invoke-Git.ps1 → source/Public/Invoke-Git.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Invokes a git command.
.DESCRIPTION
Invokes a git command with command line arguments.
Invokes a git command with command line arguments using System.Diagnostics.Process.
.PARAMETER WorkingDirectory
The path to the git working directory.
Expand All @@ -20,7 +20,6 @@
Invokes the Git executable to clone the specified repository to the working directory.
.EXAMPLE
Invoke-Git -WorkingDirectory 'C:\SomeDirectory' -Arguments @( 'status' ) -TimeOut 10
Invokes the Git executable to return the status while having a 10 second timeout.
Expand All @@ -29,7 +28,7 @@
function Invoke-Git
{
[CmdletBinding()]
[OutputType([System.Int32])]
[OutputType([System.Collections.Hashtable])]
param
(
[Parameter(Mandatory = $true)]
Expand All @@ -45,6 +44,12 @@ function Invoke-Git
$Arguments
)

$returnValue = @{
'ExitCode' = -1
'StandardOutput' = ''
'StandardError' = ''
}

$argumentsJoined = $Arguments -join ' '

# Trying to remove any access token from the debug output.
Expand All @@ -71,18 +76,9 @@ function Invoke-Git
{
if ($process.WaitForExit($TimeOut) -eq $true)
{
<#
Assuming the error code 1 from git is warnings or informational like
"nothing to commit, working tree clean" and those are returned instead
of throwing an exception.
#>
if ($process.ExitCode -gt 1)
{
Write-Warning -Message ($localizedData.UnexpectedInvokeGitReturnCode -f $process.ExitCode)

Write-Debug -Message ($localizedData.InvokeGitStandardOutputReturn -f $process.StandardOutput.ReadToEnd())
Write-Debug -Message ($localizedData.InvokeGitStandardErrorReturn -f $process.StandardError.ReadToEnd())
}
$returnValue.ExitCode = $process.ExitCode
$returnValue.StandardOutput = $process.StandardOutput.ReadToEnd()
$returnValue.StandardError = $process.StandardError.ReadToEnd()
}
}
}
Expand All @@ -94,10 +90,9 @@ function Invoke-Git
{
if ($process)
{
$exitCode = $process.ExitCode
$process.Dispose()
}
}

return $exitCode
return $returnValue
}
86 changes: 51 additions & 35 deletions source/Public/Publish-WikiContent.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ function Publish-WikiContent
Write-Verbose -Message $script:localizedData.CreateTempDirMessage

$tempPath = New-TempFolder
$wikiRepoName = "https://github.com/$OwnerName/$RepositoryName.wiki.git"

try
{
Expand All @@ -112,60 +113,75 @@ function Publish-WikiContent
-Arguments @( 'config', '--global', 'core.autocrlf', $GlobalCoreAutoCrLf )
}

$wikiRepoName = "https://github.com/$OwnerName/$RepositoryName.wiki.git"

Write-Verbose -Message ($script:localizedData.CloneWikiGitRepoMessage -f $WikiRepoName)

$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'clone', $wikiRepoName, $tempPath, '--quiet' )
$gitCloneResult = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'clone', $wikiRepoName, $tempPath, '--quiet' )

$copyWikiFileParameters = @{
Path = $Path
DestinationPath = $tempPath
Force = $true
}
if ($gitCloneResult.ExitCode -eq 0)
{
$copyWikiFileParameters = @{
Path = $Path
DestinationPath = $tempPath
Force = $true
}

Copy-WikiFolder @copyWikiFileParameters
Copy-WikiFolder @copyWikiFileParameters

New-WikiSidebar -ModuleName $ModuleName -Path $tempPath
New-WikiFooter -Path $tempPath
New-WikiSidebar -ModuleName $ModuleName -Path $tempPath
New-WikiFooter -Path $tempPath

Write-Verbose -Message $script:localizedData.ConfigLocalGitMessage
Set-Location -Path $tempPath

$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'config', '--local', 'user.email', $GitUserEmail )
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'config', '--local', 'user.name', $GitUserName )
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'remote', 'set-url', 'origin', "https://$($GitUserName):$($GitHubAccessToken)@github.com/$OwnerName/$RepositoryName.wiki.git" )
Write-Verbose -Message $script:localizedData.ConfigLocalGitMessage

Write-Verbose -Message $localizedData.AddWikiContentToGitRepoMessage
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'config', '--local', 'user.email', $GitUserEmail )

$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'add', '*' )
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'config', '--local', 'user.name', $GitUserName )

Write-Verbose -Message ($localizedData.CommitAndTagRepoChangesMessage -f $ModuleVersion)
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'remote', 'set-url', 'origin', "https://$($GitUserName):$($GitHubAccessToken)@github.com/$OwnerName/$RepositoryName.wiki.git" )

$invokeGitResult = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'commit', '--message', "`"$($localizedData.UpdateWikiCommitMessage -f $ModuleVersion)`"", '--quiet' )
Write-Verbose -Message $localizedData.AddWikiContentToGitRepoMessage

if ($invokeGitResult -eq 0)
{
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'tag', '--annotate', $ModuleVersion, '--message', $ModuleVersion )
-Arguments @( 'add', '*' )

Write-Verbose -Message $localizedData.PushUpdatedRepoMessage
Write-Verbose -Message ($localizedData.CommitAndTagRepoChangesMessage -f $ModuleVersion)

$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'push', 'origin', '--quiet' )
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'push', 'origin', $ModuleVersion, '--quiet' )
$gitCommitResult = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'commit', '--message', "`"$($localizedData.UpdateWikiCommitMessage -f $ModuleVersion)`"", '--quiet' )

if ($gitCommitResult.ExitCode -eq 0)
{
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'tag', '--annotate', $ModuleVersion, '--message', $ModuleVersion )

Write-Verbose -Message $localizedData.PushUpdatedRepoMessage

Write-Verbose -Message $localizedData.PublishWikiContentCompleteMessage
$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'push', 'origin', '--quiet' )

$null = Invoke-Git -WorkingDirectory $tempPath.FullName `
-Arguments @( 'push', 'origin', $ModuleVersion, '--quiet' )

Write-Verbose -Message $localizedData.PublishWikiContentCompleteMessage
}
else
{
Write-Warning -Message $localizedData.NothingToCommitToWiki
}
}
else
{
Write-Warning -Message $localizedData.NothingToCommitToWiki
Write-Verbose -Message $script:localizedData.WikiGitCloneFailMessage

Write-Debug -Message ($script:localizedData.WikiGitCloneFailMessageDebug -f $wikiRepoName)
Write-Debug -Message ($script:localizedData.InvokeGitStandardOutput -f $gitCloneResult.StandardOutput)
Write-Debug -Message ($script:localizedData.InvokeGitStandardError -f $gitCloneResult.StandardError)
Write-Debug -Message ($script:localizedData.InvokeGitExitCodeMessage -f $gitCloneResult.ExitCode)
}
}
finally
Expand Down
8 changes: 5 additions & 3 deletions source/en-US/DscResource.DocGenerator.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ ConvertFrom-StringData @'
CommentBasedHelpMessage = Reading comment-based help from source file '{0}'.
FoundResourceExamplesMessage = Found {0} examples.
IgnoreAstParseErrorMessage = Errors was found during parsing of comment-based help. These errors were ignored: {0}
WikiGitCloneFailMessage = Failed to clone wiki. Ensure the feature is enabled and the first page has been created.
WikiGitCloneFailMessageDebug = Wiki clone URL '{0}'
InvokeGitStandardOutputMessage = git standard output: '{0}'
InvokeGitStandardErrorMessage = git standard error: '{0}'
InvokeGitExitCodeMessage = git exit code: '{0}'
FoundCompositeFilesMessage = Found {0} composite files in path '{1}'.
UnexpectedInvokeGitReturnCode = Unexpected return code '{0}'. Run with -Debug to see details.
InvokeGitStandardOutputReturn = Git Standard Output: '{0}'
InvokeGitStandardErrorReturn = Git Standard Error: '{0}'
CommentBasedHelpBlockNotFound = A comment-based help block in source file '{0}' could not be found.
CommentBasedHelpBlockNotAtTopMessage = A comment-based help block in source file '{0}' was found, but is not at the top of the file.
CompositeResourceMultiConfigError = {1} composite resources were found in the source file '{0}'. This is not currently supported. Please separate these into different scripts.
Expand Down
8 changes: 7 additions & 1 deletion source/tasks/Publish_GitHub_Wiki_Content.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,13 @@ task Publish_GitHub_Wiki_Content {
}
}

$remoteURL = git remote get-url origin
$gitRemoteResult = Invoke-Git -WorkingDirectory $BuildRoot `
-Arguments @( 'remote', 'get-url', 'origin' )

if ($gitRemoteResult.ExitCode -eq 0)
{
$remoteURL = $gitRemoteResult.StandardOutput
}

# Parse the URL for owner name and repository name.
if ($remoteURL -match 'github')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,50 +31,64 @@ InModuleScope $script:moduleName {
}

Context 'When calling Invoke-Git' {
It 'Should call without throwing' {
{
Invoke-Git -WorkingDirectory $TestDrive -Arguments @( 'config', '--local', 'user.email', '[email protected]' )
} | Should -Not -Throw
BeforeAll {
$mockProcess | Add-Member -MemberType ScriptProperty -Name 'StandardOutput' -Value {
New-Object -TypeName 'Object' | `
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Output Message 0' } -PassThru -Force
} -Force

Assert-VerifiableMock
$mockProcess | Add-Member -MemberType ScriptProperty -Name 'StandardError' -Value {
New-Object -TypeName 'Object' | `
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Error Message 0' } -PassThru -Force
} -Force
}
}
It 'Should complete with ExitCode=0' {

Context 'When calling Invoke-Git with an access token' {
BeforeAll {
Mock -CommandName Write-Debug
}
$result = Invoke-Git -WorkingDirectory $TestDrive `
-Arguments @( 'config', '--local', 'user.email', '[email protected]' )

It 'Should call git but mask access token in debug message' {
{
Invoke-Git -WorkingDirectory $TestDrive `
-Arguments @( 'remote', 'set-url', 'origin', 'https://name:[email protected]/repository.wiki.git' ) `
-Debug
} | Should -Not -Throw
$result.ExitCode | Should -BeExactly 0

Assert-MockCalled -CommandName Write-Debug -ParameterFilter {
$Message -match 'https://name:[email protected]/repository.wiki.git'
} -Exactly -Times 1 -Scope It
$result.StandardOutput | Should -BeExactly 'Standard Output Message 0'

$result.StandardError | Should -BeExactly 'Standard Error Message 0'

Assert-VerifiableMock
}
}

Context 'When git exits with error code 1' {
Context 'When calling Invoke-Git with an access token' {
BeforeAll {
$mockProcess | Add-Member -MemberType ScriptProperty -Name ExitCode -Value { 1 } -Force
}

It 'Should not throw an exception' {
{
Invoke-Git -WorkingDirectory $TestDrive -Arguments @( 'status' )
} | Should -Not -Throw
$mockProcess | Add-Member -MemberType ScriptProperty -Name 'StandardOutput' -Value {
New-Object -TypeName 'Object' | `
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Output Message 1' } -PassThru -Force
} -Force

Assert-VerifiableMock
$mockProcess | Add-Member -MemberType ScriptProperty -Name 'StandardError' -Value {
New-Object -TypeName 'Object' | `
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Error Message 1' } -PassThru -Force
} -Force

Mock -CommandName Write-Debug
}
It 'Should return 1' {
$returnCode = Invoke-Git -WorkingDirectory $TestDrive -Arguments @( 'status' )
$returnCode | Should -BeExactly 1

It 'Should complete with ExitCode=1 and mask access token in debug message' {

$result = Invoke-Git -WorkingDirectory $TestDrive `
-Arguments @( 'remote', 'set-url', 'origin', 'https://name:[email protected]/repository.wiki.git' ) `
-Debug

$result.ExitCode | Should -BeExactly 1

$result.StandardOutput | Should -BeExactly 'Standard Output Message 1'

$result.StandardError | Should -BeExactly 'Standard Error Message 1'

Assert-MockCalled -CommandName Write-Debug -ParameterFilter {
$Message -match 'https://name:[email protected]/repository.wiki.git'
} -Exactly -Times 1 -Scope It

Assert-VerifiableMock
}
Expand All @@ -86,24 +100,23 @@ InModuleScope $script:moduleName {

$mockProcess | Add-Member -MemberType ScriptProperty -Name 'StandardOutput' -Value {
New-Object -TypeName 'Object' | `
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Output Message' } -PassThru -Force
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Output Message 128' } -PassThru -Force
} -Force

$mockProcess | Add-Member -MemberType ScriptProperty -Name 'StandardError' -Value {
New-Object -TypeName 'Object' | `
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Error Message' } -PassThru -Force
Add-Member -MemberType ScriptMethod -Name 'ReadToEnd' -Value { 'Standard Error Message 128' } -PassThru -Force
} -Force

Mock -CommandName Write-Warning
}

It 'Should produce ExitCode=128 and Write-Warning' {
$returnCode = Invoke-Git -WorkingDirectory $TestDrive -Arguments @( 'status' )
$returnCode | Should -BeExactly '128'
It 'Should complete with ExitCode=128' {
$result = Invoke-Git -WorkingDirectory $TestDrive -Arguments @( 'status' )

Assert-MockCalled -CommandName Write-Warning -ParameterFilter {
$Message -eq $($localizedData.UnexpectedInvokeGitReturnCode -f $mockProcess.ExitCode)
} -Exactly -Times 1 -Scope It
$result.ExitCode | Should -BeExactly 128

$result.StandardOutput | Should -BeExactly 'Standard Output Message 128'

$result.StandardError | Should -BeExactly 'Standard Error Message 128'

Assert-VerifiableMock
}
Expand Down
Loading

0 comments on commit c75f492

Please sign in to comment.