- Información general
- Comience ya
- Conceptos
- Using UiPath CLI
- Guías prácticas
- CI/CD recipes
- Referencia de los comandos
- Información general
- Códigos de salida
- Global options
- uip codedagent
- uip docsai
- add-test-data-entity
- add-test-data-queue
- add-test-data-variation
- analyze
- build
- Crear proyecto
- diff
- find-activities
- get-analyzer-rules
- get-default-activity-xaml
- get-errors
- get-manual-test-cases
- get-manual-test-steps
- get-versions
- get-workflow-example
- indicate-application
- indicate-element
- inspect-package
- install-data-fabric-entities
- install-or-update-packages
- list-data-fabric-entities
- list-workflow-examples
- pack
- restore
- run-file
- search-templates
- start-studio
- stop-execution
- uia
- uip traces
- Migración
- Reference & support
UiPath CLI user guide
This page gives you a complete declarative Jenkinsfile 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. Place it in the root of your repo, create a matching Jenkins credentials entry, and the pipeline 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 Jenkins syntax, including the bits (withCredentials, stash / unstash, agent selection) that are Jenkins-specific.
Requisitos previos
Before copying the Jenkinsfile:
- Create an External Application in UiPath with the
OR.*scopes your pipeline needs. See Authentication — Flow 2. - Store the secrets in Jenkins credentials:
- Manage Jenkins → Credentials → System → Global credentials (unrestricted).
- Add two Secret text entries with IDs
UIPATH_CLIENT_IDandUIPATH_CLIENT_SECRET. - Add a Plain text or Secret text entry with ID
UIPATH_TENANT(the tenant name; not strictly secret, but credentials are the most portable place).
- Agent requirements. The pipeline assumes an agent labelled
linuxwith Node.js 18+ andnpmon the PATH. See the alternative agent options below if you run on Windows or in a container. - Provision a Test Manager project and test set if you want the test stage. Add
TEST_SET_KEYandPROJECT_KEYas additional credentials (or as pipeline parameters).
Jenkinsfile
pipeline {
agent none
options {
timestamps()
buildDiscarder(logRotator(numToKeepStr: '30'))
disableConcurrentBuilds()
}
environment {
CLI_VERSION = '1.0.0'
SOLUTION_NAME = 'my-solution'
SOLUTION_DIR = 'my-solution'
OUTPUT_DIR = 'dist'
SOLUTION_VERSION = "1.2.0-ci.${env.BUILD_NUMBER}"
// npm global prefix for a user-local, no-sudo install
NPM_PREFIX = "${env.WORKSPACE}/.npm-global"
}
stages {
stage('Build') {
agent { label 'linux' }
steps {
checkout scm
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 \
@uipath/orchestrator-tool \
@uipath/solution-tool \
@uipath/test-manager-tool
fi
uip --version
mkdir -p "$OUTPUT_DIR"
uip solution pack "$SOLUTION_DIR" "$OUTPUT_DIR" \
--name "$SOLUTION_NAME" \
--version "$SOLUTION_VERSION"
'''
// Carry the .zip to the Deploy stage, which runs on a fresh agent.
stash name: 'solution-zip', includes: "${OUTPUT_DIR}/${SOLUTION_NAME}.${SOLUTION_VERSION}.zip"
archiveArtifacts artifacts: "${OUTPUT_DIR}/*.zip", fingerprint: true
}
}
stage('Deploy') {
agent { label 'linux' }
steps {
unstash 'solution-zip'
withCredentials([
string(credentialsId: 'UIPATH_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'),
string(credentialsId: 'UIPATH_CLIENT_SECRET', variable: 'UIPATH_CLIENT_SECRET'),
string(credentialsId: 'UIPATH_TENANT', variable: 'UIPATH_TENANT')
]) {
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 \
@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"
uip solution publish "${OUTPUT_DIR}/${SOLUTION_NAME}.${SOLUTION_VERSION}.zip"
uip solution deploy run \
--name "${SOLUTION_NAME}-${BUILD_NUMBER}" \
--package-name "$SOLUTION_NAME" \
--package-version "$SOLUTION_VERSION" \
--folder-name MySolution \
--folder-path Shared
'''
}
}
}
stage('Test') {
when {
expression { return env.TEST_SET_KEY?.trim() }
}
agent { label 'linux' }
steps {
withCredentials([
string(credentialsId: 'UIPATH_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'),
string(credentialsId: 'UIPATH_CLIENT_SECRET', variable: 'UIPATH_CLIENT_SECRET'),
string(credentialsId: 'UIPATH_TENANT', variable: 'UIPATH_TENANT'),
string(credentialsId: 'TEST_SET_KEY', variable: 'TEST_SET_KEY'),
string(credentialsId: 'PROJECT_KEY', variable: 'PROJECT_KEY')
]) {
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 @uipath/test-manager-tool
fi
uip login \
--client-id env.UIPATH_CLIENT_ID \
--client-secret env.UIPATH_CLIENT_SECRET \
--tenant "$UIPATH_TENANT"
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 "test run did not finish within 30 minutes" >&2; exit 2 ;;
*) echo "wait failed (exit $code)" >&2; 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 "$FAILED test case(s) failed" >&2
exit 1
fi
'''
}
}
}
}
post {
always {
// Best-effort cleanup; uip logout only matters on a persistent agent.
node('linux') {
sh '''
if command -v uip >/dev/null; then
uip logout || true
fi
'''
}
}
}
}
pipeline {
agent none
options {
timestamps()
buildDiscarder(logRotator(numToKeepStr: '30'))
disableConcurrentBuilds()
}
environment {
CLI_VERSION = '1.0.0'
SOLUTION_NAME = 'my-solution'
SOLUTION_DIR = 'my-solution'
OUTPUT_DIR = 'dist'
SOLUTION_VERSION = "1.2.0-ci.${env.BUILD_NUMBER}"
// npm global prefix for a user-local, no-sudo install
NPM_PREFIX = "${env.WORKSPACE}/.npm-global"
}
stages {
stage('Build') {
agent { label 'linux' }
steps {
checkout scm
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 \
@uipath/orchestrator-tool \
@uipath/solution-tool \
@uipath/test-manager-tool
fi
uip --version
mkdir -p "$OUTPUT_DIR"
uip solution pack "$SOLUTION_DIR" "$OUTPUT_DIR" \
--name "$SOLUTION_NAME" \
--version "$SOLUTION_VERSION"
'''
// Carry the .zip to the Deploy stage, which runs on a fresh agent.
stash name: 'solution-zip', includes: "${OUTPUT_DIR}/${SOLUTION_NAME}.${SOLUTION_VERSION}.zip"
archiveArtifacts artifacts: "${OUTPUT_DIR}/*.zip", fingerprint: true
}
}
stage('Deploy') {
agent { label 'linux' }
steps {
unstash 'solution-zip'
withCredentials([
string(credentialsId: 'UIPATH_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'),
string(credentialsId: 'UIPATH_CLIENT_SECRET', variable: 'UIPATH_CLIENT_SECRET'),
string(credentialsId: 'UIPATH_TENANT', variable: 'UIPATH_TENANT')
]) {
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 \
@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"
uip solution publish "${OUTPUT_DIR}/${SOLUTION_NAME}.${SOLUTION_VERSION}.zip"
uip solution deploy run \
--name "${SOLUTION_NAME}-${BUILD_NUMBER}" \
--package-name "$SOLUTION_NAME" \
--package-version "$SOLUTION_VERSION" \
--folder-name MySolution \
--folder-path Shared
'''
}
}
}
stage('Test') {
when {
expression { return env.TEST_SET_KEY?.trim() }
}
agent { label 'linux' }
steps {
withCredentials([
string(credentialsId: 'UIPATH_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'),
string(credentialsId: 'UIPATH_CLIENT_SECRET', variable: 'UIPATH_CLIENT_SECRET'),
string(credentialsId: 'UIPATH_TENANT', variable: 'UIPATH_TENANT'),
string(credentialsId: 'TEST_SET_KEY', variable: 'TEST_SET_KEY'),
string(credentialsId: 'PROJECT_KEY', variable: 'PROJECT_KEY')
]) {
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 @uipath/test-manager-tool
fi
uip login \
--client-id env.UIPATH_CLIENT_ID \
--client-secret env.UIPATH_CLIENT_SECRET \
--tenant "$UIPATH_TENANT"
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 "test run did not finish within 30 minutes" >&2; exit 2 ;;
*) echo "wait failed (exit $code)" >&2; 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 "$FAILED test case(s) failed" >&2
exit 1
fi
'''
}
}
}
}
post {
always {
// Best-effort cleanup; uip logout only matters on a persistent agent.
node('linux') {
sh '''
if command -v uip >/dev/null; then
uip logout || true
fi
'''
}
}
}
}
Walkthrough
Top-level setup
agent noneat the top declares that the pipeline has no default agent; each stage picks its own withagent { label 'linux' }. This lets you put the build on a high-capacity agent and the deploy on a locked-down agent if your infrastructure separates them that way.options—timestamps()adds[2026-04-24T10:30:12]prefixes to every console line, which makes debugging long runs much easier.disableConcurrentBuilds()prevents two deploys from racing into the same Orchestrator folder.environmentblock — the same pattern as the other recipes: pinCLI_VERSION, computeSOLUTION_VERSIONfromBUILD_NUMBER, and route npm's global prefix into the workspace so installs are per-build and need nosudo.
Build stage
checkout scm— Jenkins needs this explicitly in a declarative pipeline.- Install step — same
if ! command -v uipguard as other platforms. The workspace-local npm prefix ($NPM_PREFIX) means every build starts clean; no caching across runs. If your Jenkins agents are persistent and you want to cache the CLI, either use the Job Cacher plugin or setNPM_PREFIXto a path on the agent rather than${env.WORKSPACE}. - Pack step — straight
uip solution packwith an explicit version. stash name: 'solution-zip'— this is the Jenkins-specific piece. Unlike GitHub Actions artifacts or Azure Pipelinespublish, astashis scoped to the pipeline run and survives across stages without needing the workspace to persist. Every stage that needs the.zipcallsunstash 'solution-zip'at its start. See the Jenkins docs onstash/unstash.archiveArtifacts— a copy of the.zipalso appears on the build page for humans to download.fingerprint: truelets Jenkins track it across jobs.
Deploy stage
unstash 'solution-zip'restores the.zipto the workspace. Combined with a fresh agent, this cleanly separates "build context" from "deploy context".withCredentialsbinds three credential entries to environment variables visible to theshblock. The closure is the credentials-safe boundary — values are masked in the console log and not leaked to any step outside this block. Use this for everyuipcall that talks to Orchestrator.uip loginusesenv.UIPATH_CLIENT_ID/env.UIPATH_CLIENT_SECRET— theenv.VAR_NAMEprefix reads the variable set bywithCredentials. See Authentication — the env.VAR_NAME prefix. Never interpolate the secret into the command line directly (--client-secret "$UIPATH_CLIENT_SECRET") — that embeds it into the rendered shell command and, under some logging configurations, into the console output.- Publish + deploy —
uip solution publishthenuip solution deploy run.--name "${SOLUTION_NAME}-${BUILD_NUMBER}"makes each deployment traceable back to its Jenkins build.
Test stage
Gated by when { expression { return env.TEST_SET_KEY?.trim() } } — if you do not set the TEST_SET_KEY credential (or leave it empty), the stage is skipped. The shell block is the canonical launch → wait → verify pattern from How-to: run tests from the CLI:
uip tm testset executelaunches and returns anExecutionId.uip tm waitblocks until the execution reaches a terminal state. Onwait, exit code2means timeout (not authentication failure — it is a domain-specific reuse of the code).uip tm report getreadsData.Failedand the shell exits1when any test failed.
post { always }
Best-effort uip logout. On ephemeral agents this is unnecessary; on a persistent agent it clears the workspace-local .uipath/ folder so a later job on the same workspace does not reuse a stale session. The || true swallows the error if uip was never installed (the build failed before installation).
Common variations
Agent variations
- Windows agent — replace
shwithbat, translate the bash scripts tocmd.exeor PowerShell. Theenv.prefix and everyuipcommand are identical; only the surrounding shell changes. See Installing UiPath CLI — Windows. - Docker agent —
agent { docker { image 'node:20' } }gives you a fresh Node runtime per build with zero agent config. Addargs '-u root'if you need sudo-free global npm installs in a rootful image; otherwise configure the NPM prefix to$WORKSPACE/.npm-globalas above and skip the privilege dance. - Kubernetes plugin — use a pod template with a
node:20container and mount/root/.npm-globalas a PVC to cache the CLI between builds.
Pin tool versions too
For patch-level reproducibility:
sh 'uip tools install @uipath/solution-tool@1.0.2 @uipath/orchestrator-tool@1.0.2 @uipath/test-manager-tool@1.0.2'
sh 'uip tools install @uipath/solution-tool@1.0.2 @uipath/orchestrator-tool@1.0.2 @uipath/test-manager-tool@1.0.2'
Promote across environments
Turn each environment into its own stage, reusing the same stash:
stage('Deploy stage') {
agent { label 'linux' }
steps {
unstash 'solution-zip'
withCredentials([string(credentialsId: 'UIPATH_STAGE_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'), ...]) {
sh '...deploy to stage tenant...'
}
}
}
stage('Approval') {
steps {
input message: 'Deploy to production?', ok: 'Deploy'
}
}
stage('Deploy prod') {
agent { label 'linux' }
steps {
unstash 'solution-zip'
withCredentials([string(credentialsId: 'UIPATH_PROD_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'), ...]) {
sh '...deploy to prod tenant...'
}
}
}
stage('Deploy stage') {
agent { label 'linux' }
steps {
unstash 'solution-zip'
withCredentials([string(credentialsId: 'UIPATH_STAGE_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'), ...]) {
sh '...deploy to stage tenant...'
}
}
}
stage('Approval') {
steps {
input message: 'Deploy to production?', ok: 'Deploy'
}
}
stage('Deploy prod') {
agent { label 'linux' }
steps {
unstash 'solution-zip'
withCredentials([string(credentialsId: 'UIPATH_PROD_CLIENT_ID', variable: 'UIPATH_CLIENT_ID'), ...]) {
sh '...deploy to prod tenant...'
}
}
}
The input step pauses the pipeline until a human clicks Deploy. Use Jenkins' Matrix Authorization Strategy to restrict who can approve. Deeper coverage in How-to: pack and publish a Solution — promote one package across tenants.
Reversión
Add a parameterized job — Jenkins → New Item → Pipeline → This project is parameterized → Add Parameter (String) → "ROLLBACK_VERSION" — and add a guarded stage:
stage('Rollback') {
when { expression { return params.ROLLBACK_VERSION?.trim() } }
agent { label 'linux' }
steps {
withCredentials([/* UIPATH_* credentials */]) {
sh '''#!/usr/bin/env bash
set -euo pipefail
# …install + login…
uip solution deploy run \
--name "${SOLUTION_NAME}-rollback" \
--package-name "$SOLUTION_NAME" \
--package-version "$ROLLBACK_VERSION" \
--folder-name MySolution \
--folder-path Shared
'''
}
}
environment {
ROLLBACK_VERSION = "${params.ROLLBACK_VERSION}"
}
}
stage('Rollback') {
when { expression { return params.ROLLBACK_VERSION?.trim() } }
agent { label 'linux' }
steps {
withCredentials([/* UIPATH_* credentials */]) {
sh '''#!/usr/bin/env bash
set -euo pipefail
# …install + login…
uip solution deploy run \
--name "${SOLUTION_NAME}-rollback" \
--package-name "$SOLUTION_NAME" \
--package-version "$ROLLBACK_VERSION" \
--folder-name MySolution \
--folder-path Shared
'''
}
}
environment {
ROLLBACK_VERSION = "${params.ROLLBACK_VERSION}"
}
}
Trigger from the build page with Build with Parameters. For destructive rollback (uninstall + delete artifact), see How-to: pack and publish a Solution — rollback.
Common pitfalls
withCredentialsscoping. Credentials are only available inside the closure. If you calluip logininsidewithCredentialsanduip solution publishoutside, the second command has no session. Keep the whole CLI block inside onewithCredentials.stashbefore changing agents. Astashdeclared in one stage is usable in later stages only if the stash step ran to completion before the agent switched. If theBuildstage's shell block exits non-zero beforestash, later stages will fail atunstash. Puttingstashoutside theshblock — as in this recipe — ensures it runs on a clean agent regardless of shell outcome.|| trueat the wrong time. Theuip logout || trueinpostis safe because the only failure mode is "uip was never installed". Do not pepper|| truethrough earlier stages — it hides real failures.shstrict mode. Start everyshblock's bash script with#!/usr/bin/env bashandset -euo pipefail. The default Jenkins shell is/bin/sh, which does not supportpipefail. See Scripting patterns — strict shell options.- Multiline strings in Groovy. Prefer triple-single-quoted strings (
'''...''') for shell bodies — they do not interpolate$VAR, so the variable is expanded by bash rather than by Groovy. This avoids a common class of "variable is empty" bugs. For values you want Groovy to fill in at pipeline-compile time, use${env.SOME_VAR}explicitly.
Ver también
- How-to: deploy to Orchestrator from CI — platform-agnostic guidance.
- How-to: pack and publish a Solution — versioning and rollback.
- How-to: run tests from the CLI — the launch → wait → verify pattern.
- CI/CD recipe: Azure Pipelines, GitHub Actions, GitLab CI — the same pipeline in other platforms.