Merge "[fix][core] common lib calling inside kaasUtils"
diff --git a/src/com/mirantis/mk/DockerImageScanner.groovy b/src/com/mirantis/mk/DockerImageScanner.groovy
index ec449f9..ff4a73e 100644
--- a/src/com/mirantis/mk/DockerImageScanner.groovy
+++ b/src/com/mirantis/mk/DockerImageScanner.groovy
@@ -185,8 +185,6 @@
     imageDict.each{
         image ->
             def image_key = image.key.replaceAll(/(^[a-z0-9-.]+.mirantis.(net|com)\/|:.*$)/, '')
-            // Temporary exclude tungsten images
-            if (image_key.startsWith('tungsten/') || image_key.startsWith('tungsten-operator/')) { return }
             jira_summary = "[${image_key}] Found CVEs in Docker image"
             jira_description = "{noformat}${image.key}\\n"
             image.value.each{
@@ -237,6 +235,7 @@
                 def post_comment_response = callREST("${uri}/${jira_key[0]}/comment", auth, 'POST', post_comment_json)
                 if ( post_comment_response['responseCode'] == 201 ) {
                     def issueCommentJSON = new JsonSlurper().parseText(post_comment_response["responseText"])
+                    print "\n\nComment was posted to ${jira_key[0]} for ${image_key} and ${image.key}"
                 } else {
                     print "\nComment to ${jira_key[0]} Jira issue was not posted"
                 }
@@ -245,11 +244,12 @@
                 if (post_issue_response['responseCode'] == 201) {
                     def issueJSON = new JsonSlurper().parseText(post_issue_response["responseText"])
                     dict = updateDictionary(issueJSON['key'], dict, uri, auth, jiraUserID)
+                    print "\n\nJira issue was created ${issueJSON['key']} for ${image_key} and ${image.key}"
                 } else {
                     print "\n${image.key} CVE issues were not published\n"
                 }
             } else {
-                print "\n\nNothing to process for for ${image_key} and ${image.key}"
+                print "\n\nNothing to process for ${image_key} and ${image.key}"
             }
     }
 }
diff --git a/src/com/mirantis/mk/Gerrit.groovy b/src/com/mirantis/mk/Gerrit.groovy
index 85b0411..c33dc5e 100644
--- a/src/com/mirantis/mk/Gerrit.groovy
+++ b/src/com/mirantis/mk/Gerrit.groovy
@@ -460,3 +460,71 @@
         return getGerritChange(gerritUser, gerritHost, jsonChange['number'], gerritCredentials, true)
     }
 }
+
+/**
+ * Download change from gerrit, if needed repository maybe pre cloned
+ *
+ * @param path               Directory to checkout repository to
+ * @param url                Source Gerrit repository URL
+ * @param reference          Gerrit reference to download (e.g refs/changes/77/66777/16)
+ * @param type               type of gerrit download
+ * @param credentialsId      Credentials ID to use for source Git
+ * @param gitCheckoutParams  map with additional parameters for git.checkoutGitRepository method e.g:
+ *                           [ branch: 'master', poll: true, timeout: 10, depth: 0 ]
+ * @param doGitClone      boolean whether to pre clone and do some checkout
+ */
+def downloadChange(path, url, reference, credentialsId, type = 'cherry-pick', doGitClone = true, Map gitCheckoutParams = [:]){
+    def git = new com.mirantis.mk.Git()
+    def ssh = new com.mirantis.mk.Ssh()
+    def cmd
+    switch(type) {
+        case 'cherry-pick':
+            cmd = "git fetch ${url} ${reference} && git cherry-pick FETCH_HEAD"
+            break;
+        case 'format-patch':
+            cmd = "git fetch ${url} ${reference} && git format-patch -1 --stdout FETCH_HEAD"
+            break;
+        case 'pull':
+            cmd = "git pull ${url} ${reference}"
+            break;
+        default:
+            error("Unsupported gerrit download type")
+    }
+    if (doGitClone) {
+        def branch =  gitCheckoutParams.get('branch', 'master')
+        def poll = gitCheckoutParams.get('poll', true)
+        def timeout = gitCheckoutParams.get('timeout', 10)
+        def depth = gitCheckoutParams.get('depth', 0)
+        git.checkoutGitRepository(path, url, branch, credentialsId, poll, timeout, depth, '')
+    }
+    ssh.prepareSshAgentKey(credentialsId)
+    dir(path){
+         ssh.agentSh(cmd)
+    }
+}
+
+/**
+ * Parse gerrit event text and if Workflow +1 is detected,
+ * return true
+ *
+ * @param gerritEventCommentText  gerrit event comment text
+ * @param gerritEventType         type of gerrit event
+ */
+def isGate(gerritEventCommentText, gerritEventType) {
+    def common = new com.mirantis.mk.Common()
+    def gerritEventCommentTextStr = ''
+    def res = false
+    if (gerritEventCommentText) {
+        try{
+            gerritEventCommentTextStr = new String(gerritEventCommentText.decodeBase64())
+        } catch (e) {
+            gerritEventCommentTextStr = gerritEventCommentText
+        }
+        common.infoMsg("GERRIT_EVENT_COMMENT_TEXT is ${gerritEventCommentTextStr}")
+    }
+    if (gerritEventType == 'comment-added' && gerritEventCommentTextStr =~ /^Patch Set \d+:\s.*Workflow\+1$/) {
+        common.infoMsg("Running in gate mode")
+        res = true
+    }
+    return res
+}
diff --git a/src/com/mirantis/mk/Workflow.groovy b/src/com/mirantis/mk/Workflow.groovy
index 6cdfe5f..aa38c0c 100644
--- a/src/com/mirantis/mk/Workflow.groovy
+++ b/src/com/mirantis/mk/Workflow.groovy
@@ -18,6 +18,32 @@
 
 
 /**
+ * Get Jenkins parameter names, values and types from jobName
+ * @param jobName job name
+ * @return Map with parameter names as keys and the following map as values:
+ *  [
+ *    <str name1>: [type: <str cls1>, use_variable: <str name1>, defaultValue: <cls value1>],
+ *    <str name2>: [type: <str cls2>, use_variable: <str name2>, defaultValue: <cls value2>],
+ *  ]
+ */
+def getJobDefaultParameters(jobName) {
+    def jenkinsUtils = new com.mirantis.mk.JenkinsUtils()
+    def item = jenkinsUtils.getJobByName(env.JOB_NAME)
+    def parameters = [:]
+    def prop = item.getProperty(ParametersDefinitionProperty.class)
+    if(prop != null) {
+        for(param in prop.getParameterDefinitions()) {
+            def defaultParam = param.getDefaultParameterValue()
+            def cls = defaultParam.getClass().getName()
+            def value = defaultParam.getValue()
+            def name = defaultParam.getName()
+            parameters[name] = [type: cls, use_variable: name, defaultValue: value]
+        }
+    }
+    return parameters
+}
+
+/**
  * Run a Jenkins job using the collected parameters
  *
  * @param job_name          Name of the running job
@@ -141,7 +167,15 @@
         stage("Running job ${step['job']}") {
 
             def job_name = step['job']
-            def job_parameters = step['parameters']
+            def job_parameters = [:]
+            def step_parameters = step['parameters'] ?: [:]
+            if (step['inherit_parent_params'] ?: false) {
+                // add parameters from the current job for the child job
+                job_parameters << getJobDefaultParameters(env.JOB_NAME)
+            }
+            // add parameters from the workflow for the child job
+            job_parameters << step_parameters
+
             // Collect job parameters and run the job
             def job_info = runJob(job_name, job_parameters, global_variables, propagate)
             def job_result = job_info.getResult()
@@ -158,17 +192,27 @@
             // Store links to the resulting artifacts into 'global_variables'
             storeArtifacts(build_url, step['artifacts'], global_variables, job_name, build_id)
 
-            // Job failed, fail the build or keep going depending on 'ignore_failed' flag
-            if (job_result != "SUCCESS") {
-                def job_ignore_failed = step['ignore_failed'] ?: false
-                failed_jobs[build_url] = job_result
-                if (job_ignore_failed) {
-                    println "Job ${build_url} finished with result: ${job_result}"
-                } else {
+            // Check job result, in case of SUCCESS, move to next step.
+            // In case job has status NOT_BUILT, fail the build or keep going depending on 'ignore_not_built' flag
+            // In other cases check flag ignore_failed, if true ignore any statuses and keep going.
+            if (job_result != 'SUCCESS'){
+                def ignoreStepResult = false
+                switch(job_result) {
+                    // In cases when job was waiting too long in queue or internal job logic allows to skip building,
+                    // job may have NOT_BUILT status. In that case ignore_not_built flag can be used not to fail scenario.
+                    case "NOT_BUILT":
+                        ignoreStepResult = step['ignore_not_built'] ?: false
+                        break;
+                    default:
+                        ignoreStepResult = step['ignore_failed'] ?: false
+                        failed_jobs[build_url] = job_result
+                }
+                if (!ignoreStepResult) {
                     currentBuild.result = job_result
                     error "Job ${build_url} finished with result: ${job_result}"
-                }
-            } // if (job_result == "SUCCESS")
+                } // if (!ignoreStepResult)
+            } // if (job_result != 'SUCCESS')
+            println "Job ${build_url} finished with result: ${job_result}"
         } // stage ("Running job ${step['job']}")
     } // for (step in scenario['workflow'])
 }
@@ -196,7 +240,8 @@
  *         KUBECONFIG_ARTIFACT: artifacts/management_kubeconfig
  *         DEPLOYED_KAAS_VERSION: artifacts/management_version
  *
- *     - job: test-kaas-ui
+ *     - job: create-child
+ *       inherit_parent_params: true
  *       ignore_failed: false
  *       parameters:
  *         KUBECONFIG_ARTIFACT_URL:
@@ -205,6 +250,16 @@
  *         KAAS_VERSION:
  *           type: StringParameterValue
  *           get_variable_from_url: DEPLOYED_KAAS_VERSION
+ *
+ *     - job: test-kaas-ui
+ *       ignore_not_built: false
+ *       parameters:
+ *         KUBECONFIG_ARTIFACT_URL:
+ *           type: StringParameterValue
+ *           use_variable: KUBECONFIG_ARTIFACT
+ *         KAAS_VERSION:
+ *           type: StringParameterValue
+ *           get_variable_from_url: DEPLOYED_KAAS_VERSION
  *       artifacts:
  *         REPORT_SI_KAAS_UI: artifacts/test_kaas_ui_result.xml
  *
@@ -223,6 +278,13 @@
  *
  *     runScenario(scenario)
  *
+ * Scenario workflow keys:
+ *
+ *   job: string. Jenkins job name
+ *   ignore_failed: bool. if true, keep running the workflow jobs if the job is failed, but fail the workflow at finish
+ *   ignore_not_built: bool. if true, keep running the workflow jobs if the job set own status to NOT_BUILT, do not fail the workflow at finish for such jobs
+ *   inherit_parent_params: bool. if true, provide all parameters from the parent job to the child job as defaults
+ *   parameters: dict. parameters name and type to inherit from parent to child job, or from artifact to child job
  */
 
 def runScenario(scenario, slackReportChannel = '') {