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 uploaded by
suluctl(or any import-API client) 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.
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 job dialog 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
# 1. Run your tests, producing allure-results/ (or JUnit XML)
- run: <your test command> # e.g. ./gradlew test, pytest --alluredir=allure-results
# 2. Install suluctl
- if: always()
run: curl -fsSL https://raw.githubusercontent.com/ellyZz/suluctl/main/install.sh | sh
# 3. Upload results — SULU_LAUNCH_UUID routes them into the pre-created Launch
- if: always()
run: suluctl upload --results ./allure-results
env:
SULU_URL: ${{ inputs.SULU_API_URL }}
SULU_TOKEN: ${{ secrets.SULU_TOKEN }}
SULU_PROJECT_ID: "<your project id>"
SULU_LAUNCH_UUID: ${{ inputs.SULU_LAUNCH_UUID }}4. 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 |
How results reach the pre-created Launch
Sulu forwards the pre-created launch's id to your workflow as the SULU_LAUNCH_UUID input. suluctl (both upload and watch) auto-detects SULU_LAUNCH_UUID from the environment and uploads into that launch instead of creating a new one — no extra flags needed. The upload must target the same project as the Job; the launch keeps the Job's name. See the suluctl page for details.
For runs not triggered from Sulu (plain pushes/PRs), the same upload step simply creates a fresh launch — see GitHub Actions and GitLab CI for the standalone setup.
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 the validator snippet in the job dialog |
Upload fails with 403 mentioning another project | The Job targets a different project than SULU_PROJECT_ID — they must match |
| Two Launches per run (one empty + one real) | The upload step didn't receive SULU_LAUNCH_UUID (input not passed into the step's env), so results went to a fresh launch |