#!/usr/bin/env pwsh <# .SYNOPSIS Updates git submodules and generates a commit message with the list of changes .PARAMETER GitAuthorName The author name to use in the commit message. (Optional) .PARAMETER GitAuthorEmail The author email to use in the commit message. (Optional) .PARAMETER GitCommitArgs Additional arguments to pass into git-commit .PARAMETER NoCommit Make changes without executing git-commit .PARAMETER Force Specified this to make a commit with any changes #> [cmdletbinding(SupportsShouldProcess = $true)] param( [string]$GitAuthorName = $null, [string]$GitAuthorEmail = $null, [string[]]$GitCommitArgs = @(), [switch]$NoCommit, [switch]$Force ) $ErrorActionPreference = 'Stop' Set-StrictMode -Version 2 $RepoRoot = Resolve-Path "$PSScriptRoot\.." $ModuleDirectory = Join-Path $RepoRoot "modules" Import-Module "$PSScriptRoot/common.psm1" -Scope Local -Force function Get-GitChanges([string]$Path) { Write-Verbose "git diff --cached --quiet $Path" & git diff --cached --quiet $Path | Out-Null if ($LastExitCode -ne 0) { return $true } Write-Verbose "git diff --quiet $Path" & git diff --quiet $Path | Out-Null return $LastExitCode -ne 0 } Push-Location $RepoRoot | Out-Null try { Assert-Git Write-Host "Checking that submodules are in a clean state first..." if (Get-GitChanges $ModuleDirectory) { Write-Error "$RepoRoot/modules is in an unclean state. Reset submodules first by running ``git submodule update``" exit 1 } $submodules = Get-Submodules $RepoRoot -Verbose:$VerbosePreference foreach ($submodule in $submodules) { $submodulePath = $submodule.path Write-Host "Updating $submodulePath" $vcs_name = "BUILD_VCS_NUMBER_" + $submodule.module $newCommit = [environment]::GetEnvironmentVariable($vcs_name) if (-not $newCommit) { Write-Warning "TeamCity env variable '$vcs_name' not found. Pulling the latest submodule branch instead" Invoke-Block { & git submodule update --remote $submodulePath } Push-Location $submodulePath | Out-Null try { $newCommit = $(git rev-parse HEAD) } finally { Pop-Location | Out-Null } } else { Push-Location $submodulePath | Out-Null try { Invoke-Block { & git checkout $newCommit } } finally { Pop-Location | Out-Null } } $submodule.newCommit = $newCommit if ($newCommit -ne $submodule.commit) { $submodule.changed = $true Write-Host -ForegroundColor Cyan "`t=> $($submodule.module) updated to $($submodule.newCommit)" } else { Write-Host -ForegroundColor Magenta "`t$($submodule.module) did not change" } } $changes = $submodules ` | ? { $_.changed } ` | % { Invoke-Block { & git add $_.path } "$($_.module) => $($_.newCommit)" } if ($changes) { $shortMessage = "Updating submodule(s) `n`n$( $changes -join "`n" )" # add this to the commit message to make it possible to filter commit triggers based on message $message = "$shortMessage`n`n[auto-updated: submodules]" if (-not $NoCommit -and ($Force -or ($PSCmdlet.ShouldContinue($shortMessage, 'Create a new commit with these changes?')))) { $gitConfigArgs = @() if ($GitAuthorName) { $gitConfigArgs += '-c',"user.name=$GitAuthorName" } if ($GitAuthorEmail) { $gitConfigArgs += '-c',"user.email=$GitAuthorEmail" } Invoke-Block { & git @gitConfigArgs commit -m $message @GitCommitArgs } } else { # If composing this script with others, return the message that would have been used return @{ message = $message } } } else { Write-Host -ForegroundColor Magenta 'No changes detected in git submodules' } } finally { Pop-Location }