Skip to content

subzone/ado-tf-agent

ADO Terraform Agent

Azure DevOps extension that adds a Terraform pipeline task and a Terraform tab on the build results page. The tab renders plan.json (from terraform show -json) as a change table and a high-level diagram derived from resource_changes.

Prerequisites

Test sample (Terraform + pipeline)

  • infra/ — minimal root module using the null provider only (no Azure/AWS/GCP credentials). Local backend by default.
  • azure-pipelines.yml — installs the extension task subzone.ado-tf-agent.terraform-task.Terraform@0, then runs init → validate → plan (with Publish plan JSON artifact) → apply.

In Azure DevOps

  1. Install the extension on the same organization that runs the pipeline (otherwise YAML fails with A task is missing):
    • Organization Settings (⚙ bottom left) → ExtensionsSharedUpload extension → choose dist/subzone.ado-tf-agent-*.vsix from a local npm run package, or install from the Marketplace if it is published.
  2. Create a pipeline from azure-pipelines.yml and run it.
  3. After Plan, open the completed build → Terraform tab (build results).

There is no substitute pipeline in this repo: testing the extension means installing it on your org, then running azure-pipelines.yml. Plain Terraform scripts would not exercise the task or the build Terraform tab.

“A task is missing …” (YAML task name)

Marketplace tasks use four dot-separated parts before @, not three:

publisher.extensionId.contributionId.taskJsonName@major

Example for this extension: subzone.ado-tf-agent.terraform-task.Terraform@0

  • Terraform is the name field from tasks/Terraform/task.json (not the friendly name).
  • Using only subzone.ado-tf-agent.terraform-task@0 is invalid and produces task is missing even when the extension is installed.

If the name is correct and it still fails, the extension is not on this org: install it under Organization settings → Extensions, then re-run the pipeline.

Locally (without the extension):

cd infra && terraform init -input=false && terraform validate && terraform plan -out=tfplan

Configure the manifest

  1. Confirm publisher in vss-extension.json (currently subzone).
  2. Update repository.uri, task author / helpMarkDown in tasks/Terraform/task.json, and branding as needed.
  3. Replace images/extension-icon.png with a 128×128 PNG for the Marketplace.

Build and package

npm install
npm run package

This produces dist/subzone.ado-tf-agent-<version>.vsix (see vss-extension.json).

Build and publish from GitHub Actions

Workflow: .github/workflows/extension.yml.

Trigger What happens
Push / PR to main or master Builds and uploads the VSIX as a workflow artifact (no Marketplace publish).
Push a version tag v* (e.g. v0.2.0) Automatically syncs version across all files, builds, then publishes that VSIX to the Marketplace.
Run workflow manually Builds; set Publish VSIX to Marketplace to true to publish.

Version management: The extension uses automated version sync from git tags. Simply create and push a version tag:

git tag v0.2.0
git push origin v0.2.0

The workflow automatically updates vss-extension.json, task.json, and all package versions to match. See VERSIONING.md for details.

Repository secret (Settings → Secrets and variables → Actions):

  • AZURE_DEVOPS_EXT_TOKEN — Azure DevOps PAT with Marketplace (Manage) scope, tied to the same identity that owns publisher subzone.

Publishing uses tfx extension publish with your public manifest ("public": true); you can still complete or adjust listing details in the publisher portal afterward.

Install dependencies for local iteration:

cd tasks/Terraform && npm install && npm run build
cd ../../ui && npm install && npm run build

Publish to your organization today (no Marketplace review)

Private sharing is the fastest way to validate on real pipelines:

npx tfx-cli extension publish \
  --manifest-globs vss-extension.json \
  --token <PAT> \
  --share-with <your-org-name>

Or upload the .vsix under Organization settings → Extensions → Shared → Upload extension.

Marketplace (public listing)

The manifest sets "public": true so the package is eligible for the public Marketplace. Publishing still requires:

  • A valid privacy policy URL (often on your publisher profile or in the extension’s Marketplace listing).
  • Support / contact information as required by the submission wizard.
  • Microsoft review (not instant; timelines vary).

Publish with tfx extension publish without --share-with, then finish any remaining steps in the publisher portal. You can keep using --share-with for private testing of the same or another version if needed.

Example pipeline (YAML)

pool:
  vmImage: ubuntu-latest

steps:
  - task: subzone.ado-tf-agent.terraform-task.Terraform@0
    displayName: Install Terraform
    inputs:
      command: install
      terraformVersion: 1.7.5

  - task: subzone.ado-tf-agent.terraform-task.Terraform@0
    displayName: Terraform init (Azure backend)
    inputs:
      command: init
      workingDirectory: infra
      backendType: azurerm
      azureResourceGroup: rg-terraform-state
      azureStorageAccount: tfstateacct
      azureContainer: tfstate
      azureStateKey: myapp.tfstate

  - task: subzone.ado-tf-agent.terraform-task.Terraform@0
    displayName: Terraform plan
    inputs:
      command: plan
      workingDirectory: infra
      publishPlanArtifact: true
      planArtifactName: terraform-plan

Use service connections or Azure CLI / environment variables for provider credentials as you normally would for Terraform on hosted agents.

Architecture notes

  • Task — Node 20 handler (azure-pipelines-task-lib, azure-pipelines-tool-lib) for cross-platform agents.
  • UIms.vss-build-web.build-results-tab loads ui/dist/planTab.html, uses azure-devops-extension-sdk and BuildRestClient.getArtifactContentZip to read the published artifact.
  • Diagram — Mermaid flowchart with subgraphs per resource type prefix; a future iteration can parse terraform graph or dependency metadata for richer edges.

Security

Request only the scopes you need. This manifest uses vso.build and vso.build_execute. Review with your security team before broad rollout.

VSIX size (optional)

Before publishing, you can drop TypeScript from the packaged task folder:

cd tasks/Terraform && npm prune --omit=dev && cd ../..
npm run package

Re-run npm install in tasks/Terraform afterward if you need to compile again locally.

About

Azure Terraform Agent

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors