Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions .claude/commands/release.md
Original file line number Diff line number Diff line change
@@ -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/<sdk>/VERSION` with the new version (remove `-dev` suffix for release)
- Update the version field in `sdks/<sdk>/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 <sdk> -v <new-version>
```

Then for each, show the diff in `repos/<sdk>/` and confirm before creating the release branch and PR.

### Step 8: Create release PRs

For each SDK, in `repos/<sdk>/`:
- Create branch `release-<version>`
- Commit with message "Release <version>: <summary>"
- 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/<sdk> <sdk>
./run --sdk=<sdk> --auth_type=apikey --auth_key="$HELLO_SIGN_QA_KEY" --server=api.qa-hellosign.com --json="${PWD}/test_fixtures/<fixture>.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-repo>/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.
104 changes: 104 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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/<lang>/`
- Copies finalized SDK code into per-language public repos via `repos/<lang>/`

## Key scripts

| Script | Purpose |
|--------|---------|
| `./build` | Translate spec, produce `openapi.yaml` + `openapi-sdk.yaml`, copy examples into sandboxes |
| `./generate-sdks -t <sdk\|all>` | Regenerate SDK code under `sdks/` |
| `./copy-sdks -t <sdk> -v <version>` | Copy built SDK into `repos/<sdk>/` (clones public repo if needed) |

## SDKs

Languages: `dotnet`, `java-v1`, `java-v2`, `node`, `php`, `python`, `ruby`

Each SDK has:
- `sdks/<sdk>/VERSION` — current version string
- `sdks/<sdk>/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-<lang>-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`
Loading