1- name : Label Microsoft contrib
1+ name : Label Microsoft contrib and close PR
22
33permissions :
44 pull-requests : write
@@ -23,13 +23,25 @@ jobs:
2323 if : github.repository_owner == 'MicrosoftDocs'
2424 runs-on : ubuntu-latest
2525 steps :
26+
27+ - name : Create App Token
28+ id : app-token
29+ uses : actions/create-github-app-token@v1
30+ with :
31+ app-id : ${{ secrets.ClientId }}
32+ private-key : ${{ secrets.PrivateKey }}
33+ owner : ${{ github.repository_owner }}
34+
2635 - name : Script
2736 shell : pwsh
2837 env :
2938 PayloadJson : ${{ inputs.PayloadJson }}
39+ AppGitHubAccessToken : ${{ steps.app-token.outputs.token }}
3040 AccessToken : ${{ secrets.AccessToken }}
3141 ClientId : ${{ secrets.ClientId }}
3242 PrivateKey : ${{ secrets.PrivateKey }}
43+ IsPublicOnlyRepo : ${{ contains(github.event.repository.topics, 'publiconly') }}
44+
3345
3446 run : |
3547
@@ -38,144 +50,21 @@ jobs:
3850 # Get payload data from GitHub.
3951 $GitHubData = $env:PayloadJson | ConvertFrom-Json -Depth 50
4052 $GitRequestEvent = $GitHubData.event_name
53+ $GitHubAction = $GithubData.event.action
4154 $AccessToken = $env:AccessToken
55+ $AppGitHubAccessToken = $env:AppGitHubAccessToken
4256 $ClientId = $env:ClientId
4357 $PrivateKey = $env:PrivateKey
58+ $IsPublicOnlyRepo = [System.Convert]::ToBoolean($env:IsPublicOnlyRepo)
4459
4560 $RepoName = $GitHubData.event.repository.name
4661 $RepoUrl = $GitHubData.event.repository.url
47- $RepoTopicUrl = "$RepoUrl/topics"
4862
4963 # URL of the org team to check. We're using the "everyone" team in MicrosoftDocs.
5064 $OrgTeamUrl = "https://api.github.com/orgs/microsoftdocs/teams/everyone/memberships/"
5165
52- ###########################################
53- ###########################################
54- # GitHub app/installation token block start
55- ###########################################
56- ###########################################
57-
58- Function ConvertTo-JwtBase64 {
59- param(
60- [Parameter(Mandatory = $True)]
61- [string]$RawJson
62- )
63-
64- # Convert UTF-8 bytes to Base64, then make it URL-safe for JWT
65- $Encoded = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($RawJson))
66- Return $Encoded.TrimEnd('=') -replace '\+','-' -replace '/','_'
67- }
68-
69- Function New-GitHubAppJWT {
70- param(
71- [Parameter(Mandatory = $True)]
72- [string]$ClientId,
73-
74- [Parameter(Mandatory = $True)]
75- [string]$PrivateKey,
76-
77- [int]$ExpiresInMinutes = 10
78- )
79-
80- Write-Host "Create JWT"
81-
82- # Build the header
83- $Header = @{
84- alg = "RS256"
85- typ = "JWT"
86- } | ConvertTo-Json -Compress
87-
88- $HeaderEncoded = ConvertTo-JwtBase64 -RawJson $Header
89-
90- # Build the payload
91- $Now = [System.DateTimeOffset]::UtcNow
92- $Payload = @{
93- iat = $now.AddSeconds(-10).ToUnixTimeSeconds()
94- exp = $now.AddMinutes($ExpiresInMinutes).ToUnixTimeSeconds()
95- iss = $ClientId
96- } | ConvertTo-Json -Compress
97-
98- $PayloadEncoded = ConvertTo-JwtBase64 -RawJson $Payload
99-
100- # Combine and sign
101- $Rsa = [System.Security.Cryptography.RSA]::Create()
102- $Rsa.ImportFromPem($PrivateKey)
103-
104- $Combined = "$HeaderEncoded.$PayloadEncoded"
105- $SignatureBytes = $Rsa.SignData(
106- [System.Text.Encoding]::UTF8.GetBytes($Combined),
107- [System.Security.Cryptography.HashAlgorithmName]::SHA256,
108- [System.Security.Cryptography.RSASignaturePadding]::Pkcs1
109- )
110-
111- $SignatureEncoded = [Convert]::ToBase64String($SignatureBytes).TrimEnd('=') -replace '\+','-' -replace '/','_'
112-
113- Return "$HeaderEncoded.$PayloadEncoded.$SignatureEncoded"
114- }
115-
116- Function Get-GitHubAppInstallationToken {
117- param(
118- [Parameter(Mandatory = $true)]
119- [string]$ClientId,
120-
121- [Parameter(Mandatory = $true)]
122- [string]$PrivateKey,
123-
124- [Parameter(Mandatory = $true)]
125- [string]$Organization,
126-
127- [int]$TokenTTLMinutes = 10
128- )
129-
130- # Create the JWT
131- $Jwt = New-GitHubAppJWT -ClientId $ClientId -PrivateKey $PrivateKey -ExpiresInMinutes $TokenTTLMinutes
132-
133- # Prepare headers
134- $JwtHeaders = @{
135- Authorization = "Bearer $Jwt"
136- Accept = "application/vnd.github+json"
137- "X-GitHub-Api-Version"= "2022-11-28"
138- }
139-
140- Write-Host "Request org installation ID"
141-
142- # 1) Retrieve the installation ID for the org
143- Try {
144- $InstallationInfo = Invoke-RestMethod `
145- -Uri "https://api.github.com/orgs/$Organization/installation" `
146- -Headers $JwtHeaders `
147- -ErrorAction Stop
148-
149- $InstallationId = $InstallationInfo.id
150- }
151- Catch {
152- Write-Error "Failed to get installation ID from GitHub. $_"
153- Return $Null
154- }
155-
156- Write-Host "Get installation token"
157-
158- # 2) Use the installation ID to request an installation token
159- Try {
160- $TokenResponse = Invoke-RestMethod `
161- -Uri "https://api.github.com/app/installations/$InstallationId/access_tokens" `
162- -Headers $JwtHeaders `
163- -Method Post `
164- -ErrorAction Stop
165-
166- Return $TokenResponse.token
167- }
168- Catch {
169- Write-Error "Failed to get access token from GitHub. $_"
170- Return $Null
171- }
172- }
173-
174- #########################################
175- #########################################
176- # GitHub app/installation token block end
177- #########################################
178- #########################################
66+ $WorkflowsResourcePath = "https://api.github.com/repos/MicrosoftDocs/microsoft-365-docs/contents/.github/workflows/resources"
67+ $WorkflowsRef = "workflows-prod"
17968
18069 #####################
18170 #####################
@@ -298,9 +187,118 @@ jobs:
298187
299188 #####################
300189 #####################
301- # Main
190+ # Close-Pr
191+ Function Close-Pr {
192+
193+ param(
194+
195+ $PrUrl,
196+ $Headers
197+
198+ )
199+
200+ $Body = @{
201+
202+ state = "closed"
203+
204+ } | ConvertTo-Json
205+
206+ Try {
207+
208+ Write-Host "Closing PR URL: $PrUrl"
209+
210+ Invoke-RestMethod -Uri $PrUrl -Headers $Headers -Method PATCH -Body $Body -ErrorAction Stop
211+
212+ $PrClosed = $True
213+
214+ } Catch {
215+
216+ Write-Host "ERROR: Failed to close PR URL: $PrUrl. Error: $_"
217+
218+ $PrClosed = $False
219+
220+ }
221+
222+ Return $PrClosed
223+
224+ }
225+
226+ #####################
227+ #####################
228+ # Set-PrMessage
229+
230+ Function Set-PrMessage {
231+
232+ Param(
233+ $Message,
234+ $CommentsUrl,
235+ $Headers
236+ )
237+
238+ $BodyHash = @{}
239+ $BodyHash.body = $Message
240+ $BodyJson = $BodyHash | ConvertTo-Json
241+ $BodyJson
242+
243+ Try {
244+
245+ Write-Host "Setting message on comment URL: $CommentsUrl"
246+
247+ $Result = Invoke-RestMethod -Uri $CommentsUrl -Body $BodyJson -Headers $Headers -Method POST -ErrorAction Stop
248+
249+ $PostCommentSuccess = $True
250+
251+ } Catch {
252+
253+ Write-Host "ERROR: Failed to post message to comments URL: $CommentsUrl. Error: $_"
254+
255+
256+ $PostCommentSuccess = $False
257+
258+ }
259+
260+ Return $PostCommentSuccess
261+
262+ }
263+
264+ #####################
265+ #####################
266+ # Get-PrMessage
267+
268+ Function Get-PrMessage {
302269
270+ [cmdletbinding()]
271+ Param(
272+ [Parameter(Mandatory=$True)]
273+ $PrMessageFileName,
274+ [Parameter(Mandatory=$True)]
275+ $Headers
276+ )
277+
278+ $PrMessageFile = "$WorkflowsResourcePath/$PrMessageFileName`?ref=$WorkflowsRef"
279+
280+ Try {
281+
282+ Write-Host "Getting PR message from $PrMessageFile"
283+
284+ $PrMessageData = Invoke-RestMethod -Uri $PrMessageFile -Headers $Headers
285+ $PrMessage = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($PrMessageData.content));
286+
287+ } Catch {
288+
289+ Write-Host "Failed to get PR message $PrMessageFileName. Error: $_"
290+
291+ $PrMessage = $Null
292+
293+ }
294+
295+ Return $PrMessage
296+
297+ }
303298
299+ #####################
300+ #####################
301+ # Main
304302
305303 Write-Host "Repo: $($GitHubData.event.repository.name)"
306304 Write-Host "Sender: $($GitHubData.event.sender.login)"
@@ -316,16 +314,14 @@ jobs:
316314 # Create team read GitHub HTTP authentication header. Need a token that has access to org scope. Get-GitHubAppInstallationToken
317315 # requests an installation token from our GitHub app so that we can authenticate. GITHUB_TOKEN that is used to populate $AccessToken
318316 # doesn't have access to org scope so using our GitHub app's access.
319- $GitHubAccessToken = Get-GitHubAppInstallationToken -ClientId $ClientId -PrivateKey $PrivateKey -Organization MicrosoftDocs -TokenTTLMinutes 10
320-
321317 $TeamReadGitHubHeaders = @{}
322- $TeamReadGitHubHeaders.Add("Authorization","token $($GitHubAccessToken )")
318+ $TeamReadGitHubHeaders.Add("Authorization","token $($AppGitHubAccessToken )")
323319 $TeamReadGitHubHeaders.Add("User-Agent", "OfficeDocs")
324320 $TeamReadGitHubHeaders.Add("Accept","application/vnd.github.mercy-preview+json")
325321
326322 # -and ($GitHubData.event.action -eq "opened")
327323 # Only process event types of 'pull_request_target' that are 'opened' (PR created)
328- If (($GitRequestEvent -eq "pull_request_target") ) {
324+ If (($GitRequestEvent -eq "pull_request_target") -and ($GitHubAction -eq "opened") ) {
329325
330326 $Contributor = $GitHubData.event.pull_request.user.login
331327 $LabelName = "Microsoft submitter"
@@ -390,7 +386,6 @@ jobs:
390386
391387 Write-Host "Setting label on PR."
392388
393-
394389 $LabelUrl = $GitHubData.event.pull_request.issue_url
395390
396391 Write-Host "Using pull request URL $LabelUrl."
@@ -409,6 +404,30 @@ jobs:
409404
410405 }
411406
407+ If ($IsPublicOnlyRepo) {
408+
409+ Write-Host "Repo is a public-only repo. Not closing PR."
410+
411+ } Else {
412+
413+ $PrUrl = $GitHubData.event.pull_request.url
414+ $CommentsUrl = $GitHubData.event.pull_request.comments_url
415+
416+ $CloseSuccess = Close-Pr -PrUrl $PrUrl -Headers $GitHubHeaders
417+
418+ If ($CloseSuccess) {
419+
420+ $PrMessage = Get-PrMessage -PrMessageFileName "AutoLabelMsftContributor-PrCloseMessage.md" -Headers $GitHubHeaders
421+
422+ If ($PrMessage) {
423+
424+ Set-PrMessage -Message $PrMessage -Headers $GitHubHeaders -CommentsUrl $CommentsUrl
425+
426+ }
427+
428+ }
429+
430+ }
412431
413432 } Else {
414433
0 commit comments