|
| 1 | +#!/usr/bin/env pwsh -c |
| 2 | + |
| 3 | +<# |
| 4 | +.SYNOPSIS |
| 5 | + Updates git submodules and generates a commit message with the list of changes |
| 6 | +.PARAMETER GitAuthorName |
| 7 | + The author name to use in the commit message. (Optional) |
| 8 | +.PARAMETER GitAuthorEmail |
| 9 | + The author email to use in the commit message. (Optional) |
| 10 | +.PARAMETER GitCommitArgs |
| 11 | + Additional arguments to pass into git-commit |
| 12 | +.PARAMETER NoCommit |
| 13 | + Make changes without executing git-commit |
| 14 | +.PARAMETER Force |
| 15 | + Specified this to make a commit with any changes |
| 16 | +.PARAMETER IgnoredRepos |
| 17 | + Repos to not update (likely because they are temporarily broken). |
| 18 | +#> |
| 19 | +[cmdletbinding(SupportsShouldProcess = $true)] |
| 20 | +param( |
| 21 | + [string]$GitAuthorName = $null, |
| 22 | + [string]$GitAuthorEmail = $null, |
| 23 | + [string[]]$GitCommitArgs = @(), |
| 24 | + [switch]$NoCommit, |
| 25 | + [switch]$Force, |
| 26 | + [string[]]$IgnoredRepos = @() |
| 27 | +) |
| 28 | + |
| 29 | +$ErrorActionPreference = 'Stop' |
| 30 | +Set-StrictMode -Version 2 |
| 31 | + |
| 32 | +$RepoRoot = Resolve-Path "$PSScriptRoot\.." |
| 33 | +$ModuleDirectory = Join-Path $RepoRoot "modules" |
| 34 | + |
| 35 | +Import-Module "$PSScriptRoot/common.psm1" -Scope Local -Force |
| 36 | + |
| 37 | +function Get-GitChanges([string]$Path) { |
| 38 | + Write-Verbose "git diff --cached --quiet $Path" |
| 39 | + & git diff --cached --quiet $Path | Out-Null |
| 40 | + if ($LastExitCode -ne 0) { |
| 41 | + return $true |
| 42 | + } |
| 43 | + Write-Verbose "git diff --quiet $Path" |
| 44 | + & git diff --quiet $Path | Out-Null |
| 45 | + return $LastExitCode -ne 0 |
| 46 | +} |
| 47 | + |
| 48 | +Push-Location $RepoRoot | Out-Null |
| 49 | +try { |
| 50 | + Assert-Git |
| 51 | + |
| 52 | + Write-Host "Checking that submodules are in a clean state first..." |
| 53 | + if (Get-GitChanges $ModuleDirectory) { |
| 54 | + Write-Error "$RepoRoot/modules is in an unclean state. Reset submodules first by running ``git submodule update``" |
| 55 | + exit 1 |
| 56 | + } |
| 57 | + |
| 58 | + $submodules = Get-Submodules $RepoRoot -Verbose:$VerbosePreference |
| 59 | + |
| 60 | + foreach ($submodule in $submodules) { |
| 61 | + $submoduleName = $submodule.module |
| 62 | + if ($IgnoredRepos.Contains($submoduleName)) |
| 63 | + { |
| 64 | + Write-Host "Skipping $submoduleName due to IgnoredRepos." |
| 65 | + continue |
| 66 | + } |
| 67 | + |
| 68 | + $submodulePath = $submodule.path |
| 69 | + Write-Host "Updating $submodulePath" |
| 70 | + |
| 71 | + $vcs_name = "BUILD_VCS_NUMBER_" + ($submodule.module -replace '\.','_') |
| 72 | + $newCommit = [environment]::GetEnvironmentVariable($vcs_name) |
| 73 | + |
| 74 | + if (-not $newCommit) { |
| 75 | + if ($env:TEAMCITY_PROJECT_NAME) { |
| 76 | + throw "TeamCity env variable '$vcs_name' not found. Make sure to configure a VCS root for $submodulePath" |
| 77 | + } |
| 78 | + Invoke-Block { & git submodule update --remote $submodulePath } |
| 79 | + Push-Location $submodulePath | Out-Null |
| 80 | + try { |
| 81 | + $newCommit = $(git rev-parse HEAD) |
| 82 | + } |
| 83 | + finally { |
| 84 | + Pop-Location | Out-Null |
| 85 | + } |
| 86 | + } |
| 87 | + else { |
| 88 | + Push-Location $submodulePath | Out-Null |
| 89 | + try { |
| 90 | + Invoke-Block { & git checkout $newCommit } |
| 91 | + } |
| 92 | + finally { |
| 93 | + Pop-Location | Out-Null |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + $submodule.newCommit = $newCommit |
| 98 | + if ($newCommit -ne $submodule.commit) { |
| 99 | + $submodule.changed = $true |
| 100 | + Write-Host -ForegroundColor Cyan "`t=> $($submodule.module) updated to $($submodule.newCommit)" |
| 101 | + } |
| 102 | + else { |
| 103 | + Write-Host -ForegroundColor Magenta "`t$($submodule.module) did not change" |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + $changes = $submodules ` |
| 108 | + | ? { $_.changed } ` |
| 109 | + | % { |
| 110 | + Invoke-Block { & git add $_.path } |
| 111 | + "$($_.module) => $($_.newCommit)" |
| 112 | + } |
| 113 | + |
| 114 | + if ($changes) { |
| 115 | + $shortMessage = "Updating submodule(s) `n`n$( $changes -join "`n" )" |
| 116 | + # add this to the commit message to make it possible to filter commit triggers based on message |
| 117 | + $message = "$shortMessage`n`n[auto-updated: submodules]" |
| 118 | + if (-not $NoCommit -and ($Force -or ($PSCmdlet.ShouldContinue($shortMessage, 'Create a new commit with these changes?')))) { |
| 119 | + |
| 120 | + $gitConfigArgs = @() |
| 121 | + if ($GitAuthorName) { |
| 122 | + $gitConfigArgs += '-c',"user.name=$GitAuthorName" |
| 123 | + } |
| 124 | + |
| 125 | + if ($GitAuthorEmail) { |
| 126 | + $gitConfigArgs += '-c',"user.email=$GitAuthorEmail" |
| 127 | + } |
| 128 | + |
| 129 | + Invoke-Block { & git @gitConfigArgs commit -m $message @GitCommitArgs } |
| 130 | + } |
| 131 | + else { |
| 132 | + # If composing this script with others, return the message that would have been used |
| 133 | + return @{ |
| 134 | + message = $message |
| 135 | + } |
| 136 | + } |
| 137 | + } |
| 138 | + else { |
| 139 | + Write-Host -ForegroundColor Magenta 'No changes detected in git submodules' |
| 140 | + } |
| 141 | +} |
| 142 | +finally { |
| 143 | + Pop-Location |
| 144 | +} |
0 commit comments