Fix cicd jobs

- use XML escape for '<' and '>' for all deployment reports
- revert the environment after pytest if
  SHUTDOWN_ENV_ON_TEARDOWN=false
- change error messages color to 'purple' to differ from Groovy
  traceback messages
- add helper message for reverting devops snapshots

Related task: PROD-21660

Change-Id: Ic2c5b0b69b647a0c6607cf45f6a60de1ec28ee6a
diff --git a/jobs/pipelines/deploy-cicd-and-run-tests.groovy b/jobs/pipelines/deploy-cicd-and-run-tests.groovy
index 3e96c84..55dda48 100644
--- a/jobs/pipelines/deploy-cicd-and-run-tests.groovy
+++ b/jobs/pipelines/deploy-cicd-and-run-tests.groovy
@@ -32,21 +32,19 @@
         currentBuild.result = 'SUCCESS'
 
     } catch (e) {
-        common.printMsg("Deploy is failed: " + e.message , "red")
+        common.printMsg("Deploy is failed: " + e.message , "purple")
+        report_text = e.message
+        def snapshot_name = "deploy_failed"
         shared.run_cmd("""\
             dos.py suspend ${ENV_NAME} || true
-            dos.py snapshot ${ENV_NAME} deploy_failed || true
+            dos.py snapshot ${ENV_NAME} ${snapshot_name} || true
         """)
         if ("${env.SHUTDOWN_ENV_ON_TEARDOWN}" == "false") {
             shared.run_cmd("""\
                 dos.py resume ${ENV_NAME} || true
             """)
-        } else {
-            shared.run_cmd("""\
-                dos.py destroy ${ENV_NAME} || true
-            """)
         }
-        report_text = e.message
+        shared.devops_snapshot_info(snapshot_name)
         throw e
     } finally {
         shared.create_deploy_result_report(steps, currentBuild.result, report_text)
@@ -60,22 +58,19 @@
         }
 
     } catch (e) {
-        common.printMsg("Tests are failed: " + e.message, "red")
+        common.printMsg("Tests are failed: " + e.message, "purple")
+        def snapshot_name = "tests_failed"
         shared.run_cmd("""\
             dos.py suspend ${ENV_NAME} || true
-            dos.py snapshot ${ENV_NAME} tests_failed || true
+            dos.py snapshot ${ENV_NAME} ${snapshot_name} || true
         """)
-        throw e
-    } finally {
         if ("${env.SHUTDOWN_ENV_ON_TEARDOWN}" == "false") {
             shared.run_cmd("""\
                 dos.py resume ${ENV_NAME} || true
             """)
-        } else {
-            shared.run_cmd("""\
-                dos.py destroy ${ENV_NAME} || true
-            """)
         }
+        shared.devops_snapshot_info(snapshot_name)
+        throw e
     }
 }
 
@@ -83,12 +78,21 @@
 throttle(['fuel_devops_environment']) {
   node ("${NODE_NAME}") {
     try {
+        // run deploy stages
         deploy(shared, common, steps)
+        // run test stages
         test(shared, common, steps)
     } catch (e) {
-        common.printMsg("Job is failed: " + e.message, "red")
+        common.printMsg("Job is failed: " + e.message, "purple")
         throw e
     } finally {
+        // shutdown the environment if required
+        if ("${env.SHUTDOWN_ENV_ON_TEARDOWN}" == "true") {
+            shared.run_cmd("""\
+                dos.py destroy ${ENV_NAME} || true
+            """)
+        }
+        // report results to testrail
         shared.swarm_testrail_report(steps)
     }
   }