Functions to fetch job params from commit message

Related-Prod: PRODX-22233

Change-Id: I7204b14145f61f8b04bb879d1c9df7f878b17626
diff --git a/src/com/mirantis/mk/KaasUtils.groovy b/src/com/mirantis/mk/KaasUtils.groovy
index b42cbc4..702a4ac 100644
--- a/src/com/mirantis/mk/KaasUtils.groovy
+++ b/src/com/mirantis/mk/KaasUtils.groovy
@@ -818,3 +818,95 @@
             error('Net map locks supported for Equinix/Vsphere providers only')
     }
 }
+
+/**
+* getCIKeywordsFromCommitMsg parses commit message and returns all gerrit keywords with their values as a list of maps.
+* Each element (map) contains keys 'key' for keyword name and 'value' for its value.
+* If keyword contains only 'key' part then 'value' is boolean True.
+* This function does not perform keywords validation.
+* First line of a commit message is ignored.
+* To use '[' or ']' characters inside keyword prepend it with backslash '\'.
+* TODO: Remove backslash chars from values if they prepend '[' or ']'.
+**/
+
+List getCIKeywordsFromCommitMsg() {
+    String commitMsg = env.GERRIT_CHANGE_COMMIT_MESSAGE ? new String(env.GERRIT_CHANGE_COMMIT_MESSAGE.decodeBase64()) : ''
+    List commitMsgLines = commitMsg.split('\n')
+    List keywords = []
+    if (commitMsgLines.size() < 2) {
+        return keywords
+    }
+
+    String commitMsgBody = commitMsgLines[1..-1].join('\n')
+
+    // Split commit message body to chunks using '[' or ']' as delimiter,
+    // ignoring them if prepended by backslash (regex negative lookbehind).
+    // Resulting list will have chunks between '[' and ']' at odd indexes.
+    List parts = commitMsgBody.split(/(?<!\\)[\[\]]/)
+
+    // Iterate chunks by odd indexes only, trim values and split to
+    // <key> / <value> pair where <key> is the part of a sting before the first
+    // whitespace delimiter, and <value> is the rest (may include whitespaces).
+    // If there is no whitespace in the string then this is a 'switch'
+    // and <value> will be boolean True.
+    for (i = 1; i < parts.size(); i += 2) {
+        def (key, value) = (parts[i].trim().split(/\s+/, 2) + [true, ])[0..1]
+        keywords.add(['key': key, 'value': value])
+    }
+
+    return keywords
+}
+
+/**
+* getJobsParamsFromCommitMsg parses list of CI keywords and returns values of 'job-params' keyword
+* that were specified for given job name. `job-params` keyword has the following structure
+*
+*   [job-params <job name> <parameter name> <parameter value>]
+*
+* Return value is a Map that contains those parameters using the following structure:
+*
+*    <job name>:
+*       <parameter name>: <parameter value>
+*
+**/
+Map getJobsParamsFromCommitMsg() {
+    List keywords = getCIKeywordsFromCommitMsg()
+
+    List jobsParamsList = []
+    keywords.findAll{ it.key == 'job-params' }.collect(jobsParamsList) {
+        def (name, params) = (it['value'].split(/\s+/, 2) + [null, ])[0..1]
+        def (key, value) = params.split(/\s+/, 2)
+        ['name': name, 'key': key, 'value': value]
+    }
+
+    Map jobsParams = jobsParamsList.inject([:]) { result, it ->
+        if (!result.containsKey(it.name)) {
+            result[it.name] = [:]
+        }
+        result[it.name][it.key] = it.value
+        result
+    }
+
+    return jobsParams
+}
+
+
+/**
+* getJobParamsFromCommitMsg returns key:value Map of parameters set for a job in commit message.
+* It uses getJobsParamsFromCommitMsg to get all parameters from commit message and then
+* uses only those parametes that were set to all jobs (with <job name> == '*') or to
+* a particular job. Parameters set to a particular job have higher precedence.
+*
+* Return value is a Map that contains those parameters:
+*
+*    <parameter name>: <parameter value>
+*
+**/
+Map getJobParamsFromCommitMsg(String jobName) {
+    jobsParams = getJobsParamsFromCommitMsg()
+    jobParams = jobsParams.getOrDefault('*', [:])
+    if (jobName) {
+        jobParams.putAll(jobsParams.getOrDefault(jobName, [:]))
+    }
+    return jobParams
+}