Skip to content

Commit 4ac0a77

Browse files
Merge pull request #175 from StartAutomating/ugit-ufix
ugit 0.4
2 parents 14267d5 + 5d472ad commit 4ac0a77

File tree

16 files changed

+464
-47
lines changed

16 files changed

+464
-47
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [StartAutomating]

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## 0.4:
2+
3+
* Adding Sponsorship! (#174)
4+
* RealGit / GitReal will opt-out of ugit (#173)
5+
* Added git.commit.info.psuh (#111)
6+
* Fixing directory piping (#172)
7+
* Git Clone allows absolute paths (#169, thanks @corbob)
8+
* Fixing Git Log -Statistics (#171)
9+
* Not Mapping Partial Dynamic Parameters (#168)
10+
11+
--
12+
113
## 0.3.9:
214

315
* Adding ugit demo (Fixes #163)

Extensions/Git.Clone.UGit.Extension.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ end {
4949

5050

5151
if ($dest) {
52-
$destPath = Join-Path $pwd $dest
52+
$destPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($dest)
5353
$gitUrl = $gitArgument | Where-Object { $_ -like '*.git' -and $_ -as [uri]}
5454
[PSCustomObject]@{
5555
PSTypeName = 'git.clone'
56-
GitRoot = $destPath
57-
Directory = Get-Item -Path $destPath
56+
GitRoot = "$destPath"
57+
Directory = Get-Item -LiteralPath $destPath
5858
GitUrl = $gitUrl
5959
}
6060
} else {

Extensions/Git.Help.All.UGit.Extension.ps1

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,3 @@ process {
3434
Category = $category
3535
}
3636
}
37-
38-
end {
39-
40-
}

Extensions/Git.Log.Input.UGit.Extension.ps1

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,6 @@ foreach ($dashToDoubleDash in 'after', 'before', 'author') {
8383
}
8484
}
8585

86-
foreach ($dashToDoubleDashSwitch in 'Statistics') {
87-
if ($PSBoundParameters[$dashToDoubleDash]) {
88-
"--$dashToDoubleDashSwitch"
89-
}
90-
}
91-
9286
if ($CurrentBranch) {
9387
$headbranch = git remote | git remote show | Select-Object -ExpandProperty HeadBranch
9488
$currentBranchName = git branch | Where-Object IsCurrentBranch
@@ -119,4 +113,8 @@ if ($SearchString) {
119113
if ($SearchPattern) {
120114
"-G"
121115
$SearchPattern
116+
}
117+
118+
if ($Statistics) {
119+
'--stat'
122120
}

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
<a href='https://www.powershellgallery.com/packages/ugit/'>
44
<img src='https://img.shields.io/powershellgallery/dt/ugit' />
55
</a>
6+
<br/>
7+
<a href='https://github.com/sponsors/StartAutomating'>❤️</a>
8+
<a href='https://github.com/StartAutomating/ugit/stargazers'>⭐</a>
69
</div>
710

8-
Updated Git: A powerful PowerShell wrapper for git that lets you extend git, automate multiple repos, and output git as objects.
9-
11+
ugit (Updated Git) is a powerful PowerShell module for git that lets you: output git as objects, automate multiple repos, and extend git.
1012

1113
## What is ugit?
1214

@@ -470,4 +472,9 @@ ugit also allows you to extend the input for git.
470472

471473

472474

475+
## What uses ugit?
476+
477+
ugit is part of the core of [GitLogger](https://gitlogger.com/).
478+
479+
GitLogger uses ugit to turn logs into objects and then provides standardized metrics and a way to query your logs.
473480

README.ps1.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
<a href='https://www.powershellgallery.com/packages/ugit/'>
44
<img src='https://img.shields.io/powershellgallery/dt/ugit' />
55
</a>
6+
<br/>
7+
<a href='https://github.com/sponsors/StartAutomating'>❤️</a>
8+
<a href='https://github.com/StartAutomating/ugit/stargazers'>⭐</a>
69
</div>
710

8-
Updated Git: A powerful PowerShell wrapper for git that lets you extend git, automate multiple repos, and output git as objects.
9-
11+
ugit (Updated Git) is a powerful PowerShell module for git that lets you: output git as objects, automate multiple repos, and extend git.
1012

1113
## What is ugit?
1214

@@ -127,3 +129,8 @@ ugit also allows you to extend the input for git.
127129
}
128130
~~~
129131

132+
## What uses ugit?
133+
134+
ugit is part of the core of [GitLogger](https://gitlogger.com/).
135+
136+
GitLogger uses ugit to turn logs into objects and then provides standardized metrics and a way to query your logs.

Types/git.commit.info/Push.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Push-Location $this.GitRoot
2+
git push @args
3+
Pop-Location

Use-Git.ps1

Lines changed: 96 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
.NOTES
3636
Use-Git will generate two events before git runs. They will have the source identifiers of "Use-Git" and "Use-Git $GitArgument"
3737
#>
38-
[Alias('git')]
38+
[Alias('git','realgit','gitreal')]
3939
[CmdletBinding(PositionalBinding=$false,SupportsShouldProcess,ConfirmImpact='Low')]
4040
param(
4141
# Any arguments passed to git. All positional arguments will automatically be passed to -GitArgument.
@@ -53,9 +53,11 @@
5353
)
5454

5555
dynamicParam {
56+
# To get dynamic parameters, we need to look at our invocation
5657
$myInv = $MyInvocation
5758

58-
$callstackPeek = @(Get-PSCallStack)[1]
59+
# and peek up the callstack.
60+
$callstackPeek = @(Get-PSCallStack)[-1]
5961
$callingContext =
6062
if ($callstackPeek.InvocationInfo.MyCommand.ScriptBlock) {
6163
@($callstackPeek.InvocationInfo.MyCommand.ScriptBlock.Ast.FindAll({
@@ -66,27 +68,80 @@
6668
},$true))[0]
6769
}
6870

71+
# This will give us something to validate against, so we don't get dynamic parameters for everything
6972
$ToValidate =
7073
if (-not $callingContext -and
7174
$callstackPeek.Command -like 'TabExpansion*' -and
7275
$callstackPeek.InvocationInfo.BoundParameters.InputScript
7376
) {
7477
$callstackPeek.InvocationInfo.BoundParameters.InputScript.ToString()
75-
} else {
78+
}
79+
elseif ($callingContext) {
7680
$callingContext.CommandElements -join ' '
7781
}
82+
elseif ($myInv.Line) {
83+
$myInv.Line.Substring($myInv.OffsetInLine - 1)
84+
}
85+
86+
# If there's nothing to validate, there are no dynamic parameters.
87+
if (-not $ToValidate) { return }
7888

89+
# Get dynamic parameters that are valid for this command
7990
$dynamicParameterSplat = [Ordered]@{
8091
CommandName='Use-Git'
8192
ValidateInput=$ToValidate
8293
DynamicParameter=$true
8394
DynamicParameterSetName='__AllParameterSets'
8495
NoMandatoryDynamicParameter=$true
96+
}
97+
$myDynamicParameters = Get-UGitExtension @dynamicParameterSplat
98+
if (-not $myDynamicParameters) { return }
99+
100+
# Here's where things get a little tricky.
101+
# we want to make as much muscle memory work as possible, so we don't wany any dynamic parameter that is not "fully" mapped.
102+
# So we need to walk over each command element.
103+
104+
if (-not ($callingContext -or ($callstackPeek.Command -like 'TabExpansion*'))) {
105+
# (bonus points - within Pester, we cannot callstack peek effectively, and need to use the invocation line)
106+
# Therefore, when testing dynamic parameters, assign to a variable (because parenthesis and pipes may make this an invalid ScriptBlock)
107+
$callingContext = try {
108+
[scriptblock]::Create($ToValidate).Ast.EndBlock.Statements[0].PipelineElements[0]
109+
} catch { $null}
85110
}
86-
Get-UGitExtension @dynamicParameterSplat
111+
foreach ($commandElement in $callingContext.CommandElements) {
112+
if (-not $commandElement.parameterName) { continue } # that is a Powershell parameter
113+
foreach ($dynamicParam in @($myDynamicParameters.Values)) {
114+
if (
115+
(
116+
# If it started with this name
117+
$dynamicParam.Name.StartsWith($commandElement.parameterName, 'CurrentCultureIgnoreCase') -and
118+
# but was not the full parameter name, we'll remove it
119+
$dynamicParam.Name -ne $commandElement.parameterName
120+
) -or # otherwise
121+
(
122+
# If the dynamic parameter had aliases
123+
$dynamicParam.Attributes.AliasNames -and
124+
$(foreach ($aliasName in $dynamicParam.Attributes.AliasNames) {
125+
if (-not $aliasName) { continue }
126+
# and any of those aliases starts with the parameter name
127+
if ($aliasName.StartsWith($commandElement.parameterName, 'CurrentCultureIgnoreCase') -and
128+
# and is not the full parameter name
129+
$aliasName -ne $commandElement.parameterName) {
130+
# we also want to remove it
131+
$true; break
132+
}
133+
})
134+
)
135+
) {
136+
$null = $myDynamicParameters.Remove($dynamicParam.Name)
137+
}
138+
}
139+
}
140+
$myDynamicParameters
87141
}
88142

89143
begin {
144+
$myInv = $MyInvocation
90145
if (-not $script:CachedGitCmd) { # If we haven't cahced the git command
91146
# go get it.
92147
$script:CachedGitCmd = $ExecutionContext.SessionState.InvokeCommand.GetCommand('git', 'Application')
@@ -117,21 +172,22 @@
117172
$gitArgsArray.AddRange($GitArgument)
118173
}
119174

120-
foreach ($commandElement in $callingContext.CommandElements) {
121-
if ($commandElement.parameterName -in 'd', 'v', 'c') {
175+
:nextCommandElement foreach ($commandElement in $callingContext.CommandElements) {
176+
if (-not $commandElement.parameterName) { $argumentNumber++; continue }
177+
$paramName = $commandElement.parameterName
178+
if ($paramName -in 'd', 'c', 'v') {
122179
# Insert the argument into the list
123180
$gitArgsArray.Insert(
124-
$argumentNumber - 1, # ( don't forget to subtract one, because the command is an element)
181+
$argumentNumber - 1, # ( don't forget to subtract one, because the command name is an element)
125182
$commandElement.Extent.ToString()
126183
)
127-
if ($commandElement.parameterName -in 'd', 'c', 'v') {
128-
if ($commandElement.parameterName -eq 'c') {
129-
$ConfirmPreference = 'none' # so set confirm preference to none
130-
}
131-
$VerbosePreference = 'silentlyContinue'
132-
$DebugPreference = 'silentlyContinue'
184+
if ($paramName -eq 'c') {
185+
$ConfirmPreference = 'none' # so set confirm preference to none
133186
}
187+
$VerbosePreference = 'silentlyContinue'
188+
$DebugPreference = 'silentlyContinue'
134189
}
190+
135191
$argumentNumber++
136192
}
137193

@@ -166,6 +222,8 @@
166222
return # we're done.
167223
}
168224

225+
$pipedInDirectories = $false
226+
169227
$inputObject =
170228
@(foreach ($in in $AllInputObjects) {
171229
if ($in -is [IO.FileInfo]) { # If the input is a file
@@ -184,11 +242,13 @@
184242
$in.Fullname # and adding this file name.
185243
}
186244
} elseif ($in -is [IO.DirectoryInfo]) {
245+
$pipedInDirectories = $true
187246
$directories += Get-Item -LiteralPath $in.Fullname # If the input was a directory, keep track of it.
188247
} else {
189248
# Otherwise, see if it was a path and it was a directory
190249
if ((Test-Path $in -ErrorAction SilentlyContinue) -and
191250
(Get-Item $in -ErrorAction SilentlyContinue) -is [IO.DirectoryInfo]) {
251+
$pipedInDirectories = $true
192252
$directories += Get-Item $in
193253
} else {
194254

@@ -267,8 +327,10 @@
267327

268328
# Walk over each input for each directory
269329
:nextInput foreach ($inObject in $InputDirectories[$dir]) {
270-
# Continue if there was no input and we were not the first step of the pipeline.
271-
if (-not $inObject -and $myInv.PipelinePosition -gt 1) { continue }
330+
# Continue if there was no input and we were not the first step of the pipeline that was not a directory.
331+
if (-not $inObject -and (
332+
$myInv.PipelinePosition -gt 1
333+
) -and -not $pipedInDirectories) { continue }
272334

273335
$AllGitArgs = @(@($GitArgument) + $inObject) # Then we collect the combined arguments
274336

@@ -344,30 +406,38 @@
344406
Write-Progress -PercentComplete $percentageComplete -Status "git $allGitArgs " -Activity "$($dir) " -Id $progId
345407
}
346408

409+
# If -WhatIf was passed, $WhatIfPreference will be true.
347410
if ($WhatIfPreference) {
411+
# If that's the case, return the command line we would execute.
348412
"git $AllGitArgs"
349413
}
350414

351-
# If we have indicated we do not care about -Confirmation, don't prompt
415+
# otherwise, if we have indicated we do not want to -Confirm, don't prompt.
352416
elseif (($ConfirmPreference -eq 'None' -and (-not $paramCopy.Confirm)) -or
353-
$PSCmdlet.ShouldProcess("$pwd : git $allGitArgs") # otherwise, as for confirmation to run.
417+
$PSCmdlet.ShouldProcess("$pwd : git $allGitArgs") # otherwise, prompt for confirmation to run.
354418
) {
355419
$eventSourceIds = @("Use-Git","Use-Git $allGitArgs")
356-
$messageData = @{
357-
GitRoot = "$pwd"
420+
$messageData = [Ordered]@{
358421
GitCommand = @(@("git") + $AllGitArgs) -join ' '
359-
}
422+
GitRoot = "$pwd"
423+
}
424+
360425
$null =
361426
foreach ($sourceIdentifier in $eventSourceIds) {
362427
New-Event -SourceIdentifier $sourceIdentifier -MessageData $messageData
363428
}
364-
& $script:CachedGitCmd @AllGitArgs *>&1 | # Then we run git, combining all streams into output.
365-
# then pipe to Out-Git, which will
366-
Out-Git @OutGitParams # output git as objects.
367429

368-
# These objects are decorated for the PowerShell Extended Type System.
369-
# This makes them easy to extend and customize their display.
370-
# If Out-Git finds one or more extensions to run, these can parse the output.
430+
if ($myInv.InvocationName -in 'realgit', 'gitreal') {
431+
& $script:CachedGitCmd @AllGitArgs *>&1
432+
} else {
433+
& $script:CachedGitCmd @AllGitArgs *>&1 | # Then we run git, combining all streams into output.
434+
# then pipe to Out-Git, which will
435+
Out-Git @OutGitParams # output git as objects.
436+
437+
# These objects are decorated for the PowerShell Extended Type System.
438+
# This makes them easy to extend and customize their display.
439+
# If Out-Git finds one or more extensions to run, these can parse the output.
440+
}
371441
}
372442

373443
}

docs/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## 0.4:
2+
3+
* Adding Sponsorship! (#174)
4+
* RealGit / GitReal will opt-out of ugit (#173)
5+
* Added git.commit.info.psuh (#111)
6+
* Fixing directory piping (#172)
7+
* Git Clone allows absolute paths (#169, thanks @corbob)
8+
* Fixing Git Log -Statistics (#171)
9+
* Not Mapping Partial Dynamic Parameters (#168)
10+
11+
--
12+
113
## 0.3.9:
214

315
* Adding ugit demo (Fixes #163)

0 commit comments

Comments
 (0)