Extended jenkins views enforcing by Categorize Views

Change-Id: I92289f8af5f26adff06483426d06bbc76d3acb09
diff --git a/README.rst b/README.rst
index 5e8a6e9..7dc19af 100644
--- a/README.rst
+++ b/README.rst
@@ -485,7 +485,7 @@
          my-list-view:
            enabled: true
            type: ListView
-           include_regex: ".\*."
+           include_regex: ".*"
          my-view:
            # set false to disable
            enabled: true
@@ -493,7 +493,25 @@
 
 View specific params:
 
-- include_regex for ListView
+- include_regex for ListView and CategorizedJobsView
+- categories for CategorizedJobsView
+
+Categorized views
+
+.. code-block:: yaml
+
+    jenkins:
+      client:
+        view:
+          my-categorized-view:
+            enabled: true
+            type: CategorizedJobsView
+            include_regex: ".*"
+            categories:
+              - group_regex: "aptly-.*-nightly-testing"
+                naming_rule: "Nightly -> Testing"
+              - group_regex: "aptly-.*-nightly-production"
+                naming_rule: "Nightly -> Production"
 
 
 Credentials enforcing from client
diff --git a/_states/jenkins_view.py b/_states/jenkins_view.py
index e14d3fd..6f0d995 100644
--- a/_states/jenkins_view.py
+++ b/_states/jenkins_view.py
@@ -1,4 +1,5 @@
 import logging
+from json import dumps
 logger = logging.getLogger(__name__)
 
 add_view_groovy = """\
@@ -12,6 +13,32 @@
     }}else{{
         print("EXISTS")
     }}
+  }}else if(view.getClass().getName().equals("org.jenkinsci.plugins.categorizedview.CategorizedJobsView")){{
+    def jsonSlurper = new groovy.json.JsonSlurper()
+    def inputCategories = jsonSlurper.parseText('{categories_string}')
+    def groupRegexes = inputCategories.stream().map{{e -> e["group_regex"]}}.collect(Collectors.toList())
+    def namingRules = inputCategories.stream().map{{e -> e["naming_rule"]}}.collect(Collectors.toList())
+    def actualCategories = view.categorizationCriteria
+    def equals = !actualCategories.isEmpty()
+    def include_regex="{include_regex}"
+    if(include_regex != "" && !view.getIncludeRegex().equals(include_regex)){{
+        view.setIncludeRegex(include_regex)
+        equals = false
+    }}
+    for(int i=0;i<actualCategories.size();i++){{
+      if(!groupRegexes.contains(actualCategories[i].groupRegex) || !namingRules.contains(actualCategories[i].namingRule)){{
+        equals = false
+      }}
+    }}
+    if(!equals){{
+      view.categorizationCriteria.clear()
+      for(int i=0;i<inputCategories.size();i++){{
+        view.categorizationCriteria.add(new GroupingRule(inputCategories[i].group_regex,inputCategories[i].naming_rule))
+      }}
+      print("ADDED/CHANGED")
+    }}else{{
+      print("EXISTS")
+    }}
   }}else{{
     print("EXISTS")
   }}
@@ -24,7 +51,7 @@
     print("FAILED")
   }}
 }}
-""" # noqa
+"""  # noqa
 
 remove_view_groovy = """\
 view = Jenkins.instance.getView("{view_name}")
@@ -38,7 +65,7 @@
 }}else{{
   print("NOT PRESENT")
 }}
-""" # noqa
+"""  # noqa
 
 
 def present(name, type="ListView", **kwargs):
@@ -79,12 +106,26 @@
         view_def = "view = new {}(\"{}\")".format(type, name)
         # handle view specific params
         include_regex = kwargs.get('include_regex')
+        categories_string = ""
         if type == "ListView":
             if include_regex:
-                view_def += "\nview.setIncludeRegex(\"{}\")".format(include_regex)
+                view_def += "\nview.setIncludeRegex(\"{}\")".format(
+                    include_regex)
+        if type == "CategorizedJobsView":
+            # add imports for categorized views
+            template = "import java.util.stream.Collectors\nimport org.jenkinsci.plugins.categorizedview.CategorizedJobsView\nimport org.jenkinsci.plugins.categorizedview.GroupingRule\n" + template
+            if include_regex:
+                view_def += "\nview.setIncludeRegex(\"{}\")".format(
+                    include_regex)
+            categories = kwargs.get('categories', [])
+            for category in categories:
+                view_def += "\nview.categorizationCriteria.add(new GroupingRule(\"{}\", \"{}\"))".format(
+                    category["group_regex"], category["naming_rule"])
+            # create catogories string readable in groovy
+            categories_string = dumps(categories)
 
         call_result = __salt__['jenkins_common.call_groovy_script'](
-            template, {"view_def": view_def, "view_name": name, "type": type if type else "", "include_regex": include_regex if include_regex else ""})
+            template, {"view_def": view_def, "view_name": name, "type": type if type else "", "include_regex": include_regex if include_regex else "", "categories_string": categories_string if categories_string else ""})
         if call_result["code"] == 200 and call_result["msg"] in success_msgs:
             status = call_result["msg"]
             if status == success_msgs[0]:
@@ -96,6 +137,6 @@
             logger.error(
                 "Jenkins view API call failure: %s", call_result["msg"])
             ret['comment'] = 'Jenkins view API call failure: %s' % (call_result[
-                                                                           "msg"])
+                "msg"])
     ret['result'] = None if test else result
     return ret