From 66ffdc2fd606d1dbe7071e51a49e4513029797c1 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 26 Apr 2024 18:50:31 +0200 Subject: [PATCH 1/3] feat: improve body parsing logic Current body parsing logic with trim() + split("###") is too fragile and pose problems with some body that contains case with ### in the middle of the line or case with codeblock ``` section. These case will cause the script to parse these as separate section and produce wrong outputs and in some case even prints error assuming things are checkbox and errors out on the concat function. To make the parsing logic more solid, implement a dedicated function and parse with this logic: - We split the body for "\n" - We ignore codeblock ``` section - We check "###" only at the start of the line - We check for "### " (with the space included) as that is the correct section Github issue template expects. With the following change case like: ``` root@OpenWrt:~# cat /boot/config.txt ``` Are correctly parsed as all part of a single section instead of being wrongly treated as different empty sections. Signed-off-by: Christian Marangi --- index.js | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 5af14eb..07cfb53 100644 --- a/index.js +++ b/index.js @@ -111,9 +111,35 @@ async function run(env, body, fs, core) { return result } - result = body - .trim() - .split("###") + function parseBody(body) { + let result = []; + let ignore = false; + + body.split("\n").reduce((str, line, idx, arr) => { + // ``` Section must be ignored and not parsed as new section + if (line == "```") + ignore = !ignore + + // Parse new setion only if they start with ### SPACE + if (!ignore && line.startsWith("### ")) { + result.push(str.trim()) + + return line.replace(/^### /, "")+"\n"; + } + + str += line + "\n" + + // Push the last string if we are at the end of lines + if (arr.length - 1 == idx) + result.push(str.trim()) + + return str; + }, "") + + return result; + } + + result = parseBody(body) .filter(Boolean) .map((line) => { return line From 4a7eb3ed4f82c91f2dcd5e24b528eec3de0895cd Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 26 Apr 2024 18:57:19 +0200 Subject: [PATCH 2/3] feat: add additional test for section with #### Add additional test for section with #### to prevent and catch in future code change that would produce wrong parsing. Signed-off-by: Christian Marangi --- .../paragraph-confusing-####/expected.json | 3 ++ fixtures/paragraph-confusing-####/form.yml | 9 +++++ .../paragraph-confusing-####/issue-body.md | 3 ++ fixtures/paragraph-confusing-####/issue.js | 6 +++ test.spec.js | 39 +++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 fixtures/paragraph-confusing-####/expected.json create mode 100644 fixtures/paragraph-confusing-####/form.yml create mode 100644 fixtures/paragraph-confusing-####/issue-body.md create mode 100644 fixtures/paragraph-confusing-####/issue.js diff --git a/fixtures/paragraph-confusing-####/expected.json b/fixtures/paragraph-confusing-####/expected.json new file mode 100644 index 0000000..34954d8 --- /dev/null +++ b/fixtures/paragraph-confusing-####/expected.json @@ -0,0 +1,3 @@ +{ + "textarea-one": "Textarea input text 1 ####" +} diff --git a/fixtures/paragraph-confusing-####/form.yml b/fixtures/paragraph-confusing-####/form.yml new file mode 100644 index 0000000..cb5bf9f --- /dev/null +++ b/fixtures/paragraph-confusing-####/form.yml @@ -0,0 +1,9 @@ +body: + - type: textarea + id: textarea-one + attributes: + label: My textarea input + - type: textarea + id: textarea-two + attributes: + label: Another textarea input diff --git a/fixtures/paragraph-confusing-####/issue-body.md b/fixtures/paragraph-confusing-####/issue-body.md new file mode 100644 index 0000000..38a4b14 --- /dev/null +++ b/fixtures/paragraph-confusing-####/issue-body.md @@ -0,0 +1,3 @@ +### My textarea input + +Textarea input text 1 #### diff --git a/fixtures/paragraph-confusing-####/issue.js b/fixtures/paragraph-confusing-####/issue.js new file mode 100644 index 0000000..6851c74 --- /dev/null +++ b/fixtures/paragraph-confusing-####/issue.js @@ -0,0 +1,6 @@ +const { resolve } = require("path"); +const { readFileSync } = require("fs"); + +const issueBodyPath = resolve(__dirname, "issue-body.md"); + +module.exports = readFileSync(issueBodyPath, "utf-8") diff --git a/test.spec.js b/test.spec.js index adbd4ec..f3f1a61 100644 --- a/test.spec.js +++ b/test.spec.js @@ -130,6 +130,45 @@ it("multiple paragraphs", () => { expect(core.setOutput.mock.calls.length).toBe(3) }); +it("paragraph with confusing ####", () => { + const expectedOutput = require("./fixtures/paragraph-confusing-####/expected.json"); + const expectedOutputJson = JSON.stringify(expectedOutput, null, 2); + + // mock ENV + const env = { + HOME: "", + }; + + // mock event payload + const eventPayload = require("./fixtures/paragraph-confusing-####/issue"); + + // mock fs + const fs = { + readFileSync(path, encoding) { + expect(path).toBe(""); + expect(encoding).toBe("utf8"); + return readFileSync("fixtures/paragraph-confusing-####/form.yml", "utf-8"); + }, + writeFileSync(path, content) { + expect(path).toBe("/issue-parser-result.json"); + expect(content).toBe(expectedOutputJson); + }, + }; + + // mock core + const core = { + getInput: jest.fn(() => ''), + setOutput: jest.fn(), + }; + + run(env, eventPayload, fs, core); + + expect(core.getInput).toHaveBeenCalledWith('template-path') + expect(core.setOutput).toHaveBeenCalledWith('jsonString', JSON.stringify(expectedOutput, null, 2)) + expect(core.setOutput).toHaveBeenCalledWith('issueparser_textarea-one', 'Textarea input text 1 ####') + expect(core.setOutput.mock.calls.length).toBe(2) +}); + it("blank", () => { const expectedOutput = require("./fixtures/blank/expected.json"); const expectedOutputJson = JSON.stringify(expectedOutput, null, 2); From 7b837e5b71ccbfd8b2744481ab7a3ea7d66a8589 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 26 Apr 2024 18:58:26 +0200 Subject: [PATCH 3/3] feat: add additional test for codeblock ``` ignore Add test for codeblock ``` ignore to prevent and catch in future code change that would produce wrong parsing. Signed-off-by: Christian Marangi --- fixtures/paragraph-ignore-```/expected.json | 3 ++ fixtures/paragraph-ignore-```/form.yml | 9 +++++ fixtures/paragraph-ignore-```/issue-body.md | 7 ++++ fixtures/paragraph-ignore-```/issue.js | 6 ++++ test.spec.js | 39 +++++++++++++++++++++ 5 files changed, 64 insertions(+) create mode 100644 fixtures/paragraph-ignore-```/expected.json create mode 100644 fixtures/paragraph-ignore-```/form.yml create mode 100644 fixtures/paragraph-ignore-```/issue-body.md create mode 100644 fixtures/paragraph-ignore-```/issue.js diff --git a/fixtures/paragraph-ignore-```/expected.json b/fixtures/paragraph-ignore-```/expected.json new file mode 100644 index 0000000..2f8fdda --- /dev/null +++ b/fixtures/paragraph-ignore-```/expected.json @@ -0,0 +1,3 @@ +{ + "textarea-one": "Textarea input text 1\n\n```\n### To be ignored tag\n```" +} diff --git a/fixtures/paragraph-ignore-```/form.yml b/fixtures/paragraph-ignore-```/form.yml new file mode 100644 index 0000000..cb5bf9f --- /dev/null +++ b/fixtures/paragraph-ignore-```/form.yml @@ -0,0 +1,9 @@ +body: + - type: textarea + id: textarea-one + attributes: + label: My textarea input + - type: textarea + id: textarea-two + attributes: + label: Another textarea input diff --git a/fixtures/paragraph-ignore-```/issue-body.md b/fixtures/paragraph-ignore-```/issue-body.md new file mode 100644 index 0000000..ebe88ce --- /dev/null +++ b/fixtures/paragraph-ignore-```/issue-body.md @@ -0,0 +1,7 @@ +### My textarea input + +Textarea input text 1 + +``` +### To be ignored tag +``` diff --git a/fixtures/paragraph-ignore-```/issue.js b/fixtures/paragraph-ignore-```/issue.js new file mode 100644 index 0000000..6851c74 --- /dev/null +++ b/fixtures/paragraph-ignore-```/issue.js @@ -0,0 +1,6 @@ +const { resolve } = require("path"); +const { readFileSync } = require("fs"); + +const issueBodyPath = resolve(__dirname, "issue-body.md"); + +module.exports = readFileSync(issueBodyPath, "utf-8") diff --git a/test.spec.js b/test.spec.js index f3f1a61..51ca14a 100644 --- a/test.spec.js +++ b/test.spec.js @@ -169,6 +169,45 @@ it("paragraph with confusing ####", () => { expect(core.setOutput.mock.calls.length).toBe(2) }); +it("paragraph with ``` section", () => { + const expectedOutput = require("./fixtures/paragraph-ignore-```/expected.json"); + const expectedOutputJson = JSON.stringify(expectedOutput, null, 2); + + // mock ENV + const env = { + HOME: "", + }; + + // mock event payload + const eventPayload = require("./fixtures/paragraph-ignore-```/issue"); + + // mock fs + const fs = { + readFileSync(path, encoding) { + expect(path).toBe(""); + expect(encoding).toBe("utf8"); + return readFileSync("fixtures/paragraph-ignore-```/form.yml", "utf-8"); + }, + writeFileSync(path, content) { + expect(path).toBe("/issue-parser-result.json"); + expect(content).toBe(expectedOutputJson); + }, + }; + + // mock core + const core = { + getInput: jest.fn(() => ''), + setOutput: jest.fn(), + }; + + run(env, eventPayload, fs, core); + + expect(core.getInput).toHaveBeenCalledWith('template-path') + expect(core.setOutput).toHaveBeenCalledWith('jsonString', JSON.stringify(expectedOutput, null, 2)) + expect(core.setOutput).toHaveBeenCalledWith('issueparser_textarea-one', 'Textarea input text 1\n\n```\n### To be ignored tag\n```') + expect(core.setOutput.mock.calls.length).toBe(2) +}); + it("blank", () => { const expectedOutput = require("./fixtures/blank/expected.json"); const expectedOutputJson = JSON.stringify(expectedOutput, null, 2);