Skip to content
check-square

GitHub Action

IssueOps Form Parser

v4.0.0 Latest version

IssueOps Form Parser

check-square

IssueOps Form Parser

Convert issue form responses to JSON

Installation

Copy and paste the following snippet into your .yml file.

              

- name: IssueOps Form Parser

uses: issue-ops/[email protected]

Learn more about this action in issue-ops/parser

Choose a version

IssueOps Parser

Check dist/ Code Coverage CodeQL Continuous Integration Continuous Delivery Linter

Convert issue form responses to JSON

About

This action is designed to be used in conjunction with issue forms to allow you to parse created issues into machine-readable JSON for processing.

Issues submitted using issue forms use a structured Markdown format. So long as the issue body is not heavily modified by the user, we can reliably parse the issue body into a JSON object.

You can use this action to conditionally run steps in a workflow based on the contents of the issue body. For example, you may want to run a step only if the issue body contains a specific keyword, version number, etc.

Setup

Here is a simple example of how to use this action in your workflow. Make sure to replace vX.X.X with the latest version of this action.

steps:
  - name: Parse Issue
    id: parser
    uses: issue-ops/[email protected]
    with:
      body: ${{ github.event.issue.body }}

  - name: Output Issue JSON
    id: output-issue
    run: echo ${{ steps.parser.outputs.json }}

Inputs

Input Description
body The issue body to parse
Default: ${{ github.event.issue.body }}
issue-form-template The issue form template file
e.g. example.yml
workspace The checkout path on the runner
Default: ${{ github.workspace }}

Outputs

Output Description
json The parsed issue as a JSON string

Example

Given an example issue template and the following issue submitted with that template:

### The Name of the Thing

this-thing

### The Nickname of the Thing

thing

### The Color of the Thing

blue

### The Shape of the Thing

square

### The Sounds of the Thing

re, mi

### The Topics About the Thing

_No response_

### The Description of the Thing

This is a description.

It has lines.

### The Notes About the Thing

- Note
- Another note
- Lots of notes

### The Code of the Thing

const thing = new Thing()

thing.doThing()

### The String Method of the Code of the Thing

thing.toString()

### Is the Thing a Thing?

- [x] Yes
- [x] No

### Is the Thing Useful?

- [ ] Yes
- [x] Sometimes
- [ ] No

### Read Team

IssueOps-Demo-Readers

### Write Team

IssueOps-Demo-Writers-NotATeam

The output of this action would be:

{
  "name": "this-thing",
  "nickname": "thing",
  "color": ["blue"],
  "shape": ["square"],
  "sounds": ["re", "mi"],
  "topics": [],
  "description": "This is a description.\n\nIt has multiple lines.\n\nIt's pretty cool!",
  "notes": "- Note\n- Another note\n- Lots of notes",
  "code": "const thing = new Thing()\nthing.doThing()",
  "code-string": "thing.toString()",
  "is-thing": {
    "selected": ["Yes"],
    "unselected": ["No"]
  },
  "is-thing-useful": {
    "selected": ["Sometimes"],
    "unselected": ["Yes", "No"]
  },
  "read-team": "IssueOps-Demo-Readers",
  "write-team": "IssueOps-Demo-Writers"
}

No Template Provided

The issue-form-template input is optional. If not provided, the action will still parse the issue body, however the output will be a flat JSON object. The object keys will be slugified versions of the headers, and the values will be the contents of the headers.

Using the same example as above, the output would instead be:

{
  "the_name_of_the_thing": "this-thing",
  "the_nickname_of_the_thing": "thing",
  "the_color_of_the_thing": "blue",
  "the_shape_of_the_thing": "square",
  "the_sounds_of_the_thing": "re, mi",
  "the_topics_about_the_thing": "_No response_",
  "the_description_of_the_thing": "This is a description.\n\nIt has multiple lines.\n\nIt's pretty cool!",
  "the_notes_about_the_thing": "- Note\n- Another note\n- Lots of notes",
  "the_code_of_the_thing": "const thing = new Thing()\nthing.doThing()",
  "the_string_method_of_the_code_of_the_thing": "thing.toString()",
  "is_the_thing_a_thing": "- [x] Yes\n- [ ] No",
  "is_the_thing_useful": "- [ ] Yes\n- [x] Sometimes\n- [ ] No",
  "read_team": "IssueOps-Demo-Readers",
  "write_team": "IssueOps-Demo-Writers"
}

Transformations

Headings

The following transformations will take place for each heading:

Transformation Before After
Trim ### This is a title! :) This is a title! :)
Lowercase This is a title! :) this is a title! :)
Replace Spaces this is a title! :) this_is__a_title!_:)
Remove Symbols this_is_a_title!_:) this_is__a_title_
Trim Underscores this_is__a_title_ this_is_a_title

Values

The following transformations will take place for responses, depending on the input type. The type is inferred from the issue form template. For information on each specific type, see Syntax for GitHub's form schema.

Single Line

Type: input

Before:

This is a response

After (no change):

This is a response

Multiline

Type: textarea

Note

Empty lines are preserved in multiline responses.

Before:

First line :D

Third line!

After:

First line :D\n\nThird line!

Dropdown Selections

Type: dropdown

Before:

red, blue, green

After:

["red", "blue", "green"]

Checkboxes

Type: checkboxes

Before:

- [x] Pick me!
- [ ] Don't pick me D:

After:

{
  "selected": ["Pick me!"],
  "unselected": ["Don't pick me D:"]
}

Omitting Inputs

In the following situations, an input will be omitted from the output JSON:

Scenario Example
Invalid Heading ## This is invalid
Empty Heading ###
This is a value
No Value ### This is a heading
<empty>
### This is another
This is a value

If a form is submitted with empty field(s), they will be included in the issue body as one of the following:

### Field A

_No response_

### Field B

None

### Field C

<empty>

These will be converted to one of the following, based on the type of input specified in the issue form template:

Type Output
input Empty string ("")
textarea Empty string ("")
dropdown Empty list ([])
checkboxes Empty checkboxes ({ "selected": [], "unselected": []})