Skip to content

Commit 112e469

Browse files
chore: set up publishing
1 parent e8130e4 commit 112e469

File tree

20 files changed

+425
-38
lines changed

20 files changed

+425
-38
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
name: speakeasy-context
3+
description: "Speakeasy workflow: run 'agent context' FIRST, do task, run 'agent feedback' LAST. Triggers on speakeasy, SDK, OpenAPI."
4+
license: Apache-2.0
5+
---
6+
7+
# speakeasy-context
8+
9+
## Rule
10+
11+
Before any Speakeasy task: **run `speakeasy agent context`**. Prefer CLI output over web/docs.
12+
13+
## Commands
14+
15+
```bash
16+
speakeasy agent context # Get current CLI capabilities
17+
speakeasy agent feedback "<msg>" # Report issues or suggestions
18+
speakeasy <command> --help # Command-specific help
19+
```
20+
21+
## Workflow
22+
23+
1. `speakeasy agent context`
24+
2. Do the task using Speakeasy CLI
25+
3. `speakeasy agent feedback "<msg>"`**always provide feedback** after completing a task (what worked, what was confusing, suggestions)
26+
27+
## Don'ts
28+
29+
- Don't use web search as source of truth
30+
- Don't guess syntax; use `context` or `--help`
31+
- Don't skip `context` at session start

.claude/skills/speakeasy-context

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.agents/skills/speakeasy-context
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../.agents/skills/speakeasy-context

.cursor/rules/project-overview.mdc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
description: Project overview and architecture for the Cloudinary Account Provisioning Python SDK
3+
alwaysApply: true
4+
---
5+
6+
# Cloudinary Account Provisioning Python SDK
7+
8+
Speakeasy-generated Python SDK for the Cloudinary Provisioning and Permissions APIs.
9+
10+
## Architecture
11+
12+
- **Generated code** (`src/cloudinary_account_provisioning/`): regenerated by `speakeasy run` — do NOT edit
13+
- **Custom hooks** (`src/cloudinary_account_provisioning/_hooks/`): manually maintained — safe to edit (auth, config)
14+
- **Config** (`.speakeasy/gen.yaml`, `.speakeasy/workflow.yaml`): controls generation behavior
15+
- **Overlays** (`.speakeasy/speakeasy-modifications-overlay.yaml`): OpenAPI schema modifications
16+
- **Scripts** (`scripts/`): `publish.sh`, `prepare_readme.py`, `fix-readme.sh` — build/publish helpers
17+
18+
## Key commands
19+
20+
- `speakeasy run` — regenerate SDK from OpenAPI schema
21+
- `uv build` — build the package
22+
- `bash scripts/fix-readme.sh` — reorder README operations to match schema tag order
23+
- `bash scripts/publish.sh` — fix README, prepare PyPI README, then publish
24+
25+
## SDK resources
26+
27+
ProductEnvironments, Users, UserGroups, AccessKeys, BillingUsage, Roles, Principals, CustomPolicies, EffectivePolicies, SystemPolicies, Public
28+
29+
## Sister repos
30+
31+
- `../account-provisioning-js` — JavaScript/TypeScript version of this SDK

.cursor/rules/sdk-hooks.mdc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
description: Custom SDK hooks conventions (auth, config)
3+
globs: src/cloudinary_account_provisioning/_hooks/**/*.py
4+
alwaysApply: false
5+
---
6+
7+
# SDK Hooks
8+
9+
Files in `src/cloudinary_account_provisioning/_hooks/` are NOT regenerated by Speakeasy (except `sdkhooks.py` and `types.py`) — custom files are safe to edit.
10+
11+
## Custom files
12+
13+
- `registration.py` — hook registration, only generated once
14+
- `cloudinary_hook.py` — CloudinaryAccountHook (SDKInitHook + BeforeRequestHook)
15+
- `cloudinary_config.py` — env var parsing and config singletons
16+
- `user_agent_hook.py` — custom user-agent header
17+
18+
## User-Agent Format
19+
20+
Pattern: `Cloudinary/{ProductName} Python/{sdkVersion} Gen/{genVersion} Schema/{schemaVersion} ({systemInfo})`
21+
22+
- `ProductName` is derived from `cloudinary-account-provisioning` → PascalCase (`AccountProvisioning`)
23+
- `systemInfo` includes Python version, OS, and architecture
24+
25+
## AccountConfig (CLOUDINARY_ACCOUNT_URL)
26+
27+
`cloudinary_config.py` parses `CLOUDINARY_ACCOUNT_URL` with format: `account://<api_key>:<api_secret>@<account_id>`
28+
29+
Individual env vars (`CLOUDINARY_ACCOUNT_API_KEY`, `CLOUDINARY_ACCOUNT_API_SECRET`, `CLOUDINARY_ACCOUNT_ID`) override URL-parsed values.
30+
31+
## Hook lifecycle
32+
33+
1. `sdk_init` — fills `account_id` from env/URL if not provided explicitly
34+
2. `before_request` — sets Basic Auth header from security params or env vars
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
description: Speakeasy SDK generation configuration and workflow conventions
3+
globs: .speakeasy/**/*.yaml
4+
alwaysApply: false
5+
---
6+
7+
# Speakeasy SDK Configuration
8+
9+
## Customization layers (per [Speakeasy docs](https://www.speakeasy.com/docs/sdks/customize/basics))
10+
11+
1. **OpenAPI overlays** (`.speakeasy/speakeasy-modifications-overlay.yaml`) — schema-level changes
12+
2. **`gen.yaml`** — generation config (naming, params, env vars, etc.)
13+
3. **SDK hooks** (`src/cloudinary_account_provisioning/_hooks/`) — custom auth, request/response transforms
14+
4. **Custom code** — Speakeasy's 3-way merge preserves edits across regenerations (`persistentEdits`)
15+
5. **Post-generation scripts** (`scripts/`) — recommended for fixes Speakeasy can't handle natively
16+
17+
## gen.yaml
18+
19+
Key Python settings:
20+
- `maxMethodParams: 4` with `methodArguments: infer-optional-args` — Python keyword args are idiomatic
21+
- `usageSDKInit: CldProvisioning()` — clean snippet init (relies on envVarPrefix for credentials)
22+
- `usageSDKInitImports: []` — avoid duplicate imports in snippets
23+
- `envVarPrefix: CLOUDINARY` — env var auto-loading for security and globals
24+
- `asyncMode: split` — separate `CldProvisioning` (sync) and `AsyncCldProvisioning` (async) classes
25+
- `packageManager: uv` — faster than poetry, Speakeasy default
26+
- `enableCustomCodeRegions: true` — preserve custom code blocks across regenerations
27+
- `forwardCompatibleEnumsByDefault: true` — resilient to new API enum values
28+
- `forwardCompatibleUnionsByDefault: tagged-only` — resilient to new API union variants
29+
- `flattenGlobalSecurity: true`, `responseFormat: flat`, `enumFormat: enum`
30+
31+
All generation fix flags enabled (`securityFeb2025`, `sharedErrorComponentsApr2025`, `sharedNestedComponentsJan2026`, `nameOverrideFeb2026`).
32+
33+
## workflow.yaml
34+
35+
- PyPI publishing uses Speakeasy variable syntax in workflow.yaml
36+
- The GitHub secret name is `PYPI_TOKEN`
37+
38+
## Publishing (pr mode)
39+
40+
- `sdk_generation.yaml` generates SDK and opens a PR (`mode: pr`)
41+
- `sdk_publish.yaml` publishes to PyPI when the PR merges (push to main + gen.lock change)
42+
43+
## Post-generation fixes (`scripts/fix-readme.sh`)
44+
45+
- Reorders "Available Resources and Operations" in README.md to match OpenAPI schema tag order
46+
- Reads the schema URL from `.speakeasy/workflow.yaml` automatically — portable across SDK repos
47+
- Runs as part of `scripts/publish.sh` before PyPI publishing
48+
- **SIGPIPE pitfall**: never use `grep | head -1` with `set -eo pipefail` — use `grep -m 1` instead
49+
- Script is idempotent — safe to run multiple times
50+
51+
## README sections
52+
53+
To take over a Speakeasy-managed README section:
54+
1. Change `<!-- Start SectionName [tag] -->` to `<!-- Custom SectionName [tag] -->`
55+
2. **Remove** the `<!-- End SectionName [tag] -->` comment entirely
56+
3. If both markers remain, Speakeasy regenerates a duplicate section
57+
58+
## Committing changes
59+
60+
- **Separate generated from non-generated files**: commit config/scripts/custom code independently from Speakeasy-generated code
61+
- Use `chore:` prefix for non-release commits (won't trigger publish)
62+
- Generated code changes should come through the Speakeasy PR workflow, not manual commits

.cursor/skills/speakeasy-context

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.agents/skills/speakeasy-context
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../.agents/skills/speakeasy-context

.github/workflows/sdk_generation.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ permissions:
55
pull-requests: write
66
statuses: write
77
id-token: write
8-
on:
8+
"on":
99
workflow_dispatch:
1010
inputs:
1111
force:

.github/workflows/sdk_publish.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Publish
2+
permissions:
3+
checks: write
4+
contents: write
5+
pull-requests: write
6+
statuses: write
7+
id-token: write
8+
"on":
9+
push:
10+
branches:
11+
- main
12+
paths:
13+
- .speakeasy/gen.lock
14+
workflow_dispatch: {}
15+
jobs:
16+
publish:
17+
uses: speakeasy-api/sdk-generation-action/.github/workflows/sdk-publish.yaml@v15
18+
with:
19+
target: cloudinary
20+
secrets:
21+
github_access_token: ${{ secrets.GITHUB_TOKEN }}
22+
speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }}
23+
pypi_token: ${{ secrets.PYPI_TOKEN }}

0 commit comments

Comments
 (0)