🚧 This instance is under construction; expect occasional downtime. Runners available in /repos. Questions? Ask in #wikimedia-gitlab on libera.chat, or under GitLab on Phabricator.

Commit 45d1c770 authored by 20after4's avatar 20after4
Browse files

Resolve PHIDs to Task IDs and other nice stuff.

parent f1a992a1
import re
def version(ver):
"""Validate our version number formats"""
try:
return re.match("(\\d+\\.\\d+(\\.\\d+-)?wmf\\.?\\d+)", ver).group(0)
except Exception:
return None
return None
from __future__ import annotations
import json
import os
from builtins import str
from collections import UserDict, UserList, deque
from collections.abc import Iterable
import json
import os
from pprint import pprint
from tokenize import Number
from typing import Collection, MutableMapping, MutableSequence, Union
from numpy import real
# todo: remove dependency on requests
import requests
from numpy import real
from ddd.data import Data, DataIterator, wrapitem
from ddd.phobjects import PHObject, isPHID
......@@ -185,17 +184,7 @@ class ConduitCursor(object):
self.resolve_phids(data=val)
if data is self.data and len(PHObject.instances):
phids = [phid for phid in PHObject.instances.keys()]
pprint(phids)
res = self.conduit.raw_request(method="phid.query", args={"phids": phids})
pprint(res.text)
objs = res.json()
for key, vals in objs["result"].items():
PHObject.instances[key].update(vals)
# for attr in vals.keys():
# setattr(PHObject.instances[key], attr, vals[attr])
return res
PHObject.resolve_phids(self.conduit)
def __iter__(self):
return DataIterator(self.data)
......@@ -220,6 +209,11 @@ class ConduitException(Exception):
self.result = result
self.message = message
def __repr__(self):
return "ConduitException(message='%s')" % self.message
def __str__(self):
return "ConduitException: " + self.message
def flatten_for_post(h, result=None, kk=None):
"""
......
from __future__ import annotations
from enum import Enum
from functools import total_ordering
from pydoc import classname
from symbol import classdef
from pprint import pprint
import time
from typing import ClassVar, Dict, Generic, Mapping, NewType, Type, TypeVar, Union
from datetime import datetime
......@@ -25,25 +25,14 @@ from datetime import datetime
"""
PHID = NewType("PHID", str)
class PHIDTypes(Enum):
PHOB = "PHObject"
PROJ = "Project"
TASK = "Task"
CMIT = "Commit"
XACT = "Transaction"
STRY = "FeedStory"
APPS = "Application"
PCOL = "ProjectColumn"
USER = "User"
Status = NewType('Status', str)
def isPHID(value: str):
return isinstance(value, str) and value.startswith("PHID-")
def PHIDType(phid: PHID):
def PHIDType(phid: PHID) -> Union[Type[PhabObjectBase], str]:
parts = phid.split("-")
phidtype = parts[1]
if phidtype in PHIDTypes.__members__:
......@@ -72,6 +61,17 @@ class SubclassCache(Generic[TID, T]):
@classmethod
def byid(cls, id: TID) -> Union[T, None]:
obj = cls.instances.get(id)
return obj
@classmethod
def resolve_phids(cls, conduit):
phids = [phid for phid in cls.instances.keys()]
res = conduit.raw_request(method="phid.query", args={"phids": phids})
objs = res.json()
for key, vals in objs["result"].items():
cls.instances[key].update(vals)
class PhabObjectBase(object):
......@@ -82,9 +82,14 @@ class PhabObjectBase(object):
fullName: str
dateCreated: datetime
dateModified: datetime
status: Status
def __init__(self, phid: PHID):
self.phid = phid
self.phid = PHID(phid)
self.name = "(Unknown object)"
self.status = Status("unknown")
self.fullName = ""
def update(self, data: Mapping):
self.__dict__.update(data)
......@@ -118,7 +123,7 @@ class PHObject(PhabObjectBase, SubclassCache[PHID, PhabObjectBase]):
self.__dict__.update(kwargs)
def __str__(self):
return "%s (%s)" % (self.phid, self.fullName)
return self.name if len(self.name) else self.phid
def __repr__(self):
# {self.__dict__}
......@@ -139,14 +144,15 @@ class PHObject(PhabObjectBase, SubclassCache[PHID, PhabObjectBase]):
return len(self.__dict__.keys()) > 1
@classmethod
def instance(cls, phid: PHID) -> Union[PhabObjectBase, None]:
if phid in __class__.instances:
obj = __class__.byid(phid)
def instance(cls, phid: PHID) -> PhabObjectBase:
obj = __class__.byid(phid)
if obj:
return obj
phidtype = PHIDType(phid)
typecls = __class__.subclass(phidtype, cls)
newinstance = typecls(phid)
if isinstance(phidtype, str):
phidtype = __class__.subclass(phidtype, cls)
newinstance = phidtype(phid)
__class__.instances[phid] = newinstance
return newinstance
......@@ -167,6 +173,19 @@ class Task(PHObject):
pass
class Commit(PHObject):
pass
class FeedStory(PHObject):
pass
class Application(PHObject):
pass
class Transaction(PHObject):
relationships = {
......@@ -176,4 +195,21 @@ class Transaction(PHObject):
"close-as-duplicate": 63,
}
class Event(PHObject):
""" Phabricator Calendar Event """
pass
class PHIDTypes(Enum):
PHOB = PHObject
PROJ = Project
TASK = Task
CMIT = Commit
CEVT = Event
XACT = Transaction
STRY = FeedStory
APPS = Application
PCOL = ProjectColumn
USER = User
#!/usr/bin/python3
import json
import sys
from collections import UserDict
from typing import Mapping
from ddd.phobjects import PHIDType, Task
from operator import itemgetter
import requests
import sys
import json
from pprint import pprint
from typing import Mapping
import pandas as pd
import requests
from IPython.display import display
import ddd
from ddd.phab import Conduit, ConduitException
from ddd.mw import version
from ddd.phab import Conduit, ConduitException
from ddd.phobjects import PHIDType, Task, PHObject
phab = Conduit()
pd.options.display.max_columns = None
pd.options.display.max_rows = None
# find all train blocker tasks
......@@ -20,6 +25,9 @@ r = phab.request(
"maniphest.search",
{
"queryKey": "ZKaMIUs_NEXo",
"constraints": {
'ids': ['249964'],
},
"limit": "50",
"attachments": {"projects": False, "columns": False},
},
......@@ -68,11 +76,14 @@ def gettransactions(taskids):
ov = [key for key in ov.keys()]
# ... we only care about tasks:
if len(ov) == 0 and len(nv) == 1 and PHIDType(nv[0]) is Task:
return ("added", nv[0])
elif len(ov) == 1 and len(nv) == 0 and PHIDType(ov[0]) is Task:
return ("removed", nv[0])
if len(ov) == 0 and len(nv) > 0 and PHIDType(nv[0]) is Task:
return ("added", [obj for obj in map(PHObject.instance, nv)])
elif len(ov) > 0 and len(nv) == 0 and PHIDType(ov[0]) is Task:
return ("removed", [obj for obj in map(PHObject.instance, ov)])
else:
print("--- new %s --- old %s ---" % (len(nv), len(ov)))
pprint(nv)
pprint(ov)
# ignore other edge types
return None
......@@ -83,10 +94,10 @@ def gettransactions(taskids):
ov = t["oldValue"]
for item in nv.items():
phid, action = item
return (action, phid)
return (action, PHObject.instance(phid))
# a comment was added
@ttype("core:comment")
#@ttype("core:comment")
def comment(t):
# todo: we could check for the risky revision template here, if we care
# to count that.
......@@ -100,6 +111,15 @@ def gettransactions(taskids):
if nv:
return ('version', nv)
#@ttype("core:columns")
def columns(t):
pprint(t)
#@ttype("status")
def status(t):
pprint(t)
transactions = phab.request(
"maniphest.gettasktransactions",
{
......@@ -116,7 +136,7 @@ def gettransactions(taskids):
# Ignore all transactions which do not have a matching formatter
# you can uncomment the print statement below to see what other
# transaction types are available:
# print(trnstype)
print(trnstype)
continue
# format the transaction data using the matching formatter function
formatted = formatters[trnstype](tr)
......@@ -127,12 +147,10 @@ def gettransactions(taskids):
# now collect all of the formatted transaction details
rows = [row for row in gettransactions(tasks)]
# now we could write a csv file or output the data to stdout
# for now, just output tsv:
for row in rows:
print("\t".join(row))
PHObject.resolve_phids(phab)
columns = ['task', 'timestamp', 'author','action','values']
data = pd.DataFrame(rows, columns=columns)
display(data)
if __name__ == "__main__":
pass
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment