Skip to content

CI/CD: GitHub Actions

Run your test suite in GitHub Actions and upload the results to Sulu with suluctl — no test-framework plugins needed.

This is the same workflow the in-app Set up reporting dialog (Jobs page) generates, prefilled with your backend URL and project id.

Minimal example

yaml
# .github/workflows/tests.yml
name: tests
on: [push]

jobs:
  test:
    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 to Sulu
      - if: always()
        run: suluctl upload --results ./allure-results
        env:
          SULU_URL: "<your Sulu base URL>"
          SULU_TOKEN: ${{ secrets.SULU_TOKEN }}
          SULU_PROJECT_ID: "<your project id>"
          SULU_LAUNCH_NAME: "CI · ${{ github.ref_name }}"

The if: always() conditions make sure failed test runs are reported too — usually the runs you care about most.

Token storage

Add an API token (Profile → API keys in Sulu) as a repository secret named SULU_TOKEN. Reference it in the workflow as ${{ secrets.SULU_TOKEN }} — never paste the token into the YAML.

Linking the launch back to the run

Include an executor.json file in your results directory; Sulu reads it during import and renders its buildUrl as the launch's external-run link:

yaml
      - name: Write executor.json
        if: always()
        run: |
          cat > allure-results/executor.json <<EOF
          {
            "name": "GitHub Actions",
            "type": "github",
            "buildName": "${{ github.workflow }} #${{ github.run_number }}",
            "buildUrl": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
          }
          EOF

Runs dispatched from a Sulu Job get the CI run link automatically — no executor.json needed.

Per-branch launch names

SULU_LAUNCH_NAME is free text — compose it from GitHub's context, e.g. "CI · ${{ github.ref_name }}" for one launch name per branch, or use the PR title from the event payload.

Streaming results live

Swap the separate test + upload steps for suluctl watch to see results appear in Sulu while the suite is still running:

yaml
      - run: suluctl watch --results ./allure-results -- <your test command>
        env:
          SULU_URL: "<your Sulu base URL>"
          SULU_TOKEN: ${{ secrets.SULU_TOKEN }}
          SULU_PROJECT_ID: "<your project id>"

watch always exits with your test command's exit code, so it's safe as the main test step. See Live streaming for what it does.

Sulu Test Management System