summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@baturin.org>2024-03-15 18:44:46 +0100
committerGitHub <noreply@github.com>2024-03-15 18:44:46 +0100
commitdadd2191b244c9f4ae411899d59fcf4edd6f5396 (patch)
treee5b86e19ba49d5d13f61d9ec1fa4cb8187a9640a
parent9c40be5e6ce8069621e08015800ebf59dface868 (diff)
parent0e274feaab32b8e79760d4f9137d4b5a065a0c57 (diff)
downloadvyos-infrastructure-dadd2191b244c9f4ae411899d59fcf4edd6f5396.tar.gz
vyos-infrastructure-dadd2191b244c9f4ae411899d59fcf4edd6f5396.zip
Merge pull request #1 from rebortg/main
add phabricator autoclose script and github action
-rw-r--r--.github/workflows/phabricator_tasks.yml24
-rw-r--r--.gitignore2
-rw-r--r--README.md4
-rw-r--r--phabricator_tasks/requirements.txt2
-rw-r--r--phabricator_tasks/tasks.py186
5 files changed, 218 insertions, 0 deletions
diff --git a/.github/workflows/phabricator_tasks.yml b/.github/workflows/phabricator_tasks.yml
new file mode 100644
index 0000000..678ce65
--- /dev/null
+++ b/.github/workflows/phabricator_tasks.yml
@@ -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 }} \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ceef511
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+venv
+.DS_Store \ No newline at end of file
diff --git a/README.md b/README.md
index 4763d4d..3b85061 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,6 @@
# vyos-infrastructure
Various scripts and automations for VyOS infrastructure tasks
+
+
+## phabricator_tasks
+autoclose all finished tasks in https://vyos.dev \ No newline at end of file
diff --git a/phabricator_tasks/requirements.txt b/phabricator_tasks/requirements.txt
new file mode 100644
index 0000000..40c30be
--- /dev/null
+++ b/phabricator_tasks/requirements.txt
@@ -0,0 +1,2 @@
+phabricator
+requests \ No newline at end of file
diff --git a/phabricator_tasks/tasks.py b/phabricator_tasks/tasks.py
new file mode 100644
index 0000000..78ce2c7
--- /dev/null
+++ b/phabricator_tasks/tasks.py
@@ -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)}')
+ \ No newline at end of file