> For the complete documentation index, see [llms.txt](https://docs.sealights.io/knowledgebase/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sealights.io/knowledgebase/setup-and-configuration/integrations/qtest-integration/ci-cd-integration.md).

# CI/CD Integration

Running `npm run report` on a scheduled basis is the recommended way to keep SeaLights up to date. Use environment variables instead of `config.json` to configure the tool in CI/CD pipelines — this avoids storing credentials in your repository.

## Environment Variables

Set these variables in your CI/CD secrets store:

| Variable         | Description                                 |
| ---------------- | ------------------------------------------- |
| `SL_TOKEN`       | SeaLights agent token                       |
| `SL_QTEST_TOKEN` | qTest bearer token                          |
| `SL_QTEST_URL`   | Your qTest instance URL                     |
| `SL_PROJECT`     | Default project name                        |
| `SL_DAYS`        | Days to look back (e.g. `1` for daily runs) |
| `HTTPS_PROXY`    | Corporate proxy URL (if required)           |

A `config.json` with `testDesignMapping` and `userLabMapping` is still required on the runner. Store it as a CI/CD secret file or generate it during pipeline setup.

***

## GitHub Actions

{% code overflow="wrap" lineNumbers="true" %}

```yaml
name: SeaLights qTest Daily Report

on:
  schedule:
    - cron: '0 6 * * *'   # Daily at 6:00 AM UTC
  workflow_dispatch:        # Allow manual trigger

jobs:
  report:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Write config file
        run: echo '${{ secrets.QTEST_CONFIG_JSON }}' > config.json

      - name: Run report
        run: npm run report
        env:
          SL_TOKEN: ${{ secrets.SEALIGHTS_TOKEN }}
          SL_QTEST_TOKEN: ${{ secrets.QTEST_TOKEN }}
          SL_QTEST_URL: ${{ vars.QTEST_URL }}
          SL_PROJECT: ${{ vars.PROJECT_NAME }}
          SL_DAYS: 1
```

{% endcode %}

{% hint style="info" %}
Store `config.json` (containing `testDesignMapping` and `userLabMapping`) as a GitHub Actions secret (`QTEST_CONFIG_JSON`) and write it to disk at runtime. This keeps mapping configuration out of your source code while keeping credentials secure.
{% endhint %}

***

## GitLab CI

{% code overflow="wrap" lineNumbers="true" %}

```yaml
qtest-report:
  image: node:20
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  script:
    - npm ci
    - echo "$QTEST_CONFIG_JSON" > config.json
    - npm run report
  variables:
    SL_TOKEN: $SEALIGHTS_TOKEN
    SL_QTEST_TOKEN: $QTEST_TOKEN
    SL_QTEST_URL: $QTEST_URL
    SL_PROJECT: $PROJECT_NAME
    SL_DAYS: "1"
```

{% endcode %}

Schedule this job from **CI/CD → Schedules** in the GitLab project settings.

***

## Jenkins

{% code overflow="wrap" lineNumbers="true" %}

```groovy
pipeline {
  agent any
  triggers {
    cron('H 6 * * *')    // Daily at approximately 6:00 AM
  }
  environment {
    SL_TOKEN      = credentials('sealights-token')
    SL_QTEST_TOKEN = credentials('qtest-token')
    SL_QTEST_URL  = 'https://your-company.qtestnet.com'
    SL_PROJECT    = 'MyProject'
    SL_DAYS       = '1'
  }
  stages {
    stage('Install') {
      steps {
        sh 'npm ci'
      }
    }
    stage('Write Config') {
      steps {
        withCredentials([file(credentialsId: 'qtest-config-json', variable: 'CONFIG_FILE')]) {
          sh 'cp $CONFIG_FILE config.json'
        }
      }
    }
    stage('Report') {
      steps {
        sh 'npm run report'
      }
    }
  }
}
```

{% endcode %}

Store credentials in Jenkins Credentials Manager. Use a `Secret file` credential for the full `config.json`.

***

## Behind a Corporate Proxy

Add the proxy environment variable to your pipeline environment:

```yaml
# GitHub Actions
env:
  HTTPS_PROXY: ${{ vars.CORPORATE_PROXY_URL }}

# GitLab CI
variables:
  HTTPS_PROXY: $CORPORATE_PROXY_URL

# Jenkins
environment {
  HTTPS_PROXY = 'http://proxy.company.com:8080'
}
```

***

## Scheduling Recommendations

Unlike reporting (which runs automatically on a schedule), the recommendations command is interactive by design — it requires human decisions at each step. It is best run manually before a planned test execution cycle.

If you want to automate recommendations (for fully automated test suites), contact SeaLights support to discuss non-interactive options for your use case.

***

## Tips

{% hint style="success" %}
For daily incremental reporting, set `SL_DAYS=1`. For weekly runs, use `SL_DAYS=7`.
{% endhint %}

{% hint style="info" %}
Add `SL_DEBUG=true` to your CI environment to get verbose logs when troubleshooting a failed report run.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sealights.io/knowledgebase/setup-and-configuration/integrations/qtest-integration/ci-cd-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
