Usage¶
Every task takes an Argo CD service connection, which carries the server URL and a token. See Security for which credential to use and how to scope it.
Always set displayName¶
In a YAML pipeline, a step with no displayName shows the task identifier in the run —
ArgoCDInstall, not the friendly name. That is Azure DevOps behaviour, not something the task
can change: a task's name is its TaskName@1 reference and cannot contain spaces.
Every example below sets one.
Deploying¶
Sync an application and wait for it to become healthy. This is the common case.
- task: ArgoCDApp@1
name: argocd
displayName: Deploy payments
inputs:
connection: 'argocd-prod'
command: 'sync'
applications: 'payments-api'
project: 'payments'
prune: true
syncOptions: |
CreateNamespace=true
ServerSideApply=true
wait: true
waitFor: 'sync,health'
timeoutSeconds: '600'
- script: echo "Deployed $(argocd.revision) — $(argocd.appUrl)"
Use a deployment job
Running the sync inside a deployment: job targeting an Environment gives you deployment
history, approvals and an exclusive lock for free — none of which the task has to implement.
Always set project¶
Argo CD deliberately refuses to distinguish "this application does not exist" from "your token
may not see it": without a project, both return permission denied. Supplying it turns a
missing application into a real 404, so a typo stops looking like a broken token. The task warns
when you omit it.
Waiting¶
waitFor takes a comma-separated list of conditions that must all hold: sync, health,
operation, suspended. suspended is for Argo Rollouts pause points — Suspended only counts
as healthy when you ask for it.
A failed sync operation stops the wait immediately. Degraded and Missing do not —
both occur transiently during a normal rollout, so they fail the task by being the state at
timeout rather than by aborting early.
Reviewing a change¶
Show reviewers what would actually change in the cluster, without blocking the build:
- task: ArgoCDApp@1
displayName: Show what would change
inputs:
connection: 'argocd-prod'
command: 'diff'
applications: 'payments-api'
project: 'payments'
failOnDiff: false # report as "succeeded with issues"
The diff is rendered from Argo CD's normalized-live and predicted-live states — the same comparison the UI shows — as a collapsible unified diff per changed resource in the run summary.
For ApplicationSets, generate renders the Applications a change would produce without
persisting anything:
- task: ArgoCDAppSet@1
displayName: Preview generated applications
name: preview
inputs:
connection: 'argocd-prod'
command: 'generate'
generateFrom: 'file'
manifestFile: 'gitops/appsets/payments.yaml'
Recovering¶
Roll back to the previous revision:
- task: ArgoCDApp@1
displayName: Roll back the application
inputs:
connection: 'argocd-prod'
command: 'rollback'
applications: 'payments-api'
project: 'payments'
historyId: 'previous'
wait: true
Automated sync blocks rollback
Argo CD refuses to roll back an application with automated sync enabled, because the controller would immediately sync it forward again. The task detects this before making the request and says so. The GitOps-native alternative is to revert in Git and let Argo CD sync that — which also leaves an audit trail.
Collect evidence when something fails:
- task: ArgoCDApp@1
displayName: Collect logs for triage
condition: failed()
inputs:
connection: 'argocd-prod'
command: 'logs'
applications: 'payments-api'
project: 'payments'
tailLines: '500'
Logs and manifests are written to a file and published as a pipeline artifact, with a bounded tail echoed to the log.
Targeting several applications¶
Name them one per line, or match them with a label selector:
- task: ArgoCDApp@1
displayName: Wait for the application
inputs:
connection: 'argocd-prod'
command: 'wait'
selector: 'app.kubernetes.io/instance=platform'
project: 'platform'
waitFor: 'sync,health'
timeoutSeconds: '1800'
A run covering several applications fails if any single one fails. Use namespace/name in
applications for app-in-any-namespace installs.
Destructive commands take names only
delete — on both ArgoCDApp@1 and ArgoCDAppSet@1 — refuses label selectors and requires
confirm: true. Deleting an application also deletes the resources it manages, and deleting
an ApplicationSet deletes every Application it generated.
Using the CLI¶
When you need something the REST API cannot do — app diff --local, --core mode, admin
subcommands — install the CLI and run it with authentication injected:
- task: ArgoCDInstall@1
displayName: Install Argo CD CLI
inputs:
connection: 'argocd-prod'
version: 'server' # match the server you are talking to
- task: ArgoCDCli@1
displayName: Run argocd
inputs:
connection: 'argocd-prod'
arguments: 'app diff payments-api --local ./manifests'
workingDirectory: '$(Build.SourcesDirectory)'
The CLI costs bandwidth
The argocd binary is ~250 MB and the tool cache only persists on self-hosted agents, so
Microsoft-hosted agents download it every run. Set the pipeline variable ARGOCD_CLI_MIRROR
to an internal mirror laid out as <base>/releases/download/<tag>/<asset> for air-gapped or
bandwidth-sensitive setups.
Task results¶
| Result | When |
|---|---|
| Failed | A health status in failOnHealth (default Degraded,Missing), a failed sync operation, or a timeout with failOnTimeout on. |
| SucceededWithIssues | Out of sync with failOnOutOfSync off, differences with failOnDiff off, or a timeout with failOnTimeout off. |
| Succeeded | The requested conditions were met. |
Output variables¶
Give the step a name and reference them as $(stepName.variable):
- task: ArgoCDApp@1
displayName: Read application status
name: argocd
inputs:
connection: 'argocd-prod'
command: 'get'
applications: 'payments-api'
project: 'payments'
- script: echo "Health is $(argocd.healthStatus) at $(argocd.revision)"
name is what makes this work, and it is easy to miss. Without it the task still runs and still
sets its outputs, but Azure DevOps assigns the step a generated reference name — ArgoCDApp1
for the first such step, ArgoCDApp2 for the next — so $(argocd.healthStatus) resolves to
nothing. No warning is logged.
If you are debugging this, dump the environment in the following step. Output variables appear as
<REFERENCE_NAME>_<VARIABLE>, upper-cased:
Seeing ARGOCDAPP1_HEALTHSTATUS rather than ARGOCD_HEALTHSTATUS means the step had no name,
and the variables are there under the generated prefix.
Two further constraints, both Azure DevOps behaviour rather than anything this task controls:
- Only later steps can read them. A variable set by a step is not visible to that same step.
- Across jobs or stages you need the long form, plus an explicit
dependsOn:
- job: verify
dependsOn: deploy
variables:
health: $[ dependencies.deploy.outputs['argocd.healthStatus'] ]
steps:
- script: echo "Health was $(health)"
Note the task's step name (argocd) and the output name are one quoted string inside the
brackets, and $[ ] is not interchangeable with $( ) here.
revision on multi-source applications¶
For an application with several sources (spec.sources), Argo CD reports one revision per source
and revision holds them comma-separated, in source order.
They are not all git SHAs. A Helm chart source reports its chart version, so the common
"chart from a registry, values from a repo" application produces something like
1.2.3,4f9a2c…. Joined together those cannot be told apart, so the list is also published as
revisions, a JSON array:
- task: ArgoCDApp@1
displayName: Read application status
name: argocd
inputs:
connection: 'argocd-prod'
command: 'get'
applications: 'payments-api'
project: 'payments'
- bash: |
chart=$(echo '$(argocd.revisions)' | jq -r '.[0]') # the Helm chart version
values=$(echo '$(argocd.revisions)' | jq -r '.[1]') # the values repo commit
echo "chart $chart, values $values"
Entries are positional and follow the order of spec.sources.
The full list is in the task inputs reference.