Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions extensions/oviya12/doctask2-oviya-senthilkumar/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Shell scripts must stay LF so they run on the Linux CI runner (CRLF breaks bash).
*.sh text eol=lf
# Everything else: normalize to LF in the repo.
* text=auto eol=lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: client-pipeline

# Regenerates the typed clients from the spec, runs the compatibility gate, and
# smoke-tests both clients against a Prism mock — on every push and PR.
on:
push:
pull_request:
workflow_dispatch:

jobs:
pipeline:
runs-on: ubuntu-latest # Docker, make, python, node all preinstalled
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- uses: actions/setup-node@v4
with:
node-version: "20"

# fetch -> generate -> compat (gate) -> mock -> smoke.
# The compat gate exits non-zero if the old->new spec diff is breaking,
# failing the build; it also asserts the gate fires on the breaking demo.
- name: Run pipeline
run: make all

- name: Upload compatibility report
if: always()
uses: actions/upload-artifact@v4
with:
name: compat-report
path: |
reports/compat.md
reports/compat.json
reports/breaking-demo/compat.md
17 changes: 17 additions & 0 deletions extensions/oviya12/doctask2-oviya-senthilkumar/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated clients — regenerated by `make all`, not committed.
/clients/python/
/clients/typescript/

# Local dependencies
/.venv/
/node_modules/
__pycache__/
*.pyc

# Intermediate diff output (compat.md / compat.json are kept as deliverables)
/reports/changelog.json
/reports/changelog-breaking.json

# Secrets — never commit. (This pipeline needs none; mock-only.)
.env
*.key
26 changes: 26 additions & 0 deletions extensions/oviya12/doctask2-oviya-senthilkumar/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Spec-driven client generation pipeline for the SuperDocs API.
# `make all` runs the whole thing; individual stages are available too.
# Real work lives in scripts/pipeline.sh so it runs identically on CI and locally.

.PHONY: all fetch generate compat mock smoke clean

all: ## Run the full pipeline: fetch -> generate -> compat -> mock -> smoke
bash scripts/pipeline.sh

fetch: ## Re-fetch the pinned spec versions and rebuild the breaking demo
bash scripts/fetch.sh

compat: ## Regenerate the compatibility report (old -> new) with CI gate
docker run --rm -v "$(CURDIR):/work" tufin/oasdiff changelog -f json \
/work/specs/superdocs-old.json /work/specs/superdocs-new.json > reports/changelog.json
python scripts/compat.py --changelog reports/changelog.json \
--base specs/superdocs-old.json --revision specs/superdocs-new.json --out reports --gate

mock: ## Start the Prism mock server on :4010 (Ctrl-C to stop)
docker run --rm --name superdocs-mock -p 4010:4010 -v "$(CURDIR):/tmp" \
stoplight/prism:4 mock -h 0.0.0.0 /tmp/specs/superdocs-new.json

clean: ## Remove generated clients, reports, and local deps
rm -rf clients/python clients/typescript reports/changelog*.json \
reports/compat.* reports/breaking-demo .venv node_modules
-docker rm -f superdocs-mock 2>/dev/null
146 changes: 146 additions & 0 deletions extensions/oviya12/doctask2-oviya-senthilkumar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# doctask2 — Spec-Driven Client Generation Pipeline

Consumes SuperDocs' **published OpenAPI spec** and, in one command, produces
typed API clients for **Python** and **TypeScript**, a **compatibility report**
between two spec versions (with a CI gate that fails on breaking changes), and a
**smoke test per language** against a mock server — no API key, no live service.

---

## What this is & who it serves

When an API is defined by a spec, the clients, the change-review, and the tests
should all be **generated from that spec**, not hand-maintained. This pipeline is
for the team that owns the SuperDocs API and the developers who consume it:

- **API owners** get an automated **breaking-change gate** — a PR that changes
the spec incompatibly fails CI before it ships.
- **Client developers** get **typed SDKs** (Python + TypeScript) regenerated
from the spec, and proof they actually work (smoke tests against a mock).

## One-command run

```bash
make all # fetch → generate → compat (gate) → mock → smoke
```

Requirements: **Docker** (runs the generator, differ, and mock — so a clean
machine needs nothing else installed), plus **python3** and **node** to run the
two smoke tests. No API key. On Windows without `make`, run `bash scripts/pipeline.sh`.

What it does, in order:

| Stage | Tool | Output |
|---|---|---|
| Fetch | `curl` (pinned commit SHAs) | `specs/superdocs-old.json`, `superdocs-new.json` |
| Generate | **openapi-generator 7.12** (Docker) | `clients/python/`, `clients/typescript/` |
| **Compat report** | **oasdiff** (Docker) + `scripts/compat.py` | `reports/compat.md` + `compat.json`, **CI gate** |
| Mock | **Stoplight Prism** (Docker) | mock server on `:4010`, schema-valid examples |
| Smoke | pytest (Py) + tsx (TS) | one typed call per client through the mock |

## Architecture — why each tool

- **openapi-generator** : it's the industry
standard, supports 40+ targets, and turns "add a language" into a one-line
config change. *Buys:* correctness + breadth for free. *Costs:* generated code
is verbose and opinionated, and OpenAPI 3.1 support needs a recent version
(we pin 7.12 and pass `--skip-validate-spec` because the published spec uses a
few 3.1-only constructs).
- **oasdiff** (not a bespoke differ): purpose-built OpenAPI diff with a
**severity model** — it already knows that a removed endpoint or a
newly-required parameter is *breaking* while an added endpoint is *safe*. Our
`scripts/compat.py` wraps its JSON output into a human report and the CI gate.
*Buys:* correct breaking-change classification. *Costs:* one more binary
(we run it via Docker so nothing is installed).
- **Stoplight Prism** (not a stub server): mocks the API straight from the spec,
returning schema-valid example responses — so the smoke tests exercise the
generated clients with **zero** hand-written server code and **no** API key.
- **Docker for all three**: the reproducibility guarantee. A reviewer with only
Docker installed gets identical tool versions.

## The compatibility report (the centerpiece)

`scripts/compat.py` consumes oasdiff's JSON changelog and emits `reports/compat.md`
+ `reports/compat.json`, classifying every change as **breaking** (oasdiff level 3
— removed endpoint, newly-required param, narrowed type) or **safe** (added
endpoint, new optional field). With `--gate` it **exits non-zero on any breaking
change**, so CI fails on an incompatible spec bump.

**Result on the real SuperDocs history** (`old → new`, see below):

> **BACKWARD COMPATIBLE** — 0 breaking, 32 safe changes (12 endpoints added).
> Both specs declare version **2.0.0**, yet the contract changed. *The version
> string alone does not signal compatibility — this diff does.* That gap is the
> whole reason this report exists.

**Proving the gate actually fires:** the pipeline also diffs the new spec against
a synthesized breaking revision (`specs/superdocs-breaking.json`) and asserts the
gate returns non-zero. It flags exactly the three injected breaks:

```
request-parameter-became-required POST /v1/chat authorization became required
api-path-removed-without-deprecation POST /v1/documents/export path removed
request-parameter-type-changed GET /v1/documents/{id} document_id string → integer
```

## Where the "previous" spec version came from

The task needs two spec versions to diff. **We used real published history, not a
fabricated one:**

- **New** = `superdocsapp/docs@ac0d44c` (2026-07-23), 77 paths.
- **Old** = `superdocsapp/docs@a8351de` (2026-06-24), 65 paths.

Both are the genuine `openapi.json` at those commits, pinned by SHA for
reproducibility. There are no version *tags* in the repo, but `openapi.json` has
25 commits of history — we picked two a month apart. Notably **both are labeled
`info.version: 2.0.0`** despite 32 structural differences, which makes the
version-diff genuinely useful.

The real diff turned out to be **backward-compatible** (only additions) — the
correct, honest result. So to demonstrate the breaking-change gate, we
**additionally** synthesize a breaking revision from the new spec via
`scripts/make_breaking_demo.py`, applying three controlled, clearly-logged deltas
(remove an endpoint, make a param required, narrow a type). This is the only
synthesized artifact; everything else is the real published spec.

## Repo layout

```
specs/ vendored spec versions (old, new) + synthesized breaking demo
clients/ generated Python + TypeScript clients (git-ignored; make all rebuilds)
reports/ compat.md + compat.json (the deliverable) + breaking-demo/
scripts/ fetch.sh, pipeline.sh, compat.py, make_breaking_demo.py
tests/ python/ (pytest) and typescript/ (tsx) smoke tests
mock/ (Prism runs from the spec directly)
.github/workflows/pipeline.yml CI: runs `make all`, gates on the report
Makefile one-command entry
```

## Explicit, defended cuts

Scoped as a one-day build. What we deliberately left out and why:

- **No real registry publishing** (PyPI / npm). We generate and *prove the
clients work*; publishing is a packaging/release concern orthogonal to the
spec-driven point, and it would need registry credentials.
- **Two languages** (Python + TypeScript). They prove the pattern; Go, Java, etc.
are each a one-line `openapi-generator` target, not new engineering.
- **Smoke test, not full contract coverage.** One representative typed call per
language (`GET /v1/users/me`) proves the generated client can build a request,
reach the server, and deserialize a typed response. Exhaustively testing all
77 paths is volume, not signal, for one day.
- **Mock-only, no live API.** Prism from the spec keeps the whole pipeline
hermetic, keyless, and reproducible. No auth or integration against production.
- **Generated clients used as-is.** No hand-editing of generator output — that
is the entire value of spec-driven generation.

## Secrets

None required — the pipeline is mock-only. `.env` and `*.key` are git-ignored;
nothing secret is committed.

## Attribution

Built for the SuperDocs task. Uses the publicly published SuperDocs OpenAPI spec
(`docs.superdocs.app/openapi.json`, mirrored at `github.com/superdocsapp/docs`).
13 changes: 13 additions & 0 deletions extensions/oviya12/doctask2-oviya-senthilkumar/mock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Mock server

There is no hand-written mock here — that's the point. The mock is **Stoplight
Prism**, run directly from the OpenAPI spec:

```bash
docker run --rm -p 4010:4010 -v "$PWD:/tmp" \
stoplight/prism:4 mock -h 0.0.0.0 /tmp/specs/superdocs-new.json
```

Prism serves schema-valid example responses for every operation in the spec, so
the generated clients can be smoke-tested with no API key and no live service.
`make all` starts and stops it automatically; `make mock` runs it standalone.
Loading