commit 1fbf6912cb99a747b286ce0417c1c9cda1dcb203
parent 29f5171a3885a495a6d122cd09e20fa61f34c3a3
Author: lash <dev@holbrook.no>
Date: Sun, 1 Jan 2023 14:02:27 +0000
Add dependency setting for issues
Diffstat:
9 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -3,3 +3,4 @@ __pycache__
build/
dist/
*.egg-info
+.piknik
diff --git a/CHANGELOG b/CHANGELOG
@@ -1,3 +1,6 @@
+- 0.2.3
+ * Add possibility to set dependencies between issues
+ * Set default data directory under working directory
- 0.2.2
* Add html requirements to default install
- 0.2.1
diff --git a/piknik/basket.py b/piknik/basket.py
@@ -162,6 +162,24 @@ class Basket:
def get_msg(self, issue_id, envelope_callback=None, message_callback=None, post_callback=None):
return self.__get_msg(issue_id, envelope_callback=envelope_callback, message_callback=message_callback, post_callback=post_callback)
+
+ def dep(self, issue_id, dependency_issue_id):
+ r = self.state.get(issue_id)
+ self.state.get(dependency_issue_id)
+ o = Issue.from_str(r)
+ r = o.dep(dependency_issue_id)
+ self.state.replace(issue_id, contents=str(o))
+ return r
+
+
+ def undep(self, issue_id, dependency_issue_id):
+ r = self.state.get(issue_id)
+ self.state.get(dependency_issue_id)
+ o = Issue.from_str(r)
+ r = o.undep(dependency_issue_id)
+ self.state.replace(issue_id, contents=str(o))
+ return r
+
def assign(self, issue_id, identity):
r = self.state.get(issue_id)
diff --git a/piknik/error.py b/piknik/error.py
@@ -2,7 +2,7 @@ class DeadIssue(Exception):
pass
-class AlreadyAssignedError(Exception):
+class ExistsError(Exception):
pass
diff --git a/piknik/issue.py b/piknik/issue.py
@@ -6,7 +6,7 @@ import datetime
# local imports
from piknik.identity import Identity
from piknik.error import UnknownIdentityError
-from piknik.error import AlreadyAssignedError
+from piknik.error import ExistsError
class Issue:
@@ -18,6 +18,7 @@ class Issue:
self.title = title
self.assigned = []
self.assigned_time = []
+ self.dependencies = []
self.owner_idx = 0
@@ -33,17 +34,32 @@ class Issue:
if r['owner'] == None or k == r['owner']:
r['owner'] = k
o.owner_idx = i
+ for v in r['dependencies']:
+ o.dep(v)
return o
def assign(self, identity, t=None):
if identity in self.assigned:
- raise AlreadyAssignedError(identity)
+ raise ExistsError(identity)
if t == None:
t = datetime.datetime.utcnow()
self.assigned.append(identity)
self.assigned_time.append(t)
+
+ def dep(self, dependency_issue_id):
+ if dependency_issue_id in self.dependencies:
+ raise ExistsError(self.id, dependency_issue_id)
+ self.dependencies.append(dependency_issue_id)
+
+
+ def undep(self, dependency_issue_id=None):
+ if dependency_issue_id == None:
+ self.dependencies = []
+ return
+ self.dependencies.remove(dependency_issue_id)
+
def get_assigned(self):
return list(zip(self.assigned, self.assigned_time))
@@ -86,6 +102,7 @@ class Issue:
'id': str(self.id),
'title': self.title,
'assigned': {},
+ 'dependencies': self.dependencies,
'owner': None,
}
diff --git a/piknik/render/plain.py b/piknik/render/plain.py
@@ -88,6 +88,10 @@ tags: {}
#s = '\t' + str(s) + '\n'
assigns.append(ss)
s += ', '.join(assigns) + '\n'
+
+ if len(issue.dependencies) > 0:
+ s += 'depends on: '
+ s += ', '.join(issue.dependencies) + '\n'
self.add(s, accumulator=accumulator)
super(Renderer, self).apply_issue(state, issue, tags, accumulator=accumulator)
diff --git a/piknik/runnable/mod.py b/piknik/runnable/mod.py
@@ -1,10 +1,14 @@
import sys
import argparse
+import logging
from piknik import Basket
from piknik import Issue
from piknik.store import FileStoreFactory
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
argp = argparse.ArgumentParser()
argp.add_argument('-d', type=str, help='Data directory')
@@ -19,6 +23,8 @@ argp.add_argument('-u', '--untag', type=str, action='append', default=[], help='
argp.add_argument('-a', '--assign', type=str, action='append', default=[], help='Assign given identity to issue')
argp.add_argument('--unassign', type=str, action='append', default=[], help='Unassign given identity from issue')
argp.add_argument('-o', '--owner', type=str, help='Set given identity as owner of issue')
+argp.add_argument('--dep', action='append', default=[], type=str, help='Set issue dependency')
+argp.add_argument('--undep', action='append', default=[], type=str, help='Remove issue dependency')
argp.add_argument('issue_id', type=str, help='Issue id to modify')
arg = argp.parse_args(sys.argv[1:])
@@ -51,7 +57,13 @@ def main():
for v in arg.assign:
basket.assign(arg.issue_id, v)
-
+
+ for v in arg.undep:
+ basket.undep(arg.issue_id, v)
+
+ for v in arg.dep:
+ basket.dep(arg.issue_id, v)
+
if arg.owner:
basket.owner(arg.issue_id, arg.owner)
diff --git a/piknik/store/__init__.py b/piknik/store/__init__.py
@@ -47,7 +47,7 @@ class FileStoreFactory:
def __init__(self, directory=None):
if directory == None:
- directory = os.path.join(os.environ['HOME'], '.piknik')
+ directory = os.path.join('.', '.piknik')
self.directory = directory
diff --git a/tests/test_dep.py b/tests/test_dep.py
@@ -0,0 +1,34 @@
+# standard imports
+import unittest
+import logging
+import json
+
+# local imports
+from piknik import Issue
+from piknik.identity import Identity
+from piknik.error import UnknownIdentityError
+from piknik.error import ExistsError
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+
+class TestAssign(unittest.TestCase):
+
+ def setUp(self):
+ self.alice = 'F3FAF668E82EF5124D5187BAEF26F4682343F692'
+ self.bob = 'F645E047EE5BC4E2824C94DB42DC91CFA8ABA02B'
+
+
+ def test_dep_basic(self):
+ one = Issue('foo')
+ one.dep('bar')
+ one.dep('baz')
+ with self.assertRaises(ExistsError):
+ one.dep('bar')
+ one.undep('bar')
+ self.assertEqual(len(one.dependencies), 1)
+
+
+if __name__ == '__main__':
+ unittest.main()