up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
This commit is contained in:
@@ -27,3 +27,5 @@ Generate and maintain official StellaOps SDKs across supported languages using r
|
||||
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
|
||||
- 6. When running codegen with `--enable-post-process-file`, export `STELLA_POSTPROCESS_ROOT` (output directory) and `STELLA_POSTPROCESS_LANG` (`ts|python|go|java|csharp|ruby`) so shared hooks are copied deterministically.
|
||||
- 7. For the TypeScript track, prefer running `ts/generate-ts.sh` with `STELLA_SDK_OUT` pointing to a temp directory to avoid mutating the repo; use `ts/test_generate_ts.sh` for a quick fixture-based smoke.
|
||||
- 8. Always set `STELLA_OAS_EXPECTED_SHA256` to the pinned aggregate OAS digest when generating alphas; scripts will write `.oas.sha256` and fail fast on spec drift.
|
||||
- 9. Per-language smoke commands: `npm run sdk:smoke:ts`, `sdk:smoke:python`, `sdk:smoke:go`, `sdk:smoke:java`; run `npm run sdk:smoke` for the full set before shipping.
|
||||
|
||||
@@ -4,5 +4,7 @@
|
||||
| --- | --- | --- |
|
||||
| SDKGEN-62-001 | DONE (2025-11-24) | Toolchain pinned: OpenAPI Generator CLI 7.4.0 + JDK 21, determinism rules in TOOLCHAIN.md/toolchain.lock.yaml. |
|
||||
| SDKGEN-62-002 | DONE (2025-11-24) | Shared post-process now copies auth/retry/pagination/telemetry helpers for TS/Python/Go/Java, wires TS/Python exports, and adds smoke tests. |
|
||||
| SDKGEN-63-001 | DOING (2025-11-24) | Added TS generator config/script, fixture spec, smoke test (green with vendored JDK/JAR); packaging templates and typed error/helper exports now copied via postprocess. Waiting on frozen OpenAPI to publish alpha. |
|
||||
| SDKGEN-63-002 | DOING (2025-11-24) | Python generator scaffold added (config, script, smoke test, reuse ping fixture); awaiting frozen OpenAPI to emit alpha. |
|
||||
| SDKGEN-63-001 | DOING (2025-11-24) | Added TS generator config/script, fixture spec, smoke test (green with vendored JDK/JAR); packaging templates and typed error/helper exports now copied via postprocess. Spec hash guard writes `.oas.sha256` and optionally enforces `STELLA_OAS_EXPECTED_SHA256`; waiting on frozen OpenAPI to publish alpha. |
|
||||
| SDKGEN-63-002 | DOING (2025-11-24) | Python generator scaffold added (config, script, smoke test, reuse ping fixture) with spec hash guard + `.oas.sha256`; awaiting frozen OpenAPI to emit alpha. |
|
||||
| SDKGEN-63-003 | BLOCKED (2025-11-26) | Go generator scaffold ready; blocked on frozen aggregate OAS digest to emit alpha. |
|
||||
| SDKGEN-63-004 | BLOCKED (2025-11-26) | Java generator scaffold ready; blocked on frozen aggregate OAS digest to emit alpha. |
|
||||
|
||||
26
src/Sdk/StellaOps.Sdk.Generator/go/README.md
Normal file
26
src/Sdk/StellaOps.Sdk.Generator/go/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Go SDK (SDKGEN-63-003)
|
||||
|
||||
Deterministic generator settings for the Go SDK.
|
||||
|
||||
## Prereqs
|
||||
- `STELLA_OAS_FILE` pointing to the frozen OpenAPI spec.
|
||||
- Optional but recommended: `STELLA_OAS_EXPECTED_SHA256` set to the pinned spec hash; the script will verify and emit `.oas.sha256` in the output.
|
||||
- OpenAPI Generator CLI 7.4.0 jar at `tools/openapi-generator-cli-7.4.0.jar` (override with `STELLA_OPENAPI_GENERATOR_JAR`).
|
||||
- JDK 21 on PATH (or vendored at `../tools/jdk-21.0.1+12`).
|
||||
|
||||
## Generate
|
||||
```bash
|
||||
cd src/Sdk/StellaOps.Sdk.Generator
|
||||
STELLA_OAS_FILE=ts/fixtures/ping.yaml \
|
||||
STELLA_SDK_OUT=$(mktemp -d) \
|
||||
STELLA_OAS_EXPECTED_SHA256=$(sha256sum ts/fixtures/ping.yaml | awk '{print $1}') \
|
||||
go/generate-go.sh
|
||||
```
|
||||
|
||||
Outputs land in `out/go/` (or `STELLA_SDK_OUT`) and are post-processed to normalize whitespace, inject the banner, copy shared hooks (`hooks.go`), and record the spec hash in `.oas.sha256`.
|
||||
|
||||
## Smoke test
|
||||
```bash
|
||||
cd src/Sdk/StellaOps.Sdk.Generator/go
|
||||
./test_generate_go.sh # skips if generator jar or JDK is missing
|
||||
```
|
||||
9
src/Sdk/StellaOps.Sdk.Generator/go/config.yaml
Normal file
9
src/Sdk/StellaOps.Sdk.Generator/go/config.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
packageName: stellaops
|
||||
enumClassPrefix: true
|
||||
sourceFolder: src
|
||||
withGoMod: true
|
||||
additionalProperties:
|
||||
# Keep generated code lean and deterministic for alpha
|
||||
packageVersion: 0.1.0-alpha
|
||||
hideGenerationTimestamp: true
|
||||
useOneOfDiscriminatorLookup: true
|
||||
77
src/Sdk/StellaOps.Sdk.Generator/go/generate-go.sh
Normal file
77
src/Sdk/StellaOps.Sdk.Generator/go/generate-go.sh
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
config="$root_dir/go/config.yaml"
|
||||
spec="${STELLA_OAS_FILE:-}"
|
||||
|
||||
if [ -z "$spec" ]; then
|
||||
echo "STELLA_OAS_FILE is required (path to OpenAPI spec)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
else
|
||||
echo "No sha256 tool available (install sha256sum or shasum)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
spec_hash=$(compute_sha256 "$spec")
|
||||
expected_hash="${STELLA_OAS_EXPECTED_SHA256:-}"
|
||||
if [ -n "$expected_hash" ] && [ "$expected_hash" != "$spec_hash" ]; then
|
||||
echo "Spec hash mismatch: expected $expected_hash but got $spec_hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_dir="${STELLA_SDK_OUT:-$root_dir/out/go}"
|
||||
mkdir -p "$output_dir"
|
||||
printf "%s %s\n" "$spec_hash" "$(basename "$spec")" > "$output_dir/.oas.sha256"
|
||||
|
||||
# Ensure postprocess copies shared helpers into the generated tree
|
||||
export STELLA_POSTPROCESS_ROOT="$output_dir"
|
||||
export STELLA_POSTPROCESS_LANG="go"
|
||||
|
||||
JAR="${STELLA_OPENAPI_GENERATOR_JAR:-$root_dir/tools/openapi-generator-cli-7.4.0.jar}"
|
||||
if [ ! -f "$JAR" ]; then
|
||||
echo "OpenAPI Generator CLI jar not found at $JAR" >&2
|
||||
echo "Set STELLA_OPENAPI_GENERATOR_JAR or download to tools/." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prefer vendored JDK when java is absent
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "java not found; install JDK 21 or provide vendored tools/jdk-21.0.1+12" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh"
|
||||
export JAVA_OPTS
|
||||
|
||||
java -jar "$JAR" generate \
|
||||
-i "$spec" \
|
||||
-g go \
|
||||
-c "$config" \
|
||||
--skip-validate-spec \
|
||||
--enable-post-process-file \
|
||||
--global-property models,apis,supportingFiles \
|
||||
-o "$output_dir"
|
||||
|
||||
# Ensure shared helpers are present even if upstream post-process hooks were skipped for some files
|
||||
if [ -f "$output_dir/client.go" ]; then
|
||||
"$root_dir/postprocess/postprocess.sh" "$output_dir/client.go"
|
||||
fi
|
||||
|
||||
echo "Go SDK generated at $output_dir"
|
||||
51
src/Sdk/StellaOps.Sdk.Generator/go/test_generate_go.sh
Normal file
51
src/Sdk/StellaOps.Sdk.Generator/go/test_generate_go.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
script="$root_dir/go/generate-go.sh"
|
||||
spec="$root_dir/ts/fixtures/ping.yaml"
|
||||
jar_default="$root_dir/tools/openapi-generator-cli-7.4.0.jar"
|
||||
jar="${STELLA_OPENAPI_GENERATOR_JAR:-$jar_default}"
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
else
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
fi
|
||||
}
|
||||
expected_hash=$(compute_sha256 "$spec")
|
||||
|
||||
if [ ! -f "$jar" ]; then
|
||||
echo "SKIP: generator jar not found at $jar" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If java is missing, try vendored JDK in tools/
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "SKIP: java not on PATH and vendored JDK not found; set JAVA_HOME or install JDK to run this smoke." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
out_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$out_dir"' EXIT
|
||||
|
||||
STELLA_OAS_FILE="$spec" \
|
||||
STELLA_SDK_OUT="$out_dir" \
|
||||
STELLA_OPENAPI_GENERATOR_JAR="$jar" \
|
||||
STELLA_OAS_EXPECTED_SHA256="$expected_hash" \
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh" \
|
||||
"$script"
|
||||
|
||||
test -f "$out_dir/.oas.sha256" || { echo "missing spec hash output" >&2; exit 1; }
|
||||
test -f "$out_dir/hooks/hooks.go" || test -f "$out_dir/hooks.go" || { echo "missing helper copy" >&2; exit 1; }
|
||||
|
||||
echo "Go generator smoke test passed"
|
||||
26
src/Sdk/StellaOps.Sdk.Generator/java/README.md
Normal file
26
src/Sdk/StellaOps.Sdk.Generator/java/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Java SDK (SDKGEN-63-004)
|
||||
|
||||
Deterministic generator settings for the Java SDK (okhttp-gson client).
|
||||
|
||||
## Prereqs
|
||||
- `STELLA_OAS_FILE` pointing to the frozen OpenAPI spec.
|
||||
- Optional but recommended: `STELLA_OAS_EXPECTED_SHA256` set to the pinned spec hash; the script will verify and emit `.oas.sha256` in the output.
|
||||
- OpenAPI Generator CLI 7.4.0 jar at `tools/openapi-generator-cli-7.4.0.jar` (override with `STELLA_OPENAPI_GENERATOR_JAR`).
|
||||
- JDK 21 on PATH (or vendored at `../tools/jdk-21.0.1+12`).
|
||||
|
||||
## Generate
|
||||
```bash
|
||||
cd src/Sdk/StellaOps.Sdk.Generator
|
||||
STELLA_OAS_FILE=ts/fixtures/ping.yaml \
|
||||
STELLA_SDK_OUT=$(mktemp -d) \
|
||||
STELLA_OAS_EXPECTED_SHA256=$(sha256sum ts/fixtures/ping.yaml | awk '{print $1}') \
|
||||
java/generate-java.sh
|
||||
```
|
||||
|
||||
Outputs land in `out/java/` (or `STELLA_SDK_OUT`) and are post-processed to normalize whitespace, inject the banner, copy shared hooks (`Hooks.java` under `org.stellaops.sdk`), and record the spec hash in `.oas.sha256`.
|
||||
|
||||
## Smoke test
|
||||
```bash
|
||||
cd src/Sdk/StellaOps.Sdk.Generator/java
|
||||
./test_generate_java.sh # skips if generator jar or JDK is missing
|
||||
```
|
||||
12
src/Sdk/StellaOps.Sdk.Generator/java/config.yaml
Normal file
12
src/Sdk/StellaOps.Sdk.Generator/java/config.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
groupId: org.stellaops
|
||||
artifactId: stellaops-sdk
|
||||
artifactVersion: 0.1.0-alpha
|
||||
invokerPackage: org.stellaops.sdk
|
||||
modelPackage: org.stellaops.sdk.model
|
||||
apiPackage: org.stellaops.sdk.api
|
||||
library: okhttp-gson
|
||||
hideGenerationTimestamp: true
|
||||
dateLibrary: java8
|
||||
useRuntimeException: true
|
||||
serializationLibrary: gson
|
||||
useJakartaEe: true
|
||||
76
src/Sdk/StellaOps.Sdk.Generator/java/generate-java.sh
Normal file
76
src/Sdk/StellaOps.Sdk.Generator/java/generate-java.sh
Normal file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
config="$root_dir/java/config.yaml"
|
||||
spec="${STELLA_OAS_FILE:-}"
|
||||
|
||||
if [ -z "$spec" ]; then
|
||||
echo "STELLA_OAS_FILE is required (path to OpenAPI spec)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
else
|
||||
echo "No sha256 tool available (install sha256sum or shasum)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
spec_hash=$(compute_sha256 "$spec")
|
||||
expected_hash="${STELLA_OAS_EXPECTED_SHA256:-}"
|
||||
if [ -n "$expected_hash" ] && [ "$expected_hash" != "$spec_hash" ]; then
|
||||
echo "Spec hash mismatch: expected $expected_hash but got $spec_hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_dir="${STELLA_SDK_OUT:-$root_dir/out/java}"
|
||||
mkdir -p "$output_dir"
|
||||
printf "%s %s\n" "$spec_hash" "$(basename "$spec")" > "$output_dir/.oas.sha256"
|
||||
|
||||
export STELLA_POSTPROCESS_ROOT="$output_dir"
|
||||
export STELLA_POSTPROCESS_LANG="java"
|
||||
|
||||
JAR="${STELLA_OPENAPI_GENERATOR_JAR:-$root_dir/tools/openapi-generator-cli-7.4.0.jar}"
|
||||
if [ ! -f "$JAR" ]; then
|
||||
echo "OpenAPI Generator CLI jar not found at $JAR" >&2
|
||||
echo "Set STELLA_OPENAPI_GENERATOR_JAR or download to tools/." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prefer vendored JDK when java is absent
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "java not found; install JDK 21 or provide vendored tools/jdk-21.0.1+12" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh"
|
||||
export JAVA_OPTS
|
||||
|
||||
java -jar "$JAR" generate \
|
||||
-i "$spec" \
|
||||
-g java \
|
||||
-c "$config" \
|
||||
--skip-validate-spec \
|
||||
--enable-post-process-file \
|
||||
--global-property models,apis,supportingFiles \
|
||||
-o "$output_dir"
|
||||
|
||||
# Ensure shared helpers are present even if upstream post-process hooks were skipped for some files
|
||||
if [ -f "$output_dir/src/main/java/org/stellaops/sdk/ApiClient.java" ]; then
|
||||
"$root_dir/postprocess/postprocess.sh" "$output_dir/src/main/java/org/stellaops/sdk/ApiClient.java"
|
||||
fi
|
||||
|
||||
echo "Java SDK generated at $output_dir"
|
||||
51
src/Sdk/StellaOps.Sdk.Generator/java/test_generate_java.sh
Normal file
51
src/Sdk/StellaOps.Sdk.Generator/java/test_generate_java.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
root_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
script="$root_dir/java/generate-java.sh"
|
||||
spec="$root_dir/ts/fixtures/ping.yaml"
|
||||
jar_default="$root_dir/tools/openapi-generator-cli-7.4.0.jar"
|
||||
jar="${STELLA_OPENAPI_GENERATOR_JAR:-$jar_default}"
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
else
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
fi
|
||||
}
|
||||
expected_hash=$(compute_sha256 "$spec")
|
||||
|
||||
if [ ! -f "$jar" ]; then
|
||||
echo "SKIP: generator jar not found at $jar" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If java is missing, try vendored JDK in tools/
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "SKIP: java not on PATH and vendored JDK not found; set JAVA_HOME or install JDK to run this smoke." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
out_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$out_dir"' EXIT
|
||||
|
||||
STELLA_OAS_FILE="$spec" \
|
||||
STELLA_SDK_OUT="$out_dir" \
|
||||
STELLA_OPENAPI_GENERATOR_JAR="$jar" \
|
||||
STELLA_OAS_EXPECTED_SHA256="$expected_hash" \
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh" \
|
||||
"$script"
|
||||
|
||||
test -f "$out_dir/.oas.sha256" || { echo "missing spec hash output" >&2; exit 1; }
|
||||
test -f "$out_dir/src/main/java/org/stellaops/sdk/Hooks.java" || { echo "missing helper copy" >&2; exit 1; }
|
||||
|
||||
echo "Java generator smoke test passed"
|
||||
@@ -1,145 +0,0 @@
|
||||
// Generated by StellaOps SDK generator — do not edit.
|
||||
package com.stellaops.sdk.hooks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public final class Hooks {
|
||||
private Hooks() {}
|
||||
|
||||
public static OkHttpClient withAll(OkHttpClient base, AuthProvider auth, RetryOptions retry,
|
||||
TelemetryOptions telemetry) {
|
||||
OkHttpClient.Builder builder = base.newBuilder();
|
||||
if (auth != null) {
|
||||
builder.addInterceptor(new StellaAuthInterceptor(auth));
|
||||
}
|
||||
if (telemetry != null) {
|
||||
builder.addInterceptor(new StellaTelemetryInterceptor(telemetry));
|
||||
}
|
||||
if (retry != null) {
|
||||
builder.addInterceptor(new StellaRetryInterceptor(retry));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public interface AuthProvider {
|
||||
String token();
|
||||
|
||||
default String headerName() {
|
||||
return "Authorization";
|
||||
}
|
||||
|
||||
default String scheme() {
|
||||
return "Bearer";
|
||||
}
|
||||
}
|
||||
|
||||
public static final class RetryOptions {
|
||||
public int retries = 2;
|
||||
public long backoffMillis = 200L;
|
||||
public Set<Integer> statusCodes = new HashSet<>();
|
||||
public Logger logger = Logger.getLogger("StellaRetry");
|
||||
|
||||
public RetryOptions() {
|
||||
statusCodes.add(429);
|
||||
statusCodes.add(500);
|
||||
statusCodes.add(502);
|
||||
statusCodes.add(503);
|
||||
statusCodes.add(504);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TelemetryOptions {
|
||||
public String source = "";
|
||||
public String traceParent = "";
|
||||
public String headerName = "X-Stella-Client";
|
||||
}
|
||||
|
||||
static final class StellaAuthInterceptor implements Interceptor {
|
||||
private final AuthProvider provider;
|
||||
|
||||
StellaAuthInterceptor(AuthProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
String token = provider.token();
|
||||
if (token != null && !token.isEmpty()) {
|
||||
String scheme = provider.scheme();
|
||||
String value = (scheme == null || scheme.isEmpty()) ? token : scheme + " " + token;
|
||||
request = request.newBuilder()
|
||||
.header(provider.headerName(), value)
|
||||
.build();
|
||||
}
|
||||
return chain.proceed(request);
|
||||
}
|
||||
}
|
||||
|
||||
static final class StellaTelemetryInterceptor implements Interceptor {
|
||||
private final TelemetryOptions options;
|
||||
|
||||
StellaTelemetryInterceptor(TelemetryOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
Request.Builder builder = request.newBuilder();
|
||||
if (options.source != null && !options.source.isEmpty()) {
|
||||
builder.header(options.headerName, options.source);
|
||||
}
|
||||
if (options.traceParent != null && !options.traceParent.isEmpty()) {
|
||||
builder.header("traceparent", options.traceParent);
|
||||
}
|
||||
return chain.proceed(builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
static final class StellaRetryInterceptor implements Interceptor {
|
||||
private final RetryOptions options;
|
||||
|
||||
StellaRetryInterceptor(RetryOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
int attempts = 0;
|
||||
IOException lastError = null;
|
||||
while (attempts <= options.retries) {
|
||||
try {
|
||||
Response response = chain.proceed(chain.request());
|
||||
if (!options.statusCodes.contains(response.code()) || attempts == options.retries) {
|
||||
return response;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
lastError = ex;
|
||||
if (attempts == options.retries) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(options.backoffMillis * (1L << attempts));
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("retry interrupted", ie);
|
||||
}
|
||||
attempts += 1;
|
||||
}
|
||||
if (lastError != null) {
|
||||
throw lastError;
|
||||
}
|
||||
return chain.proceed(chain.request());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// Generated by StellaOps SDK generator — do not edit.
|
||||
|
||||
package org.stellaops.sdk;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
/**
|
||||
* Reusable hooks for auth, telemetry, retries, and pagination helpers.
|
||||
*/
|
||||
public final class Hooks {
|
||||
|
||||
private Hooks() {}
|
||||
|
||||
public static Interceptor auth(Supplier<String> tokenProvider, String headerName, String scheme) {
|
||||
return chain -> {
|
||||
Request original = chain.request();
|
||||
String token = tokenProvider != null ? tokenProvider.get() : null;
|
||||
if (token == null || token.isEmpty()) {
|
||||
return chain.proceed(original);
|
||||
}
|
||||
|
||||
String header = scheme != null && !scheme.isEmpty() ? scheme + " " + token : token;
|
||||
Request authed = original.newBuilder()
|
||||
.header(firstNonEmpty(headerName, "Authorization"), header)
|
||||
.build();
|
||||
return chain.proceed(authed);
|
||||
};
|
||||
}
|
||||
|
||||
public static Interceptor telemetry(String source, String traceParent, String headerName) {
|
||||
return chain -> {
|
||||
Request.Builder builder = chain.request().newBuilder();
|
||||
if (source != null && !source.isEmpty()) {
|
||||
builder.header(firstNonEmpty(headerName, "X-Stella-Client"), source);
|
||||
}
|
||||
if (traceParent != null && !traceParent.isEmpty()) {
|
||||
builder.header("traceparent", traceParent);
|
||||
}
|
||||
return chain.proceed(builder.build());
|
||||
};
|
||||
}
|
||||
|
||||
public static Interceptor retries(int retries, Duration backoff, Set<Integer> statusCodes) {
|
||||
final int maxAttempts = Math.max(retries, 2);
|
||||
final Duration baseBackoff = backoff != null && !backoff.isNegative() && !backoff.isZero()
|
||||
? backoff : Duration.ofMillis(200);
|
||||
final Set<Integer> retryable = statusCodes == null || statusCodes.isEmpty()
|
||||
? Set.of(429, 500, 502, 503, 504)
|
||||
: statusCodes;
|
||||
|
||||
return new Interceptor() {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
IOException lastError = null;
|
||||
Response lastResponse = null;
|
||||
|
||||
for (int attempt = 0; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
Response resp = chain.proceed(chain.request());
|
||||
if (!retryable.contains(resp.code()) || attempt == maxAttempts) {
|
||||
return resp;
|
||||
}
|
||||
lastResponse = resp;
|
||||
} catch (IOException ex) {
|
||||
lastError = ex;
|
||||
if (attempt == maxAttempts) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(baseBackoff.toMillis() * (1L << attempt));
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("Retry interrupted", ie);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastError != null) {
|
||||
throw lastError;
|
||||
}
|
||||
return lastResponse;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static OkHttpClient withHooks(OkHttpClient base, Interceptor... interceptors) {
|
||||
OkHttpClient.Builder builder = base != null ? base.newBuilder() : new OkHttpClient.Builder();
|
||||
for (Interceptor interceptor : interceptors) {
|
||||
if (interceptor != null) {
|
||||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static <T> PaginationResult<T> paginate(String startCursor, Pager<T> pager) throws Exception {
|
||||
String cursor = startCursor;
|
||||
PaginationResult<T> result = new PaginationResult<>();
|
||||
while (true) {
|
||||
Page<T> page = pager.fetch(cursor);
|
||||
result.items.addAll(page.items());
|
||||
if (page.nextCursor() == null || page.nextCursor().isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
cursor = page.nextCursor();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Pager<T> {
|
||||
Page<T> fetch(String cursor) throws Exception;
|
||||
}
|
||||
|
||||
public record Page<T>(java.util.List<T> items, String nextCursor) {}
|
||||
|
||||
public static final class PaginationResult<T> {
|
||||
public final java.util.List<T> items = new java.util.ArrayList<>();
|
||||
}
|
||||
|
||||
private static String firstNonEmpty(String... values) {
|
||||
if (values == null) return "";
|
||||
for (String v : values) {
|
||||
if (v != null && !v.isEmpty()) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ Deterministic generator settings for the Python SDK (asyncio library).
|
||||
|
||||
## Prereqs
|
||||
- `STELLA_OAS_FILE` pointing to the frozen OpenAPI spec.
|
||||
- Optional but recommended: `STELLA_OAS_EXPECTED_SHA256` set to the pinned spec hash; the script will verify and emit `.oas.sha256` in the output.
|
||||
- OpenAPI Generator CLI 7.4.0 jar at `tools/openapi-generator-cli-7.4.0.jar` (override with `STELLA_OPENAPI_GENERATOR_JAR`).
|
||||
- JDK 21 available on PATH (vendored at `../tools/jdk-21.0.1+12`; set `JAVA_HOME` if needed).
|
||||
|
||||
@@ -12,8 +13,8 @@ Deterministic generator settings for the Python SDK (asyncio library).
|
||||
cd src/Sdk/StellaOps.Sdk.Generator
|
||||
STELLA_OAS_FILE=ts/fixtures/ping.yaml \
|
||||
STELLA_SDK_OUT=$(mktemp -d) \
|
||||
STELLA_OAS_EXPECTED_SHA256=$(sha256sum ts/fixtures/ping.yaml | awk '{print $1}') \
|
||||
python/generate-python.sh
|
||||
```
|
||||
|
||||
Outputs land in `out/python/` and are post-processed to normalize whitespace, inject the banner, and copy shared helpers (`sdk_hooks.py`).
|
||||
Override `STELLA_SDK_OUT` to keep the repo clean during local runs.
|
||||
Outputs land in `out/python/` and are post-processed to normalize whitespace, inject the banner, copy shared helpers (`sdk_hooks.py`), and write `.oas.sha256` with the spec hash. Override `STELLA_SDK_OUT` to keep the repo clean during local runs.
|
||||
|
||||
@@ -10,8 +10,27 @@ if [ -z "$spec" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
else
|
||||
echo "No sha256 tool available (install sha256sum or shasum)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
spec_hash=$(compute_sha256 "$spec")
|
||||
expected_hash="${STELLA_OAS_EXPECTED_SHA256:-}"
|
||||
if [ -n "$expected_hash" ] && [ "$expected_hash" != "$spec_hash" ]; then
|
||||
echo "Spec hash mismatch: expected $expected_hash but got $spec_hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_dir="${STELLA_SDK_OUT:-$root_dir/out/python}"
|
||||
mkdir -p "$output_dir"
|
||||
printf "%s %s\n" "$spec_hash" "$(basename "$spec")" > "$output_dir/.oas.sha256"
|
||||
|
||||
export STELLA_POSTPROCESS_ROOT="$output_dir"
|
||||
export STELLA_POSTPROCESS_LANG="python"
|
||||
@@ -22,6 +41,20 @@ if [ ! -f "$jar" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prefer vendored JDK when java is absent
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "java not found; install JDK 21 or provide vendored tools/jdk-21.0.1+12" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh"
|
||||
export JAVA_OPTS
|
||||
|
||||
@@ -34,4 +67,9 @@ java -jar "$jar" generate \
|
||||
--global-property models,apis,supportingFiles \
|
||||
-o "$output_dir"
|
||||
|
||||
# Ensure shared helpers are present even if upstream post-process hooks were skipped for some files
|
||||
if [ -f "$output_dir/stellaops_sdk/__init__.py" ]; then
|
||||
"$root_dir/postprocess/postprocess.sh" "$output_dir/stellaops_sdk/__init__.py"
|
||||
fi
|
||||
|
||||
echo "Python SDK generated at $output_dir"
|
||||
|
||||
@@ -7,11 +7,34 @@ spec="$root_dir/ts/fixtures/ping.yaml"
|
||||
jar_default="$root_dir/tools/openapi-generator-cli-7.4.0.jar"
|
||||
jar="${STELLA_OPENAPI_GENERATOR_JAR:-$jar_default}"
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
else
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
fi
|
||||
}
|
||||
expected_hash=$(compute_sha256 "$spec")
|
||||
|
||||
if [ ! -f "$jar" ]; then
|
||||
echo "SKIP: generator jar not found at $jar" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If java is missing, try vendored JDK in tools/
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "SKIP: java not on PATH and vendored JDK not found; set JAVA_HOME or install JDK to run this smoke." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "SKIP: java not on PATH; set JAVA_HOME to run this smoke." >&2
|
||||
exit 0
|
||||
@@ -23,9 +46,11 @@ trap 'rm -rf "$out_dir"' EXIT
|
||||
STELLA_OAS_FILE="$spec" \
|
||||
STELLA_SDK_OUT="$out_dir" \
|
||||
STELLA_OPENAPI_GENERATOR_JAR="$jar" \
|
||||
STELLA_OAS_EXPECTED_SHA256="$expected_hash" \
|
||||
"$script"
|
||||
|
||||
test -f "$out_dir/stellaops_sdk/__init__.py" || { echo "missing generated package" >&2; exit 1; }
|
||||
test -f "$out_dir/sdk_hooks.py" || { echo "missing helper copy" >&2; exit 1; }
|
||||
test -f "$out_dir/.oas.sha256" || { echo "missing spec hash output" >&2; exit 1; }
|
||||
|
||||
echo "Python generator smoke test passed"
|
||||
|
||||
@@ -4,6 +4,7 @@ This directory contains deterministic generator settings for the TypeScript SDK.
|
||||
|
||||
## Prereqs
|
||||
- OpenAPI spec file path exported as `STELLA_OAS_FILE` (temporary until APIG0101 publishes the canonical spec).
|
||||
- Optional but recommended: set `STELLA_OAS_EXPECTED_SHA256` to the pinned spec hash; the script will verify and emit `.oas.sha256` in the output.
|
||||
- OpenAPI Generator CLI 7.4.0 jar at `tools/openapi-generator-cli-7.4.0.jar` or override `STELLA_OPENAPI_GENERATOR_JAR`.
|
||||
- JDK 21 available on PATH (vendored at `../tools/jdk-21.0.1+12`; set `JAVA_HOME` accordingly).
|
||||
|
||||
@@ -14,6 +15,7 @@ cd src/Sdk/StellaOps.Sdk.Generator
|
||||
STELLA_OAS_FILE=/path/to/api.yaml \
|
||||
STELLA_SDK_OUT=$(mktemp -d) \
|
||||
STELLA_OPENAPI_GENERATOR_JAR=tools/openapi-generator-cli-7.4.0.jar \
|
||||
STELLA_OAS_EXPECTED_SHA256=$(sha256sum /path/to/api.yaml | awk '{print $1}') \
|
||||
ts/generate-ts.sh
|
||||
```
|
||||
|
||||
@@ -21,6 +23,7 @@ Outputs land in `out/typescript/` and are post-processed to:
|
||||
- Normalize whitespace/line endings.
|
||||
- Inject traceability banner.
|
||||
- Copy shared helpers (`sdk-hooks.ts`) and wire them through the package barrel.
|
||||
- Record the spec hash to `.oas.sha256` for downstream provenance checks.
|
||||
|
||||
To validate the pipeline locally with a tiny fixture spec (`ts/fixtures/ping.yaml`), run:
|
||||
|
||||
|
||||
@@ -10,8 +10,27 @@ if [ -z "$spec" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
else
|
||||
echo "No sha256 tool available (install sha256sum or shasum)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
spec_hash=$(compute_sha256 "$spec")
|
||||
expected_hash="${STELLA_OAS_EXPECTED_SHA256:-}"
|
||||
if [ -n "$expected_hash" ] && [ "$expected_hash" != "$spec_hash" ]; then
|
||||
echo "Spec hash mismatch: expected $expected_hash but got $spec_hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_dir="${STELLA_SDK_OUT:-$root_dir/out/typescript}"
|
||||
mkdir -p "$output_dir"
|
||||
printf "%s %s\n" "$spec_hash" "$(basename "$spec")" > "$output_dir/.oas.sha256"
|
||||
|
||||
# Ensure postprocess copies shared helpers into the generated tree
|
||||
export STELLA_POSTPROCESS_ROOT="$output_dir"
|
||||
@@ -24,6 +43,20 @@ if [ ! -f "$JAR" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prefer vendored JDK when java is absent
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
if [ -d "$vendor_jdk/bin" ]; then
|
||||
export JAVA_HOME="$vendor_jdk"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
echo "java not found; install JDK 21 or provide vendored tools/jdk-21.0.1+12" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh"
|
||||
export JAVA_OPTS
|
||||
|
||||
|
||||
@@ -12,6 +12,15 @@ if [ ! -f "$jar" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
compute_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$1" | awk '{print $1}'
|
||||
else
|
||||
shasum -a 256 "$1" | awk '{print $1}'
|
||||
fi
|
||||
}
|
||||
expected_hash=$(compute_sha256 "$spec")
|
||||
|
||||
# If java is missing, try vendored JDK in tools/
|
||||
if ! command -v java >/dev/null 2>&1; then
|
||||
vendor_jdk="$root_dir/tools/jdk-21.0.1+12"
|
||||
@@ -32,11 +41,13 @@ trap 'rm -rf "$out_dir"' EXIT
|
||||
STELLA_OAS_FILE="$spec" \
|
||||
STELLA_SDK_OUT="$out_dir" \
|
||||
STELLA_OPENAPI_GENERATOR_JAR="$jar" \
|
||||
STELLA_OAS_EXPECTED_SHA256="$expected_hash" \
|
||||
JAVA_OPTS="${JAVA_OPTS:-} -Dorg.openapitools.codegen.utils.postProcessFile=$root_dir/postprocess/postprocess.sh" \
|
||||
"$script"
|
||||
|
||||
test -f "$out_dir/src/apis/DefaultApi.ts" || { echo "missing generated API" >&2; exit 1; }
|
||||
test -f "$out_dir/sdk-hooks.ts" || { echo "missing helper copy" >&2; exit 1; }
|
||||
test -f "$out_dir/.oas.sha256" || { echo "missing spec hash output" >&2; exit 1; }
|
||||
|
||||
# Basic eslint-free sanity: ensure banner on generated helper
|
||||
first_line=$(head -n 1 "$out_dir/sdk-hooks.ts")
|
||||
|
||||
Reference in New Issue
Block a user