From 4fb926e36146c454f431273b84e97fe6443b2183 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 12 Feb 2017 14:43:56 -0700 Subject: [PATCH 1/4] Quote tab completion items with PS special chars. Fix #293 --- src/GitTabExpansion.ps1 | 26 +++++++++++---- test/TabExpansion.Tests.ps1 | 66 +++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/GitTabExpansion.ps1 b/src/GitTabExpansion.ps1 index f8a6751b0..23d08235c 100644 --- a/src/GitTabExpansion.ps1 +++ b/src/GitTabExpansion.ps1 @@ -51,6 +51,15 @@ catch { Write-Debug "Search for 'flow' in 'git help' output failed with error: $_" } +filter quoteStringWithSpecialChars { + if ($_ -and ($_ -match '\s+|#|@|\$|;|\{|\}|\(|\)')) { + "'" + $_ + "'" + } + else { + $_ + } +} + function script:gitCommands($filter, $includeAliases) { $cmdList = @() if (-not $global:GitTabSettings.AllCommands) { @@ -86,7 +95,8 @@ function script:gitBranches($filter, $includeHEAD = $false, $prefix = '') { $branches | Where-Object { $_ -ne '(no branch)' -and $_ -like "$filter*" } | - ForEach-Object { $prefix + $_ } + ForEach-Object { $prefix + $_ } | + quoteStringWithSpecialChars } function script:gitRemoteUniqueBranches($filter) { @@ -95,13 +105,15 @@ function script:gitRemoteUniqueBranches($filter) { Group-Object -NoElement | Where-Object { $_.Count -eq 1 } | Select-Object -ExpandProperty Name | - Where-Object { $_ -like "$filter*" } + Where-Object { $_ -like "$filter*" } | + quoteStringWithSpecialChars } function script:gitTags($filter, $prefix = '') { git tag | Where-Object { $_ -like "$filter*" } | - ForEach-Object { $prefix + $_ } + ForEach-Object { $prefix + $_ } | + quoteStringWithSpecialChars } function script:gitFeatures($filter, $command){ @@ -109,13 +121,15 @@ function script:gitFeatures($filter, $command){ $branches = @(git branch --no-color | ForEach-Object { if ($_ -match "^\*?\s*$featurePrefix(?.*)") { $matches['ref'] } }) $branches | Where-Object { $_ -ne '(no branch)' -and $_ -like "$filter*" } | - ForEach-Object { $prefix + $_ } + ForEach-Object { $prefix + $_ } | + quoteStringWithSpecialChars } function script:gitRemoteBranches($remote, $ref, $filter, $prefix = '') { git branch --no-color -r | Where-Object { $_ -like " $remote/$filter*" } | - ForEach-Object { $prefix + $ref + ($_ -replace " $remote/","") } + ForEach-Object { $prefix + $ref + ($_ -replace " $remote/","") } | + quoteStringWithSpecialChars } function script:gitStashes($filter) { @@ -133,7 +147,7 @@ function script:gitTfsShelvesets($filter) { function script:gitFiles($filter, $files) { $files | Sort-Object | Where-Object { $_ -like "$filter*" } | - ForEach-Object { if ($_ -like '* *') { "'$_'" } else { $_ } } + quoteStringWithSpecialChars } function script:gitIndex($GitStatus, $filter) { diff --git a/test/TabExpansion.Tests.ps1 b/test/TabExpansion.Tests.ps1 index fe45ec894..2e48db00d 100644 --- a/test/TabExpansion.Tests.ps1 +++ b/test/TabExpansion.Tests.ps1 @@ -127,7 +127,7 @@ Describe 'TabExpansion Tests' { $temp = [System.IO.Path]::GetTempPath() $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) - git init $repoPath + git.exe init $repoPath Set-Location $repoPath } AfterEach { @@ -137,16 +137,70 @@ Describe 'TabExpansion Tests' { } } It 'Tab completes non-ASCII file name' { - git config core.quotepath true # Problematic (default) config + git.exe config core.quotepath true # Problematic (default) config $fileName = "posh$([char]8226)git.txt" - New-Item $fileName + New-Item $fileName -ItemType File - $GitStatus = & $module Get-GitStatus - - $result = & $module GitTabExpansionInternal 'git add ' $GitStatus + $gitStatus = & $module Get-GitStatus + $result = & $module GitTabExpansionInternal 'git add ' $gitStatus $result | Should BeExactly $fileName } } + + Context 'PowerShell Special Chars Tests' { + BeforeAll { + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] + $origPath = Get-Location + $temp = [System.IO.Path]::GetTempPath() + $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) + + git.exe init $repoPath + Set-Location $repoPath + + 'readme' | Out-File .\README.md -Encoding ascii + git.exe add .\README.md + git.exe commit -m "initial commit." + } + AfterAll { + Set-Location $origPath + if (Test-Path $repoPath) { + Remove-Item $repoPath -Recurse -Force + } + } + AfterEach { + Set-Location $repoPath + git.exe reset HEAD --hard + git.exe checkout master 2>$null + } + It 'Tab completes branch name with special char as quoted' { + git.exe branch '#develop' 2>$null + + $result = & $module GitTabExpansionInternal 'git checkout #' + $result | Should BeExactly "'#develop'" + } + It 'Tab completes git feature branch name with special char as quoted' { + git.exe branch '#develop' 2>$null + + $result = & $module GitTabExpansionInternal 'git flow feature list #' + $result | Should BeExactly "'#develop'" + } + It 'Tab completes a tag name with special char as quoted' { + $tag = "v1.0.0;abcdef" + git.exe tag $tag + + $result = & $module GitTabExpansionInternal 'git show v1' + $result | Should BeExactly "'$tag'" + } + It 'Tab completes add file in working dir with special char as quoted' { + $filename = 'foo{bar} (x86).txt'; + New-Item $filename -ItemType File + + $gitStatus = & $module Get-GitStatus + + $result = & $module GitTabExpansionInternal 'git add ' $gitStatus + $result | Should BeExactly "'$filename'" + } + } } From 8440c88c84a99bfe5f6478c22576cf224e2f0e9c Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 12 Feb 2017 18:54:58 -0700 Subject: [PATCH 2/4] Consistently use the quote special char function. --- src/GitTabExpansion.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitTabExpansion.ps1 b/src/GitTabExpansion.ps1 index 23d08235c..b1aca1646 100644 --- a/src/GitTabExpansion.ps1 +++ b/src/GitTabExpansion.ps1 @@ -135,13 +135,13 @@ function script:gitRemoteBranches($remote, $ref, $filter, $prefix = '') { function script:gitStashes($filter) { (git stash list) -replace ':.*','' | Where-Object { $_ -like "$filter*" } | - ForEach-Object { "'$_'" } + quoteStringWithSpecialChars } function script:gitTfsShelvesets($filter) { (git tfs shelve-list) | Where-Object { $_ -like "$filter*" } | - ForEach-Object { "'$_'" } + quoteStringWithSpecialChars } function script:gitFiles($filter, $files) { From 32c9a2b4d1d4794c5b29d921de96c5bb0a956a2f Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 13 Feb 2017 16:38:12 -0700 Subject: [PATCH 3/4] Address most PR review issues. I don't know that Pester will support a user-defined construct to encapuslate BeforeAll/AfterAll. But I did pull the guts out into shared functions. --- src/GitTabExpansion.ps1 | 5 +++-- test/Shared.ps1 | 22 ++++++++++++++++++++++ test/TabExpansion.Tests.ps1 | 35 ++++++++++++----------------------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/GitTabExpansion.ps1 b/src/GitTabExpansion.ps1 index b1aca1646..f4f2829eb 100644 --- a/src/GitTabExpansion.ps1 +++ b/src/GitTabExpansion.ps1 @@ -52,8 +52,9 @@ catch { } filter quoteStringWithSpecialChars { - if ($_ -and ($_ -match '\s+|#|@|\$|;|\{|\}|\(|\)')) { - "'" + $_ + "'" + if ($_ -and ($_ -match '\s+|#|@|\$|;|,|''|\{|\}|\(|\)')) { + $str = $_ -replace "'", "''" + "'$str'" } else { $_ diff --git a/test/Shared.ps1 b/test/Shared.ps1 index 0b07e90a4..46a717a1e 100644 --- a/test/Shared.ps1 +++ b/test/Shared.ps1 @@ -23,6 +23,28 @@ function MakeGitPath([string]$Path) { $Path -replace '\\', '/' } +function NewGitTempRepo { + Push-Location + $temp = [System.IO.Path]::GetTempPath() + $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) + git.exe init $repoPath *>$null + Set-Location $repoPath + $repoPath +} + +function RemoveGitTempRepo($RepoPath) { + Pop-Location + if (Test-Path $repoPath) { + Remove-Item $repoPath -Recurse -Force + } +} + +function ResetGitTempRepoWorkingDir($RepoPath, $Branch = 'master') { + Set-Location $repoPath + git.exe reset HEAD --hard + git.exe checkout $Branch 2>$null +} + # Force the posh-git prompt to be installed. Could be runnng on dev system where # user has customized the prompt. [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] diff --git a/test/TabExpansion.Tests.ps1 b/test/TabExpansion.Tests.ps1 index 2e48db00d..f15875fc0 100644 --- a/test/TabExpansion.Tests.ps1 +++ b/test/TabExpansion.Tests.ps1 @@ -120,21 +120,14 @@ Describe 'TabExpansion Tests' { } } } + Context 'Add/Reset/Checkout TabExpansion Tests' { BeforeEach { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] - $origPath = Get-Location - $temp = [System.IO.Path]::GetTempPath() - $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) - - git.exe init $repoPath - Set-Location $repoPath + $repoPath = NewGitTempRepo } AfterEach { - Set-Location $origPath - if (Test-Path $repoPath) { - Remove-Item $repoPath -Recurse -Force - } + RemoveGitTempRepo $repoPath } It 'Tab completes non-ASCII file name' { git.exe config core.quotepath true # Problematic (default) config @@ -152,27 +145,17 @@ Describe 'TabExpansion Tests' { Context 'PowerShell Special Chars Tests' { BeforeAll { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] - $origPath = Get-Location - $temp = [System.IO.Path]::GetTempPath() - $repoPath = Join-Path $temp ([IO.Path]::GetRandomFileName()) - - git.exe init $repoPath - Set-Location $repoPath + $repoPath = NewGitTempRepo 'readme' | Out-File .\README.md -Encoding ascii git.exe add .\README.md git.exe commit -m "initial commit." } AfterAll { - Set-Location $origPath - if (Test-Path $repoPath) { - Remove-Item $repoPath -Recurse -Force - } + RemoveGitTempRepo $repoPath } AfterEach { - Set-Location $repoPath - git.exe reset HEAD --hard - git.exe checkout master 2>$null + ResetGitTempRepoWorkingDir $repoPath } It 'Tab completes branch name with special char as quoted' { git.exe branch '#develop' 2>$null @@ -193,6 +176,12 @@ Describe 'TabExpansion Tests' { $result = & $module GitTabExpansionInternal 'git show v1' $result | Should BeExactly "'$tag'" } + It 'Tab completes a tag name with single quote correctly' { + git.exe tag "v2.0.0'" + + $result = & $module GitTabExpansionInternal 'git show v2' + $result | Should BeExactly "'v2.0.0'''" + } It 'Tab completes add file in working dir with special char as quoted' { $filename = 'foo{bar} (x86).txt'; New-Item $filename -ItemType File From 39d559e39412bad5edfa506c4b7e51e334a2d183 Mon Sep 17 00:00:00 2001 From: Keith Dahlby Date: Tue, 14 Feb 2017 00:02:02 -0600 Subject: [PATCH 4/4] Simplify ResetGitTempRepoWorkingDir, plus clean --- test/Shared.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Shared.ps1 b/test/Shared.ps1 index 46a717a1e..0f8f49977 100644 --- a/test/Shared.ps1 +++ b/test/Shared.ps1 @@ -41,8 +41,8 @@ function RemoveGitTempRepo($RepoPath) { function ResetGitTempRepoWorkingDir($RepoPath, $Branch = 'master') { Set-Location $repoPath - git.exe reset HEAD --hard - git.exe checkout $Branch 2>$null + git.exe checkout -fq $Branch 2>$null + git.exe clean -xdfq 2>$null } # Force the posh-git prompt to be installed. Could be runnng on dev system where