From 8bfb4aead8c7da227c7a7dde69aa9c20b3792521 Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez Date: Fri, 12 Jun 2026 21:10:34 -0700 Subject: [PATCH] fix: warn when Git target exists but is not a valid git repository (#86) Previously, if a directory already existed at the clone target but was not a git repository, `git rev-parse` returned nothing and the handler silently fell into the "we don't support moving versions" branch with null branch/commit values, producing a confusing verbose message and a no-op install. Now emits `Write-Warning` in that case so the user knows why the dependency was skipped. Also confirmed that the nesting bug from #86 (Repo/Repo on repeated runs) does not reproduce on current code; adds two Pester tests to lock in idempotency and the non-git-directory warning path. Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 13 ++++++++++++ PSDepend/PSDependScripts/Git.ps1 | 6 +++++- Tests/Git.Type.Tests.ps1 | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ddaf36..18f7557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- `Git` handler no longer silently ignores a pre-existing directory at + the clone target that is not a valid git repository; it now emits a + `Write-Warning` so the user knows why the install was skipped (#86). + +### Tests + +- Added idempotency test: a second install run against an already-cloned + repo does not trigger a second `git clone` (#86). +- Added non-git-directory test: confirms a warning is emitted and no + clone is attempted when the target path exists but is not a git repo (#86). + ## [0.4.1] - 2026-06-12 ### Fixed diff --git a/PSDepend/PSDependScripts/Git.ps1 b/PSDepend/PSDependScripts/Git.ps1 index 64c4e7a..ad9b452 100644 --- a/PSDepend/PSDependScripts/Git.ps1 +++ b/PSDepend/PSDependScripts/Git.ps1 @@ -132,7 +132,11 @@ if ($GottaTest) { $Branch = Invoke-ExternalCommand git -Arguments (Write-Output rev-parse --abbrev-ref HEAD) -Passthru $Commit = Invoke-ExternalCommand git -Arguments (Write-Output rev-parse HEAD) -Passthru Pop-Location - if ($Version -eq $Branch -or $Version -eq $Commit) { + if (-not $Branch) { + Write-Warning "[$RepoPath] exists but does not appear to be a valid git repository. Skipping [$DependencyName]." + $GottaInstall = $False + } + elseif ($Version -eq $Branch -or $Version -eq $Commit) { Write-Verbose "[$RepoPath] exists and is already at version [$Version]" if ($PSDependAction -contains 'Test' -and $PSDependAction.count -eq 1) { return $true diff --git a/Tests/Git.Type.Tests.ps1 b/Tests/Git.Type.Tests.ps1 index 848b94b..2175af4 100644 --- a/Tests/Git.Type.Tests.ps1 +++ b/Tests/Git.Type.Tests.ps1 @@ -74,4 +74,39 @@ Describe 'Git script' { $result | Should -Be $false Should -Invoke -CommandName Invoke-ExternalCommand -ModuleName PSDepend -Times 0 } + + It 'Does not clone again when repo already exists at the correct version (idempotency)' { + $targetDir = (New-Item 'TestDrive:/git-idempotent' -ItemType Directory -Force).FullName + # Pre-create the repo directory as if a prior run cloned it + $null = New-Item (Join-Path $targetDir 'repo') -ItemType Directory -Force + $dep = New-PSDependFixture -DependencyName 'https://example.com/user/repo.git' -DependencyType 'Git' -Version 'main' -Target $targetDir + + InModuleScope PSDepend -Parameters @{ Dep = $dep; ScriptPath = $script:ScriptPath } { + # rev-parse returns the branch name matching Version + Mock Invoke-ExternalCommand { + if ($Arguments -contains '--abbrev-ref') { return 'main' } + if ($Arguments -notcontains 'clone' -and $Arguments -notcontains '--abbrev-ref') { return 'abc1234' } + } + & $ScriptPath -Dependency $Dep + } + Should -Invoke -CommandName Invoke-ExternalCommand -ModuleName PSDepend -Times 0 -ParameterFilter { + $Arguments -contains 'clone' + } + } + + It 'Emits a warning and skips install when the repo path exists but is not a git repository' { + $targetDir = (New-Item 'TestDrive:/git-nongit' -ItemType Directory -Force).FullName + # Pre-create the directory but leave it empty (not a git repo) + $null = New-Item (Join-Path $targetDir 'repo') -ItemType Directory -Force + $dep = New-PSDependFixture -DependencyName 'https://example.com/user/repo.git' -DependencyType 'Git' -Version 'main' -Target $targetDir + + InModuleScope PSDepend -Parameters @{ Dep = $dep; ScriptPath = $script:ScriptPath } { + # rev-parse returns nothing (non-git directory) + Mock Invoke-ExternalCommand { } + { & $ScriptPath -Dependency $Dep } | Should -Not -Throw + } + Should -Invoke -CommandName Invoke-ExternalCommand -ModuleName PSDepend -Times 0 -ParameterFilter { + $Arguments -contains 'clone' + } + } }