zuplo 7.13.3 → 7.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/articles/api-lint-breaking-changes.mdx +211 -0
- package/docs/articles/api-lint-ci-cd.mdx +242 -0
- package/docs/articles/api-lint-configuration.mdx +459 -0
- package/docs/articles/api-lint-custom-rules.mdx +222 -0
- package/docs/articles/api-lint-rules.mdx +360 -0
- package/docs/articles/api-lint.mdx +267 -0
- package/docs/cli/lint.mdx +64 -0
- package/docs/cli/lint.partial.mdx +70 -0
- package/docs/dev-portal/zudoku/configuration/api-catalog.md +16 -0
- package/docs/dev-portal/zudoku/configuration/blog.md +217 -0
- package/package.json +5 -5
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Breaking Change Detection
|
|
3
|
+
sidebar_label: Breaking changes
|
|
4
|
+
description:
|
|
5
|
+
Use `zuplo lint` to compare your OpenAPI files to a Git branch and catch
|
|
6
|
+
removed endpoints, new required inputs, and changed types before they reach
|
|
7
|
+
consumers.
|
|
8
|
+
applies_to:
|
|
9
|
+
product: gateway
|
|
10
|
+
hosting: all
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Your OpenAPI files are the contract your API consumers build against. Remove an
|
|
14
|
+
endpoint, make a query parameter required, or change a field from a string to an
|
|
15
|
+
integer, and every client that relied on the old shape breaks — usually in
|
|
16
|
+
production, and usually after the change has shipped.
|
|
17
|
+
|
|
18
|
+
Breaking change detection catches these changes before you merge them.
|
|
19
|
+
`zuplo lint` compares each OpenAPI file in your project with the same file on a
|
|
20
|
+
Git branch, such as `main`, and reports every change that can break an existing
|
|
21
|
+
consumer:
|
|
22
|
+
|
|
23
|
+
```txt
|
|
24
|
+
Breaking Changes
|
|
25
|
+
|
|
26
|
+
config/routes.oas.json
|
|
27
|
+
0:0 error Removed "/todos/{id}" (was "/todos/{id}") breaking-change
|
|
28
|
+
15:25 error Modified "required" from "false" to "true" breaking-change
|
|
29
|
+
37:21 error Modified "type" from "string" to "integer" breaking-change
|
|
30
|
+
|
|
31
|
+
✖ 3 breaking changes remaining
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Turn on detection
|
|
35
|
+
|
|
36
|
+
Breaking change detection is off by default. Turn it on in `zuplo.lint.jsonc` in
|
|
37
|
+
the root of your project:
|
|
38
|
+
|
|
39
|
+
```jsonc title="zuplo.lint.jsonc"
|
|
40
|
+
{
|
|
41
|
+
"version": 2,
|
|
42
|
+
"breakingChanges": {
|
|
43
|
+
"enabled": true,
|
|
44
|
+
"baseline": "origin/main",
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then run the linter as usual:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git fetch origin main
|
|
53
|
+
npx zuplo lint
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Detection runs alongside the rest of the lint checks. It uses no extra flags, so
|
|
57
|
+
the same command works on your machine and in CI.
|
|
58
|
+
|
|
59
|
+
## Settings
|
|
60
|
+
|
|
61
|
+
| Field | Description |
|
|
62
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `enabled` | Turns detection on. Defaults to `false`. |
|
|
64
|
+
| `baseline` | The branch, tag, or commit SHA to compare against, such as `main`, `origin/main`, or `v1.2.0`. Defaults to `"main"`. |
|
|
65
|
+
| `severity` | `"error"` or `"warn"`. Defaults to `"error"`. Controls whether a breaking change fails the run — see [Block or warn](#block-or-warn). |
|
|
66
|
+
|
|
67
|
+
## Choose a baseline
|
|
68
|
+
|
|
69
|
+
The baseline is the version of your API that consumers use today. Compare
|
|
70
|
+
against whatever represents that version:
|
|
71
|
+
|
|
72
|
+
- **The branch you deploy production from**, usually `main`. Each pull request
|
|
73
|
+
then reports what it would break once merged. This is the most common setup.
|
|
74
|
+
- **A release tag**, such as `v1.2.0`. Every change since the last release is
|
|
75
|
+
checked, which is useful when several merges ship together.
|
|
76
|
+
|
|
77
|
+
Use `origin/main` rather than `main` when you lint in CI. CI systems usually
|
|
78
|
+
check out the pull request's commit without creating a local `main` branch, so
|
|
79
|
+
only the remote-tracking branch `origin/main` exists. `origin/main` also works
|
|
80
|
+
on your machine after `git fetch`, so one configuration serves both.
|
|
81
|
+
|
|
82
|
+
The `baseline` value must be a branch, tag, or commit SHA. Expressions such as
|
|
83
|
+
`HEAD~1` or `main^` aren't accepted.
|
|
84
|
+
|
|
85
|
+
## What counts as a breaking change
|
|
86
|
+
|
|
87
|
+
A change is breaking when a client written against the baseline can fail against
|
|
88
|
+
the new version. The linter reports these kinds of change, among others:
|
|
89
|
+
|
|
90
|
+
| Change | Example message |
|
|
91
|
+
| ----------------------------------------------------- | -------------------------------------------- |
|
|
92
|
+
| Removing a path or an operation | `Removed "/todos/{id}" (was "/todos/{id}")` |
|
|
93
|
+
| Adding a required parameter | `Added "parameters"` |
|
|
94
|
+
| Making an optional parameter required | `Modified "required" from "false" to "true"` |
|
|
95
|
+
| Making a request body property required | `Added property "required"` |
|
|
96
|
+
| Changing the type of a parameter, property, or schema | `Modified "type" from "string" to "integer"` |
|
|
97
|
+
| Removing a value from an enum | `Removed property "enum" (was "done")` |
|
|
98
|
+
| Removing a response status code | `Removed "codes" (was "201")` |
|
|
99
|
+
|
|
100
|
+
These changes are safe, so the linter doesn't report them:
|
|
101
|
+
|
|
102
|
+
- Adding a new path, operation, or response
|
|
103
|
+
- Adding an optional parameter or request body property
|
|
104
|
+
- Adding a property to a response
|
|
105
|
+
- Adding a value to an enum
|
|
106
|
+
- Changing descriptions, summaries, and examples
|
|
107
|
+
|
|
108
|
+
Detection compares the API contract — paths, operations, parameters, request
|
|
109
|
+
bodies, and responses. It doesn't compare the gateway configuration inside
|
|
110
|
+
`x-zuplo-route`, so removing a policy or changing a handler isn't reported as a
|
|
111
|
+
breaking change.
|
|
112
|
+
|
|
113
|
+
## Read the results
|
|
114
|
+
|
|
115
|
+
Breaking changes appear in their own **Breaking Changes** section, after the
|
|
116
|
+
other lint results, and are counted separately in the summary. Every result uses
|
|
117
|
+
the ID `breaking-change`.
|
|
118
|
+
|
|
119
|
+
Each result points at the change in your current file. A removal has nothing
|
|
120
|
+
left to point at, so its location is `0:0`; the message names what was removed.
|
|
121
|
+
|
|
122
|
+
In `--format json` output, breaking changes are in the `breakingChanges` array
|
|
123
|
+
and counted in `summary.breakingChanges`. In `--format sarif` output, they're
|
|
124
|
+
included with the other results.
|
|
125
|
+
|
|
126
|
+
New files have nothing to compare against, so a file that doesn't exist on the
|
|
127
|
+
baseline never reports breaking changes. Detection checks the same files as the
|
|
128
|
+
rest of the linter: every `.oas.json` file in `config/`, or the files listed in
|
|
129
|
+
[`include`](./api-lint-configuration.mdx#include).
|
|
130
|
+
[`ignorePaths`](./api-lint-configuration.mdx#ignorepaths) doesn't apply to
|
|
131
|
+
breaking changes.
|
|
132
|
+
|
|
133
|
+
## Block or warn
|
|
134
|
+
|
|
135
|
+
`severity` decides whether a breaking change fails the run:
|
|
136
|
+
|
|
137
|
+
| `severity` | `failOn: "error"` (default) | `failOn: "warn"` |
|
|
138
|
+
| ------------------- | --------------------------- | ---------------- |
|
|
139
|
+
| `"error"` (default) | Fails | Fails |
|
|
140
|
+
| `"warn"` | Passes, and reports | Fails |
|
|
141
|
+
|
|
142
|
+
Use `"error"` to block pull requests that break the contract. Use `"warn"` when
|
|
143
|
+
breaking changes are sometimes intentional — for example, while an API is still
|
|
144
|
+
in beta — and you want reviewers to see them without blocking the merge.
|
|
145
|
+
|
|
146
|
+
When you do mean to ship a breaking change, the usual approach is to version the
|
|
147
|
+
API instead: keep the old operation, add the new one under a new path such as
|
|
148
|
+
`/v2/todos`, and remove the old one later. See
|
|
149
|
+
[Versioning on Zuplo](./versioning-on-zuplo.mdx).
|
|
150
|
+
|
|
151
|
+
## Run in CI
|
|
152
|
+
|
|
153
|
+
Detection reads the baseline from your Git history, so the CI checkout has to
|
|
154
|
+
include it. With GitHub Actions, set `fetch-depth: 0` on `actions/checkout`:
|
|
155
|
+
|
|
156
|
+
```yaml title=".github/workflows/lint.yaml"
|
|
157
|
+
steps:
|
|
158
|
+
- uses: actions/checkout@v4
|
|
159
|
+
with:
|
|
160
|
+
fetch-depth: 0
|
|
161
|
+
|
|
162
|
+
- uses: actions/setup-node@v4
|
|
163
|
+
with:
|
|
164
|
+
node-version: 24
|
|
165
|
+
|
|
166
|
+
- name: Install dependencies
|
|
167
|
+
run: npm ci
|
|
168
|
+
|
|
169
|
+
- name: Lint
|
|
170
|
+
run: npx zuplo lint
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
On other CI systems, run `git fetch origin main` (or the branch you compare
|
|
174
|
+
against) before the linter. See [Lint in CI/CD](./api-lint-ci-cd.mdx) for
|
|
175
|
+
complete workflows, including GitHub code scanning.
|
|
176
|
+
|
|
177
|
+
## Requirements and errors
|
|
178
|
+
|
|
179
|
+
Detection uses Git, so it needs:
|
|
180
|
+
|
|
181
|
+
- Git installed where the linter runs.
|
|
182
|
+
- A project inside a Git repository. The project can be the repository root or
|
|
183
|
+
any subdirectory of it.
|
|
184
|
+
- The baseline ref in the local repository.
|
|
185
|
+
|
|
186
|
+
If any of these is missing, the linter can't compare, and it says so instead of
|
|
187
|
+
reporting no changes:
|
|
188
|
+
|
|
189
|
+
```txt
|
|
190
|
+
Breaking Changes
|
|
191
|
+
|
|
192
|
+
0:0 error Breaking change detection failed: baseline ref "main" not found in this repository; fetch it first (for example, git fetch origin main) or set breakingChanges.baseline to a ref that exists, such as origin/main breaking-change
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
This result uses the `severity` you set, so with the default `"error"` it fails
|
|
196
|
+
the run. A comparison you asked for that can't happen fails the same gate a
|
|
197
|
+
breaking change would.
|
|
198
|
+
|
|
199
|
+
| Message | Fix |
|
|
200
|
+
| ----------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
201
|
+
| `baseline ref "main" not found` | Fetch the branch (`git fetch origin main`), or set `baseline` to `origin/main`. |
|
|
202
|
+
| `cannot read baseline ... not a git repository` | Run the linter inside a Git repository, or turn off detection for that environment. |
|
|
203
|
+
| `invalid baseline ref` | Use a branch, tag, or commit SHA rather than an expression such as `HEAD~1`. |
|
|
204
|
+
|
|
205
|
+
## Next steps
|
|
206
|
+
|
|
207
|
+
- [Lint in CI/CD](./api-lint-ci-cd.mdx) — run detection on every pull request.
|
|
208
|
+
- [Lint configuration](./api-lint-configuration.mdx) — the rest of the
|
|
209
|
+
`zuplo.lint.jsonc` options.
|
|
210
|
+
- [Versioning on Zuplo](./versioning-on-zuplo.mdx) — ship a breaking change
|
|
211
|
+
without breaking existing consumers.
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Lint in CI/CD
|
|
3
|
+
sidebar_label: Lint in CI/CD
|
|
4
|
+
description:
|
|
5
|
+
Run `zuplo lint` in CI to block pull requests on lint errors, show results in
|
|
6
|
+
GitHub code scanning, and report breaking OpenAPI changes against the main
|
|
7
|
+
branch.
|
|
8
|
+
applies_to:
|
|
9
|
+
product: gateway
|
|
10
|
+
hosting: all
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
`zuplo lint` exits with a non-zero code when it finds problems, so any CI system
|
|
14
|
+
can use it as a gate. This page shows a GitHub Actions workflow for each common
|
|
15
|
+
setup, then the pieces you need to adapt them to another CI system.
|
|
16
|
+
|
|
17
|
+
The examples assume your Zuplo project is at the root of the repository and
|
|
18
|
+
lists `zuplo` in `package.json`, as projects created with
|
|
19
|
+
[`create-zuplo-api`](../cli/create-zuplo-api.mdx) do. `zuplo lint` doesn't need
|
|
20
|
+
an API key; it reads only the files in your repository.
|
|
21
|
+
|
|
22
|
+
## Fail pull requests on lint errors
|
|
23
|
+
|
|
24
|
+
The simplest setup runs the linter and lets its exit code pass or fail the job:
|
|
25
|
+
|
|
26
|
+
```yaml title=".github/workflows/lint.yaml"
|
|
27
|
+
name: Lint
|
|
28
|
+
|
|
29
|
+
on:
|
|
30
|
+
pull_request:
|
|
31
|
+
push:
|
|
32
|
+
branches:
|
|
33
|
+
- main
|
|
34
|
+
|
|
35
|
+
jobs:
|
|
36
|
+
lint:
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-node@v4
|
|
43
|
+
with:
|
|
44
|
+
node-version: 24
|
|
45
|
+
|
|
46
|
+
- name: Install dependencies
|
|
47
|
+
run: npm ci
|
|
48
|
+
|
|
49
|
+
- name: Lint
|
|
50
|
+
run: npx zuplo lint
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The job fails when the linter finds an error. To fail on warnings too, change
|
|
54
|
+
the step to `npx zuplo lint --fail-on warn`, or set
|
|
55
|
+
[`failOn`](./api-lint-configuration.mdx#failon) in `zuplo.lint.jsonc` so local
|
|
56
|
+
runs and CI agree.
|
|
57
|
+
|
|
58
|
+
To lint before deploying, add the same step before `zuplo deploy` in your
|
|
59
|
+
deployment workflow. See [Custom CI/CD](./custom-ci-cd.mdx) for deployment
|
|
60
|
+
workflows.
|
|
61
|
+
|
|
62
|
+
## Show results in GitHub code scanning
|
|
63
|
+
|
|
64
|
+
With `--format sarif`, the linter writes results in the SARIF format that GitHub
|
|
65
|
+
code scanning reads. Code scanning shows each result as an annotation on the
|
|
66
|
+
line it applies to in the pull request diff, and tracks open results in the
|
|
67
|
+
repository's **Security** tab.
|
|
68
|
+
|
|
69
|
+
```yaml title=".github/workflows/lint.yaml"
|
|
70
|
+
name: Lint
|
|
71
|
+
|
|
72
|
+
on:
|
|
73
|
+
pull_request:
|
|
74
|
+
push:
|
|
75
|
+
branches:
|
|
76
|
+
- main
|
|
77
|
+
|
|
78
|
+
permissions:
|
|
79
|
+
contents: read
|
|
80
|
+
security-events: write
|
|
81
|
+
|
|
82
|
+
jobs:
|
|
83
|
+
lint:
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
|
|
89
|
+
- uses: actions/setup-node@v4
|
|
90
|
+
with:
|
|
91
|
+
node-version: 24
|
|
92
|
+
|
|
93
|
+
- name: Install dependencies
|
|
94
|
+
run: npm ci
|
|
95
|
+
|
|
96
|
+
- name: Lint
|
|
97
|
+
run: npx zuplo lint --format sarif > zuplo-lint.sarif
|
|
98
|
+
|
|
99
|
+
- name: Upload results
|
|
100
|
+
if: ${{ !cancelled() }}
|
|
101
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
102
|
+
with:
|
|
103
|
+
sarif_file: zuplo-lint.sarif
|
|
104
|
+
category: zuplo-lint
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The `if: ${{ !cancelled() }}` condition uploads the results even when the lint
|
|
108
|
+
step fails, so the annotations appear on the pull requests that need them. The
|
|
109
|
+
lint step still fails the job.
|
|
110
|
+
|
|
111
|
+
:::note
|
|
112
|
+
|
|
113
|
+
Code scanning is available on public repositories, and on private repositories
|
|
114
|
+
with GitHub Advanced Security. Without it, use the
|
|
115
|
+
[pass/fail workflow](#fail-pull-requests-on-lint-errors) — the results appear in
|
|
116
|
+
the job log.
|
|
117
|
+
|
|
118
|
+
:::
|
|
119
|
+
|
|
120
|
+
## Report breaking changes on pull requests
|
|
121
|
+
|
|
122
|
+
[Breaking change detection](./api-lint-breaking-changes.mdx) compares your
|
|
123
|
+
OpenAPI files with the version on another branch. In CI, point the baseline at
|
|
124
|
+
the remote branch and make sure Git has fetched it.
|
|
125
|
+
|
|
126
|
+
```jsonc title="zuplo.lint.jsonc"
|
|
127
|
+
{
|
|
128
|
+
"version": 2,
|
|
129
|
+
"breakingChanges": {
|
|
130
|
+
"enabled": true,
|
|
131
|
+
"baseline": "origin/main",
|
|
132
|
+
"severity": "error",
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`actions/checkout` fetches a single commit by default, and the local `main`
|
|
138
|
+
branch doesn't exist in that checkout. Set `fetch-depth: 0` to fetch the full
|
|
139
|
+
history, including `origin/main`:
|
|
140
|
+
|
|
141
|
+
```yaml title=".github/workflows/lint.yaml"
|
|
142
|
+
steps:
|
|
143
|
+
- uses: actions/checkout@v4
|
|
144
|
+
with:
|
|
145
|
+
fetch-depth: 0
|
|
146
|
+
|
|
147
|
+
- uses: actions/setup-node@v4
|
|
148
|
+
with:
|
|
149
|
+
node-version: 24
|
|
150
|
+
|
|
151
|
+
- name: Install dependencies
|
|
152
|
+
run: npm ci
|
|
153
|
+
|
|
154
|
+
- name: Lint
|
|
155
|
+
run: npx zuplo lint
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
If the baseline isn't in the checkout, the run fails with
|
|
159
|
+
`baseline ref "origin/main" not found`. Fetch the branch before linting.
|
|
160
|
+
|
|
161
|
+
`origin/main` also works on your machine after a `git fetch`, so the same
|
|
162
|
+
configuration file serves local runs and CI.
|
|
163
|
+
|
|
164
|
+
To report breaking changes without blocking the merge, set `"severity": "warn"`.
|
|
165
|
+
The changes still appear in the output and in code scanning, and the job passes
|
|
166
|
+
unless `failOn` is `"warn"`.
|
|
167
|
+
|
|
168
|
+
## Use the JSON output in scripts
|
|
169
|
+
|
|
170
|
+
`--format json` prints a single JSON document with a summary, every result, and
|
|
171
|
+
any breaking changes or fixes. Use it to build your own report, such as a pull
|
|
172
|
+
request comment or a job summary:
|
|
173
|
+
|
|
174
|
+
```yaml title=".github/workflows/lint.yaml"
|
|
175
|
+
- name: Lint
|
|
176
|
+
id: lint
|
|
177
|
+
run: npx zuplo lint --format json > zuplo-lint.json || true
|
|
178
|
+
|
|
179
|
+
- name: Summarize
|
|
180
|
+
run: |
|
|
181
|
+
jq -r '"### Zuplo lint\n\n\(.summary.errors) errors, \(.summary.warnings) warnings, \(.summary.breakingChanges) breaking changes"' \
|
|
182
|
+
zuplo-lint.json >> "$GITHUB_STEP_SUMMARY"
|
|
183
|
+
jq -e '.passed' zuplo-lint.json > /dev/null
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`--fail-on none` keeps the lint step from failing before the summary is written;
|
|
187
|
+
the final `jq -e '.passed'` fails the job when the run didn't pass. The `passed`
|
|
188
|
+
field already takes `failOn` from your configuration file into account. See
|
|
189
|
+
[Output formats](./api-lint.mdx#output-formats) for the full JSON shape.
|
|
190
|
+
|
|
191
|
+
## Other CI systems
|
|
192
|
+
|
|
193
|
+
Any CI system that runs Node.js can run the linter. Each workflow above uses
|
|
194
|
+
three things you need to carry over:
|
|
195
|
+
|
|
196
|
+
1. **Install the project's dependencies** with `npm ci` (or your package
|
|
197
|
+
manager's equivalent), so `npx zuplo` uses the version in your lockfile.
|
|
198
|
+
2. **Run `npx zuplo lint`** from the project root, or pass `--dir`. With
|
|
199
|
+
`--dir`, file paths in the output are relative to that directory, so SARIF
|
|
200
|
+
results won't line up with files in code scanning unless the project is at
|
|
201
|
+
the repository root.
|
|
202
|
+
3. **Read the exit code.** `0` passes, `1` means the linter found problems, and
|
|
203
|
+
`2` means it couldn't run. Treat `2` as a broken pipeline rather than a lint
|
|
204
|
+
result — check the error message in the log.
|
|
205
|
+
|
|
206
|
+
For breaking change detection, also fetch the baseline branch before linting,
|
|
207
|
+
for example with `git fetch origin main`.
|
|
208
|
+
|
|
209
|
+
## Troubleshooting
|
|
210
|
+
|
|
211
|
+
### The linter binary for your platform isn't installed
|
|
212
|
+
|
|
213
|
+
The linter ships as a separate, platform-specific package that npm installs
|
|
214
|
+
alongside the Zuplo CLI as an optional dependency. If optional dependencies are
|
|
215
|
+
skipped — for example with `npm install --omit=optional` — `zuplo lint` stops
|
|
216
|
+
with:
|
|
217
|
+
|
|
218
|
+
```txt
|
|
219
|
+
The zuplo-lint binary for your platform (linux-x64) is not installed.
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Install the dependencies again without skipping optional dependencies. The error
|
|
223
|
+
message names the exact package for your platform, such as
|
|
224
|
+
`@zuplo/lint-linux-x64`, if you need to install it directly.
|
|
225
|
+
|
|
226
|
+
### Invalid directory
|
|
227
|
+
|
|
228
|
+
```txt
|
|
229
|
+
Invalid directory: The project directory is not the root of a Zuplo project.
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The command needs a `config/` directory containing at least one file that ends
|
|
233
|
+
in `.oas.json`. Run it from the project root, or pass `--dir` to point at the
|
|
234
|
+
project. This error exits with `2`.
|
|
235
|
+
|
|
236
|
+
## Next steps
|
|
237
|
+
|
|
238
|
+
- [Lint configuration](./api-lint-configuration.mdx) — presets, severities, and
|
|
239
|
+
breaking change settings.
|
|
240
|
+
- [Testing your API](./testing.mdx) — run tests against a live gateway in the
|
|
241
|
+
same pipeline.
|
|
242
|
+
- [Custom CI/CD](./custom-ci-cd.mdx) — deploy from your own CI system.
|