Skip to content

Commit 953d82a

Browse files
authored
Throw 400 exposable errors instead of internal errors when Git sync config value are missing/incomplete (#634)
1 parent 2d5ae22 commit 953d82a

File tree

7 files changed

+41
-21
lines changed

7 files changed

+41
-21
lines changed

.changeset/twelve-balloons-help.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@gitbook/integration-github': patch
3+
'@gitbook/integration-gitlab': patch
4+
---
5+
6+
Throw 400 exposable errors instead of internal errors when Git sync config value are missing/incomplete

integrations/github/src/provider.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export async function getGitHubAppJWT(context: GithubRuntimeContext): Promise<st
3939
* Returns the URL of the Git repository.
4040
*/
4141
export function getRepositoryUrl(config: GitHubSpaceConfiguration, withExtension = false): string {
42-
assertIsDefined(config.accountName, { label: 'config.accountName' });
43-
assertIsDefined(config.repoName, { label: 'config.repoName' });
42+
assertIsDefined(config.accountName, { label: 'config.accountName', statusCode: 400 });
43+
assertIsDefined(config.repoName, { label: 'config.repoName', statusCode: 400 });
4444

4545
return `https://github.com/${config.accountName}/${config.repoName}${
4646
withExtension ? '.git' : ''
@@ -54,7 +54,7 @@ export async function getRepositoryAuth(
5454
context: GithubRuntimeContext,
5555
config: GitHubSpaceConfiguration,
5656
) {
57-
assertIsDefined(config.installation, { label: 'config.installation' });
57+
assertIsDefined(config.installation, { label: 'config.installation', statusCode: 400 });
5858

5959
const appJWT = await getGitHubAppJWT(context);
6060
const installationAccessToken = await createAppInstallationAccessToken(
@@ -84,9 +84,9 @@ export async function updateCommitStatus(
8484
description: string;
8585
},
8686
) {
87-
assertIsDefined(config.accountName, { label: 'config.accountName' });
88-
assertIsDefined(config.repoName, { label: 'config.repoName' });
89-
assertIsDefined(config.installation, { label: 'config.installation' });
87+
assertIsDefined(config.accountName, { label: 'config.accountName', statusCode: 400 });
88+
assertIsDefined(config.repoName, { label: 'config.repoName', statusCode: 400 });
89+
assertIsDefined(config.installation, { label: 'config.installation', statusCode: 400 });
9090

9191
const appJWT = await getGitHubAppJWT(context);
9292
const installationAccessToken = await createAppInstallationAccessToken(

integrations/github/src/sync.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function triggerImport(
6868
return;
6969
}
7070

71-
assertIsDefined(config.branch, { label: 'config.branch' });
71+
assertIsDefined(config.branch, { label: 'config.branch', statusCode: 400 });
7272

7373
logger.info(`Initiating an import from GitHub to GitBook space ${spaceId}`);
7474

@@ -130,7 +130,7 @@ export async function triggerExport(
130130
return;
131131
}
132132

133-
assertIsDefined(config.branch, { label: 'config.branch' });
133+
assertIsDefined(config.branch, { label: 'config.branch', statusCode: 400 });
134134

135135
logger.info(`Initiating an export from space ${spaceId} to GitHub`);
136136

integrations/github/src/utils.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GitSyncOperationState, IntegrationSpaceInstallation } from '@gitbook/api';
22

33
import type { GitHubSpaceConfiguration } from './types';
4+
import { ExposableError } from '@gitbook/runtime';
45

56
export const BRANCH_REF_PREFIX = 'refs/heads/';
67

@@ -75,12 +76,17 @@ export function computeConfigQueryKey(
7576

7677
export function assertIsDefined<T>(
7778
value: T,
78-
options: {
79-
label: string;
80-
},
79+
options: { label: string; statusCode?: number },
8180
): asserts value is NonNullable<T> {
81+
const { label, statusCode = 500 } = options;
82+
8283
if (value === undefined || value === null) {
83-
throw new Error(`Expected value (${options.label}) to be defined, but received ${value}`);
84+
const errorMsg = `Expected value (${label}) to be defined, but received ${value}`;
85+
if (statusCode >= 400 && statusCode < 500) {
86+
throw new ExposableError(errorMsg, statusCode);
87+
}
88+
89+
throw new Error(errorMsg);
8490
}
8591
}
8692

integrations/gitlab/src/provider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export async function installWebhook(
2323
) {
2424
const config = getSpaceConfigOrThrow(spaceInstallation);
2525

26-
assertIsDefined(config.project, { label: 'config.project' });
26+
assertIsDefined(config.project, { label: 'config.project', statusCode: 400 });
2727

2828
const projectId = config.project;
2929
const id = await addProjectWebhook(config, config.project, webhookUrl, webhookToken);
@@ -38,8 +38,8 @@ export async function installWebhook(
3838
* project.
3939
*/
4040
export async function uninstallWebhook(config: GitLabSpaceConfiguration) {
41-
assertIsDefined(config.project, { label: 'config.project' });
42-
assertIsDefined(config.webhookId, { label: 'config.webhookId' });
41+
assertIsDefined(config.project, { label: 'config.project', statusCode: 400 });
42+
assertIsDefined(config.webhookId, { label: 'config.webhookId', statusCode: 400 });
4343

4444
const projectId = config.project;
4545
const webhookId = config.webhookId;
@@ -62,7 +62,7 @@ export async function updateCommitStatus(
6262
description: string;
6363
},
6464
) {
65-
assertIsDefined(config.project, { label: 'config.project' });
65+
assertIsDefined(config.project, { label: 'config.project', statusCode: 400 });
6666

6767
const projectId = config.project;
6868

integrations/gitlab/src/sync.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
IntegrationSpaceInstallation,
55
Revision,
66
} from '@gitbook/api';
7-
import { Logger } from '@gitbook/runtime';
7+
import { ExposableError, Logger } from '@gitbook/runtime';
88

99
import {
1010
getGitCommitURL,
@@ -68,7 +68,7 @@ export async function triggerImport(
6868
return;
6969
}
7070

71-
assertIsDefined(config.branch, { label: 'config.branch' });
71+
assertIsDefined(config.branch, { label: 'config.branch', statusCode: 400 });
7272

7373
logger.info(`Initiating an import from GitLab to GitBook space ${spaceId}`);
7474

@@ -130,7 +130,7 @@ export async function triggerExport(
130130
return;
131131
}
132132

133-
assertIsDefined(config.branch, { label: 'config.branch' });
133+
assertIsDefined(config.branch, { label: 'config.branch', statusCode: 400 });
134134

135135
logger.info(`Initiating an export from space ${spaceId} to GitLab`);
136136

integrations/gitlab/src/utils.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { GitSyncOperationState, IntegrationSpaceInstallation } from '@gitbook/api';
22

33
import type { GitLabSpaceConfiguration } from './types';
4+
import { ExposableError } from '@gitbook/runtime';
45

56
export const BRANCH_REF_PREFIX = 'refs/heads/';
67

@@ -100,10 +101,17 @@ export async function verifySignature(
100101

101102
export function assertIsDefined<T>(
102103
value: T,
103-
options: { label: string },
104+
options: { label: string; statusCode?: number },
104105
): asserts value is NonNullable<T> {
106+
const { label, statusCode = 500 } = options;
107+
105108
if (value === undefined || value === null) {
106-
throw new Error(`Expected value (${options.label}) to be defined, but received ${value}`);
109+
const errorMsg = `Expected value (${label}) to be defined, but received ${value}`;
110+
if (statusCode >= 400 && statusCode < 500) {
111+
throw new ExposableError(errorMsg, statusCode);
112+
}
113+
114+
throw new Error(errorMsg);
107115
}
108116
}
109117

0 commit comments

Comments
 (0)