#!/usr/bin/env pwsh <# .SYNOPSIS Updates git submodules and generates a commit message with the list of changes .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[]]$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?')))) { Invoke-Block { & git 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 }