-
Notifications
You must be signed in to change notification settings - Fork 309
chore(cli): migrate @fern-api/ir-generator to use CliError #15004
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 all commits
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,7 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WebSocketChannelId | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "@fern-api/ir-sdk"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { FilteredIr, getOriginalName, IdGenerator } from "@fern-api/ir-utils"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { CliError } from "@fern-api/task-context"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { mapValues } from "lodash-es"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type UnprocessedPackage = Omit<Package, "hasEndpointsInTree">; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -40,7 +41,10 @@ export class PackageTreeGenerator { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public addPackageRedirection({ from, to }: { from: FernFilepath; to: FernFilepath }): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const package_ = this.getPackageForFernFilepath(from); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (package_.navigationConfig != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Found duplicate navigationConfig for package"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Found duplicate navigationConfig for package", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package_.navigationConfig = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pointsTo: IdGenerator.generateSubpackageId(to) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -50,7 +54,7 @@ export class PackageTreeGenerator { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public addDocs(fernFilepath: FernFilepath, docs: string): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const package_ = this.getPackageForFernFilepath(fernFilepath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (package_.docs != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Found duplicate docs for package"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ message: "Found duplicate docs for package", code: CliError.Code.InternalError }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package_.docs = docs; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -70,23 +74,32 @@ export class PackageTreeGenerator { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public addService(serviceId: ServiceId, service: HttpService): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const package_ = this.getPackageForFernFilepath(service.name.fernFilepath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (package_.service != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Found duplicate service for " + serviceId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Found duplicate service for " + serviceId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package_.service = serviceId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public addWebhookGroup(webhookGroupId: WebhookGroupId, fernFilepath: FernFilepath): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const package_ = this.getPackageForFernFilepath(fernFilepath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (package_.webhooks != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Found duplicate webhook group for " + webhookGroupId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Found duplicate webhook group for " + webhookGroupId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package_.webhooks = webhookGroupId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public addWebSocketChannel(websocketChannelId: WebSocketChannelId, fernFilepath: FernFilepath): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const package_ = this.getPackageForFernFilepath(fernFilepath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (package_.webhooks != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Found duplicate webhook group for " + websocketChannelId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Found duplicate webhook group for " + websocketChannelId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+88
to
+102
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. The // Should be:
if (package_.websocket != null) {
throw new CliError({
message: "Found duplicate websocket channel for " + websocketChannelId,
code: CliError.Code.InternalError
});
}Note: This is a pre-existing bug in the original code (line 88-89), but the PR changes the error on lines 99-102 without fixing it.
Suggested change
Spotted by Graphite |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package_.websocket = websocketChannelId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -152,26 +165,35 @@ export class PackageTreeGenerator { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public sortRootPackage(subpackagesInOrder: SubpackageId[]): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isEqualIgnoreOrder(this.rootPackage.subpackages, subpackagesInOrder)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Sorted subpackages differ from unsorted packages in root"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Sorted subpackages differ from unsorted packages in root", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.rootPackage.subpackages = subpackagesInOrder; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public sortSubpackage(subpackageId: SubpackageId, subpackagesInOrder: SubpackageId[]): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const subpackage = this.subpackages[subpackageId]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (subpackage == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Subpackage does not exist: " + subpackageId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Subpackage does not exist: " + subpackageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.ResolutionError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isEqualIgnoreOrder(subpackage.subpackages, subpackagesInOrder)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Sorted subpackages differ from unsorted packages"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Sorted subpackages differ from unsorted packages", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| subpackage.subpackages = subpackagesInOrder; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private getAllSubpackagesWithEndpoints(root: SubpackageId): SubpackageId[] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const subpackage = this.subpackages[root]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (subpackage == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Subpackage does not exist: " + root); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ message: "Subpackage does not exist: " + root, code: CliError.Code.ResolutionError }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const subpackagesWithEndpoints = this.getAllChildrenWithEndpoints(subpackage); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -200,7 +222,10 @@ export class PackageTreeGenerator { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const subpackagesInParent = parent.subpackages.map((subpackageId) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const subpackage = this.subpackages[subpackageId]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (subpackage == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error("Subpackage ID is invalid: " + subpackageId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new CliError({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Subpackage ID is invalid: " + subpackageId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: CliError.Code.InternalError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return subpackage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this PR, these throws were plain
Errorobjects.resolveErrorCode()inCliError.tsresolves unknown errors toUnclassified, for whichshouldReportToSentry()returnsfalse. After this PR they areCliErrorwithInternalErrororResolutionErrorcodes, both of which haveshouldReportToSentry() = true. The full error (including its.message) is then sent to Sentry viacaptureExceptionin thecatchblock insiderunInteractiveTask.Error messages that now reach Sentry include user-supplied API definition identifiers:
serviceId,webhookGroupId,websocketChannelId,subpackageId(this file), plusJSON.stringify(endpointDeclaration)inconvertTransport.tsand type/wire-key names in several other migrated files. TheSENTRY_DSNis baked into the production CLI binary at publish time (see.github/workflows/publish-cli.yml), so this affects all users who have not setFERN_DISABLE_TELEMETRY=true.Concrete impact: proprietary API definition names and structure are sent to Fern's Sentry instance whenever these error paths are hit, which was not the case before this PR.
Prompt To Fix With AI
Severity: low | Confidence: 78%