Skip to content

suluctl CLI

suluctl is Sulu's open-source (Apache-2.0), zero-dependency CLI that streams test reports into the import API. Single static binary — nothing to add to your test project.

Install

bash
curl -fsSL https://raw.githubusercontent.com/ellyZz/suluctl/main/install.sh | sh

Or grab a binary from GitHub Releases, or use the container image ghcr.io/ellyzz/suluctl in CI.

Configure

Env varRequiredMeaning
SULU_URLyesYour Sulu base URL
SULU_TOKENyesAPI token (Profile → API keys)
SULU_PROJECT_IDyesNumeric destination project id
SULU_LAUNCH_NAMEnoLaunch display name
SULU_LAUNCH_UUIDnoUpload into an existing launch (set automatically by Sulu Jobs — see below)

Flags override env: --url --token --project --launch-name --launch-uuid --env --tag --env-var --insecure.

One-shot upload

bash
suluctl upload --results ./allure-results
# or a JUnit XML directory:
suluctl upload --results ./build/test-results/test

Creates a launch, uploads everything in batches, finishes the launch, and prints a per-file summary plus the launch link. Exit code is non-zero only on total failure (config or auth errors, plan limits, exhausted retries, unreachable server) — individual bad files are reported per-file and don't fail your build.

Live streaming (watch mode)

bash
suluctl watch --results ./allure-results -- pytest --alluredir=allure-results

Runs your test command, streams result files into Sulu as they appear (results show up in the launch while tests are still running), and always exits with your test command's exit code — safe to wrap in any CI step. If Sulu is unreachable, watch degrades to a transparent wrapper: your tests still run and the exit code still passes through.

Triggered from a Sulu Job

When a run is dispatched by a Sulu Job (/app/jobs), Sulu pre-creates the launch and forwards its id to your workflow as the SULU_LAUNCH_UUID environment variable. suluctl reads it automatically and uploads into that pre-created launch instead of creating a new one — no extra flags or configuration needed (it works for both upload and watch).

A few things to know:

  • The Job must target the same project as SULU_PROJECT_ID. If they differ, Sulu rejects the upload with a 403 ("clientUuid belongs to a launch in another project").
  • The launch keeps the name from the Job, so --launch-name / SULU_LAUNCH_NAME has no effect on a Job-triggered run.
  • For the cleanest results, dispatch the Job without a specific test-case or test-plan selection so the launch is populated entirely from your uploaded report.

Sulu Test Management System