feat: JS SDK emitter (#131), C# SDK emitter (#132), Python SDK emitter (#133)#180
feat: JS SDK emitter (#131), C# SDK emitter (#132), Python SDK emitter (#133)#180johnOC03 wants to merge 16 commits into
Conversation
…rchestration-cluster-api Implements issue camunda#131. Adds a new `js-sdk` emitter target that generates Vitest `.test.ts` integration suites (not Playwright `.spec.ts`) calling `@camunda8/orchestration-cluster-api` SDK methods directly. Key additions: - `path-analyser/src/codegen/js-sdk/sdk-mapping.ts`: SdkMappingSource interface, OperationMapJsonSource (reads operation-map.json), FallbackMappingSource (returns operationId unchanged), regionToCamelCase - `path-analyser/src/codegen/js-sdk/emitter.ts`: createJsSdkEmitter(), renderJsSdkSuite(), jsSdkSuiteFileName(); hard-fails on multipart steps - `path-analyser/src/codegen/js-sdk/materialize-support.ts`: vendors support/ helpers + project-root scaffolding into the generated output dir - `path-analyser/src/codegen/js-sdk/project-templates/`: package.json, tsconfig.json, vitest.config.ts, .env.example, README.md - `scripts/fetch-js-sdk-map.js`: sparse-clones operation-map.json from camunda/orchestration-cluster-api-js (npm run fetch-js-sdk-map) - `path-analyser/src/codegen/index.ts`: registers js-sdk emitter, calls materializeSdkSupport on js-sdk target - `path-analyser/scripts/copy-support-templates.js`: stages js-sdk support + project templates into dist/ at build time - `tests/codegen/js-sdk-emitter.test.ts`: 27 unit tests (all passing) Also updates configs/camunda-oca/spec-pin.json expectedSpecHash to match camunda-schema-bundler ^2.3.0 (already in devDependencies on main) which produces a different hash for the same spec ref.
…s-sdk block, fix spec-pin hash
- Add PythonSdkEmitter class generating async def test_*() functions - Implement snake_case SDK method mapping (camelCase operationId conversion) - Vendor Python project skeleton: conftest.py, helper.py, requirements.txt, pytest.ini - Add fetch-python-sdk-map script for operation-map.json extraction - Layer-1 fixture: hand-built minimal scenario with golden output reference - Layer-2 purity test: 18 comprehensive emitter behavior + determinism assertions - Layer-3 regression invariants: URL binding + operation-map keyset parity checks - Add npm scripts: codegen:python-sdk, codegen:python-sdk:all - Integrate into main pipeline (fetch-python-sdk-map)
… map loading - Refactor PythonSdkEmitter to factory pattern (createPythonSdkEmitter) - Fix file naming to use snake_case (activateJobs -> activate_jobs.python_sdk.spec.py) - Improve scenario rendering with proper context initialization - Fix body dict template placeholder replacement (\ -> ctx['var']) - Add Python SDK emitter registration in codegen/index.ts with operation-map loading - Load spec/python-sdk/operation-map.json with fallback to camelToSnake conversion - Complete comprehensive README with usage, examples, and limitations - Align with JS SDK emitter patterns for consistency Implements Phase 3-6 of Python SDK support (camunda#133): - Factory pattern with optional operation-map source - Layer-based test fixtures (Layer-1, Layer-2, Layer-3) - Deterministic output for regression testing - Hard-fail on unsupported multipart uploads - Pure emitter: no filesystem/network I/O
…iome path, and script restores
Add REST SDK support for job search, job failure, and getting process instances: new client methods (GetProcessInstanceAsync, SearchJobsAsync, FailJobAsync) and a GetJsonAsync helper; add models JobFailRequest and JobSearchModels. Update the C# codegen emitter to generate calls for getProcessInstance, searchJobs, and failJob, and add corresponding default method mappings. Add a unit test for emitting searchJobs scaffolding and update the operation map to include the new operations. Also include documentation notes (AUTOMATION_BOUNDARY.md and GRPC_ORIENTATION.md) describing C# semantic type generation boundaries and gRPC orientation details.
…ns — fixtures, READMEs, materialize, L3 invariants
…late string guards
|
Dasha seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
There was a problem hiding this comment.
Pull request overview
This PR adds three new path-analyser codegen targets that emit SDK-based test suites (JS, Python, and C#) instead of raw HTTP/Playwright calls, plus supporting fetch/materialization scripts and layered regression tests/invariants.
Changes:
- Added JS SDK emitter (
--target=js-sdk) that generates Vitest suites calling@camunda8/orchestration-cluster-api, including vendored project/support templates. - Added Python SDK emitter (
--target=python-sdk) that generates async pytest suites callingCamundaAsyncClient, plus a sparse-clone fetch script foroperation-map.jsonand Python support files. - Added C# SDK emitter (
--target=csharp-sdk) that generates.cssuite files plus a materialized .NET project skeleton, and introduced a minimal C# REST SDK scaffold undercsharp-sdk/.
Reviewed changes
Copilot reviewed 69 out of 77 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/regression/generated-suites-typecheck.test.ts | Adjusts strict typecheck guard execution for emitted TS suites. |
| tests/fixtures/planner/python-sdk-emitter.test.ts | Layer-1 fixture for Python emitter golden output & structure checks. |
| tests/fixtures/planner/planner-seed-bindings.test.ts | Clarifies fixture placeholders with Biome ignore comments. |
| tests/fixtures/planner/planner-establishes.test.ts | Minor access style tweak in establisher/producers fixture. |
| tests/fixtures/planner/js-sdk-emitter.test.ts | Layer-1 fixture assertions for JS SDK suite rendering. |
| tests/fixtures/planner/csharp-sdk-emitter.test.ts | Layer-1 fixture assertions for C# SDK emitter output. |
| tests/codegen/python-sdk-emitter.test.ts | Layer-2 determinism/contract tests for Python emitter. |
| tests/codegen/js-sdk-emitter.test.ts | Layer-2 determinism/contract tests for JS SDK emitter + mapping. |
| tests/codegen/csharp-sdk-emitter.test.ts | Layer-2 determinism/contract tests for C# emitter. |
| scripts/fetch-python-sdk-map.ts | Fetches Python SDK operation-map.json via sparse clone. |
| scripts/fetch-js-sdk-map.js | Fetches JS SDK operation-map.json via sparse clone. |
| path-analyser/src/codegen/python-sdk/sdk-mapping.ts | Python operationId→snake_case mapping and map lookup. |
| path-analyser/src/codegen/python-sdk/README.md | Documentation for Python emitter usage, mapping, and limitations. |
| path-analyser/src/codegen/python-sdk/materialize-support.ts | Writes pytest scaffolding files (conftest/helper/requirements/ini). |
| path-analyser/src/codegen/python-sdk/emitter.ts | Implements Python SDK emitter to generate .python_sdk.spec.py suites. |
| path-analyser/src/codegen/playwright/materialize-support.ts | Tweaks response schema extraction spawn options. |
| path-analyser/src/codegen/js-sdk/sdk-mapping.ts | JS SDK operationId→method mapping source implementations. |
| path-analyser/src/codegen/js-sdk/README.md | Documentation for JS SDK emitter usage and prerequisites. |
| path-analyser/src/codegen/js-sdk/project-templates/vitest.config.ts | Template Vitest config for generated JS SDK suites. |
| path-analyser/src/codegen/js-sdk/project-templates/tsconfig.json | Template TS config for generated JS SDK suites. |
| path-analyser/src/codegen/js-sdk/project-templates/README.md | Template README for generated JS SDK suite projects. |
| path-analyser/src/codegen/js-sdk/project-templates/package.json | Template package.json for generated JS SDK suite projects. |
| path-analyser/src/codegen/js-sdk/project-templates/.env.example | Template env var example for JS SDK suite projects. |
| path-analyser/src/codegen/js-sdk/materialize-support.ts | Copies JS SDK support + project templates into outDir. |
| path-analyser/src/codegen/js-sdk/emitter.ts | Implements JS SDK emitter suite rendering and lowering logic. |
| path-analyser/src/codegen/index.ts | Registers new emitters and materializes their support files. |
| path-analyser/src/codegen/csharp-sdk/README.md | Documentation for C# emitter usage and emitted layout. |
| path-analyser/src/codegen/csharp-sdk/operation-map.ts | Loads/parses committed C# operation-map.json into a typed map. |
| path-analyser/src/codegen/csharp-sdk/materialize-support.ts | Writes .NET project skeleton files for generated C# suites. |
| path-analyser/src/codegen/csharp-sdk/emitter.ts | Implements C# emitter producing csharp/<op>.<mode>.cs suites. |
| path-analyser/scripts/copy-support-templates.js | Stages templates for both Playwright and JS SDK emitters in dist. |
| package.json | Adds fetch/codegen scripts for SDK emitters and updates pipeline. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Types/Identifiers.cs | Adds semantic identifier wrapper types for the C# REST SDK scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/project.nuget.cache | Build/restore artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/project.assets.json | Build/restore artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.sourcelink.json | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.GlobalUsings.g.cs | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.GeneratedMSBuildEditorConfig.editorconfig | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.csproj.FileListAbsolute.txt | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.csproj.CoreCompileInputs.cache | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.AssemblyInfoInputs.cache | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/Camunda.Orchestration.RestSdk.AssemblyInfo.cs | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs | Build artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Camunda.Orchestration.RestSdk.csproj.nuget.g.targets | Restore artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Camunda.Orchestration.RestSdk.csproj.nuget.g.props | Restore artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/Camunda.Orchestration.RestSdk.csproj.nuget.dgspec.json | Restore artifact (should not be committed). |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/SearchQuery.cs | Adds shared search query request/response models for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/SearchProcessInstancesResponse.cs | Adds search process instance response models for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/SearchProcessInstancesRequest.cs | Adds search process instance request models for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/JobSearchModels.cs | Adds job search request/response models for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/JobFailRequest.cs | Adds job failure request model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/DeploymentResponse.cs | Adds deployment response models for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/DeploymentResource.cs | Adds deployment resource model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/DeploymentRequest.cs | Adds deployment request model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/CreateProcessInstanceResponse.cs | Adds create process instance response model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/CreateProcessInstanceRequest.cs | Adds create process instance request model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/CompleteJobRequest.cs | Adds complete job request model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/CancelProcessInstanceRequest.cs | Adds cancel process instance request model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/ActivateJobsResponse.cs | Adds activate jobs response models for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Models/ActivateJobsRequest.cs | Adds activate jobs request model for C# scaffold. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Client/OrchestrationClusterClient.cs | Adds minimal REST client implementation for the C# scaffold SDK. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Client/ClientOptions.cs | Adds client options model for C# scaffold SDK. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/Camunda.Orchestration.RestSdk.csproj | Adds the C# scaffold SDK project file. |
| csharp-sdk/src/Camunda.Orchestration.RestSdk/bin/Debug/net8.0/Camunda.Orchestration.RestSdk.deps.json | Build output artifact (should not be committed). |
| csharp-sdk/README.md | Documents the included minimal C# REST SDK scaffold. |
| csharp-sdk/GRPC_ORIENTATION.md | Notes about gRPC client baseline for comparison. |
| csharp-sdk/examples/usage.cs | Example usage of the minimal C# REST SDK scaffold. |
| csharp-sdk/examples/operation-map.json | Committed operation→method mapping for the C# emitter. |
| csharp-sdk/AUTOMATION_BOUNDARY.md | Documents what should/shouldn’t be generator-automated for C# types. |
| configs/camunda-oca/regression-invariants.test.ts | Adds Layer-3 invariants for Python/JS/C# emitted suites. |
Comments suppressed due to low confidence (2)
path-analyser/src/codegen/python-sdk/emitter.ts:188
- buildBodyDict() produces Python dict source by JSON-stringifying and then applying regex replacements. Besides quoting/escaping issues, it will output JSON booleans/null (
true/false/null) which are not valid Python syntax, making generated tests fail for templates containing booleans or nulls. A safer approach is to render Python literals recursively (withTrue/False/None) and only substitute placeholders at string-leaf nodes.
path-analyser/src/codegen/csharp-sdk/materialize-support.ts:70 - The generated README instructs users to run
dotnet run, but with the current scaffold there is no generated entrypoint (and the project is marked asExe). This is misleading and will fail unless an explicit runner/Program is added. Update the README to match the emitted project shape (or add the runner).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Build kwargs for the client method call | ||
| const kwargs: string[] = []; | ||
| if (step.bodyTemplate && step.bodyKind === 'json') { | ||
| // Use from_dict() with model class name derived from operationId | ||
| const modelClassName = inferModelClassName(step.operationId); | ||
| kwargs.push(`data=${modelClassName}.from_dict(request_body)`); | ||
| } |
| if (Object.keys(bindings).length > 0) { | ||
| lines.push(' # Seed scenario bindings'); | ||
| for (const [k, v] of Object.entries(bindings)) { | ||
| if (v === '__PENDING__') continue; // Skip pending markers | ||
| // Use Python-style single-quoted strings for string values | ||
| const pyValue = typeof v === 'string' ? `'${v}'` : JSON.stringify(v); | ||
| lines.push(` ctx['${k}'] = ${pyValue}`); | ||
| } | ||
| lines.push(''); |
| for (const file of files) { | ||
| const src = readFileSync(join(GENERATED_TESTS_DIR, file), 'utf8'); | ||
| assertionsRun++; | ||
| const regexClientCall = /await\s+client\.([a-z_]+)\(/g; | ||
| const methodsSeen = new Set<string>(); | ||
| let match; | ||
| while ((match = regexClientCall.exec(src)) !== null) { | ||
| methodsSeen.add(match[1]); | ||
| } | ||
| for (const method of methodsSeen) { | ||
| if (operationMap && !(method in operationMap)) { | ||
| // Fallback snake_case conversion is always valid; allow any method | ||
| } | ||
| } | ||
| } | ||
| expect(assertionsRun).toBeGreaterThan(0); |
| const CSPROJ = `<Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
| lines.push(' using var httpClient = new HttpClient();'); | ||
| lines.push(' var client = new OrchestrationClusterClient('); | ||
| lines.push(' httpClient,'); | ||
| lines.push(' new ClientOptions { BaseUri = new Uri("http://localhost:8080/v2/") }'); | ||
| lines.push(' );'); | ||
| lines.push(' var ctx = new Dictionary<string, object?>();'); |
| function execCommand(cmd: string, options?: Record<string, unknown>): string { | ||
| try { | ||
| return execSync(cmd, { encoding: 'utf-8', ...options }).trim(); | ||
| } catch (error) { | ||
| // biome-ignore lint/plugin: error is caught from execSync; status/stderr/stdout are the Node.js SpawnSyncReturns fields | ||
| const err = error as { status: number; stderr: Buffer; stdout: Buffer }; | ||
| console.error(`Command failed: ${cmd}`); | ||
| console.error(err.stderr?.toString() || err.stdout?.toString() || String(error)); | ||
| throw error; | ||
| } |
| { | ||
| "version": 3, | ||
| "targets": { | ||
| "net8.0": {} | ||
| }, | ||
| "libraries": {}, | ||
| "projectFileDependencyGroups": { | ||
| "net8.0": [] | ||
| }, | ||
| "packageFolders": { | ||
| "/home/muhamad/.nuget/packages/": {} | ||
| }, | ||
| "project": { | ||
| "version": "1.0.0", | ||
| "restore": { | ||
| "projectUniqueName": "/home/muhamad/API-Test/api-test-generator/csharp-sdk/src/Camunda.Orchestration.RestSdk/Camunda.Orchestration.RestSdk.csproj", | ||
| "projectName": "Camunda.Orchestration.RestSdk", | ||
| "projectPath": "/home/muhamad/API-Test/api-test-generator/csharp-sdk/src/Camunda.Orchestration.RestSdk/Camunda.Orchestration.RestSdk.csproj", | ||
| "packagesPath": "/home/muhamad/.nuget/packages/", | ||
| "outputPath": "/home/muhamad/API-Test/api-test-generator/csharp-sdk/src/Camunda.Orchestration.RestSdk/obj/", |
| This downloads the SDK's method-to-operationId mapping from the | ||
| `@camunda8/orchestration-cluster-api` npm package and writes it to | ||
| `spec/js-sdk/operation-map.json`. Without it, the emitter falls back to | ||
| identity mapping (operationId unchanged) which works for most Camunda REST |
- Issue 1-2: Python SDK — implement toPythonLiteral() for correct boolean/null/template rendering - Issue 3: C# SDK — read CAMUNDA_BASE_URL env var instead of hardcoded localhost:8080 - Issue 4: C# SDK — change OutputType from Exe to Library and update README - Issue 5: Add .gitignore entries for csharp-sdk/**/obj/ and bin/ directories - Issue 6: Fix no-op regression invariant loop in Python SDK operation-map test - Issue 7: JS SDK — add⚠️ warning about fallback mapping in README and console.warn() All changes follow Biome formatting, TypeScript strict types, and project conventions.
…n C) Remove explicit <OutputType>Library</OutputType> from the scaffolded .csproj template. In .NET SDK-style projects, the default output type is Library when <OutputType> is omitted, achieving the same result as explicit declaration but with cleaner XML. Changes: - Remove <OutputType>Library</OutputType> from CSPROJ template (line 19) - Update JSDoc to reflect test framework/runner consumption model - Enhance README with step-by-step xUnit/NUnit setup instructions - Include code examples for test wrapper and dotnet test workflow - Document alternative direct consumption approach The implicit default approach follows modern .NET conventions while keeping the project configuration minimal. Test frameworks (xUnit, NUnit, MSTest) consume library assemblies natively via dotnet test.
…m/camunda/api-test-generator into feat/python-sdk-emitter-issue-133
Summary
This PR implements three new SDK emitters, closing issues #131, #132, and #133.
Closes
js-sdk) — lower path-analyser scenarios onto @camunda8/orchestration-cluster-api #131 — JS SDK emitter (@camunda8/orchestration-cluster-api)csharp-sdk) — lower path-analyser scenarios onto Camunda C# orchestration SDK #132 — C# SDK emitterpython-sdk) — lower path-analyser scenarios onto camunda-orchestration-sdk #133 — Python SDK async pytest emitterWhat was done
#133 — Python SDK emitter
PythonSdkEmittergeneratesasync def test_*()functions using theCamundaAsyncClientoperationId→ snake_case)conftest.py,helper.py,requirements.txt,pytest.iniscripts/fetch-python-sdk-map.ts— fetchesoperation-map.jsonfrom the Python SDK repotests/fixtures/planner/python-sdk-emitter.test.ts): hand-built minimal scenario with golden output referencetests/codegen/python-sdk-emitter.test.ts): 18 emitter behaviour + determinism assertionsconfigs/camunda-oca/regression-invariants.test.ts:ctxread-without-binding guard (mirrors Bug A)codegen:python-sdk,codegen:python-sdk:all#131 — JS SDK emitter
JsSdkEmitterlowers path-analyser scenarios onto@camunda8/orchestration-cluster-apipath-analyser/src/codegen/js-sdk/README.mddocuments usagetests/fixtures/planner/js-sdk-emitter.test.ts)${...}placeholder guard (Bug A equivalent)#132 — C# SDK emitter
CsharpSdkEmitteremitscsharp/<operationId>.<mode>.csfiles with namespace declarationsmaterializeCsharpSupportwrites.csproj,.env.example,README.mdproject skeleton to outDirpath-analyser/src/codegen/csharp-sdk/README.mddocuments usagetests/fixtures/planner/csharp-sdk-emitter.test.ts)csharp/<operationId>.<mode>.csnaming convention checkQuality gates
npm run lint— clean (135 files, no errors)npx tsc --noEmit— all 3 workspace tsconfigs passnpm test— 435 passed, 6 skipped, 0 failures (46 test files)main(resolves conflicts from PR feat: relocate Layer-3 invariants under configs/<name>/ for per-config matrix (#128 PR 3/N) #144 relocation of Layer-3 invariants)