forked from microsoft/AL-Go-Actions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDetermineProjectsToBuild.psm1
287 lines (234 loc) · 10.4 KB
/
DetermineProjectsToBuild.psm1
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
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath "..\Github-Helper.psm1" -Resolve) -DisableNameChecking
<#
.Synopsis
Gets the modified files in a GitHub pull request.
#>
function Get-ModifiedFiles {
param(
[Parameter(HelpMessage = "The GitHub token to use to fetch the changed files", Mandatory = $true)]
[string] $token
)
if(!$env:GITHUB_EVENT_PATH) {
Write-Host "GITHUB_EVENT_PATH not set, returning empty list of changed files"
return @()
}
$ghEvent = Get-Content $env:GITHUB_EVENT_PATH -Encoding UTF8 | ConvertFrom-Json
if(-not ($ghEvent.PSObject.Properties.name -eq 'pull_request')) {
Write-Host "Not a pull request, returning empty list of changed files"
return @()
}
$url = "$($env:GITHUB_API_URL)/repos/$($env:GITHUB_REPOSITORY)/compare/$($ghEvent.pull_request.base.sha)...$($ghEvent.pull_request.head.sha)"
$headers = @{
"Authorization" = "token $token"
"Accept" = "application/vnd.github.baptiste-preview+json"
}
$response = (InvokeWebRequest -Headers $headers -Uri $url).Content | ConvertFrom-Json
$modifiedFiles = @($response.files | ForEach-Object { $_.filename })
return $modifiedFiles
}
<#
.Synopsis
Determines whether a full build is required.
.Outputs
A boolean indicating whether a full build is required.
.Description
Determines whether a full build is required.
A full build is required if:
- The alwaysBuildAllProjects setting is set to true
- More than 250 files have been modified
- The modified files contain a file that matches one of the fullBuildPatterns
#>
function Get-BuildAllProjects {
param(
[Parameter(HelpMessage = "The base folder", Mandatory = $true)]
[string] $baseFolder,
[Parameter(HelpMessage = "The modified files", Mandatory = $false)]
[string[]] $modifiedFiles = @()
)
$settings = $env:Settings | ConvertFrom-Json
if ($settings.alwaysBuildAllProjects) {
Write-Host "Building all projects because alwaysBuildAllProjects is set to true"
return $true
}
if (!$modifiedFiles) {
Write-Host "No files modified, building all projects"
return $true
}
if ($modifiedFiles.Count -ge 250) {
Write-Host "More than 250 files modified, building all projects"
return $true
}
$fullBuildPatterns = @(Join-Path '.github' '*.json')
if($settings.fullBuildPatterns) {
$fullBuildPatterns += $settings.fullBuildPatterns
}
#Include the base folder in the modified files
$modifiedFiles = @($modifiedFiles | ForEach-Object { return Join-Path $baseFolder $_ })
foreach($fullBuildFolder in $fullBuildPatterns) {
# The Join-Path is needed to make sure the path has the correct slashes
$fullBuildFolder = Join-Path $baseFolder $fullBuildFolder
if ($modifiedFiles -like $fullBuildFolder) {
Write-Host "Changes to $fullBuildFolder, building all projects"
return $true
}
}
Write-Host "No changes to fullBuildPatterns, building only modified projects"
return $false
}
<#
.Synopsis
Filters AL-Go projects based on modified files.
.Outputs
An array of AL-Go projects, filtered based on the modified files.
#>
function ShouldBuildProject {
param (
[Parameter(HelpMessage = "An AL-Go project", Mandatory = $true)]
$project,
[Parameter(HelpMessage = "The base folder", Mandatory = $true)]
$baseFolder,
[Parameter(HelpMessage = "A list of modified files", Mandatory = $true)]
$modifiedFiles
)
Write-Host "Determining whether to build project $project based on modified files"
$projectFolders = GetProjectFolders -baseFolder $baseFolder -project $project -includeAlGoFolder
$modifiedProjectFolders = @()
foreach($projectFolder in $projectFolders) {
$projectFolder = Join-Path $baseFolder "$projectFolder/*"
if ($modifiedFiles -like $projectFolder) {
$modifiedProjectFolders += $projectFolder
}
}
if ($modifiedProjectFolders.Count -gt 0) {
Write-Host "Modified files found for project $project : $($modifiedProjectFolders -join ', ')"
return $true
}
Write-Host "No modified files found for project $project. Not building project"
return $false
}
<#
.Synopsis
Creates buils dimensions for a list of projects.
.Outputs
An array of build dimensions for the projects and their corresponding build modes.
Each build dimension is a hashtable with the following keys:
- project: The name of the AL-Go project
- buildMode: The build mode to use for the project
#>
function CreateBuildDimensions {
param(
[Parameter(HelpMessage = "A list of AL-Go projects for which to generate build dimensions")]
$projects = @(),
$baseFolder
)
$buildDimensions = @()
foreach($project in $projects) {
$projectSettings = ReadSettings -project $project -baseFolder $baseFolder
$buildModes = @($projectSettings.buildModes)
if(!$buildModes) {
Write-Host "No build modes found for project $project, using default build mode 'Default'."
$buildModes = @('Default')
}
foreach($buildMode in $buildModes) {
$buildDimensions += @{
project = $project
projectName = $projectSettings.projectName
buildMode = $buildMode
}
}
}
return @(, $buildDimensions) # force array
}
<#
.Synopsis
Analyzes a folder for AL-Go projects and determines the build order of these projects.
.Description
Analyzes a folder for AL-Go projects and determines the build order of these projects.
The build order is determined by the project dependencies and the projects that have been modified.
.Outputs
The function returns the following values:
- projects: An array of all projects found in the folder
- projectsToBuild: An array of projects that need to be built
- projectDependencies: A hashtable with the project dependencies
- projectsOrderToBuild: An array of build dimensions, each build dimension contains the following properties:
- projects: An array of projects to build
- projectsCount: The number of projects to build
- buildDimensions: An array of build dimensions, to be used in a build matrix. Properties of the build dimension are:
- project: The project to build
- buildMode: The build mode to use
#>
function Get-ProjectsToBuild {
param (
[Parameter(HelpMessage = "The folder to scan for projects to build", Mandatory = $true)]
$baseFolder,
[Parameter(HelpMessage = "Whether a full build is required", Mandatory = $false)]
[bool] $buildAllProjects = $true,
[Parameter(HelpMessage = "An array of changed files paths, used to filter the projects to build", Mandatory = $false)]
[string[]] $modifiedFiles = @(),
[Parameter(HelpMessage = "The maximum depth to build the dependency tree", Mandatory = $false)]
[int] $maxBuildDepth = 0
)
. (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve)
Write-Host "Determining projects to build in $baseFolder"
Push-Location $baseFolder
try {
$settings = $env:Settings | ConvertFrom-Json
$projects = @(GetProjectsFromRepository -baseFolder $baseFolder -projectsFromSettings $settings.projects)
Write-Host "Found AL-Go Projects: $($projects -join ', ')"
$projectsToBuild = @()
$projectDependencies = @{}
$projectsOrderToBuild = @()
if ($projects) {
if($buildAllProjects) {
Write-Host "Full build required, building all projects"
$projectsToBuild = @($projects)
}
else {
Write-Host "Full build not required, filtering projects to build based on the modified files"
#Include the base folder in the modified files
$modifiedFilesFullPaths = @($modifiedFiles | ForEach-Object { return Join-Path $baseFolder $_ })
$projectsToBuild = @($projects | Where-Object { ShouldBuildProject -baseFolder $baseFolder -project $_ -modifiedFiles $modifiedFilesFullPaths })
}
if($settings.useProjectDependencies) {
$buildAlso = @{}
# Calculate the full projects order
$fullProjectsOrder = AnalyzeProjectDependencies -baseFolder $baseFolder -projects $projects -buildAlso ([ref]$buildAlso) -projectDependencies ([ref]$projectDependencies)
$projectsToBuild = @($projectsToBuild | ForEach-Object { $_; if ($buildAlso.Keys -contains $_) { $buildAlso."$_" } } | Select-Object -Unique)
}
else {
# Use a flatten build order (all projects on the same level)
$fullProjectsOrder = @(@{ 'projects' = $projectsToBuild; 'projectsCount' = $projectsToBuild.Count})
}
# Create a project order based on the projects to build
foreach($depth in $fullProjectsOrder) {
$projectsOnDepth = @($depth.projects | Where-Object { $projectsToBuild -contains $_ })
if ($projectsOnDepth) {
# Create build dimensions for the projects on the current depth
$buildDimensions = CreateBuildDimensions -baseFolder $baseFolder -projects $projectsOnDepth
$projectsOrderToBuild += @{
projects = $projectsOnDepth
projectsCount = $projectsOnDepth.Count
buildDimensions = $buildDimensions
}
}
}
}
if ($projectsOrderToBuild.Count -eq 0) {
Write-Host "Did not find any projects to add to the build order, adding default values"
$projectsOrderToBuild += @{
projects = @()
projectsCount = 0
buildDimensions = @()
}
}
Write-Host "Projects to build: $($projectsToBuild -join ', ')"
if($maxBuildDepth -and ($projectsOrderToBuild.Count -gt $maxBuildDepth)) {
throw "The build depth is too deep, the maximum build depth is $maxBuildDepth. You need to run 'Update AL-Go System Files' to update the workflows"
}
return $projects, $projectsToBuild, $projectDependencies, $projectsOrderToBuild
}
finally {
Pop-Location
}
}
Export-ModuleMember *-*