-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a script to create local development environment (#417)
#### Summary <!-- Provide a general summary of your changes --> Create a script to create local development environment for working with apps from the repository. The NewDevEnv.ps1 script creates a docker container (if it doesn't exist), builds the apps, based on the provided parameters, and publishes the apps to the container. Test run: https://github.com/mazhelez/BCApps/actions/runs/7225774768/job/19689897656 Note: - The created container contains only apps from the BCApps repository. To be considered for future enhancement: - The created container contains all BC apps (by Microsoft): the ones from this repo are rebuilt, the rest are taken from the BC artifact. - Rebuild apps functionality. Now the rebuild happens only after manual clean up the cache folder. #### Work Item(s) <!-- Add the issue number here after the #. The issue needs to be open and approved. Submitting PRs with no linked issues or unapproved issues is highly discouraged. --> Fixes AB#492033 --------- Co-authored-by: Alexander Holstrup <[email protected]>
- Loading branch information
1 parent
8695b1f
commit 956334e
Showing
6 changed files
with
622 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ bld/ | |
[Oo]bj/ | ||
[Ll]og/ | ||
[Oo]ut/ | ||
.artifactsCache | ||
|
||
# Visual Studio 2015 cache/options directory | ||
.vs/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using module .\AppProjectInfo.class.psm1 | ||
|
||
<# | ||
.SYNOPSIS | ||
This class is used to store information about an AL-Go project. | ||
#> | ||
class ALGoProjectInfo { | ||
[string] $ProjectFolder | ||
[PSCustomObject] $Settings | ||
|
||
|
||
hidden ALGoProjectInfo([string] $projectFolder) { | ||
$alGoFolder = Join-Path $projectFolder '.AL-Go' | ||
|
||
if (-not (Test-Path -Path $alGoFolder -PathType Container)) { | ||
throw "Could not find .AL-Go folder in $projectFolder" | ||
} | ||
|
||
$settingsJsonFile = Join-Path $alGoFolder 'settings.json' | ||
|
||
if (-not (Test-Path -Path $settingsJsonFile -PathType Leaf)) { | ||
throw "Could not find settings.json in $alGoFolder" | ||
} | ||
|
||
$this.ProjectFolder = $projectFolder | ||
$this.Settings = Get-Content -Path $settingsJsonFile -Raw | ConvertFrom-Json | ||
} | ||
|
||
<# | ||
Gets the AL-Go project info from the specified folder. | ||
#> | ||
static [ALGoProjectInfo] Get([string] $projectFolder) { | ||
$alGoProjectInfo = [ALGoProjectInfo]::new($projectFolder) | ||
|
||
return $alGoProjectInfo | ||
} | ||
|
||
<# | ||
Finds all AL-Go projects in the specified folder. | ||
#> | ||
static [ALGoProjectInfo[]] FindAll([string] $folder) { | ||
$alGoProjects = @() | ||
|
||
$alGoProjectFolders = Get-ChildItem -Path $folder -Filter '.AL-Go' -Recurse -Directory | Select-Object -ExpandProperty Parent | Select-Object -ExpandProperty FullName | ||
|
||
foreach($alGoProjectFolder in $alGoProjectFolders) { | ||
$alGoProjects += [ALGoProjectInfo]::Get($alGoProjectFolder) | ||
} | ||
|
||
return $alGoProjects | ||
} | ||
|
||
<# | ||
Gets the app folders. | ||
#> | ||
[string[]] GetAppFolders([switch] $Resolve) { | ||
$appFolders = $this.Settings.appFolders | ||
|
||
if ($Resolve) { | ||
$appFolders = $appFolders | ForEach-Object { Join-Path $this.ProjectFolder $_ -Resolve -ErrorAction SilentlyContinue } | Where-Object { [AppProjectInfo]::IsAppProjectFolder($_) }| Select-Object -Unique | ||
} | ||
|
||
return $appFolders | ||
} | ||
|
||
<# | ||
Gets the test folders. | ||
#> | ||
[string[]] GetTestFolders([switch] $Resolve) { | ||
$testFolders = $this.Settings.testFolders | ||
|
||
if ($Resolve) { | ||
$testFolders = $testFolders | ForEach-Object { Join-Path $this.ProjectFolder $_ -Resolve -ErrorAction SilentlyContinue } | Where-Object { [AppProjectInfo]::IsAppProjectFolder($_) }| Select-Object -Unique | ||
} | ||
|
||
return $testFolders | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<# | ||
.SYNOPSIS | ||
This class is used to store information about an AL project. | ||
#> | ||
class AppProjectInfo { | ||
[string] $AppProjectFolder | ||
[string] $Id | ||
[ValidateSet('app', 'test')] | ||
[string] $Type | ||
[PSCustomObject] $AppJson | ||
|
||
|
||
hidden AppProjectInfo([string] $appProjectFolder, [string] $type = 'app') { | ||
|
||
if(-not [AppProjectInfo]::IsAppProjectFolder($appProjectFolder)) { | ||
throw "$appProjectFolder is not an app project folder" | ||
} | ||
|
||
$appJsonFile = Join-Path $appProjectFolder 'app.json' -Resolve | ||
$_appJson = Get-Content -Path $appJsonFile -Raw | ConvertFrom-Json | ||
|
||
$this.AppProjectFolder = $appProjectFolder | ||
$this.Type = $type | ||
$this.Id = $_appJson.id | ||
$this.AppJson = $_appJson | ||
} | ||
|
||
static [AppProjectInfo] Get([string] $appProjectFolder) { | ||
$appInfo = [AppProjectInfo]::new($appProjectFolder, 'app') | ||
|
||
return $appInfo | ||
} | ||
|
||
static [AppProjectInfo] Get([string] $appProjectFolder, [string] $type) { | ||
$appInfo = [AppProjectInfo]::new($appProjectFolder, $type) | ||
|
||
return $appInfo | ||
} | ||
|
||
static [boolean] IsAppProjectFolder([string] $folder) { | ||
return (Test-Path -Path (Join-Path $folder 'app.json') -PathType Leaf) | ||
} | ||
|
||
<# | ||
Gets the app publisher. | ||
#> | ||
[string] GetAppPublisher() { | ||
return $this.AppJson.publisher | ||
} | ||
|
||
<# | ||
Gets the app name. | ||
#> | ||
[string] GetAppName() { | ||
return $this.AppJson.name | ||
} | ||
|
||
<# | ||
Gets the app version. | ||
#> | ||
[string] GetAppVersion() { | ||
return $this.AppJson.version | ||
} | ||
|
||
<# | ||
Gets the app file name. | ||
#> | ||
[string] GetAppFileName() { | ||
$appPublisher = $this.GetAppPublisher() | ||
$appName = $this.GetAppName() | ||
$appVersion = $this.GetAppVersion() | ||
|
||
return "$($appPublisher)_$($appName)_$($appVersion).app" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
using module .\AppProjectInfo.class.psm1 | ||
using module .\ALGoProjectInfo.class.psm1 | ||
|
||
<# | ||
.Synopsis | ||
Creates a docker-based development environment for AL apps. | ||
.Parameter containerName | ||
The name of the container to use. The container will be created if it does not exist. | ||
.Parameter userName | ||
The user name to use for the container. | ||
.Parameter password | ||
The password to use for the container. | ||
.Parameter projectPaths | ||
The paths of the AL projects to build. May contain wildcards. | ||
.Parameter workspacePath | ||
The path of the workspace to build. The workspace file must be in JSON format. | ||
.Parameter alGoProject | ||
The path of the AL-Go project to build. | ||
.Parameter packageCacheFolder | ||
The folder to store the built artifacts. | ||
#> | ||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '', Justification = 'local build')] | ||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'local build')] | ||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'packageCacheFolder', Justification = 'false-postiive, used in Measure-Command')] | ||
[CmdletBinding(DefaultParameterSetName = 'ProjectPaths')] | ||
param( | ||
[Parameter(Mandatory = $false)] | ||
[string] $containerName = "BC-$(Get-Date -Format 'yyyyMMdd')", | ||
|
||
[Parameter(Mandatory = $false)] | ||
[string] $userName = 'admin', | ||
|
||
[Parameter(Mandatory = $true)] | ||
[string] $password, | ||
|
||
[Parameter(Mandatory = $true, ParameterSetName = 'ProjectPaths')] | ||
[string[]] $projectPaths, | ||
|
||
[Parameter(Mandatory = $true, ParameterSetName = 'WorkspacePath')] | ||
[string] $workspacePath, | ||
|
||
[Parameter(Mandatory = $true, ParameterSetName = 'ALGoProject')] | ||
[string] $alGoProject, | ||
|
||
[Parameter(Mandatory = $false)] | ||
[string] $packageCacheFolder = ".artifactsCache" | ||
) | ||
|
||
$errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0 | ||
|
||
# Install BCContainerHelper module if not already installed | ||
if (-not (Get-Module -ListAvailable -Name "BCContainerHelper")) { | ||
Write-Host "BCContainerHelper module not found. Installing..." | ||
Install-Module -Name "BCContainerHelper" -Scope CurrentUser -AllowPrerelease -Force | ||
} | ||
|
||
Import-Module "BCContainerHelper" -DisableNameChecking | ||
Import-Module "$PSScriptRoot\..\EnlistmentHelperFunctions.psm1" -DisableNameChecking | ||
Import-Module "$PSScriptRoot\NewDevEnv.psm1" -DisableNameChecking | ||
|
||
$baseFolder = Get-BaseFolder | ||
|
||
# Create BC container | ||
$credential = New-Object System.Management.Automation.PSCredential ($userName, $(ConvertTo-SecureString $password -AsPlainText -Force)) | ||
$createContainerJob = Create-BCContainer -containerName $containerName -credential $credential -backgroundJob | ||
|
||
# Resolve AL project paths | ||
$projectPaths = Resolve-ProjectPaths -projectPaths $projectPaths -workspacePath $workspacePath -alGoProject $alGoProject -baseFolder $baseFolder | ||
Write-Host "Resolved project paths: $($projectPaths -join [Environment]::NewLine)" | ||
|
||
# Build apps | ||
$appFiles = @() | ||
$buildingAppsStats = Measure-Command { | ||
Write-Host "Building apps..." -ForegroundColor Yellow | ||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'false-postiive')] | ||
$appFiles = Build-Apps -projectPaths $projectPaths -packageCacheFolder $packageCacheFolder | ||
} | ||
|
||
Write-Host "Building apps took $($buildingAppsStats.TotalSeconds) seconds" | ||
Write-Host "App files: $($appFiles -join [Environment]::NewLine)" -ForegroundColor Green | ||
|
||
# Wait for container creation to finish | ||
if($createContainerJob) { | ||
Write-Host 'Waiting for container creation to finish...' -ForegroundColor Yellow | ||
Wait-Job -Job $createContainerJob -Timeout 1 | ||
Receive-Job -Job $createContainerJob -Wait -AutoRemoveJob | ||
|
||
if($createContainerJob.State -eq 'Failed'){ | ||
Write-Output "Creating container failed:" | ||
throw $($createContainerJob.ChildJobs | ForEach-Object { $_.JobStateInfo.Reason.Message } | Out-String) | ||
} | ||
} | ||
|
||
if(Test-ContainerExists -containerName $containerName) { | ||
Write-Host "Container $containerName is available" -ForegroundColor Green | ||
} else { | ||
throw "Container $containerName not available. Check if the container was created successfully and is running." | ||
} | ||
|
||
|
||
# Publish apps | ||
Write-Host "Publishing apps..." -ForegroundColor Yellow | ||
$publishingAppsStats = Measure-Command { | ||
foreach($currentAppFile in $appFiles) { | ||
Publish-BcContainerApp -containerName $containerName -appFile $currentAppFile -syncMode ForceSync -sync -credential $credential -skipVerification -install -useDevEndpoint -replacePackageId | ||
} | ||
} | ||
|
||
Write-Host "Publishing apps took $($publishingAppsStats.TotalSeconds) seconds" | ||
|
Oops, something went wrong.