Security change on December 1, 2026: TLS 1.2 will become the minimum standard for 365 business Print Agent. Details and system requirements
365 business development
Azure DevOps Extension

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

TaskReference namePurpose
Check TranslationsCheckTranslations@0Checks AL XLIFF files for missing and needs-work translations (CI gate).
Cleanup ALbuild CachesCleanupCaches@0Prunes old, unused ALbuild artifact/package/BC-artifact caches (and optionally Docker) to reclaim agent disk space.
Compile AL AppCompileApp@0Compiles an AL project into an .app package using the AL tool or a container.
Create BC ContainerCreateBcContainer@0Creates a Business Central container from an artifact URL and waits for it to be ready.
Create BC Container UserCreateBcContainerUser@0Creates a Business Central user inside a container and assigns a permission set.
Create NuGet PackageCreateNuGetPackage@0Creates a NuGet package (.nupkg) from a compiled Business Central .app.
Get BC ArtifactGetBcArtifact@0Resolves a Business Central artifact URL and stores it in an output variable.
Get Universal PackageGetUniversalPackage@0Downloads a named package from an Azure DevOps Universal feed into a folder.
Import Configuration PackageImportConfigPackage@0Imports a RapidStart (.rapidstart) configuration package into a Business Central container.
Install 365 AppInstallBc365App@0Installs one or more 365 business development apps into a Business Central container.
Install DependenciesInstallDependencies@0Installs an AL project's resolved dependency apps into the container, in dependency order.
Install Test ToolkitInstallTestToolkit@0Publishes and installs the Business Central test toolkit apps into a container.
Publish AppPublishApp@0Publishes, synchronises and installs an .app into a Business Central container.
Publish Testiny ResultsPublishTestinyResults@0Publishes a JUnit test result file to Testiny.
Remove BC ContainerRemoveBcContainer@0Removes a Business Central build container.
Resolve DependenciesResolveDependencies@0Resolves an AL project's dependencies from NuGet feeds and writes them to .alpackages.
Run AL TestsRunBcTests@0Runs AL tests in a Business Central container using ALbuild's built-in test runner and publishes a JUnit result file.
Sign AL AppSignBcApp@0Signs .app files with an Azure Key Vault certificate (AzureSignTool).
Stamp Build VersionStampBuildVersion@0Stamps 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

YAMLCode
- task: CheckTranslations@0 displayName: 'Check translations' inputs: path: '' # empty = all AL projects in the repo skipNeedsWork: false failOnIssue: true

Inputs

InputTypeRequiredDefaultDescription
pathfilePathNo—Translations path (empty = all AL projects in the repo)
excludeProjectsstringNo—Projects to exclude (folder names, comma-separated)
skipNeedsWorkbooleanNofalseOnly check for missing translations
failOnIssuebooleanNotrueFail 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

YAMLCode
- task: CleanupCaches@0 displayName: 'Prune ALbuild caches' condition: always() # keep the agent lean even when the build failed inputs: keepDays: '3' # remove cache entries not written in the last 3 days keepLatest: '1' # ...but always keep the newest per cache (the version in use) cache: 'All' # All | Artifacts | Packages | BcArtifacts includeDocker: true # also prune dangling BC images + stopped containers

Inputs

InputTypeRequiredDefaultDescription
keepDaysstringNo30Cache entries not written within this many days are removed. Default 30.
keepLateststringNo0Safety floor: always keep at least this many most-recently-written entries per cache, regardless of age.
cachepickListNoAllCaches to prune Options: All = All, Artifacts = Artifacts (symbols), Packages = Packages, BcArtifacts = BC artifacts.
includeDockerbooleanNofalseAlso prune unused Docker images/stopped containers
whatIfbooleanNofalseWhat-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. keepLatest is a safety floor (never empties a cache); keepDays sets the retention window. includeDocker runs docker image/container prune filtered to the same window. Use whatIf: true to 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

YAMLCode
- task: CompileApp@0 displayName: 'Compile AL app' inputs: projectFolder: '' # empty = all AL projects in the repo, in dependency order engine: 'AlTool' # container-less compile with the AL tool artifactUrl: '$(bcArtifactUrl)' # analyzers: 'CodeCop,UICop' # empty = use albuild.json / .vscode settings # updateManifest: true # rewrite app.json to the target BC version (runtime-package builds) # alToolPrerelease: 'Auto' # NextMajor: use the prerelease compiler when the runtime has no stable one # -> sets $(bcAppFile) (first app) and $(bcAppFiles) (all, ';'-joined)

Inputs

InputTypeRequiredDefaultDescription
projectFolderfilePathNo—Project folder (empty = all AL projects in the repo)
excludeProjectsstringNo—Projects to exclude (folder names, comma-separated)
outputFolderfilePathNo—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.
enginepickListNoAlToolEngine Options: AlTool = AL tool (cross-platform), Container = Container.
containerNamestringNo—Container name (Container engine)
artifactUrlstringNo$(bcArtifactUrl)BC artifact URL (for first-party symbols)
testToolkitSymbolsstringNo$(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').
compilerPathstringNo—AL compiler path (blank = auto-detect / install the AL Tool)
installAlToolbooleanNotrueInstall the AL Tool on the agent if missing (AlTool engine)
alToolVersionstringNo—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.
alToolPrereleasepickListNoAutoA 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.
analyzersstringNo—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.
rulesetstringNo—Ruleset file applied to the analyzers. Overrides albuild.json 'ruleset' and .vscode/settings.json 'al.ruleSetPath'. Relative paths resolve against the project folder.
updateManifestbooleanNofalseBefore 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.
preprocessorSymbolsstringNo—Additional preprocessor symbols to add alongside the BC<n> range (only applied when 'Update app.json' is enabled).
treatWarningsAsErrorsbooleanNofalseWhen 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

ValueMeaning
AlToolCross-platform, container-less compile with the AL compiler tool (fast; no container needed). Default.
ContainerCompile inside the BC container named by containerName (uses the container's bundled compiler).

alToolPrerelease

ValueMeaning
AutoPrefer 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.
AlwaysAlways take the newest compiler for the runtime, even when it is a prerelease.
NeverStable compilers only; a build whose target runtime has no stable compiler fails instead of using a prerelease.

Output variables

VariableDescription
bcAppFilePath to the first built .app (convenience for single-app repos).
bcAppFilesAll built .app paths, semicolon-joined, in dependency (build) order.

Note: The analyzers input is free text, not a pickList: the built-in names are CodeCop, UICop, AppSourceCop, PerTenantExtensionCop (with or without the ${...} wrapper), or explicit analyzer DLL paths. It overrides albuild.json analyzers and .vscode/settings.json al.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

YAMLCode
- task: CreateBcContainer@0 displayName: 'Create BC container' inputs: artifactUrl: '$(bcArtifactUrl)' containerName: 'albuild-$(Build.BuildId)' auth: 'UserPassword' userName: 'admin' # password: '$(BcContainerPassword)' # empty = a random password is generated # licenseFile: '$(BcLicensePath)' # isolation: '' # empty = auto (Docker decides process/hyperv) # -> sets $(containerName), $(containerUsername), $(containerPassword) (secret)

Inputs

InputTypeRequiredDefaultDescription
artifactUrlstringNo$(bcArtifactUrl)Artifact URL
containerNamestringNoalbuild-$(Build.BuildId)Container name
authpickListNoUserPasswordAuthentication Options: UserPassword = UserPassword, NavUserPassword = NavUserPassword, Windows = Windows, AAD = AAD.
userNamestringNoadminAdmin user name
passwordstringNo—Admin password (blank = generated)
licenseFilestringNo—License file (path or URL)
memoryLimitstringNo—Memory limit (e.g. 8G)
isolationpickListNo—Isolation Options: = (auto), process = process, hyperv = hyperv.

Option values

auth

ValueMeaning
UserPasswordUsername/password authentication (the usual CI choice).
NavUserPasswordClassic NAV username/password authentication.
WindowsWindows (NTLM) authentication using the container host identity.
AADMicrosoft Entra ID (Azure AD) authentication.

isolation

ValueMeaning
(empty)Let Docker choose the isolation mode automatically based on the host.
processProcess isolation - lighter/faster; requires matching host and container OS builds.
hypervHyper-V isolation - stronger isolation; tolerates host/container OS mismatch, more overhead.

Output variables

VariableDescription
containerNameThe name of the created container (consumed by Publish/Run tasks).
containerUsernameThe admin username inside the container.
containerPasswordThe admin password (marked secret; a random password is generated when password is left blank).

Note: If password is 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

YAMLCode
- task: CreateBcContainerUser@0 displayName: 'Create BC container user' inputs: containerName: '$(containerName)' userName: 'testuser' password: '$(BcTestUserPassword)' permissionSetId: 'SUPER'

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
userNamestringNo$(containerUsername)User name
passwordstringNo$(containerPassword)Password
permissionSetIdstringNoSUPERPermission set

Note: Creates a user inside the container and assigns a permission set. userName / password default to the container admin credentials set by Create BC Container; permissionSetId defaults to SUPER. 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

YAMLCode
- task: CreateNuGetPackage@0 displayName: 'Create NuGet package' inputs: path: '$(bcAppFile)' # a .app file or a folder of .app files idScheme: '{publisher}.{name}.{id}' # packageId: 'MyCompany.MyApp' # overrides idScheme with an explicit id # version: '$(appVersion)' # empty = version from app.json outputFolder: '$(Build.ArtifactStagingDirectory)' outputVariable: 'bcNuGetPackage' # -> sets $(bcNuGetPackage) (first package) and $(bcNuGetPackages) (all, ';'-joined)

Inputs

InputTypeRequiredDefaultDescription
pathstringNo$(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'.
packageIdstringNo—Package id (blank = derived from id scheme)
idSchemestringNo&#123;publisher}.&#123;name}.&#123;id}Template for the package id when 'Package id' is blank. Placeholders: {publisher}, {name}, {id}.
versionstringNo—Package version (blank = app version)
authorsstringNo—Authors (blank = app publisher)
descriptionstringNo—Description (blank = app name)
outputFolderfilePathNo—Where the .nupkg files are written. Blank = a 'nuget' folder under the artifact staging directory (or the app's own folder).
outputVariablestringNobcNuGetPackageOutput variable name

Option values

idScheme

ValueMeaning
{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

VariableDescription
bcNuGetPackagePath to the first created .nupkg. The variable name is configurable via the outputVariable input (default bcNuGetPackage).
bcNuGetPackagesAll 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 packageId when set, otherwise from idScheme (a template of {publisher}, {name}, {id}). version defaults to the app.json version. The primary output variable name is chosen with outputVariable; the plural bcNuGetPackages is 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

YAMLCode
- task: GetBcArtifact@0 displayName: 'Get BC artifact' inputs: type: 'Sandbox' # empty = from albuild.json (default Sandbox) country: 'w1' # empty = from albuild.json (default w1) select: 'Latest' # version: '26' # optional version / prefix filter # -> sets $(bcArtifactUrl) and $(bcArtifactVersion) for the downstream tasks

Inputs

InputTypeRequiredDefaultDescription
typepickListNo—Type Options: = (from albuild.json / Sandbox), Sandbox = Sandbox, OnPrem = OnPrem.
countrystringNo—Leave empty to use the country from albuild.json (default w1).
versionstringNo—Version
selectpickListNo—Select Options: = (from albuild.json / Latest), Latest = Latest, First = First, Closest = Closest, NextMinor = NextMinor, NextMajor = NextMajor.
projectFolderfilePathNo—Project folder (reads albuild.json)
dependencyAwarebooleanNofalseFor 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.
maxDowngradeStepsstringNo5How 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.)
outputVariablestringNobcArtifactUrlOutput variable name

Option values

type

ValueMeaning
(empty)Take the artifact type from albuild.json (falls back to Sandbox).
SandboxThe Sandbox artifact (in-memory, cronus demo data) - the normal build/test target.
OnPremThe OnPrem artifact - use when building/testing against the on-premises platform.

select

ValueMeaning
(empty)Take the selection strategy from albuild.json (falls back to Latest).
LatestNewest artifact matching type/country/version.
FirstEarliest artifact matching the filter.
ClosestArtifact closest to the given version.
NextMinorThe upcoming next-minor Insider build (requires accepting the BC Insider EULA).
NextMajorThe upcoming next-major Insider build (requires accepting the BC Insider EULA).

Output variables

VariableDescription
bcArtifactUrlThe resolved artifact URL. The variable name is configurable via the outputVariable input (default bcArtifactUrl).
bcArtifactVersionThe 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: true to 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

YAMLCode
- task: GetUniversalPackage@0 displayName: 'Download universal package' inputs: feed: 'ALbuild' name: 'my-universal-package' version: '*' # '*' = latest version outputFolder: '$(Pipeline.Workspace)/pkg' # project: 'MyProject' # for a project-scoped feed # organization / accessToken default to the current collection / $(System.AccessToken)

Inputs

InputTypeRequiredDefaultDescription
organizationstringNo$(System.TeamFoundationCollectionUri)Organization (URL or name)
feedstringNo—Feed
namestringNo—Package name
versionstringNo*Version (or *)
outputFolderfilePathNo—Output folder
projectstringNo—Project (for project-scoped feeds)
accessTokenstringNo$(System.AccessToken)Access token (PAT)

Note: Downloads an Azure Artifacts Universal Package from the named feed into outputFolder. version accepts an exact version or * (latest). Set project for a project-scoped feed; organization and accessToken default 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

YAMLCode
- task: ImportConfigPackage@0 displayName: 'Import configuration package' inputs: containerName: '$(containerName)' path: 'config/RapidStart.rapidstart' # a .rapidstart configuration package

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
pathfilePathNo—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

YAMLCode
- task: InstallBc365App@0 displayName: 'Install 365 business apps' inputs: containerName: '$(containerName)' appId: | # one app id per line 63ca2fa4-4f03-4f2b-a480-172fef340d3f abcabc00-0000-0000-0000-000000000000 # installerUrl: 'https://.../installer' # optional custom installer source

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
appIdmultiLineNo—App id(s) (one per line)
installerUrlstringNo—Installer URL (optional)

Note: Installs one or more 365 business development apps into the container by app id. The appId input is multi-line - provide one app id per line. installerUrl overrides 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

YAMLCode
- task: InstallDependencies@0 displayName: 'Install app dependencies into container' inputs: containerName: '$(containerName)' packageFolder: '' # empty = the symbols cache resolved by Resolve Dependencies skipVerification: true

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
projectFolderfilePathNo—Project folder (empty = all AL projects in the repo)
excludeProjectsstringNo—Projects to exclude (folder names, comma-separated)
packageFolderfilePathNo—Dependency package folder (default: each project's .alpackages)
skipVerificationbooleanNotrueSkip signature verification

Note: Publishes the resolved dependency .app files into the container so the app under test can be installed. packageFolder points 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

YAMLCode
- task: InstallTestToolkit@0 displayName: 'Install test toolkit' inputs: containerName: '$(containerName)' includeTestLibrariesOnly: true # false = also install the full test framework apps # -> sets $(bcTestToolkitSymbols) with the exported test-symbol folder

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
includeTestLibrariesOnlybooleanNotrueDefault (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.
symbolExportFolderstringNo—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

VariableDescription
bcTestToolkitSymbolsFolder 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. symbolExportFolder overrides 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

YAMLCode
- task: PublishApp@0 displayName: 'Publish AL app to container' inputs: containerName: '$(containerName)' appFile: '$(bcAppFile)' # empty = publish every .app under appFolder syncMode: 'Add' install: true skipVerification: true

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
appFilestringNo—App (.app) file (single-app; leave empty to publish all built apps)
appFolderfilePathNo$(Build.ArtifactStagingDirectory)Folder of built .app files (multi-project)
projectFolderfilePathNo—Project folder (empty = all AL projects in the repo)
excludeProjectsstringNo—Projects to exclude (folder names, comma-separated)
syncModepickListNoAddSchema sync mode Options: Add = Add, Clean = Clean, Development = Development, ForceSync = ForceSync.
skipVerificationbooleanNotrueSkip signature verification
installbooleanNotrueInstall after sync

Option values

syncMode

ValueMeaning
AddAdditive schema sync - only non-breaking schema changes are applied; existing data is kept. Default.
CleanPublish with a clean schema: the app's tables are recreated, discarding their data. Use for a fresh install.
DevelopmentDevelopment sync (rapid application development): schema changes are forced and table data may be lost - for dev boxes only.
ForceSyncForce 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

YAMLCode
- task: PublishTestinyResults@0 displayName: 'Publish results to Testiny' inputs: resultsFile: '$(bcTestResults)' # defaults to TestResults.xml apiKey: '$(TestinyApiKey)' projectId: '$(TestinyProjectId)' # runId: '123' # optional: append to an existing run

Inputs

InputTypeRequiredDefaultDescription
resultsFilefilePathNoTestResults.xmlResults file (JUnit)
apiKeystringNo—Testiny API key
projectIdstringNo—Testiny project id
runIdstringNo—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 given projectId. apiKey, resultsFile and projectId are required. runId targets 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

YAMLCode
- task: RemoveBcContainer@0 displayName: 'Remove BC container' condition: always() # tear down even when earlier steps failed inputs: containerName: '$(containerName)'

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo—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

YAMLCode
- task: ResolveDependencies@0 displayName: 'Resolve AL dependencies' inputs: feedUrl: 'https://pkgs.dev.azure.com/365businessdev/_packaging/ALbuild/nuget/v3/index.json' feedToken: '$(System.AccessToken)' feedKind: 'symbols' select: 'Latest' targetVersion: '$(bcArtifactVersion)' includeMicrosoftDefaults: true

Inputs

InputTypeRequiredDefaultDescription
projectFolderfilePathNo—Project folder (empty = all AL projects in the repo)
excludeProjectsstringNo—Projects to exclude (folder names, comma-separated)
includeMicrosoftDefaultsbooleanNotrueInclude Microsoft default feeds
feedUrlstringNo—NuGet feed URL (v3 index.json)
feedTokenstringNo—Feed token / PAT
feedKindpickListNosymbolsFeed kind Options: symbols = symbols, apps = apps, runtime = runtime.
selectpickListNoLatestSelection Options: Latest = Latest, LowestCompatible = LowestCompatible.
containerNamestringNo$(containerName)Container (pin installed apps)
targetVersionstringNo$(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'.
outputFolderfilePathNo—Output folder (.alpackages)

Option values

feedKind

ValueMeaning
symbolsDownload the symbols (.app placeholder) packages - enough to compile against. Default.
appsDownload the full runtime .app packages - needed to publish/install the dependencies.
runtimeDownload the runtime-package variant of the dependencies.

select

ValueMeaning
LatestTake the newest compatible version of each dependency. Default.
LowestCompatibleTake 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

YAMLCode
- task: RunBcTests@0 displayName: 'Run AL tests' inputs: containerName: '$(containerName)' testSuite: 'DEFAULT' failOnTestFailure: true codeCoverage: 'PerRun' coverageFormats: 'Cobertura,Markdown' publishCoverage: true minLineCoverage: '80' # fail the build below 80% line coverage failOnCoverageBelow: true # -> sets $(bcTestResults), $(bcCoverageLineRate), $(bcCoverageCobertura), $(bcTestQualityScore)

Inputs

InputTypeRequiredDefaultDescription
containerNamestringNo$(containerName)Container name
usernamestringNo$(containerUsername)Container user
passwordstringNo$(containerPassword)Container password
authstringNoNavUserPasswordClient services auth
projectFolderfilePathNo—Project folder
extensionIdstringNo—Extension id (optional)
testSuitestringNoDEFAULTTest suite
testRunnerCodeunitIdstringNo—Test runner codeunit id (optional)
disableIsolationbooleanNoFalseDisable test isolation
installTestToolkitbooleanNoTrueAuto-install the BC test toolkit into the container when it is not already present, so a separate Install Test Toolkit step is not required.
includeTestLibrariesOnlybooleanNoFalseTest libraries only (when auto-installing)
resultPathfilePathNoTestResults.xmlResult file (JUnit)
failOnTestFailurebooleanNoFalseFail on test failure
codeCoveragepickListNoDisabledCapture 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.
codeCoverageMappickListNoDisabledAlso capture a test -> covered-line map. Options: Disabled = Disabled, PerCodeunit = Per codeunit, PerTest = Per test. (Shown when: codeCoverage != Disabled.)
coverageFormatsstringNoCobertura,MarkdownComma-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.)
coverageWorkspaceRootfilePathNo—AL source root, so coverage maps to your app objects only and to source files. Defaults to the project folder. (Shown when: codeCoverage != Disabled.)
coverageOutputFolderfilePathNoCodeCoverageCoverage output folder (Shown when: codeCoverage != Disabled.)
publishCoveragebooleanNoTruePublish 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.)
minLineCoveragestringNo—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.)
minObjectLineCoveragestringNo—Optional per-object coverage floor; any object below it fails the gate. (Shown when: codeCoverage != Disabled.)
failOnCoverageBelowbooleanNoTrueFail build when below coverage gate (Shown when: codeCoverage != Disabled.)
checkTestQualitybooleanNoFalseTest 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

ValueMeaning
DisabledNo code coverage is collected. Default.
PerRunCollect one coverage result for the whole test run.
PerCodeunitCollect coverage separately per test codeunit.
PerTestCollect coverage separately per test method (most granular, slowest).

codeCoverageMap

ValueMeaning
DisabledDo not produce a coverage map. Default.
PerCodeunitEmit a coverage map per codeunit.
PerTestEmit a coverage map per test method.

coverageFormats

ValueMeaning
CoberturaCobertura XML - published to the build's Code Coverage tab.
MarkdownA Markdown summary - uploaded as a build summary tab.
ALbuildJsonThe raw ALbuild JSON coverage document.

Output variables

VariableDescription
bcTestResultsPath to the JUnit/XML test results file (resultPath).
bcCoverageLineRateOverall line-coverage rate (only when code coverage is enabled).
bcCoverageCoberturaPath to the generated Cobertura XML (only when Cobertura is among coverageFormats).
bcTestQualityScoreTest-quality score (only when checkTestQuality is true).

Note: The coverageFormats input is a comma-separated list; valid entries are Cobertura, Markdown and ALbuildJson. minLineCoverage / minObjectLineCoverage set coverage thresholds; combined with failOnCoverageBelow (default true) they fail the build when coverage is below target. checkTestQuality additionally 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

YAMLCode
- task: SignBcApp@0 displayName: 'Sign AL app' inputs: path: '$(bcAppFile)' # a .app file or a folder of .app files certificateName: '$(SigningCertName)' env: # Secret pipeline variables do not reach task inputs, so map them via env (SignBcApp reads ALBUILD_SIGN_*): ALBUILD_SIGN_KEYVAULTURL: $(SigningAzureKeyVaultUrl) ALBUILD_SIGN_TENANTID: $(SigningAzureKeyVaultTenantId) ALBUILD_SIGN_CLIENTID: $(SigningAzureKeyVaultClientId) ALBUILD_SIGN_CLIENTSECRET: $(SigningAzureKeyVaultClientSecret) ALBUILD_SIGN_CERTNAME: $(SigningCertName)

Inputs

InputTypeRequiredDefaultDescription
pathstringNo$(bcAppFile)App file / folder / wildcard
keyVaultUrlstringNo—Key Vault URL
tenantIdstringNo—Tenant id
clientIdstringNo—Client id
clientSecretstringNo—Client secret
certificateNamestringNo—Certificate name
timestampUrlstringNohttp://timestamp.digicert.comTimestamp 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 / _CERTNAME environment variables when the matching inputs are blank. Signs via Azure Key Vault (AzureSignTool); the certificate must be a code-signing cert. timestampUrl defaults to http://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

YAMLCode
# CI: version app.json from its current Major.Minor, Build+1, Revision 0, and claim a build/<version> # branch so the CD build can seed the exact validated version later. - task: StampBuildVersion@0 displayName: 'Stamp build version' inputs: schema: 'major.minor.increment.0' # version: '1.2.3.0' # an explicit version overrides schema entirely # onlyUpdateOnChangedSource: true env: AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) # required to push the build/<version> branch # CD: inherit Major.Minor.Build from the latest CI build branch, set Revision = build id. - task: StampBuildVersion@0 inputs: schema: 'latest.latest.latest.build-id' # 'latest' auto-enables Seed from build branch noBuildBranch: true env: AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)

Inputs

InputTypeRequiredDefaultDescription
pathfilePathNo—Repository / project path
schemastringNomajor.minor.increment.0One 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.
versionstringNo—Explicit version (overrides schema)
buildIdstringNo$(Build.BuildId)Build id (for the build-id token)
onlyUpdateOnChangedSourcebooleanNofalseOnly version changed apps
branchPrefixstringNobuild/Build branch prefix
remotestringNooriginGit remote
noBuildBranchbooleanNofalseDo not create/push a build branch
seedFromBuildBranchbooleanNofalseRelease/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.
updateBuildNumberbooleanNotrueUpdate the pipeline build number

Option values

schema

ValueMeaning
<number>A literal non-negative integer at that position (e.g. the 0 in major.minor.increment.0).
incrementThe current app.json component + 1 (e.g. Build+1).
build-idThe pipeline build id from the buildId input (default $(Build.BuildId)); must be numeric.
no-of-commitsThe git commit count (V1-style versioning); must be numeric.
dateA numeric date stamp, yyyyMMdd.
majorKeep the current Major from app.json (unchanged).
minorKeep the current Minor from app.json (unchanged).
buildKeep the current Build from app.json (unchanged).
revisionKeep the current Revision from app.json (unchanged).
keepKeep the current component at this position (alias of major/minor/build/revision).
latestKeep 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

VariableDescription
appVersionThe full stamped version, Major.Minor.Build.Revision.
appVersionShortMajor.Minor.Build (no revision).
semanticAppVersionAlias of appVersionShort.
appVersionMajorThe Major component.
appVersionMinorThe Minor component.
appVersionBuildThe Build component.
appVersionRevisionThe Revision component.
buildBranchThe 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 a latest token, or when seedFromBuildBranch is set, the task reads the highest existing build/<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).


Last modified on