diff --git a/README.md b/README.md index c9cd00c..1c9c9eb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ The `# TODO` comment is commonly used in Python, but this can be customised to w - [Examples](#examples) - [Adding TODOs](#adding-todos) - [Multiline TODOs](#multiline-todos) - - [Dynamic Labels](#dynamic-labels) + - [Specifying Labels](#specifying-labels) + - [Specifying Assignees](#specifying-assignees) + - [Specifying Milestone](#specifying-milestone) - [Removing TODOs](#removing-todos) - [Updating TODOs](#updating-todos) - [Existing TODOs](#existing-todos) @@ -29,7 +31,7 @@ Create a workflow file in your .github/workflows directory as follows: ### workflow.yaml -Latest version is `v2.1`. +Latest version is `v2.2`. name: "Workflow" on: ["push"] @@ -39,7 +41,7 @@ Latest version is `v2.1`. steps: - uses: "actions/checkout@master" - name: "TODO to Issue" - uses: "alstr/todo-to-issue-action@v2.0" + uses: "alstr/todo-to-issue-action@v2.2" with: REPO: ${{ github.repository }} BEFORE: ${{ github.event.before }} @@ -94,7 +96,7 @@ The extra line(s) will be posted in the body of the issue. The `COMMENT_MARKER` input must be set to the correct syntax (e.g. `#` for Python). -### Dynamic Labels +### Specifying Labels def hello_world(): # TODO Come up with a more imaginative greeting @@ -106,10 +108,34 @@ You can specify the labels to add to your issue in the TODO body. The labels should be on their own line below the initial TODO declaration. -Include the `labels:` prefix, then a list of comma-separated label titles. +Include the `labels:` prefix, then a list of comma-separated label titles. If any of the label do not already exist, they will be created. The `todo` label is automatically added to issues to help the action efficiently retrieve them in the future. +### Specifying Assignees + + def hello_world(): + # TODO Come up with a more imaginative greeting + # Everyone uses hello world and it's boring. + # assignees: alstr, bouteillerAlan, hbjydev + print('Hello world!') + +Similar to labels, you can define assignees as a comma-separated list. + +If the assignee is not valid, it will be dropped from issue creation request. + +### Specifying Milestone + + def hello_world(): + # TODO Come up with a more imaginative greeting + # Everyone uses hello world and it's boring. + # milestone: 1 + print('Hello world!') + +You can set the issue milestone by specifying the milestone ID. Only a single milestone can be specified. + +If the milestone does not already exist, it will be dropped from issue creation request. + ### Removing TODOs def hello_world(): diff --git a/main.py b/main.py index 51b9b94..060cedc 100644 --- a/main.py +++ b/main.py @@ -72,6 +72,8 @@ def main(): todo_pattern = re.compile(r'(?<=' + label + r'[\s:]).+') comment_pattern = re.compile(r'(?<=' + comment_marker + r'\s).+') labels_pattern = re.compile(r'(?<=labels:).+') + assignees_pattern = re.compile(r'(?<=assignees:).+') + milestone_pattern = re.compile(r'(?<=milestone:).+') new_issues = [] closed_issues = [] @@ -97,7 +99,19 @@ def main(): labels = list(filter(None, labels.split(','))) curr_issue['labels'].extend(labels) else: - curr_issue['body'] += '\n\n' + comment_search.group(0).lstrip() + assignees_search = assignees_pattern.search(comment, re.IGNORECASE) + if assignees_search: + assignees = assignees_search.group(0).lstrip().replace(', ', ',') + assignees = list(filter(None, assignees.split(','))) + curr_issue['assignees'] = assignees + else: + milestone_search = milestone_pattern.search(comment, re.IGNORECASE) + if milestone_search: + milestone = milestone_search.group(0).strip() + if milestone.isdigit(): + curr_issue['milestone'] = int(milestone) + else: + curr_issue['body'] += '\n\n' + comment_search.group(0).lstrip() return True return False @@ -215,6 +229,28 @@ def main(): break else: new_issue_body = {'title': title, 'body': body, 'labels': issue['labels']} + + # We need to check if any assignees/milestone specified exist, otherwise issue creation will fail. + if 'assignees' in issue: + valid_assignees = [] + for assignee in issue['assignees']: + assignee_url = f'{base_url}{repo}/assignees/{assignee}' + assignee_request = requests.get(url=assignee_url, headers=issue_headers) + if assignee_request.status_code == 204: + valid_assignees.append(assignee) + else: + print('Assignee doesn\'t exist! Dropping this assignee!') + new_issue_body['assignees'] = valid_assignees + + if 'milestone' in issue: + milestone_number = issue['milestone'] + milestone_url = f'{base_url}{repo}/milestones/{milestone_number}' + milestone_request = requests.get(url=milestone_url, headers=issue_headers) + if milestone_request.status_code == 200: + new_issue_body['milestone'] = issue['milestone'] + else: + print('Milestone doesn\'t exist! Dropping this parameter!') + new_issue_request = requests.post(url=issues_url, headers=issue_headers, data=json.dumps(new_issue_body)) print(f'Creating issue {i + 1} of {len(new_issues)}')