diff --git a/resources/scripts/jenkins/apm-ci/test-mac.sh b/resources/scripts/jenkins/apm-ci/test-mac.sh index 7dc5fad..4ca6a01 100755 --- a/resources/scripts/jenkins/apm-ci/test-mac.sh +++ b/resources/scripts/jenkins/apm-ci/test-mac.sh @@ -23,15 +23,19 @@ virtualenv venv source venv/bin/activate pip install testinfra -## Prepare the docker for mac -docker-machine start default || true -eval "$(docker-machine env default)" -set -x +## Prepare the docker for mac if docker-machine is installed +if command -v docker-machine ; then + docker-machine start default || true + eval "$(docker-machine env default)" + docker_py_test=test-infra/apm-ci/test_installed_tools_docker.py +else + docker_py_test="" +fi ## Run test-infra and trap error to notify when required +set -x { py.test -v \ - test-infra/apm-ci/test_installed_tools.py \ - test-infra/apm-ci/test_installed_tools_docker.py \ + test-infra/apm-ci/test_installed_tools.py "${docker_py_test}" \ --junit-xml=target/junit-test-infra.xml; \ err="$?"; } || true diff --git a/src/test/groovy/SuperLinterStepTests.groovy b/src/test/groovy/SuperLinterStepTests.groovy index 4580243..d0936dd 100644 --- a/src/test/groovy/SuperLinterStepTests.groovy +++ b/src/test/groovy/SuperLinterStepTests.groovy @@ -26,6 +26,9 @@ class SuperLinterStepTests extends ApmBasePipelineTest { @Before void setUp() throws Exception { super.setUp() + helper.registerAllowedMethod('sh', [Map.class], { m -> + return 0 + }) } @Test @@ -75,7 +78,7 @@ class SuperLinterStepTests extends ApmBasePipelineTest { } @Test - void test_with_installation_error() throws Exception { + void test_with_installation_error_with_not_failNever() throws Exception { def script = loadScript(scriptName) env.GIT_BASE_COMMIT = 'bar' helper.registerAllowedMethod('sh', [Map.class], { m -> @@ -84,7 +87,7 @@ class SuperLinterStepTests extends ApmBasePipelineTest { } }) try { - script.call() + script.call(failNever: false) } catch(e) { // NOOP } @@ -93,4 +96,42 @@ class SuperLinterStepTests extends ApmBasePipelineTest { assertTrue(assertMethodCallContainsPattern('sh', "label=Install super-linter")) assertJobStatusFailure() } + + @Test + void test_with_superlinter_error_and_not_failNever() throws Exception { + def script = loadScript(scriptName) + env.GIT_BASE_COMMIT = 'bar' + helper.registerAllowedMethod('sh', [Map.class], { m -> + if(m?.label?.contains('Run super-linter')){ + return 1 + } + }) + try { + script.call(failNever: false) + } catch(e) { + // NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'Super linter failed')) + assertJobStatusFailure() + } + + @Test + void test_with_superlinter_error_and_failNever() throws Exception { + def script = loadScript(scriptName) + env.GIT_BASE_COMMIT = 'bar' + helper.registerAllowedMethod('sh', [Map.class], { m -> + if(m?.label?.contains('Run super-linter')){ + return 1 + } + }) + try { + script.call(failNever: true) + } catch(e) { + // NOOP + } + printCallStack() + assertTrue(assertMethodCallOccurrences('error', 0)) + assertJobStatusSuccess() + } } diff --git a/src/test/groovy/isMemberOfStepTests.groovy b/src/test/groovy/isMemberOfStepTests.groovy new file mode 100644 index 0000000..0dce0f6 --- /dev/null +++ b/src/test/groovy/isMemberOfStepTests.groovy @@ -0,0 +1,102 @@ +// 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. + +import hudson.model.Cause +import org.junit.Before +import org.junit.Test +import static org.junit.Assert.assertTrue +import static org.junit.Assert.assertFalse + +class IsMemberOfStepTests extends ApmBasePipelineTest { + + def script + + @Override + @Before + void setUp() throws Exception { + super.setUp() + script = loadScript('vars/isMemberOf.groovy') + } + + @Test + void test_without_user_parameter() throws Exception { + try { + script.call() + } catch(e) { + //NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'user param is required')) + assertJobStatusFailure() + } + + @Test + void test_without_team_parameter() throws Exception { + try { + script.call(user: 'foo') + } catch(e) { + //NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'team param is required')) + assertJobStatusFailure() + } + + @Test + void test_active_membership() throws Exception { + helper.registerAllowedMethod('githubApiCall', [Map.class], { return net.sf.json.JSONSerializer.toJSON('{ "message": {"state":"active","role":"maintainer","url":"https://api.github.com/organizations/6764390/team/2448411/memberships/foo"} }') }) + def ret = script.call(user: 'foo', team: 'apm-ui') + printCallStack() + assertTrue(ret) + assertJobStatusSuccess() + } + + @Test + void test_pending_membership() throws Exception { + helper.registerAllowedMethod('githubApiCall', [Map.class], { return net.sf.json.JSONSerializer.toJSON('{ "message": {"state":"pending","role":"member","url":"https://api.github.com/organizations/6764390/team/2448411/memberships/foo"} }') }) + def ret = script.call(user: 'foo', team: 'apm-ui') + printCallStack() + assertFalse(ret) + assertJobStatusSuccess() + } + + @Test + void test_no_membership() throws Exception { + helper.registerAllowedMethod('githubApiCall', [Map.class], { + return net.sf.json.JSONSerializer.toJSON( """{ + "Code": "404", + "message": "Not Found", + "documentation_url": "https://developer.github.com/v3" + }""") + }) + def ret = script.call(user: 'foo', team: 'bar') + printCallStack() + assertFalse(ret) + assertJobStatusSuccess() + } + + @Test + void test_no_membership_with_error() throws Exception { + helper.registerAllowedMethod('githubApiCall', [Map.class], { + throw new Exception('Forced a failure') + }) + def ret = script.call(user: 'foo', team: 'bar') + printCallStack() + assertFalse(ret) + assertJobStatusSuccess() + } +} diff --git a/vars/README.md b/vars/README.md index 4624592..c45ed10 100644 --- a/vars/README.md +++ b/vars/README.md @@ -1071,6 +1071,25 @@ Whether the given tools is installed and available. * tool: The name of the tool to check whether it is installed and available. Mandatory. * flag: The flag to be added to the validation. For instance `--version`. Optional. +## isMemberOf +Check if the given GitHub user is member of the given GitHub team. + +``` +whenTrue(isMemberOf(user: 'my-user', team: 'my-team')) { + //... +} + +// using another organisation +whenTrue(isMemberOf(user: 'my-user', team: 'my-team', org: 'acme')) { + //... +} + +``` + +* user: the GitHub user. Mandatory +* team: the GitHub teamd. Mandatory +* org: the GitHub organisation. Optional. Default: 'elastic' + ## isPR Whether the build is based on a Pull Request or no diff --git a/vars/isMemberOf.groovy b/vars/isMemberOf.groovy new file mode 100644 index 0000000..24801cc --- /dev/null +++ b/vars/isMemberOf.groovy @@ -0,0 +1,41 @@ +// 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. + +import com.cloudbees.groovy.cps.NonCPS +/** + Check if the given GitHub user is member of the given GitHub team. + + whenTrue(isMemberOf(user: 'my-user', team: 'my-team')) + + NOTE: https://developer.github.com/v3/teams/members/#get-team-membership-for-a-user +*/ + +def call(Map args = [:]) { + def user = args.containsKey('user') ? args.user : error('isMemberOf: user param is required') + def team = args.containsKey('team') ? args.team : error('isMemberOf: team param is required') + def org = args.containsKey('org') ? args.org : 'elastic' + + try { + def token = getGithubToken() + def url = "https://api.github.com/orgs/${org}/teams/${team}/memberships/${user}" + def membershipResponse = githubApiCall(token: token, allowEmptyResponse: true, url: url) + return membershipResponse.message?.state?.equals('active') + } catch(err) { + return false + } + return false +} diff --git a/vars/isMemberOf.txt b/vars/isMemberOf.txt new file mode 100644 index 0000000..d250ea4 --- /dev/null +++ b/vars/isMemberOf.txt @@ -0,0 +1,17 @@ +Check if the given GitHub user is member of the given GitHub team. + +``` +whenTrue(isMemberOf(user: 'my-user', team: 'my-team')) { + //... +} + +// using another organisation +whenTrue(isMemberOf(user: 'my-user', team: 'my-team', org: 'acme')) { + //... +} + +``` + +* user: the GitHub user. Mandatory +* team: the GitHub teamd. Mandatory +* org: the GitHub organisation. Optional. Default: 'elastic' diff --git a/vars/superLinter.groovy b/vars/superLinter.groovy index 46ad7e6..81851b8 100644 --- a/vars/superLinter.groovy +++ b/vars/superLinter.groovy @@ -36,16 +36,19 @@ def call(Map args = [:]) { varsEnv.each { envFlags += " -e ${it}" } - sh(label: 'Run super-linter', script: """ - docker run ${envFlags} \ - -e OUTPUT_FORMAT=tap -e OUTPUT_DETAILS=detailed -e OUTPUT_FOLDER=${output} \ - -v \$(pwd):/tmp/lint \ - -u \$(id -u):\$(id -g) \ - ${dockerImage}""") - + def status = sh(label: 'Run super-linter', + script: """ + docker run ${envFlags} \ + -e OUTPUT_FORMAT=tap -e OUTPUT_DETAILS=detailed -e OUTPUT_FOLDER=${output} \ + -v \$(pwd):/tmp/lint \ + -u \$(id -u):\$(id -g) \ + ${dockerImage}""", returnStatus: true) if(junitFlag) { dir("${output}") { tap2Junit(pattern: '*.tap', package: 'super-linter') } } + if (!failNever && status != 0) { + error 'Super linter failed' + } }