...
1 #!/usr/bin/env pwsh -c
2
3<#
4.DESCRIPTION
5Create local branch of the given repo and attempt to push changes. The push may fail if
6there has been other changes pushed to the same branch, if so, fetch, rebase and try again.
7.PARAMETER PRBranchName
8The name of the github branch the changes are being put into
9.PARAMETER CommitMsg
10The message for this particular commit
11.PARAMETER GitUrl
12The GitHub repository URL
13.PARAMETER PushArgs
14Optional arguments to the push command
15#>
16[CmdletBinding(SupportsShouldProcess = $true)]
17param(
18 [Parameter(Mandatory = $true)]
19 [string] $PRBranchName,
20
21 [Parameter(Mandatory = $true)]
22 [string] $CommitMsg,
23
24 [Parameter(Mandatory = $true)]
25 [string] $GitUrl,
26
27 [Parameter(Mandatory = $false)]
28 [string] $PushArgs = "",
29
30 [Parameter(Mandatory = $false)]
31 [string] $RemoteName = "azure-sdk-fork",
32
33 [Parameter(Mandatory = $false)]
34 [boolean] $SkipCommit = $false,
35
36 [Parameter(Mandatory = $false)]
37 [boolean] $AmendCommit = $false
38)
39
40# This is necessary because of the git command output writing to stderr.
41# Without explicitly setting the ErrorActionPreference to continue the script
42# would fail the first time git wrote command output.
43$ErrorActionPreference = "Continue"
44
45if ((git remote) -contains $RemoteName)
46{
47 Write-Host "git remote get-url $RemoteName"
48 $remoteUrl = git remote get-url $RemoteName
49 if ($remoteUrl -ne $GitUrl)
50 {
51 Write-Error "Remote with name $RemoteName already exists with an incompatible url [$remoteUrl] which should be [$GitUrl]."
52 exit 1
53 }
54}
55else
56{
57 Write-Host "git remote add $RemoteName $GitUrl"
58 git remote add $RemoteName $GitUrl
59 if ($LASTEXITCODE -ne 0)
60 {
61 Write-Error "Unable to add remote LASTEXITCODE=$($LASTEXITCODE), see command output above."
62 exit $LASTEXITCODE
63 }
64}
65# Checkout to $PRBranch, create new one if not exists.
66git show-ref --verify --quiet refs/heads/$PRBranchName
67if ($LASTEXITCODE -eq 0) {
68 Write-Host "git checkout $PRBranchName."
69 git checkout $PRBranchName
70}
71else {
72 Write-Host "git checkout -b $PRBranchName."
73 git checkout -b $PRBranchName
74}
75if ($LASTEXITCODE -ne 0)
76{
77 Write-Error "Unable to create branch LASTEXITCODE=$($LASTEXITCODE), see command output above."
78 exit $LASTEXITCODE
79}
80
81if (!$SkipCommit) {
82 if ($AmendCommit) {
83 $amendOption = "--amend"
84 }
85 else {
86 $amendOption = ""
87 }
88 Write-Host "git -c user.name=`"azure-sdk`" -c user.email=`"azuresdk@microsoft.com`" commit $amendOption -am `"$($CommitMsg)`""
89 git -c user.name="azure-sdk" -c user.email="azuresdk@microsoft.com" commit $amendOption -am "$($CommitMsg)"
90 if ($LASTEXITCODE -ne 0)
91 {
92 Write-Error "Unable to add files and create commit LASTEXITCODE=$($LASTEXITCODE), see command output above."
93 exit $LASTEXITCODE
94 }
95}
96else {
97 Write-Host "Skipped applying commit"
98}
99
100# The number of retries can be increased if necessary. In theory, the number of retries
101# should be the max number of libraries in the largest pipeline -1 as everything except
102# the first commit could hit issues and need to rebase. The reason this isn't set to that
103# is because the largest pipeline is cognitive services which has 18 libraries in its
104# pipeline and that just seemed a bit too large and 10 seemed like a good starting value.
105$numberOfRetries = 10
106$needsRetry = $false
107$tryNumber = 0
108do
109{
110 $needsRetry = $false
111 Write-Host "git push $RemoteName $PRBranchName $PushArgs"
112 git push $RemoteName $PRBranchName $PushArgs
113 $tryNumber++
114 if ($LASTEXITCODE -ne 0)
115 {
116 $needsRetry = $true
117 Write-Host "Git push failed with LASTEXITCODE=$($LASTEXITCODE) Need to fetch and rebase: attempt number=$($tryNumber)"
118
119 Write-Host "git fetch $RemoteName $PRBranchName"
120 # Full fetch will fail when the repo is in a sparse-checkout state, and single branch fetch is faster anyway.
121 git fetch $RemoteName $PRBranchName
122 if ($LASTEXITCODE -ne 0)
123 {
124 Write-Error "Unable to fetch remote LASTEXITCODE=$($LASTEXITCODE), see command output above."
125 exit $LASTEXITCODE
126 }
127
128 try
129 {
130 $TempPatchFile = New-TemporaryFile
131 Write-Host "git diff ${PRBranchName}~ ${PRBranchName} --output $TempPatchFile"
132 git diff ${PRBranchName}~ ${PRBranchName} --output $TempPatchFile
133 if ($LASTEXITCODE -ne 0)
134 {
135 Write-Error "Unable to create diff file LASTEXITCODE=$($LASTEXITCODE), see command output above."
136 continue
137 }
138
139 Write-Host "git reset --hard $RemoteName/${PRBranchName}"
140 git reset --hard $RemoteName/${PRBranchName}
141 if ($LASTEXITCODE -ne 0)
142 {
143 Write-Error "Unable to hard reset branch LASTEXITCODE=$($LASTEXITCODE), see command output above."
144 continue
145 }
146
147 # -C0 means to use no extra before or after lines of context to enable us to avoid adjacent line merge conflicts
148 Write-Host "git apply -C0 $TempPatchFile"
149 git apply -C0 $TempPatchFile
150 if ($LASTEXITCODE -ne 0)
151 {
152 Write-Error "Unable to apply diff file LASTEXITCODE=$($LASTEXITCODE), see command output above."
153 exit $LASTEXITCODE
154 }
155
156
157 Write-Host "git add -A"
158 git add -A
159 if ($LASTEXITCODE -ne 0)
160 {
161 Write-Error "Unable to git add LASTEXITCODE=$($LASTEXITCODE), see command output above."
162 continue
163 }
164
165 Write-Host "git -c user.name=`"azure-sdk`" -c user.email=`"azuresdk@microsoft.com`" commit -m `"$($CommitMsg)`""
166 git -c user.name="azure-sdk" -c user.email="azuresdk@microsoft.com" commit -m "$($CommitMsg)"
167 if ($LASTEXITCODE -ne 0)
168 {
169 Write-Error "Unable to commit LASTEXITCODE=$($LASTEXITCODE), see command output above."
170 continue
171 }
172 }
173 finally
174 {
175 if ( Test-Path $TempPatchFile )
176 {
177 Remove-Item $TempPatchFile
178 }
179 }
180 }
181} while($needsRetry -and $tryNumber -le $numberOfRetries)
182
183if ($LASTEXITCODE -ne 0 -or $tryNumber -gt $numberOfRetries)
184{
185 Write-Error "Unable to push commit after $($tryNumber) retries LASTEXITCODE=$($LASTEXITCODE), see command output above."
186 if (0 -eq $LASTEXITCODE)
187 {
188 exit 1
189 }
190 exit $LASTEXITCODE
191}
View as plain text