mirror of
https://github.com/ditkrg/todo-to-issue-action.git
synced 2026-01-25 07:16:42 +00:00
Merge pull request #162 from Christoph-Koschel/patch-1
Escape special Markdown characters
This commit is contained in:
@@ -75,4 +75,8 @@ inputs:
|
|||||||
GITHUB_URL:
|
GITHUB_URL:
|
||||||
description: 'Base url of GitHub API'
|
description: 'Base url of GitHub API'
|
||||||
required: false
|
required: false
|
||||||
default: ${{ github.api_url }}
|
default: ${{ github.api_url }}
|
||||||
|
ESCAPE:
|
||||||
|
description: 'Escape all special Markdown characters'
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
25
main.py
25
main.py
@@ -295,6 +295,9 @@ class TodoParser(object):
|
|||||||
ORG_PROJECTS_PATTERN = re.compile(r'(?<=org projects:\s).+')
|
ORG_PROJECTS_PATTERN = re.compile(r'(?<=org projects:\s).+')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
# Determine if the Issues should be escaped.
|
||||||
|
self.should_escape = os.getenv('INPUT_ESCAPE', 'true') == 'true'
|
||||||
|
|
||||||
# Load any custom identifiers, otherwise use the default.
|
# Load any custom identifiers, otherwise use the default.
|
||||||
custom_identifiers = os.getenv('INPUT_IDENTIFIERS')
|
custom_identifiers = os.getenv('INPUT_IDENTIFIERS')
|
||||||
self.identifiers = ['TODO']
|
self.identifiers = ['TODO']
|
||||||
@@ -530,7 +533,10 @@ class TodoParser(object):
|
|||||||
elif org_projects:
|
elif org_projects:
|
||||||
issue.org_projects.extend(org_projects)
|
issue.org_projects.extend(org_projects)
|
||||||
elif len(cleaned_line):
|
elif len(cleaned_line):
|
||||||
issue.body.append(cleaned_line)
|
if self.should_escape:
|
||||||
|
issue.body.append(self._escape_markdown(cleaned_line))
|
||||||
|
else:
|
||||||
|
issue.body.append(cleaned_line)
|
||||||
|
|
||||||
if issue is not None and issue.identifier is not None and self.identifiers_dict is not None:
|
if issue is not None and issue.identifier is not None and self.identifiers_dict is not None:
|
||||||
for identifier_dict in self.identifiers_dict:
|
for identifier_dict in self.identifiers_dict:
|
||||||
@@ -541,6 +547,23 @@ class TodoParser(object):
|
|||||||
|
|
||||||
return issue
|
return issue
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _escape_markdown(comment):
|
||||||
|
# All basic characters according to: https://www.markdownguide.org/basic-syntax
|
||||||
|
must_escaped = ['\\', '<', '>', '#', '`', '*', '_', '[', ']', '(', ')', '!', '+', '-', '.', '|', '{', '}', '~', '=']
|
||||||
|
|
||||||
|
escaped = ''
|
||||||
|
|
||||||
|
# Linear Escape Algorithm, because the algorithm ends in an infinite loop when using the function 'replace',
|
||||||
|
# which tries to replace all backslashes with duplicate backslashes, i.e. also the already other escaped
|
||||||
|
# characters.
|
||||||
|
for c in comment:
|
||||||
|
if c in must_escaped:
|
||||||
|
escaped += '\\' + c
|
||||||
|
else:
|
||||||
|
escaped += c
|
||||||
|
return escaped
|
||||||
|
|
||||||
def _get_line_status(self, comment):
|
def _get_line_status(self, comment):
|
||||||
"""Return a Tuple indicating whether this is an addition/deletion/unchanged, plus the cleaned comment."""
|
"""Return a Tuple indicating whether this is an addition/deletion/unchanged, plus the cleaned comment."""
|
||||||
addition_search = self.ADDITION_PATTERN.search(comment)
|
addition_search = self.ADDITION_PATTERN.search(comment)
|
||||||
|
|||||||
19
tests/test_escape.diff
Normal file
19
tests/test_escape.diff
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
diff --git a/tests/ExampleFile.java b/tests/ExampleFile.java
|
||||||
|
index d340f6a..29b54da 100644
|
||||||
|
--- a/tests/ExampleFile.java
|
||||||
|
+++ b/tests/ExampleFile.java
|
||||||
|
@@ -1,13 +1,5 @@
|
||||||
|
package com.mydomain.myapp;
|
||||||
|
|
||||||
|
public class JavaTests {
|
||||||
|
- // TODO: Some Java
|
||||||
|
- // # Some title
|
||||||
|
- // <SomeTag>
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- TODO: Definitely some Java
|
||||||
|
- # Another title
|
||||||
|
- <AnotherTag>
|
||||||
|
- */
|
||||||
|
}
|
||||||
|
\ No newline at end of file
|
||||||
@@ -169,7 +169,7 @@ class ClosedIssueTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_nix_issues(self):
|
def test_nix_issues(self):
|
||||||
self.assertEqual(count_issues_for_file_type(self.raw_issues, 'nix'), 2)
|
self.assertEqual(count_issues_for_file_type(self.raw_issues, 'nix'), 2)
|
||||||
|
|
||||||
def test_xaml_issues(self):
|
def test_xaml_issues(self):
|
||||||
self.assertEqual(count_issues_for_file_type(self.raw_issues, 'xml'), 2)
|
self.assertEqual(count_issues_for_file_type(self.raw_issues, 'xml'), 2)
|
||||||
|
|
||||||
@@ -204,3 +204,26 @@ class IgnorePatternTests(unittest.TestCase):
|
|||||||
# Includes 2 tests for Crystal.
|
# Includes 2 tests for Crystal.
|
||||||
self.assertEqual(count_issues_for_file_type(self.raw_issues, 'ruby'), 5)
|
self.assertEqual(count_issues_for_file_type(self.raw_issues, 'ruby'), 5)
|
||||||
os.environ['INPUT_IGNORE'] = ''
|
os.environ['INPUT_IGNORE'] = ''
|
||||||
|
|
||||||
|
class EscapeMarkdownTest(unittest.TestCase):
|
||||||
|
def test_simple_escape(self):
|
||||||
|
os.environ['INPUT_ESCAPE'] = 'true'
|
||||||
|
parser = TodoParser()
|
||||||
|
with open('syntax.json', 'r') as syntax_json:
|
||||||
|
parser.syntax_dict = json.load(syntax_json)
|
||||||
|
diff_file = open('tests/test_escape.diff', 'r')
|
||||||
|
|
||||||
|
# I had no other idea to make these checks dynamic.
|
||||||
|
self.raw_issues = parser.parse(diff_file)
|
||||||
|
self.assertEqual(len(self.raw_issues), 2)
|
||||||
|
|
||||||
|
issue = self.raw_issues[0]
|
||||||
|
self.assertEqual(len(issue.body), 2)
|
||||||
|
self.assertEqual(issue.body[0], '\\# Some title')
|
||||||
|
self.assertEqual(issue.body[1], '\\<SomeTag\\>')
|
||||||
|
|
||||||
|
issue = self.raw_issues[1]
|
||||||
|
self.assertEqual(len(issue.body), 2)
|
||||||
|
self.assertEqual(issue.body[0], '\\# Another title')
|
||||||
|
self.assertEqual(issue.body[1], '\\<AnotherTag\\>')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user