Skip to content

Commit c3afa6e

Browse files
authored
feat: GitHubProjectInvalidValueError (#141)
closes #136
1 parent e55dac2 commit c3afa6e

File tree

10 files changed

+268
-244
lines changed

10 files changed

+268
-244
lines changed

README.md

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,10 +1243,160 @@ Example for `error.toHumanMessage()`:
12431243

12441244
> "NOPE" could not be matched with any of the existing field names: "My text", "My number", "My Date". If the field should be considered optional, then set it to "nope: { name: "NOPE", optional: true}
12451245
1246-
#### `GitHubProjectUnknownFieldOptionError`
1246+
#### `GitHubProjectInvalidValueError`
12471247

12481248
Thrown when attempting to set a single select project field to a value that is not included in the field's configured options.
12491249

1250+
```js
1251+
import Project, { GitHubProjectInvalidValueError } from "github-project";
1252+
1253+
try {
1254+
await myScript(new Project(options));
1255+
} catch (error) {
1256+
if (error instanceof GitHubProjectInvalidValueError) {
1257+
analytics.track("GitHubProjectInvalidValueError", {
1258+
fieldName: error.details.field.name,
1259+
userValue: error.details.userValue,
1260+
});
1261+
1262+
myLogger.error(
1263+
{
1264+
code: error.code,
1265+
details: error.details,
1266+
},
1267+
error.toHumanMessage(),
1268+
);
1269+
}
1270+
1271+
throw error;
1272+
}
1273+
```
1274+
1275+
<table>
1276+
<thead align=left>
1277+
<tr>
1278+
<th>
1279+
name
1280+
</th>
1281+
<th>
1282+
type
1283+
</th>
1284+
<th width=100%>
1285+
description
1286+
</th>
1287+
</tr>
1288+
</thead>
1289+
<tbody align=left valign=top>
1290+
<tr>
1291+
<th>
1292+
<code>name</code>
1293+
</th>
1294+
<td>
1295+
<code>constant</code>
1296+
</td>
1297+
<td><code>GitHubProjectInvalidValueError</code></td>
1298+
</tr>
1299+
<tr>
1300+
<th>
1301+
<code>message</code>
1302+
</th>
1303+
<td>
1304+
<code>constant</code>
1305+
</td>
1306+
<td>
1307+
1308+
> User value is incompatible with project field type
1309+
1310+
</td>
1311+
<tr>
1312+
<th>
1313+
<code>details</code>
1314+
</th>
1315+
<td>
1316+
<code>object</code>
1317+
</td>
1318+
<td>
1319+
1320+
Object with error details
1321+
1322+
</td>
1323+
</tr>
1324+
<tr>
1325+
<th>
1326+
<code>details.field</code>
1327+
</th>
1328+
<td>
1329+
<code>object</code>
1330+
</td>
1331+
<td>
1332+
1333+
Object with field details
1334+
1335+
</td>
1336+
</tr>
1337+
<tr>
1338+
<th>
1339+
<code>details.field.id</code>
1340+
</th>
1341+
<td>
1342+
<code>string</code>
1343+
</td>
1344+
<td>
1345+
1346+
`details.field.id` is the project field GraphQL node ID
1347+
1348+
</td>
1349+
</tr>
1350+
<tr>
1351+
<th>
1352+
<code>details.field.name</code>
1353+
</th>
1354+
<td>
1355+
<code>string</code>
1356+
</td>
1357+
<td>
1358+
1359+
The field name as shown in the project
1360+
1361+
</td>
1362+
</tr>
1363+
<tr>
1364+
<th>
1365+
<code>details.field.type</code>
1366+
</th>
1367+
<td>
1368+
<code>string</code>
1369+
</td>
1370+
<td>
1371+
1372+
Is always either `DATE`, `NUMBER`, or `SINGLE_SELECT`. If it's `SINGLE_SELECT`, then the error is a [`GitHubProjectUnknownFieldOptionError`](#githubprojectunknownfieldoptionerror).
1373+
1374+
</td>
1375+
</tr>
1376+
<tr>
1377+
<th>
1378+
<code>details.userValue</code>
1379+
</th>
1380+
<td>
1381+
<code>string</code>
1382+
</td>
1383+
<td>
1384+
1385+
The stringified value set in the API call.
1386+
1387+
</td>
1388+
</tr>
1389+
</tbody>
1390+
</table>
1391+
1392+
Example for `error.toHumanMessage()`:
1393+
1394+
> "unknown" is not compatible with the "My Date" project field
1395+
1396+
#### `GitHubProjectUnknownFieldOptionError`
1397+
1398+
Thrown when attempting to set a single select project field to a value that is not included in the field's configured options. Inherits from [`GitHubProjectInvalidValueError`](#githubprojectinvalidvalueerror).
1399+
12501400
```js
12511401
import Project, { GitHubProjectUnknownFieldOptionError } from "github-project";
12521402

@@ -1358,6 +1508,19 @@ Object with field details
13581508

13591509
The field name as shown in the project
13601510

1511+
</td>
1512+
</tr>
1513+
<tr>
1514+
<th>
1515+
<code>details.field.type</code>
1516+
</th>
1517+
<td>
1518+
<code>constant</code>
1519+
</td>
1520+
<td>
1521+
1522+
`SINGLE_SELECT`
1523+
13611524
</td>
13621525
</tr>
13631526
<tr>

api/errors.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,21 @@ export class GitHubProjectUnknownFieldError extends GitHubProjectError {
3838
}
3939
}
4040

41-
export class GitHubProjectUnknownFieldOptionError extends GitHubProjectError {
41+
export class GitHubProjectInvalidValueError extends GitHubProjectError {
4242
constructor(details) {
43-
super("Project field option cannot be found");
43+
super("User value is incompatible with project field type");
44+
this.details = details;
45+
}
46+
47+
toHumanMessage() {
48+
return `"${this.details.userValue}" is not compatible with the "${this.details.field.name}" project field which expects a value of type "${this.details.field.type}"`;
49+
}
50+
}
51+
52+
export class GitHubProjectUnknownFieldOptionError extends GitHubProjectInvalidValueError {
53+
constructor(details) {
54+
super(details);
55+
this.message = "Project field option cannot be found";
4456
this.details = details;
4557
}
4658

api/lib/get-fields-update-query-and-fields.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,15 @@ function findFieldOptionIdAndValue(state, field, value) {
197197
return { name, id };
198198
});
199199

200-
throw Object.assign(
201-
new GitHubProjectUnknownFieldOptionError({
202-
field: {
203-
id: field.id,
204-
name: field.name,
205-
options,
206-
},
207-
userValue: value,
208-
})
209-
);
200+
throw new GitHubProjectUnknownFieldOptionError({
201+
field: {
202+
id: field.id,
203+
name: field.name,
204+
type: "SINGLE_SELECT",
205+
options,
206+
},
207+
userValue: value,
208+
});
210209
}
211210

212211
return { id: optionId, value: optionValue };

api/lib/update-project-item-fields.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-check
22

3+
import { GitHubProjectInvalidValueError } from "../../index.js";
34
import { getFieldsUpdateQueryAndFields } from "./get-fields-update-query-and-fields.js";
45
import { getStateWithProjectFields } from "./get-state-with-project-fields.js";
56

@@ -29,10 +30,34 @@ export async function updateItemFields(project, state, itemNodeId, fields) {
2930

3031
const result = getFieldsUpdateQueryAndFields(stateWithFields, existingFields);
3132

32-
await project.octokit.graphql(result.query, {
33-
projectId: stateWithFields.id,
34-
itemId: itemNodeId,
35-
});
33+
try {
34+
await project.octokit.graphql(result.query, {
35+
projectId: stateWithFields.id,
36+
itemId: itemNodeId,
37+
});
38+
} catch (error) {
39+
const isInvalidValueError =
40+
error?.response?.errors?.[0]?.extensions?.code ===
41+
"argumentLiteralsIncompatible";
42+
43+
/* c8 ignore next */
44+
if (!isInvalidValueError) throw error;
45+
46+
const key = error.response.errors[0].path[1];
47+
const field = stateWithFields.fields[key];
48+
49+
throw new GitHubProjectInvalidValueError({
50+
userValue: fields[key],
51+
field: {
52+
// @ts-expect-error
53+
id: field.id,
54+
// @ts-expect-error
55+
name: field.name,
56+
// @ts-expect-error
57+
type: field.dataType,
58+
},
59+
});
60+
}
3661

3762
return result.fields;
3863
}

index.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,29 @@ export declare class GitHubProjectUnknownFieldError<
338338
constructor(details: TDetails);
339339
}
340340

341+
type GitHubProjectInvalidValueErrorDetails = {
342+
userValue: string;
343+
field: {
344+
id: string;
345+
name: string;
346+
type: "NUMBER" | "DATE" | "SINGLE_SELECT";
347+
};
348+
};
349+
350+
export declare class GitHubProjectInvalidValueError<
351+
TDetails extends GitHubProjectInvalidValueErrorDetails,
352+
> extends GitHubProjectError {
353+
name: "GitHubProjectInvalidValueError";
354+
details: TDetails;
355+
constructor(details: TDetails);
356+
}
357+
341358
type GitHubProjectUnknownFieldOptionErrorDetails = {
342359
userValue: string;
343360
field: {
344361
id: string;
345362
name: string;
363+
type: "SINGLE_SELECT";
346364
options: {
347365
id: string;
348366
name: string;

index.test-d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import GitHubProject, {
44
GitHubProjectError,
55
GitHubProjectNotFoundError,
66
GitHubProjectUnknownFieldError,
7+
GitHubProjectInvalidValueError,
78
GitHubProjectUnknownFieldOptionError,
89
GitHubProjectUpdateReadOnlyFieldError,
910
} from "./index";
@@ -682,11 +683,28 @@ export function testGitHubProjectUnknownFieldError() {
682683
expectType<string>(error.toHumanMessage());
683684
}
684685

686+
export function testGitHubProjectInvalidValueError() {
687+
const details = {
688+
field: {
689+
id: "field id",
690+
name: "field name",
691+
type: "DATE" as const,
692+
},
693+
userValue: "invalid",
694+
};
695+
const error = new GitHubProjectInvalidValueError(details);
696+
697+
expectType<"GitHubProjectInvalidValueError">(error.name);
698+
expectType<typeof details>(error.details);
699+
expectType<string>(error.toHumanMessage());
700+
}
701+
685702
export function testGitHubProjectUnknownFieldOptionError() {
686703
const details = {
687704
field: {
688705
id: "field id",
689706
name: "field name",
707+
type: "SINGLE_SELECT" as const,
690708
options: [
691709
{
692710
id: "option id",

test/recorded/api.items.add-draft-with-invalid-date/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function test(project) {
1010
},
1111
(error) => ({
1212
error,
13-
// humanMessage: error.toHumanMessage(),
13+
humanMessage: error.toHumanMessage(),
1414
})
1515
);
1616
}

test/recorded/api.items.update-with-invalid-field-option/test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// @ts-check
22

3+
import { GitHubProjectInvalidValueError } from "../../../index.js";
4+
35
/**
46
* @param {import("../../../").default} project
57
* @param {string} [itemId]
@@ -12,6 +14,8 @@ export function test(project, itemId = "PVTI_1") {
1214
(error) => ({
1315
error,
1416
humanMessage: error.toHumanMessage(),
17+
isInstanceOfGitHubProjectInvalidValueError:
18+
error instanceof GitHubProjectInvalidValueError,
1519
})
1620
);
1721
}

0 commit comments

Comments
 (0)