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

# Pipeline module: local pipeline runner

**Module:** `businessdev.ALbuild.Pipeline` &nbsp;•&nbsp; **Tier:** Free &nbsp;•&nbsp; **Cmdlets:** 1

[`Invoke-ALbuildPipeline`](#invoke-albuildpipeline) runs an ALbuild Azure DevOps pipeline **YAML template** on your machine, step by step, the way the agent would. Because it parses the *same* template the cloud pipeline uses, a local run reflects the real pipeline from a single source of truth.

---

## How it works

For the parsed template it:

1. **Resolves parameters**: the template's `parameters` defaults, overridden by `-Parameters`.
2. **Expands expressions**: compile-time `${{ parameters.* }}` and the `${{ if }}` / `${{ each }}` directives, plus `$(var)` macros from the environment and from earlier steps' outputs.
3. **Flattens** stages → jobs → steps (and a deployment job's `runOnce.deploy.steps`) into an ordered step list.
4. **Runs each step**:
   - `task: Name@n` → finds the matching extension `task.ps1`, sets its `INPUT_*` environment variables and runs it in a child PowerShell process, capturing `##vso[task.setvariable]` outputs so later steps can read them via `$(var)`.
   - `pwsh:` / `powershell:` → runs the inline script (also capturing set-variable commands).
   - `publish:` → logged (artifacts are not uploaded for a local run).
   - `condition: always()` / `succeededOrFailed()` still run after a previous failure; the run then reports the failure at the end.

<Callout type="info" title="Build-version step is forced to dry-run">
The build-version step (`StampBuildVersion`) is automatically forced to **dry-run** (no build branch is claimed or pushed) so a local run never touches the remote.
</Callout>

<Callout type="caution" title="Supported subset">
Only the constructs the ALbuild templates use are implemented, `parameters`, stages/jobs/steps, `${{ if|each }}`, `${{ parameters.* }}` / `$(var)`, and the `always()`/`succeededOrFailed()` conditions. It is not a full Azure DevOps expression engine.
</Callout>

---

## Prerequisites

- The `businessdev.ALbuild` module (installed from the Gallery or from the repository `src`).
- `powershell-yaml` (installed on demand for the current user the first time you run it).
- For the container CI template: Windows + Docker. For Universal-feed steps: the Azure CLI.

---

## Usage

```powershell
Import-Module businessdev.ALbuild
Invoke-ALbuildPipeline -Path templates/yaml/ci-pipeline.yml `
    -Parameters @{ country = 'de'; projectFolder = 'app' } `
    -RepositoryRoot 'D:\Code\DevOps\Customer\D365BC-Core'
```

The variables Azure DevOps normally injects (`Build.*`, `System.*`, signing/feed secrets, container settings) are read from the environment. Set them first, the easiest way is the sample script `templates/local/Run-ALbuildPipeline.sample.ps1`, which sets placeholder values and then calls `Invoke-ALbuildPipeline`.

<Callout type="caution" title="Secrets">
Keep any copy of the setup script that contains real Key Vault secrets, PATs or feed tokens out of source control. The sample ships with placeholders only.
</Callout>

---

## Invoke-ALbuildPipeline

Runs an ALbuild Azure DevOps pipeline YAML template locally, step by step.

### Parameters

| Parameter | Description |
| --- | --- |
| `-Path` | The pipeline YAML template to run. |
| `-Parameters` | Hashtable of template parameter overrides; unset parameters use the template default. |
| `-RepositoryRoot` | The AL repository the steps build. Defaults to `BUILD_REPOSITORY_LOCALPATH` or the current location. |
| `-TasksRoot` | The extension `Tasks` folder. Defaults to the ALbuild repo's `extension/Tasks` next to the module. |
| `-PowerShellExe` | PowerShell executable used to run each task. Defaults to the current host. |

### Output

A summary object: `Steps` (each with `Label` and `Succeeded`) and `Failed`. The cmdlet throws if any step failed, after running any `always()` cleanup steps.

### Example

```powershell
Invoke-ALbuildPipeline -Path templates/yaml/ci-pipeline.yml -Parameters @{ country = 'w1' }
```
