1
0
Fork 0
mirror of https://gitlab.wikimedia.org/ladsgroup/Phabricator-maintenance-bot synced 2024-11-24 13:02:38 +01:00

Initial commit

This commit is contained in:
Amir Sarabadani 2019-11-22 22:19:59 +01:00
parent e06b410188
commit 73098f3ff1
4 changed files with 271 additions and 0 deletions

6
.gitignore vendored
View file

@ -1,3 +1,6 @@
# My credentials
creds.json
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
@ -102,3 +105,6 @@ venv.bak/
# mypy
.mypy_cache/
.idea/
*.iml

72
column_mover.py Normal file
View file

@ -0,0 +1,72 @@
from lib import Client
class Checker():
def __init__(self, work, client):
self.work = work
self.client = client
def phid_check(self, phid):
if self.work.get('projects'):
return self.phid_check_project(
phid, [
self.client.lookupPhid(
'#' + i) for i in self.work['projects']])
if self.work.get('status'):
return self.phid_check_status(phid, self.work['status'])
return False
def phid_check_project(self, phid, project_phids):
taskDetails = self.client.taskDetails(phid)
for project_phid in project_phids:
if project_phid in taskDetails['projectPHIDs']:
return True
return False
def phid_check_status(self, phid, statuses):
taskDetails = self.client.taskDetails(phid)
return taskDetails['statusName'] in statuses
client = Client.newFromCreds()
work = [{'from': ['incoming'],
'project': 'Wikidata',
'to': 'in progress',
'projects': ['wikidata-campsite-iteration-∞',
'RL_Module_Terminators_Trailblazing',
'wikidata-bridge-sprint-8']},
{'from': ['Incoming'],
'project': 'User-Ladsgroup',
'to': 'In progress',
'projects': ['wikidata-campsite-iteration-∞',
'RL_Module_Terminators_Trailblazing']},
{'from': ['In progress',
'Incoming'],
'project': 'User-Ladsgroup',
'to': 'Done',
'status': ['Resolved']},
{'from': ['Unsorted'],
'project': 'user-dannys712',
'to': 'Global Watchlist',
'projects': ['DannyS712-Global_watchlist.js']},
]
for case in work:
gen = client.getTasksWithProject(client.lookupPhid('#' + case['project']))
checker = Checker(case, client)
columns = client.getColumns(client.lookupPhid('#' + case['project']))
mapping = {}
for column in columns['data']:
mapping[column['fields']['name']] = column['phid']
for phid in gen:
if checker.phid_check(phid):
project_phid = client.lookupPhid('#' + case['project'])
currentColumnName = client.getTaskColumns(
phid)['boards'][project_phid]['columns'][0]['name']
if currentColumnName not in case['from']:
continue
try:
print(phid)
client.moveColumns(phid, mapping[case['to']])
except KeyboardInterrupt:
continue

123
lib.py Normal file
View file

@ -0,0 +1,123 @@
import json
import time
import requests
class Client(object):
"""Phabricator client"""
def __init__(self, url, username, key):
self.url = url
self.username = username
self.column_cache = {}
self.phid_cache = {}
self.session = {
'token': key,
}
@classmethod
def newFromCreds(cls):
with open('creds.json', 'r') as f:
creds = json.loads(f.read())
return cls(*creds)
def post(self, path, data):
data['__conduit__'] = self.session
r = requests.post('%s/api/%s' % (self.url, path), data={
'params': json.dumps(data),
'output': 'json',
})
resp = r.json()
if resp['error_code'] is not None:
raise Exception(resp['error_info'])
return resp['result']
def lookupPhid(self, label):
"""Lookup information on a Phab object by name."""
if not self.phid_cache.get(label):
r = self.post('phid.lookup', {'names': [label]})
if label in r and 'phid' in r[label]:
obj = r[label]['phid']
self.phid_cache[label] = obj
else:
raise Exception('No object found for %s' % label)
return self.phid_cache[label]
def getColumns(self, project_phid):
if not self.column_cache.get(project_phid):
self.column_cache[project_phid] = self.post(
'project.column.search', {
"constraints": {
"projects": [project_phid]}})
return self.column_cache[project_phid]
def moveColumns(self, task_phid, to_column):
self.post('maniphest.edit', {
'objectIdentifier': task_phid,
'transactions': [{
'type': 'column',
'value': [to_column],
}]
})
def taskDetails(self, phid):
"""Lookup details of a Maniphest task."""
r = self.post('maniphest.query', {'phids': [phid]})
if phid in r:
return r[phid]
raise Exception('No task found for phid %s' % phid)
def getTransactions(self, phid):
r = self.post('transaction.search', {'objectIdentifier': phid})
if 'data' in r:
return r['data']
raise Exception('No transaction found for phid %s' % phid)
def removeProject(self, project_phid, task):
return self.removeProjectByPhid(project_phid, self.lookupPhid(task))
def removeProjectByPhid(self, project_phid, task_phid):
self.post('maniphest.edit', {
'objectIdentifier': task_phid,
'transactions': [{
'type': 'projects.remove',
'value': [project_phid],
}]
})
def getTasksWithProject(self, project_phid, continue_=None):
r = self._getTasksWithProjectContinue(project_phid, continue_)
cursor = r['cursor']
for case in r['data']:
if case['type'] != 'TASK':
continue
yield case['phid']
if cursor.get('after'):
for case in self.getTasksWithProject(
project_phid, cursor['after']):
yield case
def _getTasksWithProjectContinue(self, project_phid, continue_=None):
params = {
'limit': 100,
'constraints': {
'projects': [project_phid],
"modifiedStart": int(time.time() - 3600)
}
}
if continue_:
params['after'] = continue_
return self.post('maniphest.search', params)
def getTaskColumns(self, phid):
params = {
"attachments": {
"columns": {"boards": {"columns": True}}
},
"constraints": {
"phids": [phid]
}
}
return self.post('maniphest.search', params)[
'data'][0]['attachments']['columns']

70
patchforreview_remover.py Normal file
View file

@ -0,0 +1,70 @@
import re
import time
from collections import defaultdict
from lib import Client
class Checker():
def __init__(self, gerrit_bot_phid, project_patch_for_review_phid, client):
self.gerrit_bot_phid = gerrit_bot_phid
self.project_patch_for_review_phid = project_patch_for_review_phid
self.client = client
def check(self, t_id):
phid = self.client.lookupPhid(t_id)
return self.phid_check(phid)
def phid_check(self, phid):
gerrit_bot_actions = []
for transaction in self.client.getTransactions(phid):
if 'https://github.com/' in str(transaction):
return False
if transaction['authorPHID'] == self.gerrit_bot_phid:
gerrit_bot_actions.append(transaction)
else:
if transaction['type'] == 'projects':
check = self.project_patch_for_review_phid in str(
transaction['fields'])
add_check = "'add'" in str(transaction['fields'])
if check and add_check:
return False
gerrit_patch_status = defaultdict(list)
for case in gerrit_bot_actions:
if case['type'] != 'comment':
continue
if len(case['comments']) != 1:
return False
raw_comment = case['comments'][0]['content']['raw']
gerrit_patch_id = re.findall(
r'https\:\/\/gerrit\.wikimedia\.org\/r\/(\d+)', raw_comment)[0]
merged = re.findall(
r'Change \d+ (?:\*\*merged\*\*|abandoned) by ',
raw_comment)
gerrit_patch_status[gerrit_patch_id].append(not(bool(merged)))
for patch in gerrit_patch_status:
if gerrit_patch_status[patch] != [False, True]:
return False
return True
client = Client.newFromCreds()
project_patch_for_review_phid = 'PHID-PROJ-onnxucoedheq3jevknyr'
checker = Checker(
'PHID-USER-idceizaw6elwiwm5xshb',
project_patch_for_review_phid,
client)
gen = client.getTasksWithProject(project_patch_for_review_phid)
for phid in gen:
if checker.phid_check(phid):
print(client.taskDetails(phid)['id'])
try:
client.removeProjectByPhid(project_patch_for_review_phid, phid)
except BaseException:
continue
time.sleep(10)