DevOps → discover workflows
Analyze recent tickets and wait until discovery is ready. The run never publishes a workflow without an admin review.
| Step | What the SDK does |
|---|---|
| 1. Start | start_workflow_discovery (joins a 409 in-progress run) |
| 2. Wait | wait_for_workflow_discovery until ready |
Minimal
from stackgen import StackgenClient, StackgenConfig
client = StackgenClient(
StackgenConfig(
base_url="https://app.stackgen.com",
api_token="stackgen_…",
workspace_id="<workspace-uuid>",
)
)
client.devops.start_workflow_discovery()
ready = client.devops.wait_for_workflow_discovery()
for row in ready.get("classes") or []:
print(row.get("id"), row.get("title"))import { StackgenClient, StackgenConfig } from "stackgen-sdk";
const client = new StackgenClient(
new StackgenConfig({
baseUrl: "https://app.stackgen.com",
apiToken: "stackgen_…",
workspaceId: "<workspace-uuid>",
}),
);
await client.devops.startWorkflowDiscovery();
const ready = await client.devops.waitForWorkflowDiscovery();
for (const row of (ready.classes as Array<Record<string, unknown>> | undefined) ?? []) {
console.log(row.id, row.title);
}if _, err := client.DevOps.StartWorkflowDiscovery(ctx, nil); err != nil {
return err
}
ready, err := client.DevOps.WaitForWorkflowDiscovery(ctx)
if err != nil { return err }
fmt.Println(ready["classes"])
return nilHow to run
python examples/devops/discover-workflows.py --no-wait
python examples/devops/discover-workflows.pyComplete script
- Python:
examples/devops/discover-workflows.py - TypeScript:
examples/devops/discover-workflows.ts - Go:
examples/go/devops/discover-workflows.go
#!/usr/bin/env python3
"""DevOps: start workflow discovery from recent tickets and wait until ready.
Documented at:
https://appcd-dev.github.io/stackgen-sdk/code-samples/devops-discover-workflows/
Usage:
python examples/devops/discover-workflows.py --no-wait
python examples/devops/discover-workflows.py
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from stackgen import StackgenClient, StackgenConfig
from stackgen.errors import StackgenError
def _config(args: argparse.Namespace) -> StackgenConfig:
base = (args.base_url or os.environ.get("STACKGEN_URL", "")).strip()
token = (args.api_token or os.environ.get("STACKGEN_TOKEN", "")).strip()
org = (
(args.workspace_id or "").strip()
or os.environ.get("STACKGEN_WORKSPACE_ID", "").strip()
or os.environ.get("STACKGEN_ORG_ID", "").strip()
or os.environ.get("STACKGEN_PROJECT", "").strip()
or os.environ.get("STACKGEN_PROJECT_ID", "").strip()
)
if not base or not token:
raise SystemExit("set STACKGEN_URL / STACKGEN_TOKEN")
return StackgenConfig(
base_url=base,
api_token=token,
workspace_id=org,
timeout_seconds=args.timeout_seconds,
poll_interval_seconds=args.poll_interval_seconds,
)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base-url", default="")
parser.add_argument("--api-token", default="")
parser.add_argument("--workspace-id",
"--org-id", default="")
parser.add_argument("--no-wait", action="store_true")
parser.add_argument("--window-days", type=int, default=0)
parser.add_argument("--timeout-seconds", type=int, default=1800)
parser.add_argument("--poll-interval-seconds", type=int, default=5)
args = parser.parse_args()
client = StackgenClient(_config(args))
if args.no_wait:
try:
latest = client.devops.latest_workflow_discovery()
except StackgenError as exc:
if "404" in str(exc) or "NOT_FOUND" in str(exc):
print("latest: none (no discovery run yet)")
return 0
raise
print("latest:", json.dumps(latest, indent=2, default=str))
return 0
started = client.devops.start_workflow_discovery(
window_days=args.window_days or None,
)
print("started:", json.dumps(started, indent=2, default=str))
ready = client.devops.wait_for_workflow_discovery()
print("ready:", json.dumps(ready, indent=2, default=str))
classes = ready.get("classes") if isinstance(ready, dict) else None
if isinstance(classes, list):
for row in classes:
if isinstance(row, dict):
print(f"class\t{row.get('id')}\t{row.get('title')}", file=sys.stderr)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except StackgenError as exc:
print(f"error: {exc}", file=sys.stderr)
raise SystemExit(1)/**
* DevOps: start workflow discovery and wait until ready.
* npx tsx examples/devops/discover-workflows.ts --no-wait
*/
import { parseArgs } from "node:util";
import { StackgenClient, StackgenConfig, StackgenError } from "stackgen-sdk";
function show(label: string, value: unknown): void {
console.log(`${label}:`, JSON.stringify(value, null, 2));
}
async function main(): Promise<number> {
const { values } = parseArgs({
options: {
"base-url": { type: "string", default: "" },
"api-token": { type: "string", default: "" },
"org-id": { type: "string" },
"workspace-id": { type: "string", default: "" },
"no-wait": { type: "boolean", default: false },
"window-days": { type: "string", default: "0" },
"timeout-seconds": { type: "string", default: "1800" },
"poll-interval-seconds": { type: "string", default: "5" },
},
});
const baseUrl = (values["base-url"] || process.env.STACKGEN_URL || "").trim();
const apiToken = (values["api-token"] || process.env.STACKGEN_TOKEN || "").trim();
const orgId = (
(values["org-id"] || values["workspace-id"]) ||
process.env.STACKGEN_WORKSPACE_ID ||
process.env.STACKGEN_ORG_ID ||
process.env.STACKGEN_PROJECT ||
process.env.STACKGEN_PROJECT_ID ||
""
).trim();
if (!baseUrl || !apiToken) {
console.error("set STACKGEN_URL / STACKGEN_TOKEN");
return 2;
}
const client = new StackgenClient(
new StackgenConfig({
baseUrl,
apiToken,
workspaceId: orgId,
timeoutSeconds: Number(values["timeout-seconds"]),
pollIntervalSeconds: Number(values["poll-interval-seconds"]),
}),
);
if (values["no-wait"]) {
try {
show("latest", await client.devops.latestWorkflowDiscovery());
} catch (err) {
const msg = String(err);
if (msg.includes("404") || msg.includes("NOT_FOUND")) {
console.log("latest: none (no discovery run yet)");
return 0;
}
throw err;
}
return 0;
}
const windowDays = Number(values["window-days"]);
show(
"started",
await client.devops.startWorkflowDiscovery({
windowDays: windowDays > 0 ? windowDays : undefined,
}),
);
const ready = await client.devops.waitForWorkflowDiscovery();
show("ready", ready);
return 0;
}
main().then(
(c) => process.exit(c),
(err) => {
console.error(`error: ${err}`);
process.exit(err instanceof StackgenError ? 1 : 1);
},
);// Start workflow discovery and wait until ready.
//
// go run ./examples/go/devops/discover-workflows.go --no-wait
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"strings"
stackgen "github.com/appcd-dev/stackgen-sdk/clients/go"
)
func envOr(keys ...string) string {
for _, key := range keys {
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
return v
}
}
return ""
}
func main() {
baseURL := flag.String("base-url", "", "")
apiToken := flag.String("api-token", "", "")
orgID := flag.String("workspace-id", "", "Workspace UUID (sent as orgId)")
flag.StringVar(orgID, "org-id", *orgID, "Deprecated: use -workspace-id")
noWait := flag.Bool("no-wait", false, "")
timeoutSeconds := flag.Int("timeout-seconds", 1800, "")
pollInterval := flag.Int("poll-interval-seconds", 5, "")
flag.Parse()
base := strings.TrimSpace(*baseURL)
if base == "" {
base = envOr("STACKGEN_URL")
}
token := strings.TrimSpace(*apiToken)
if token == "" {
token = envOr("STACKGEN_TOKEN")
}
org := strings.TrimSpace(*orgID)
if org == "" {
org = envOr("STACKGEN_WORKSPACE_ID", "STACKGEN_ORG_ID", "STACKGEN_PROJECT", "STACKGEN_PROJECT_ID")
}
if base == "" || token == "" {
fmt.Fprintln(os.Stderr, "set STACKGEN_URL and STACKGEN_TOKEN")
os.Exit(2)
}
client, err := stackgen.NewClient(stackgen.Config{
BaseURL: base, APIToken: token, WorkspaceID: org,
TimeoutSeconds: *timeoutSeconds, PollIntervalSeconds: *pollInterval,
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
ctx := context.Background()
if *noWait {
latest, err := client.DevOps.LatestWorkflowDiscovery(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
raw, _ := json.MarshalIndent(latest, "", " ")
fmt.Println("latest:", string(raw))
return
}
started, err := client.DevOps.StartWorkflowDiscovery(ctx, nil)
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
raw, _ := json.MarshalIndent(started, "", " ")
fmt.Println("started:", string(raw))
ready, err := client.DevOps.WaitForWorkflowDiscovery(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
raw, _ = json.MarshalIndent(ready, "", " ")
fmt.Println("ready:", string(raw))
}Related: Sync inbox · Approve request