Build tasks
Build tasks compose a Business Central build pipeline: resolve the artifact, version the app, create the container, restore dependencies, compile, sign, publish, test and clean up. Every build task is free of license. Each task is a thin wrapper over exactly one businessdev.ALbuild cmdlet, so the behaviour is identical locally and in CI.
Tasks in this category
| Task | Reference name | Purpose |
|---|---|---|
| Check Translations | CheckTranslations@0 | Checks AL XLIFF files for missing and needs-work translations (CI gate). |
| Cleanup ALbuild Caches | CleanupCaches@0 | Prunes old, unused ALbuild artifact/package/BC-artifact caches (and optionally Docker) to reclaim agent disk space. |
| Compile AL App | CompileApp@0 | Compiles an AL project into an .app package using the AL tool or a container. |
| Create BC Container | CreateBcContainer@0 | Creates a Business Central container from an artifact URL and waits for it to be ready. |
| Create BC Container User | CreateBcContainerUser@0 | Creates a Business Central user inside a container and assigns a permission set. |
| Create NuGet Package | CreateNuGetPackage@0 | Creates a NuGet package (.nupkg) from a compiled Business Central .app. |
| Get BC Artifact | GetBcArtifact@0 | Resolves a Business Central artifact URL and stores it in an output variable. |
| Get Universal Package | GetUniversalPackage@0 | Downloads a named package from an Azure DevOps Universal feed into a folder. |
| Import Configuration Package | ImportConfigPackage@0 | Imports a RapidStart (.rapidstart) configuration package into a Business Central container. |
| Install 365 App | InstallBc365App@0 | Installs one or more 365 business development apps into a Business Central container. |
| Install Dependencies | InstallDependencies@0 | Installs an AL project's resolved dependency apps into the container, in dependency order. |
| Install Test Toolkit | InstallTestToolkit@0 | Publishes and installs the Business Central test toolkit apps into a container. |
| Publish App | PublishApp@0 | Publishes, synchronises and installs an .app into a Business Central container. |
| Publish Testiny Results | PublishTestinyResults@0 | Publishes a JUnit test result file to Testiny. |
| Remove BC Container | RemoveBcContainer@0 | Removes a Business Central build container. |
| Resolve Dependencies | ResolveDependencies@0 | Resolves an AL project's dependencies from NuGet feeds and writes them to .alpackages. |
| Run AL Tests | RunBcTests@0 | Runs AL tests in a Business Central container using ALbuild's built-in test runner and publishes a JUnit result file. |
| Sign AL App | SignBcApp@0 | Signs .app files with an Azure Key Vault certificate (AzureSignTool). |
| Stamp Build Version | StampBuildVersion@0 | Stamps the app version into app.json and atomically claims a build/<version> branch (parallel-safe). |
Check Translations
Reference name: CheckTranslations@0
Checks AL XLIFF files for missing and needs-work translations (CI gate).
Note: Wraps Test-BcTranslation from the businessdev.ALbuild module.
Underlying cmdlet: Test-BcTranslation
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
path | filePath | No | — | Translations path (empty = all AL projects in the repo) |
excludeProjects | string | No | — | Projects to exclude (folder names, comma-separated) |
skipNeedsWork | boolean | No | false | Only check for missing translations |
failOnIssue | boolean | No | true | Fail on any issue |
Note: Validates the .xlf translation files (missing or untranslated entries).
failOnIssue(default true) fails the build when problems are found;skipNeedsWork(default false) ignores units flagged as needing work. This task sets no output variables.
Cleanup ALbuild Caches
Reference name: CleanupCaches@0
Prunes old, unused ALbuild artifact/package/BC-artifact caches (and optionally Docker) to reclaim agent disk space.
Note: Wraps Clear-ALbuildCache from the businessdev.ALbuild module. Removes cache entries not written within the retention window (default 30 days), keeping recent ones, from the cache folders configured via Get-ALbuildConfig. Runs non-interactively (no confirmation prompt); use 'What-if' to preview.
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
keepDays | string | No | 30 | Cache entries not written within this many days are removed. Default 30. |
keepLatest | string | No | 0 | Safety floor: always keep at least this many most-recently-written entries per cache, regardless of age. |
cache | pickList | No | All | Caches to prune Options: All = All, Artifacts = Artifacts (symbols), Packages = Packages, BcArtifacts = BC artifacts. |
includeDocker | boolean | No | false | Also prune unused Docker images/stopped containers |
whatIf | boolean | No | false | What-if (preview only, delete nothing) |
Note: Reclaims disk on long-lived self-hosted agents. ALbuild's caches grow unbounded - a multi-GB entry per BC version in the BC artifact cache (C:\bcartifacts.cache -> C:\dl), the host artifact/symbol cache and the dependency package cache - and nothing trims them automatically; repeated 'docker pull' also orphans old images. Add this as a first or scheduled step so every build self-maintains.
keepLatestis a safety floor (never empties a cache);keepDayssets the retention window.includeDockerrunsdocker image/container prunefiltered to the same window. UsewhatIf: trueto preview what would be removed without deleting. Reads the cache locations from Get-ALbuildConfig, so it prunes exactly the folders the tasks use (including any relocated to a roomier drive). This task sets no output variables. As of module 2.17.0, New-BcContainer also auto-prunes as a last resort when the drive is below its disk floor - but a scheduled CleanupCaches step is the intended retention mechanism.
Compile AL App
Reference name: CompileApp@0
Compiles an AL project into an .app package using the AL tool or a container.
Note: Wraps Invoke-BcCompiler from the businessdev.ALbuild module.
Underlying cmdlet: Invoke-BcCompiler
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
projectFolder | filePath | No | — | Project folder (empty = all AL projects in the repo) |
excludeProjects | string | No | — | Projects to exclude (folder names, comma-separated) |
outputFolder | filePath | No | — | Where to write the built .app files. Leave empty to use the build's artifact staging directory, so the Sign and Publish tasks find them without extra wiring. |
engine | pickList | No | AlTool | Engine Options: AlTool = AL tool (cross-platform), Container = Container. |
containerName | string | No | — | Container name (Container engine) |
artifactUrl | string | No | $(bcArtifactUrl) | BC artifact URL (for first-party symbols) |
testToolkitSymbols | string | No | $(bcTestToolkitSymbols) | Host folder of test-toolkit .app symbols bridged out of the container by the Install Test Toolkit task. Needed for an AL Tool compile of a test app when the artifact ships those symbols only inside the container (e.g. country 'w1'). |
compilerPath | string | No | — | AL compiler path (blank = auto-detect / install the AL Tool) |
installAlTool | boolean | No | true | Install the AL Tool on the agent if missing (AlTool engine) |
alToolVersion | string | No | — | Pin an exact AL Tool (compiler) version, e.g. '18.0.39.10160-beta'. Leave blank to derive it from the BC artifact being built against: the AL Tool major IS the AL runtime it supports (BC28 = runtime 17 = AL Tool 17.x, BC29 = 18 = 18.x). A compiler older than the app's runtime fails with AL1043. |
alToolPrerelease | pickList | No | Auto | A BC major that has not shipped yet (NextMajor) publishes ONLY prerelease ('-beta') compilers, so 'Auto' falls back to one for that runtime and returns to the stable compiler automatically once the major goes GA. 'Never' makes such a build fail rather than use a prerelease compiler. Options: Auto = Auto - only when the target runtime has no stable compiler (NextMajor), Always = Always - newest, even if prerelease, Never = Never - stable only. |
analyzers | string | No | — | Analyzers to run during compile: 'CodeCop', 'UICop', 'AppSourceCop', 'PerTenantExtensionCop' (with or without the '${...}' wrapper), or explicit analyzer DLL paths. Overrides the project's albuild.json 'analyzers' and .vscode/settings.json 'al.codeAnalyzers'. Leave blank to use those. Empty everywhere = no analyzers. |
ruleset | string | No | — | Ruleset file applied to the analyzers. Overrides albuild.json 'ruleset' and .vscode/settings.json 'al.ruleSetPath'. Relative paths resolve against the project folder. |
updateManifest | boolean | No | false | Before compiling, rewrite each app.json for the BC version being built against: set application/runtime/platform to the target, and inject the BC<min>..BC<current> preprocessor symbols (min = the app's own 'application' major) so version-conditional AL ('#if BC24') compiles. Needed when building runtime packages for older platform versions. |
preprocessorSymbols | string | No | — | Additional preprocessor symbols to add alongside the BC<n> range (only applied when 'Update app.json' is enabled). |
treatWarningsAsErrors | boolean | No | false | When true, any 'warning' diagnostic from the compiler or an analyzer fails the task (the individual warnings are still shown as annotations). Use to enforce a clean-code / analyzer quality gate. Default false keeps existing pipeline behaviour. |
Option values
engine
| Value | Meaning |
|---|---|
AlTool | Cross-platform, container-less compile with the AL compiler tool (fast; no container needed). Default. |
Container | Compile inside the BC container named by containerName (uses the container's bundled compiler). |
alToolPrerelease
| Value | Meaning |
|---|---|
Auto | Prefer a stable compiler for the target runtime, and fall back to a prerelease only when that runtime has none. Default - this is what makes a NextMajor build work, and it returns to the stable compiler by itself once the BC major ships. |
Always | Always take the newest compiler for the runtime, even when it is a prerelease. |
Never | Stable compilers only; a build whose target runtime has no stable compiler fails instead of using a prerelease. |
Output variables
| Variable | Description |
|---|---|
bcAppFile | Path to the first built .app (convenience for single-app repos). |
bcAppFiles | All built .app paths, semicolon-joined, in dependency (build) order. |
Note: The
analyzersinput is free text, not a pickList: the built-in names areCodeCop,UICop,AppSourceCop,PerTenantExtensionCop(with or without the${...}wrapper), or explicit analyzer DLL paths. It overrides albuild.jsonanalyzersand .vscode/settings.jsonal.codeAnalyzers; blank everywhere = no analyzers.
The AL compiler is matched to the BC version you build against: the AL Tool's major version IS the AL runtime it supports (BC28 = runtime 17 = AL Tool 17.x, BC29 = 18 = 18.x), and a compiler older than the app's runtime fails with AL1043. The task derives that from artifactUrl and installs the matching AL Tool into its own per-version folder rather than the machine-wide global tool, so parallel stages building different BC majors on one agent keep their own compiler. Pin an exact version with alToolVersion, or change the prerelease policy with alToolPrerelease.
Create BC Container
Reference name: CreateBcContainer@0
Creates a Business Central container from an artifact URL and waits for it to be ready.
Note: Wraps New-BcContainer from the businessdev.ALbuild module. Sets the 'containerName', 'containerUsername' and 'containerPassword' pipeline variables for downstream tasks.
Underlying cmdlet: New-BcContainer
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
artifactUrl | string | No | $(bcArtifactUrl) | Artifact URL |
containerName | string | No | albuild-$(Build.BuildId) | Container name |
auth | pickList | No | UserPassword | Authentication Options: UserPassword = UserPassword, NavUserPassword = NavUserPassword, Windows = Windows, AAD = AAD. |
userName | string | No | admin | Admin user name |
password | string | No | — | Admin password (blank = generated) |
licenseFile | string | No | — | License file (path or URL) |
memoryLimit | string | No | — | Memory limit (e.g. 8G) |
isolation | pickList | No | — | Isolation Options: = (auto), process = process, hyperv = hyperv. |
Option values
auth
| Value | Meaning |
|---|---|
UserPassword | Username/password authentication (the usual CI choice). |
NavUserPassword | Classic NAV username/password authentication. |
Windows | Windows (NTLM) authentication using the container host identity. |
AAD | Microsoft Entra ID (Azure AD) authentication. |
isolation
| Value | Meaning |
|---|---|
(empty) | Let Docker choose the isolation mode automatically based on the host. |
process | Process isolation - lighter/faster; requires matching host and container OS builds. |
hyperv | Hyper-V isolation - stronger isolation; tolerates host/container OS mismatch, more overhead. |
Output variables
| Variable | Description |
|---|---|
containerName | The name of the created container (consumed by Publish/Run tasks). |
containerUsername | The admin username inside the container. |
containerPassword | The admin password (marked secret; a random password is generated when password is left blank). |
Note: If
passwordis blank a random password is generated and exposed (secret) as$(containerPassword).memoryLimit(e.g.8G) caps container memory. Requires a Docker engine on the agent.
Create BC Container User
Reference name: CreateBcContainerUser@0
Creates a Business Central user inside a container and assigns a permission set.
Note: Wraps New-BcContainerUser from the businessdev.ALbuild module.
Underlying cmdlet: New-BcContainerUser
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
userName | string | No | $(containerUsername) | User name |
password | string | No | $(containerPassword) | Password |
permissionSetId | string | No | SUPER | Permission set |
Note: Creates a user inside the container and assigns a permission set.
userName/passworddefault to the container admin credentials set by Create BC Container;permissionSetIddefaults toSUPER. This task sets no output variables.
Create NuGet Package
Reference name: CreateNuGetPackage@0
Creates a NuGet package (.nupkg) from a compiled Business Central .app.
Note: Wraps New-BcNuGetPackage from the businessdev.ALbuild module. Packages each matched .app - a single file, every .app under a folder, or a wildcard - into a .nupkg (*.runtime.app is skipped; use the runtime-package flow for those). Sets the output variable (default 'bcNuGetPackage') to the first package and 'bcNuGetPackages' to all of them; feed those to the 'Publish NuGet Package' task.
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
path | string | No | $(bcAppFile) | The compiled .app to package, a folder to package every .app in, or a wildcard. Defaults to the primary app built by 'Compile AL App'. |
packageId | string | No | — | Package id (blank = derived from id scheme) |
idScheme | string | No | {publisher}.{name}.{id} | Template for the package id when 'Package id' is blank. Placeholders: {publisher}, {name}, {id}. |
version | string | No | — | Package version (blank = app version) |
authors | string | No | — | Authors (blank = app publisher) |
description | string | No | — | Description (blank = app name) |
outputFolder | filePath | No | — | Where the .nupkg files are written. Blank = a 'nuget' folder under the artifact staging directory (or the app's own folder). |
outputVariable | string | No | bcNuGetPackage | Output variable name |
Option values
idScheme
| Value | Meaning |
|---|---|
{publisher} | Placeholder replaced by the app publisher from app.json. |
{name} | Placeholder replaced by the app name from app.json. |
{id} | Placeholder replaced by the app id (GUID) from app.json. |
Output variables
| Variable | Description |
|---|---|
bcNuGetPackage | Path to the first created .nupkg. The variable name is configurable via the outputVariable input (default bcNuGetPackage). |
bcNuGetPackages | All created .nupkg paths, semicolon-joined (always set under this fixed name). |
Note: Wraps one or more .app files into NuGet packages. The package id comes from
packageIdwhen set, otherwise fromidScheme(a template of{publisher},{name},{id}).versiondefaults to the app.json version. The primary output variable name is chosen withoutputVariable; the pluralbcNuGetPackagesis always emitted as well.
Get BC Artifact
Reference name: GetBcArtifact@0
Resolves a Business Central artifact URL and stores it in an output variable.
Note: Wraps Find-BcArtifactUrl from the businessdev.ALbuild module.
Underlying cmdlet: Find-BcArtifactUrl
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
type | pickList | No | — | Type Options: = (from albuild.json / Sandbox), Sandbox = Sandbox, OnPrem = OnPrem. |
country | string | No | — | Leave empty to use the country from albuild.json (default w1). |
version | string | No | — | Version |
select | pickList | No | — | Select Options: = (from albuild.json / Latest), Latest = Latest, First = First, Closest = Closest, NextMinor = NextMinor, NextMajor = NextMajor. |
projectFolder | filePath | No | — | Project folder (reads albuild.json) |
dependencyAware | boolean | No | false | For a plain 'Latest' (no pinned Version): pick the newest BC whose build all projects' dependencies still resolve against, stepping back through minor versions when an ISV has not shipped packages for the latest BC yet. Emits a warning when it downgrades. |
maxDowngradeSteps | string | No | 5 | How many minor versions back the dependency-aware selection may step (crossing a major boundary to the previous major's latest minor). Shown when dependencyAware is on. (Shown when: dependencyAware = true.) |
outputVariable | string | No | bcArtifactUrl | Output variable name |
Option values
type
| Value | Meaning |
|---|---|
(empty) | Take the artifact type from albuild.json (falls back to Sandbox). |
Sandbox | The Sandbox artifact (in-memory, cronus demo data) - the normal build/test target. |
OnPrem | The OnPrem artifact - use when building/testing against the on-premises platform. |
select
| Value | Meaning |
|---|---|
(empty) | Take the selection strategy from albuild.json (falls back to Latest). |
Latest | Newest artifact matching type/country/version. |
First | Earliest artifact matching the filter. |
Closest | Artifact closest to the given version. |
NextMinor | The upcoming next-minor Insider build (requires accepting the BC Insider EULA). |
NextMajor | The upcoming next-major Insider build (requires accepting the BC Insider EULA). |
Output variables
| Variable | Description |
|---|---|
bcArtifactUrl | The resolved artifact URL. The variable name is configurable via the outputVariable input (default bcArtifactUrl). |
bcArtifactVersion | The BC version parsed from the artifact URL (e.g. 26.1.12345.12345). Consumed by Resolve Dependencies. Not set if the URL cannot be parsed (logged as a warning). |
Note: Set
dependencyAware: trueto down-select the artifact so the app's dependency closure stays resolvable;maxDowngradeSteps(visible only then) caps how many minor versions it may step down.
Get Universal Package
Reference name: GetUniversalPackage@0
Downloads a named package from an Azure DevOps Universal feed into a folder.
Note: Wraps Get-BcUniversalPackage from the businessdev.ALbuild module. Requires the Azure CLI with the azure-devops extension on the agent.
Underlying cmdlet: Get-BcUniversalPackage
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
organization | string | No | $(System.TeamFoundationCollectionUri) | Organization (URL or name) |
feed | string | No | — | Feed |
name | string | No | — | Package name |
version | string | No | * | Version (or *) |
outputFolder | filePath | No | — | Output folder |
project | string | No | — | Project (for project-scoped feeds) |
accessToken | string | No | $(System.AccessToken) | Access token (PAT) |
Note: Downloads an Azure Artifacts Universal Package from the named
feedintooutputFolder.versionaccepts an exact version or*(latest). Setprojectfor a project-scoped feed;organizationandaccessTokendefault to the running collection and the build service token. This task sets no output variables.
Import Configuration Package
Reference name: ImportConfigPackage@0
Imports a RapidStart (.rapidstart) configuration package into a Business Central container.
Note: Wraps Import-BcConfigurationPackage from the businessdev.ALbuild module.
Underlying cmdlet: Import-BcConfigurationPackage
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
path | filePath | No | — | Path (.rapidstart file or folder) |
Note: Imports and applies a RapidStart configuration package into the container (e.g. to seed setup/master data before tests). This task sets no output variables.
Install 365 App
Reference name: InstallBc365App@0
Installs one or more 365 business development apps into a Business Central container.
Note: Wraps Install-Bc365App from the businessdev.ALbuild module. Provide one app id per line.
Underlying cmdlet: Install-Bc365App
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
appId | multiLine | No | — | App id(s) (one per line) |
installerUrl | string | No | — | Installer URL (optional) |
Note: Installs one or more 365 business development apps into the container by app id. The
appIdinput is multi-line - provide one app id per line.installerUrloverrides the default installer source. This task sets no output variables.
Install Dependencies
Reference name: InstallDependencies@0
Installs an AL project's resolved dependency apps into the container, in dependency order.
Note: Wraps Install-BcContainerDependency from the businessdev.ALbuild module. Run after Resolve Dependencies and before publishing the built apps, so the app under test can be installed against its dependencies.
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
projectFolder | filePath | No | — | Project folder (empty = all AL projects in the repo) |
excludeProjects | string | No | — | Projects to exclude (folder names, comma-separated) |
packageFolder | filePath | No | — | Dependency package folder (default: each project's .alpackages) |
skipVerification | boolean | No | true | Skip signature verification |
Note: Publishes the resolved dependency .app files into the container so the app under test can be installed.
packageFolderpoints at the folder holding the dependency packages (defaults to the resolved symbols cache);skipVerification(default true) skips app signature verification. This task sets no output variables.
Install Test Toolkit
Reference name: InstallTestToolkit@0
Publishes and installs the Business Central test toolkit apps into a container.
Note: Wraps Install-BcContainerTestToolkit from the businessdev.ALbuild module. Exports the installed toolkit .app symbols to a host folder and publishes it as the 'bcTestToolkitSymbols' pipeline variable, so a following AL Tool Compile AL App can resolve test-toolkit symbols (required for test apps on country 'w1').
Underlying cmdlet: Install-BcContainerTestToolkit
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
includeTestLibrariesOnly | boolean | No | true | Default (checked): install just the test framework + libraries — what you need to compile and run your own test app, and fast. Uncheck to also publish Microsoft's full test content apps (all Tests-* apps, recompiled in the container) — rarely needed, and much slower. |
symbolExportFolder | string | No | — | Host folder to export the installed toolkit .app symbols into (for an AL Tool host compile). Blank = a folder under the agent temp directory; the path is published as the 'bcTestToolkitSymbols' variable. |
Output variables
| Variable | Description |
|---|---|
bcTestToolkitSymbols | Folder the exported test-toolkit symbols were written to (consumed by Compile App via testToolkitSymbols). |
Note: Installs Microsoft's test toolkit into the container.
includeTestLibrariesOnly(default true) installs only the test libraries needed to compile/run tests; set false to install the complete test framework.symbolExportFolderoverrides where the test symbols are exported.
Publish App
Reference name: PublishApp@0
Publishes, synchronises and installs an .app into a Business Central container.
Note: Wraps Publish-BcContainerApp from the businessdev.ALbuild module.
Underlying cmdlet: Publish-BcContainerApp
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
appFile | string | No | — | App (.app) file (single-app; leave empty to publish all built apps) |
appFolder | filePath | No | $(Build.ArtifactStagingDirectory) | Folder of built .app files (multi-project) |
projectFolder | filePath | No | — | Project folder (empty = all AL projects in the repo) |
excludeProjects | string | No | — | Projects to exclude (folder names, comma-separated) |
syncMode | pickList | No | Add | Schema sync mode Options: Add = Add, Clean = Clean, Development = Development, ForceSync = ForceSync. |
skipVerification | boolean | No | true | Skip signature verification |
install | boolean | No | true | Install after sync |
Option values
syncMode
| Value | Meaning |
|---|---|
Add | Additive schema sync - only non-breaking schema changes are applied; existing data is kept. Default. |
Clean | Publish with a clean schema: the app's tables are recreated, discarding their data. Use for a fresh install. |
Development | Development sync (rapid application development): schema changes are forced and table data may be lost - for dev boxes only. |
ForceSync | Force the schema sync through even for breaking changes (fields/tables may be dropped). Data loss is possible. |
Note: Publishes into the container named by
containerName(defaults to the$(containerName)set by Create BC Container).skipVerification(default true) skips app signature verification;install(default true) installs the app after publishing. This task sets no output variables.
Publish Testiny Results
Reference name: PublishTestinyResults@0
Publishes a JUnit test result file to Testiny.
Note: Wraps Publish-BcTestinyResult from the businessdev.ALbuild module. For standard pipeline reporting use the built-in PublishTestResults task.
Underlying cmdlet: Publish-BcTestinyResult
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
resultsFile | filePath | No | TestResults.xml | Results file (JUnit) |
apiKey | string | No | — | Testiny API key |
projectId | string | No | — | Testiny project id |
runId | string | No | — | Testiny run id (optional) |
Note: Uploads the test results (JUnit XML, e.g. the
$(bcTestResults)from Run Tests) to the Testiny test-management service for the givenprojectId.apiKey,resultsFileandprojectIdare required.runIdtargets an existing run; when omitted a new run is created. This task sets no output variables.
Remove BC Container
Reference name: RemoveBcContainer@0
Removes a Business Central build container.
Note: Wraps Remove-BcContainer from the businessdev.ALbuild module.
Underlying cmdlet: Remove-BcContainer
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | — | Container name |
Note: Removes the BC container. Put this in a cleanup step with
condition: always()so the container is torn down even when the build fails. This task sets no output variables.
Resolve Dependencies
Reference name: ResolveDependencies@0
Resolves an AL project's dependencies from NuGet feeds and writes them to .alpackages.
Note: Wraps Register-BcFeed + Resolve-BcDependencies from the businessdev.ALbuild module. NuGet feeds take precedence over the albuild.json Universal/local/URL packages: a dependency a registered feed offers is resolved from the feed, and those external packages are used only as a fallback for apps no feed provides.
Underlying cmdlet: Resolve-BcDependencies
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
projectFolder | filePath | No | — | Project folder (empty = all AL projects in the repo) |
excludeProjects | string | No | — | Projects to exclude (folder names, comma-separated) |
includeMicrosoftDefaults | boolean | No | true | Include Microsoft default feeds |
feedUrl | string | No | — | NuGet feed URL (v3 index.json) |
feedToken | string | No | — | Feed token / PAT |
feedKind | pickList | No | symbols | Feed kind Options: symbols = symbols, apps = apps, runtime = runtime. |
select | pickList | No | Latest | Selection Options: Latest = Latest, LowestCompatible = LowestCompatible. |
containerName | string | No | $(containerName) | Container (pin installed apps) |
targetVersion | string | No | $(bcArtifactVersion) | The BC version dependency resolution caps against. Defaults to $(bcArtifactVersion) from the Get BC Artifact task so a container-less build still honours the pinned BC version. Falls back to the container's platform version, then albuild.json 'bcVersion'. |
outputFolder | filePath | No | — | Output folder (.alpackages) |
Option values
feedKind
| Value | Meaning |
|---|---|
symbols | Download the symbols (.app placeholder) packages - enough to compile against. Default. |
apps | Download the full runtime .app packages - needed to publish/install the dependencies. |
runtime | Download the runtime-package variant of the dependencies. |
select
| Value | Meaning |
|---|---|
Latest | Take the newest compatible version of each dependency. Default. |
LowestCompatible | Take the lowest version that still satisfies the app.json dependency range (reproducible minimum-baseline builds). |
Note: Restores dependencies from a NuGet feed into the symbols cache.
targetVersion(default$(bcArtifactVersion)from Get BC Artifact) pins the BC platform the dependencies must match;includeMicrosoftDefaults(default true) also pulls the Microsoft first-party symbol packages. This task sets no output variables.
Run AL Tests
Reference name: RunBcTests@0
Runs AL tests in a Business Central container using ALbuild's built-in test runner and publishes a JUnit result file.
Note: Wraps Invoke-BcContainerTest from the businessdev.ALbuild module. Discovers AL test apps under the project folder (honouring each app's pipeline.config alTestRunnerId) or runs an explicit extension id.
Underlying cmdlet: Invoke-BcContainerTest
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
containerName | string | No | $(containerName) | Container name |
username | string | No | $(containerUsername) | Container user |
password | string | No | $(containerPassword) | Container password |
auth | string | No | NavUserPassword | Client services auth |
projectFolder | filePath | No | — | Project folder |
extensionId | string | No | — | Extension id (optional) |
testSuite | string | No | DEFAULT | Test suite |
testRunnerCodeunitId | string | No | — | Test runner codeunit id (optional) |
disableIsolation | boolean | No | False | Disable test isolation |
installTestToolkit | boolean | No | True | Auto-install the BC test toolkit into the container when it is not already present, so a separate Install Test Toolkit step is not required. |
includeTestLibrariesOnly | boolean | No | False | Test libraries only (when auto-installing) |
resultPath | filePath | No | TestResults.xml | Result file (JUnit) |
failOnTestFailure | boolean | No | False | Fail on test failure |
codeCoverage | pickList | No | Disabled | Capture Business Central code coverage at this granularity while the tests run. When enabled, a Cobertura file and a Markdown summary are produced and (optionally) published. Options: Disabled = Disabled, PerRun = Per run, PerCodeunit = Per codeunit, PerTest = Per test. |
codeCoverageMap | pickList | No | Disabled | Also capture a test -> covered-line map. Options: Disabled = Disabled, PerCodeunit = Per codeunit, PerTest = Per test. (Shown when: codeCoverage != Disabled.) |
coverageFormats | string | No | Cobertura,Markdown | Comma-separated: ALbuildJson, Cobertura, Markdown, Html. 'Html' writes a self-contained report that the build's Code Coverage tab renders; it is added automatically when 'Publish coverage' is on, so you only need to list it here if you want the report without publishing. (Shown when: codeCoverage != Disabled.) |
coverageWorkspaceRoot | filePath | No | — | AL source root, so coverage maps to your app objects only and to source files. Defaults to the project folder. (Shown when: codeCoverage != Disabled.) |
coverageOutputFolder | filePath | No | CodeCoverage | Coverage output folder (Shown when: codeCoverage != Disabled.) |
publishCoverage | boolean | No | True | Publish the Cobertura file to the build and append the Markdown summary to the build summary. This also generates the HTML report the Code Coverage tab renders - without it the tab reports "report HTML was not found", because the publish command uploads a report directory but never creates one. The report lists objects lowest-coverage first and expands to uncovered line ranges and annotated source. Azure DevOps runs no JavaScript in that tab, so filtering and column sorting appear only when you download the report artifact and open it in a browser; everything else works in the tab itself. (Shown when: codeCoverage != Disabled.) |
minLineCoverage | string | No | — | Fail (or warn) the task when honest line coverage is below this percent. Empty = no gate. Uses the source-based denominator. (Shown when: codeCoverage != Disabled.) |
minObjectLineCoverage | string | No | — | Optional per-object coverage floor; any object below it fails the gate. (Shown when: codeCoverage != Disabled.) |
failOnCoverageBelow | boolean | No | True | Fail build when below coverage gate (Shown when: codeCoverage != Disabled.) |
checkTestQuality | boolean | No | False | Test quality is ALWAYS part of the coverage report and the build summary when coverage is enabled - coverage says which lines ran, not that a wrong result would be caught, because a [Test] method that asserts nothing still covers every line it touches. This option adds the bcTestQualityScore build variable and raises a build WARNING when tests without assertions exist; it is off by default so switching on coverage does not start flagging existing pipelines. |
Option values
codeCoverage
| Value | Meaning |
|---|---|
Disabled | No code coverage is collected. Default. |
PerRun | Collect one coverage result for the whole test run. |
PerCodeunit | Collect coverage separately per test codeunit. |
PerTest | Collect coverage separately per test method (most granular, slowest). |
codeCoverageMap
| Value | Meaning |
|---|---|
Disabled | Do not produce a coverage map. Default. |
PerCodeunit | Emit a coverage map per codeunit. |
PerTest | Emit a coverage map per test method. |
coverageFormats
| Value | Meaning |
|---|---|
Cobertura | Cobertura XML - published to the build's Code Coverage tab. |
Markdown | A Markdown summary - uploaded as a build summary tab. |
ALbuildJson | The raw ALbuild JSON coverage document. |
Output variables
| Variable | Description |
|---|---|
bcTestResults | Path to the JUnit/XML test results file (resultPath). |
bcCoverageLineRate | Overall line-coverage rate (only when code coverage is enabled). |
bcCoverageCobertura | Path to the generated Cobertura XML (only when Cobertura is among coverageFormats). |
bcTestQualityScore | Test-quality score (only when checkTestQuality is true). |
Note: The
coverageFormatsinput is a comma-separated list; valid entries areCobertura,MarkdownandALbuildJson.minLineCoverage/minObjectLineCoverageset coverage thresholds; combined withfailOnCoverageBelow(default true) they fail the build when coverage is below target.checkTestQualityadditionally warns about tests without assertions.
Sign AL App
Reference name: SignBcApp@0
Signs .app files with an Azure Key Vault certificate (AzureSignTool).
Note: Wraps Invoke-BcAppSigning from the businessdev.ALbuild module. AzureSignTool must be available on the agent. NOTE: Azure DevOps does not pass secret pipeline variables into task inputs. If your Key Vault credentials are secret variables, map them via the task 'env:' block instead of inputs: ALBUILD_SIGN_KEYVAULTURL, ALBUILD_SIGN_TENANTID, ALBUILD_SIGN_CLIENTID, ALBUILD_SIGN_CLIENTSECRET, ALBUILD_SIGN_CERTNAME.
Underlying cmdlet: Invoke-BcAppSigning
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
path | string | No | $(bcAppFile) | App file / folder / wildcard |
keyVaultUrl | string | No | — | Key Vault URL |
tenantId | string | No | — | Tenant id |
clientId | string | No | — | Client id |
clientSecret | string | No | — | Client secret |
certificateName | string | No | — | Certificate name |
timestampUrl | string | No | http://timestamp.digicert.com | Timestamp URL |
Note: Azure DevOps does not pass secret variables to task inputs, so the Key Vault credentials are read from the
ALBUILD_SIGN_KEYVAULTURL/_TENANTID/_CLIENTID/_CLIENTSECRET/_CERTNAMEenvironment variables when the matching inputs are blank. Signs via Azure Key Vault (AzureSignTool); the certificate must be a code-signing cert.timestampUrldefaults tohttp://timestamp.digicert.com.
Stamp Build Version
Reference name: StampBuildVersion@0
Stamps the app version into app.json and atomically claims a build/<version> branch (parallel-safe).
Note: Wraps Invoke-BcBuildVersionStamp from the businessdev.ALbuild module. Uses a branch-push compare-and-swap so concurrent builds never share a version.
Underlying cmdlet: Invoke-BcBuildVersionStamp
Example
Code
Inputs
| Input | Type | Required | Default | Description |
|---|---|---|---|---|
path | filePath | No | — | Repository / project path |
schema | string | No | major.minor.increment.0 | One token per dotted position: a number = literal; 'increment' = current + 1; 'build-id' = the build id; 'no-of-commits' = the git commit count; 'date' = a yyyyMMdd date stamp; 'major'/'minor'/'build'/'revision'/'keep' = keep the current app.json component; 'latest' = take the component from the latest build branch (implies Seed from build branch). Fewer than four tokens keeps the remaining lower components unchanged. E.g. 'latest.latest.latest.build-id' → keep Major.Minor.Build from the latest CI build, revision = build id. |
version | string | No | — | Explicit version (overrides schema) |
buildId | string | No | $(Build.BuildId) | Build id (for the build-id token) |
onlyUpdateOnChangedSource | boolean | No | false | Only version changed apps |
branchPrefix | string | No | build/ | Build branch prefix |
remote | string | No | origin | Git remote |
noBuildBranch | boolean | No | false | Do not create/push a build branch |
seedFromBuildBranch | boolean | No | false | Release/CD use. Instead of claiming a new build branch, read the highest build/<Major>.<Minor>.* the CI already claimed on the remote (e.g. 1.1.588.0), apply the schema to it, and stamp every app to the result — e.g. schema 'latest.latest.latest.build-id' → 1.1.588.$(Build.BuildId). Lets a release pipeline that checks out the source branch (where app.json is still 1.1.0.0) reproduce the CI build number. Also enabled automatically when the schema uses a 'latest' token, so you usually just set the schema. Read-only on the remote (no branch is pushed). Ignored when an explicit version is given. |
updateBuildNumber | boolean | No | true | Update the pipeline build number |
Option values
schema
| Value | Meaning |
|---|---|
<number> | A literal non-negative integer at that position (e.g. the 0 in major.minor.increment.0). |
increment | The current app.json component + 1 (e.g. Build+1). |
build-id | The pipeline build id from the buildId input (default $(Build.BuildId)); must be numeric. |
no-of-commits | The git commit count (V1-style versioning); must be numeric. |
date | A numeric date stamp, yyyyMMdd. |
major | Keep the current Major from app.json (unchanged). |
minor | Keep the current Minor from app.json (unchanged). |
build | Keep the current Build from app.json (unchanged). |
revision | Keep the current Revision from app.json (unchanged). |
keep | Keep the current component at this position (alias of major/minor/build/revision). |
latest | Keep the component, but seed the base version from the latest build/<Major>.<Minor>.* branch on the remote first (i.e. take it from the latest CI build). Auto-enables Seed from build branch. |
Output variables
| Variable | Description |
|---|---|
appVersion | The full stamped version, Major.Minor.Build.Revision. |
appVersionShort | Major.Minor.Build (no revision). |
semanticAppVersion | Alias of appVersionShort. |
appVersionMajor | The Major component. |
appVersionMinor | The Minor component. |
appVersionBuild | The Build component. |
appVersionRevision | The Revision component. |
buildBranch | The build/<version> branch that was claimed and pushed (only emitted when a branch was created, i.e. not with noBuildBranch). |
Note: A schema with fewer than four positions keeps the remaining lower components unchanged (implicit
latest). Any token other than those above fails the build. When the schema contains alatesttoken, or whenseedFromBuildBranchis set, the task reads the highest existingbuild/<Major>.<Minor>.*branch on the remote as the base before applying the schema; the build/<version> branch push is a compare-and-swap (Build is incremented on conflict). Pushing the branch needs the build service to have Contribute on the repo (map $(System.AccessToken) to AZURE_DEVOPS_EXT_PAT).


