VeilVer.psm1
#Region './Private/Get-GitBlobTags.ps1' -1 function Get-GitBlobTags { [CmdletBinding()] param ( # Does not need to exist anymore, but must be a valid path [Parameter(Mandatory)] [ValidateScript({ Test-Path $_ -IsValid }, ErrorMessage = 'Must be a valid path format, but does not need to exist (anymore).')] [string]$RelativeRootPath ) # Example tag: VV/demo/docs/Contoso/Doc1.md/v1.0.0 $TagPattern = "VV/$RelativeRootPath/v*" # Get tags with version data split by semicolon, sorted by version in descending order $Tags = Invoke-GitCommand 'tag', '--list', '--format=%(refname:short);%(contents)', '--sort=-version:refname', $TagPattern | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $Tag, $Base64Data = $_ -split ';' $TagVersionString = ($Tag -split '/')[-1].TrimStart('v') $TagVersion = [version]$TagVersionString # The tag command returns an empty line as part of the tag message, so we need to filter it out $JsonData = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Base64Data)) $Metadata = $JsonData | ConvertFrom-Json [pscustomobject]@{ 'File' = $RelativeRootPath 'Tag' = $Tag 'Version' = $TagVersion 'Metadata' = $Metadata } } if ($Tags.Count -eq 0) { return } Write-Verbose @" Found the following hidden version tag(s) for the path '$RelativeRootPath': - $(($Tags | ForEach-Object { $_.Version }) -join "`n- ") "@ Write-Output $Tags } #EndRegion './Private/Get-GitBlobTags.ps1' 45 #Region './Private/Get-GitCurrentCommit.ps1' -1 function Get-GitCurrentCommit { [CmdletBinding()] param () Invoke-GitCommand 'rev-parse', '--verify', 'HEAD' } #EndRegion './Private/Get-GitCurrentCommit.ps1' 7 #Region './Private/Get-GitFileHistoryNames.ps1' -1 function Get-GitFileHistoryNames { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Path ) # Get all names that the file has had by looking at commits that have changed the file # Automatically sorted by most recent (current) name first # Empty format string to only get the file names $FileNames = Invoke-GitCommand 'log', '--format=', '--name-only', '--follow', '--', $Path | Select-Object -Unique Write-Verbose @" Found the following file path(s) of the file from the commit history: - $($FileNames -join "`n- ") "@ Write-Output $FileNames } #EndRegion './Private/Get-GitFileHistoryNames.ps1' 20 #Region './Private/Get-GitRepoRoot.ps1' -1 function Get-GitRepoRoot { [CmdletBinding()] param() Invoke-GitCommand 'rev-parse', '--show-toplevel' } #EndRegion './Private/Get-GitRepoRoot.ps1' 7 #Region './Private/Invoke-GitCommand.ps1' -1 function Invoke-GitCommand { [CmdletBinding()] param( [Parameter(Mandatory)] [string[]]$Arguments ) Test-GitInstallation -ErrorAction Stop Write-Verbose "Invoking 'git $Arguments'." & git $Arguments if ($LASTEXITCODE -ne 0) { throw "Command 'git $Arguments' failed with exit code $LASTEXITCODE." } } #EndRegion './Private/Invoke-GitCommand.ps1' 18 #Region './Private/Remove-GitBlobTag.ps1' -1 function Remove-GitBlobTag { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$Tag ) Invoke-GitCommand 'tag', '--delete', $Tag } #EndRegion './Private/Remove-GitBlobTag.ps1' 10 #Region './Private/Test-GitFileIsModified.ps1' -1 function Test-GitFileIsModified { [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = 'Path must exist and be a file.')] [string]$Path ) try { $null = Invoke-GitCommand 'diff-index', 'HEAD', '--quiet', '--', $Path } catch {} # Returns true if the file has been modified $LASTEXITCODE -eq 1 } #EndRegion './Private/Test-GitFileIsModified.ps1' 16 #Region './Private/Test-GitInstallation.ps1' -1 function Test-GitInstallation { [CmdletBinding()] param() if (-not (Get-Command "git" -ErrorAction SilentlyContinue)) { throw 'No installation of git was found, please install git to use this module.' } } #EndRegion './Private/Test-GitInstallation.ps1' 9 #Region './Public/Get-VVVersion.ps1' -1 function Get-VVVersion { [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = 'Path must exist and be a file.')] [string]$Path ) # Get all tags based on file names $FileNames = Get-GitFileHistoryNames -Path $Path Write-Verbose @" Found the following file path(s) of the file through the commit history: - $($FileNames -join "`n- ") "@ $Tags = $FileNames | ForEach-Object { Get-GitBlobTags -RelativeRootPath $_ } if ($Tags.Count -eq 0) { Write-Warning "No hidden version tags found for the file '$Path'." return } Write-Output $Tags } #EndRegion './Public/Get-VVVersion.ps1' 26 #Region './Public/Remove-VVVersion.ps1' -1 function Remove-VVVersion { [CmdletBinding(DefaultParameterSetName = 'FileVersion')] param ( [Parameter(Mandatory, ParameterSetName = 'FileVersion')] [ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = 'Path must exist and be a file.')] [string]$Path, [Parameter(Mandatory, ParameterSetName = 'FileVersion')] [version]$Version, [Parameter(Mandatory, ParameterSetName = 'Tag')] [string]$Tag ) # If parameter set name if ($PSCmdlet.ParameterSetName -eq 'FileVersion') { # Get all tags based on file names $FileNames = Get-GitFileHistoryNames -Path $Path $Tags = $FileNames | ForEach-Object { Get-GitBlobTags -RelativeRootPath $_ } $Tag = $Tags | Where-Object { $_.Version -eq $Version } | Select-Object -ExpandProperty Tag if ($null -eq $Tag) { Write-Warning "No hidden version tags found for the file '$Path' with version '$Version'." return } } try { Remove-GitBlobTag -Tag $Tag -ErrorAction Stop Write-Verbose "Successfully removed the hidden version tag '$Tag'." } catch { throw "Failed to remove the hidden version tag '$Tag'." } } #EndRegion './Public/Remove-VVVersion.ps1' 41 #Region './Public/Set-VVVersion.ps1' -1 function Set-VVVersion { [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = 'Path must exist and be a file.')] [string]$Path, [Parameter(Mandatory)] [version]$Version, [Parameter(Mandatory)] [hashtable]$Metadata ) Push-Location (Get-GitRepoRoot) # Get the relative path of the file from the root of the repo and trim start $RelativePath = (Resolve-Path $Path -Relative).TrimStart('.\').TrimStart('./') $TagName = "VV/$RelativePath/v$Version" # Ensure that the file has no pending changes, since we are tagging the file content together with the commit and don't want any discrepancies if (Test-GitFileIsModified -Path $RelativePath) { Write-Warning "The file '$RelativePath' has been modified. Please commit the changes before setting the version." return } # Set extra metadata for the tag if ($Metadata.ContainsKey('Commit')) { Write-Warning "The 'Commit' key is reserved and will be overwritten." } $Metadata['Commit'] = Get-GitCurrentCommit # Assemble metadata, convert to JSON and then to Base64 $JsonMetadata = $Metadata | ConvertTo-Json -Compress -Depth 20 $Base64Metadata = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($JsonMetadata)) # Tag the file with the version data as json in the tag message $BlobHash = Invoke-GitCommand 'hash-object', '-t', 'blob', $Path Invoke-GitCommand 'tag', '-a', $TagName, $BlobHash, '-m', $Base64Metadata -ErrorAction Stop Write-Verbose "Hidden tag '$TagName' has been created for '$RelativePath'." } #EndRegion './Public/Set-VVVersion.ps1' 41 |