Skip to content

Commit 6997f2a

Browse files
authored
Merge pull request #11 from APIOpsCycles/linting-support-coverage-report
add linting, audits, style guide as json, improve create-apiops package
2 parents bd591cc + 8a901bc commit 6997f2a

51 files changed

Lines changed: 4182 additions & 2308 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 68 additions & 62 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919
],
2020
"exports": {
2121
"./method-engine": "./src/lib/method-engine.js",
22+
"./snippet-engine": "./src/lib/snippet-engine.js",
2223
"./canvasData.json": "./src/data/canvas/canvasData.json",
2324
"./localizedData.json": "./src/data/canvas/localizedData.json",
2425
"./method/stations.json": "./src/data/method/stations.json",
2526
"./method/resources.json": "./src/data/method/resources.json",
2627
"./method/station-criteria.json": "./src/data/method/station-criteria.json",
2728
"./method/stakeholders.json": "./src/data/method/stakeholders.json",
28-
"./method/station-stakeholders.json": "./src/data/method/station-stakeholders.json"
29+
"./method/station-stakeholders.json": "./src/data/method/station-stakeholders.json",
30+
"./snippets/*": "./src/snippets/*"
2931
},
3032
"scripts": {
3133
"test": "node scripts/validate.mjs && node scripts/test-method-stakeholders.mjs && node scripts/test-note-colors.mjs && node scripts/test-print-method-snippet.mjs",

packages/create-apiops/bin/create-apiops-project.js

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { spawnSync } from "node:child_process";
88
const __filename = fileURLToPath(import.meta.url);
99
const __dirname = path.dirname(__filename);
1010
const templateDir = path.resolve(__dirname, "..", "template");
11+
const repoRoot = path.resolve(__dirname, "..", "..", "..");
12+
const canonicalOpenApiSnippetPath = path.join(repoRoot, "src", "snippets", "api-contract-example.yaml");
1113

1214
const DEFAULTS = {
1315
name: "my-api-project",
@@ -89,6 +91,11 @@ function copyDir(src, dest) {
8991
}
9092
}
9193

94+
function copyFile(src, dest) {
95+
fs.mkdirSync(path.dirname(dest), { recursive: true });
96+
fs.copyFileSync(src, dest);
97+
}
98+
9299
function replaceInFile(filePath, replacements) {
93100
let content = fs.readFileSync(filePath, "utf8");
94101
for (const [from, to] of Object.entries(replacements)) {
@@ -119,32 +126,6 @@ function runCommand(command, args, options = {}) {
119126
});
120127
}
121128

122-
function getScripts(locale, apiStyle) {
123-
const base = {
124-
"method": "node ./node_modules/apiops-cycles-method-data/packages/create-apiops/bin/method-cli.js",
125-
"method:start": `node ./node_modules/apiops-cycles-method-data/packages/create-apiops/bin/method-cli.js start --default-locale ${locale}`,
126-
"method:resources:strategy": `node ./node_modules/apiops-cycles-method-data/packages/create-apiops/bin/method-cli.js resources --station api-product-strategy --locale ${locale}`,
127-
"method:canvases:new-api": `node ./node_modules/apiops-cycles-method-data/packages/create-apiops/bin/method-cli.js generate-canvases --preset new-api --style "${apiStyle}" --locale ${locale} --output ./specs/canvases`,
128-
"method:stations": `node ./node_modules/apiops-cycles-method-data/skills/new-api-guide/scripts/get-core-stations.cjs ${locale}`,
129-
"method:resource:audit": `node ./node_modules/apiops-cycles-method-data/skills/new-api-guide/scripts/get-resource-metadata.cjs api-audit-checklist ${locale}`
130-
};
131-
132-
if (apiStyle === "REST" || apiStyle === "Not sure yet") {
133-
base["method:canvas:rest"] =
134-
`node ./node_modules/apiops-cycles-method-data/skills/new-api-guide/scripts/get-canvas-metadata.cjs restCanvas ${locale}`;
135-
}
136-
if (apiStyle === "Event" || apiStyle === "Not sure yet") {
137-
base["method:canvas:event"] =
138-
`node ./node_modules/apiops-cycles-method-data/skills/new-api-guide/scripts/get-canvas-metadata.cjs eventCanvas ${locale}`;
139-
}
140-
if (apiStyle === "GraphQL" || apiStyle === "Not sure yet") {
141-
base["method:canvas:graphql"] =
142-
`node ./node_modules/apiops-cycles-method-data/skills/new-api-guide/scripts/get-canvas-metadata.cjs graphqlCanvas ${locale}`;
143-
}
144-
145-
return base;
146-
}
147-
148129
function hasMissingFlagValue(args) {
149130
return ["name", "locale", "style"].some((key) => args[key] === undefined && process.argv.includes(`--${key}`));
150131
}
@@ -199,6 +180,7 @@ async function main() {
199180
}
200181

201182
copyDir(templateDir, targetDir);
183+
copyFile(canonicalOpenApiSnippetPath, path.join(targetDir, "specs", "openapi", "api.yaml"));
202184

203185
const replacements = {
204186
"__PROJECT_NAME__": projectName,
@@ -208,17 +190,9 @@ async function main() {
208190
};
209191

210192
replaceInFile(path.join(targetDir, "README.md"), replacements);
193+
replaceInFile(path.join(targetDir, "package.json"), replacements);
211194
replaceInFile(path.join(targetDir, "specs", "openapi", "api.yaml"), replacements);
212195

213-
const packageJsonPath = path.join(targetDir, "package.json");
214-
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
215-
pkg.name = projectName;
216-
pkg.scripts = {
217-
...pkg.scripts,
218-
...getScripts(locale, apiStyle)
219-
};
220-
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
221-
222196
console.log(`Created ${projectName}`);
223197

224198
if (installNow) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: OpenAPI lint and audit coverage
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
audit_profile:
7+
description: Audit profile to run
8+
required: true
9+
default: read-only
10+
type: choice
11+
options:
12+
- read-only
13+
- full-crud
14+
push:
15+
paths:
16+
- "specs/openapi/api.yaml"
17+
- "specs/audit/**"
18+
- "spectral/**"
19+
- "docs/api/audit/**"
20+
- "scripts/run-design-audit.js"
21+
- "package.json"
22+
- "package-lock.json"
23+
- ".spectral.yaml"
24+
- ".github/workflows/openapi-lint.yml"
25+
pull_request:
26+
paths:
27+
- "specs/openapi/api.yaml"
28+
- "specs/audit/**"
29+
- "spectral/**"
30+
- "docs/api/audit/**"
31+
- "scripts/run-design-audit.js"
32+
- "package.json"
33+
- "package-lock.json"
34+
- ".spectral.yaml"
35+
- ".github/workflows/openapi-lint.yml"
36+
37+
permissions:
38+
contents: read
39+
checks: write
40+
41+
jobs:
42+
spectral:
43+
runs-on: ubuntu-latest
44+
env:
45+
AUDIT_PROFILE: ${{ github.event_name == 'workflow_dispatch' && inputs.audit_profile || 'read-only' }}
46+
steps:
47+
- name: Checkout
48+
uses: actions/checkout@v4
49+
- name: Setup Node
50+
uses: actions/setup-node@v4
51+
with:
52+
node-version: 22
53+
cache: npm
54+
- name: Install
55+
run: npm ci
56+
- name: Lint OpenAPI
57+
run: npm run lint:openapi${{ env.AUDIT_PROFILE == 'full-crud' && ':full-crud' || '' }}
58+
- name: Generate audit reports
59+
run: npm run audit:design${{ env.AUDIT_PROFILE == 'full-crud' && ':full-crud' || '' }}
60+
- name: Publish audit coverage
61+
if: (!cancelled())
62+
continue-on-error: true
63+
uses: EnricoMi/publish-unit-test-result-action@v2
64+
with:
65+
files: reports/junit/design-audit.${{ env.AUDIT_PROFILE }}.xml
66+
check_name: APIOps Cycles coverage (${{ env.AUDIT_PROFILE }})

packages/create-apiops/template/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
dist/
33
coverage/
44
*.log
5+
create-apiops-*.tgz
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
extends:
2+
- "./spectral/read-only.yaml"
Lines changed: 138 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,67 @@
1-
# __API_TITLE__
1+
# APIOps Project Template
22

3-
This project uses APIOps Cycles method tooling to design, review, implement, audit, publish, and improve APIs.
4-
For a brand-new API, start with the method station checks and canvases before filling `specs/openapi/api.yaml`.
3+
This project is a scaffolded APIOps workspace for creating a new API, producing API design artifacts, or reviewing and improving an existing API.
54

6-
## Structure
5+
It uses the APIOps Cycles method through the shared `apiops-cycles-method-data` package. The generated project includes CLI commands and local wrapper scripts that help developers, AI assistants, or other tooling move from method guidance into canvases, API contracts, style guidance, and audit work.
76

8-
- `specs/canvases/` = source canvas JSON files
9-
- `specs/openapi/` = source OpenAPI contracts for later API Design and contract-first work
10-
- `specs/audit/` = audit reviews and checklists
11-
- `docs/api/` = rendered SVGs and human-readable outputs
12-
- `src/` = implementation
7+
## When to use this project
8+
9+
Use this project when you have any of these starting points:
10+
11+
- an idea for a new API but not yet a clear scope, contract, or implementation plan
12+
- an existing API concept and a need to capture the business, domain, and interaction design more clearly
13+
- an OpenAPI contract that you want to review, improve, or audit with more structured method guidance
14+
- a need to create reviewable API design artifacts for a team, stakeholders, or governance process
15+
16+
You do not need to start with a finished API design. A rough idea, early requirements, or an existing OpenAPI file is enough.
17+
18+
## What you get from using it
19+
20+
After using this project, you should have:
21+
22+
- a structured set of API design artifacts in `specs/`, including canvases, style guidance, audit data, and optionally an OpenAPI contract
23+
- reviewable documentation and audit outputs in `docs/`
24+
- APIOps Cycles coverage results that show what is already addressed and where the current design still has gaps
25+
- a repeatable workflow for improving the API design over time, locally and in CI
26+
27+
## What this project does and does not prescribe
28+
29+
- The project uses Node.js for the local CLI, helper scripts, linting, and CI workflow.
30+
- It does not require your API implementation itself to use Node.js.
31+
- You can implement the actual API in any language or platform, such as Java, C#, Go, Python, Node.js, or a gateway-based platform.
32+
- The main requirement is that your API design artifacts, especially the OpenAPI contract and audit inputs, are kept in this project structure.
33+
34+
## What else you may need
35+
36+
This project helps you design, review, and govern an API, but it is not the full runtime or deployment solution.
37+
38+
To complete and publish an API, you will usually still need:
39+
40+
- an actual implementation or backend service
41+
- deployment and hosting infrastructure
42+
- an API gateway or publishing channel if your organization uses one
43+
- developer documentation publishing and access management as needed
44+
- organization-specific delivery, security, and operational tooling
45+
46+
In other words, this project gives you the design-time and review-time workspace. You may still need separate tools or platforms for implementation, deployment, publishing, and runtime operations.
1347

1448
## Install
1549

1650
```bash
17-
npm install
51+
npm create apiops@latest
1852
```
1953

54+
## What this project contains
55+
56+
- `specs/canvases/` for canvas JSON source files used to explore business, domain, and API design decisions
57+
- `specs/openapi/api.yaml` for the local project-owned API contract when the work is ready to move into OpenAPI design
58+
- `specs/style/` for optional project-local style guide overrides when you need to replace the canonical default
59+
- `specs/audit/` for generated audit outputs and optional local checklist overrides
60+
- `docs/` for rendered or review-oriented artifacts
61+
- `scripts/` for project-local helper commands that wrap shared package functionality
62+
63+
Treat `specs/` as the source of truth and `docs/` as generated or review material.
64+
2065
## Useful commands
2166

2267
```bash
@@ -26,18 +71,90 @@ npm run method:canvases:new-api
2671
npm run method -- resources --station api-design --style "__API_STYLE__"
2772
npm run method:stations
2873
npm run method:resource:audit
74+
npm run lint:openapi
75+
npm run validate:openapi
76+
npm run audit:design
77+
npm run audit:design:full-crud
2978
```
3079

31-
## Notes
32-
33-
- Start with `npm run method:start`; in an interactive terminal it asks one criterion at a time and recommends the station to begin from.
34-
- `npm run method:resources:strategy` now walks the station steps one by one, and lets you inspect each related resource or canvas before continuing.
35-
- For canvas steps, the CLI can show the related canvas structure, save starter JSON, guide section-by-section note entry, or give you a CanvasCreator URL for browser-based editing and export.
36-
- If you want to build your own helper app or automation, you can also import the shared method logic from `apiops-cycles-method-data/method-engine`.
37-
- Continue with the generated strategy canvases before moving into API contract work.
38-
- Treat `specs/openapi/api.yaml` as a later artifact, not the first design step for a new API.
39-
- Keep source artifacts version controlled
40-
- Treat `specs/` as source of truth
41-
- Treat `docs/` as rendered review material
80+
## How to use it
81+
82+
- Use `npm run method:start` to find the right station to begin from. In an interactive terminal it checks criteria one by one and recommends where to start.
83+
- Use the `method:resources:*` commands or `npm run method -- resources --station ...` to walk the method resources for a station and inspect related canvases or snippets.
84+
- Use `npm run method:canvases:new-api` to generate starter canvas JSON files for a new API initiative.
85+
- Use the generated canvas files to capture scope, business needs, domain understanding, and interface options before going too early into contract details.
86+
- Use `specs/openapi/api.yaml` when you are ready to produce or review API contract details.
87+
- The starter `specs/openapi/api.yaml` is copied during scaffolding from the canonical package example and then becomes project-specific.
88+
- Use the canonical style and audit JSON assets from the package when reviewing design consistency, governance, and quality expectations.
89+
- Add local override files under `specs/style/` or `specs/audit/` only when this project needs to customize those defaults.
90+
91+
## Linting and audit coverage
92+
93+
- Use `npm run lint:openapi` to lint the current OpenAPI contract with the read-only Spectral ruleset.
94+
- Use `npm run lint:openapi:full-crud` when you want the stricter full CRUD ruleset.
95+
- Use `npm run validate:openapi` to run both lint profiles in sequence.
96+
- Use `npm run audit:design` to generate the APIOps Cycles coverage report for the `read-only` profile.
97+
- Use `npm run audit:design:full-crud` to generate the same report for the `full-crud` profile.
98+
99+
The Spectral configuration in this project is split into a default config file and explicit profile rulesets:
100+
101+
- `.spectral.yaml` is the default Spectral entry point and extends `./spectral/read-only.yaml`
102+
- `spectral/base.yaml` contains the shared OpenAPI rules used by all profiles
103+
- `spectral/read-only.yaml` adds rules for read-only APIs, such as blocking `POST`, `PUT`, `PATCH`, and `DELETE`
104+
- `spectral/full-crud.yaml` uses the shared base rules without the read-only restrictions
105+
106+
In practice:
107+
108+
- the npm lint scripts call the profile files in `spectral/` directly
109+
- the GitHub Actions workflow uses those same npm scripts
110+
- `scripts/run-design-audit.js` also selects the matching Spectral ruleset directly when generating coverage reports
111+
- `.spectral.yaml` is still useful as the default config for editor integrations or manual commands like `spectral lint specs/openapi/api.yaml`
112+
113+
The audit command writes multiple outputs so the same result can be used by developers, docs, and CI:
114+
115+
- `specs/audit/design-audit.<profile>.json` as the canonical machine-readable result
116+
- `specs/audit/design-audit.<profile>.md` as the local Markdown report
117+
- `docs/api/audit/design-audit.<profile>.md` as the docs-side Markdown copy
118+
- `docs/api/audit/design-audit.<profile>.html` as the rendered APIOps Cycles Coverage page
119+
- `reports/junit/design-audit.<profile>.xml` as the CI-friendly JUnit result
120+
121+
## GitHub Actions
122+
123+
This template includes `.github/workflows/openapi-lint.yml`, which runs on pushes, pull requests, and manual dispatch.
124+
125+
The workflow:
126+
127+
- installs dependencies with `npm ci`
128+
- runs Spectral linting for the selected audit profile
129+
- generates the audit coverage artifacts
130+
- publishes the JUnit XML result as a GitHub check named `APIOps Cycles coverage (<profile>)`
131+
132+
This makes the generated project useful both for local design work and for automated API review in CI.
133+
134+
## Using skills with AI assistants
135+
136+
This template also supports AI-assisted work through the skill instructions in `AGENTS.md`.
137+
138+
The main skills available in a generated project are:
139+
140+
- `new-api-guide` for moving through the APIOps Cycles method from strategy to design and review
141+
- `canvas-import-json-authoring` for creating or validating CanvasCreator import JSON
142+
- `export-cli-usage-patterns` for exporting canvas artifacts and troubleshooting export flows
143+
144+
In practice, this means an AI assistant can use the same project as a developer:
145+
146+
- start from `npm run method:start` to identify the right station
147+
- inspect station resources and related snippets or canvases
148+
- generate or fill canvas JSON in `specs/canvases/`
149+
- review or improve `specs/openapi/api.yaml`
150+
- run linting and audit coverage checks
151+
152+
The skill guidance is meant to keep AI work aligned with the project structure: prefer the shared method engine and local wrapper scripts, keep editable source artifacts in `specs/`, and treat `docs/` as rendered or review-oriented output.
153+
154+
## Working style
155+
156+
- Continue with the canvases before moving into detailed API contract work for a brand new API.
157+
- This project can also be used for an existing API by reviewing the current design against the canvases, style guide, and audit checklist.
158+
- If you are building your own helper app, agent, or automation, you can also import the shared method logic from `apiops-cycles-method-data/method-engine`.
42159
- Default locale: `__LOCALE__`
43160
- Selected API style hint: `__API_STYLE__`
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# API Docs
2+
3+
This folder is the generated documentation hub for the starter API.
4+
5+
- `strategy/` for business framing and canvases
6+
- `architecture/` for capacity and placement canvases
7+
- `design/` for interaction and REST canvases
8+
- `audit/` for audit coverage views
9+
- `delivery/` for implementation and release notes
10+
- `publishing/` for gateway and developer portal guidance
11+
- `improving/` for iteration notes and follow-up actions
12+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Architecture
2+
3+
Rendered architecture outputs and links for the starter API live here.
4+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Audit
2+
3+
The audit pipeline renders JSON, Markdown, HTML, and JUnit output from the same
4+
canonical audit model.
5+

0 commit comments

Comments
 (0)