Repository: iterative/dvc

Issue:
introduce `dvc pl list`
E.g.

```
1.dvc
2.dvc
...
1000.dvc
===============
isolated1.dvc
===============
isolated2.dvc

3 pipelines total 
```

Discussion:

Patch:
diff --git a/dvc/cli.py b/dvc/cli.py
index c57a103ca..39ec74680 100644
--- a/dvc/cli.py
+++ b/dvc/cli.py
@@ -25,7 +25,7 @@ from dvc.command.metrics import CmdMetricsRemove, CmdMetricsModify
 from dvc.command.install import CmdInstall
 from dvc.command.root import CmdRoot
 from dvc.command.lock import CmdLock, CmdUnlock
-from dvc.command.pipeline import CmdPipelineShow
+from dvc.command.pipeline import CmdPipelineShow, CmdPipelineList
 from dvc.logger import Logger
 from dvc import VERSION
 
@@ -927,6 +927,14 @@ def parse_args(argv=None):
                         help="DVC files. 'Dvcfile' by default.")
     pipeline_show_parser.set_defaults(func=CmdPipelineShow)
 
+    PIPELINE_LIST_HELP = 'List pipelines.'
+    pipeline_list_parser = pipeline_subparsers.add_parser(
+                        'list',
+                        parents=[parent_parser],
+                        description=PIPELINE_LIST_HELP,
+                        help=PIPELINE_LIST_HELP)
+    pipeline_list_parser.set_defaults(func=CmdPipelineList)
+
     args = parser.parse_args(argv)
 
     if (issubclass(args.func, CmdRepro)
diff --git a/dvc/command/pipeline.py b/dvc/command/pipeline.py
index ac682b282..83eb40ebc 100644
--- a/dvc/command/pipeline.py
+++ b/dvc/command/pipeline.py
@@ -110,3 +110,19 @@ class CmdPipelineShow(CmdBase):
                 self.project.logger.error(msg, ex)
                 return 1
         return 0
+
+
+class CmdPipelineList(CmdBase):
+    def run(self):
+        import networkx
+
+        pipelines = self.project.pipelines()
+        for p in pipelines:
+            stages = networkx.get_node_attributes(p, 'stage')
+            for stage in stages:
+                self.project.logger.info(stage)
+            if len(stages) != 0:
+                self.project.logger.info("="*80)
+        self.project.logger.info("{} pipeline(s) total".format(len(pipelines)))
+
+        return 0


Test patch:
diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py
index ec1d829c8..7fe287298 100644
--- a/tests/test_pipeline.py
+++ b/tests/test_pipeline.py
@@ -165,3 +165,15 @@ class TestPipelineShowDeep(TestReproChangedDeepData):
     def test_non_existing(self):
         ret = main(['pipeline', 'show', 'non-existing'])
         self.assertNotEqual(ret, 0)
+
+
+class TestPipelineListEmpty(TestDvc):
+    def test(self):
+        ret = main(['pipeline', 'list'])
+        self.assertEqual(ret, 0)
+
+
+class TestPipelineListSingle(TestPipelineShowDeep):
+    def test(self):
+        ret = main(['pipeline', 'list'])
+        self.assertEqual(ret, 0)