Skip to content

feat: JS SDK emitter (#131), C# SDK emitter (#132), Python SDK emitter (#133)#180

Open
johnOC03 wants to merge 16 commits into
camunda:mainfrom
johnOC03:feat/python-sdk-emitter-issue-133
Open

feat: JS SDK emitter (#131), C# SDK emitter (#132), Python SDK emitter (#133)#180
johnOC03 wants to merge 16 commits into
camunda:mainfrom
johnOC03:feat/python-sdk-emitter-issue-133

Conversation

@johnOC03
Copy link
Copy Markdown
Collaborator

Summary

This PR implements three new SDK emitters, closing issues #131, #132, and #133.


Closes


What was done

#133 — Python SDK emitter

  • PythonSdkEmitter generates async def test_*() functions using the CamundaAsyncClient
  • Snake_case SDK method mapping (camelCase operationId → snake_case)
  • Vendor Python project skeleton: conftest.py, helper.py, requirements.txt, pytest.ini
  • scripts/fetch-python-sdk-map.ts — fetches operation-map.json from the Python SDK repo
  • Layer-1 fixture (tests/fixtures/planner/python-sdk-emitter.test.ts): hand-built minimal scenario with golden output reference
  • Layer-2 purity test (tests/codegen/python-sdk-emitter.test.ts): 18 emitter behaviour + determinism assertions
  • Layer-3 regression invariants in configs/camunda-oca/regression-invariants.test.ts:
    • ctx read-without-binding guard (mirrors Bug A)
    • operation-map keyset parity check
  • npm scripts: codegen:python-sdk, codegen:python-sdk:all

#131 — JS SDK emitter

  • JsSdkEmitter lowers path-analyser scenarios onto @camunda8/orchestration-cluster-api
  • path-analyser/src/codegen/js-sdk/README.md documents usage
  • Layer-1 fixture (tests/fixtures/planner/js-sdk-emitter.test.ts)
  • Layer-3 regression invariants:
    • Unresolved ${...} placeholder guard (Bug A equivalent)
    • Operation-map keyset check

#132 — C# SDK emitter

  • CsharpSdkEmitter emits csharp/<operationId>.<mode>.cs files with namespace declarations
  • materializeCsharpSupport writes .csproj, .env.example, README.md project skeleton to outDir
  • path-analyser/src/codegen/csharp-sdk/README.md documents usage
  • Layer-1 fixture (tests/fixtures/planner/csharp-sdk-emitter.test.ts)
  • Layer-3 regression invariants:
    • csharp/<operationId>.<mode>.cs naming convention check
    • Namespace declaration presence check

Quality gates

johnOC03 and others added 9 commits May 13, 2026 15:15
…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.
- 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
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
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 13, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
4 out of 5 committers have signed the CLA.

✅ dashka-str
✅ yarm03
✅ johnOC03
✅ Muhamad690
❌ Dasha


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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 calling CamundaAsyncClient, plus a sparse-clone fetch script for operation-map.json and Python support files.
  • Added C# SDK emitter (--target=csharp-sdk) that generates .cs suite files plus a materialized .NET project skeleton, and introduced a minimal C# REST SDK scaffold under csharp-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 (with True/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 as Exe). 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.

Comment on lines +126 to +132
// 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)`);
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +70 to +78
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('');
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +3195 to +3210
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);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +16 to +24
const CSPROJ = `<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +47 to +52
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?>();');
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +39 to +48
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;
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +1 to +20
{
"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/",
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +40 to +43
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
Muhamad690 and others added 6 commits May 14, 2026 19:24
- 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment