import { Callout } from "zudoku/ui/Callout";

# Azure DevOps extension

**ALbuild for Azure DevOps** provides **granular, composable** pipeline tasks for Microsoft Dynamics 365 Business Central AL development. Every task is a thin wrapper that imports the [`businessdev.ALbuild`](../powershell-module/index) module and calls a single cmdlet, so the same behaviour runs **locally and in CI**, with **no dependency on BcContainerHelper**.

- **Marketplace name:** ALbuild for Azure DevOps
- **Publisher:** `365businessdevelopment`
- **Tasks:** build, release and frozen V1-legacy tasks — see the reference pages below for the complete, always-current list
- **Free trial:** 30 days for the licensed deployment tasks

---

## Install

1. Open the Azure DevOps Marketplace and search for **ALbuild for Azure DevOps**.
2. Select the extension and choose **Get it free** to install it into your organization.
3. Add the tasks to your build and release pipelines.

The free-of-license tasks work immediately, no license key required. To use the [licensed deployment tasks](../concepts/licensing), acquire a license for your Azure DevOps organization at [365businessdev.com](https://365businessdev.com). Licensing is verified automatically per organization, and a free trial is available.

<Callout type="info" title="Supported environments">
Business Central On-Premises · Business Central Online (SaaS) · Business Central on Docker.
</Callout>

---

## Design

- **Granular tasks.** The monolithic "Create Build Container" of the previous generation is split into small, reusable steps you arrange freely: *Get BC Artifact → Create BC Container → Resolve Dependencies → Compile → Sign → Publish → Run Tests → Remove BC Container*.
- **No BcContainerHelper.** The extension depends only on the `businessdev.ALbuild` module.
- **Each task** = `task.json` (inputs/outputs) + `task.ps1` → imports the pinned module → maps inputs → calls one cmdlet → reports results.

---

## Task categories

| Category | Tier | Reference |
| --- | --- | --- |
| [Build tasks](build-tasks) | Free | Resolve, version, container, dependencies, compile, sign, publish, test, clean up |
| [Release tasks](release-tasks) | Free + Licensed | NuGet publish (free); PTE, on-prem, dev, Marketplace, runtime packages (licensed) |
| [Legacy (V1) tasks](legacy-tasks) | Free | Frozen V1 compatibility tasks; see [migration](migration) |

Each reference page is **generated from the shipped `task.json` files**, so it lists every task and
every input as actually released.

The [license check](../concepts/licensing) runs only on entry to a licensed task. Free-of-license tasks never perform a license check.

---

## Example pipeline

A minimal build pipeline that resolves the BC artifact, creates a container, restores dependencies, compiles, signs, installs, runs the tests, and removes the container:

```yaml
trigger:
  - main
  - master

pool:
  name: Self Hosted

steps:
  - checkout: self
    persistCredentials: true

  - task: GetBcArtifact@0
    displayName: 'Get BC Artifact'
    inputs:
      type: 'Sandbox'
      country: 'w1'
      select: 'Latest'

  - task: StampBuildVersion@0
    displayName: 'Set Version Number'
    inputs:
      schema: 'major.minor.increment.0'
      onlyUpdateOnChangedSource: true
    env:
      AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)

  - task: CreateBcContainer@0
    displayName: 'Create BC Container'
    inputs:
      artifactUrl: '$(bcArtifactUrl)'

  - task: ResolveDependencies@0
    displayName: 'Resolve Dependencies'
    inputs:
      feedToken: '$(System.AccessToken)'
      targetVersion: '$(bcArtifactVersion)'

  - task: CompileApp@0
    displayName: 'Compile'
    inputs:
      artifactUrl: '$(bcArtifactUrl)'

  - task: CreateNuGetPackage@0
    displayName: 'Create NuGet Package'
    inputs:
      path: '$(bcAppFile)'

  - task: SignBcApp@0
    displayName: 'Sign'
    inputs:
      path: '$(bcAppFile)'
      certificateName: '$(SigningCertName)'
    env:
      # Secret pipeline variables do not reach task inputs - 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)

  - task: PublishApp@0
    displayName: 'Publish & Install'
    inputs:
      containerName: '$(containerName)'
      appFile: '$(bcAppFile)'
      syncMode: 'Add'
      install: true

  - task: RunBcTests@0
    displayName: 'Run Tests'
    inputs:
      containerName: '$(containerName)'
      failOnTestFailure: true

  - task: PublishTestResults@2
    displayName: 'Publish Test Results'
    inputs:
      testResultsFormat: XUnit
      testResultsFiles: '$(bcTestResults)'
      failTaskOnFailedTests: true

  - task: RemoveBcContainer@0
    displayName: 'Remove BC Container'
    inputs:
      containerName: '$(containerName)'
    condition: always()
```

Ready-to-use templates ship in the [`templates/`](https://github.com/365businessdev/ALbuild/tree/main/templates) folder, and you can run any of these tasks locally with the [local pipeline runner](../powershell-module/pipeline).

---

## Migrating from ALbuild V1

To keep existing pipelines running, the extension also ships the **ALbuild V1 tasks** (`CreateBuildContainer`, `Compile`, `Install`, `AppVersioning`, `SignApp`, `ReleaseAppSource`, …). They keep their original name, version and inputs, reproduce the V1 behaviour on top of the module, and emit a deprecation warning while still succeeding. They are **frozen**: migrate at your own pace. See [Migrating from V1](migration).
