Skip to main content

Migration: pipeline examples

Before/after pipeline snippets for the four common CI platforms. Each example is the auth + pack + deploy core — the shortest portable shape. For full working pipelines (caching, stages, approvals, test stage), cross-link to the CI/CD recipes.

Read Command map and Flag renames first if you have not — this page shows the ported result, not the mapping rules.

Azure DevOps (YAML)

Before: a pipeline using the UiPath.CLI NuGet package and uipcli.exe via a Command Line task.

# Before — azure-pipelines.yml using legacy .NET CLI
trigger: [ main ]

pool:
vmImage: 'windows-2022'

variables:
UIPCLI_VERSION: '25.10.9401.39120'
ORCH_URL: 'https://cloud.uipath.com/'
ORCH_TENANT: 'DefaultTenant'

steps:
- task: NuGetCommand@2
displayName: 'Install UiPath.CLI.Windows'
inputs:
command: 'custom'
arguments: 'install UiPath.CLI.Windows -Version $(UIPCLI_VERSION) -OutputDirectory $(Agent.ToolsDirectory)\uipcli'

- script: |
set UIPCLI_PATH=$(Agent.ToolsDirectory)\uipcli\UiPath.CLI.Windows.$(UIPCLI_VERSION)\tools\uipcli.exe
"%UIPCLI_PATH%" package pack "$(Build.SourcesDirectory)\MyProject\project.json" ^
-o "$(Build.ArtifactStagingDirectory)" ^
--autoVersion --traceLevel Information
displayName: 'Pack project'

- script: |
set UIPCLI_PATH=$(Agent.ToolsDirectory)\uipcli\UiPath.CLI.Windows.$(UIPCLI_VERSION)\tools\uipcli.exe
"%UIPCLI_PATH%" package deploy "$(Build.ArtifactStagingDirectory)" ^
"$(ORCH_URL)" "$(ORCH_TENANT)" ^
-A "$(UIPATH_ORG)" ^
-I "$(UIPATH_CLIENT_ID)" ^
-S "$(UIPATH_CLIENT_SECRET)" ^
--applicationScope "OR.Folders OR.Execution OR.Assets" ^
--identityUrl "$(ORCH_URL)identity" ^
-o "Shared" ^
--processName "MyProcess" ^
--entryPointsPath "Main.xaml" ^
--traceLevel Information
displayName: 'Deploy package'
env:
UIPATH_CLIENT_ID: $(UIPATH_CLIENT_ID)
UIPATH_CLIENT_SECRET: $(UIPATH_CLIENT_SECRET)

After: the same flow with uip, running on ubuntu-latest. A full end-to-end Azure Pipelines recipe (caching, deployment stages with approvals, Test Manager stage) lives in CI/CD recipe: Azure Pipelines.

# After — azure-pipelines.yml using uip
trigger: [ main ]

pool:
vmImage: 'ubuntu-latest'

variables:
- group: uipath-prod # holds UIPATH_CLIENT_ID, UIPATH_CLIENT_SECRET
- name: CLI_VERSION
value: '1.0.0'
- name: UIPATH_TENANT
value: 'DefaultTenant'

steps:
- task: NodeTool@0
displayName: 'Use Node.js 20'
inputs:
versionSpec: '20.x'

- script: |
set -euo pipefail
npm install -g "@uipath/cli@$(CLI_VERSION)"
uip tools install or # pre-install the Orchestrator tool
uip tools install rpa # for rpa pack / analyze / restore
uip --version
displayName: 'Install UiPath CLI'

- script: |
set -euo pipefail
uip rpa pack ./MyProject --output ./dist --version "$(Build.BuildNumber)"
# See `uip rpa pack --help` for the complete flag list.
displayName: 'Pack project'

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

# Discover the packed file — version flows through from the pack step
PACKAGE=$(ls ./MyProject.*.nupkg | head -1)

# Upload to the tenant feed
uip or packages upload "$PACKAGE"

# Extract the uploaded package key (format: "PackageId:Version")
PKG_KEY=$(uip or packages upload "$PACKAGE" \
--output-filter 'Data[0].body' --output plain)
PKG_ID=${PKG_KEY%:*}
PKG_VER=${PKG_KEY#*:}

# Create or update the process
uip or processes create \
--name "MyProcess" \
--package-key "$PKG_ID" \
--package-version "$PKG_VER" \
--folder-path "Shared" \
--entry-point "Main.xaml"
displayName: 'Deploy package'
env:
UIPATH_CLIENT_ID: $(UIPATH_CLIENT_ID)
UIPATH_CLIENT_SECRET: $(UIPATH_CLIENT_SECRET)
UIPATH_TENANT: $(UIPATH_TENANT)

Key differences to review:

  • Agent image. ubuntu-latest works now because the CLI is a Node tool. If you have other Windows-only pipeline steps, keep windows-2022uip runs on both.
  • Auth flag shape. --client-id env.UIPATH_CLIENT_ID resolves from the environment without expanding onto the command line. The env: block at the step level wires the variable-group secret into the process environment. See Breaking changes — implicit env-var reading.
  • Pack + deploy split. Legacy package deploy <folder> uploaded every .nupkg in the folder and created processes in one call. uip splits upload (uip or packages upload) from create (uip or processes create). Capture the package key from the upload response to chain them cleanly.
  • set -euo pipefail. Multi-line bash steps need strict mode so a pack failure aborts the step before deploy runs. See Scripting patterns — strict shell options.
  • No --traceLevel. The new CLI uses --log-level (default info). Logs go to stderr and stay out of the JSON payload on stdout.

Cross-link: CI/CD recipe: Azure Pipelines — full stages, variable groups, deployment jobs with approvals, and a Test Manager stage.

Jenkins (declarative)

Before: a Windows-agent pipeline unpacking the UiPath.CLI.Windows NuGet and invoking uipcli.exe.

// Before — Jenkinsfile using legacy .NET CLI
pipeline {
agent { label 'windows' }

environment {
UIPCLI_VERSION = '25.10.9401.39120'
UIPCLI_PATH = "${env.WORKSPACE}\\uipcli\\UiPath.CLI.Windows.${UIPCLI_VERSION}\\tools\\uipcli.exe"
ORCH_URL = 'https://cloud.uipath.com/'
ORCH_TENANT = 'DefaultTenant'
}

stages {
stage('Install CLI') {
steps {
bat '''
curl -L -O https://www.nuget.org/api/v2/package/UiPath.CLI.Windows/%UIPCLI_VERSION%
tar -xf UiPath.CLI.Windows.%UIPCLI_VERSION%.nupkg -C uipcli
'''
}
}
stage('Pack') {
steps {
bat '"%UIPCLI_PATH%" package pack "%WORKSPACE%\\MyProject\\project.json" -o "%WORKSPACE%\\dist" --autoVersion'
}
}
stage('Deploy') {
steps {
withCredentials([
string(credentialsId: 'UIPATH_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'),
string(credentialsId: 'UIPATH_CLIENT_SECRET', variable: 'UIPATH_CLIENT_SECRET')
]) {
bat '''
"%UIPCLI_PATH%" package deploy "%WORKSPACE%\\dist" "%ORCH_URL%" "%ORCH_TENANT%" ^
-A "%UIPATH_ORG%" -I "%UIPATH_CLIENT_ID%" -S "%UIPATH_CLIENT_SECRET%" ^
--applicationScope "OR.Folders OR.Execution OR.Assets" ^
--identityUrl "%ORCH_URL%identity" ^
-o "Shared" ^
--processName "MyProcess"
'''
}
}
}
}
}

After: Linux agent, npm install, session auth. A full Jenkinsfile with a Test Manager stage lives in CI/CD recipe: Jenkins.

// After — Jenkinsfile using uip
pipeline {
agent { label 'linux' }

environment {
CLI_VERSION = '1.0.0'
UIPATH_TENANT = 'DefaultTenant'
NPM_PREFIX = "${env.WORKSPACE}/.npm-global"
}

stages {
stage('Install CLI') {
steps {
sh '''#!/usr/bin/env bash
set -euo pipefail
mkdir -p "$NPM_PREFIX"
npm config set prefix "$NPM_PREFIX"
export PATH="$NPM_PREFIX/bin:$PATH"
if ! command -v uip >/dev/null; then
npm install -g "@uipath/cli@${CLI_VERSION}"
uip tools install or
uip tools install rpa
fi
uip --version
'''
}
}

stage('Pack') {
steps {
sh '''#!/usr/bin/env bash
set -euo pipefail
export PATH="$NPM_PREFIX/bin:$PATH"
uip rpa pack ./MyProject
'''
}
}

stage('Deploy') {
steps {
withCredentials([
string(credentialsId: 'UIPATH_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'),
string(credentialsId: 'UIPATH_CLIENT_SECRET', variable: 'UIPATH_CLIENT_SECRET')
]) {
sh '''#!/usr/bin/env bash
set -euo pipefail
export PATH="$NPM_PREFIX/bin:$PATH"

uip login \
--client-id env.UIPATH_CLIENT_ID \
--client-secret env.UIPATH_CLIENT_SECRET \
--tenant "$UIPATH_TENANT"

PACKAGE=$(ls ./MyProject.*.nupkg | head -1)
PKG_KEY=$(uip or packages upload "$PACKAGE" \
--output-filter "Data[0].body" --output plain)
PKG_ID=${PKG_KEY%:*}
PKG_VER=${PKG_KEY#*:}

uip or processes create \
--name "MyProcess" \
--package-key "$PKG_ID" \
--package-version "$PKG_VER" \
--folder-path "Shared" \
--entry-point "Main.xaml"
'''
}
}
}
}
}

Key differences to review:

  • withCredentialsenv. prefix. Jenkins' withCredentials block exports the secret into the process environment; on the CLI side, reference it as env.UIPATH_CLIENT_SECRET so it never expands onto the command line. Do not use --client-secret "$UIPATH_CLIENT_SECRET".
  • Agent label. linux + Node 18+ is the common case. If you must run on Windows, agent { label 'windows' } and bat '''npm install -g @uipath/cli …''' work — Node is cross-platform.
  • NPM_PREFIX workaround. The npm install -g target defaults to a path that may need root. Setting NPM_PREFIX to a workspace-local directory avoids the need for sudo. Cached by Jenkins between builds if the workspace is preserved.

Cross-link: CI/CD recipe: Jenkins — full declarative pipeline with stash/unstash, archiveArtifacts, test stage, and agent variations.

GitHub Actions

Before: a Windows runner installing UiPath.CLI.Windows from NuGet. Condensed to the deploy step for brevity.

# Before — .github/workflows/deploy.yml using legacy .NET CLI
jobs:
deploy:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- name: Install uipcli
run: |
nuget install UiPath.CLI.Windows -Version 25.10.9401.39120 -OutputDirectory $env:RUNNER_TEMP\uipcli
echo "UIPCLI_PATH=$env:RUNNER_TEMP\uipcli\UiPath.CLI.Windows.25.10.9401.39120\tools\uipcli.exe" >> $env:GITHUB_ENV

- name: Deploy
run: |
& "$env:UIPCLI_PATH" package deploy "${{ github.workspace }}\dist" `
"${{ vars.ORCH_URL }}" "${{ vars.ORCH_TENANT }}" `
-I "${{ secrets.UIPATH_CLIENT_ID }}" `
-S "${{ secrets.UIPATH_CLIENT_SECRET }}" `
--applicationScope "OR.Folders OR.Execution" `
-o "Shared" --processName "MyProcess"

After: Ubuntu runner, npm install, session auth.

# After — .github/workflows/deploy.yml using uip
jobs:
deploy:
runs-on: ubuntu-latest
env:
CLI_VERSION: '1.0.0'
UIPATH_TENANT: 'DefaultTenant'
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install UiPath CLI
run: |
set -euo pipefail
npm install -g "@uipath/cli@${CLI_VERSION}"
uip tools install or
uip tools install rpa

- name: Pack
run: |
set -euo pipefail
uip rpa pack ./MyProject

- name: Deploy
env:
UIPATH_CLIENT_ID: ${{ secrets.UIPATH_CLIENT_ID }}
UIPATH_CLIENT_SECRET: ${{ secrets.UIPATH_CLIENT_SECRET }}
run: |
set -euo pipefail

uip login \
--client-id env.UIPATH_CLIENT_ID \
--client-secret env.UIPATH_CLIENT_SECRET \
--tenant "$UIPATH_TENANT"

PACKAGE=$(ls ./MyProject.*.nupkg | head -1)
PKG_KEY=$(uip or packages upload "$PACKAGE" \
--output-filter "Data[0].body" --output plain)
PKG_ID=${PKG_KEY%:*}
PKG_VER=${PKG_KEY#*:}

uip or processes create \
--name "MyProcess" \
--package-key "$PKG_ID" \
--package-version "$PKG_VER" \
--folder-path "Shared" \
--entry-point "Main.xaml"

Key differences:

  • env: at step level, env.VAR_NAME in flags. GitHub Actions secrets are injected through the step's env: block; the CLI reads them through --client-id env.UIPATH_CLIENT_ID. Never use --client-secret "${{ secrets.X }}" — that expands the secret literal into the workflow log.
  • actions/setup-node@v4 replaces every .NET / NuGet setup step.

Cross-link: CI/CD recipe: GitHub Actions — full workflow with matrix builds, artifact upload, and a test job.

GitLab CI

Before: a dotnet-sdk image unpacking UiPath.CLI from NuGet.

# Before — .gitlab-ci.yml using legacy .NET CLI
image: mcr.microsoft.com/dotnet/sdk:6.0

variables:
UIPCLI_VERSION: '25.10.9401.39120'

deploy:
script:
- |
dotnet tool install -g UiPath.CLI --version $UIPCLI_VERSION
uipcli package deploy "./dist" \
"$ORCH_URL" "$ORCH_TENANT" \
-I "$UIPATH_CLIENT_ID" -S "$UIPATH_CLIENT_SECRET" \
--applicationScope "OR.Folders OR.Execution" \
-o "Shared" --processName "MyProcess"

After: Node image, session auth, explicit env. references.

# After — .gitlab-ci.yml using uip
image: node:20

variables:
CLI_VERSION: '1.0.0'
UIPATH_TENANT: 'DefaultTenant'

deploy:
script:
- set -euo pipefail
- npm install -g "@uipath/cli@$CLI_VERSION"
- uip tools install or
- uip tools install rpa
- uip rpa pack ./MyProject
- |
uip login \
--client-id env.UIPATH_CLIENT_ID \
--client-secret env.UIPATH_CLIENT_SECRET \
--tenant "$UIPATH_TENANT"
- |
PACKAGE=$(ls ./MyProject.*.nupkg | head -1)
PKG_KEY=$(uip or packages upload "$PACKAGE" \
--output-filter "Data[0].body" --output plain)
PKG_ID=${PKG_KEY%:*}
PKG_VER=${PKG_KEY#*:}
uip or processes create \
--name "MyProcess" \
--package-key "$PKG_ID" \
--package-version "$PKG_VER" \
--folder-path "Shared" \
--entry-point "Main.xaml"

GitLab CI variables defined under the project's CI/CD settings (UIPATH_CLIENT_ID, UIPATH_CLIENT_SECRET, marked Masked and Protected) appear in the job's environment automatically, so the env. prefix on the CLI flags resolves without extra wiring.

Cross-link: CI/CD recipe: GitLab CI — full .gitlab-ci.yml with stages, artifacts, manual deploy gates, and a test stage.

Checklist for a clean port

Run through this before you commit the first pass:

  • uipcli.exe is no longer referenced anywhere in the pipeline files.
  • UiPath.CLI / UiPath.CLI.Windows NuGet install steps are removed.
  • .NET or dotnet-sdk setup is removed (unless other pipeline steps still need it).
  • Auth flags (-u, -p, -t, -a, -I, -S, -A) are gone from every command.
  • uip login --client-id env.X --client-secret env.Y --tenant Z is the single auth entry point.
  • --identityUrl is renamed to --authority (only used for non-Automation-Cloud environments).
  • --traceLevel is replaced by --log-level (or dropped).
  • Every shell parse of legacy uipcli text stdout is replaced with --output-filter ... --output plain or jq.
  • Downstream expectations of .nupkg for Solutions are updated to .zip.
  • Exit-code branches (case $?) use only 0/1/2/3/4/130, with uip tm wait's timeout-reuses-2 handled explicitly.
  • UIPATH_TELEMETRY_DISABLED=1 is set if your org prohibits outbound telemetry.

See also