Repository: regro/regolith

Issue:
BUG: u_milestone
problem with the due_date. 
loading ../db/projecta.yml...
Traceback (most recent call last):
  File "/Users/danielayano/miniconda3/envs/regolith/bin/regolith", line 7, in <module>
    exec(compile(f.read(), __file__, 'exec'))
  File "/Users/danielayano/dev/regolith/scripts/regolith", line 3, in <module>
    main()
  File "/Users/danielayano/dev/regolith/regolith/main.py", line 337, in main
    CONNECTED_COMMANDS[rc.cmd](rc)
  File "/Users/danielayano/dev/regolith/regolith/commands.py", line 150, in helper
    hlpr.hlp()
  File "/Users/danielayano/dev/regolith/regolith/helpers/basehelper.py", line 93, in hlp
    getattr(self, cmd)()
  File "/Users/danielayano/dev/regolith/regolith/helpers/u_milestonehelper.py", line 84, in db_updater
    all_milestones.sort(key=lambda x: x['due_date'], reverse=False)
TypeError: '<' not supported between instances of 'datetime.date' and 'str'

Discussion:
sbillinge: btw,  we should probably have a ``-v`` ``--verbose`` mode where the current values from the milestones are printed, so we know what needs to be updated
dy2403: > btw, we should probably have a `-v` `--verbose` mode where the current values from the milestones are printed, so we know what needs to be updated

so when the user does --v, it prints:
     "Please choose from one of the following to update/add:\n"
     "1. new milestone\n"
     "2. Kick off meeting    due date: 2020-05-06    finished\n"
     "3. Project lead presentation    due date: 2020-05-20    proposed\n"
     "4. planning meeting    due date: 2020-05-30    converged\n"
     "5. deliverable    due date: 2021-05-05    finalized\n"

??

sbillinge: > 
> 
> > btw, we should probably have a `-v` `--verbose` mode where the current values from the milestones are printed, so we know what needs to be updated
> 
> just to make sure what the verbose should do:
> when the user does -v, it prints:
> "Please choose from one of the following to update/add:\n"
> "1. new milestone\n"
> "2. Kick off meeting due date: 2020-05-06 finished\n"
> "3. Project lead presentation due date: 2020-05-20 proposed\n"
> "4. planning meeting due date: 2020-05-30 converged\n"
> "5. deliverable due date: 2021-05-05 finalized\n"
> 
> should it be like this?

more like this
```
"Please choose from one of the following to update/add:\n"
1. new milestone
2. Kick off meeting due: 2020-06-11
      audience: [lead, pi, group_members]
      notes:
          - this is a note
          - this is another note
      objective: converge deliverable and make first milestones
      status: finished
      type: meeting
3. Push PR due: 2020-06-30
...
```


Patch:
diff --git a/regolith/helpers/u_milestonehelper.py b/regolith/helpers/u_milestonehelper.py
index affe269b..983cc59a 100644
--- a/regolith/helpers/u_milestonehelper.py
+++ b/regolith/helpers/u_milestonehelper.py
@@ -8,7 +8,7 @@ from dateutil import parser
 from regolith.helpers.basehelper import DbHelperBase
 from regolith.fsclient import _id_key
 from regolith.tools import all_docs_from_collection
-
+from regolith.dates import get_due_date
 
 TARGET_COLL = "projecta"
 ALLOWED_TYPES = {"m":"meeting", "r":"release", "p":"pull request", "o":"other"}
@@ -16,8 +16,11 @@ ALLOWED_STATUS = {"p":"proposed", "s":"started", "f":"finished", "b":"back_burne
 
 def subparser(subpi):
     subpi.add_argument("projectum_id", help="the id of the projectum")
-    subpi.add_argument("--number",
-                        help="number of the milestone to update from numbered list")
+    subpi.add_argument("-v", "--verbose", action="store_true",
+                        help="gives a list of the milestones available to update.")
+    subpi.add_argument("--index",
+                        help="index of the item in the enumerated list to update",
+                        type = int)
     subpi.add_argument("--due_date",
                        help="new due date of the milestone in ISO format (YYYY-MM-DD) "
                             "required to add a new milestone")
@@ -65,50 +68,47 @@ class MilestoneUpdaterHelper(DbHelperBase):
     def db_updater(self):
         rc = self.rc
         key = rc.projectum_id
-        coll = self.gtx[rc.coll]
-        pdocl = list(filter(lambda doc: doc["_id"] == key, coll))
-        if len(pdocl) == 0:
-            raise RuntimeError(
-                "This entry appears to not exist in the collection")
         filterid = {'_id': key}
-        current = rc.client.find_one(rc.database, rc.coll, filterid)
-        milestones = current.get('milestones')
-        deliverable = current.get('deliverable')
-        kickoff = current.get('kickoff')
+        target_prum = rc.client.find_one(rc.database, rc.coll, filterid)
+        if not target_prum:
+            raise RuntimeError(f"Cannot find {key} in the projecta collection")
+        milestones = target_prum.get('milestones')
+        deliverable = target_prum.get('deliverable')
+        kickoff = target_prum.get('kickoff')
         deliverable['identifier'] = 'deliverable'
         kickoff['identifier'] = 'kickoff'
         for item in milestones:
             item['identifier'] = 'milestones'
         all_milestones = [deliverable, kickoff]
         all_milestones.extend(milestones)
-        all_milestones.sort(key=lambda x: x['due_date'], reverse=False)
-        index = 2
-        numbered_milestones = {}
-        for item in all_milestones:
-            numbered_milestones[str(index)] = item
-            index += 1
-        if not rc.number:
+        for i in all_milestones:
+            i['due_date'] = get_due_date(i)
+        all_milestones.sort(key = lambda x: x['due_date'], reverse=False)
+        index_list = list(range(2, (len(all_milestones)+2)))
+        if rc.verbose:
             print("Please choose from one of the following to update/add:")
             print("1. new milestone")
-            for i in numbered_milestones:
-                current_mil = numbered_milestones[i]
-                if 'name' in current_mil:
-                    print("{}. {}    due date: {}    {}".format(i, current_mil["name"],
-                                                    current_mil["due_date"], current_mil["status"]))
+            for i, j in zip(index_list, all_milestones):
+                if j['identifier'] == 'milestones':
+                    print(f"{i}. {j['name']}    due date: {j['due_date']}:\n"
+                          f"     audience: {j['audience']}\n"
+                          f"     objetive: {j['objective']}\n"
+                          f"     status: {j['status']}\n"
+                          f"     type: {j['type']}")
                 else:
-                    print("{}. {}    due date: {}    {}".format(i, current_mil['identifier'],
-                                                                current_mil["due_date"], current_mil["status"]))
-                del current_mil['identifier']
+                    print(f"{i}. {j['identifier']}    due date: {j['due_date']}:\n"
+                          f"     audience: {j['audience']}\n"
+                          f"     status: {j['status']}")
+                del j['identifier']
             return
         pdoc = {}
-        if int(rc.number) == 1:
+        if rc.index == 1:
             mil = {}
             if not rc.due_date or not rc.name or not rc.objective:
-                for i in numbered_milestones:
-                    current_mil = numbered_milestones[i]
-                    del current_mil['identifier']
                 raise RuntimeError("name, objective, and due date are required for a new milestone")
-            mil.update({'due_date': rc.due_date, 'objective': rc.objective, 'name': rc.name})
+            mil.update({'due_date': rc.due_date})
+            mil['due_date'] = get_due_date(mil)
+            mil.update({'objective': rc.objective, 'name': rc.name})
             mil.update({'audience': ['lead', 'pi', 'group_members']})
             if rc.status:
                 mil.update({'status': ALLOWED_STATUS[rc.status]})
@@ -120,26 +120,27 @@ class MilestoneUpdaterHelper(DbHelperBase):
                 mil.update({'type': 'meeting'})
             milestones.append(mil)
             pdoc = {'milestones':milestones}
-        if int(rc.number) > 1:
-            doc = numbered_milestones[rc.number]
+        if rc.index > 1:
+            doc = all_milestones[rc.index-2]
             identifier = doc['identifier']
             if rc.due_date:
-                doc.update({'due_date':rc.due_date})
+                doc.update({'due_date': rc.due_date})
             if rc.status:
                 doc.update({'status': ALLOWED_STATUS[rc.status]})
+            if rc.type:
+                doc.update({'type': ALLOWED_TYPES[rc.type]})
+            doc['due_date'] = get_due_date(doc)
             if identifier == 'milestones':
                 new_mil = []
-                for i in numbered_milestones:
-                    if numbered_milestones[i]['identifier'] =='milestones' and i!= rc.number:
-                        new_mil.append(numbered_milestones[i])
+                for i, j in zip(index_list, all_milestones):
+                    if j['identifier'] == 'milestones' and i != rc.index:
+                        new_mil.append(j)
                 new_mil.append(doc)
                 pdoc.update({'milestones':new_mil})
             else:
                 pdoc.update({identifier:doc})
-        for i in numbered_milestones:
-            current_mil = numbered_milestones[i]
-            del current_mil['identifier']
-
+        for i in all_milestones:
+            del i['identifier']
         rc.client.update_one(rc.database, rc.coll, filterid, pdoc)
         print("{} has been updated in projecta".format(key))
 


Test patch:
diff --git a/tests/u_milestone.rst b/news/u_milestone.rst
similarity index 53%
rename from tests/u_milestone.rst
rename to news/u_milestone.rst
index b40f6681..dd022f3f 100644
--- a/tests/u_milestone.rst
+++ b/news/u_milestone.rst
@@ -1,5 +1,5 @@
 **Added:**
- * a milestone helper for adding/updating milestones/deliverable to the milestones collection.
+ * a milestones helper for adding/updating milestones to the projecta collection.
 
 **Changed:** None
 
diff --git a/tests/outputs/u_logurl/projecta.yaml b/tests/outputs/u_logurl/projecta.yaml
index fe707fb4..fdf40e35 100644
--- a/tests/outputs/u_logurl/projecta.yaml
+++ b/tests/outputs/u_logurl/projecta.yaml
@@ -55,7 +55,7 @@
   deliverable:
     audience:
       - beginning grad in chemistry
-    due_date: '2021-05-05'
+    due_date: 2021-05-05
     success_def: audience is happy
     scope:
       - UCs that are supported or some other scope description if it is software
@@ -73,7 +73,7 @@
     - ascopatz
   kickoff:
     date: '2020-05-05'
-    due_date: '2020-05-06'
+    due_date: 2020-05-06
     name: Kick off meeting
     objective: introduce project to the lead
     audience:
@@ -84,7 +84,7 @@
   lead: ascopatz
   log_url: https://docs.google.com/document/d/1pQMFpuI
   milestones:
-    - due_date: '2020-05-20'
+    - due_date: 2020-05-20
       name: Project lead presentation
       objective: lead presents background reading and initial project plan
       audience:
@@ -93,15 +93,15 @@
         - group_members
       status: proposed
       type: meeting
-    - due_date: '2020-05-30'
+    - due_date: 2020-05-30
       name: planning meeting
       objective: develop a detailed plan with dates
       audience:
         - lead
         - pi
         - group_members
-      status: converged
-      type: pr
+      status: proposed
+      type: meeting
   name: First Projectum
   pi_id: scopatz
   status: proposed
diff --git a/tests/outputs/u_milestone/projecta.yaml b/tests/outputs/u_milestone/projecta.yaml
index d2ef308a..08cbbf4a 100644
--- a/tests/outputs/u_milestone/projecta.yaml
+++ b/tests/outputs/u_milestone/projecta.yaml
@@ -55,7 +55,7 @@
   deliverable:
     audience:
       - beginning grad in chemistry
-    due_date: '2021-05-05'
+    due_date: 2021-05-05
     success_def: audience is happy
     scope:
       - UCs that are supported or some other scope description if it is software
@@ -73,7 +73,7 @@
     - ascopatz
   kickoff:
     date: '2020-05-05'
-    due_date: '2020-05-06'
+    due_date: 2020-05-06
     name: Kick off meeting
     objective: introduce project to the lead
     audience:
@@ -84,7 +84,7 @@
   lead: ascopatz
   log_url: https://docs.google.com/document/d/1YC_wtW5Q
   milestones:
-    - due_date: '2020-05-20'
+    - due_date: 2020-05-20
       name: Project lead presentation
       objective: lead presents background reading and initial project plan
       audience:
@@ -93,15 +93,15 @@
         - group_members
       status: proposed
       type: meeting
-    - due_date: '2020-05-30'
+    - due_date: 2020-05-30
       name: planning meeting
       objective: develop a detailed plan with dates
       audience:
         - lead
         - pi
         - group_members
-      status: converged
-      type: pr
+      status: proposed
+      type: meeting
   name: First Projectum
   pi_id: scopatz
   status: proposed
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index 362a8e47..1946d93e 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -61,17 +61,29 @@ helper_map = [
     (["helper", "l_contacts", "run", "-n", "ny", "-i", "col", "-o", "coffee", "-d", "2019-01-15", "-r", "2"],
      ""
      ),
-    (["helper", "u_milestone", "20sb_firstprojectum", "--number", "4",
-      "-s", "c", "--due_date", "2020-05-30"],
+    (["helper", "u_milestone", "20sb_firstprojectum", "--index", "4",
+      "-s", "p","-t", "m", "--due_date", "2020-05-30"],
      "20sb_firstprojectum has been updated in projecta\n"
      ),
-    (["helper", "u_milestone", "20sb_firstprojectum"],
+    (["helper", "u_milestone", "20sb_firstprojectum", "-v"],
      "Please choose from one of the following to update/add:\n"
      "1. new milestone\n"
-     "2. Kick off meeting    due date: 2020-05-06    finished\n"
-     "3. Project lead presentation    due date: 2020-05-20    proposed\n"
-     "4. planning meeting    due date: 2020-05-30    converged\n"
-     "5. deliverable    due date: 2021-05-05    finalized\n"
+     "2. kickoff    due date: 2020-05-06:\n"
+     "     audience: ['lead', 'pi', 'group_members']\n"
+     "     status: finished\n"
+     "3. Project lead presentation    due date: 2020-05-20:\n"
+     "     audience: ['lead', 'pi', 'group_members']\n"
+     "     objetive: lead presents background reading and initial project plan\n"
+     "     status: proposed\n"
+     "     type: meeting\n"
+     "4. planning meeting    due date: 2020-05-30:\n"
+     "     audience: ['lead', 'pi', 'group_members']\n"
+     "     objetive: develop a detailed plan with dates\n"
+     "     status: proposed\n"
+     "     type: meeting\n"
+     "5. deliverable    due date: 2021-05-05:\n"
+     "     audience: ['beginning grad in chemistry']\n"
+     "     status: finalized\n"
      ),
     (["helper", "u_logurl", "20sb", "-n", "1", "https://docs.google.com/document/d/1pQMFpuI"],
      "20sb_firstprojectum has been updated with a log_url of https://docs.google.com/document/d/1pQMFpuI\n"