Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ jobs:
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
Install-Module BcContainerHelper -Force -Scope CurrentUser -Repository PSGallery
$version = '6.1.17'
Install-Module BcContainerHelper -RequiredVersion $version -Force -Scope CurrentUser -Repository PSGallery
Import-Module BcContainerHelper -Force
Write-Host "Installed BcContainerHelper $((Get-Module BcContainerHelper).Version)."

Expand Down
35 changes: 34 additions & 1 deletion scripts/Test-AlIssueTriageWorkflow.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ function Assert-Contains([string] $Text, [string] $Expected) {
}

$workflowScriptsRoot = Join-Path $repositoryRoot 'scripts\al-issue-triage'
$versionResolverPath = Join-Path $workflowScriptsRoot 'Resolve-TriageSandboxVersions.ps1'
if (-not (Test-Path -LiteralPath $versionResolverPath -PathType Leaf)) {
throw 'Required sandbox version resolver is missing.'
}
$workflowScripts = @{}
foreach ($scriptName in @(
'Install-TriageTools.ps1',
Expand Down Expand Up @@ -69,11 +73,20 @@ foreach ($text in @(

foreach ($assertion in @(
@{ Script = 'Install-TriageTools.ps1'; Text = 'Microsoft.Dynamics.BusinessCentral.Development.Tools --prerelease' },
@{ Script = 'Install-TriageTools.ps1'; Text = "-RequiredVersion `$bcContainerHelperVersion" },
@{ Script = 'Install-TriageTools.ps1'; Text = 'ALTOOL_PATH=$altoolPath' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'Wait-DockerApi' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'Get-BcContainerNavVersion' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'Get-BcContainerPlatformVersion' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'BC_APPLICATION_VERSION=$($versions.Application)' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'BC_PLATFORM_VERSION=$($versions.Platform)' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'BC_SERVER_USERNAME=admin' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'BC_SERVER_PASSWORD=$passwordText' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'BC_SERVER_PORT=7049' },
@{ Script = 'Start-TriageSandbox.ps1'; Text = 'BC_TENANT=default' },
@{ Script = 'Test-AlToolSandboxAccess.ps1'; Text = '$env:BC_APPLICATION_VERSION' },
@{ Script = 'Test-AlToolSandboxAccess.ps1'; Text = '$env:BC_PLATFORM_VERSION' },
@{ Script = 'Test-AlToolSandboxAccess.ps1'; Text = '"retryable":true' },
@{ Script = 'Invoke-AlIssueTriage.ps1'; Text = '$rawOutput.Substring($headingIndex).Trim()' },
@{ Script = 'Invoke-AlIssueTriage.ps1'; Text = 'Invoke verify-prerelease-altool first' },
@{ Script = 'Invoke-AlIssueTriage.ps1'; Text = 'run-al-mcp-tool, compile-al-app' },
Expand All @@ -91,11 +104,20 @@ if ([regex]::Matches($workflow, '(?m)^\s+run:\s+\|').Count -ne 0) {
foreach ($text in @(
'BC_SERVER_USERNAME=admin',
'BC_SERVER_PASSWORD=$passwordText',
'BC_TENANT=default'
'BC_TENANT=default',
'Install-Module BcContainerHelper -RequiredVersion $version'
)) {
Assert-Contains $setup $text
}

$splitVersions = & $versionResolverPath `
-ApplicationVersion '30.0.54242.0-W1' `
-PlatformVersion '29.0.54137.0'
if ($splitVersions.Application -ne '30.0.0.0' -or
$splitVersions.Platform -ne '29.0.0.0') {
throw 'Sandbox application and platform versions were not resolved independently.'
}

foreach ($text in @(
'freshly installed prerelease ALTool',
'`download-al-symbols`',
Expand Down Expand Up @@ -211,6 +233,17 @@ Close this issue as likely fixed; provide a fresh current-version reproduction i
'@
Assert-AlIssueTriageEvidence -Comment $validLikelyFixedRuntimeReport

$validLikelyFixedRecommendationVariant = @'
## Automated AL issue triage
**Classification:** `tooling bug`
- **Scope:** `likely fixed` - Latest prerelease tooling did not exhibit the reported failure.
| ALTool reproduction | `not reproduced` | Executed `run-al-mcp-tool al_build`; observed success without the reported error. |
| BC runtime reproduction | `not attempted` | Not applicable. |
### Recommended next step
We recommend closing this issue as likely fixed; provide a current reproduction if the problem persists.
'@
Assert-AlIssueTriageEvidence -Comment $validLikelyFixedRecommendationVariant

foreach ($invalidReport in @(
@'
## Automated AL issue triage
Expand Down
2 changes: 1 addition & 1 deletion scripts/al-issue-triage/Assert-AlIssueTriageEvidence.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function Assert-AlIssueTriageEvidence {
)
if (-not $recommendedNextStep.Success -or
$recommendedNextStep.Groups['value'].Value -notmatch
'(?i)^\s*(?:please\s+)?close\b.*\blikely fixed\b') {
'(?im)^\s*(?:please\s+|we\s+recommend(?:\s+to)?\s+)?clos(?:e|ing)\b.*\blikely fixed\b') {
throw 'Likely fixed must recommend closing the issue as likely fixed.'
}
if ($recommendedNextStep.Groups['value'].Value -match '(?i)\baccept(?:ed|ance)?\b') {
Expand Down
4 changes: 3 additions & 1 deletion scripts/al-issue-triage/Install-TriageTools.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
param()

$ErrorActionPreference = 'Stop'
$bcContainerHelperVersion = '6.1.17'

dotnet tool install --global Microsoft.Dynamics.BusinessCentral.Development.Tools --prerelease
npm install --global @github/copilot@1.0.79-9
Install-Module BcContainerHelper -Force -Scope CurrentUser -Repository PSGallery
Install-Module BcContainerHelper -RequiredVersion $bcContainerHelperVersion `
-Force -Scope CurrentUser -Repository PSGallery

$alVersion = (& al --version 2>&1 | Out-String).Trim()
if (-not $alVersion) {
Expand Down
35 changes: 35 additions & 0 deletions scripts/al-issue-triage/Resolve-TriageSandboxVersions.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $ApplicationVersion,

[Parameter(Mandatory)]
[string] $PlatformVersion
)

$ErrorActionPreference = 'Stop'

function ConvertTo-ManifestVersion {
param(
[Parameter(Mandatory)]
[string] $Version,

[Parameter(Mandatory)]
[string] $Name
)

$versionText = $Version.Split('-')[0]
try {
$parsedVersion = [version]$versionText
}
catch {
throw "Could not determine the $Name manifest version from '$Version'."
}

"$($parsedVersion.Major).$($parsedVersion.Minor).0.0"
}

[pscustomobject]@{
Application = ConvertTo-ManifestVersion -Version $ApplicationVersion -Name 'application'
Platform = ConvertTo-ManifestVersion -Version $PlatformVersion -Name 'platform'
}
46 changes: 46 additions & 0 deletions scripts/al-issue-triage/Start-TriageSandbox.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,44 @@ param()
$ErrorActionPreference = 'Stop'
Import-Module BcContainerHelper -Force

function Wait-DockerApi {
param(
[int] $MaximumAttempts = 12,
[int] $DelaySeconds = 10
)

$dockerPath = (Get-Command docker -ErrorAction Stop).Source
$lastResponse = 'Docker did not return a response.'
for ($attempt = 1; $attempt -le $MaximumAttempts; $attempt++) {
$dockerService = Get-Service -Name docker -ErrorAction SilentlyContinue
if ($dockerService -and $dockerService.Status -ne 'Running') {
try {
Start-Service -Name docker -ErrorAction Stop
}
catch {
$lastResponse = $_.Exception.Message
}
}

$response = & $dockerPath version --format '{{.Server.Version}}' 2>&1 |
Out-String
if ($LASTEXITCODE -eq 0 -and -not [string]::IsNullOrWhiteSpace($response)) {
Write-Information "Docker API is ready (server $($response.Trim()))." -InformationAction Continue
return
}

if (-not [string]::IsNullOrWhiteSpace($response)) {
$lastResponse = $response.Trim()
}
if ($attempt -lt $MaximumAttempts) {
Write-Warning "Docker API is not ready (attempt $attempt of $MaximumAttempts): $lastResponse"
Start-Sleep -Seconds $DelaySeconds
}
}

throw "Docker API did not become ready after $MaximumAttempts attempts. Last response: $lastResponse"
}

$artifactUrl = Get-BcArtifactUrl -Type Sandbox -Country w1 -Select Latest `
-StorageAccount bcinsider -Accept_InsiderEula
if (-not $artifactUrl -or [string]$artifactUrl -notmatch '(?i)bcinsider') {
Expand All @@ -18,6 +56,8 @@ $credential = [pscredential]::new(
(ConvertTo-SecureString $passwordText -AsPlainText -Force)
)

Wait-DockerApi

New-BcContainer `
-Accept_Eula `
-Accept_InsiderEula `
Expand All @@ -33,8 +73,14 @@ if (-not (Get-BcContainerId -ContainerName $containerName)) {
throw "Business Central container '$containerName' was not created."
}

$versions = & (Join-Path $PSScriptRoot 'Resolve-TriageSandboxVersions.ps1') `
-ApplicationVersion (Get-BcContainerNavVersion -containerOrImageName $containerName) `
-PlatformVersion (Get-BcContainerPlatformVersion -containerOrImageName $containerName)

"BC_CONTAINER_NAME=$containerName" | Add-Content -Path $env:GITHUB_ENV
"BC_ARTIFACT_URL=$artifactUrl" | Add-Content -Path $env:GITHUB_ENV
"BC_APPLICATION_VERSION=$($versions.Application)" | Add-Content -Path $env:GITHUB_ENV
"BC_PLATFORM_VERSION=$($versions.Platform)" | Add-Content -Path $env:GITHUB_ENV
"BC_SERVER_URL=http://$containerName" | Add-Content -Path $env:GITHUB_ENV
"BC_SERVER_INSTANCE=BC" | Add-Content -Path $env:GITHUB_ENV
"BC_SERVER_PORT=7049" | Add-Content -Path $env:GITHUB_ENV
Expand Down
35 changes: 23 additions & 12 deletions scripts/al-issue-triage/Test-AlToolSandboxAccess.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,42 @@ $ErrorActionPreference = 'Stop'
$projectPath = Join-Path $env:RUNNER_TEMP 'altool-sandbox-preflight'
New-Item -ItemType Directory -Path $projectPath -Force | Out-Null

$artifactVersion = [regex]::Match(
$env:BC_ARTIFACT_URL,
'/(?<version>\d+\.\d+\.\d+\.\d+)/'
).Groups['version'].Value
if (-not $artifactVersion) {
throw "Could not determine the BC artifact version from '$env:BC_ARTIFACT_URL'."
foreach ($name in @('BC_APPLICATION_VERSION', 'BC_PLATFORM_VERSION')) {
if ([string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($name))) {
throw "Required sandbox version variable '$name' is unavailable."
}
}

$versionParts = $artifactVersion.Split('.')
$applicationVersion = "$($versionParts[0]).$($versionParts[1]).0.0"
[ordered]@{
id = [guid]::NewGuid().ToString()
name = 'Public AL Triage Preflight'
publisher = 'Microsoft'
version = '1.0.0.0'
platform = $applicationVersion
application = $applicationVersion
platform = $env:BC_PLATFORM_VERSION
application = $env:BC_APPLICATION_VERSION
target = 'OnPrem'
idRanges = @([ordered]@{ from = 50100; to = 50100 })
} | ConvertTo-Json -Depth 5 |
Set-Content -LiteralPath (Join-Path $projectPath 'app.json') -Encoding utf8

try {
& .\.github\skills\download-al-symbols\Invoke-DownloadAlSymbols.ps1 `
-ProjectPath $projectPath
$maximumAttempts = 3
for ($attempt = 1; $attempt -le $maximumAttempts; $attempt++) {
try {
& .\.github\skills\download-al-symbols\Invoke-DownloadAlSymbols.ps1 `
-ProjectPath $projectPath
break
}
catch {
if ($attempt -eq $maximumAttempts -or
$_.Exception.Message -notmatch '"retryable":true') {
throw
}

Write-Warning "ALTool symbol download failed with a retryable error (attempt $attempt of $maximumAttempts): $($_.Exception.Message)"
Start-Sleep -Seconds 10
}
}
}
finally {
Remove-Item -LiteralPath $projectPath -Recurse -Force -ErrorAction SilentlyContinue
Expand Down