Appearance
CI integration
Trigger your test workflows from Sulu and have the results land in the same Launch you created — no manual wiring on the test framework side.
What you get
- Launch a configured GitHub Actions or GitLab CI workflow from inside Sulu.
- Test results pushed by the Sulu SDK land in the same Sulu Launch that Sulu pre-created (no duplicate launches).
- See live status from the Sulu Launches page; click through to the GH / GL run UI for full logs.
Required versions
- Sulu: v1.9.0 or later
- sulu-java-common SDK:
0.2.0or later
This is the SDK version that reads SULU_LAUNCH_UUID from the env and binds your test run to the pre-created Sulu Launch. Without it, results go to a fresh launch and you'll see two launches per CI run.
Set up
1. Create a Personal Access Token
GitHub — Settings → Developer settings → Personal access tokens.
- Classic: scopes
workflow(+repoif private) - Fine-grained: Actions: Read+Write, Contents: Read
GitLab — User Settings → Access Tokens.
- Scopes:
api,read_repository
2. Add a CI connection in Sulu
Project Settings → Integrations → CI Connections → + New connection.
Paste the PAT and click Test connection before saving. Sulu queries /user to validate scopes; you'll see your username on success.
3. Prepare your workflow
Your workflow file must accept workflow_dispatch with Sulu's reserved inputs. Sulu's JobDialog has a built-in validator that fetches your YAML and tells you exactly what's missing, with a copy-paste snippet.
Minimum block:
yaml
on:
workflow_dispatch:
inputs:
SULU_LAUNCH_ID: { required: false, type: string }
SULU_LAUNCH_UUID: { required: false, type: string }
SULU_JOB_RUN_ID: { required: false, type: string }
SULU_API_URL: { required: false, type: string }
SULU_ENV_NAME: { required: false, type: string }
SULU_TEST_FILTER: { required: false, type: string }
# Recommended: surface SULU_JOB_RUN_ID in the run name so Sulu can match runs accurately
run-name: 'tests / SULU_JOB_RUN_ID=${{ inputs.SULU_JOB_RUN_ID }}'
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: 21 }
- name: Run tests
env:
# Pass the inputs into the SDK's env
SULU_LAUNCH_ID: ${{ inputs.SULU_LAUNCH_ID }}
SULU_LAUNCH_UUID: ${{ inputs.SULU_LAUNCH_UUID }}
run: ./gradlew test4. Create a job in Sulu
Jobs page → + New job. Pick your CI connection, fill repo (e.g. owner/repo), pick the workflow from the dropdown, set git ref.
5. Run
Jobs page → click the Play button. Sulu pre-creates a Launch, dispatches your workflow, and you'll see results stream in as your tests run.
You can also run a subset of test cases from the Test Cases page: select cases → Run → Auto mode → pick the job.
Token scopes — full table
| Provider | Token type | Required scopes |
|---|---|---|
| GitHub | Classic PAT | workflow + repo (if private) |
| GitHub | Fine-grained PAT | Actions: Read+Write, Contents: Read |
| GitLab | Personal Access Token | api, read_repository |
From your test framework
The Sulu SDK reads SULU_LAUNCH_UUID from the env and uses it as the clientUuid for the launch — Sulu's V2 ingest is idempotent on clientUuid, so test results land in the pre-created Launch instead of a fresh one.
Minimum sulu.properties in your test repo:
properties
sulu.url=https://your-sulu.example
sulu.token=sulu_*** # USER-scoped API token
sulu.project.id=42
sulu.launch.name=Smoke # Used only when not triggered from Sulu
sulu.async=true # Recommended (V2 path)You do not need to set sulu.launch.uuid in sulu.properties — the SDK auto-detects SULU_LAUNCH_UUID from the env when triggered from Sulu, and falls back to a randomly-generated UUID for local runs.
Uploading reports with suluctl
If you stream reports with suluctl (the import path) instead of an SDK, it works the same way: suluctl (upload and watch) auto-detects SULU_LAUNCH_UUID and sends it as the import clientUuid, so a Job-triggered run lands in the pre-created Launch. No flags needed. The Job must target the same project as SULU_PROJECT_ID, and the launch keeps the Job's name. See the suluctl page for details.
Troubleshooting
| Symptom | Likely cause |
|---|---|
Test connection returns 401 Bad credentials | PAT expired or wrong token type |
Test connection returns 200 but Run returns 404 | Repository path wrong (e.g. typo in owner/repo) |
Test connection passes, workflow picker loads, but Run fails with 403 Resource not accessible by personal access token | PAT has read scopes but lacks workflow (classic) / Actions: Read and write (fine-grained). Reading workflows only needs repo / Actions:Read; dispatching needs the write scope. Regenerate the token with the right scope and re-paste it. |
Run returns 422 Validation failed | Workflow missing workflow_dispatch: — fix per validator snippet in JobDialog |
| Run starts but results don't appear in Sulu Launch | SDK version too old (doesn't read SULU_LAUNCH_UUID) — bump sulu-java-common to ≥ 0.2.0 |
| Two Launches per run (one zombie + one real) | Same as above — SDK didn't pick up SULU_LAUNCH_UUID; results went to a fresh launch |