-
Notifications
You must be signed in to change notification settings - Fork 7
Add Fern Replay docs and migration guide #5497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
ed7590a
8d35d23
7863582
aed299f
64c717c
ca8f399
2e882dc
0873572
bd7e450
92a6d94
f1391d8
8882b43
778d1be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,3 +90,4 @@ exceptions: | |
| - OG | ||
| - BCP | ||
| - ISO | ||
| - Replay | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,25 @@ | ||
| --- | ||
| title: Adding custom code | ||
| headline: Adding custom code (overview) | ||
| description: Extend Fern-generated SDKs with custom methods, logic, and dependencies. Use .fernignore to protect your code from being overwritten during regeneration. | ||
| description: Extend Fern-generated SDKs with custom methods, logic, and dependencies. Use Fern Replay for line-level edits and .fernignore for files you own end-to-end. | ||
| --- | ||
|
|
||
|
|
||
| Fern-generated SDKs are designed to be extended with custom logic, methods, and dependencies. If you want your SDK to do more than just make basic API calls (like combining multiple calls, processing data, adding utilities), you can add custom code that lives in harmony with the generated code. | ||
|
|
||
| You can also add custom methods by inheriting the Fern generated client and extending it, plus add any dependencies that your custom methods depend on in your `generators.yml` file. | ||
| Fern provides two complementary tools for keeping your customizations safe across regenerations: | ||
|
|
||
| ## Using `.fernignore` to preserve your customizations | ||
| - **`.fernignore`** — Full-file ownership. The generator stops touching listed files entirely. Use for fully hand-written modules, READMEs, or custom workflows. Trade-off: you also stop receiving generator updates to those files. | ||
| - **Replay** — Line-level edits. Keep generated files under generator control, and reapply your edits via 3-way merge on every regeneration. | ||
|
|
||
| Once you add files containing custom code, use `.fernignore` to protect your custom code from being overwritten when Fern regenerates your SDK. | ||
|
|
||
| Simply add your custom files to the SDK repository and list them in `.fernignore`. Fern won't override any files listed there. A `.fernignore` file is automatically created in your SDK repository when you use GitHub publishing. | ||
| ## Full-file ownership with `.fernignore` | ||
|
|
||
| <Note>`.fernignore` applies only to SDK generation. It has no effect on [Fern Docs](/learn/docs/getting-started/overview) builds.</Note> | ||
|
|
||
| Use `.fernignore` to protect files you own end-to-end from being overwritten during SDK regeneration. | ||
|
|
||
| Add your custom files to the SDK repository and list them in `.fernignore`. A `.fernignore` file is automatically created in your SDK repository when you use GitHub publishing. | ||
|
|
||
| Your `.fernignore` file might look something like this: | ||
|
|
||
| ```gitignore title=".fernignore" | ||
|
|
@@ -31,7 +34,8 @@ LICENSE | |
| # Custom code | ||
| src/CustomClient.ts | ||
| ``` | ||
| <Note>For another example, see Cohere's [`.fernignore` file for their TypeScript SDK](https://github.com/cohere-ai/cohere-typescript/blob/ad583e3003bd51e80a82317f9e16beec85881b86/.fernignore).</Note> | ||
|
|
||
| For another real-world example, see Cohere's [`.fernignore` file for their TypeScript SDK](https://github.com/cohere-ai/cohere-typescript/blob/ad583e3003bd51e80a82317f9e16beec85881b86/.fernignore). | ||
|
|
||
| You'll have a separate `.fernignore` file for each of your SDKs: | ||
|
|
||
|
|
@@ -61,24 +65,39 @@ You'll have a separate `.fernignore` file for each of your SDKs: | |
| </Folder> | ||
| </Files> | ||
|
|
||
| ## Line-level edits with Replay | ||
|
|
||
| <Note title="Requirements"> | ||
| Replay is on by default for SDKs using [`pull-request` output mode](/learn/sdks/reference/generators-yml#pull-request). To enable Replay on an SDK that's currently on `release` or `push` mode, switch to `pull-request` mode via the [migration guide](/learn/sdks/overview/replay-migration). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| Replay requires the latest Fern CLI and SDK generator versions — run `fern upgrade` to make sure you're current. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| </Note> | ||
|
|
||
| Replay automatically preserves the edits you make to your generated SDK across regenerations. When you commit a change to generated code, Replay scans your repo's history since the last `[fern-generated]` commit and stores each customer commit as a tracked patch in `.fern/replay.lock`. On the next `fern generate`, those patches are reapplied to the freshly generated SDK via 3-way merge, and the result lands as a `[fern-replay]` commit on top of `[fern-generated]` in the regeneration PR: | ||
|
|
||
| ```text title="Regeneration PR" | ||
| * abc123 (HEAD -> main) [fern-replay] Apply customizations | ||
| * 789abc [fern-generated] Update SDK to spec rev 0451 | ||
| * 234bcd Add helpers on top of User type | ||
| * ... | ||
| ``` | ||
|
|
||
| If the generator and your customization changed the same lines, Replay reports the conflict in the PR body. Run [`fern replay resolve`](/learn/cli-api-reference/cli-reference/commands#fern-replay-resolve) locally to walk through it. | ||
|
|
||
| ### Disable Replay | ||
|
|
||
| To disable Replay for a specific generator, set `replay.enabled: false` in `generators.yml`. See the [`replay` reference](/learn/sdks/reference/generators-yml#replay) for global and per-generator configuration. | ||
|
|
||
| ## Customization patterns by language | ||
|
|
||
| Each SDK generator has its own conventions for adding custom code: how to extend the generated client, where helpers go, how to declare dependencies. See the guide for your language: | ||
|
|
||
| ## Augmenting your SDK with custom code | ||
|
|
||
| Get started adding custom code to a specific SDK: | ||
|
|
||
| <CardGroup cols={3}> | ||
| <Card title="TypeScript" icon={<img src="./images/icons/ts-light.svg" alt="TypeScript logo" className="h-6 w-6" noZoom />} href="/sdks/generators/typescript/custom-code"> | ||
| </Card> | ||
| <Card title="Python" icon={<img src="./images/icons/python-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/python/custom-code"> | ||
| </Card> | ||
| <Card title="Go" icon={<img src="./images/icons/go-light.svg" className="h-6 w-6" noZoom />} href="/learn/sdks/generators/go/custom-code"> | ||
| </Card> | ||
| <Card title="Java" icon={<img src="./images/icons/java-light.svg" className="h-6 w-6" noZoom />} href="/learn/sdks/generators/java/custom-code"> | ||
| </Card> | ||
| <Card title=".NET" icon={<img src="./images/icons/csharp-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/csharp/custom-code"> | ||
| </Card> | ||
| <Card title="PHP" icon={<img src="./images/icons/php-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/php/custom-code"> | ||
| </Card> | ||
| <Card title="Ruby" icon={<img src="./images/icons/ruby-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/ruby/custom-code"> | ||
| </Card> | ||
| </CardGroup> | ||
| <CardGroup cols={4}> | ||
| <Card title="TypeScript" icon={<img src="./images/icons/ts-light.svg" alt="TypeScript logo" className="h-6 w-6" noZoom />} href="/sdks/generators/typescript/custom-code" /> | ||
| <Card title="Python" icon={<img src="./images/icons/python-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/python/custom-code" /> | ||
| <Card title="Go" icon={<img src="./images/icons/go-light.svg" className="h-6 w-6" noZoom />} href="/learn/sdks/generators/go/custom-code" /> | ||
| <Card title="Java" icon={<img src="./images/icons/java-light.svg" className="h-6 w-6" noZoom />} href="/learn/sdks/generators/java/custom-code" /> | ||
| <Card title=".NET" icon={<img src="./images/icons/csharp-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/csharp/custom-code" /> | ||
| <Card title="PHP" icon={<img src="./images/icons/php-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/php/custom-code" /> | ||
| <Card title="Ruby" icon={<img src="./images/icons/ruby-light.svg" className="h-6 w-6" noZoom />} href="/sdks/generators/ruby/custom-code" /> | ||
| </CardGroup> | ||
Uh oh!
There was an error while loading. Please reload this page.