> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formae.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 12 - CI Setup

> Enable the plugin template's GitHub Actions workflow so build, lint, integration, and conformance tests run on every push and pull request.

With conformance tests passing locally, it's time to set up continuous integration. The plugin template includes a GitHub Actions workflow that runs on every push and pull request.

## What's included

The template provides `.github/workflows/ci.yml` with these jobs:

| Job                 | Runs on             | Description                                        |
| ------------------- | ------------------- | -------------------------------------------------- |
| `build`             | Every push/PR       | Builds plugin and runs unit tests                  |
| `lint`              | Every push/PR       | Runs golangci-lint                                 |
| `pkl-validate`      | Every push/PR       | Validates the plugin manifest                      |
| `integration-tests` | Disabled by default | Runs integration tests against real infrastructure |
| `conformance-tests` | Disabled by default | Runs conformance tests against the formae agent    |

The integration and conformance test jobs are disabled by default. You need to configure them for your infrastructure.

## Initialize your repository

If you haven't already, initialize a git repository and push to GitHub:

```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
cd formae-plugin-sftp
git init
git add .
git commit -m "feat: initial SFTP plugin"
```

Create a repository on GitHub, then push:

```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
git remote add origin git@github.com:your-org/formae-plugin-sftp.git
git branch -M main
git push -u origin main
```

## Verify basic CI

After pushing, check the Actions tab in your GitHub repository. You should see the workflow running with `build`, `lint`, and `pkl-validate` jobs.

These jobs should pass immediately.

## Enable integration tests

For our SFTP plugin, we start a Docker container directly in the workflow:

```yaml theme={"languages":{"custom":["/languages/pkl.json"]}}
integration-tests:
  needs: [build, lint]
  runs-on: ubuntu-latest
  steps:
    - name: Checkout
      uses: actions/checkout@v6

    - name: Set up Go
      uses: actions/setup-go@v6
      with:
        go-version: "1.25"

    - name: Set up Pkl
      uses: pkl-community/setup-pkl@v0
      with:
        pkl-version: 0.30.0

    - name: Start SFTP server
      run: |
        docker run -d --name sftp-test -p 2222:22 atmoz/sftp testuser:testpass:::upload
        sleep 2  # Wait for server to start

    - name: Run integration tests
      env:
        SFTP_USERNAME: testuser
        SFTP_PASSWORD: testpass
      run: make test-integration
```

Key changes from the template:

1. Remove `if: false` to enable the job
2. Add a step to start your test infrastructure (Docker container)
3. Set environment variables for credentials

## Enable conformance tests

The conformance tests follow the same pattern. Remove the `if` condition that disables the job:

```yaml theme={"languages":{"custom":["/languages/pkl.json"]}}
conformance-tests:
  needs: [build, lint, pkl-validate, integration-tests]
  runs-on: ubuntu-latest
  timeout-minutes: 60
  steps:
    - name: Checkout
      uses: actions/checkout@v6

    - name: Set up Go
      uses: actions/setup-go@v6
      with:
        go-version: "1.25"

    - name: Set up Pkl
      uses: pkl-community/setup-pkl@v0
      with:
        pkl-version: 0.30.0

    - name: Start SFTP server
      run: |
        docker run -d --name sftp-test -p 2222:22 atmoz/sftp testuser:testpass:::upload
        sleep 2

    - name: Install plugin
      run: make install

    - name: Run conformance tests
      env:
        SFTP_USERNAME: testuser
        SFTP_PASSWORD: testpass
        FORMAE_TEST_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }}
      run: make conformance-test
```

Note that conformance tests depend on integration tests passing first (`needs: [build, lint, pkl-validate, integration-tests]`).

## Verify

After updating the workflow, push your changes:

```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
git add .github/workflows/ci.yml
git commit -m "ci: enable integration and conformance tests"
git push
```

Check the Actions tab. All jobs should pass:

```text theme={"languages":{"custom":["/languages/pkl.json"]}}
build             ✓ 45s
lint              ✓ 30s
pkl-validate      ✓ 10s
integration-tests ✓ 1m 15s
conformance-tests ✓ 2m 30s
```

***

Next: [13 - Local Testing](/plugin-development/tutorial/13-local-testing) - Test your plugin locally with formae
