Guides

Run Portman in GitHub Actions

Run Portman contract tests in a GitHub Actions workflow with npx, a CLI options file, secrets as PORTMAN_ variables and Newman.

You can run Portman in GitHub Actions like any other Node.js CLI: check out the repository, set up Node, and run npx @apideck/portman with your spec, config and the --runNewman flag. Portman then converts the spec, injects the tests and runs them against the API URL you pass with --baseUrl.

Repository layout

bash
openapi.yamlportman-config.jsonportman-cli-options.json

Keep the CLI options in a file so local runs and CI use the same settings (see CLI options file):

json
{  "local": "./openapi.yaml",  "output": "./tmp/converted/collection.postman.json",  "portmanConfigFile": "./portman-config.json",  "includeTests": true,  "runNewman": true}

Workflow

.github/workflows/contract-tests.yml:

yaml
name: Contract tests on:  pull_request:  push:    branches: [main] jobs:  portman:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4       - uses: actions/setup-node@v4        with:          node-version: 20       - name: Run Portman contract tests        env:          PORTMAN_BEARER_TOKEN: ${{ secrets.API_TOKEN }}        run: npx @apideck/portman --cliOptionsFile ./portman-cli-options.json --baseUrl ${{ vars.API_BASE_URL }}       - name: Upload collection        if: always()        uses: actions/upload-artifact@v4        with:          name: postman-collection          path: tmp/converted/

What it does:

  • --cliOptionsFile loads the settings from the file. Flags passed on the command line, here --baseUrl, override the values in the file.
  • PORTMAN_BEARER_TOKEN is available in the collection as {{bearerToken}}, because Portman exposes every PORTMAN_ environment variable as a camel-cased Postman variable. See Environment variables.
  • The generated collection is uploaded as a build artifact, so you can import it into Postman when a test fails.

To use the token, reference it in your Portman config, for example on collection level:

json
{  "version": 1.0,  "globals": {    "securityOverwrites": {      "bearer": {        "token": "{{bearerToken}}"      }    }  }}

When any assertion fails, Portman exits with code 1, so the step fails and the job goes red. That makes the workflow safe to use as a required status check (merge gate).

Pin the Portman version

npx @apideck/portman downloads the latest version. To get reproducible runs, add Portman as a dev dependency (see Installation) and run npm ci before the Portman step, or pin a version in the command, for example npx @apideck/portman@<version>.

Sync to Postman from CI

To also upload the collection to Postman on main, add the Postman API key as a secret and pass --syncPostman:

yaml
      - name: Sync collection to Postman        if: github.ref == 'refs/heads/main'        env:          POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}        run: npx @apideck/portman -l ./openapi.yaml -c ./portman-config.json --syncPostman --postmanUid ${{ vars.POSTMAN_COLLECTION_UID }}

See Postman sync.

Running against a service in the workflow

If the API runs inside the job (for example started in a previous step or as a service container), point --baseUrl at it, such as http://localhost:3050.