From 52212615062ee279195c32b70326081844ac48f6 Mon Sep 17 00:00:00 2001
From: Victor Martinez
+ fooo
+
+ The list of step's params and the related default values are:
+
+
+
+ + +From bd050f6c8301ae58859d450050342b498d0c6903 Mon Sep 17 00:00:00 2001 From: Victor Martinez
+ fooo + + The list of step's params and the related default values are: +
+ + +diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index d9dc31d47..b29b0ba19 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -20,7 +20,7 @@ * Given the YAML definition and the changeset global macros * then it verifies if the project or stage should be enabled. */ -Boolean call(Map params = [:]){ +Boolean call(Map args = [:]){ def project = args.project def content = args.content def patterns = args.changeset From d4bf9a351c8b1d980b07f8b404cdc93132afcbe3 Mon Sep 17 00:00:00 2001 From: Victor Martinez
++ +beats.generateStages() + +
+ fooo + + The list of step's params and the related default values are: +
+ +diff --git a/vars/beatsStages.groovy b/vars/beatsStages.groovy new file mode 100644 index 000000000..ec07e700f --- /dev/null +++ b/vars/beatsStages.groovy @@ -0,0 +1,25 @@ +#!/usr/bin/env groovy +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +Boolean call(Map args = [:]){ + def project = args.project + def content = args.content + def patterns = args.changeset + + // TODO +} diff --git a/vars/beatsStages.txt b/vars/beatsStages.txt new file mode 100644 index 000000000..8d43b0e9e --- /dev/null +++ b/vars/beatsStages.txt @@ -0,0 +1,15 @@ +
+ fooo + + The list of step's params and the related default values are: +
+ + +From 47879e9c82a6f2f782b85ccc4202cb87ba9a09a5 Mon Sep 17 00:00:00 2001 From: Victor Martinez
- fooo + Given the YAML definition then it creates all the stages The list of step's params and the related default values are:
- - + script { + def mapParallelTasks = [:] + beatsWhen(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml')) + parallel(mapParallelTasks) + }From 3e15f57abf85d96a4e7f0a388800580be6c5e779 Mon Sep 17 00:00:00 2001 From: Victor Martinez
script { def mapParallelTasks = [:] - beatsWhen(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml')) + beatsStages(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml')) parallel(mapParallelTasks) }diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index b29b0ba19..dc01daa69 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -21,8 +21,8 @@ * then it verifies if the project or stage should be enabled. */ Boolean call(Map args = [:]){ - def project = args.project - def content = args.content + def project = args.containsKey('project') ? args.project : error('beatsWhen: project param is required') + def content = args.containsKey('content') ? args.content : error('beatsWhen: content param is required') def patterns = args.changeset def ret = false diff --git a/vars/beatsWhen.txt b/vars/beatsWhen.txt index 0ffb9bcdf..7058c62ac 100644 --- a/vars/beatsWhen.txt +++ b/vars/beatsWhen.txt @@ -1,17 +1,18 @@ -beats.when() -
- fooo + Given the YAML definition and the changeset global macros + then it verifies if the project or stage should be enabled. The list of step's params and the related default values are:
- - + whenTrue(beatsWhen(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml'))) + ... + }From 778bff60718108cdda650e0337ebac0e7a7ff914 Mon Sep 17 00:00:00 2001 From: Victor Martinez
script { def mapParallelTasks = [:] - beatsStages(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml')) + beatsStages(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml'), function: this.&myFunction) parallel(mapParallelTasks) } + + def myFunction(Map args = [:]) { + ... + }From 6f55dbdfec80358b633b6a95435751fca5c36cb2 Mon Sep 17 00:00:00 2001 From: Victor Martinez
- fooo - - The list of step's params and the related default values are: -
- - -- -beats.generateStages() - -
- fooo - - The list of step's params and the related default values are: -
- - -diff --git a/vars/beatsStages.groovy b/vars/beatsStages.groovy index ce8037cbf..8d5cec2b8 100644 --- a/vars/beatsStages.groovy +++ b/vars/beatsStages.groovy @@ -1,4 +1,3 @@ -#!/usr/bin/env groovy // Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index bd87f7b77..217939621 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -1,4 +1,3 @@ -#!/usr/bin/env groovy // Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright From da8b06859a22a79522f556efb0dd90207a7d988a Mon Sep 17 00:00:00 2001 From: Victor Martinez
whenTrue(beatsWhen(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml'))) ... From 8d00b3b28a66024f02354e23c6e783f55f19f4d0 Mon Sep 17 00:00:00 2001 From: Victor MartinezDate: Thu, 30 Jul 2020 11:32:39 +0100 Subject: [PATCH 26/37] Support disabled flag to easily disable a whole project or stage if required --- src/test/groovy/BeatsWhenStepTests.groovy | 32 +++++++++++++++++++++++ vars/beatsWhen.groovy | 18 ++++++++----- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/test/groovy/BeatsWhenStepTests.groovy b/src/test/groovy/BeatsWhenStepTests.groovy index aded66722..0d38aae42 100644 --- a/src/test/groovy/BeatsWhenStepTests.groovy +++ b/src/test/groovy/BeatsWhenStepTests.groovy @@ -185,6 +185,38 @@ class BeatsWhenStepTests extends ApmBasePipelineTest { assertFalse(ret) } + @Test + void test_whenEnabled_without_data() throws Exception { + def script = loadScript(scriptName) + def ret = script.whenEnabled() + printCallStack() + assertTrue(ret) + } + + @Test + void test_whenEnabled_with_data() throws Exception { + def script = loadScript(scriptName) + def ret = script.whenEnabled(content: [:]) + printCallStack() + assertTrue(ret) + } + + @Test + void test_whenEnabled_with_disabled() throws Exception { + def script = loadScript(scriptName) + def ret = script.whenEnabled(content: [ disabled: true]) + printCallStack() + assertFalse(ret) + } + + @Test + void test_whenEnabled_with_no_disabled() throws Exception { + def script = loadScript(scriptName) + def ret = script.whenEnabled(content: [ disabled: false]) + printCallStack() + assertTrue(ret) + } + @Test void test_whenLabels_and_no_data() throws Exception { def script = loadScript(scriptName) diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index f62cb318a..c934aeca9 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -26,12 +26,14 @@ Boolean call(Map args = [:]){ def ret = false markdownReason(project: project, reason: "## Build reasons for `${project}` ${description}") - if (whenBranches(args)) { ret = true } - if (whenChangeset(args)) { ret = true } - if (whenComments(args)) { ret = true } - if (whenLabels(args)) { ret = true } - if (whenParameters(args)) { ret = true } - if (whenTags(args)) { ret = true } + if (whenEnabled(args)) { + if (whenBranches(args)) { ret = true } + if (whenChangeset(args)) { ret = true } + if (whenComments(args)) { ret = true } + if (whenLabels(args)) { ret = true } + if (whenParameters(args)) { ret = true } + if (whenTags(args)) { ret = true } + } markdownReason(project: project, reason: "* Stages for `${project} ${description}` have been ${ret ? '✅ enabled' : '❕disabled'}") return ret @@ -105,6 +107,10 @@ private Boolean whenComments(Map args = [:]) { return false } +private boolean whenEnabled(Map args = [:]) { + return !args.content?.get('disabled') +} + private Boolean whenLabels(Map args = [:]) { if (args.content?.get('labels')) { def match = args.content.get('labels').find { matchesPrLabel(label: it) } From 8fb05e422324b0ef5d89e134cd4f4aada288227b Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 30 Jul 2020 15:39:43 +0100 Subject: [PATCH 27/37] Use the stage name as the context for the GH check --- vars/beatsStages.groovy | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/vars/beatsStages.groovy b/vars/beatsStages.groovy index 61410f1df..82268936c 100644 --- a/vars/beatsStages.groovy +++ b/vars/beatsStages.groovy @@ -53,20 +53,17 @@ private generateStages(Map args = [:]) { content.platforms.each { platform -> def id = "${project}-${stageName}-${platform}" log(level: 'DEBUG', text: "stage: ${id}") - mapOfStages[id] = generateStage(project: project, label: platform, content: content, function: function) + mapOfStages[id] = generateStage(context: id, project: project, label: platform, content: content, function: function) } } else { def id = "${project}-${stageName}" log(level: 'DEBUG', text: "stage: ${id}") - mapOfStages["${id}"] = generateStage(project: project, label: defaultNode, content: content, function: function) + mapOfStages["${id}"] = generateStage(context: id, project: project, label: defaultNode, content: content, function: function) } return mapOfStages } private generateStage(Map args = [:]) { - def project = args.project - def content = args.content - def label = args.label def function = args.function return { function(args) From c9d7c0a9c060e3bb4f7bc0bf768615de12b35245 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 30 Jul 2020 17:29:15 +0100 Subject: [PATCH 28/37] Support changesetFunction for the beatsWhen --- src/test/groovy/BeatsWhenStepTests.groovy | 26 +++++++++++++++++++++++ vars/beatsWhen.groovy | 6 ++++++ vars/beatsWhen.txt | 8 ++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/BeatsWhenStepTests.groovy b/src/test/groovy/BeatsWhenStepTests.groovy index 0d38aae42..81eba169f 100644 --- a/src/test/groovy/BeatsWhenStepTests.groovy +++ b/src/test/groovy/BeatsWhenStepTests.groovy @@ -24,6 +24,10 @@ import static org.junit.Assert.assertTrue class BeatsWhenStepTests extends ApmBasePipelineTest { String scriptName = 'vars/beatsWhen.groovy' + def getProjectDependencies(Map args = [:]) { + return [ '^projectA/.*', '^projectB' ] + } + @Override @Before void setUp() throws Exception { @@ -150,6 +154,28 @@ class BeatsWhenStepTests extends ApmBasePipelineTest { assertFalse(ret) } + @Test + void test_whenChangeset_content_and_function_with_match() throws Exception { + def script = loadScript(scriptName) + def changeset = 'projectA/Jenkinsfile' + helper.registerAllowedMethod('readFile', [String.class], { return changeset }) + def ret = script.whenChangeset(content: [ changeset: ['^Jenkinsfile']], + changesetFunction: this.&getProjectDependencies) + printCallStack() + assertTrue(ret) + } + + @Test + void test_whenChangeset_content_and_function_without_match() throws Exception { + def script = loadScript(scriptName) + def changeset = 'foo/Jenkinsfile' + helper.registerAllowedMethod('readFile', [String.class], { return changeset }) + def ret = script.whenChangeset(content: [ changeset: ['^Jenkinsfile']], + changesetFunction: this.&getProjectDependencies) + printCallStack() + assertFalse(ret) + } + @Test void test_whenComments_and_no_environment_variable() throws Exception { def script = loadScript(scriptName) diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index c934aeca9..d1f4ddab1 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -69,6 +69,12 @@ private Boolean whenChangeset(Map args = [:]) { } } + // If function then calculate the project dependencies on the fly. + if (args.get('changesetFunction')) { + calculatedPatterns = args.changesetFunction(args) + patterns.addAll(calculatedPatterns) + } + // TODO: to be refactored with isGitRegionMatch.isPartialPatternMatch() // Gather the diff between the target branch and the current commit. diff --git a/vars/beatsWhen.txt b/vars/beatsWhen.txt index 00697ea61..59be37bed 100644 --- a/vars/beatsWhen.txt +++ b/vars/beatsWhen.txt @@ -8,11 +8,17 @@ content: the content with the when section. Mandatory changeset: the global changeset. Optional description: the description to be used in the markdown generation with the build reasons. Optional +changesetFunction: the function to be called. Optional - whenTrue(beatsWhen(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml'))) + whenTrue(beatsWhen(project: 'auditbeat', changesetFunction: this.&getProjectDependencies + content: readYaml(file: 'auditbeat/Jenkinsfile.yml'))) + ... + } + + def getProjectDependencies(Map args = [:]) { ... }From 8b025e562a4786eb271df25e408fbe2aa977d266 Mon Sep 17 00:00:00 2001 From: Victor MartinezDate: Thu, 30 Jul 2020 17:29:50 +0100 Subject: [PATCH 29/37] Docs --- vars/README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/vars/README.md b/vars/README.md index 46245928f..a26edbff4 100644 --- a/vars/README.md +++ b/vars/README.md @@ -39,6 +39,56 @@ Encode a text to base64 base64encode(text: "text to encode", encoding: "UTF-8") ``` +## beatsStages + + Given the YAML definition then it creates all the stages + + The list of step's params and the related default values are: +
+
+ + +- project: the name of the project. Mandatory
+- content: the content with all the stages and commands to be transformed. Mandatory
+- function: the function to be called. Mandatory
++ script { + def mapParallelTasks = [:] + beatsStages(project: 'auditbeat', content: readYaml(file: 'auditbeat/Jenkinsfile.yml'), function: this.&myFunction) + parallel(mapParallelTasks) + } + + def myFunction(Map args = [:]) { + ... + } ++ +## beatsWhen ++ Given the YAML definition and the changeset global macros + then it verifies if the project or stage should be enabled. + + The list of step's params and the related default values are: +
+
+ + +- project: the name of the project. Mandatory
+- content: the content with the when section. Mandatory
+- changeset: the global changeset. Optional
+- description: the description to be used in the markdown generation with the build reasons. Optional
+- changesetFunction: the function to be called. Optional
++ whenTrue(beatsWhen(project: 'auditbeat', changesetFunction: this.&getProjectDependencies + content: readYaml(file: 'auditbeat/Jenkinsfile.yml'))) + ... + } + + def getProjectDependencies(Map args = [:]) { + ... + } ++ ## build Override the `build` step to highlight in BO the URL to the downstream job. From e9e9e617e694cfa44f939c0cb072067c5e049723 Mon Sep 17 00:00:00 2001 From: Victor MartinezDate: Fri, 31 Jul 2020 08:16:11 +0100 Subject: [PATCH 30/37] Add markdown collapse --- vars/beatsWhen.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index d1f4ddab1..68ccf5ba0 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -27,12 +27,14 @@ Boolean call(Map args = [:]){ markdownReason(project: project, reason: "## Build reasons for `${project}` ${description}") if (whenEnabled(args)) { + markdownReason(project: project, reason: " ") } markdownReason(project: project, reason: "* Stages for `${project} ${description}` have been ${ret ? '✅ enabled' : '❕disabled'}") From 4db5fcff974a7c1a2dc52135723165e7bb042939 Mon Sep 17 00:00:00 2001 From: Victor MartinezExpand to view the reasons
") if (whenBranches(args)) { ret = true } if (whenChangeset(args)) { ret = true } if (whenComments(args)) { ret = true } if (whenLabels(args)) { ret = true } if (whenParameters(args)) { ret = true } if (whenTags(args)) { ret = true } + markdownReason(project: project, reason: "
Date: Fri, 31 Jul 2020 08:25:27 +0100 Subject: [PATCH 31/37] Support beatsWhen with special token for some specific project dependencies --- src/test/groovy/BeatsWhenStepTests.groovy | 11 +++++++++++ vars/beatsWhen.groovy | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/src/test/groovy/BeatsWhenStepTests.groovy b/src/test/groovy/BeatsWhenStepTests.groovy index 81eba169f..21f60af45 100644 --- a/src/test/groovy/BeatsWhenStepTests.groovy +++ b/src/test/groovy/BeatsWhenStepTests.groovy @@ -165,6 +165,17 @@ class BeatsWhenStepTests extends ApmBasePipelineTest { assertTrue(ret) } + @Test + void test_whenChangeset_content_with_project_dependency_and_function_with_match() throws Exception { + def script = loadScript(scriptName) + def changeset = 'projectA/Jenkinsfile' + helper.registerAllowedMethod('readFile', [String.class], { return changeset }) + def ret = script.whenChangeset(content: [ changeset: ['#generator/common/beatgen']], + changesetFunction: this.&getProjectDependencies) + printCallStack() + assertTrue(ret) + } + @Test void test_whenChangeset_content_and_function_without_match() throws Exception { def script = loadScript(scriptName) diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index 68ccf5ba0..d56de380b 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -75,6 +75,15 @@ private Boolean whenChangeset(Map args = [:]) { if (args.get('changesetFunction')) { calculatedPatterns = args.changesetFunction(args) patterns.addAll(calculatedPatterns) + + // Search for some other project dependencies that are explicitly + // sett with the pattern # + args.content.changeset.findAll { it.startsWith('#') }.each { + Map newArgs = args + newArgs.project = it.replaceAll('#', '') + calculatedPatterns = args.changesetFunction(args) + patterns.addAll(calculatedPatterns) + } } // TODO: to be refactored with isGitRegionMatch.isPartialPatternMatch() From 25f3a0b48afb5d7962177c4ada1eade5fff6c227 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Fri, 31 Jul 2020 11:59:59 +0100 Subject: [PATCH 32/37] Cosmetic change in the markdown --- vars/beatsWhen.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index d56de380b..d8d0ec15c 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -25,9 +25,9 @@ Boolean call(Map args = [:]){ def description = args.get('description', '') def ret = false - markdownReason(project: project, reason: "## Build reasons for `${project}` ${description}") + markdownReason(project: project, reason: "## Build reasons for `${project} ${description}`") if (whenEnabled(args)) { - markdownReason(project: project, reason: " Expand to view the reasons
") + markdownReason(project: project, reason: "
diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index d8d0ec15c..1e62918ba 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -73,7 +73,8 @@ private Boolean whenChangeset(Map args = [:]) { // If function then calculate the project dependencies on the fly. if (args.get('changesetFunction')) { - calculatedPatterns = args.changesetFunction(args) + def changesetFunction = args.changesetFunction + calculatedPatterns = changesetFunction.run(args) patterns.addAll(calculatedPatterns) // Search for some other project dependencies that are explicitly @@ -81,7 +82,7 @@ private Boolean whenChangeset(Map args = [:]) { args.content.changeset.findAll { it.startsWith('#') }.each { Map newArgs = args newArgs.project = it.replaceAll('#', '') - calculatedPatterns = args.changesetFunction(args) + calculatedPatterns = changesetFunction.run(args) patterns.addAll(calculatedPatterns) } } diff --git a/vars/beatsWhen.txt b/vars/beatsWhen.txt index 59be37bed..781fc3e5a 100644 --- a/vars/beatsWhen.txt +++ b/vars/beatsWhen.txt @@ -8,7 +8,7 @@") } - markdownReason(project: project, reason: "* Stages for `${project} ${description}` have been ${ret ? '✅ enabled' : '❕disabled'}") + markdownReason(project: project, reason: "#### Stages for `${project} ${description}` have been ${ret ? '✅ enabled' : '❕disabled'}\n") return ret } From c3b029bdbd344f537c0ede767d77700005b468aa Mon Sep 17 00:00:00 2001 From: Victor MartinezExpand to view the reasons
\n") if (whenBranches(args)) { ret = true } if (whenChangeset(args)) { ret = true } if (whenComments(args)) { ret = true } @@ -36,7 +36,7 @@ Boolean call(Map args = [:]){ if (whenTags(args)) { ret = true } markdownReason(project: project, reason: "
Date: Thu, 6 Aug 2020 08:01:24 +0100 Subject: [PATCH 33/37] Pass the unique ID to be consumed for the stashed map that's required to identify the stage, since STAGE_NAME env variable is not available any more when creating stages dynamically --- vars/beatsStages.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vars/beatsStages.groovy b/vars/beatsStages.groovy index 82268936c..021221b77 100644 --- a/vars/beatsStages.groovy +++ b/vars/beatsStages.groovy @@ -53,12 +53,12 @@ private generateStages(Map args = [:]) { content.platforms.each { platform -> def id = "${project}-${stageName}-${platform}" log(level: 'DEBUG', text: "stage: ${id}") - mapOfStages[id] = generateStage(context: id, project: project, label: platform, content: content, function: function) + mapOfStages[id] = generateStage(context: id, project: project, label: platform, content: content, function: function, id: id) } } else { def id = "${project}-${stageName}" log(level: 'DEBUG', text: "stage: ${id}") - mapOfStages["${id}"] = generateStage(context: id, project: project, label: defaultNode, content: content, function: function) + mapOfStages["${id}"] = generateStage(context: id, project: project, label: defaultNode, content: content, function: function, id: id) } return mapOfStages } From cb7b8942542d628431a3030441a6656ac194a069 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 3 Sep 2020 14:19:57 +0100 Subject: [PATCH 34/37] Fix wound up catching method mismatch with this.& by using a Class expected to call org.codehaus.groovy.runtime.MethodClosure.call but wound up catching WorkflowScript.runCommand; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ was caused when using the this.& function pointer This should help to avoid any kind of issues in the future in case the mismatch is forced to fail --- src/co/elastic/beats/BeatsFunction.groovy | 35 +++++++++++++++++++ src/test/groovy/BeatsStagesStepTests.groovy | 15 ++++---- src/test/groovy/BeatsWhenStepTests.groovy | 11 +++--- .../mock/beats/GetProjectDependencies.groovy | 30 ++++++++++++++++ .../co/elastic/mock/beats/RunCommand.groovy | 30 ++++++++++++++++ src/test/resources/jobs/beats/beatsStages.dsl | 30 +++++++++------- vars/beatsStages.groovy | 2 +- vars/beatsStages.txt | 2 +- vars/beatsWhen.groovy | 5 +-- vars/beatsWhen.txt | 2 +- 10 files changed, 128 insertions(+), 34 deletions(-) create mode 100644 src/co/elastic/beats/BeatsFunction.groovy create mode 100644 src/test/groovy/co/elastic/mock/beats/GetProjectDependencies.groovy create mode 100644 src/test/groovy/co/elastic/mock/beats/RunCommand.groovy diff --git a/src/co/elastic/beats/BeatsFunction.groovy b/src/co/elastic/beats/BeatsFunction.groovy new file mode 100644 index 000000000..b5de20867 --- /dev/null +++ b/src/co/elastic/beats/BeatsFunction.groovy @@ -0,0 +1,35 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package co.elastic.beats + +/** + Base class to implement specific functions for the beats 2.0 pipeline. +*/ +class BeatsFunction { + /** object to access to pipeline steps */ + public steps + + public BeatsFunction(Map args){ + this.steps = args.steps + } + + /** + This method should be overwritten by the target pipeline. + */ + protected run(Map args){ } +} diff --git a/src/test/groovy/BeatsStagesStepTests.groovy b/src/test/groovy/BeatsStagesStepTests.groovy index cda1c61a3..5818702ac 100644 --- a/src/test/groovy/BeatsStagesStepTests.groovy +++ b/src/test/groovy/BeatsStagesStepTests.groovy @@ -20,14 +20,11 @@ import org.junit.After import org.junit.Test import static org.junit.Assert.assertFalse import static org.junit.Assert.assertTrue +import co.elastic.mock.beats.RunCommand class BeatsStagesStepTests extends ApmBasePipelineTest { String scriptName = 'vars/beatsStages.groovy' - def runCommand(Map args = [:]) { - echo "${args.label}" - } - @Override @Before void setUp() throws Exception { @@ -64,7 +61,7 @@ class BeatsStagesStepTests extends ApmBasePipelineTest { void test_with_no_platform() throws Exception { def script = loadScript(scriptName) try { - script.call(project: 'foo', content: [:], function: this.&runCommand) + script.call(project: 'foo', content: [:], function: new RunCommand(steps: this)) } catch (e) { // NOOP } @@ -96,7 +93,7 @@ class BeatsStagesStepTests extends ApmBasePipelineTest { "mage" : [ "foo" ] ] ] - ], function: this.&runCommand) + ], function: new RunCommand(steps: this)) printCallStack() assertTrue(ret.size() == 1) assertTrue(assertMethodCallContainsPattern('log', 'stage: foo-simple')) @@ -117,7 +114,7 @@ class BeatsStagesStepTests extends ApmBasePipelineTest { "platforms" : [ 'windows-2019', 'windows-2016' ] ] ] - ], function: this.&runCommand) + ], function: new RunCommand(steps: this)) printCallStack() assertTrue(ret.size() == 3) assertTrue(assertMethodCallContainsPattern('log', 'stage: foo-simple')) @@ -148,7 +145,7 @@ class BeatsStagesStepTests extends ApmBasePipelineTest { ] ] ] - ], function: this.&runCommand) + ], function: new RunCommand(steps: this)) printCallStack() assertTrue(ret.size() == 2) assertFalse(assertMethodCallContainsPattern('log', 'stage: foo-multi-when')) @@ -177,7 +174,7 @@ class BeatsStagesStepTests extends ApmBasePipelineTest { ] ] ] - ], function: this.&runCommand) + ], function: new RunCommand(steps: this)) printCallStack() assertTrue(ret.size() == 3) assertTrue(assertMethodCallContainsPattern('log', 'stage: foo-multi-when')) diff --git a/src/test/groovy/BeatsWhenStepTests.groovy b/src/test/groovy/BeatsWhenStepTests.groovy index 21f60af45..f09ed6e5e 100644 --- a/src/test/groovy/BeatsWhenStepTests.groovy +++ b/src/test/groovy/BeatsWhenStepTests.groovy @@ -20,14 +20,11 @@ import org.junit.After import org.junit.Test import static org.junit.Assert.assertFalse import static org.junit.Assert.assertTrue +import co.elastic.mock.beats.GetProjectDependencies class BeatsWhenStepTests extends ApmBasePipelineTest { String scriptName = 'vars/beatsWhen.groovy' - def getProjectDependencies(Map args = [:]) { - return [ '^projectA/.*', '^projectB' ] - } - @Override @Before void setUp() throws Exception { @@ -160,7 +157,7 @@ class BeatsWhenStepTests extends ApmBasePipelineTest { def changeset = 'projectA/Jenkinsfile' helper.registerAllowedMethod('readFile', [String.class], { return changeset }) def ret = script.whenChangeset(content: [ changeset: ['^Jenkinsfile']], - changesetFunction: this.&getProjectDependencies) + changesetFunction: new GetProjectDependencies()) printCallStack() assertTrue(ret) } @@ -171,7 +168,7 @@ class BeatsWhenStepTests extends ApmBasePipelineTest { def changeset = 'projectA/Jenkinsfile' helper.registerAllowedMethod('readFile', [String.class], { return changeset }) def ret = script.whenChangeset(content: [ changeset: ['#generator/common/beatgen']], - changesetFunction: this.&getProjectDependencies) + changesetFunction: new GetProjectDependencies()) printCallStack() assertTrue(ret) } @@ -182,7 +179,7 @@ class BeatsWhenStepTests extends ApmBasePipelineTest { def changeset = 'foo/Jenkinsfile' helper.registerAllowedMethod('readFile', [String.class], { return changeset }) def ret = script.whenChangeset(content: [ changeset: ['^Jenkinsfile']], - changesetFunction: this.&getProjectDependencies) + changesetFunction: new GetProjectDependencies()) printCallStack() assertFalse(ret) } diff --git a/src/test/groovy/co/elastic/mock/beats/GetProjectDependencies.groovy b/src/test/groovy/co/elastic/mock/beats/GetProjectDependencies.groovy new file mode 100644 index 000000000..cd87507e7 --- /dev/null +++ b/src/test/groovy/co/elastic/mock/beats/GetProjectDependencies.groovy @@ -0,0 +1,30 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package co.elastic.mock.beats + +/** + * Mock class for the Beats 2.0 beatsWhen step + */ +class GetProjectDependencies extends co.elastic.beats.BeatsFunction { + public GetProjectDependencies(Map args = [:]){ + super(args) + } + public run(Map args = [:]){ + return [ '^projectA/.*', '^projectB' ] + } +} diff --git a/src/test/groovy/co/elastic/mock/beats/RunCommand.groovy b/src/test/groovy/co/elastic/mock/beats/RunCommand.groovy new file mode 100644 index 000000000..a758a0e09 --- /dev/null +++ b/src/test/groovy/co/elastic/mock/beats/RunCommand.groovy @@ -0,0 +1,30 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package co.elastic.mock.beats + +/** + * Mock class for the Beats 2.0 beatsStages step + */ +class RunCommand extends co.elastic.beats.BeatsFunction { + public RunCommand(Map args = [:]){ + super(args) + } + public run(Map args = [:]) { + steps.echo "-------------${args.label} ---- ${args.context}" + } +} diff --git a/src/test/resources/jobs/beats/beatsStages.dsl b/src/test/resources/jobs/beats/beatsStages.dsl index 9ea54d51f..952382d49 100644 --- a/src/test/resources/jobs/beats/beatsStages.dsl +++ b/src/test/resources/jobs/beats/beatsStages.dsl @@ -62,7 +62,7 @@ stages: stage('simple') { steps { script { - def ret = beatsStages(project: 'test', content: readYaml(file: 'simple.yaml'), function: this.&runCommand) + def ret = beatsStages(project: 'test', content: readYaml(file: 'simple.yaml'), function: new RunCommand(steps: this)) whenFalse(ret.size() == 1) { error 'Assert failed. There should be just one entry.' } @@ -78,7 +78,7 @@ stages: stage('two') { steps { script { - def ret = beatsStages(project: 'test', content: readYaml(file: 'two.yaml'), function: this.&runCommand) + def ret = beatsStages(project: 'test', content: readYaml(file: 'two.yaml'), function: new RunCommand(steps: this)) whenFalse(ret.size() == 2) { error 'Assert failed. There should be just one entry.' } @@ -94,7 +94,7 @@ stages: stage('platforms') { steps { script { - def ret = beatsStages(project: 'test', content: readYaml(file: 'platforms.yaml'), function: this.&runCommand) + def ret = beatsStages(project: 'test', content: readYaml(file: 'platforms.yaml'), function: new RunCommand(steps: this)) whenFalse(ret.size() == 2) { error 'Assert failed. There should be just one entry.' } @@ -113,7 +113,7 @@ stages: } steps { script { - def ret = beatsStages(project: 'test', content: readYaml(file: 'when.yaml'), function: this.&runCommand) + def ret = beatsStages(project: 'test', content: readYaml(file: 'when.yaml'), function: new RunCommand(steps: this)) whenFalse(ret.size() == 2) { error 'Assert failed. There should be just 2 entries.' } @@ -127,7 +127,7 @@ stages: } steps { script { - def ret = beatsStages(project: 'test', content: readYaml(file: 'when.yaml'), function: this.&runCommand) + def ret = beatsStages(project: 'test', content: readYaml(file: 'when.yaml'), function: new RunCommand(steps: this)) whenFalse(ret.size() == 0) { error 'Assert failed. There should be just 0 entries.' } @@ -138,15 +138,19 @@ stages: } } -// TODO expected to call org.codehaus.groovy.runtime.MethodClosure.call but wound up catching WorkflowScript.runCommand; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ -def runCommand(Map args = [:]) { - if (args?.content?.mage) { - dir(args.project) { - echo "mage ${args.label}" - } +class RunCommand extends co.elastic.beats.BeatsFunction { + public RunCommand(Map args = [:]){ + super(args) } - if (args?.content?.make) { - echo "make ${args.label}" + public run(Map args = [:]){ + if (args?.content?.mage) { + steps.dir(args.project) { + steps.echo "mage ${args.label}" + } + } + if (args?.content?.make) { + steps.echo "make ${args.label}" + } } } ''' diff --git a/vars/beatsStages.groovy b/vars/beatsStages.groovy index 021221b77..e901fd54c 100644 --- a/vars/beatsStages.groovy +++ b/vars/beatsStages.groovy @@ -66,6 +66,6 @@ private generateStages(Map args = [:]) { private generateStage(Map args = [:]) { def function = args.function return { - function(args) + function.run(args) } } diff --git a/vars/beatsStages.txt b/vars/beatsStages.txt index fb81a1857..2cd13032d 100644 --- a/vars/beatsStages.txt +++ b/vars/beatsStages.txt @@ -5,7 +5,7 @@
- project: the name of the project. Mandatory
- content: the content with all the stages and commands to be transformed. Mandatory
-- function: the function to be called. Mandatory
+- function: the function to be called. Should implement the class BeatsFunction. Mandatory
content: the content with the when section. Mandatory changeset: the global changeset. Optional description: the description to be used in the markdown generation with the build reasons. Optional -changesetFunction: the function to be called. Optional +changesetFunction: the function to be called. Should implement the class BeatsFunction. Optional From fa26c0f8daf25efb2b521e695d6ca139c7d780c6 Mon Sep 17 00:00:00 2001 From: Victor MartinezDate: Thu, 3 Sep 2020 14:37:28 +0100 Subject: [PATCH 35/37] Fix super-linter --- .ci/Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index bfbad6186..057c22cce 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -151,6 +151,9 @@ pipeline { } } stage('Super-linter') { + options { + warnError('Super-linter failed, unstable and move forward') + } steps { withGithubNotify(context: 'Check super-linter', tab: 'tests') { deleteDir() From 28f514e22a22e1265873a357f034645e28903769 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 3 Sep 2020 16:38:21 +0100 Subject: [PATCH 36/37] Update vars/beatsWhen.groovy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Manuel de la Peña --- vars/beatsWhen.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vars/beatsWhen.groovy b/vars/beatsWhen.groovy index 1e62918ba..c32357500 100644 --- a/vars/beatsWhen.groovy +++ b/vars/beatsWhen.groovy @@ -46,7 +46,7 @@ private Boolean whenBranches(Map args = [:]) { markdownReason(project: args.project, reason: '* ✅ Branch is enabled .') return true } - markdownReason(project: args.project, reason: '* ❕Branch is `disabled`.') + markdownReason(project: args.project, reason: '* ❗Branch is `disabled`.') return false } From 72bbcac93a9cb9ec2cc50e5763e7d53f24fc0741 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 3 Sep 2020 16:51:05 +0100 Subject: [PATCH 37/37] Revert "Fix super-linter" This reverts commit fa26c0f8daf25efb2b521e695d6ca139c7d780c6. --- .ci/Jenkinsfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index 057c22cce..bfbad6186 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -151,9 +151,6 @@ pipeline { } } stage('Super-linter') { - options { - warnError('Super-linter failed, unstable and move forward') - } steps { withGithubNotify(context: 'Check super-linter', tab: 'tests') { deleteDir()