Skip to content

Commit

Permalink
Merge pull request #1 from rebortg/main
Browse files Browse the repository at this point in the history
add phabricator autoclose script and github action
  • Loading branch information
dmbaturin authored Mar 15, 2024
2 parents 9c40be5 + 0e274fe commit dadd219
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/phabricator_tasks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Autoclose Finished Phabricator Tasks
on:
workflow_dispatch:
schedule:
- cron: '0 6 * * *'

jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Set Up Python
uses: actions/setup-python@v5
with:
python-version: 3.11.x

- uses: actions/checkout@v4

- name: run script
env:
PHABRICATOR_WRITE_TOKEN: ${{ secrets.PHABRICATOR_WRITE_TOKEN }}
if: env.PHABRICATOR_WRITE_TOKEN != null
run: |
pip3 install -r phabricator_tasks/requirements.txt
python3 phabricator_tasks/tasks.py -t ${{ secrets.PHABRICATOR_WRITE_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv
.DS_Store
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# vyos-infrastructure
Various scripts and automations for VyOS infrastructure tasks


## phabricator_tasks
autoclose all finished tasks in https://vyos.dev
2 changes: 2 additions & 0 deletions phabricator_tasks/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
phabricator
requests
186 changes: 186 additions & 0 deletions phabricator_tasks/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
from phabricator import Phabricator as PhabricatorOriginal
from phabricator import parse_interfaces
import argparse


'''
get project wide tasks which are not closed but all in the Finished column
1. get all Workboard columns
- extract workboard phid for the Finished column
- and the project phid and name
2. get all open taks from projects with Finish column
3. get unique taskslists from previous step to get projekts of a task
4. get all transactions for each task and check if the task is in the Finished column per project
5. autoclose if task is in all Finished column
'''

'''
extend of original Phabricator class to add new interface "project.column.search"
this can be delete if PR https://github.com/disqus/python-phabricator/pull/71 is merged in the pip package
'''
import copy
import json
import pkgutil

INTERFACES = json.loads(
pkgutil.get_data('phabricator', 'interfaces.json')
.decode('utf-8'))

INTERFACES['project.column.search'] = {
"description": "Search for Workboard columns.",
"params": {
"ids": "optional list<int>",
"phids": "optional list<phid>",
"projects": "optional list<phid>"
},
"return": "list"
}

class Phabricator(PhabricatorOriginal):
def __init__(self, **kwargs):
kwargs['interface'] = copy.deepcopy(parse_interfaces(INTERFACES))
super(Phabricator, self).__init__(self, **kwargs)

''' end of extend the original Phabricator class'''

def phab_search(method, constraints=dict(), after=None):
results = []
while True:
response = method(
constraints=constraints,
after=after
)
results.extend(response.response['data'])
after = response.response['cursor']['after']
if after is None:
break
return results


def phab_query(method, after=None):
results = []
while True:
response = method(
offset=after
)
results.extend(response.response['data'])
after = response.response['cursor']['after']
if after is None:
break
return results


def close_task(task_id, phab):
try:
response = phab.maniphest.update(
id=task_id,
status='resolved'
)
if response.response['isClosed']:
print(f'T{task_id} closed')
except Exception as e:
print(f'T{task_id} Error: {e}')


parser = argparse.ArgumentParser()
parser.add_argument("-t", "--token", type=str, help="API token", required=True)
args = parser.parse_args()

phab = Phabricator(host='https://vyos.dev/api/', token=args.token)
phab.maniphest.update(id=6053, status='resolved')

workboards = phab_search(phab.project.column.search)
project_hirarchy = {}

# get sub-project hirarchy from proxyPHID in workboards
for workboard in workboards:
if workboard['fields']['proxyPHID']:
proxy_phid = workboard['fields']['proxyPHID']
project_phid = workboard['fields']['project']['phid']

if project_phid not in project_hirarchy.keys():
project_hirarchy[project_phid] = []
project_hirarchy[project_phid].append(proxy_phid)

finished_boards = []


for workboard in workboards:
project_id = workboard['fields']['project']['phid']
if project_id in project_hirarchy.keys():
# skip projects with sub-projects
continue
if workboard['fields']['name'] == 'Finished':
project_tasks = phab_search(phab.maniphest.search, constraints={
'projects': [project_id],
'statuses': ['open'],
})
finished_boards.append({
'project_id': project_id,
'project_name': workboard['fields']['project']['name'],
'project_tasks': project_tasks,
'should_board_id': workboard['phid'],
})

# get unique tasks
# tasks = {
# 9999: {
# 'PHID-PROJ-xxxxx': 'PHID-PCOL-xxxxx',
# 'PHID-PROJ-yyyyy': 'PHID-PCOL-yyyyy'
# }
# }
tasks = {}
for project in finished_boards:
project_id = project['project_id']
board_id = project['should_board_id']
for task in project['project_tasks']:
task_id = task['id']
if task_id not in tasks.keys():
tasks[task_id] = {}
if project_id not in tasks[task_id].keys():
tasks[task_id][project_id] = board_id

tasks = dict(sorted(tasks.items()))

# get transactions for each task and compare if the task is in the Finished column
for task_id, projects in tasks.items():
fisnish_timestamp = 0
project_ids = list(projects.keys())
# don't use own pagination function, because endpoint without pagination
transactions = phab.maniphest.gettasktransactions(ids=[task_id])
transactions = transactions.response[str(task_id)]
finished = False
for transaction in transactions:
if transaction['transactionType'] == 'core:columns':
# test if projectid is in transaction
if transaction['newValue'][0]['boardPHID'] in project_ids:
# remove project_id from project_ids to use only last transaction in this
# project
project_ids.remove(transaction['newValue'][0]['boardPHID'])
# test if boardid is the "Finished" board
if fisnish_timestamp < int(transaction['dateCreated']):
fisnish_timestamp = int(transaction['dateCreated'])
if projects[transaction['newValue'][0]['boardPHID']] == transaction['newValue'][0]['columnPHID']:
finished = True
for project in finished_boards:
if project['project_id'] == transaction['newValue'][0]['boardPHID']:
project_name = project['project_name']
# print(f'T{task_id} is Finished in {project_name}')
if len(project_ids) == 0:
print(f'T{task_id} is Finished in all projects')
close_task(task_id, phab)
break

#if len(project_ids) > 0 and finished:
# collect project names for output
# project_names = []
# for project_id in project_ids:
# for project in finished_boards:
# if project['project_id'] == project_id:
# project_names.append(project['project_name'])
# print(f'T{task_id} is in a different column: {' and '.join(project_names)}')

0 comments on commit dadd219

Please sign in to comment.