From bbee6d65410332edb38bbebed62006ffa4bcc6f5 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Fri, 17 Jan 2025 22:50:32 -0800 Subject: [PATCH] feat: add fail-if-item-not-found input to more actions --- .github/workflows/integration-tests.yml | 33 +++++++++++++++++++++++++ __tests__/delete-item.test.mts | 14 ++++++++++- __tests__/edit-item.test.mts | 14 ++++++++++- __tests__/get-item.test.mts | 14 ++++++++++- delete-item/README.md | 1 + delete-item/action.yml | 4 +++ dist/delete-item.js | 8 +++--- dist/edit-item.js | 8 +++--- dist/get-item.js | 8 +++--- edit-item/README.md | 1 + edit-item/action.yml | 4 +++ get-item/README.md | 1 + get-item/action.yml | 4 +++ src/delete-item.ts | 5 +++- src/edit-item.ts | 3 ++- src/get-item.ts | 3 ++- 16 files changed, 110 insertions(+), 15 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 78e6c71..d6ada44 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -172,6 +172,18 @@ jobs: project-number: ${{ steps.copy-project.outputs.number }} token: ${{ steps.get-auth-token.outputs.token }} + - name: Edit Item (Not Found) + uses: ./edit-item/ + id: edit-item-not-found + with: + fail-if-item-not-found: false + field: Priority + field-value: ⛰️ High + item: foobar + owner: ${{ steps.copy-project.outputs.owner }} + project-number: ${{ steps.copy-project.outputs.number }} + token: ${{ steps.get-auth-token.outputs.token }} + - name: Get Item uses: ./get-item/ id: get-edited-item @@ -182,6 +194,17 @@ jobs: project-number: ${{ steps.copy-project.outputs.number }} token: ${{ steps.get-auth-token.outputs.token }} + - name: Get Item (Not Found) + uses: ./get-item/ + id: get-item-not-found + with: + fail-if-item-not-found: false + field: Priority + item: foobar + owner: ${{ steps.copy-project.outputs.owner }} + project-number: ${{ steps.copy-project.outputs.number }} + token: ${{ steps.get-auth-token.outputs.token }} + - name: Check Edited Item Field Value uses: ./github-script/ with: @@ -236,6 +259,16 @@ jobs: project-number: ${{ steps.copy-project.outputs.number }} token: ${{ steps.get-auth-token.outputs.token }} + - name: Delete Item (Not Found) + uses: ./delete-item/ + id: delete-item-not-found + with: + item: foobar + fail-if-item-not-found: false + owner: ${{ steps.copy-project.outputs.owner }} + project-number: ${{ steps.copy-project.outputs.number }} + token: ${{ steps.get-auth-token.outputs.token }} + - name: Link Project to Repository uses: ./link-project/ id: link-project-to-repo diff --git a/__tests__/delete-item.test.mts b/__tests__/delete-item.test.mts index 8a1e302..9c0be91 100644 --- a/__tests__/delete-item.test.mts +++ b/__tests__/delete-item.test.mts @@ -4,7 +4,7 @@ import * as core from '@actions/core'; import * as index from '../src/delete-item.js'; import { ItemDetails, deleteItem, getItem } from '../src/lib.js'; -import { mockGetInput } from './utils.js'; +import { mockGetBooleanInput, mockGetInput } from './utils.js'; vi.mock('@actions/core'); vi.mock('../src/lib'); @@ -60,6 +60,18 @@ describe('deleteItemAction', () => { expect(core.setFailed).toHaveBeenLastCalledWith(`Item not found: ${item}`); }); + it('can ignore item not found', async () => { + mockGetInput({ owner, 'project-number': projectNumber, item }); + mockGetBooleanInput({ 'fail-if-item-not-found': false }); + vi.mocked(getItem).mockResolvedValue(null); + + await index.deleteItemAction(); + expect(deleteItemActionSpy).toHaveReturned(); + + expect(core.setFailed).not.toHaveBeenCalled(); + expect(core.setOutput).not.toHaveBeenCalled(); + }); + it('handles project not found', async () => { mockGetInput({ owner, 'project-number': projectNumber, item }); vi.mocked(getItem).mockResolvedValue({ id: itemId } as ItemDetails); diff --git a/__tests__/edit-item.test.mts b/__tests__/edit-item.test.mts index ce53940..7fef351 100644 --- a/__tests__/edit-item.test.mts +++ b/__tests__/edit-item.test.mts @@ -4,7 +4,7 @@ import * as core from '@actions/core'; import * as index from '../src/edit-item.js'; import { ItemDetails, editItem, getItem } from '../src/lib.js'; -import { mockGetInput } from './utils.js'; +import { mockGetBooleanInput, mockGetInput } from './utils.js'; vi.mock('@actions/core'); vi.mock('../src/lib'); @@ -95,6 +95,18 @@ describe('editItemAction', () => { expect(core.setFailed).toHaveBeenLastCalledWith(`Item not found: ${item}`); }); + it('can ignore item not found', async () => { + mockGetInput({ owner, 'project-number': projectNumber, item }); + mockGetBooleanInput({ 'fail-if-item-not-found': false }); + vi.mocked(getItem).mockResolvedValue(null); + + await index.editItemAction(); + expect(editItemActionSpy).toHaveReturned(); + + expect(core.setFailed).not.toHaveBeenCalled(); + expect(core.setOutput).not.toHaveBeenCalled(); + }); + it('handles project not found', async () => { mockGetInput({ owner, 'project-number': projectNumber, item }); vi.mocked(getItem).mockResolvedValue({ diff --git a/__tests__/get-item.test.mts b/__tests__/get-item.test.mts index 1c32fd0..927f315 100644 --- a/__tests__/get-item.test.mts +++ b/__tests__/get-item.test.mts @@ -4,7 +4,7 @@ import * as core from '@actions/core'; import * as index from '../src/get-item.js'; import { getItem } from '../src/lib.js'; -import { mockGetInput } from './utils.js'; +import { mockGetBooleanInput, mockGetInput } from './utils.js'; vi.mock('@actions/core'); vi.mock('../src/lib'); @@ -61,6 +61,18 @@ describe('getItemAction', () => { expect(core.setFailed).toHaveBeenLastCalledWith(`Item not found: ${item}`); }); + it('can ignore item not found', async () => { + mockGetInput({ owner, 'project-number': projectNumber, item }); + mockGetBooleanInput({ 'fail-if-item-not-found': false }); + vi.mocked(getItem).mockResolvedValue(null); + + await index.getItemAction(); + expect(getItemActionSpy).toHaveReturned(); + + expect(core.setFailed).not.toHaveBeenCalled(); + expect(core.setOutput).not.toHaveBeenCalled(); + }); + it('handles project not found', async () => { mockGetInput({ owner, 'project-number': projectNumber, item }); vi.mocked(getItem).mockImplementation(() => { diff --git a/delete-item/README.md b/delete-item/README.md index 5b4f358..6cf84d0 100644 --- a/delete-item/README.md +++ b/delete-item/README.md @@ -16,6 +16,7 @@ Can not delete archived items due to a bug in the GitHub GraphQL API, see input.trim()); } exports2.getMultilineInput = getMultilineInput; - function getBooleanInput(name, options) { + function getBooleanInput2(name, options) { const trueValue = ["true", "True", "TRUE"]; const falseValue = ["false", "False", "FALSE"]; const val = getInput3(name, options); @@ -18923,7 +18923,7 @@ var require_core = __commonJS({ throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name} Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); } - exports2.getBooleanInput = getBooleanInput; + exports2.getBooleanInput = getBooleanInput2; function setOutput(name, value) { const filePath = process.env["GITHUB_OUTPUT"] || ""; if (filePath) { @@ -23812,9 +23812,11 @@ async function deleteItemAction() { const owner = core2.getInput("owner", { required: true }); const projectNumber = core2.getInput("project-number", { required: true }); const item = core2.getInput("item", { required: true }); + const failIfItemNotFound = core2.getBooleanInput("fail-if-item-not-found"); const fullItem = await getItem(owner, projectNumber, item); if (!fullItem) { - core2.setFailed(`Item not found: ${item}`); + if (failIfItemNotFound) + core2.setFailed(`Item not found: ${item}`); return; } await deleteItem(owner, projectNumber, fullItem.id); diff --git a/dist/edit-item.js b/dist/edit-item.js index 70e7939..1b374ad 100644 --- a/dist/edit-item.js +++ b/dist/edit-item.js @@ -18912,7 +18912,7 @@ var require_core = __commonJS({ return inputs.map((input) => input.trim()); } exports2.getMultilineInput = getMultilineInput; - function getBooleanInput(name, options) { + function getBooleanInput2(name, options) { const trueValue = ["true", "True", "TRUE"]; const falseValue = ["false", "False", "FALSE"]; const val = getInput3(name, options); @@ -18923,7 +18923,7 @@ var require_core = __commonJS({ throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name} Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); } - exports2.getBooleanInput = getBooleanInput; + exports2.getBooleanInput = getBooleanInput2; function setOutput2(name, value) { const filePath = process.env["GITHUB_OUTPUT"] || ""; if (filePath) { @@ -23944,13 +23944,15 @@ async function editItemAction() { const body = core2.getInput("body"); const field = core2.getInput("field"); const fieldValue = core2.getInput("field-value", { required: !!field }); + const failIfItemNotFound = core2.getBooleanInput("fail-if-item-not-found"); if (!!fieldValue && !field) { core2.setFailed("Input required and not supplied: field"); return; } const fullItem = await getItem(owner, projectNumber, item); if (!fullItem) { - core2.setFailed(`Item not found: ${item}`); + if (failIfItemNotFound) + core2.setFailed(`Item not found: ${item}`); return; } if (fullItem.content.type !== "DraftIssue" && (!!title || !!body)) { diff --git a/dist/get-item.js b/dist/get-item.js index 195b317..0c6f4a4 100644 --- a/dist/get-item.js +++ b/dist/get-item.js @@ -18912,7 +18912,7 @@ var require_core = __commonJS({ return inputs.map((input) => input.trim()); } exports2.getMultilineInput = getMultilineInput; - function getBooleanInput(name, options) { + function getBooleanInput2(name, options) { const trueValue = ["true", "True", "TRUE"]; const falseValue = ["false", "False", "FALSE"]; const val = getInput3(name, options); @@ -18923,7 +18923,7 @@ var require_core = __commonJS({ throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name} Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); } - exports2.getBooleanInput = getBooleanInput; + exports2.getBooleanInput = getBooleanInput2; function setOutput2(name, value) { const filePath = process.env["GITHUB_OUTPUT"] || ""; if (filePath) { @@ -23798,9 +23798,11 @@ async function getItemAction() { const projectNumber = core2.getInput("project-number", { required: true }); const item = core2.getInput("item", { required: true }); const field = core2.getInput("field") || void 0; + const failIfItemNotFound = core2.getBooleanInput("fail-if-item-not-found"); const fullItem = await getItem(owner, projectNumber, item, field); if (!fullItem) { - core2.setFailed(`Item not found: ${item}`); + if (failIfItemNotFound) + core2.setFailed(`Item not found: ${item}`); return; } core2.setOutput("id", fullItem.id); diff --git a/edit-item/README.md b/edit-item/README.md index 40c9188..3159120 100644 --- a/edit-item/README.md +++ b/edit-item/README.md @@ -20,6 +20,7 @@ Can not edit archived items due to a bug in the GitHub GraphQL API, see { const projectNumber = core.getInput('project-number', { required: true }); const item = core.getInput('item', { required: true }); + // Optional inputs + const failIfItemNotFound = core.getBooleanInput('fail-if-item-not-found'); + // Item might be the item ID, the content ID, or the content URL const fullItem = await getItem(owner, projectNumber, item); if (!fullItem) { - core.setFailed(`Item not found: ${item}`); + if (failIfItemNotFound) core.setFailed(`Item not found: ${item}`); return; } diff --git a/src/edit-item.ts b/src/edit-item.ts index 105d3ae..9824666 100644 --- a/src/edit-item.ts +++ b/src/edit-item.ts @@ -14,6 +14,7 @@ export async function editItemAction(): Promise { const body = core.getInput('body'); const field = core.getInput('field'); const fieldValue = core.getInput('field-value', { required: !!field }); + const failIfItemNotFound = core.getBooleanInput('fail-if-item-not-found'); if (!!fieldValue && !field) { core.setFailed('Input required and not supplied: field'); @@ -24,7 +25,7 @@ export async function editItemAction(): Promise { const fullItem = await getItem(owner, projectNumber, item); if (!fullItem) { - core.setFailed(`Item not found: ${item}`); + if (failIfItemNotFound) core.setFailed(`Item not found: ${item}`); return; } diff --git a/src/get-item.ts b/src/get-item.ts index 2d0b4d7..9ea503a 100644 --- a/src/get-item.ts +++ b/src/get-item.ts @@ -11,12 +11,13 @@ export async function getItemAction(): Promise { // Optional inputs const field = core.getInput('field') || undefined; + const failIfItemNotFound = core.getBooleanInput('fail-if-item-not-found'); // Item might be the item ID, the content ID, or the content URL const fullItem = await getItem(owner, projectNumber, item, field); if (!fullItem) { - core.setFailed(`Item not found: ${item}`); + if (failIfItemNotFound) core.setFailed(`Item not found: ${item}`); return; }