UiPath Documentation
uipath-cli
latest
false

UiPath CLI user guide

Última actualización 7 de may. de 2026

CI/CD recipe: Azure Pipelines

This page gives you a complete azure-pipelines.yml that installs the CLI, authenticates with an External Application, packs and publishes a UiPath Solution, deploys it to Orchestrator, and runs a Test Manager suite against the deployment. The pipeline is self-contained: copy it into the root of your repo, wire two secrets, and it runs.

For the underlying principles — auth, caching, tool pre-install, version pinning — see How-to: deploy to Orchestrator from CI. This page focuses on the Azure Pipelines syntax.

Requisitos previos

Before copying the YAML below:

  1. Create an External Application in UiPath with the OR.* scopes your pipeline needs. See Authentication — Flow 2.
  2. Store the secrets in an Azure DevOps variable group:
    • Project Settings → Pipelines → Library → New variable group (for example, uipath-prod).
    • Add UIPATH_CLIENT_ID and UIPATH_CLIENT_SECRET — mark both as secret (padlock icon).
    • Optionally add UIPATH_TENANT (not a secret).
  3. Link the variable group to the pipeline (see the variables block below).
  4. Provision a Test Manager project and test set (if you want the test stage). You will need the TEST_SET_KEY (format PROJECT:42) and PROJECT_KEY. See How-to: run tests from the CLI.

azure-pipelines.yml

trigger:
  branches:
    include: [ main ]

pr:
  branches:
    include: [ main ]

variables:
- group: uipath-prod           # contains UIPATH_CLIENT_ID, UIPATH_CLIENT_SECRET
- name:  CLI_VERSION
  value: '1.0.0'
- name:  NODE_VERSION
  value: '20.x'
- name:  SOLUTION_NAME
  value: 'my-solution'
- name:  SOLUTION_DIR
  value: '$(Build.SourcesDirectory)/my-solution'
- name:  OUTPUT_DIR
  value: '$(Build.ArtifactStagingDirectory)'
- name:  SOLUTION_VERSION
  value: '1.2.0-ci.$(Build.BuildId)'

# Path where npm places globally-installed packages. Used to cache the CLI + tools.
- name:  NPM_GLOBAL_CACHE
  value: '$(HOME)/.npm-global/lib/node_modules'

stages:

- stage: Build
  displayName: 'Pack the Solution'
  jobs:
  - job: pack
    pool:
      vmImage: 'ubuntu-latest'
    steps:

    - task: NodeTool@0
      displayName: 'Use Node.js $(NODE_VERSION)'
      inputs:
        versionSpec: $(NODE_VERSION)

    - task: Cache@2
      displayName: 'Cache npm global (@uipath/cli)'
      inputs:
        key:  'uip | "$(Agent.OS)" | $(CLI_VERSION)'
        path: $(NPM_GLOBAL_CACHE)

    - script: |
        set -euo pipefail
        mkdir -p "$HOME/.npm-global"
        npm config set prefix "$HOME/.npm-global"
        export PATH="$HOME/.npm-global/bin:$PATH"
        echo "##vso[task.prependpath]$HOME/.npm-global/bin"

        if ! command -v uip >/dev/null; then
          npm install -g "@uipath/cli@$(CLI_VERSION)"
          uip tools install @uipath/orchestrator-tool @uipath/solution-tool @uipath/test-manager-tool
        fi

        uip --version
      displayName: 'Install UiPath CLI and tools'

    - script: |
        set -euo pipefail
        uip solution pack "$(SOLUTION_DIR)" "$(OUTPUT_DIR)" \
          --name "$(SOLUTION_NAME)" \
          --version "$(SOLUTION_VERSION)"
      displayName: 'Pack Solution'

    - publish: '$(OUTPUT_DIR)/$(SOLUTION_NAME).$(SOLUTION_VERSION).zip'
      artifact: solution-zip
      displayName: 'Publish artifact'

- stage: Deploy
  displayName: 'Publish to feed and deploy to Orchestrator'
  dependsOn: Build
  jobs:
  - deployment: deploy
    environment: 'uipath-prod'      # Azure DevOps environment — gates / approvals live here
    pool:
      vmImage: 'ubuntu-latest'
    strategy:
      runOnce:
        deploy:
          steps:

          - task: NodeTool@0
            displayName: 'Use Node.js $(NODE_VERSION)'
            inputs:
              versionSpec: $(NODE_VERSION)

          - task: Cache@2
            displayName: 'Cache npm global (@uipath/cli)'
            inputs:
              key:  'uip | "$(Agent.OS)" | $(CLI_VERSION)'
              path: $(NPM_GLOBAL_CACHE)

          - script: |
              set -euo pipefail
              mkdir -p "$HOME/.npm-global"
              npm config set prefix "$HOME/.npm-global"
              export PATH="$HOME/.npm-global/bin:$PATH"
              echo "##vso[task.prependpath]$HOME/.npm-global/bin"

              if ! command -v uip >/dev/null; then
                npm install -g "@uipath/cli@$(CLI_VERSION)"
                uip tools install @uipath/orchestrator-tool @uipath/solution-tool @uipath/test-manager-tool
              fi
            displayName: 'Install UiPath CLI and tools'

          - script: |
              set -euo pipefail
              uip login \
                --client-id env.UIPATH_CLIENT_ID \
                --client-secret env.UIPATH_CLIENT_SECRET \
                --tenant "$UIPATH_TENANT"
            displayName: 'Authenticate'
            env:
              UIPATH_CLIENT_ID:     $(UIPATH_CLIENT_ID)
              UIPATH_CLIENT_SECRET: $(UIPATH_CLIENT_SECRET)
              UIPATH_TENANT:        $(UIPATH_TENANT)

          - download: current
            artifact: solution-zip

          - script: |
              set -euo pipefail
              uip solution publish \
                "$(Pipeline.Workspace)/solution-zip/$(SOLUTION_NAME).$(SOLUTION_VERSION).zip"
            displayName: 'Publish to tenant feed'

          - script: |
              set -euo pipefail
              uip solution deploy run \
                --name "$(SOLUTION_NAME)-$(Build.BuildId)" \
                --package-name "$(SOLUTION_NAME)" \
                --package-version "$(SOLUTION_VERSION)" \
                --folder-name MySolution \
                --folder-path Shared
            displayName: 'Deploy to Orchestrator'

- stage: Test
  displayName: 'Run Test Manager suite'
  dependsOn: Deploy
  condition: and(succeeded(), ne(variables['TEST_SET_KEY'], ''))
  jobs:
  - job: test
    pool:
      vmImage: 'ubuntu-latest'
    steps:

    - task: NodeTool@0
      displayName: 'Use Node.js $(NODE_VERSION)'
      inputs:
        versionSpec: $(NODE_VERSION)

    - task: Cache@2
      displayName: 'Cache npm global (@uipath/cli)'
      inputs:
        key:  'uip | "$(Agent.OS)" | $(CLI_VERSION)'
        path: $(NPM_GLOBAL_CACHE)

    - script: |
        set -euo pipefail
        export PATH="$HOME/.npm-global/bin:$PATH"
        echo "##vso[task.prependpath]$HOME/.npm-global/bin"
        if ! command -v uip >/dev/null; then
          npm install -g "@uipath/cli@$(CLI_VERSION)"
          uip tools install @uipath/orchestrator-tool @uipath/solution-tool @uipath/test-manager-tool
        fi

        uip login \
          --client-id env.UIPATH_CLIENT_ID \
          --client-secret env.UIPATH_CLIENT_SECRET \
          --tenant "$UIPATH_TENANT"
      displayName: 'Install + authenticate'
      env:
        UIPATH_CLIENT_ID:     $(UIPATH_CLIENT_ID)
        UIPATH_CLIENT_SECRET: $(UIPATH_CLIENT_SECRET)
        UIPATH_TENANT:        $(UIPATH_TENANT)

    - script: |
        set -euo pipefail

        EXECUTION_ID=$(uip tm testset execute \
          --test-set-key "$TEST_SET_KEY" \
          --output-filter "Data.ExecutionId" \
          --output plain)

        echo "started execution $EXECUTION_ID"

        if ! uip tm wait \
          --execution-id "$EXECUTION_ID" \
          --project-key "$PROJECT_KEY" \
          --timeout 1800; then
          code=$?
          case "$code" in
            2) echo "##vso[task.logissue type=error]test run did not finish within 30 minutes"; exit 2 ;;
            *) echo "##vso[task.logissue type=error]wait failed (exit $code)"; exit "$code" ;;
          esac
        fi

        uip tm report get \
          --execution-id "$EXECUTION_ID" \
          --project-key "$PROJECT_KEY"

        FAILED=$(uip tm report get \
          --execution-id "$EXECUTION_ID" \
          --project-key "$PROJECT_KEY" \
          --output-filter "Data.Failed" \
          --output plain)

        if [ "$FAILED" -gt 0 ]; then
          echo "##vso[task.logissue type=error]$FAILED test case(s) failed"
          exit 1
        fi
      displayName: 'Launch, wait, verify'
      env:
        TEST_SET_KEY: $(TEST_SET_KEY)
        PROJECT_KEY:  $(PROJECT_KEY)
trigger:
  branches:
    include: [ main ]

pr:
  branches:
    include: [ main ]

variables:
- group: uipath-prod           # contains UIPATH_CLIENT_ID, UIPATH_CLIENT_SECRET
- name:  CLI_VERSION
  value: '1.0.0'
- name:  NODE_VERSION
  value: '20.x'
- name:  SOLUTION_NAME
  value: 'my-solution'
- name:  SOLUTION_DIR
  value: '$(Build.SourcesDirectory)/my-solution'
- name:  OUTPUT_DIR
  value: '$(Build.ArtifactStagingDirectory)'
- name:  SOLUTION_VERSION
  value: '1.2.0-ci.$(Build.BuildId)'

# Path where npm places globally-installed packages. Used to cache the CLI + tools.
- name:  NPM_GLOBAL_CACHE
  value: '$(HOME)/.npm-global/lib/node_modules'

stages:

- stage: Build
  displayName: 'Pack the Solution'
  jobs:
  - job: pack
    pool:
      vmImage: 'ubuntu-latest'
    steps:

    - task: NodeTool@0
      displayName: 'Use Node.js $(NODE_VERSION)'
      inputs:
        versionSpec: $(NODE_VERSION)

    - task: Cache@2
      displayName: 'Cache npm global (@uipath/cli)'
      inputs:
        key:  'uip | "$(Agent.OS)" | $(CLI_VERSION)'
        path: $(NPM_GLOBAL_CACHE)

    - script: |
        set -euo pipefail
        mkdir -p "$HOME/.npm-global"
        npm config set prefix "$HOME/.npm-global"
        export PATH="$HOME/.npm-global/bin:$PATH"
        echo "##vso[task.prependpath]$HOME/.npm-global/bin"

        if ! command -v uip >/dev/null; then
          npm install -g "@uipath/cli@$(CLI_VERSION)"
          uip tools install @uipath/orchestrator-tool @uipath/solution-tool @uipath/test-manager-tool
        fi

        uip --version
      displayName: 'Install UiPath CLI and tools'

    - script: |
        set -euo pipefail
        uip solution pack "$(SOLUTION_DIR)" "$(OUTPUT_DIR)" \
          --name "$(SOLUTION_NAME)" \
          --version "$(SOLUTION_VERSION)"
      displayName: 'Pack Solution'

    - publish: '$(OUTPUT_DIR)/$(SOLUTION_NAME).$(SOLUTION_VERSION).zip'
      artifact: solution-zip
      displayName: 'Publish artifact'

- stage: Deploy
  displayName: 'Publish to feed and deploy to Orchestrator'
  dependsOn: Build
  jobs:
  - deployment: deploy
    environment: 'uipath-prod'      # Azure DevOps environment — gates / approvals live here
    pool:
      vmImage: 'ubuntu-latest'
    strategy:
      runOnce:
        deploy:
          steps:

          - task: NodeTool@0
            displayName: 'Use Node.js $(NODE_VERSION)'
            inputs:
              versionSpec: $(NODE_VERSION)

          - task: Cache@2
            displayName: 'Cache npm global (@uipath/cli)'
            inputs:
              key:  'uip | "$(Agent.OS)" | $(CLI_VERSION)'
              path: $(NPM_GLOBAL_CACHE)

          - script: |
              set -euo pipefail
              mkdir -p "$HOME/.npm-global"
              npm config set prefix "$HOME/.npm-global"
              export PATH="$HOME/.npm-global/bin:$PATH"
              echo "##vso[task.prependpath]$HOME/.npm-global/bin"

              if ! command -v uip >/dev/null; then
                npm install -g "@uipath/cli@$(CLI_VERSION)"
                uip tools install @uipath/orchestrator-tool @uipath/solution-tool @uipath/test-manager-tool
              fi
            displayName: 'Install UiPath CLI and tools'

          - script: |
              set -euo pipefail
              uip login \
                --client-id env.UIPATH_CLIENT_ID \
                --client-secret env.UIPATH_CLIENT_SECRET \
                --tenant "$UIPATH_TENANT"
            displayName: 'Authenticate'
            env:
              UIPATH_CLIENT_ID:     $(UIPATH_CLIENT_ID)
              UIPATH_CLIENT_SECRET: $(UIPATH_CLIENT_SECRET)
              UIPATH_TENANT:        $(UIPATH_TENANT)

          - download: current
            artifact: solution-zip

          - script: |
              set -euo pipefail
              uip solution publish \
                "$(Pipeline.Workspace)/solution-zip/$(SOLUTION_NAME).$(SOLUTION_VERSION).zip"
            displayName: 'Publish to tenant feed'

          - script: |
              set -euo pipefail
              uip solution deploy run \
                --name "$(SOLUTION_NAME)-$(Build.BuildId)" \
                --package-name "$(SOLUTION_NAME)" \
                --package-version "$(SOLUTION_VERSION)" \
                --folder-name MySolution \
                --folder-path Shared
            displayName: 'Deploy to Orchestrator'

- stage: Test
  displayName: 'Run Test Manager suite'
  dependsOn: Deploy
  condition: and(succeeded(), ne(variables['TEST_SET_KEY'], ''))
  jobs:
  - job: test
    pool:
      vmImage: 'ubuntu-latest'
    steps:

    - task: NodeTool@0
      displayName: 'Use Node.js $(NODE_VERSION)'
      inputs:
        versionSpec: $(NODE_VERSION)

    - task: Cache@2
      displayName: 'Cache npm global (@uipath/cli)'
      inputs:
        key:  'uip | "$(Agent.OS)" | $(CLI_VERSION)'
        path: $(NPM_GLOBAL_CACHE)

    - script: |
        set -euo pipefail
        export PATH="$HOME/.npm-global/bin:$PATH"
        echo "##vso[task.prependpath]$HOME/.npm-global/bin"
        if ! command -v uip >/dev/null; then
          npm install -g "@uipath/cli@$(CLI_VERSION)"
          uip tools install @uipath/orchestrator-tool @uipath/solution-tool @uipath/test-manager-tool
        fi

        uip login \
          --client-id env.UIPATH_CLIENT_ID \
          --client-secret env.UIPATH_CLIENT_SECRET \
          --tenant "$UIPATH_TENANT"
      displayName: 'Install + authenticate'
      env:
        UIPATH_CLIENT_ID:     $(UIPATH_CLIENT_ID)
        UIPATH_CLIENT_SECRET: $(UIPATH_CLIENT_SECRET)
        UIPATH_TENANT:        $(UIPATH_TENANT)

    - script: |
        set -euo pipefail

        EXECUTION_ID=$(uip tm testset execute \
          --test-set-key "$TEST_SET_KEY" \
          --output-filter "Data.ExecutionId" \
          --output plain)

        echo "started execution $EXECUTION_ID"

        if ! uip tm wait \
          --execution-id "$EXECUTION_ID" \
          --project-key "$PROJECT_KEY" \
          --timeout 1800; then
          code=$?
          case "$code" in
            2) echo "##vso[task.logissue type=error]test run did not finish within 30 minutes"; exit 2 ;;
            *) echo "##vso[task.logissue type=error]wait failed (exit $code)"; exit "$code" ;;
          esac
        fi

        uip tm report get \
          --execution-id "$EXECUTION_ID" \
          --project-key "$PROJECT_KEY"

        FAILED=$(uip tm report get \
          --execution-id "$EXECUTION_ID" \
          --project-key "$PROJECT_KEY" \
          --output-filter "Data.Failed" \
          --output plain)

        if [ "$FAILED" -gt 0 ]; then
          echo "##vso[task.logissue type=error]$FAILED test case(s) failed"
          exit 1
        fi
      displayName: 'Launch, wait, verify'
      env:
        TEST_SET_KEY: $(TEST_SET_KEY)
        PROJECT_KEY:  $(PROJECT_KEY)

Walkthrough

Stage 1 — Build

  • NodeTool@0 pins Node.js to version 20. Pin to a major; the CLI requires 18+.
  • Cache@2 caches the npm global node_modules directory. The cache key includes $(CLI_VERSION) so a version bump invalidates cleanly.
  • Install step switches npm's global prefix to $HOME/.npm-global (no sudo needed), prepends it to the PATH, and — only if the cache missed — installs @uipath/cli and pre-installs the three tools used in this pipeline. See Installing UiPath CLI — CI/CD and Scripting patterns — pinning versions.
  • Pack step invokes uip solution pack with an explicit --version (never rely on the 1.0.0 default in CI).
  • publish: ... uploads the .zip as a pipeline artifact named solution-zip so the Deploy stage can consume it.

Stage 2 — Deploy

Uses a deployment job bound to a named environment. Environments are where you configure gates and approvals in Azure DevOps — the YAML itself stays simple.

  • Re-installs the CLI (the cache should hit on the second stage of the same run).
  • uip login uses the env.VAR_NAME prefix for both the client ID and secret. The env: block at the step level maps $(UIPATH_CLIENT_ID) (from the variable group) to the actual environment variable UIPATH_CLIENT_ID that the flag resolves. Do not pass the secret literally on the command line (--client-secret "$(UIPATH_CLIENT_SECRET)") — that leaks it into the build log and ps output. The env. prefix feature is documented in Authentication — the env.VAR_NAME prefix.
  • download: current pulls the solution-zip artifact from Stage 1 into $(Pipeline.Workspace)/solution-zip.
  • uip solution publish uploads the .zip to the tenant feed.
  • uip solution deploy run creates the deployment. --name uses $(Build.BuildId) so each run is identifiable and re-deploys do not clobber each other's deployment record.

Stage 3 — Test

Only runs if TEST_SET_KEY is set at the variable-group level — the condition: guard skips the stage cleanly if you don't have a test suite configured.

The shell block is the canonical launch → wait → verify flow from How-to: run tests from the CLI:

  1. uip tm testset execute launches the run and returns an ExecutionId.
  2. uip tm wait blocks until the execution reaches a terminal state (exit 2 means timeout, not auth failure — a domain-specific reuse of the exit-code slot).
  3. uip tm report get reads Data.Failed; the step fails with ##vso[task.logissue type=error] so the outcome surfaces cleanly in the Azure DevOps UI.

Common variations

Pin tool versions too

By default, uip tools install resolves to the latest tool version in the CLI's MAJOR.MINOR line. For strict patch-level reproducibility:

- script: |
    uip tools install \
      @uipath/orchestrator-tool@1.0.2 \
      @uipath/solution-tool@1.0.2 \
      @uipath/test-manager-tool@1.0.2
  displayName: 'Install pinned tools'
- script: |
    uip tools install \
      @uipath/orchestrator-tool@1.0.2 \
      @uipath/solution-tool@1.0.2 \
      @uipath/test-manager-tool@1.0.2
  displayName: 'Install pinned tools'

Promote across environments

Link two variable groups — uipath-stage and uipath-prod — and turn each into a separate deployment: job. Use environment-specific gates/approvals to decide when prod runs:

- stage: DeployStage
  dependsOn: Build
  jobs:
  - deployment: deploy-stage
    variables: [ { group: uipath-stage } ]
    environment: 'uipath-stage'
    # …same steps as above, but with stage's tenant

- stage: DeployProd
  dependsOn: DeployStage
  jobs:
  - deployment: deploy-prod
    variables: [ { group: uipath-prod } ]
    environment: 'uipath-prod'    # attach a manual approval gate here
    # …same steps as above
- stage: DeployStage
  dependsOn: Build
  jobs:
  - deployment: deploy-stage
    variables: [ { group: uipath-stage } ]
    environment: 'uipath-stage'
    # …same steps as above, but with stage's tenant

- stage: DeployProd
  dependsOn: DeployStage
  jobs:
  - deployment: deploy-prod
    variables: [ { group: uipath-prod } ]
    environment: 'uipath-prod'    # attach a manual approval gate here
    # …same steps as above

Reversión

Azure DevOps does not roll back automatically; add a manual stage that re-deploys the previous version:

- stage: Rollback
  dependsOn: []                   # run on demand, not from Deploy
  jobs:
  - job: rollback
    pool: { vmImage: 'ubuntu-latest' }
    steps:
    # …install + auth…
    - script: |
        uip solution deploy run \
          --name "$(SOLUTION_NAME)-rollback" \
          --package-name "$(SOLUTION_NAME)" \
          --package-version "$(ROLLBACK_VERSION)" \
          --folder-name MySolution \
          --folder-path Shared
      displayName: 'Re-deploy previous version'
- stage: Rollback
  dependsOn: []                   # run on demand, not from Deploy
  jobs:
  - job: rollback
    pool: { vmImage: 'ubuntu-latest' }
    steps:
    # …install + auth…
    - script: |
        uip solution deploy run \
          --name "$(SOLUTION_NAME)-rollback" \
          --package-name "$(SOLUTION_NAME)" \
          --package-version "$(ROLLBACK_VERSION)" \
          --folder-name MySolution \
          --folder-path Shared
      displayName: 'Re-deploy previous version'

Pass ROLLBACK_VERSION at queue time. For destructive rollback (uninstall + delete artifact), see How-to: pack and publish a Solution — rollback.

Skipping tests

To run without the test stage, delete the Test stage block (or leave TEST_SET_KEY unset — the condition: on the stage will skip it).

Common pitfalls

  • env. prefix vs literal secret. Always --client-secret env.UIPATH_CLIENT_SECRET, never --client-secret "$(UIPATH_CLIENT_SECRET)". The literal form embeds the value into the rendered command line. See the auth warning.
  • ##vso[task.setvariable] is not needed for env. resolution — env: on the step exposes the variable directly.
  • Multi-line bash needs set -euo pipefail at the top of every script: block. Without it, pack can fail while later steps keep running. See Scripting patterns — strict shell options.
  • Cache hits are not guaranteed. Always wrap the install commands in if ! command -v uip so the pipeline self-heals when the cache is cold.

Ver también

¿Te ha resultado útil esta página?

Conectar

¿Necesita ayuda? Soporte

¿Quiere aprender? UiPath Academy

¿Tiene alguna pregunta? Foro de UiPath

Manténgase actualizado