-
Notifications
You must be signed in to change notification settings - Fork 2.2k
769 lines (586 loc) · 36.8 KB
/
M365Endpoints.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
name: (Scheduled) M365 Endpoints includes automation
permissions:
contents: write
pull-requests: write
actions: read
on:
schedule:
- cron: "0 */6 * * *"
workflow_dispatch:
jobs:
get-previous-run:
if: github.repository_visibility == 'private'
name: Get previous run ID
runs-on: ubuntu-latest
continue-on-error: true
outputs:
PreviousRun: ${{ steps.previous_run.outputs.previous_run_id }}
steps:
- name: Get previous run ID
id: previous_run
uses: actions/github-script@v7
with:
script: |
const response = await github.rest.actions.listWorkflowRuns({
owner: "MicrosoftDocs",
repo: "microsoft-365-docs-pr",
workflow_id: 117238499,
branch: "main",
status: "success",
per_page: 2,
});
// Find the previous run by looking at the second run in the list
const previousRun = response.data.workflow_runs.find(run => run.id !== context.runId);
core.setOutput("previous_run_id", previousRun.id);
- name: Output previous run ID
run: |
echo "Previous run ID: ${{ steps.previous_run.outputs.previous_run_id }}"
update-includes:
if: github.repository_visibility == 'private'
needs: get-previous-run
name: Update includes
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
name: Download previous run data artifact
continue-on-error: true
with:
name: RunData
path: "${{ github.workspace }}/run-data/"
run-id: ${{ needs.get-previous-run.outputs.PreviousRun}}
github-token: ${{ github.token }}
- name: Process endpoint data
shell: pwsh
env:
AccessToken: ${{ secrets.MARVEL_REPO_ACCESS_TOKEN }}
TargetOrganization: "MicrosoftDocs"
TargetRepository: "microsoft-365-docs-pr"
TargetPath: "microsoft-365/includes"
EndpointsContentOwner: "kelleyvice-msft"
run: |
# GetServiceInstanceEndpoints
# Original script created 4-December-2018 by Peter Worley v-peworl@microsoft.com
# Script updated for Azure Torus 2-September-2020 by David Strome dstrome@microsoft.com
# Script updated for GitHub workflows 10-September-2024 by David Strome dstrome@microsoft.com
<#
This script retreives Office 365 endpoint sets for each service instance
from the endpoints web service, converts the endpoint sets into tables,
saves the tables in a markdown file for each service instance,
then uploads each markdown file to a GitHub repository for automated
publishing.
#>
# Set default encoding for file output to ASCII
$PSDefaultParameterValues['*:Encoding'] = 'ASCII'
function Set-ScriptOptions {
<#
.SYNOPSIS
Set up script variables
.DESCRIPTION
Define variables, directories, service instances, and service areas,
as well as GitHub user, authentication, & repository information.
Environment specific changes to the script can be done here.
#>
# Web Service Address Setup
# Web Service root URL
$script:ws = "https://endpoints.office.com"
Write-Host "Setting script options"
# Script Environment Setup
# Paths & files for storing client ID, service instance versions, and script output files
$script:dataPath = "$env:GITHUB_WORKSPACE/run-data/" # path to store data files
$clientIDFile = $dataPath + "endpoints-clientid.txt" # file to store client request id
$script:siVersionFile = $dataPath + "endpoints-service-instance-versions.json" # file to store service instance versions
write-host "Storage path: $dataPath"
# Output File Setup
# HTML commented-out automation notice to display at top of output files
$script:scriptContact = "the Office 365 Endpoints team" # who should be contacted for script questions/changes/etc.
$script:fileNotice = "<!--THIS FILE IS AUTOMATICALLY GENERATED. MANUAL CHANGES WILL BE OVERWRITTEN.-->`n<!--Please contact " + $scriptContact + " with any questions.-->"
# Naming convention for output file (appended after the service instance name)
$script:outFileSuffix = " Endpoints.md"
# Create output directory
If (!$(Test-Path $dataPath)) { mkdir $dataPath }
# Client ID Setup
# Fetch the local client request ID if data file exists; otherwise generate a new one
if (Test-Path $clientIDFile) {
Write-Host "Getting client request ID"
$script:clientRequestId = Get-Content -Path $clientIDFile
}
else {
Write-Host "Creating client request ID"
$script:clientRequestId = [GUID]::NewGuid().Guid
@($clientRequestId) | Out-File -FilePath $clientIDFile
}
# Service Instance Setup
# Create a lookup hash of service instances from the WS and their corresponding display names
# This name determines the output file header, as well as the file name
# (The file name is the official name + output file suffix, converted to lowercase and replacing spaces with dashes)
$script:siHash = @{}
$siHash.China = "Office 365 operated by 21Vianet"
$siHash.Germany = "Office 365 Germany"
$siHash.USGovDoD = "Office 365 U.S. Government DoD"
$siHash.USGovGCCHigh = "Office 365 U.S. Government GCC High"
$siHash.Worldwide = "Office 365 Worldwide"
# Service Area Setup
# Create a list of service areas from the WS
# This could be automated, but we want to sort manually
$script:allServiceAreas = @("Exchange", "SharePoint", "Skype", "Common")
# GitHub Setup
# Create github HTTP authentication header
$script:OfficedocsprToken = $env:AccessToken
$script:GitHubHeaders = @{}
$script:GitHubHeaders.Add("Authorization","token $($OfficedocsprToken)")
$script:GitHubHeaders.Add("User-Agent", "OfficeDocs")
# GitHub user and repo values to use
$script:Organization = $env:TargetOrganization # The GitHub user that owns the repository
$script:Repository = $env:TargetRepository # The remote repository to upload to
$script:TargetBranch = "M365-Endpoints"
$script:DefaultBranch = Get-RepoDefaultBranch -Headers $script:GitHubHeaders -Org $script:Organization -Repo $script:Repository # The remote branch
$script:RepoDir = $env:TargetPath # The target directory in the remote repository
$script:EndpointsContentOwner = $env:EndpointsContentOwner
$script:PrDescription = "@MicrosoftDocs/marveldocs-pubops`n`nThis is an automated pull request to update M365 Endpoints include files in **$RepoDir**. Before merging this PR, confirm the following:`n`n- There are no more than **$($siHash.count)** files in the PR`n- The only files in the pull request end with **$($OutFileSuffix.Trim())**`n- There are no obvious formatting issues with the content`n- The pull request is from **$TargetBranch** to **$DefaultBranch**`n`nIf issues are found with the PR, remove the **Sign off** label and add the **Back to submitter** label, assign the PR to **$EndpointsContentOwner**, and @-mention **$EndpointsContentOwner** with instructions on how to resolve the issue.`n`nAcrolinx issues can be ignored per exception: https://office.visualstudio.com/MAX/_workitems/edit/9352479`n`nIf no issues are found, merge the PR. If you have questions, email marveldocs-admins."
} # end Set-ScriptOptions function
function Get-RepoDefaultBranch {
param(
$Headers,
$Org,
$Repo
)
<#
.SYNOPSIS
Retrieve the default branch for the repo from GitHub
.DESCRIPTION
This function retrieves the repo's default branch dynamically in the event that
it's modified. A call retrieves the repo config data and the default_branch property
retrieved from that data.
#>
$DefaultBranch = $Null
$script:SetDefaultBranchSuccess = $False
# Get the default branch for Github
Try {
Write-Host "Getting default branch for $Repo. URL: https://api.github.com/repos/$Org/$Repo"
$DefaultBranch = (Invoke-RestMethod -Headers $Headers -Uri https://api.github.com/repos/$Org/$Repo -ErrorAction Stop -ErrorVariable GitHubDefaultBranchError).default_branch
# $DefaultBranch = "dstrome-test"
Write-Host "Default for $Repo is `"$DefaultBranch`""
$script:SetDefaultBranchSuccess = $True
} Catch {
Write-Host "***Failure retrieving default branch for $Repository. <p>Error: $($GitHubDefaultBranchError.ErrorRecord)"
}
Return $DefaultBranch
} # end Get-RepoDefaultBranch function
function Get-UpdateList {
<#
.SYNOPSIS
Create a list of service instances that need to be updated
.DESCRIPTION
This function calls the web service to get the current versions
for each service instance, checks the versions against a local file
containing the versions from the last time the script was run, then
builds a list of service instances that need updates.
.PARAMETER siList
A list of service instances
.PARAMETER versionFile
A path to a file which stores service instance versions
#>
param ($siList, $versionFile)
# Fetch the previous service instance versions from the local
# version file if it exists, otherwise create a new version file
if (Test-Path $versionFile) {
$previousVersions = Get-Content -Path $versionFile | ConvertFrom-Json
}
else {
$previousVersions = ""
}
Write-Host "Create list of service instances that need updates"
# Update the local version file with the current service instance versions
$siList | ConvertTo-Json | Out-File -FilePath $versionFile
# Build a hash with previous service instance versions for comparison
$siPreviousVersionHash = @{}
foreach ($item in $previousVersions) {
$instance = $item.instance;
$latest = $item.latest;
$siPreviousVersionHash.$instance = $latest;
}
# Compare the previous service instance versions with the current versions;
# Build a list of service instances that need updates
$newSiList = @()
foreach ($item in $siList) {
$instance = $item.instance;
$latest = $item.latest;
if ($siPreviousVersionHash.$instance -lt $latest) {
$newSiList += $instance
}
}
return $newSiList
} # end Get-UpdateList function
function Get-RemoteDirectoryListing {
<#
.SYNOPSIS
Create the directory listing of a remote repository
.DESCRIPTION
This function configures TLS, connects to GitHub, then gets the SHA
values of the files in the remote repository so they can be updated.
#>
# Fix TLS version so we can connect to GitHub
[net.servicepointmanager]::securityprotocol = [net.securityprotocoltype]::Tls12
Write-Host "Get file list from GitHub"
# Try to get $TargetBranch. If it exists, get the file list from $TargetBranch. If not, get it from $DefaultBranch.
Try {
Invoke-RestMethod -uri "https://api.github.com/repos/$Organization/$Repository/git/ref/heads/$TargetBranch" -headers $GitHubHeaders -Method Get | Out-Null
Write-Host "Branch $TargetBranch exists. Getting file list from $TargetBranch."
# We need the SHA of the existing files on GitHub in order to update (i.e. replace) them.
# To do that we get the repository directory listing.
$repoList = Invoke-RestMethod -Headers $GitHubHeaders -Uri https://api.github.com/repos/$Organization/$Repository/contents/$($RepoDir)?ref=$($TargetBranch)
} Catch {
Write-Host "Branch $TargetBranch does not exist. Getting file list from $DefaultBranch."
# We need the SHA of the existing files on GitHub in order to update (i.e. replace) them.
# To do that we get the repository directory listing.
$repoList = Invoke-RestMethod -Headers $GitHubHeaders -Uri https://api.github.com/repos/$Organization/$Repository/contents/$($RepoDir)?ref=$($DefaultBranch)
}
# Create a hash table with the name and SHA of each file in the remote repository
# This will be used when uploading the output files
$shaHash = @{}
foreach ($item in $repoList) {
$sname = $item.name
$ssha = $item.sha
$shaHash.$sname = $ssha
}
return $shaHash
} # end Get-RemoteDirectoryListing function
function ConvertTo-Markdown {
<#
.SYNOPSIS
Converts a PowerShell object to a Markdown table.
.DESCRIPTION
This function converts a PowerShell object (endpoint data) to a markdown table
Original function: https://gist.github.com/mac2000/86150ab43cfffc5d0eef
.EXAMPLE
$data | ConvertTo-Markdown
.EXAMPLE
ConvertTo-Markdown($data)
#>
[CmdletBinding()]
[OutputType([string])]
Param (
[Parameter(
Mandatory = $true,
Position = 0,
ValueFromPipeline = $true
)]
[PSObject[]]$collection
)
Begin {
$items = @()
$columns = [ordered]@{}
Write-Host "Convert data to markdown"
}
Process {
ForEach($item in $collection) {
$items += $item
$item.PSObject.Properties | ForEach-Object {
if(-not $columns.Contains($_.Name) -or $columns[$_.Name] -lt $_.Value.ToString().Length) {
$columns[$_.Name] = $_.Value.ToString().Length
}
}
}
}
End {
ForEach($key in $($columns.Keys)) {
$columns[$key] = [Math]::Max($columns[$key], $key.Length)
}
$header = @()
ForEach($key in $columns.Keys) {
$header += $key
}
$header -join ' | '
$separator = @()
ForEach($key in $columns.Keys) {
$separator += '-' * $columns[$key]
}
$separator -join ' | '
ForEach($item in $items) {
$values = @()
ForEach($key in $columns.Keys) {
$values += $item.($key)
}
$values -join ' | '
}
}
} # end ConvertTo-Markdown function
function Format-Ports {
<#
.SYNOPSIS
Sorts and formats a list of ports
.DESCRIPTION
Splits a string of ports into a list of ports, then separates
the individual ports from the port ranges and sorts them
.PARAMETER portList
A string containing a comma-delimited list of ports
#>
param ($portList)
# The port entry from the web service is a string; we need to convert it into an array
$splitPorts = @()
$splitPorts = $portList.Split(",")
# Separate the individual ports from port ranges and sort them
# If it has a "-" then it's a port range, otherwise it's a port
$tempPorts = $splitPorts | Where-Object {$_ -notlike '*-*'} | Sort-Object
$tempRanges = $splitPorts | Where-Object {$_ -like '*-*'} | Sort-Object
# Combine the two lists into a single object so we can specify a delimiter later
$ports = @()
$ports += $tempPorts
$ports += $tempRanges
# Return the formatted arrays of ports and ranges
return $ports
} # end function Format-Ports
function Add-OutputFile {
<#
.SYNOPSIS
Creates an output file for a service instance
.DESCRIPTION
Creates an output file for a service instance at a given path,
then places a descriptive header at the top of the file.
The output file will be referenced and added to throughout the script.
.PARAMETER siList
A list of service instances with versions
.PARAMETER si
A service instance
.PARAMETER path
A path for the output file
#>
param($siList, $si, $path)
Write-Host "Create output file for $si"
# Generate the file name, converted to lowercase and replacing spaces with dashes for compatibility
$script:siFile = (($siHash.$si + $outFileSuffix) -replace (" ", "-")).ToLower()
Out-File -FilePath ($path + $siFile) -Force # overwrite previous output file if it exists
$fileNotice | Out-File -Append -FilePath ($path + $siFile)
"<!--" + $si + " endpoints version " + ($siList | Where-Object {$_.instance -eq $si} | ForEach-Object {$_.latest}) + "-->" | Out-File -Append -FilePath ($path + $siFile)
"<!--File generated " + (Get-Date -Format yyyy-MM-dd` HH:mm:ss.ffff) + "-->" | Out-File -Append -FilePath ($path + $siFile)
# Commenting out H1 header as it's currently not needed in the include file
# "`n# " + $siHash.$si + " Endpoints`n" | Out-File -Append -FilePath ($path + $siFile)
} # end Add-OutputFile function
function Write-ServiceAreaHeader {
param($saName, $path, $file)
Write-Host "Write service header for $saName"
# Add a header with the service area name to the output file
"`n## " + $saName + "`n" | Out-File -Append -FilePath ($path + $file)
} # end function Write-ServiceAreaHeader
function ConvertTo-EndpointObject {
<#
.SYNOPSIS
Builds an endpoint set object for a service area
.DESCRIPTION
Builds a custom PS object from a list of formatted endpoint sets for the
specified service area. The resulting object will have normalized fields
corresponding to the desired fields in the final output file.
.PARAMETER eps
A list of formatted endpoint sets
.PARAMETER sa
A service area name
.NOTES
The PSCustomObject attributes will correspond to the column headers
when converted to a markdown table.
#>
param ($eps, $sa)
Write-Host "Create endpoint set for $sa"
# Loop through the endpoint sets in the service instance and build
# an object out of the endpoint sets in the current service area
$eps | ForEach-Object {
if ($_.serviceArea -eq $sa) {
$endpointSet = $_
# Join the URLs/IPs/ports into strings for output. Define the "-join" separator
# (generally "<BR>" or "," or ", ") between each URL, each IP address, and each port.
# Use <BR> if you want each IP/URL address/port to appear on a separate line
$urls = ($(if ($endpointSet.urls.Count -gt 0) {"``" + (($endpointSet.urls | Where-Object { $_ -ne $null }) -join ", ") + "``"} else { @() }))
$ips = ($(if ($endpointSet.ips.Count -gt 0) {"``" + (($endpointSet.ips | Where-Object { $_ -ne $null }) -join ", ") + "``"} else { @() }))
$tcpPorts = ($(if ($endpointSet.tcpPorts) {"**TCP:** " + ((Format-Ports $endpointSet.tcpPorts) -join ", ")}) | Where-Object { $_ -ne $null }) -join ", "
$udpPorts = ($(if ($endpointSet.udpPorts) {"**UDP:** " + ((Format-Ports $endpointSet.udpPorts) -join ", ")}) | Where-Object { $_ -ne $null }) -join ", "
# Set up the category field to also display required or optional, as well as notes
if ($endpointSet.required) {
$category = $endpointSet.category + "<BR>Required"
}
else {
$category = $endpointSet.category + "<BR>Optional<BR>" + "**Notes:** " + $endpointSet.notes
}
# Create a PowerShell object from the normalized endpoint data
# This object will be converted into a markdown table
# The attributes of this object determine the columns in the table
# The order of the object attributes determine the order of the table columns
[PSCustomObject] @{
ID = $endpointSet.id;
Category = $category;
ER = $(if($endpointSet.expressRoute) {"Yes"} else {"No"}); # Use "Yes/No" instead of "True/False"
Addresses = ($(if($urls){$urls}), $(if($ips){$ips}) | Where-Object { $_ -ne $null }) -join "<BR>";
Ports = ($(if($tcpPorts){$tcpPorts}), $(if($udpPorts){$udpPorts}) | Where-Object { $_ -ne $null }) -join "<BR>";
}
} # end if (test for service area)
} # end of $endpointSet object loop
} # end function ConvertTo-EndpointObject
function Update-TenantURLs {
# This function exists so we can put "<tenant>" in tenant wildcard URLs
param ($epsList, $placeholderString, $replaceString)
Write-Host "Update tenant URLs"
$epsList | Where-Object {$_.urls -like "*$placeHolderString*"} | ForEach-Object {
$_.urls = ($_.urls -replace $placeholderString, $replaceString)
}
return $epsList
} # end function Update-TenantURLs
function Send-ToGitHub {
<#
.SYNOPSIS
Uploads a file to a GitHub repository using the GitHub API
.DESCRIPTION
The function uses the GitHub variables declared earlier in the script
(Organization, Repository, RepoDir, Branch, GitHubHeaders) to upload a file
to a repository.
.PARAMETER path
A path where the directory where theupload file can be found
.PARAMETER file
The name of the file to be uploaded
#>
param($path, $file)
# Get the sha of the file from the repository list,
# based on the matching local file name (previously created)
Write-Host "Upload $file to GitHub"
$sha = $shaHash.$file
# Convert the local file to be uploaded to Base64 (as required by GitHub)
$Base64Content = [System.Convert]::ToBase64String([IO.File]::ReadAllBytes($path + $file))
# Build the body of the message with the file info.
$Body = @{
message = "Uploaded file: " + ($file) + " - " + (Get-Date -Format yyyy-MM-dd` HH:mm:ss.ffff)
content = $Base64Content
sha = $sha
branch = $TargetBranch
} | ConvertTo-Json
# Check if $TargetBranch exists and, if not, create it from $DefaultBranch
Try {
Invoke-RestMethod -uri "https://api.github.com/repos/$Organization/$Repository/git/ref/heads/$TargetBranch" -headers $GitHubHeaders -Method Get | Out-Null
} Catch {
Write-Host "Branch $TargetBranch does not exist. Creating branch $TargetBranch from $DefaultBranch."
$DefaultBranchData = Invoke-RestMethod -uri "https://api.github.com/repos/$Organization/$Repository/git/ref/heads/$DefaultBranch" -Headers $GitHubHeaders -Method Get
$BranchBody = @{
ref = "refs/heads/$TargetBranch"
sha = $DefaultBranchData.object.sha
} | ConvertTo-Json
Invoke-RestMethod -uri "https://api.github.com/repos/$Organization/$Repository/git/refs" -headers $GitHubHeaders -Method POST -Body $BranchBody
}
Write-Host $Body
Write-Host "https://api.github.com/repos/$Organization/$Repository/contents/$($RepoDir)/$($File)?ref=$TargetBranch"
# Upload the file
Invoke-RestMethod -Headers $GitHubHeaders -Uri https://api.github.com/repos/$Organization/$Repository/contents/$($RepoDir)/$($File)?ref=$TargetBranch -Method PUT -Body $Body
} # end Send-ToGitHub function
Function New-PullRequest {
$BranchResponse = $Null
Write-Host "Checking if $TargetBranch exists"
Try {
$BranchResponse = Invoke-RestMethod -uri "https://api.github.com/repos/$Organization/$Repository/git/ref/heads/$TargetBranch" -headers $GitHubHeaders -Method Get -ErrorAction Stop
} Catch {
Write-Host "Branch doesn't exist."
}
If ($BranchResponse) {
Write-Host "Checking if $TargetBranch is ahead of $DefaultBranch"
Try {
$CompareResponse = Invoke-RestMethod -Uri "https://api.github.com/repos/$Organization/$Repository/compare/$DefaultBranch...$TargetBranch" -Method GET -Headers $GitHubHeaders
} Catch {
Throw "Failed to check if $TargetBranch is ahead of $DefaultBranch. Error: $($Error[0])"
}
If ($CompareResponse.ahead_by -gt 0) {
Write-Host "$TargetBranch has changes ahead of $DefaultBranch"
Write-Host "Checking if a pull request exists between $TargetBranch and $DefaultBranch"
Try {
$PrsResponse = Invoke-RestMethod -Uri "https://api.github.com/repos/$Organization/$Repository/pulls?head=$($Organization):$TargetBranch&base=$DefaultBranch&state=open" -Method GET -Headers $GitHubHeaders
} Catch {
Throw "Failed to check if pull request exists between $TargetBranch and $DefaultBranch. Error: $($Error[0])"
}
If (($PrsResponse | Measure-Object).Count -le 0) {
Write-Host "No existing pull request. Creating a new PR from $TargetBranch to $DefaultBranch"
$PrBody = @{
title = "Merge $TargetBranch into $DefaultBranch"
head = $TargetBranch
base = "$DefaultBranch"
body = "$PrDescription"
} | ConvertTo-Json
Try {
$PrResponse = Invoke-RestMethod -Uri "https://api.github.com/repos/$Organization/$Repository/pulls" -Method POST -Headers $GitHubHeaders -Body $PrBody
Write-Host "Created pull request $($PrResponse.html_url)"
$LabelBody = @{
labels = @("Sign off")
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://api.github.com/repos/$Organization/$Repository/issues/$($PrResponse.number)/labels" -Method POST -Headers $GitHubHeaders -Body $LabelBody
} Catch {
Throw "Failed to create pull request. Error: $($Error[0])"
}
} Else {
Write-Host "Pull request exists. "
}
}
}
}
### END FUNCTION BLOCK ###
### BEGIN EXECUTION BLOCK ###
Write-Host "Starting endpoints update script"
# Set up the script variables
Set-ScriptOptions
If ($SetDefaultBranchSuccess) {
# Get the current list of service instances and versions from the web service
$allServiceInstances = Invoke-RestMethod -Uri ($ws + "/version?clientrequestid=" + $clientRequestId)
# Check the service instances for new versions, then if necessary
# create a list of service instances needing updates
$serviceInstances = Get-UpdateList $allServiceInstances $siVersionFile
# If any service instances need to be updated, we need the SHA of the
# existing files on GitHub in order to replace them with updated files
if ($serviceInstances.Count -gt 0) {
$shaHash = Get-RemoteDirectoryListing $serviceInstances
} Else {
Write-Host "No service instances need updates"
}
# Loop through the list of service instances to get updated endpoint sets, format
# the endpoint data, convert to markdown, save an output file, and upload to GitHub.
$serviceInstances | ForEach-Object {
$currentServiceInstance = $_
Write-Host "Processing $currentServiceInstance"
# Create the initial output file for the service instance ($siFile). We will
# write to this file as we build the markdown table for each service area.
Add-OutputFile $allServiceInstances $currentServiceInstance $dataPath
# DEALING WITH TENANT WILDCARD URLS
# We need to display <tenant> in tenant wildcard URLs, but we can't
# actually pass that value to the web service anymore.
# The following workaround uses placeholder text for tenant URLs,
# then replaces the placeholder text with the text we need displayed.
$tenantPlaceHolderText = "AnyUniqueString"
$tenantTextToDisplay = "<tenant>"
$endpointSets = ""
Write-Host "Retrieving endpoint set for $currentServiceInstance from M365 web service"
# Call the web service to get the endpoint sets for the current service instance
$endpointSets = Invoke-RestMethod -Uri ($ws + "/endpoints/"+ $currentServiceInstance + "?tenantname=" + $tenantPlaceHolderText + "&clientRequestId=" + $clientRequestId)
# Only continue if we have valid endpoint set data
if ($endpointSets -ne "") {
Write-Host "Retrieved endpoint sets"
# Replace the tenant placeholder text with the text we need to display
$endpointSets = Update-TenantURLs $endpointSets $tenantPlaceHolderText $tenantTextToDisplay
# Group the endpoint sets by service area and convert to markdown, then append to the output file
$allServiceAreas | ForEach-Object {
$currentServiceArea = $_
Write-Host "Processing $currentServiceArea"
# Create a custom object from the list of normalized endpoint sets
$saEndpointSetsObject = ConvertTo-EndpointObject $endpointSets $currentServiceArea
# Get the official display name for the service area
$saDisplayName = $endpointSets | Where-Object -Property serviceArea -EQ $currentServiceArea | ForEach-Object {$_.serviceAreaDisplayName} | Select-Object -Unique
# Put a header at the top of each service area section in the markdown
Write-ServiceAreaHeader $saDisplayName $dataPath $siFile
# Convert the endpoint sets object to markdown and append to the output file for the current service instance
($saEndpointSetsObject) | Select-Object * | ConvertTo-Markdown | Out-File -Append -FilePath ($dataPath + $siFile)
} # end allServiceAreas loop
# Upload the final output file to GitHub
Send-ToGitHub $dataPath $siFile
} Else {
Write-Host "Didn't receive any endpoint sets from webservice for $currentServiceInstance"
}
} # end serviceInstances loop
# Create a new pull request. New-PullRequest will only create a new PR if one is needed.
New-PullRequest
} # set default branch check
ls -alr $dataPath
Write-Host "Finished endpoints update script"
- uses: actions/upload-artifact@v4
name: Upload run data artifact
with:
name: RunData
path: "${{ github.workspace }}/run-data/endpoints*"