# Set up CI

CI has two jobs: prove a proposed ontology still works, and—only when the GitHub App is not the publisher—upload the merged tree from the default branch.

Store `CASSIS_API_KEY` as a CI secret and `CASSIS_PROJECT_ID` as a repository variable. Install a pinned CLI version in each job.

## Choose the right workflow

| Repository setup | Pull or merge request | Default branch |
| --- | --- | --- |
| GitHub App connected | Cassis validates; your CI runs `cassis eval run` | The App imports and publishes |
| Any provider without the App | Your CI runs `cassis verify` | Your CI runs `cassis ontology upload` |

Use one publisher. If the GitHub App is connected, do not add an upload job for the same project.

## GitHub Actions

### With the GitHub App

The App validates pull requests and publishes merges. Add only the eval suite:

```yaml title=".github/workflows/ontology-eval.yml"
name: Cassis ontology eval

on:
  pull_request:
    paths: ["cassis/**"]

permissions:
  contents: read

jobs:
  ontology-eval:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: python -m pip install "cassis-cli==1.6.0"
      - run: cassis eval run
        env:
          CASSIS_API_KEY: ${{ secrets.CASSIS_API_KEY }}
          CASSIS_PROJECT_ID: ${{ vars.CASSIS_PROJECT_ID }}
```

Require both the Cassis validation check and this eval job before merge.

### Without the GitHub App

This workflow validates pull requests and publishes after a merge to `main`:

```yaml title=".github/workflows/ontology.yml"
name: Cassis ontology

on:
  pull_request:
    paths: ["cassis/**"]
  push:
    branches: [main]
    paths: ["cassis/**"]

permissions:
  contents: read

jobs:
  ontology-check:
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: python -m pip install "cassis-cli==1.6.0"
      - run: cassis verify
        env:
          CASSIS_API_KEY: ${{ secrets.CASSIS_API_KEY }}
          CASSIS_PROJECT_ID: ${{ vars.CASSIS_PROJECT_ID }}

  ontology-publish:
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: python -m pip install "cassis-cli==1.6.0"
      - run: cassis ontology upload
        env:
          CASSIS_API_KEY: ${{ secrets.CASSIS_API_KEY }}
          CASSIS_PROJECT_ID: ${{ vars.CASSIS_PROJECT_ID }}
```

Change `main` if your default branch has another name.

## GitLab CI

The same two stages work on GitLab:

```yaml title=".gitlab-ci.yml"
ontology-check:
  image: python:3.12-slim
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - python -m pip install "cassis-cli==1.6.0"
    - cassis verify
  variables:
    CASSIS_API_KEY: $CASSIS_API_KEY
    CASSIS_PROJECT_ID: $CASSIS_PROJECT_ID

ontology-publish:
  image: python:3.12-slim
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  script:
    - python -m pip install "cassis-cli==1.6.0"
    - cassis ontology upload
  variables:
    CASSIS_API_KEY: $CASSIS_API_KEY
    CASSIS_PROJECT_ID: $CASSIS_PROJECT_ID
```

Protect the default branch and require the validation job before merge. If a job fails, the CLI output distinguishes an ontology failure from missing credentials or an unreachable API; see [Troubleshoot git and publishing](/build/troubleshooting/).

A publish that fails on the server now fails the publish job and prints the server’s reason. This needs cassis-cli 1.6.0 or later. On an older version, a failure that happened after the upload started processing could leave the job green even though nothing was published.
