Skip to content

Commit 45f7652

Browse files
bcbuild-github-agentmicrosoft
and
microsoft
authored
Deploying AL-Go from main (4000fc21109200985749fbbb6b62d22d20a8adcb) to main (#74)
Deploying AL-Go from main (4000fc21109200985749fbbb6b62d22d20a8adcb) to main Co-authored-by: microsoft <[email protected]>
1 parent 663e9df commit 45f7652

38 files changed

+1619
-345
lines changed

AL-Go-Helper.ps1

+117-51
Large diffs are not rendered by default.

AL-Go-TestRepoHelper.ps1

+25-7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,23 @@ function Test-Shell {
4343
}
4444
}
4545

46+
function Test-Deprecations {
47+
Param(
48+
[HashTable] $json,
49+
[string] $settingsDescription
50+
)
51+
52+
# cleanModePreprocessorSymbols is deprecated
53+
if ($json.Keys -contains 'cleanModePreprocessorSymbols') {
54+
OutputWarning -Message "cleanModePreprocessorSymbols in $settingsDescription is deprecated. See https://aka.ms/algodeprecations#cleanModePreprocessorSymbols"
55+
}
56+
57+
# <workflowName>Schedule is deprecated
58+
($json.Keys | Where-Object {$_ -like '*Schedule' -and $_ -ne 'WorkflowSchedule'}) | ForEach-Object {
59+
OutputWarning -Message "$_ in $settingsDescription is deprecated. See https://aka.ms/algodeprecations#_workflow_Schedule. This warning will become an error in the future."
60+
}
61+
}
62+
4663
function Test-SettingsJson {
4764
Param(
4865
[hashtable] $json,
@@ -51,6 +68,8 @@ function Test-SettingsJson {
5168
[string] $type
5269
)
5370

71+
Test-Deprecations -json $json -settingsDescription $settingsDescription
72+
5473
Test-Shell -json $json -settingsDescription $settingsDescription -property 'shell'
5574
Test-Shell -json $json -settingsDescription $settingsDescription -property 'gitHubRunnerShell'
5675

@@ -71,18 +90,17 @@ function Test-SettingsJson {
7190
if ($type -eq 'Workflow') {
7291
# Test for things that should / should not exist in a workflow settings file
7392
}
93+
else {
94+
# workflowSchedule and workflowConcurrency should only exist in workflow specific settings files (or conditional settings - not tested)
95+
Test-Property -settingsDescription $settingsDescription -json $json -key 'workflowSchedule' -maynot
96+
Test-Property -settingsDescription $settingsDescription -json $json -key 'workflowConcurrency' -maynot
97+
}
7498
if ($type -eq 'Variable') {
7599
# Test for things that should / should not exist in a settings variable
76100
}
77101
if ($type -eq 'Project' -or $type -eq 'Workflow') {
78102
# templateUrl should not be in Project or Workflow settings
79103
Test-Property -settingsDescription $settingsDescription -json $json -key 'templateUrl' -maynot
80-
81-
# schedules and runs-on should not be in Project or Workflow settings
82-
# These properties are used in Update AL-Go System Files, hence they should only be in Repo settings
83-
'nextMajorSchedule','nextMinorSchedule','currentSchedule','runs-on' | ForEach-Object {
84-
Test-Property -settingsDescription $settingsDescription -json $json -key $_ -shouldnot
85-
}
86104
}
87105
}
88106

@@ -100,7 +118,7 @@ function Test-JsonStr {
100118

101119
try {
102120
$json = $jsonStr | ConvertFrom-Json | ConvertTo-HashTable
103-
Test-SettingsJson -json $json -settingsDescription $settingsDescription -type:$type
121+
Test-SettingsJson -json $json -settingsDescription $settingsDescription -type $type
104122
}
105123
catch {
106124
OutputError "$($_.Exception.Message.Replace("`r",'').Replace("`n",' ')) in $settingsDescription"

CheckForUpdates/CheckForUpdates.HelperFunctions.ps1

+58-9
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,26 @@ function GetLatestTemplateSha {
5050
$branch = $templateUrl.Split('@')[1]
5151

5252
try {
53+
Write-Host "Get latest SHA for $templateUrl"
5354
$response = InvokeWebRequest -Headers $headers -Uri "$apiUrl/branches?per_page=100" -retry
54-
$branchInfo = ($response.content | ConvertFrom-Json) | Where-Object { $_.Name -eq $branch }
5555
} catch {
56-
if ($_.Exception.Message -like "*401*") {
57-
throw "Failed to update AL-Go System Files. Make sure that the personal access token, defined in the secret called GhTokenWorkflow, is not expired and it has permission to update workflows. (Error was $($_.Exception.Message))"
58-
} else {
56+
Write-Host "Exception: $($_.Exception.Message)"
57+
if ($_.Exception.Message -like "*Unauthorized*") {
58+
try {
59+
Write-Host "retry without Authorization header"
60+
$headers.Remove('Authorization')
61+
$response = InvokeWebRequest -Headers $headers -Uri "$apiUrl/branches?per_page=100" -retry
62+
}
63+
catch {
64+
throw "Failed to update AL-Go System Files. Make sure that the personal access token, defined in the secret called GhTokenWorkflow, is not expired and it has permission to update workflows. (Error was $($_.Exception.Message))"
65+
}
66+
}
67+
else {
5968
throw $_.Exception.Message
6069
}
6170
}
6271

72+
$branchInfo = ($response.content | ConvertFrom-Json) | Where-Object { $_.Name -eq $branch }
6373
if (!$branchInfo) {
6474
throw "$templateUrl doesn't exist"
6575
}
@@ -293,14 +303,53 @@ function GetWorkflowContentWithChangesFromSettings {
293303

294304
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($srcFile)
295305
$yaml = [Yaml]::Load($srcFile)
296-
$workflowScheduleKey = "$($baseName)Schedule"
306+
$yamlName = $yaml.get('name:')
307+
if ($yamlName) {
308+
$workflowName = $yamlName.content.SubString('name:'.Length).Trim().Trim('''"').Trim()
309+
}
310+
else {
311+
$workflowName = $baseName
312+
}
313+
314+
$workflowScheduleKey = "WorkflowSchedule"
315+
$workflowConcurrencyKey = "WorkflowConcurrency"
316+
foreach($key in @($workflowScheduleKey,$workflowConcurrencyKey)) {
317+
if ($repoSettings.Keys -contains $key -and ($repoSettings."$key")) {
318+
throw "The $key setting is not allowed in the global repository settings. Please use the workflow specific settings file or conditional settings."
319+
}
320+
}
297321

298-
# Any workflow (except for the PullRequestHandler and reusable workflows (_*)) can have a RepoSetting called <workflowname>Schedule, which will be used to set the schedule for the workflow
322+
# Re-read settings and this time include workflow specific settings
323+
$repoSettings = ReadSettings -buildMode '' -project '' -workflowName $workflowName -userName '' -branchName '' | ConvertTo-HashTable -recurse
324+
325+
# Old Schedule key is deprecated, but still supported
326+
$oldWorkflowScheduleKey = "$($baseName)Schedule"
327+
if ($repoSettings.Keys -contains $oldWorkflowScheduleKey) {
328+
# DEPRECATION: REPLACE WITH ERROR AFTER October 1st 2025 --->
329+
if ($repoSettings.Keys -contains $workflowScheduleKey) {
330+
OutputWarning "Both $oldWorkflowScheduleKey and $workflowScheduleKey are defined in the settings file. $oldWorkflowScheduleKey will be ignored. This warning will become an error in the future"
331+
}
332+
else {
333+
Trace-DeprecationWarning -Message "$oldWorkflowScheduleKey is deprecated" -DeprecationTag "_workflow_Schedule" -WillBecomeError
334+
# Convert the old <workflow>Schedule setting to the new WorkflowSchedule setting
335+
$repoSettings."$workflowScheduleKey" = @{ "cron" = $repoSettings."$oldWorkflowScheduleKey" }
336+
}
337+
# <--- REPLACE WITH ERROR AFTER October 1st 2025
338+
}
339+
340+
# Any workflow (except for the PullRequestHandler and reusable workflows (_*)) can have concurrency and schedule defined
299341
if ($baseName -ne "PullRequestHandler" -and $baseName -notlike '_*') {
342+
# Add Schedule and Concurrency settings to the workflow
300343
if ($repoSettings.Keys -contains $workflowScheduleKey) {
301-
# Read the section under the on: key and add the schedule section
302-
$yamlOn = $yaml.Get('on:/')
303-
$yaml.Replace('on:/', $yamlOn.content+@('schedule:', " - cron: '$($repoSettings."$workflowScheduleKey")'"))
344+
if ($repoSettings."$workflowScheduleKey" -isnot [hashtable] -or $repoSettings."$workflowScheduleKey".Keys -notcontains 'cron' -or $repoSettings."$workflowScheduleKey".cron -isnot [string]) {
345+
throw "The $workflowScheduleKey setting must be a structure containing a cron property"
346+
}
347+
# Replace or add the schedule part under the on: key
348+
$yaml.ReplaceOrAdd('on:/', 'schedule:', @("- cron: '$($repoSettings."$workflowScheduleKey".cron)'"))
349+
}
350+
if ($repoSettings.Keys -contains $workflowConcurrencyKey) {
351+
# Replace or add the concurrency part
352+
$yaml.ReplaceOrAdd('', 'concurrency:', $repoSettings."$workflowConcurrencyKey")
304353
}
305354
}
306355

CheckForUpdates/CheckForUpdates.ps1

+36-23
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,13 @@ Param(
1616
)
1717

1818
. (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve)
19+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '..\TelemetryHelper.psm1' -Resolve)
1920
. (Join-Path -Path $PSScriptRoot -ChildPath "yamlclass.ps1")
2021
. (Join-Path -Path $PSScriptRoot -ChildPath "CheckForUpdates.HelperFunctions.ps1")
2122

2223
# ContainerHelper is used for determining project folders and dependencies
2324
DownloadAndImportBcContainerHelper
2425

25-
if ($update -eq 'Y') {
26-
if (-not $token) {
27-
throw "A personal access token with permissions to modify Workflows is needed. You must add a secret called GhTokenWorkflow containing a personal access token. You can Generate a new token from https://github.com/settings/tokens. Make sure that the workflow scope is checked."
28-
}
29-
else {
30-
$token = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($token))
31-
}
32-
}
33-
34-
# Use Authenticated API request to avoid the 60 API calls per hour limit
35-
$headers = @{
36-
"Accept" = "application/vnd.github.baptiste-preview+json"
37-
"Authorization" = "Bearer $token"
38-
}
39-
4026
if (-not $templateUrl.Contains('@')) {
4127
$templateUrl += "@main"
4228
}
@@ -48,14 +34,36 @@ $templateUrl = $templateUrl -replace "^(https:\/\/)(www\.)(.*)$", '$1$3'
4834

4935
# TemplateUrl is now always a full url + @ and a branch name
5036

37+
if ($update -eq 'Y') {
38+
if (-not $token) {
39+
throw "The GhTokenWorkflow secret is needed. Read https://github.com/microsoft/AL-Go/blob/main/Scenarios/GhTokenWorkflow.md for more information."
40+
}
41+
}
42+
43+
$readToken = $token
44+
if ($token) {
45+
# token comes from a secret, base 64 encoded
46+
$token = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($token))
47+
48+
# Get token with read permissions for this and the template repository - if private and in the same organization
49+
$repositories = @($ENV:GITHUB_REPOSITORY)
50+
if ($templateUrl -like "https://github.com/$($ENV:GITHUB_REPOSITORY_OWNER)/*") {
51+
$repositories += $templateUrl.Split('@')[0]
52+
}
53+
$readToken = GetAccessToken -token $token -permissions @{"actions"="read";"contents"="read";"metadata"="read"} -repositories $repositories
54+
}
55+
56+
# Use Authenticated API request if possible to avoid the 60 API calls per hour limit
57+
$headers = GetHeaders -token $readToken
58+
5159
# CheckForUpdates will read all AL-Go System files from the Template repository and compare them to the ones in the current repository
5260
# CheckForUpdates will apply changes to the AL-Go System files based on AL-Go repo settings, such as "runs-on" etc.
5361
# if $update is set to Y, CheckForUpdates will also update the AL-Go System files in the current repository using a PR or a direct commit (if $directCommit is set to true)
5462
# if $update is set to N, CheckForUpdates will only check for updates and output a warning if there are updates available
5563
# if $downloadLatest is set to true, CheckForUpdates will download the latest version of the template repository, else it will use the templateSha setting in the .github/AL-Go-Settings file
5664

5765
# Get Repo settings as a hashtable (do NOT read any specific project settings, nor any specific workflow, user or branch settings)
58-
$repoSettings = ReadSettings -project '' -workflowName '' -userName '' -branchName '' | ConvertTo-HashTable -recurse
66+
$repoSettings = ReadSettings -buildMode '' -project '' -workflowName '' -userName '' -branchName '' | ConvertTo-HashTable -recurse
5967
$templateSha = $repoSettings.templateSha
6068
$unusedALGoSystemFiles = $repoSettings.unusedALGoSystemFiles
6169
$includeBuildPP = $repoSettings.type -eq 'PTE' -and $repoSettings.powerPlatformSolutionFolder -ne ''
@@ -120,7 +128,7 @@ $removeFiles = @()
120128
$depth = 1
121129
if ($projects.Count -gt 1) {
122130
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath "..\DetermineProjectsToBuild\DetermineProjectsToBuild.psm1" -Resolve) -DisableNameChecking
123-
$allProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -buildAllProjects $true -maxBuildDepth 100
131+
$allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -buildAllProjects $true -maxBuildDepth 100
124132
$depth = $buildOrder.Count
125133
Write-Host "Calculated dependency depth to be $depth"
126134
}
@@ -204,16 +212,21 @@ else {
204212
# $update set, update the files
205213
try {
206214
# If a pull request already exists with the same REF, then exit
207-
$commitMessage = "[$updateBranch] Update AL-Go System Files from $templateInfo - $templateSha"
208-
$env:GH_TOKEN = $token
215+
$branchSHA = RunAndCheck git rev-list -n 1 $updateBranch
216+
$commitMessage = "[$($updateBranch)@$($branchSHA.SubString(0,7))] Update AL-Go System Files from $templateInfo - $($templateSha.SubString(0,7))"
217+
218+
# Get Token with permissions to modify workflows in this repository
219+
$writeToken = GetAccessToken -token $token -permissions @{"actions"="read";"contents"="write";"pull_requests"="write";"workflows"="write"}
220+
$env:GH_TOKEN = $writeToken
221+
209222
$existingPullRequest = (gh api --paginate "/repos/$env:GITHUB_REPOSITORY/pulls?base=$updateBranch" -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" | ConvertFrom-Json) | Where-Object { $_.title -eq $commitMessage } | Select-Object -First 1
210223
if ($existingPullRequest) {
211224
OutputWarning "Pull request already exists for $($commitMessage): $($existingPullRequest.html_url)."
212225
exit
213226
}
214227

215228
# If $directCommit, then changes are made directly to the default branch
216-
$serverUrl, $branch = CloneIntoNewFolder -actor $actor -token $token -updateBranch $updateBranch -DirectCommit $directCommit -newBranchPrefix 'update-al-go-system-files'
229+
$serverUrl, $branch = CloneIntoNewFolder -actor $actor -token $writeToken -updateBranch $updateBranch -DirectCommit $directCommit -newBranchPrefix 'update-al-go-system-files'
217230

218231
invoke-git status
219232

@@ -257,16 +270,16 @@ else {
257270
Write-Host "ReleaseNotes:"
258271
Write-Host $releaseNotes
259272

260-
if (!(CommitFromNewFolder -serverUrl $serverUrl -commitMessage $commitMessage -branch $branch -body $releaseNotes)) {
273+
if (!(CommitFromNewFolder -serverUrl $serverUrl -commitMessage $commitMessage -branch $branch -body $releaseNotes -headBranch $updateBranch)) {
261274
OutputNotice -message "No updates available for AL-Go for GitHub."
262275
}
263276
}
264277
catch {
265278
if ($directCommit) {
266-
throw "Failed to update AL-Go System Files. Make sure that the personal access token, defined in the secret called GhTokenWorkflow, is not expired and it has permission to update workflows. (Error was $($_.Exception.Message))"
279+
throw "Failed to update AL-Go System Files. Make sure that the personal access token, defined in the secret called GhTokenWorkflow, is not expired and it has permission to update workflows. Read https://github.com/microsoft/AL-Go/blob/main/Scenarios/GhTokenWorkflow.md for more information. (Error was $($_.Exception.Message))"
267280
}
268281
else {
269-
throw "Failed to create a pull-request to AL-Go System Files. Make sure that the personal access token, defined in the secret called GhTokenWorkflow, is not expired and it has permission to update workflows. (Error was $($_.Exception.Message))"
282+
throw "Failed to create a pull-request to AL-Go System Files. Make sure that the personal access token, defined in the secret called GhTokenWorkflow, is not expired and it has permission to update workflows. Read https://github.com/microsoft/AL-Go/blob/main/Scenarios/GhTokenWorkflow.md for more information. (Error was $($_.Exception.Message))"
270283
}
271284
}
272285
}

CheckForUpdates/yamlclass.ps1

+12-3
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,18 @@ class Yaml {
144144
$this.Remove($start, $count)
145145
$this.Insert($start, $yamlContent)
146146
}
147-
else {
148-
Write-Host -ForegroundColor Red "cannot locate $line"
149-
}
147+
}
148+
149+
# Add the lines in $content to the lines for the specified Yaml path, given by $line
150+
[void] Add([string] $line, [string[]] $content) {
151+
$this.Replace($line, $this.Get($line).content + $content)
152+
}
153+
154+
# Replace or add a key and content to the lines for the specified Yaml path, given by $line
155+
[void] ReplaceOrAdd([string] $line, [string] $key, [string[]]$content) {
156+
# Remove the key part under the line
157+
$this.Replace("$line$key",@())
158+
$this.Add($line, @($key) + @($content | ForEach-Object { " $_" }))
150159
}
151160

152161
# Replace all occurrences of $from with $to throughout the Yaml content

CreateApp/AppHelper.psm1

+3-2
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,15 @@ function NewSamplePerformanceTestApp
175175

176176
UpdateManifest -sourceFolder $appSourceFolder -appJsonFile "$($destinationPath)\app.json" -name $name -publisher $publisher -idrange $idrange -version $version
177177

178+
$sampleRange = @{ "fromId" = 149100; "toId" = 149999 }
178179
if ($sampleCode) {
179180
Get-ChildItem -Path "$appSourceFolder\src" -Recurse -Filter "*.al" | ForEach-Object {
180181
Write-Host $_.Name
181-
UpdateALFile -sourceFolder $_.DirectoryName -destinationFolder "$($destinationPath)\src" -alFileName $_.name -fromId 149100 -toId 149200 -startId $idrange[0]
182+
UpdateALFile -sourceFolder $_.DirectoryName -destinationFolder "$($destinationPath)\src" -alFileName $_.name -fromId $sampleRange.fromId -toId $sampleRange.toId -startId $idrange[0]
182183
}
183184
}
184185
if ($sampleSuite) {
185-
UpdateALFile -sourceFolder $alTemplatePath -destinationFolder $destinationPath -alFileName bcptSuite.json -fromId 149100 -toId 149200 -startId $idrange[0]
186+
UpdateALFile -sourceFolder $alTemplatePath -destinationFolder $destinationPath -alFileName bcptSuite.json -fromId $sampleRange.fromId -toId $sampleRange.toId -startId $idrange[0]
186187
}
187188
}
188189

0 commit comments

Comments
 (0)