Skip to content
This repository was archived by the owner on Feb 21, 2025. It is now read-only.

Commit 2837c02

Browse files
authored
Relocate pipeline YAML file from the yaml-templates repo (#27)
1 parent 187e76d commit 2837c02

File tree

1 file changed

+273
-0
lines changed

1 file changed

+273
-0
lines changed

backport-bot.yml

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
trigger: none
2+
3+
parameters:
4+
- name: BackportRepoName
5+
displayName: Backport Repository Name
6+
type: string
7+
- name: BackportRepoOrg
8+
displayName: Backport Repository Organization
9+
type: string
10+
- name: BackportTargetBranch
11+
displayName: Backport Target Branch
12+
type: string
13+
- name: BackportPRNumber
14+
displayName: Backport Pull Request Number
15+
type: number
16+
- name: BackportHeadSHA
17+
displayName: Tip of the source PR
18+
type: string
19+
- name: UseFork
20+
displayName: Use a fork to create PRs
21+
type: boolean
22+
default: false
23+
24+
variables:
25+
- name: GitHubEndpoint
26+
value: ${{ parameters.BackportRepoOrg }}
27+
- name: SourceRepo
28+
value: ${{ parameters.BackportRepoOrg }}/${{ parameters.BackportRepoName }}
29+
- name: TargetBranch
30+
value: ${{ parameters.BackportTargetBranch }}
31+
- name: SourceBranch
32+
value: "backport-pr-${{ parameters.BackportPRNumber }}-to-$(TargetBranch)"
33+
- group: Xamarin-Secrets
34+
- name: GitHubApiPrUri
35+
value: "https://api.github.com/repos/$(SourceRepo)/pulls/${{ parameters.BackportPRNumber }}"
36+
37+
resources:
38+
repositories:
39+
- repository: backportRepo
40+
type: github
41+
# TODO: is there a way to not hardcode the endpoint?
42+
endpoint: xamarin
43+
name: $(SourceRepo)
44+
ref: $(TargetBranch)
45+
46+
jobs:
47+
- job: BackportBot
48+
pool:
49+
vmImage: ubuntu-latest
50+
51+
variables:
52+
- name: ChangesPatch
53+
value: $(Build.ArtifactStagingDirectory)/changes.patch
54+
- name: WorkingDir
55+
value: $(Build.SourcesDirectory)/${{ parameters.BackportRepoName }}
56+
57+
steps:
58+
- checkout: self
59+
- checkout: backportRepo
60+
persistCredentials: true
61+
62+
- powershell: |
63+
Write-Host "BackportRepoName: ${{ parameters.BackportRepoName }}"
64+
Write-Host "BackportRepoOrg: ${{ parameters.BackportRepoOrg }}"
65+
Write-Host "BackportTargetBranch: ${{ parameters.BackportTargetBranch }}"
66+
Write-Host "BackportPRNumber: ${{ parameters.BackportPRNumber }}"
67+
Write-Host "BackportHeadSHA: ${{ parameters.BackportHeadSHA }}"
68+
Write-Host "UseFork: ${{ parameters.UseFork}}"
69+
displayName: Debug parameters
70+
71+
# TODO: redundant, but echo git version
72+
- powershell: |
73+
git --version
74+
git status > $(Build.ArtifactStagingDirectory)/git_status.txt
75+
Get-Content $(Build.ArtifactStagingDirectory)/git_status.txt
76+
git diff > $(Build.ArtifactStagingDirectory)/git_diff.txt
77+
git checkout -b $(SourceBranch)
78+
workingDirectory: $(WorkingDir)
79+
displayName: Checkout Backport Branch
80+
81+
- powershell: |
82+
$headers = @{ Authorization = "token $(github--pat--vs-mobiletools-engineering-service2)"; Accept = "application/vnd.github.v3.patch" }
83+
Write-Host "Grabbing PR Patch from ${{ variables.GitHubApiPrUri }}"
84+
Invoke-Webrequest -UseBasicParsing -OutFile $(ChangesPatch) -Headers $headers -Uri "${{ variables.GitHubApiPrUri }}"
85+
displayName: Grab Patch File
86+
87+
# TODO: try and grab PR author
88+
- powershell: |
89+
git config --global credential.helper store
90+
Set-Content -Path "$HOME\.git-credentials" -Value "https://$(github--pat--vs-mobiletools-engineering-service2):x-oauth-basic@github.com`n" -NoNewline
91+
git config user.email "valco@microsoft.com"
92+
git config user.name "vs-mobiletools-engineering-service2"
93+
Write-Host "git am $(ChangesPatch) --3way --ignore-whitespace --keep-non-patch --exclude=`"external/api-snapshot`""
94+
git am $(ChangesPatch) --3way --ignore-whitespace --keep-non-patch --exclude="external/api-snapshot" > $(Build.ArtifactStagingDirectory)/am_output.txt 2>&1
95+
$result = $(git status)
96+
if ($result.Contains("You are in the middle of an am session")) {
97+
throw "Merge conflict. Please backport manually"
98+
}
99+
workingDirectory: $(WorkingDir)
100+
displayName: Apply Patch
101+
102+
# - powershell: |
103+
# Write-Host "git filter-branch --prune-empty -f $(SourceRef)..HEAD"
104+
# git filter-branch --prune-empty -f $(SourceRef)..HEAD > $(Build.ArtifactStagingDirectory)/filter_status.txt 2>&1
105+
# workingDirectory: $(WorkingDir)
106+
# displayName: Filter Branch
107+
108+
# try to retrieve the repo for the bot, if not present, create it
109+
- powershell: |
110+
$headers = @{ Authorization = "token $(github--pat--vs-mobiletools-engineering-service2)"; Accept = "application/vnd.github.v3.patch" }
111+
try {
112+
$response = Invoke-Webrequest -UseBasicParsing -Headers $headers -Uri "https://api.github.com/repos/vs-mobiletools-engineering-service2/$Env:RepoName" | ConvertFrom-Json
113+
} catch {
114+
Write-Host "Fork was not found, creating one."
115+
# fork does not exist and has to be created, this is async, we are going to wait some time and then retry until we get that the fork was indeed created.
116+
$payload= @{
117+
owner = "vs-mobiletools-engineering-service2"
118+
repo = $Env:RepoName
119+
}
120+
try {
121+
$reposUri = "https://api.github.com/repos/$Env:RepoOrg/$Env:RepoName/forks"
122+
Write-Host "Creating fork via $reposUri and $($payload | ConvertTo-json )"
123+
$response = Invoke-Webrequest -Method POST -UseBasicParsing -Headers $headers -Uri $reposUri -Body ($payload | ConvertTo-json)
124+
Write-Host "Response was $response"
125+
$count = 0
126+
#give some time
127+
Start-Sleep -Seconds 5
128+
do {
129+
try {
130+
# if we do not have the fork just yet, an exception is thrown, we wait and try again
131+
$response = Invoke-Webrequest -UseBasicParsing -Headers $headers -Uri "https://api.github.com/repos/vs-mobiletools-engineering-service2/$Env:RepoName" | ConvertFrom-Json
132+
break
133+
} catch {
134+
if ($count -gt 10) {
135+
# notify and throw
136+
Write-Host "Could not access fork vs-mobiletools-engineering-service2/$Env:RepoName after 10 attempts."
137+
throw $_.Exception
138+
} else {
139+
$count = $count + 1
140+
$seconds = 5 * $count
141+
Write-Host "Error performing request trying in $seconds seconds"
142+
Start-Sleep -Seconds $seconds
143+
}
144+
}
145+
} while ($true)
146+
} catch {
147+
Write-Host "Could not create fork vs-mobiletools-engineering-service2/$Env:RepoName."
148+
throw $_.Exception
149+
}
150+
}
151+
Write-Host "Adding remote to local git."
152+
# add remote so that we do push there
153+
$remoteUrl = "https://github.com/vs-mobiletools-engineering-service2/" + $Env:RepoName + ".git"
154+
Write-Host "Using remote at '$remoteUrl'"
155+
git remote add vs-mobiletools-engineering-service2 $remoteUrl
156+
git remote -v
157+
workingDirectory: $(WorkingDir)
158+
displayName: Create fork
159+
condition: ${{ parameters.UseFork }}
160+
env:
161+
RepoName: ${{ parameters.BackportRepoName }}
162+
RepoOrg: ${{ parameters.BackportRepoOrg }}
163+
164+
- powershell: |
165+
git push -f -u vs-mobiletools-engineering-service2 HEAD:$(SourceBranch)
166+
workingDirectory: $(WorkingDir)
167+
displayName: Push Branch to Fork
168+
condition: ${{ parameters.UseFork }}
169+
170+
- powershell: |
171+
git push -f -u origin HEAD:$(SourceBranch)
172+
workingDirectory: $(WorkingDir)
173+
displayName: Push Branch
174+
condition: not(${{ parameters.UseFork }})
175+
176+
# Grab PR details and
177+
- powershell: |
178+
Write-Host "Grabbing PR details from ${{ variables.GitHubApiPrUri }}"
179+
$headers = @{ Authorization = "token $(github--pat--vs-mobiletools-engineering-service2)"; Accept = "application/json" }
180+
$response = Invoke-WebRequest -Headers $headers -uri "${{ variables.GitHubApiPrUri }}"
181+
$content = $response.Content | ConvertFrom-Json
182+
$title = "[$(TargetBranch)] $($content.title)" -replace '[\u00A0]', ' '
183+
184+
# pws + json does not like /n but append line works
185+
$msg = [System.Text.StringBuilder]::new()
186+
$msg.AppendLine("$($content.body)")
187+
$msg.AppendLine()
188+
$msg.AppendLine()
189+
$msg.AppendLine("Backport of #${{ parameters.BackportPRNumber }}")
190+
191+
Write-Host "Use Fork? $Env:UseFork"
192+
$head = "$(SourceBranch)"
193+
if ("$Env:UseFork".ToLower() -eq "true") {
194+
$head = "vs-mobiletools-engineering-service2:$(SourceBranch)"
195+
}
196+
197+
$payload=@{
198+
title = $title
199+
body = $msg.ToString()
200+
head = "$head"
201+
base = "$(TargetBranch)"
202+
maintainer_can_modify = $true
203+
}
204+
205+
$headers = @{ Authorization = "token $(github--pat--vs-mobiletools-engineering-service2)" }
206+
207+
# let it throw
208+
$response = Invoke-WebRequest -UseBasicParsing -Method POST -Headers $headers -Uri "https://api.github.com/repos/$(SourceRepo)/pulls" -Body ($payload | ConvertTo-json)
209+
$newPr = $response.Content | ConvertFrom-Json
210+
211+
Write-Host "Response is $newPr"
212+
# add labels to the new created PR
213+
[System.Collections.Generic.List[string]]$labels= @()
214+
$labels.Add("backported")
215+
216+
# get the labels from the old PR which are stored in $content
217+
foreach ($labelInfo in $content.labels) {
218+
$labelName = $labelInfo.name
219+
Write-Host "Found label $labelName"
220+
$labels.Add($labelName)
221+
}
222+
$payload=@{
223+
labels = $labels
224+
}
225+
Write-Host "https://api.github.com/repos/(SourceRepo)/issues/$($response.number)/labels"
226+
$response = Invoke-WebRequest -UseBasicParsing -Method PUT -Headers $headers -Uri "https://api.github.com/repos/$(SourceRepo)/issues/$($newPr.number)/labels" -Body ($payload | ConvertTo-json)
227+
displayName: Open Pull Request
228+
env:
229+
UseFork: ${{ parameters.UseFork }}
230+
BackportRepoOrg: ${{ parameters.BackportRepoOrg }}
231+
BackportRepoName: ${{ parameters.BackportRepoName }}
232+
233+
- publish: $(Build.ArtifactStagingDirectory)
234+
artifact: patch
235+
condition: always()
236+
237+
- powershell: |
238+
if ("$(Agent.JobStatus)".Equals("Succeeded")) {
239+
$state = "success"
240+
$desc = "succeeded"
241+
$message = "Hooray"
242+
} else {
243+
$state = "failure"
244+
$desc = "failed"
245+
$message = "Oh no"
246+
}
247+
248+
$buildUri = "$(System.CollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)"
249+
250+
$statusJson = @{
251+
state = $state;
252+
description = "Backport $desc`.";
253+
target_url = $buildUri;
254+
context = "Backport to $(TargetBranch)"
255+
} | ConvertTo-Json
256+
257+
$uri = "https://api.github.com/repos/${{ parameters.BackportRepoOrg }}/${{ parameters.BackportRepoName }}/statuses/${{ parameters.BackportHeadSHA }}"
258+
Write-Host "Reporting to status api at $uri"
259+
Write-Host $statusJson
260+
261+
$headers = @{ Authorization = "token $(github--pat--vs-mobiletools-engineering-service2)" }
262+
Invoke-WebRequest -UseBasicParsing -Method POST -Headers $headers -Uri $uri -Body $statusJson
263+
264+
# Comment on the original PR
265+
$commentJson = @{
266+
body = "$message! Backport $desc`! Please see $buildUri for more details."
267+
} | ConvertTo-Json
268+
269+
$commentApi = "https://api.github.com/repos/${{ parameters.BackportRepoOrg }}/${{ parameters.BackportRepoName }}/issues/${{ parameters.BackportPRNumber }}/comments"
270+
Write-Host "Commenting on original PR via $commentApi"
271+
Invoke-WebRequest -UseBasicParsing -Method POST -Headers $headers -Uri $commentApi -Body $commentJson
272+
displayName: Report Status on PR
273+
condition: always()

0 commit comments

Comments
 (0)