Skip to content

Commit 2a13ba8

Browse files
authored
Merge branch 'main' into create-pull-request/patch
2 parents eb89587 + 90ee086 commit 2a13ba8

File tree

5 files changed

+158
-8
lines changed

5 files changed

+158
-8
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ jobs:
4949
content_id: ${{ github.event.client_payload.command.resource.id }}
5050
field: Status
5151
value: ${{ github.event.client_payload.data.status }}
52+
- name: Clear due date
53+
id: clear_due_date
54+
uses: github/update-project-action@v3
55+
with:
56+
github_token: ${{ secrets.STATUS_UPDATE_TOKEN }}
57+
organization: github
58+
project_number: 1234
59+
content_id: ${{ github.event.client_payload.command.resource.id }}
60+
field: "Due Date"
61+
operation: clear
5262
```
5363
5464
*Note: The above step can be repeated multiple times in a given job to update multiple fields on the same or different projects.*
@@ -62,10 +72,10 @@ The Action is largely feature complete with regards to its initial goals. Find a
6272
* `content_id` - The global ID of the issue or pull request within the project
6373
* `field` - The field on the project to set the value of
6474
* `github_token` - A GitHub Token with access to both the source issue and the destination project (`repo` and `write:org` scopes)
65-
* `operation` - Operation type (update or read)
75+
* `operation` - Operation type (update, read, or clear)
6676
* `organization` - The organization that contains the project, defaults to the current repository owner
6777
* `project_number` - The project number from the project's URL
68-
* `value` - The value to set the project field to. Only required for operation type read
78+
* `value` - The value to set the project field to. Only required for operation type `update`; not required for `read` or `clear`.
6979

7080
### Outputs
7181

__test__/main.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ describe("with environmental variables", () => {
9393
expect(result.operation).toEqual("read");
9494
});
9595

96+
test("getInputs accepts clear", () => {
97+
process.env = { ...process.env, ...{ INPUT_OPERATION: "clear" } };
98+
const result = updateProject.getInputs();
99+
expect(result.operation).toEqual("clear");
100+
});
101+
96102
test("getInputs doesn't accept other operations", () => {
97103
process.env = { ...process.env, ...{ INPUT_OPERATION: "foo" } };
98104
const result = updateProject.getInputs();
@@ -514,6 +520,41 @@ describe("with Octokit setup", () => {
514520
expect(mock.done()).toBe(true);
515521
});
516522

523+
test("clearField clears a field", async () => {
524+
const item = { project: { number: 1, owner: { login: "github" } } };
525+
mockContentMetadata("test", item);
526+
527+
const field = {
528+
id: 1,
529+
name: "testField",
530+
dataType: "date",
531+
};
532+
mockProjectMetadata(1, field);
533+
534+
const data = { data: { projectV2Item: { id: 1 } } };
535+
mockGraphQL(data, "clearField", "clearProjectV2ItemFieldValue");
536+
537+
const projectMetadata = await updateProject.fetchProjectMetadata(
538+
"github",
539+
1,
540+
"testField",
541+
"",
542+
"clear"
543+
);
544+
const contentMetadata = await updateProject.fetchContentMetadata(
545+
"1",
546+
"test",
547+
1,
548+
"github"
549+
);
550+
const result = await updateProject.clearField(
551+
projectMetadata,
552+
contentMetadata
553+
);
554+
expect(result).toEqual(data.data);
555+
expect(mock.done()).toBe(true);
556+
});
557+
517558
test("run updates a field that was not empty", async () => {
518559
const item = {
519560
field: { value: "testValue" },
@@ -617,4 +658,27 @@ describe("with Octokit setup", () => {
617658
await updateProject.run();
618659
expect(mock.done()).toBe(true);
619660
});
661+
662+
test("run clears a field", async () => {
663+
process.env = { ...OLD_ENV, ...INPUTS, ...{ INPUT_OPERATION: "clear" } };
664+
665+
const item = {
666+
field: { value: "2023-01-01" },
667+
project: { number: 1, owner: { login: "github" } },
668+
};
669+
mockContentMetadata("testField", item);
670+
671+
const field = {
672+
id: 1,
673+
name: "testField",
674+
dataType: "date",
675+
};
676+
mockProjectMetadata(1, field);
677+
678+
const data = { data: { projectV2Item: { id: 1 } } };
679+
mockGraphQL(data, "clearField", "clearProjectV2ItemFieldValue");
680+
681+
await updateProject.run();
682+
expect(mock.done()).toBe(true);
683+
});
620684
});

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ inputs:
99
description: The project number from the project's URL
1010
required: true
1111
operation:
12-
description: Operation type (update or read)
12+
description: Operation type (update, read, or clear)
1313
default: update
1414
required: false
1515
content_id:

dist/index.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10408,7 +10408,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
1040810408
});
1040910409
};
1041010410
Object.defineProperty(exports, "__esModule", ({ value: true }));
10411-
exports.run = exports.setupOctokit = exports.getInputs = exports.updateField = exports.convertValueToFieldType = exports.valueGraphqlType = exports.ensureExists = exports.fetchProjectMetadata = exports.fetchContentMetadata = void 0;
10411+
exports.run = exports.setupOctokit = exports.getInputs = exports.clearField = exports.updateField = exports.convertValueToFieldType = exports.valueGraphqlType = exports.ensureExists = exports.fetchProjectMetadata = exports.fetchContentMetadata = void 0;
1041210412
const core_1 = __nccwpck_require__(2186);
1041310413
const github_1 = __nccwpck_require__(5438);
1041410414
let octokit;
@@ -10648,6 +10648,37 @@ function updateField(projectMetadata, contentMetadata, value) {
1064810648
});
1064910649
}
1065010650
exports.updateField = updateField;
10651+
/**
10652+
* Clears the field value for the content item
10653+
* @param {GraphQlQueryResponseData} projectMetadata - The project metadata returned from fetchProjectMetadata()
10654+
* @param {GraphQlQueryResponseData} contentMetadata - The content metadata returned from fetchContentMetadata()
10655+
* @return {Promise<GraphQlQueryResponseData>} - The updated content metadata
10656+
*/
10657+
function clearField(projectMetadata, contentMetadata) {
10658+
return __awaiter(this, void 0, void 0, function* () {
10659+
const result = yield octokit.graphql(`
10660+
mutation($project: ID!, $item: ID!, $field: ID!) {
10661+
clearProjectV2ItemFieldValue(
10662+
input: {
10663+
projectId: $project
10664+
itemId: $item
10665+
fieldId: $field
10666+
}
10667+
) {
10668+
projectV2Item {
10669+
id
10670+
}
10671+
}
10672+
}
10673+
`, {
10674+
project: projectMetadata.projectId,
10675+
item: contentMetadata.id,
10676+
field: projectMetadata.field.fieldId,
10677+
});
10678+
return result;
10679+
});
10680+
}
10681+
exports.clearField = clearField;
1065110682
/**
1065210683
* Returns the validated and normalized inputs for the action
1065310684
*
@@ -10657,8 +10688,8 @@ function getInputs() {
1065710688
let operation = (0, core_1.getInput)("operation");
1065810689
if (operation === "")
1065910690
operation = "update";
10660-
if (!["read", "update"].includes(operation)) {
10661-
(0, core_1.setFailed)(`Invalid value passed for the 'operation' parameter (passed: ${operation}, allowed: read, update)`);
10691+
if (!["read", "update", "clear"].includes(operation)) {
10692+
(0, core_1.setFailed)(`Invalid value passed for the 'operation' parameter (passed: ${operation}, allowed: read, update, clear)`);
1066210693
return {};
1066310694
}
1066410695
const inputs = {
@@ -10704,6 +10735,11 @@ function run() {
1070410735
(0, core_1.setOutput)("field_updated_value", inputs.value);
1070510736
(0, core_1.info)(`Updated field ${inputs.fieldName} on ${contentMetadata.title} to ${inputs.value}`);
1070610737
}
10738+
else if (inputs.operation === "clear") {
10739+
yield clearField(projectMetadata, contentMetadata);
10740+
(0, core_1.setOutput)("field_updated_value", null);
10741+
(0, core_1.info)(`Cleared field ${inputs.fieldName} on ${contentMetadata.title}`);
10742+
}
1070710743
else {
1070810744
(0, core_1.setOutput)("field_updated_value", (_b = contentMetadata.field) === null || _b === void 0 ? void 0 : _b.value);
1070910745
}

src/update-project.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,42 @@ export async function updateField(
289289
return result;
290290
}
291291

292+
/**
293+
* Clears the field value for the content item
294+
* @param {GraphQlQueryResponseData} projectMetadata - The project metadata returned from fetchProjectMetadata()
295+
* @param {GraphQlQueryResponseData} contentMetadata - The content metadata returned from fetchContentMetadata()
296+
* @return {Promise<GraphQlQueryResponseData>} - The updated content metadata
297+
*/
298+
export async function clearField(
299+
projectMetadata: GraphQlQueryResponseData,
300+
contentMetadata: GraphQlQueryResponseData
301+
): Promise<GraphQlQueryResponseData> {
302+
const result: GraphQlQueryResponseData = await octokit.graphql(
303+
`
304+
mutation($project: ID!, $item: ID!, $field: ID!) {
305+
clearProjectV2ItemFieldValue(
306+
input: {
307+
projectId: $project
308+
itemId: $item
309+
fieldId: $field
310+
}
311+
) {
312+
projectV2Item {
313+
id
314+
}
315+
}
316+
}
317+
`,
318+
{
319+
project: projectMetadata.projectId,
320+
item: contentMetadata.id,
321+
field: projectMetadata.field.fieldId,
322+
}
323+
);
324+
325+
return result;
326+
}
327+
292328
/**
293329
* Returns the validated and normalized inputs for the action
294330
*
@@ -298,9 +334,9 @@ export function getInputs(): { [key: string]: any } {
298334
let operation = getInput("operation");
299335
if (operation === "") operation = "update";
300336

301-
if (!["read", "update"].includes(operation)) {
337+
if (!["read", "update", "clear"].includes(operation)) {
302338
setFailed(
303-
`Invalid value passed for the 'operation' parameter (passed: ${operation}, allowed: read, update)`
339+
`Invalid value passed for the 'operation' parameter (passed: ${operation}, allowed: read, update, clear)`
304340
);
305341

306342
return {};
@@ -361,6 +397,10 @@ export async function run(): Promise<void> {
361397
info(
362398
`Updated field ${inputs.fieldName} on ${contentMetadata.title} to ${inputs.value}`
363399
);
400+
} else if (inputs.operation === "clear") {
401+
await clearField(projectMetadata, contentMetadata);
402+
setOutput("field_updated_value", null);
403+
info(`Cleared field ${inputs.fieldName} on ${contentMetadata.title}`);
364404
} else {
365405
setOutput("field_updated_value", contentMetadata.field?.value);
366406
}

0 commit comments

Comments
 (0)