Skip to content

Commit

Permalink
Merge pull request #6 from demisto/AddPRSupport
Browse files Browse the repository at this point in the history
Add Pull Request support
  • Loading branch information
DeanArbel authored Mar 8, 2021
2 parents 17e265e + 4ad7b91 commit e9746b3
Show file tree
Hide file tree
Showing 23 changed files with 2,374 additions and 639 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ This tool will help you maintain and organize your GitHub project using an autom
## Use case
In case you work with GitHub projects, and maintain a board for your project this tool is for you.
As we offer a functionality of managing your board in GitHub project boards.
This is by searching for the issues you wish to include in the board(By a set of filter you provide) and placing them in the right place in your board for you - both in the correct column and the correct place within the column.
This is by searching for the issues or pull request you wish to include in the board (By a set of filter you provide) and placing them in the right place in your board for you - both in the correct column and the correct place within the column.

The supported functionality is:
* Adding new issues to your board.
* Moving issues to the correct column of your project, with the priority in mind.
* Sorting your issues within your existing columns by their priorities and creation times.
* Removing issues that fail to meet your issue filters.
* Adding new issues or pull requests to your board.
* Moving issues or pull requests to the correct column of your project, with the priority in mind.
* Sorting your issues or pull requests within your existing columns by their priorities and creation times.
* Removing issues or pull requests that fail to meet your filters.
___
In order to configure github-automation you will need to create an `.ini` file, here is an example:
```buildoutcfg
[General]
closed_issues_column = Done
merged_pull_requests_column = Merged
project_owner = ronykoz
repository_name = test
project_number = 1
Expand All @@ -38,11 +39,13 @@ issue.assignees = false
[In progress]
issue.assignees = true
pull_request.assignees = true
[Review in progress]
issue.assignees = true
issue.pull_request = true
issue.pull_request.review_requested = true
pull_request.review_requested = true
[Waiting for Docs]
issue.assignees = true
Expand All @@ -53,7 +56,7 @@ issue.pull_request.assignees = ronykoz
```
While the General and Actions sections must be in the `.ini` the rest of the sections are dynamic, and each represents the rules for each of your columns.
The keys listed in the column section are the attributes of the classes which represent the issue you are working on. For a more detailed explanation please click [here](https://github.com/demisto/github-automation/blob/master/docs/ini_file.md)
The keys listed in the column section are the attributes of the classes which represent the issue or pull request you are working on. For a more detailed explanation please click [here](https://github.com/demisto/github-automation/blob/master/docs/ini_file.md)


### GitHub Actions
Expand Down
12 changes: 12 additions & 0 deletions docs/ini_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ As an example you can take a look at:
closed_issues_column = Done
project_owner = ronykoz
repository_name = test
is_org_project = false
project_number = 1
priority_list = Critical,High,Medium,Low
filter_labels=bug
Expand Down Expand Up @@ -45,8 +46,11 @@ This section will help you set the basic rules for the project. All the fields t
Here is a quick explanation about their meaning:

- closed_issues_column - The column name of the closed issues.
- closed_pull_requests_column - The column name of the closed pull requests.
- merged_pull_requests_column - The column name of the merged pull requests.
- project_owner - The project owner or organization the repository is in.
- repository_name - The name of the repository containing the project.
- is_org_project - Whether the managed project is an organization level project linked to a repository - optional values are true/false.
- project_number - The project number you will want to manage
- priority_list - The list of priorities you want to order your issues by, descending order.(The default is Critical,High,Medium,Low - for labels with the same power use `||` - i.e. `priority1||priority2`)
- filter_labels - The labels you want to filter the issues that get into the project by.(In case of multiple labels we support CSV format and the condition is or between the labels, Please choose a strict filter to reduce API usage)
Expand All @@ -69,9 +73,17 @@ The supported options are:
The column section is the place you will determine the rules for that column. The optional keys are:

- issue.assignees - Could be the names of the assignees(CSV will be AND condition, and `||` will be OR condition, True for any assignee, False for no assignees)
- issue.labels - Could be the names of the labels (CSV will be AND condition, and `||` will be OR condition, True for any labels, False for no labels)
- issue.pull_request - Whether there is a Pull request or not - optional values true/false
- issue.pull_request.review_requested - Whether a review was requested for the Pull request- optional values true/false
- issue.pull_request.review_completed - Whether the Pull request review is completed - optional values true/false
- issue.pull_request.review_requested_changes - Whether the Pull request review requested for changes - optional values true/false
- issue.pull_request.assignees - Could be the names of the assignees(CSV will be AND condition, and `||` will be OR condition, True for any assignee, False for no assignees)
- issue.pull_request.labels - Could be the names of the labels (CSV will be AND condition, and `||` will be OR condition, True for any labels, False for no labels)
- pull_request.assignees - Could be the names of the assignees(CSV will be AND condition, and `||` will be OR condition, True for any assignee, False for no assignees)
- pull_request.review_requested - Whether a review was requested for the Pull request- optional values true/false
- pull_request.labels - Could be the names of the labels (CSV will be AND condition, and `||` will be OR condition, True for any labels, False for no labels)
- pull_request.review_completed - Whether the Pull request review is completed - optional values true/false
- pull_request.review_requested_changes - Whether the Pull request review requested for changes - optional values true/false


2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
click>=7.0
configparser
gql
gql==3.0.0a5
python-dateutil
requests
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
setup_requires=['setuptools_scm'],
url='https://github.com/demisto/github-automation',
license='MIT',
author='Rony Kozakish',
author='Rony Kozakish & Dean Arbel',
author_email='',
description='GitHub automatic project manager tool',
install_requires=[
'click',
'requests',
'python-dateutil',
'gql'
'gql==3.0.0a5'
],
packages=find_packages("src"),
package_dir={"": "src"},
Expand Down
102 changes: 69 additions & 33 deletions src/github_automation/common/utils.py
Original file line number Diff line number Diff line change
@@ -1,57 +1,93 @@
from github_automation.common.constants import OR


def get_first_column_issues(client, config):
response = client.get_first_column_issues(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number)
cards_page_info = response['repository']['project']['columns']['nodes'][0]['cards']['pageInfo']
while cards_page_info['hasNextPage']:
new_response = client.get_first_column_issues(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
start_cards_cursor=cards_page_info['endCursor'])
response['repository']['project']['columns']['nodes'][0]['cards']['edges']. \
extend(new_response['repository']['project']['columns']['nodes'][0]['cards']['edges'])
cards_page_info = new_response['repository']['project']['columns']['nodes'][0]['cards']['pageInfo']
def get_first_column_items(client, config):
response = client.get_first_column_items(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
is_org_project=config.is_org_project)
project = get_project_from_response(response, config.is_org_project)
project_cards = get_project_cards(project)
cards_page_info = project_cards.get('pageInfo', {})
while cards_page_info.get('hasNextPage'):
new_response = client.get_first_column_items(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
start_cards_cursor=cards_page_info['endCursor'],
is_org_project=config.is_org_project)
project = get_project_from_response(new_response, config.is_org_project)
new_cards = get_project_cards(project)
project_cards['edges'].extend(new_cards['edges'])
cards_page_info = new_cards['pageInfo']

return response


def get_column_issues_with_prev_column(client, config, prev_cursor):
response = client.get_column_issues(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
prev_column_id=prev_cursor)
cards_page_info = response['repository']['project']['columns']['nodes'][0]['cards']['pageInfo']
while cards_page_info['hasNextPage']:
new_response = client.get_column_issues(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
prev_column_id=prev_cursor,
start_cards_cursor=cards_page_info['endCursor'])
response['repository']['project']['columns']['nodes'][0]['cards']['edges']. \
extend(new_response['repository']['project']['columns']['nodes'][0]['cards']['edges'])
cards_page_info = new_response['repository']['project']['columns']['nodes'][0]['cards']['pageInfo']
def get_column_items_with_prev_column(client, config, prev_cursor):
response = client.get_column_items(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
prev_column_id=prev_cursor,
is_org_project=config.is_org_project)
project = get_project_from_response(response, config.is_org_project)
project_cards = get_project_cards(project)
cards_page_info = project_cards.get('pageInfo', {})
while cards_page_info.get('hasNextPage'):
new_response = client.get_column_items(owner=config.project_owner,
name=config.repository_name,
project_number=config.project_number,
prev_column_id=prev_cursor,
start_cards_cursor=cards_page_info['endCursor'],
is_org_project=config.is_org_project)
project = get_project_from_response(new_response, config.is_org_project)
new_cards = get_project_cards(project)
project_cards['edges'].extend(new_cards['edges'])
cards_page_info = new_cards['pageInfo']

return response


def is_matching_issue(issue_labels, must_have_labels, cant_have_labels, filter_labels):
if not any([(value in issue_labels) for value in filter_labels]):
def is_matching_project_item(item_labels, must_have_labels, cant_have_labels, filter_labels):
if not any([(value in item_labels) for value in filter_labels]):
return False

for label in must_have_labels:
if OR in label:
new_labels = label.split(OR)
if all(new_label not in issue_labels for new_label in new_labels):
if all(new_label not in item_labels for new_label in new_labels):
return False

elif label not in issue_labels:
elif label not in item_labels:
return False

for label in cant_have_labels:
if label in issue_labels:
if label in item_labels:
return False

return True


def get_labels(label_edges):
label_names = []
for edge in label_edges:
node_data = edge.get('node')
if node_data:
label_names.append(node_data['name'])

return label_names


def get_project_from_response(response, is_org_project):
root = response['organization'] if is_org_project else response['repository']
return root.get('project', {})


def get_project_cards(project):
if project:
if 'columns' in project:
columns = project['columns']
if 'nodes' in columns and isinstance(columns['nodes'], list):
nodes = columns['nodes']
if len(nodes) > 0 and 'cards' in nodes[0]:
return nodes[0]['cards']
return {}
48 changes: 0 additions & 48 deletions src/github_automation/core/issue/pull_request.py

This file was deleted.

Loading

0 comments on commit e9746b3

Please sign in to comment.