Skip to content

Commit

Permalink
code and docs more robust
Browse files Browse the repository at this point in the history
- handle better special characters
- improved readibility
  • Loading branch information
onmax committed Jan 22, 2023
1 parent d2a49de commit 6afb625
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 30 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,21 @@ steps:
issue_number: ${{ github.event.issue.number }}

# Examples on how to use the output
- name: Show parsed payload
- name: Show parsed payload data
run: |
echo "${{ toJson(steps.parse.outputs.payload) }}"
- name: Show 'Name' field
run: |
echo "${{ steps.parse.outputs.payload['Name'] }}"
# Using the character `'` to prevent all characters enclosed within
# them from being treated as special characters (e.g. $ or `)
echo '${{ steps.parse.outputs.payload }}'
# Print the value of the "Name" field
echo '${{ fromJson(steps.parse.outputs.payload)["Name"] }}'
```
## ⚠️ Limitations
- The action only works with issues, not pull requests.
- **The `issue_number` input is required.** If the event that trigger the workflow is not an issue, you need to specify the issue number manually.
- **The returned `payload` is a string.** You need to use `toJson` to convert it to a JSON object. Read more about [GitHub Actions expressions](https://docs.github.com/en/actions/learn-github-actions/expressions#tojson).
- **The returned `payload` is a string.** You need to use `fromJson` to convert it to a JSON object. Read more about [GitHub Actions expressions](https://docs.github.com/en/actions/learn-github-actions/expressions#fromJson).
- Checkboxes are not supported. If you need to use checkboxes, you can create a PR or use the [`peter-murray/issue-forms-body-parser@v3.0.0`](/~https://github.com/peter-murray/issue-forms-body-parser)

## Example
Expand Down
13 changes: 11 additions & 2 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { expect, test } from "@jest/globals";
import { parseBody } from "../src/parser";

test("One section", async () => {
const body = "### name1\r\n\r\nvalue 1";
const res = parseBody(body);
const expected = {
name1: "value 1",
};
expect(res).toEqual(expected);
});

test("Normal body", async () => {
const body = "### name1\r\n\r\nvalue1\r\n\r\n### This is a longer section\r\n\r\nWith a longer answers!!\n\r\n\rBut it works!!\r\n\r\n### name3\r\n\r\nvalue3";
const res = parseBody(body);
const expected = {
name1: "value1",
"This is a longer section": "With a longer answers!!\n\r\n\rBut it works!!",
"This is a longer section": "With a longer answers\!\!\n\r\n\rBut it works\!\!",
name3: "value3",
};
expect(res).toEqual(expected);
Expand Down Expand Up @@ -38,6 +47,6 @@ test("Body with SVG as HTML", async () => {
test("Invalid body", async () => {
const body = "# This does not have h1.\r\n\r\nAnd this\r\n\r\n## h2";
expect(() => parseBody(body)).toThrowError(
"No section in the form."
"Invalid issue body format"
);
});
48 changes: 39 additions & 9 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export async function getIssueBody(githubToken: string, issueNumber: number): Pr
if (!issueNumber) {
throw new Error('Issue number is not defined.');
}
core.debug(`Fetching issue body with issue number ${issueNumber} in ${github.context.repo.owner}/${github.context.repo.repo}`);

core.debug(`Fetching issue body with issue number ${issueNumber} in ${github.context.repo.owner}/${github.context.repo.repo}`);
core.debug(`Github token: ${githubToken}`);
core.debug(`Issue number: ${issueNumber}`);

Expand Down
35 changes: 24 additions & 11 deletions src/parser.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
import * as core from "@actions/core"
import { sanitazeString } from "./util";

type IssueFormPayload = Record<string, string | undefined>

// SectionNameOneWord\r\n\r\nvalue => ["SectionNameOneWord", "value"]
// SectionName\r\n\r\nsection value option 1 => ["SectionName", "section value option 1"]
// SectionNameUndefinedValue\r\n\r\n => ["SectionNameUndefinedValue", undefined]
function parseSection(section: string): { name: string, value?: string } {
console
const trimmed = section.trim();
const sanitazed = sanitazeString(section);

// Split on the first \r\n\r\n
const re = /\r\n\r\n/;
const split = trimmed.search(re);
return split !== -1 // True? Has a name and value
? { name: trimmed.substring(0, split), value: trimmed.substring(split + 1).trim() }
: { name: trimmed, value: undefined };
const split = sanitazed.search(re);

if (split !== -1) {
// There is an answer
const name = sanitazed.substring(0, split);
const value = sanitazed.substring(split + 1).trim();
return { name, value };
} else {
// No answer
return { name: sanitazed, value: undefined };
}
}

// ### NameSection1\r\n\r\nvalue1\r\n\r\n ### NameSection2\r\n\r\nvalue2: With a long value\r\n\r\n### NameSection3\r\n\r\n
// => { NameSection1: "value1", NameSection2: "value2: With a long value", NameSection3: undefined }
export function parseBody(body: string): IssueFormPayload {
core.debug(`Body: ${body}`)
const sections = body.split("###").filter((s) => s.trim().length > 0);
core.debug(`Found ${sections.length} sections in the form.`);

if (sections.length < 2) {
throw new Error(`No section in the form. Make sure to have '###' in the body of your issue. What we got ${body}`);
if (!body.startsWith("###")) {
throw new Error(`
Invalid issue body format. Body must start with '###' followed by the name of the section and its value.
See /~https://github.com/onmax/issue-form-parser/issues. The body we got is: ${body}
`);
}

const sections = body.split("###").filter((s) => s.trim().length > 0);
core.debug(`Found ${sections.length} sections in the form.`);

const res: IssueFormPayload = {};
sections.map(parseSection).forEach(({ name, value }) => res[name] = value);

core.debug(`Payload JSON: ${JSON.stringify(res)}`);

return res;
}
7 changes: 7 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Some characters are not treated well in Bash, so we sanitize them
// For example, the use of ` will break the workflow if you try to print it
export function sanitazeString(value: string) {
let trimmed = value.trim();
const bashChars = ["`", "$"];
return bashChars.reduce((acc, char) => acc.replace(char, ""), trimmed).trim();
}

0 comments on commit 6afb625

Please sign in to comment.