Repository: regro/regolith

Issue:
ENH: l_projecta group by lead
desired behavior:
when --grp_by_lead is specified, output lools like:
```
sbillinge:
   20sb_prum1
   20sb_prum2
astudent:
   20as_prum1
   20as_prum2
```

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=h1) Report
> Merging [#468](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=desc) into [master](https://codecov.io/gh/regro/regolith/commit/26ad556f36eb83cc153ec26c567e5f0992a17dfc&el=desc) will **increase** coverage by `0.04%`.
> The diff coverage is `84.61%`.

[![Impacted file tree graph](https://codecov.io/gh/regro/regolith/pull/468/graphs/tree.svg?width=650&height=150&src=pr&token=YOWfAqEPVS)](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #468      +/-   ##
==========================================
+ Coverage   63.89%   63.94%   +0.04%     
==========================================
  Files          54       54              
  Lines        4878     4890      +12     
==========================================
+ Hits         3117     3127      +10     
- Misses       1761     1763       +2     
```


| [Impacted Files](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [regolith/helpers/l\_projectahelper.py](https://codecov.io/gh/regro/regolith/pull/468/diff?src=pr&el=tree#diff-cmVnb2xpdGgvaGVscGVycy9sX3Byb2plY3RhaGVscGVyLnB5) | `87.06% <84.61%> (-0.44%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=footer). Last update [26ad556...7ccbd40](https://codecov.io/gh/regro/regolith/pull/468?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

mwinitch: @sbillinge This is ready for review and merge
mwinitch: @sbillinge This is ready for review and merge
mwinitch: @sbillinge This is ready for review and merge

Patch:
diff --git a/news/grp_by_lead.rst b/news/grp_by_lead.rst
new file mode 100644
index 00000000..4de9662e
--- /dev/null
+++ b/news/grp_by_lead.rst
@@ -0,0 +1,12 @@
+**Added:**
+    * New flag to l_projecta called --grp_by_lead that groups all projectums by their leads
+
+**Changed:** None
+
+**Deprecated:** None
+
+**Removed:** None
+
+**Fixed:** None
+
+**Security:** None
\ No newline at end of file
diff --git a/regolith/helpers/l_projectahelper.py b/regolith/helpers/l_projectahelper.py
index 65a1ca4c..17b41f61 100644
--- a/regolith/helpers/l_projectahelper.py
+++ b/regolith/helpers/l_projectahelper.py
@@ -49,6 +49,8 @@ def subparser(subpi):
     subpi.add_argument("-g", "--grant",
                        help="Filter projecta by a grant ID"
                        )
+    subpi.add_argument("--grp_by_lead", action='store_true',
+                       help="Lists all projecta by their lead")
     subpi.add_argument("-f", "--filter", nargs="+",
                        help="Search this collection by giving key element pairs"
                        )
@@ -99,7 +101,8 @@ class ProjectaListerHelper(SoutHelperBase):
             results = search_collection(self.gtx["projecta"], rc.filter, rc.keys)
             print(results, end="")
             return
-        if (not rc.lead) and (not rc.person) and (not rc.ended) and (not rc.grant) and (not rc.verbose):
+
+        if (not rc.lead) and (not rc.person) and (not rc.ended) and (not rc.grant) and (not rc.verbose) and (not rc.grp_by_lead):
             return
         if rc.date:
             desired_date = date_parser.parse(rc.date).date()
@@ -114,9 +117,16 @@ class ProjectaListerHelper(SoutHelperBase):
         bad_stati = ["finished", "cancelled", "paused", "back_burner"]
         projecta = []
         end_projecta = []
+        grouped_projecta = {}
         if rc.lead and rc.person:
             raise RuntimeError(f"please specify either lead or person, not both")
         for projectum in self.gtx["projecta"]:
+            if rc.grp_by_lead:
+                if projectum.get('lead') not in grouped_projecta:
+                    grouped_projecta[projectum.get('lead')] = [projectum.get('_id')]
+                else:
+                    grouped_projecta[projectum.get('lead')].append(projectum.get('_id'))
+                continue
             if isinstance(projectum.get('group_members'), str):
                 projectum['group_members'] = [projectum.get('group_members')]
             if rc.lead and projectum.get('lead') != rc.lead:
@@ -162,6 +172,11 @@ class ProjectaListerHelper(SoutHelperBase):
                                                                                           p.get("description"),
                                                                                           p.get("lead"), members,
                                                                                           collaborators))
+        if rc.grp_by_lead:
+            for key, values in grouped_projecta.items():
+                print(f"{key}:")
+                for v in values:
+                    print(f"    {v}")
         projecta.sort()
         for i in projecta:
             print(i)


Test patch:
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index 5c073952..736fa917 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -39,6 +39,9 @@ helper_map = [
     (["helper", "l_projecta", "--grant", "SymPy-1.1"],
      "20ly_newprojectum\n20sb_firstprojectum\n"
      ),
+    (["helper", "l_projecta", "--grp_by_lead"],
+     "lyang:\n    20ly_newprojectum\nascopatz:\n    20sb_firstprojectum\n"
+     ),
     (["helper", "l_projecta", "--ended", "-d", "2020-06-02"],
      "20sb_firstprojectum    My first projectum\n    Lead: ascopatz    Members: ascopatz    Collaborators: aeinstein, pdirac\n"
      ),