diff --git a/.claude/commands/release.md b/.claude/commands/release.md new file mode 100644 index 000000000..675098eed --- /dev/null +++ b/.claude/commands/release.md @@ -0,0 +1,170 @@ +You are an interactive release assistant for the hellosign-openapi SDK release process. Guide the user through each step, running automatable parts and pausing for human decisions. + +## Your role + +- Walk through the release steps sequentially +- Run checks and validations automatically where possible +- Surface errors early before they propagate +- Never proceed to the next step without confirming the current one succeeded +- Ask before any destructive or irreversible action (force push, publishing, etc.) + +## Release steps + +Work through these steps in order. At each step, explain what you're about to do, do the automatable parts, validate the result, and confirm with the user before moving on. + +### Step 1: Assess current state + +Run these checks and report: +- Current branch and clean working tree status +- What's on `main` vs `oas-release` (commits ahead/behind) +- Current SDK versions in `sdks/*/VERSION` +- Whether `openapi-raw.yaml` has uncommitted upstream changes + +Ask the user: "Which commits from main do you want to release?" or "Do you want to release the full main delta?" + +### Step 2: Promote commits to oas-release + +Based on the user's answer: +- If specific commits: cherry-pick them onto `oas-release` +- If full delta: prepare a merge + +Before pushing, show the user what will land on `oas-release` and get confirmation. + +### Step 3: Determine version bumps + +For each SDK that has changes, ask: +- Show what changed in that SDK's generated code +- Recommend MAJOR/MINOR/PATCH based on the change type: + - New endpoint or breaking param change → MAJOR + - New optional param, new response field → MINOR + - Bug fix, doc change, no surface change → PATCH +- Let the user override + +### Step 4: Bump versions + +For each SDK being released: +- Update `sdks//VERSION` with the new version (remove `-dev` suffix for release) +- Update the version field in `sdks//openapi-config.yaml` (field name varies: `npmVersion`, `packageVersion`, `artifactVersion`, `gemVersion`) +- Verify both files agree + +### Step 5: Regenerate SDKs + +Run: +``` +./generate-sdks -t all +``` + +Check the output for errors. Report what changed. + +### Step 6: Commit and push version bump on oas-release + +Stage and commit the version bump + regenerated code. Push to `oas-release`. + +### Step 7: Copy SDKs to public repos + +For each SDK being released: +``` +./copy-sdks -t -v +``` + +Then for each, show the diff in `repos//` and confirm before creating the release branch and PR. + +### Step 8: Create release PRs + +For each SDK, in `repos//`: +- Create branch `release-` +- Commit with message "Release : " +- Open PR with customer-facing title and description + +Remind the user: no internal context, tickets, or PII in PR descriptions. + +### Step 9: Validate with sdk-tester (manual) + +Remind the user to run sdk-tester validation: +``` +cd sdk-tester +./build --local ../openapi/hellosign-openapi/repos/ +./run --sdk= --auth_type=apikey --auth_key="$HELLO_SIGN_QA_KEY" --server=api.qa-hellosign.com --json="${PWD}/test_fixtures/.json" +``` + +Ask which SDKs passed and note any failures. + +### Step 10: Post-merge verification + +After the user confirms PRs are merged: +- Check that GitHub Actions published each package +- Provide links to verify on each registry: + - npm: https://www.npmjs.com/package/@dropbox/sign + - PyPI: https://pypi.org/project/dropbox-sign/ + - Packagist: https://packagist.org/packages/dropbox/sign + - RubyGems: https://rubygems.org/gems/dropbox-sign + - Maven Central: https://mvnrepository.com/artifact/com.dropbox.sign/dropbox-sign + - NuGet: https://www.nuget.org/packages/Dropbox.Sign + +### Step 11: Documentation (Fern) + +Remind the user to: +- Copy `openapi.yaml` into the Fern docs repo: `cp openapi.yaml /fern/openapi.yaml` +- Add a changelog entry under `fern/pages/changelog/` +- Preview locally with `fern docs dev` +- Open a PR — get approval from API Support or Sign API Team +- On merge, the deploy workflow publishes to developers.hellosign.com +- NEVER run `fern generate --docs` without `--preview` — it publishes straight to production + +## Safety rules + +- Never use production API keys +- Never run `fern generate --docs` without `--preview` +- Never overwrite a published package version +- Always use `test_mode: true` in test fixtures +- Strip internal context from anything customer-facing (no Jira tickets, internal URLs, PII, feature-flag names, customer emails/account IDs) +- Use placeholders: `test_user@example.com`, `test_account_id`, `api.hellosign.com` +- If a publish fails, fix forward with a patch — don't retry the same version +- Releases are forward-only — published packages cannot be recalled, only deprecated + +## Important notes + +- `java-v1` uses branch `v1` of the same `dropbox-sign-java` repo (legacy OpenAPI). `java-v2` uses `main`. +- The version field name in `openapi-config.yaml` varies: `npmVersion` (node), `packageVersion` (python, php), `artifactVersion` (java-v1, java-v2), `gemVersion` (ruby). For dotnet check the config. +- Current dev baselines: dotnet `2.1-dev`, java-v2 `2.6-dev`, java-v1/node/php/python/ruby `1.10-dev` +- The older runbook references `./generate-sdk` (singular) — that's a typo; use `./generate-sdks` +- Package manager credentials are in LastPass under "APITeamStuff_LastPass" (npm/Packagist/PyPI/RubyGems/Maven). NuGet creds are separate — ask #ask-sign-support. + +## Suggestions to surface when relevant + +These are not fixed steps — raise them as suggestions when the situation calls for it. + +### Branch hygiene: main vs oas-release divergence + +In Step 1, always run `git log --oneline origin/main..origin/oas-release` to detect commits on `oas-release` that aren't on `main`. If there are any beyond version bumps, flag this to the user with a count and summary. + +The healthy state is: +- `oas-release` should be a fast-forward subset of `main`, plus release-only version bump commits on top +- Cherry-picking creates duplicate SHAs that accumulate divergence and cause merge conflicts over time +- Prefer merge-based promotion (like PR #370 / #498) over cherry-pick when possible + +When divergence exists, actively recommend a promotion strategy: +- If divergence is small (< 5 commits, all version bumps): cherry-pick is fine +- If divergence is complex (both branches have unique real commits): recommend a merge PR to bring main into oas-release, with potential conflict resolution — do not assume cherry-pick will be clean +- Show the user both options and let them decide + +Suggest: +- After a release, merge the version bump back to main (incrementing to next `-dev`) to keep branches in sync +- If divergence has accumulated, consider a one-time "Merge oas-release -> main" PR to re-sync before the next release +- If the user still wants cherry-pick, warn that it will add to divergence + +### Filtering commits for release + +Not all main commits belong on `oas-release`. When listing commits, call out which ones are: +- **Tooling/infra only** (reformatting, CI changes, OSEG, redoc-container) — these typically don't need to be released unless they affect generated SDK output +- **SDK-affecting** (new fields, endpoints, bug fixes) — these are release candidates + +Suggest the user skip tooling commits unless they've verified the generated output changed. + +### Current branch check + +If the user invokes `/release` while not on `main` or `oas-release`, warn them immediately and ask whether to switch. The release flow operates on those two branches — running it from a feature branch will produce misleading state assessments. + +## Starting the flow + +Begin by running the Step 1 checks and presenting the current state to the user. Ask what they'd like to release. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..b26da5ad7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,104 @@ +# hellosign-openapi + +Central repo for the Dropbox Sign (HelloSign) OpenAPI spec and SDK generation. + +## What this repo does + +- Holds the generated `openapi-raw.yaml` (from the `sign` PHP repo), translates it into `openapi.yaml` and `openapi-sdk.yaml` +- Generates all public SDKs from the spec into `sdks//` +- Copies finalized SDK code into per-language public repos via `repos//` + +## Key scripts + +| Script | Purpose | +|--------|---------| +| `./build` | Translate spec, produce `openapi.yaml` + `openapi-sdk.yaml`, copy examples into sandboxes | +| `./generate-sdks -t ` | Regenerate SDK code under `sdks/` | +| `./copy-sdks -t -v ` | Copy built SDK into `repos//` (clones public repo if needed) | + +## SDKs + +Languages: `dotnet`, `java-v1`, `java-v2`, `node`, `php`, `python`, `ruby` + +Each SDK has: +- `sdks//VERSION` — current version string +- `sdks//openapi-config.yaml` — generator config (version field name varies by language: `npmVersion`, `packageVersion`, `artifactVersion`, `gemVersion`) + +Both files must agree on the version number. SDKs version independently following SemVer. + +## Branches + +- `main` — development branch. Merging here does not release anything. +- `oas-release` — release branch. SDK releases are cut from here via cherry-pick or merge PR. + +## Expected directory layout + +``` +~/Projects/ +├── sign/ (dropbox-internal/sign — PHP monorepo, private) +├── openapi/ +│ └── hellosign-openapi/ (this repo, public) +│ └── repos/ +│ ├── dotnet/ +│ ├── java-v1/ (branch v1 of dropbox-sign-java) +│ ├── java-v2/ (default main branch) +│ ├── node/ +│ ├── php/ +│ ├── python/ +│ └── ruby/ +└── sdk-tester/ (hellosign/sdk-tester — public) +``` + +## Related repos + +| Repo | Purpose | +|------|---------| +| `dropbox-internal/sign` | PHP API source; `./scripts/bin/openapi-generate` produces `openapi-raw.yaml` | +| `hellosign/dropbox-sign-dotnet` | NuGet: `Dropbox.Sign` | +| `hellosign/dropbox-sign-java` | Maven: `com.dropbox.sign:dropbox-sign` (branch `main` = v2, branch `v1` = legacy) | +| `hellosign/dropbox-sign-node` | npm: `@dropbox/sign` | +| `hellosign/dropbox-sign-php` | Packagist: `dropbox/sign` | +| `hellosign/dropbox-sign-python` | PyPI: `dropbox-sign` | +| `hellosign/dropbox-sign-ruby` | RubyGems: `dropbox-sign` | +| `hellosign/sdk-tester` | Integration test harness against QA/staging | +| Fern docs repo | Builds developers.hellosign.com | + +## Translations + +`translations/en.yaml` maps translation keys to English strings (or markdown file paths). If `./build` reports "Untranslated strings", add missing keys here, grouped near related strings. + +## Public repo rules + +All repos this project touches are public. Never commit: +- Customer emails, account IDs, internal hostnames, Slack URLs, Jira tickets +- Tracing IDs, feature-flag names, screenshots of internal tools +- Use `test_user@example.com`, `test_account_id`, `api.hellosign.com` as placeholders + +## CI expectations + +PRs on this repo must have no uncommitted diffs after running `./build && ./generate-sdks -t all`. CI enforces this. + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `./build` lists "Untranslated" strings | Add to `translations/en.yaml`, rerun `./build` | +| CI says "uncommitted changes" | Rerun `./build && ./generate-sdks -t all` locally, commit the diff | +| `./copy-sdks` fails "no such directory" | Clone missing SDK repo into `repos/` | +| sdk-tester Docker build hangs on Maven | See sdk-tester README troubleshooting section | +| Node SDK dependencies stale | Dependabot/Renovate not yet enabled; bump manually in release PR | + +## Obsolete repos (do not use) + +Anything named `HelloFax/*`, `hellosign/hellosign--sdk`, `dropbox-internal/sign-sdk-tester`, or `HelloFax/sdk-tester` is archived. + +The older runbook references `./generate-sdk` (singular) — that's a typo; the real script is `./generate-sdks`. + +## Release flow + +Use the `/release` slash command for an interactive guided release. + +## Team contacts + +- **Sign API team** — owns the spec, monorepo, and release cut. Slack: `#ask-sign` +- **API Support** — co-owns SDK quality, reviews Fern PRs. Slack: `#ask-sign-support`