mirror of
https://github.com/ditkrg/todo-to-issue-action.git
synced 2026-01-25 07:16:42 +00:00
parent
87d6da6e33
commit
52c5630654
1
.github/workflows/workflow.yml
vendored
1
.github/workflows/workflow.yml
vendored
@ -10,3 +10,4 @@ jobs:
|
|||||||
id: "todo"
|
id: "todo"
|
||||||
with:
|
with:
|
||||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PROJECTS_SECRET: ${{ secrets.PROJECTS_SECRET }}
|
||||||
|
|||||||
30
README.md
30
README.md
@ -7,7 +7,7 @@ The new issue will contain a link to the line in the file containing the TODO, t
|
|||||||
It will also close an issue when a `# TODO` is removed in a pushed commit. A comment will be posted
|
It will also close an issue when a `# TODO` is removed in a pushed commit. A comment will be posted
|
||||||
with the ref of the commit that it was closed by.
|
with the ref of the commit that it was closed by.
|
||||||
|
|
||||||
## Important information about v3.0
|
## Important information about v3.0+
|
||||||
|
|
||||||
This version is a complete rewrite of the action. TODO labels are now parsed dynamically based on the file type identified by the action. As such, you no longer need to hard-code the `LABEL` or `COMMENT_MARKER` inputs.
|
This version is a complete rewrite of the action. TODO labels are now parsed dynamically based on the file type identified by the action. As such, you no longer need to hard-code the `LABEL` or `COMMENT_MARKER` inputs.
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ A few basic tests are included if you would like to see how the new action works
|
|||||||
- [Specifying Labels](#specifying-labels)
|
- [Specifying Labels](#specifying-labels)
|
||||||
- [Specifying Assignees](#specifying-assignees)
|
- [Specifying Assignees](#specifying-assignees)
|
||||||
- [Specifying Milestone](#specifying-milestone)
|
- [Specifying Milestone](#specifying-milestone)
|
||||||
|
- [Specifying Projects](#specifying-projects)
|
||||||
- [Removing TODOs](#removing-todos)
|
- [Removing TODOs](#removing-todos)
|
||||||
- [Updating TODOs](#updating-todos)
|
- [Updating TODOs](#updating-todos)
|
||||||
- [Existing TODOs](#existing-todos)
|
- [Existing TODOs](#existing-todos)
|
||||||
@ -38,7 +39,7 @@ Create a workflow file in your .github/workflows directory as follows:
|
|||||||
|
|
||||||
### workflow.yaml
|
### workflow.yaml
|
||||||
|
|
||||||
Latest version is `v3.0.5`.
|
Latest version is `v4.0-alpha`.
|
||||||
|
|
||||||
name: "Workflow"
|
name: "Workflow"
|
||||||
on: ["push"]
|
on: ["push"]
|
||||||
@ -48,7 +49,7 @@ Latest version is `v3.0.5`.
|
|||||||
steps:
|
steps:
|
||||||
- uses: "actions/checkout@master"
|
- uses: "actions/checkout@master"
|
||||||
- name: "TODO to Issue"
|
- name: "TODO to Issue"
|
||||||
uses: "alstr/todo-to-issue-action@v3.0.5"
|
uses: "alstr/todo-to-issue-action@v4.0-alpha"
|
||||||
id: "todo"
|
id: "todo"
|
||||||
with:
|
with:
|
||||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@ -73,6 +74,8 @@ Three other inputs are provided automatically by GitHub and should not be includ
|
|||||||
| `BEFORE` | The SHA of the previous commit. |
|
| `BEFORE` | The SHA of the previous commit. |
|
||||||
| `SHA` | The SHA of the latest commit. |
|
| `SHA` | The SHA of the latest commit. |
|
||||||
|
|
||||||
|
There are additional inputs if you want to be able to assign issues to projects. See [Specifying Projects](#specifying-projects).
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Adding TODOs
|
### Adding TODOs
|
||||||
@ -155,6 +158,27 @@ You can set the issue milestone by specifying the milestone ID. Only a single mi
|
|||||||
|
|
||||||
If the milestone does not already exist, it will be dropped from the issue creation request.
|
If the milestone does not already exist, it will be dropped from the issue creation request.
|
||||||
|
|
||||||
|
### Specifying Projects
|
||||||
|
|
||||||
|
**The action cannot access your projects by default. To enable access, you must [create an encrypted secret in your repo settings](https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository), with the value set to a valid Personal Access Token. Then, assign the secret in the workflow file like `PROJECTS_SECRET: ${{ secrets.NAME_OF_MY_SECRET }}`. Do not enter the raw secret.**
|
||||||
|
|
||||||
|
def hello_world():
|
||||||
|
# TODO Come up with a more imaginative greeting
|
||||||
|
# Everyone uses hello world and it's boring.
|
||||||
|
# user projects: alstr/Test User Project/To Do
|
||||||
|
# org projects: alstrorg/Test Org Project/To Do
|
||||||
|
print('Hello world!')
|
||||||
|
|
||||||
|
You can assign the created issue to columns within user or organisation projects.
|
||||||
|
|
||||||
|
To assign to a user project, use the `user projects:` prefix. To assign to an organisation project, use `org projects:` prefix.
|
||||||
|
|
||||||
|
The syntax is `<user or org name>/project name/column name`. All three must be provided.
|
||||||
|
|
||||||
|
You can assign to multiple projects by using commas, for example: `user projects: alstr/Test User Project 1/To Do, alstr/Test User Project 2/Tasks`.
|
||||||
|
|
||||||
|
You can also specify default projects in your workflow file using `USER_PROJECTS` or `ORG_PROJECTS`. These will be applied automatically to every issue, but will be overrode by any specified within the TODO.
|
||||||
|
|
||||||
### Removing TODOs
|
### Removing TODOs
|
||||||
|
|
||||||
def hello_world():
|
def hello_world():
|
||||||
|
|||||||
@ -37,3 +37,12 @@ inputs:
|
|||||||
description: "For multiline TODOs, format each line as a new paragraph when creating the issue"
|
description: "For multiline TODOs, format each line as a new paragraph when creating the issue"
|
||||||
required: true
|
required: true
|
||||||
default: true
|
default: true
|
||||||
|
PROJECTS_SECRET:
|
||||||
|
description: "Encrypted secret corresponding to your personal access token, e.g. ${{ secrets.MY_SECRET }} (do not enter the actual secret)"
|
||||||
|
required: false
|
||||||
|
USER_PROJECTS:
|
||||||
|
description: "Default user projects"
|
||||||
|
required: false
|
||||||
|
ORG_PROJECTS:
|
||||||
|
description: "Default organisation projects"
|
||||||
|
required: false
|
||||||
|
|||||||
143
main.py
143
main.py
@ -21,12 +21,15 @@ class LineStatus(Enum):
|
|||||||
|
|
||||||
class Issue(object):
|
class Issue(object):
|
||||||
"""Basic Issue model for collecting the necessary info to send to GitHub."""
|
"""Basic Issue model for collecting the necessary info to send to GitHub."""
|
||||||
def __init__(self, title, labels, assignees, milestone, body, hunk, file_name, start_line, markdown_language,
|
|
||||||
status):
|
def __init__(self, title, labels, assignees, milestone, user_projects, org_projects, body, hunk, file_name,
|
||||||
|
start_line, markdown_language, status):
|
||||||
self.title = title
|
self.title = title
|
||||||
self.labels = labels
|
self.labels = labels
|
||||||
self.assignees = assignees
|
self.assignees = assignees
|
||||||
self.milestone = milestone
|
self.milestone = milestone
|
||||||
|
self.user_projects = user_projects
|
||||||
|
self.org_projects = org_projects
|
||||||
self.body = body
|
self.body = body
|
||||||
self.hunk = hunk
|
self.hunk = hunk
|
||||||
self.file_name = file_name
|
self.file_name = file_name
|
||||||
@ -38,14 +41,15 @@ class Issue(object):
|
|||||||
class GitHubClient(object):
|
class GitHubClient(object):
|
||||||
"""Basic client for getting the last diff and creating/closing issues."""
|
"""Basic client for getting the last diff and creating/closing issues."""
|
||||||
existing_issues = []
|
existing_issues = []
|
||||||
base_url = 'https://api.github.com/repos/'
|
base_url = 'https://api.github.com/'
|
||||||
|
repos_url = f'{base_url}repos/'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.repo = os.getenv('INPUT_REPO')
|
self.repo = os.getenv('INPUT_REPO')
|
||||||
self.before = os.getenv('INPUT_BEFORE')
|
self.before = os.getenv('INPUT_BEFORE')
|
||||||
self.sha = os.getenv('INPUT_SHA')
|
self.sha = os.getenv('INPUT_SHA')
|
||||||
self.token = os.getenv('INPUT_TOKEN')
|
self.token = os.getenv('INPUT_TOKEN')
|
||||||
self.issues_url = f'{self.base_url}{self.repo}/issues'
|
self.issues_url = f'{self.repos_url}{self.repo}/issues'
|
||||||
self.issue_headers = {
|
self.issue_headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Authorization': f'token {self.token}'
|
'Authorization': f'token {self.token}'
|
||||||
@ -57,7 +61,7 @@ class GitHubClient(object):
|
|||||||
|
|
||||||
def get_last_diff(self):
|
def get_last_diff(self):
|
||||||
"""Get the last diff based on the SHA of the last two commits."""
|
"""Get the last diff based on the SHA of the last two commits."""
|
||||||
diff_url = f'{self.base_url}{self.repo}/compare/{self.before}...{self.sha}'
|
diff_url = f'{self.repos_url}{self.repo}/compare/{self.before}...{self.sha}'
|
||||||
diff_headers = {
|
diff_headers = {
|
||||||
'Accept': 'application/vnd.github.v3.diff',
|
'Accept': 'application/vnd.github.v3.diff',
|
||||||
'Authorization': f'token {self.token}'
|
'Authorization': f'token {self.token}'
|
||||||
@ -108,7 +112,7 @@ class GitHubClient(object):
|
|||||||
# We need to check if any assignees/milestone specified exist, otherwise issue creation will fail.
|
# We need to check if any assignees/milestone specified exist, otherwise issue creation will fail.
|
||||||
valid_assignees = []
|
valid_assignees = []
|
||||||
for assignee in issue.assignees:
|
for assignee in issue.assignees:
|
||||||
assignee_url = f'{self.base_url}{self.repo}/assignees/{assignee}'
|
assignee_url = f'{self.repos_url}{self.repo}/assignees/{assignee}'
|
||||||
assignee_request = requests.get(url=assignee_url, headers=self.issue_headers)
|
assignee_request = requests.get(url=assignee_url, headers=self.issue_headers)
|
||||||
if assignee_request.status_code == 204:
|
if assignee_request.status_code == 204:
|
||||||
valid_assignees.append(assignee)
|
valid_assignees.append(assignee)
|
||||||
@ -117,7 +121,7 @@ class GitHubClient(object):
|
|||||||
new_issue_body['assignees'] = valid_assignees
|
new_issue_body['assignees'] = valid_assignees
|
||||||
|
|
||||||
if issue.milestone:
|
if issue.milestone:
|
||||||
milestone_url = f'{self.base_url}{self.repo}/milestones/{issue.milestone}'
|
milestone_url = f'{self.repos_url}{self.repo}/milestones/{issue.milestone}'
|
||||||
milestone_request = requests.get(url=milestone_url, headers=self.issue_headers)
|
milestone_request = requests.get(url=milestone_url, headers=self.issue_headers)
|
||||||
if milestone_request.status_code == 200:
|
if milestone_request.status_code == 200:
|
||||||
new_issue_body['milestone'] = issue.milestone
|
new_issue_body['milestone'] = issue.milestone
|
||||||
@ -127,6 +131,16 @@ class GitHubClient(object):
|
|||||||
new_issue_request = requests.post(url=self.issues_url, headers=self.issue_headers,
|
new_issue_request = requests.post(url=self.issues_url, headers=self.issue_headers,
|
||||||
data=json.dumps(new_issue_body))
|
data=json.dumps(new_issue_body))
|
||||||
|
|
||||||
|
# Check if we should assign this issue to any projects.
|
||||||
|
if new_issue_request.status_code == 201 and (len(issue.user_projects) > 0 or len(issue.org_projects) > 0):
|
||||||
|
issue_json = new_issue_request.json()
|
||||||
|
issue_id = issue_json['id']
|
||||||
|
|
||||||
|
if len(issue.user_projects) > 0:
|
||||||
|
self.add_issue_to_projects(issue_id, issue.user_projects, 'user')
|
||||||
|
if len(issue.org_projects) > 0:
|
||||||
|
self.add_issue_to_projects(issue_id, issue.org_projects, 'org')
|
||||||
|
|
||||||
return new_issue_request.status_code
|
return new_issue_request.status_code
|
||||||
|
|
||||||
def close_issue(self, issue):
|
def close_issue(self, issue):
|
||||||
@ -144,17 +158,92 @@ class GitHubClient(object):
|
|||||||
issue_number = existing_issue['number']
|
issue_number = existing_issue['number']
|
||||||
else:
|
else:
|
||||||
# The titles match, so we will try and close the issue.
|
# The titles match, so we will try and close the issue.
|
||||||
update_issue_url = f'{self.base_url}{self.repo}/issues/{issue_number}'
|
update_issue_url = f'{self.repos_url}{self.repo}/issues/{issue_number}'
|
||||||
body = {'state': 'closed'}
|
body = {'state': 'closed'}
|
||||||
requests.patch(update_issue_url, headers=self.issue_headers, data=json.dumps(body))
|
requests.patch(update_issue_url, headers=self.issue_headers, data=json.dumps(body))
|
||||||
|
|
||||||
issue_comment_url = f'{self.base_url}{self.repo}/issues/{issue_number}/comments'
|
issue_comment_url = f'{self.repos_url}{self.repo}/issues/{issue_number}/comments'
|
||||||
body = {'body': f'Closed in {self.sha}'}
|
body = {'body': f'Closed in {self.sha}'}
|
||||||
update_issue_request = requests.post(issue_comment_url, headers=self.issue_headers,
|
update_issue_request = requests.post(issue_comment_url, headers=self.issue_headers,
|
||||||
data=json.dumps(body))
|
data=json.dumps(body))
|
||||||
return update_issue_request.status_code
|
return update_issue_request.status_code
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def add_issue_to_projects(self, issue_id, projects, projects_type):
|
||||||
|
"""Attempt to add this issue to the specified user or organisation projects."""
|
||||||
|
projects_secret = os.getenv('INPUT_PROJECTS_SECRET', None)
|
||||||
|
if not projects_secret:
|
||||||
|
print('You need to create and set PROJECTS_SECRET to use projects')
|
||||||
|
return
|
||||||
|
projects_headers = {
|
||||||
|
'Accept': 'application/vnd.github.inertia-preview+json',
|
||||||
|
'Authorization': f'token {projects_secret}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Loop through all the projects that we should assign this issue to.
|
||||||
|
for i, project in enumerate(projects):
|
||||||
|
print(f'Adding issue to {projects_type} project {i + 1} of {len(projects)}')
|
||||||
|
project = project.replace(' / ', '/')
|
||||||
|
try:
|
||||||
|
entity_name, project_name, column_name = project.split('/')
|
||||||
|
except ValueError:
|
||||||
|
print('Invalid project syntax')
|
||||||
|
continue
|
||||||
|
entity_name = entity_name.strip()
|
||||||
|
project_name = project_name.strip()
|
||||||
|
column_name = column_name.strip()
|
||||||
|
|
||||||
|
if projects_type == 'user':
|
||||||
|
projects_url = f'{self.base_url}users/{entity_name}/projects'
|
||||||
|
elif projects_type == 'org':
|
||||||
|
projects_url = f'{self.base_url}orgs/{entity_name}/projects'
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# We need to use the project name to get its ID.
|
||||||
|
projects_request = requests.get(url=projects_url, headers=projects_headers)
|
||||||
|
if projects_request.status_code == 200:
|
||||||
|
projects_json = projects_request.json()
|
||||||
|
for project_dict in projects_json:
|
||||||
|
if project_dict['name'].lower() == project_name.lower():
|
||||||
|
project_id = project_dict['id']
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print('Project does not exist, skipping')
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print('An error occurred, skipping')
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Use the project ID and column name to get the column ID.
|
||||||
|
columns_url = f'{self.base_url}projects/{project_id}/columns'
|
||||||
|
columns_request = requests.get(url=columns_url, headers=projects_headers)
|
||||||
|
if columns_request.status_code == 200:
|
||||||
|
columns_json = columns_request.json()
|
||||||
|
for column_dict in columns_json:
|
||||||
|
if column_dict['name'].lower() == column_name.lower():
|
||||||
|
column_id = column_dict['id']
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print('Column does not exist, skipping')
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print('An error occurred, skipping')
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Use the column ID to assign the issue to the project.
|
||||||
|
new_card_url = f'{self.base_url}projects/columns/{column_id}/cards'
|
||||||
|
new_card_body = {
|
||||||
|
'content_id': int(issue_id),
|
||||||
|
'content_type': 'Issue'
|
||||||
|
}
|
||||||
|
new_card_request = requests.post(url=new_card_url, headers=projects_headers,
|
||||||
|
data=json.dumps(new_card_body))
|
||||||
|
if new_card_request.status_code == 201:
|
||||||
|
print('Issue card added to project')
|
||||||
|
else:
|
||||||
|
print('Issue card could not be added to project')
|
||||||
|
|
||||||
|
|
||||||
class TodoParser(object):
|
class TodoParser(object):
|
||||||
"""Parser for extracting information from a given diff file."""
|
"""Parser for extracting information from a given diff file."""
|
||||||
@ -170,6 +259,8 @@ class TodoParser(object):
|
|||||||
LABELS_PATTERN = re.compile(r'(?<=labels:\s).+')
|
LABELS_PATTERN = re.compile(r'(?<=labels:\s).+')
|
||||||
ASSIGNEES_PATTERN = re.compile(r'(?<=assignees:\s).+')
|
ASSIGNEES_PATTERN = re.compile(r'(?<=assignees:\s).+')
|
||||||
MILESTONE_PATTERN = re.compile(r'(?<=milestone:\s).+')
|
MILESTONE_PATTERN = re.compile(r'(?<=milestone:\s).+')
|
||||||
|
USER_PROJECTS_PATTERN = re.compile(r'(?<=user projects:\s).+')
|
||||||
|
ORG_PROJECTS_PATTERN = re.compile(r'(?<=org projects:\s).+')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# We could support more identifiers later quite easily.
|
# We could support more identifiers later quite easily.
|
||||||
@ -301,8 +392,10 @@ class TodoParser(object):
|
|||||||
if issue:
|
if issue:
|
||||||
issues.append(issue)
|
issues.append(issue)
|
||||||
|
|
||||||
# Strip some of the diff symbols so it can be included as a code snippet in the issue body.
|
default_user_projects = os.getenv('INPUT_USER_PROJECTS', None)
|
||||||
|
default_org_projects = os.getenv('INPUT_ORG_PROJECTS', None)
|
||||||
for i, issue in enumerate(issues):
|
for i, issue in enumerate(issues):
|
||||||
|
# Strip some of the diff symbols so it can be included as a code snippet in the issue body.
|
||||||
# Strip removed lines.
|
# Strip removed lines.
|
||||||
cleaned_hunk = re.sub(r'\n^-.*$', '', issue.hunk, 0, re.MULTILINE)
|
cleaned_hunk = re.sub(r'\n^-.*$', '', issue.hunk, 0, re.MULTILINE)
|
||||||
# Strip leading symbols/whitespace.
|
# Strip leading symbols/whitespace.
|
||||||
@ -310,6 +403,14 @@ class TodoParser(object):
|
|||||||
# Strip newline message.
|
# Strip newline message.
|
||||||
cleaned_hunk = re.sub(r'\n\sNo newline at end of file', '', cleaned_hunk, 0, re.MULTILINE)
|
cleaned_hunk = re.sub(r'\n\sNo newline at end of file', '', cleaned_hunk, 0, re.MULTILINE)
|
||||||
issue.hunk = cleaned_hunk
|
issue.hunk = cleaned_hunk
|
||||||
|
|
||||||
|
# If no projects have been specified for this issue, assign any default projects that exist.
|
||||||
|
if len(issue.user_projects) == 0 and default_user_projects is not None:
|
||||||
|
separated_user_projects = self._get_projects(f'user projects: {default_user_projects}', 'user')
|
||||||
|
issue.user_projects = separated_user_projects
|
||||||
|
if len(issue.org_projects) == 0 and default_org_projects is not None:
|
||||||
|
separated_org_projects = self._get_projects(f'org projects: {default_org_projects}', 'user')
|
||||||
|
issue.org_projects = separated_org_projects
|
||||||
return issues
|
return issues
|
||||||
|
|
||||||
def _get_file_details(self, file):
|
def _get_file_details(self, file):
|
||||||
@ -342,6 +443,8 @@ class TodoParser(object):
|
|||||||
labels=['todo'],
|
labels=['todo'],
|
||||||
assignees=[],
|
assignees=[],
|
||||||
milestone=None,
|
milestone=None,
|
||||||
|
user_projects=[],
|
||||||
|
org_projects=[],
|
||||||
body=[line_title],
|
body=[line_title],
|
||||||
hunk=code_block['hunk'],
|
hunk=code_block['hunk'],
|
||||||
file_name=code_block['file'],
|
file_name=code_block['file'],
|
||||||
@ -365,12 +468,18 @@ class TodoParser(object):
|
|||||||
line_labels = self._get_labels(cleaned_line)
|
line_labels = self._get_labels(cleaned_line)
|
||||||
line_assignees = self._get_assignees(cleaned_line)
|
line_assignees = self._get_assignees(cleaned_line)
|
||||||
line_milestone = self._get_milestone(cleaned_line)
|
line_milestone = self._get_milestone(cleaned_line)
|
||||||
|
user_projects = self._get_projects(cleaned_line, 'user')
|
||||||
|
org_projects = self._get_projects(cleaned_line, 'org')
|
||||||
if line_labels:
|
if line_labels:
|
||||||
issue.labels.extend(line_labels)
|
issue.labels.extend(line_labels)
|
||||||
elif line_assignees:
|
elif line_assignees:
|
||||||
issue.assignees.extend(line_assignees)
|
issue.assignees.extend(line_assignees)
|
||||||
elif line_milestone and not issue.milestone:
|
elif line_milestone and not issue.milestone:
|
||||||
issue.milestone = line_milestone
|
issue.milestone = line_milestone
|
||||||
|
elif user_projects:
|
||||||
|
issue.user_projects.extend(user_projects)
|
||||||
|
elif org_projects:
|
||||||
|
issue.org_projects.extend(org_projects)
|
||||||
elif len(cleaned_line):
|
elif len(cleaned_line):
|
||||||
issue.body.append(cleaned_line)
|
issue.body.append(cleaned_line)
|
||||||
return issue
|
return issue
|
||||||
@ -445,6 +554,20 @@ class TodoParser(object):
|
|||||||
milestone = int(milestone)
|
milestone = int(milestone)
|
||||||
return milestone
|
return milestone
|
||||||
|
|
||||||
|
def _get_projects(self, comment, projects_type):
|
||||||
|
"""Check the passed comment for projects to link the issue to."""
|
||||||
|
projects = []
|
||||||
|
if projects_type == 'user':
|
||||||
|
projects_search = self.USER_PROJECTS_PATTERN.search(comment, re.IGNORECASE)
|
||||||
|
elif projects_type == 'org':
|
||||||
|
projects_search = self.ORG_PROJECTS_PATTERN.search(comment, re.IGNORECASE)
|
||||||
|
else:
|
||||||
|
return projects
|
||||||
|
if projects_search:
|
||||||
|
projects = projects_search.group(0).replace(', ', ',')
|
||||||
|
projects = list(filter(None, projects.split(',')))
|
||||||
|
return projects
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if os.getenv('INPUT_BEFORE') != '0000000000000000000000000000000000000000':
|
if os.getenv('INPUT_BEFORE') != '0000000000000000000000000000000000000000':
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user