From 74a5c2bd524890543a8838e159b57a573b89a99d Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Fri, 31 Jan 2025 11:45:00 +0000 Subject: [PATCH] Fix commits with only filesToDelete --- create-or-update-files.js | 60 ++++++++++++++++++---------------- create-or-update-files.test.js | 49 +++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 29 deletions(-) diff --git a/create-or-update-files.js b/create-or-update-files.js index 838597f..a698c18 100644 --- a/create-or-update-files.js +++ b/create-or-update-files.js @@ -165,35 +165,37 @@ module.exports = function (octokit, opts) { } } - for (const batch of chunk(Object.keys(change.files), batchSize)) { - await Promise.all( - batch.map(async (fileName) => { - const properties = change.files[fileName] || ""; - - const contents = properties.contents || properties; - const mode = properties.mode || "100644"; - const type = properties.type || "blob"; - - if (!contents) { - return reject(`No file contents provided for ${fileName}`); - } - - const fileSha = await createBlob( - octokit, - owner, - repo, - contents, - type, - ); - - treeItems.push({ - path: fileName, - sha: fileSha, - mode: mode, - type: type, - }); - }), - ); + if (hasFiles) { + for (const batch of chunk(Object.keys(change.files), batchSize)) { + await Promise.all( + batch.map(async (fileName) => { + const properties = change.files[fileName] || ""; + + const contents = properties.contents || properties; + const mode = properties.mode || "100644"; + const type = properties.type || "blob"; + + if (!contents) { + return reject(`No file contents provided for ${fileName}`); + } + + const fileSha = await createBlob( + octokit, + owner, + repo, + contents, + type, + ); + + treeItems.push({ + path: fileName, + sha: fileSha, + mode: mode, + type: type, + }); + }), + ); + } } // no need to issue further requests if there are no updates, creations and deletions diff --git a/create-or-update-files.test.js b/create-or-update-files.test.js index 69ffe07..beb9d9e 100644 --- a/create-or-update-files.test.js +++ b/create-or-update-files.test.js @@ -442,6 +442,29 @@ test("success (fileToDelete exists)", async () => { await expect(run(body)).resolves.toEqual(mockSecondCommitList); }); +test("success (fileToDelete exists, no content provided)", async () => { + mockGetRef(branch, `sha-${branch}`, false); + mockGetRef(base, `sha-${base}`, true); + mockGetContents("wow-this-file-disappeared", `sha-${base}`, true); + mockCreateTreeWithDeleteOnly(`sha-${base}`); + mockCommitSecond(`sha-${base}`); + mockCreateRefSecond(branch); + + const changes = [ + { + message: "This is the second commit", + filesToDelete: ["wow-this-file-disappeared"], + }, + ]; + + const body = { + ...validRequest, + changes, + }; + + await expect(run(body)).resolves.toEqual(mockSecondCommitList); +}); + test("failure (fileToDelete is missing)", async () => { mockGetRef(branch, `sha-${branch}`, false); mockGetRef(base, `sha-${base}`, true); @@ -658,6 +681,32 @@ function mockCreateTreeWithIgnoredDelete(baseTree) { m.reply(200, body); } +function mockCreateTreeWithDeleteOnly(baseTree) { + // The order here is important. Removals must be applied before creations + const expectedBody = { + tree: [ + { + path: "wow-this-file-disappeared", + sha: null, + mode: "100644", + type: "commit", + }, + ], + base_tree: baseTree, + }; + + const m = nock("https://api.github.com").post( + `/repos/${owner}/${repo}/git/trees`, + expectedBody, + ); + + const body = { + sha: "fffff6bbf5ab983d31b1cca28e204b71ab722764", + }; + + m.reply(200, body); +} + function mockCreateTreeWithDelete(baseTree) { // The order here is important. Removals must be applied before creations const expectedBody = {