functions/Invoke-GitClone.ps1
function Invoke-GitClone { <# .SYNOPSIS Clones a git repository. .DESCRIPTION Clones a git repository to the specified directory. .PARAMETER RepoURL The URL of the git repository to clone. If a default URL root is defined in $Powdrgit.DefaultCloneUrl, only the repository name is required. The URL can start with any of the following: http://, https://, ftp://, ftps://, git://, ssh://, [A-Z]:\, \\ .PARAMETER ParentDir The parent directory where the git repository will be cloned to. If the parameter is omitted, and a default parent directory is defined in $Powdrgit.DefaultDir, the repository will be cloned under that directory. If no directory is specified, the repository is cloned to the current location. .PARAMETER RepoName The name to give the repository (the folder name of the top-level directory of the cloned repository). If the parameter is omitted, the name will be derived from the RepoURL value. .PARAMETER UseDefaultDir Uses the directory stored in the $Powdrgit.DefaultDir variable as the ParentDir value. .PARAMETER AppendPowdrgitPath Appends the path of the cloned repository to the $Powdrgit.Path module variable. .PARAMETER SetLocation Sets the location to the top-level directory of the cloned repository. .EXAMPLE ## Clone a non-existent repository from a URL ## PS C:\> $Powdrgit.ShowWarnings = $true # to ensure warnings are visible PS C:\> Invoke-GitClone -RepoURL 'https://my.repos.com/MyMissingRepo' WARNING: [Invoke-GitClone]fatal: repository 'https://my.repos.com/MyMissingRepo/' not found # Attempting to clone to a non-existent repository generates a warning. .EXAMPLE ## Clone an existent repository from a URL ## PS C:\> Invoke-GitClone -RepoURL 'https://my.repos.com/MyToolbox' | Format-Table Name,FullName Name FullName ---- -------- MyToolbox C:\MyToolbox # The repository was cloned to the current directory. .EXAMPLE ## Clone a repository from a local path ## PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' | Format-Table Name,FullName Name FullName ---- -------- MyToolbox C:\MyToolbox # The repository was cloned to the current directory. .EXAMPLE ## Clone a repository to an existing repository ## PS C:\> $Powdrgit.ShowWarnings = $true # to ensure warnings are visible PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' WARNING: [Invoke-GitClone]fatal: destination path 'C:\MyToolbox' already exists and is not an empty directory. # Attempting to clone to an existing repository generates a warning. .EXAMPLE ## Clone a repository with $Powdrgit.DefaultCloneUrl set ## PS C:\> $Powdrgit.DefaultCloneUrl = 'C:\PowdrgitExamples\<RepoURL>' PS C:\> Invoke-GitClone -RepoURL 'MyToolbox' | Format-Table Name,FullName Name FullName ---- -------- MyToolbox C:\MyToolbox # Equivalent to the previous example .EXAMPLE ## Clone a repository to a specified directory ## PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' -ParentDir 'C:\Temp' | Format-Table Name,FullName Name FullName ---- -------- MyToolbox C:\Temp\MyToolbox # The repository was cloned to the specified directory. .EXAMPLE ## Clone a repository with a specified name ## PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' -RepoName 'MyTools' | Format-Table Name,FullName Name FullName ---- -------- MyTools C:\MyTools # The repository was cloned to the specified directory and given the specified name. .EXAMPLE ## Clone a repository to the default directory ## PS C:\> $Powdrgit.DefaultDir = 'C:\Temp' PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' -UseDefaultDir | Format-Table Name,FullName Name FullName ---- -------- MyToolbox C:\Temp\MyToolbox # The repository was cloned to the default directory. .EXAMPLE ## Clone a repository and add the path to $Powdrgit.Path ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\Project1' PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' -AppendPowdrgitPath | Out-Null PS C:\> Test-PowdrgitPath -PassThru C:\MyToolbox C:\PowdrgitExamples\Project1 # A [GitRepo] object is returned and the repository path is added to the $Powdrgit.Path module variable. .EXAMPLE ## Clone a repository and set the location to the repository ## PS C:\> Invoke-GitClone -RepoURL 'C:\PowdrgitExamples\MyToolbox' -SetLocation | Out-Null PS C:\MyToolbox> # The location was changed to the repository top-level folder. .INPUTS [System.String] Accepts string objects via the RepoURL parameter. .OUTPUTS [GitRepo] [System.IO.DirectoryInfo] Returns either a custom GitRepo object or a System.IO.DirectoryInfo object. The DirectoryInfo property of the GitRepo object contains the System.IO.DirectoryInfo object for the repository. .NOTES Author : nmbell .LINK Find-GitRepo .LINK Get-GitRepo .LINK Set-GitRepo .LINK New-GitRepo .LINK Remove-GitRepo .LINK Add-PowdrgitPath .LINK Remove-PowdrgitPath .LINK Test-PowdrgitPath .LINK about_powdrgit .LINK https://github.com/nmbell/powdrgit/blob/main/help/about_powdrgit.md #> # Function alias [Alias('igc')] # Use cmdlet binding [CmdletBinding( DefaultParameterSetName = 'ParentDir' , SupportsShouldProcess = $true , ConfirmImpact = 'Medium' , HelpURI = 'https://github.com/nmbell/powdrgit/blob/main/help/Invoke-GitClone.md' )] # Declare output type [OutputType('GitRepo' , ParameterSetName = ('ParentDir','UseDefaultDir'))] [OutputType([System.IO.DirectoryInfo], ParameterSetName = ('ParentDir','UseDefaultDir'))] # Declare parameters Param( [Parameter( Mandatory = $true , HelpMessage = 'Enter the URL of the git repository to clone.' , Position = 0 , ValueFromPipeline = $true , ValueFromPipelineByPropertyName = $true )] [ValidateNotNullOrEmpty()] [String] $RepoURL , [Parameter( Mandatory = $false , Position = 1 , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $true , ParameterSetName = 'ParentDir' )] [ValidateNotNullOrEmpty()] [Alias('FullName','Path')] [String] $ParentDir , [Parameter( Mandatory = $false , Position = 2 , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $true )] [ValidateNotNullOrEmpty()] [String] $RepoName , [Parameter( ParameterSetName = 'UseDefaultDir' )] [Switch] $UseDefaultDir , [Switch] $AppendPowdrgitPath , [Switch] $SetLocation ) BEGIN { $bk = 'B' # Common BEGIN: Set-StrictMode -Version 3.0 $thisFunctionName = $MyInvocation.MyCommand $start = Get-Date $indent = ($Powdrgit.DebugIndentChar[0]+' ')*($PowdrgitCallDepth++) $PSDefaultParameterValues += @{ '*:Verbose' = $(If ($DebugPreference -notin 'Ignore','SilentlyContinue') { $DebugPreference } Else { $VerbosePreference }) } # turn on Verbose with Debug $warn = $Powdrgit.ShowWarnings -and !($PSBoundParameters.ContainsKey('WarningAction') -and $PSBoundParameters.WarningAction -eq 'Ignore') # because -WarningAction:Ignore is not implemented correctly Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Start: $($start.ToString('yyyy-MM-dd HH:mm:ss.fff'))" # Function BEGIN: } PROCESS { $bk = 'P' Try { $gitCloneUrl = $null $gitClonePath = $null # Determine URL to clone from Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Determining URL to clone from" $gitCloneUrl = $RepoURL $cloneUrlMatchString = '^((https?|ftps?|git|ssh)://|[A-Z]:\\|\\\\)' $cloneUrlPlaceholder = '<RepoURL>' If ($RepoURL -notmatch $cloneUrlMatchString) # assumes a repository under the default URL root is intended { If (!$Powdrgit.DefaultCloneUrl) { Write-Error '$Powdrgit.DefaultCloneUrl is not defined.' -ErrorAction Stop } If ($Powdrgit.DefaultCloneUrl -notmatch $cloneUrlMatchString) { Write-Error '$Powdrgit.DefaultCloneUrl is not properly defined. Should start with one of the following: http://, https://, ftp://, ftps://, git://, ssh://, [A-Z]:\, \\' -ErrorAction Stop } If ($Powdrgit.DefaultCloneUrl -notlike "*$cloneUrlPlaceholder*") { Write-Error "`$Powdrgit.DefaultCloneUrl is not properly defined. Should be like *$cloneUrlPlaceholder*." -ErrorAction Stop } $gitCloneUrl = $Powdrgit.DefaultCloneUrl -replace $cloneUrlPlaceholder,$RepoURL } If (!$gitCloneUrl) { Write-Error 'URL to clone from could not be determined.' -ErrorAction Stop } If ($gitCloneUrl -notmatch $cloneUrlMatchString) { Write-Error "URL to clone from is not valid: $gitCloneUrl" -ErrorAction Stop } Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Will clone from: $gitCloneUrl" # Determine path to clone to Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Determining path to clone to" $gitClonePath = $PWD.Path # default to current location If ($UseDefaultDir) { If (Test-PowdrgitDefaultDir) { $gitClonePath = $Powdrgit.DefaultDir } Else { $warn = $false # Test-PowdrgitDefaultDir will generate a warning if necessary Write-Error $gitClonePath -ErrorAction Stop } } If ($ParentDir) { $gitClonePath = $ParentDir } If (!$PSBoundParameters.ContainsKey('RepoName')) { $RepoName = (Split-Path -Path $gitCloneUrl -Leaf) -replace '\.git$','' } $gitClonePath = Join-Path -Path $gitClonePath -ChildPath $RepoName If (!$gitClonePath) { Write-Error 'Path to clone to could not be determined.' -ErrorAction Stop } Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Will clone to : $gitClonePath" # Determine procession $shouldText = ("Cloning: $gitCloneUrl >> $gitClonePath") If ($WhatIfPreference) { Write-Host } $shouldProcess = $PSCmdlet.ShouldProcess($shouldText,$null,$null) # Clone the repository # If ($WhatIfPreference) { Write-Host "What if: $shouldText" } # handled by ShouldProcess If ($shouldProcess) { Write-Verbose "$(ts)$indent[$thisFunctionName][$bk]$shouldText" $pc = 0 $gitCommand = "git clone `"$gitCloneUrl`" `"$gitClonePath`"" Invoke-GitExpression -Command "$gitCommand --progress" ` | ForEach-Object { If ($_ -match "Cloning into '(.*)'...") { Write-Progress -Activity $gitCommand -Status ' ' -CurrentOperation $_ -PercentComplete $pc } ElseIf ($_ -match '^(remote|Receiving objects|Resolving deltas|Updating files):' ) { $Matches = $null If($_ -match '(\d+)%') { $pc = $Matches[1] } Write-Progress -Activity $gitCommand -Status ' ' -CurrentOperation $_ -PercentComplete $pc } ElseIf ($_ -like 'fatal:*') { Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Repository was not cloned." Write-Error $_ -ErrorAction Stop } } Write-Progress -Activity $gitCommand -Completed } # Add to the $Powdrgit.Path variable If ($AppendPowdrgitPath) { $shouldText = 'Adding path to `$Powdrgit.Path' If ($WhatIfPreference) { Write-Host "What if: $shouldText" } If ($shouldProcess) { Write-Debug " $(ts)$indent[$thisFunctionName][$bk]$shouldText" Add-PowdrgitPath -Path "$gitClonePath" -WhatIf:$false -Confirm:$false } } # Return the repository directory If ($AppendPowdrgitPath) { $shouldText = 'Returning [GitRepo]' If ($WhatIfPreference) { Write-Host "What if: $shouldText" } If ($shouldProcess) { Write-Debug " $(ts)$indent[$thisFunctionName][$bk]$shouldText" Get-GitRepo -Repo "$gitClonePath" } } Else { $shouldText = 'Returning [System.IO.DirectoryInfo]' If ($WhatIfPreference) { Write-Host "What if: $shouldText" } If ($shouldProcess) { Write-Debug " $(ts)$indent[$thisFunctionName][$bk]$shouldText" Get-Item -Path "$gitClonePath" } } } Catch { If ($warn) { Write-Warning "[$thisFunctionName]$_" } } } END { $bk = 'E' # Function END: # Set location to the repository directory If ($SetLocation) { $shouldText = "Setting location to: $gitClonePath" If ($WhatIfPreference) { Write-Host; Write-Host "What if: $shouldText" } If ($shouldProcess) { Write-Debug " $(ts)$indent[$thisFunctionName][$bk]$shouldText" Set-Location -Path "$gitClonePath" -ErrorAction Ignore } } If ($WhatIfPreference) { Write-Host } # Common END: $end = Get-Date $duration = New-TimeSpan -Start $start -End $end Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Finish: $($end.ToString('yyyy-MM-dd HH:mm:ss.fff')) ($($duration.ToString('d\d\ hh\:mm\:ss\.fff')))" $PowdrgitCallDepth-- } } |