Skip to content

Commit f02050d

Browse files
authored
Merge pull request #134 from PrincipleStudios/feature/refactor-release
Refactor `release` function
2 parents f6de7bd + 15c2bea commit f02050d

17 files changed

+653
-263
lines changed

docs/release.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
Usage:
44

5-
git-release.ps1 [-sourceBranch] <string> [-target] <string>
6-
[-comment <string>] [-preserve <string[]>] [-dryRun] [-cleanupOnly]
5+
git-release.ps1 [-source] <string> [-target] <string>
6+
[-comment <string>] [-preserve <string[]>] [-cleanupOnly] [-force]
7+
[-noFetch] [-dryRun] [-quiet]
78

89
## Parameters
910

10-
### `[-sourceBranch] <string>` (Mandatory)
11+
### `[-source] <string>` (Mandatory)
1112

1213
The name of the branch to "release".
1314

@@ -26,12 +27,27 @@ branch.
2627

2728
A comma delimited list of branches to preserve in addition to those upstream
2829

30+
### `-cleanupOnly` (Optional)
31+
32+
Use this flag when the released branch (from `-branchName`) was already merged
33+
to the target branch (`-target`) to clean up the included branches.
34+
35+
### `-force` (Optional)
36+
37+
Bypasses up-to-date checks for the source, target, and all branches being
38+
removed.
39+
40+
## `-noFetch` (Optional)
41+
42+
By default, all scripts fetch the latest before processing. To skip this (which
43+
was the old behavior), include `-noFetch`.
44+
2945
### `-dryRun` (Optional)
3046

3147
If specified, changes to branches will be displayed but no actual changes will
3248
be applied.
3349

34-
### `-cleanupOnly` (Optional)
50+
## `-quiet` (Optional)
3551

36-
Use this flag when the released branch (from `-branchName`) was already merged
37-
to the target branch (`-target`) to clean up the included branches.
52+
Suppress unnecessary output. Useful when a tool is designed to consume the
53+
output of this script via git rather than via PowerShell.

git-release.ps1

Lines changed: 121 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,151 @@
11
#!/usr/bin/env pwsh
22

33
Param(
4-
[Parameter(Mandatory)][String] $sourceBranch,
5-
[Parameter(Mandatory)][String] $target,
4+
[Parameter(Mandatory)][Alias('sourceBranch')][String] $source,
5+
[Parameter(Mandatory)][Alias('targetBranch')][String] $target,
66
[Parameter()][Alias('message')][Alias('m')][string] $comment,
7-
[Parameter()][String[]] $preserve,
8-
[switch] $dryRun,
9-
[switch] $cleanupOnly
7+
[Parameter()][String[]] $preserve = @(),
8+
[switch] $cleanupOnly,
9+
[switch] $force,
10+
[switch] $noFetch,
11+
[switch] $quiet,
12+
[switch] $dryRun
1013
)
1114

12-
. $PSScriptRoot/config/core/coalesce.ps1
13-
. $PSScriptRoot/config/core/ArrayToHash.ps1
1415
Import-Module -Scope Local "$PSScriptRoot/utils/query-state.psm1"
15-
Import-Module -Scope Local "$PSScriptRoot/config/git/Get-GitFileNames.psm1"
16-
Import-Module -Scope Local "$PSScriptRoot/config/git/Set-MultipleUpstreamBranches.psm1"
16+
Import-Module -Scope Local "$PSScriptRoot/utils/framework.psm1"
17+
Import-Module -Scope Local "$PSScriptRoot/utils/actions.psm1"
1718

19+
$diagnostics = New-Diagnostics
1820
$config = Get-Configuration
21+
if (-not $noFetch) {
22+
Update-GitRemote -quiet:$quiet
23+
}
1924

20-
Update-GitRemote
25+
$commonParams = @{
26+
diagnostics = $diagnostics
27+
}
2128

22-
if ($cleanupOnly) {
23-
# Verify that $target already has all of $sourceBranch
24-
$count = git rev-list ($config.remote -eq $nil ? $sourceBranch : "$($config.remote)/$($sourceBranch)") "^$($config.remote -eq $nil ? $target : "$($config.remote)/$($target)")" --count
25-
if ($count -ne 0) {
26-
throw "Found $count commits in $sourceBranch that were not included in $target"
27-
}
28-
} else {
29-
$count = git rev-list ($config.remote -eq $nil ? $target : "$($config.remote)/$($target)") "^$($config.remote -eq $nil ? $sourceBranch : "$($config.remote)/$($sourceBranch)")" --count
30-
if ($count -ne 0) {
31-
throw "Could not fast-forward $target to $sourceBranch; $count commits in $target that were not included in $sourceBranch"
29+
# Assert up-to-date
30+
# a) if $cleanupOnly, ensure no commits are in source that are not in target
31+
# b) otherwise, ensure no commits are in target that are not in source
32+
if (-not $force) {
33+
Invoke-LocalAction @commonParams @{
34+
type = 'assert-updated'
35+
parameters = $cleanupOnly `
36+
? @{ downstream = $target; upstream = $source }
37+
: @{ downstream = $source; upstream = $target }
3238
}
39+
Assert-Diagnostics $diagnostics
3340
}
3441

35-
$allPreserve = [String[]](@($target, $preserve) | ForEach-Object { $_ } | Select-Object -uniq)
36-
37-
$allUpstream = Select-UpstreamBranches $sourceBranch -recurse
42+
# $toRemove = (git show-upstream $source -recurse) without ($target, git show-upstream $target -recurse, $preserve)
43+
$sourceUpstream = Invoke-LocalAction @commonParams @{
44+
type = 'get-upstream'
45+
parameters = @{ target = $source; recurse = $true }
46+
}
47+
Assert-Diagnostics $diagnostics
3848

39-
$upstreamCache = @($allUpstream, $allPreserve) | ForEach-Object { $_ } | ArrayToHash -getValue { Select-UpstreamBranches $_ -recurse }
49+
$targetUpstream = Invoke-LocalAction @commonParams @{
50+
type = 'get-upstream'
51+
parameters = @{ target = $target; recurse = $true }
52+
}
53+
Assert-Diagnostics $diagnostics
54+
55+
[string[]]$keep = @($target) + $targetUpstream + $preserve
56+
[string[]]$toRemove = (@($source) + $sourceUpstream) | Where-Object { $_ -notin $keep }
57+
58+
# Assert all branches removed are up-to-date, unless $force is set
59+
if (-not $force) {
60+
foreach ($branch in $toRemove) {
61+
if ($branch -eq $source) { continue }
62+
Invoke-LocalAction @commonParams @{
63+
type = 'assert-updated'
64+
parameters = @{ downstream = $cleanupOnly ? $target : $source; upstream = $branch }
65+
}
66+
}
67+
Assert-Diagnostics $diagnostics
68+
}
4069

41-
$preservedUpstream = [String[]]($allPreserve
42-
| ForEach-Object { $_; $upstreamCache[$_] }
43-
| ForEach-Object { $_ }
44-
| Select-Object -uniq)
70+
# For all branches:
71+
# 1. Replace $toRemove branches with $target
72+
# 2. Simplify (new)
4573

46-
$toRemove = @($allUpstream, $sourceBranch) | ForEach-Object { $_ } | Select-Object -uniq | Where-Object { $preservedUpstream -notcontains $_ }
74+
$originalUpstreams = Invoke-LocalAction @commonParams @{
75+
type = 'get-all-upstreams'
76+
parameters= @{}
77+
}
78+
Assert-Diagnostics $diagnostics
4779

48-
function Invoke-RemoveBranches($branch) {
49-
if ($toRemove -contains $branch) {
50-
return $upstreamCache[$branch] | ForEach-Object { Invoke-RemoveBranches $_ } | Foreach-Object { $_ } | Select-Object -uniq
80+
$resultUpstreams = @{}
81+
foreach ($branch in $originalUpstreams.Keys) {
82+
if ($branch -in $toRemove) {
83+
$resultUpstreams[$branch] = $null
84+
continue
85+
}
86+
87+
if ($originalUpstreams[$branch] | Where-Object { $_ -in $toRemove }) {
88+
$resultUpstreams[$branch] = Invoke-LocalAction @commonParams @{
89+
type = 'filter-branches'
90+
parameters = @{
91+
include = @($target) + $originalUpstreams[$branch]
92+
exclude = $toRemove
93+
}
94+
}
95+
Assert-Diagnostics $diagnostics
5196
}
52-
return $branch
5397
}
5498

55-
$updates = Get-GitFileNames -branchName $config.upstreamBranch -remote $config.remote | ForEach-Object {
56-
if ($toRemove -contains $_) { return $nil }
57-
$upstream = Select-UpstreamBranches $_
58-
if (($upstream | Where-Object { $toRemove -contains $_ })) {
59-
# Needs to change
60-
return @{
61-
branch = $_
62-
newUpstream = [string[]]($upstream | ForEach-Object { Invoke-RemoveBranches $_ } | ForEach-Object { $_ } | Select-Object -uniq)
99+
$keys = @() + $resultUpstreams.Keys
100+
foreach ($branch in $keys) {
101+
if (-not $resultUpstreams[$branch]) { continue }
102+
$resultUpstreams[$branch] = Invoke-LocalAction @commonParams @{
103+
type = 'simplify-upstream'
104+
parameters = @{
105+
upstreamBranches = $resultUpstreams[$branch]
106+
overrideUpstreams = $resultUpstreams
107+
branchName = $branch
63108
}
64109
}
65-
return $nil
66-
} | Where-Object { $_ -ne $nil }
110+
Assert-Diagnostics $diagnostics
111+
}
67112

68-
if ($dryRun) {
69-
if (-not $cleanupOnly) {
70-
Write-Host "Would push $sourceBranch to $target"
71-
}
72-
Write-Host "Would remove $toRemove"
73-
Write-Host "Would perform updates: $(ConvertTo-Json $updates)"
74-
} else {
75-
$commitMessage = "Release $sourceBranch to $target$($comment -eq $nil -or $comment -eq '' ? '' : "`n`n$comment")"
76-
$upstreamContents = $updates | ArrayToHash -getKey { $_.branch } -getValue { $_.newUpstream }
77-
$upstreamContents[$sourceBranch] = $nil
78-
$toRemove | ForEach-Object {
79-
$upstreamContents[$_] = $nil
113+
$upstreamHash = Invoke-LocalAction @commonParams @{
114+
type = 'set-upstream'
115+
parameters = @{
116+
upstreamBranches = $resultUpstreams
117+
message = "Release $($source) to $($target)$($comment -eq '' ? '' : " for $($params.comment)")"
80118
}
81-
$commitish = Set-MultipleUpstreamBranches $upstreamContents -m $commitMessage
119+
}
120+
Assert-Diagnostics $diagnostics
82121

83-
if ($config.remote -ne $nil) {
84-
$gitDeletions = [String[]]($toRemove | ForEach-Object { ":$_" })
122+
$sourceHash = Get-BranchCommit (Get-RemoteBranchRef $source)
85123

86-
$atomicPart = $config.atomicPushEnabled ? @("--atomic") : @()
87-
$releasePart = $cleanupOnly ? @() : @("$($config.remote)/$($sourceBranch):$target")
124+
# Finalize:
125+
# 1. Push the following:
126+
# - Update _upstream
127+
# - Delete $toRemove branches
128+
# - If not $cleanupOnly, push $source commitish to $target
88129

89-
git push @atomicPart $config.remote @releasePart @gitDeletions "$($commitish):refs/heads/$($config.upstreamBranch)"
90-
} else {
91-
git branch -f $config.upstreamBranch $commitish
92-
if (-not $cleanupOnly) {
93-
git branch -f $sourceBranch $target
94-
}
95-
$toRemove | ForEach-Object {
96-
git branch -D $_
97-
}
130+
$commonParams = @{
131+
diagnostics = $diagnostics
132+
dryRun = $dryRun
133+
}
134+
135+
$resultBranches = @{
136+
"$($config.upstreamBranch)" = $upstreamHash.commit
137+
}
138+
foreach ($branch in $toRemove) {
139+
$resultBranches[$branch] = $null
140+
}
141+
if (-not $cleanupOnly) {
142+
$resultBranches[$target] = $sourceHash
143+
}
144+
145+
Invoke-FinalizeAction @commonParams @{
146+
type = 'set-branches'
147+
parameters = @{
148+
branches = $resultBranches
98149
}
99150
}
151+
Assert-Diagnostics $diagnostics

0 commit comments

Comments
 (0)