diff --git a/resources/scripts/install-with-choco.ps1 b/resources/scripts/install-with-choco.ps1 new file mode 100644 index 000000000..4ad91bc5b --- /dev/null +++ b/resources/scripts/install-with-choco.ps1 @@ -0,0 +1,9 @@ +# Abort with non zero exit code on errors +$ErrorActionPreference = "Stop" + +Write-Host("Getting latest {0} version for {1} ..." -f $env:TOOL,$env:VERSION) +& choco list $env:TOOL --exact --by-id-only --all | Select-String -Pattern "$env:TOOL $env:VERSION" +$Version = $(choco list $env:TOOL --exact --by-id-only --all) | Select-String -Pattern "$env:TOOL $env:VERSION" | %{$_.ToString().split(" ")[1]} | sort | Select-Object -Last 1 + +Write-Host("Installing {0} version: {1} ..." -f $env:TOOL,$Version) +& choco install $env:TOOL --no-progress -y --version "$Version" diff --git a/src/test/groovy/ApmBasePipelineTest.groovy b/src/test/groovy/ApmBasePipelineTest.groovy index 4fd9de10b..fff865a92 100644 --- a/src/test/groovy/ApmBasePipelineTest.groovy +++ b/src/test/groovy/ApmBasePipelineTest.groovy @@ -277,6 +277,8 @@ class ApmBasePipelineTest extends DeclarativePipelineTest { f.write(m.body) println f.toString() }) + helper.registerAllowedMethod('powershell', [Map.class], null) + helper.registerAllowedMethod('powershell', [String.class], null) helper.registerAllowedMethod('readFile', [Map.class], { '' }) helper.registerAllowedMethod('readJSON', [Map.class], { m -> return readJSON(m) diff --git a/src/test/groovy/InstallToolsStepTests.groovy b/src/test/groovy/InstallToolsStepTests.groovy new file mode 100644 index 000000000..c925e7368 --- /dev/null +++ b/src/test/groovy/InstallToolsStepTests.groovy @@ -0,0 +1,118 @@ +// 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 org.junit.Before +import org.junit.Test +import static org.junit.Assert.assertFalse +import static org.junit.Assert.assertTrue + +class InstallToolsStepTests extends ApmBasePipelineTest { + String scriptName = 'vars/installTools.groovy' + + @Override + @Before + void setUp() throws Exception { + super.setUp() + } + + @Test + void test_without_arguments() throws Exception { + def script = loadScript(scriptName) + try { + script.call() + } catch(e) { + // NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'installTools: missing params')) + assertJobStatusFailure() + } + + @Test + void test_with_some_missing_arguments() throws Exception { + def script = loadScript(scriptName) + try { + script.installTool([ tool: 'python3' ]) + } catch(e) { + // NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'installTools: missing version param')) + assertJobStatusFailure() + } + + @Test + void test_with_unsupported_provider_in_windows() throws Exception { + def script = loadScript(scriptName) + helper.registerAllowedMethod('isUnix', [], { false }) + try { + script.installTool([ tool: 'python3', provider: 'foo', version: '1' ]) + } catch(e) { + // NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'installTools: unsupported provider')) + assertJobStatusFailure() + } + + @Test + void test_install_tool_in_linux() throws Exception { + def script = loadScript(scriptName) + try { + script.installTool([ tool: 'foo', version: 'x.y.z' ]) + } catch(e) { + // NOOP + } + printCallStack() + assertTrue(assertMethodCallContainsPattern('error', 'TBD: install in linux')) + assertJobStatusFailure() + } + + @Test + void test_install_tool_in_windows() throws Exception { + def script = loadScript(scriptName) + helper.registerAllowedMethod('isUnix', [], { false }) + script.installTool([ tool: 'foo', version: 'x.y.z' ]) + printCallStack() + assertTrue(assertMethodCallContainsPattern('withEnv', 'VERSION=x.y.z, TOOL=foo')) + assertTrue(assertMethodCallContainsPattern('powershell', 'Install foo:x.y.z, script=.\\install-with-choco.ps1')) + assertJobStatusSuccess() + } + + @Test + void test_install_multiple_tools_in_windows() throws Exception { + def script = loadScript(scriptName) + helper.registerAllowedMethod('isUnix', [], { false }) + script.call([[ tool: 'foo', version: 'x.y.z' ], [ tool: 'bar', version: 'z.y.x' ]]) + printCallStack() + assertTrue(assertMethodCallContainsPattern('withEnv', 'VERSION=x.y.z, TOOL=foo')) + assertTrue(assertMethodCallContainsPattern('withEnv', 'VERSION=z.y.x, TOOL=bar')) + assertJobStatusSuccess() + } + + @Test + void test_install_tool_in_windows_with_all_flags() throws Exception { + def script = loadScript(scriptName) + helper.registerAllowedMethod('isUnix', [], { false }) + script.installTool([ tool: 'foo', version: 'x.y.z', provider: 'choco', extraArgs: "--foo 'bar' 'foo'" ]) + printCallStack() + assertTrue(assertMethodCallContainsPattern('powershell', 'Install foo:x.y.z')) + assertTrue(assertMethodCallContainsPattern('powershell', """script=choco install foo --no-progress -y --version 'x.y.z' "--foo 'bar' 'foo'" """)) + assertFalse(assertMethodCallContainsPattern('powershell', 'script=.\\install-with-choco.ps1')) + assertJobStatusSuccess() + } +} diff --git a/vars/README.md b/vars/README.md index c05031837..80fc4ae4d 100644 --- a/vars/README.md +++ b/vars/README.md @@ -647,6 +647,27 @@ def body = httpRequest(url: "https://www.google.com", method: "GET", headers: [" def body = httpRequest(url: "https://duckduckgo.com", method: "POST", headers: ["User-Agent": "dummy"], data: "q=value&other=value") ``` +## installTools +This step will install the list of tools + +``` +installTools([ [ tool: 'python3', version: '3.5'] ]) +installTools([ [ tool: 'python3', version: '3.5'], [tool: 'nodejs', version: '12.0' ] ]) +``` + +``` + installTools([ + [ tool: 'visualstudio2019enterprise', version: '16.4.0.0', provider: 'choco', extraArgs: '--package-parameters "--includeRecommended"' ] + ]) +``` + + +* tool: The name of the tool to be installed for the default package manager. Mandatory. +* version: The version of the tool to be installated. Mandatory. +* provider: The provider to be used for installing the tools. Default behaviour + will detect then one available for the OS. Optional. +* extraArgs: Allow to use some extra args to extend the provider. Optional. + ## isCommentTrigger Check it the build was triggered by a comment in GitHub and the user is an Elastic user. it stores the comment owner username in the BUILD_CAUSE_USER environment variable and the diff --git a/vars/installTools.groovy b/vars/installTools.groovy new file mode 100644 index 000000000..586664c7f --- /dev/null +++ b/vars/installTools.groovy @@ -0,0 +1,62 @@ +// 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. + +/** + This step will install the list of tools + + installTools([ [ tool: 'python3', version: '3.5'] ]) + installTools([ [ tool: 'python3', version: '3.5'], [tool: 'nodejs', version: '12.0' ] ]) + + installTools([ + [ tool: 'visualstudio2019enterprise', version: '16.4.0.0', provider: 'choco', extraArgs: '--package-parameters "--includeRecommended"' ] + ]) +*/ + +def call(List params = []){ + if (params.isEmpty()) { + error("installTools: missing params, please use the format [ [ tool: 'foo', version: 'x.y.z'] , ...] tool param.") + } + params.each { item -> + installTool(item) + } +} + +private installTool(Map params) { + def tool = params.containsKey('tool') ? params.tool : error('installTools: missing tool param.') + def version = params.containsKey('version') ? params.version : error('installTools: missing version param.') + def provider = params.containsKey('provider') ? params.provider : '' + def extraArgs = params.containsKey('extraArgs') ? params.extraArgs : '' + + if(isUnix()) { + error 'TBD: install in linux' + } + switch (provider) { + case 'choco': + powershell label: "Install ${tool}:${version}", script: """choco install ${tool} --no-progress -y --version '${version}' "${extraArgs}" """ + break + case '': + def scriptFile = 'install-with-choco.ps1' + def resourceContent = libraryResource('scripts/install-with-choco.ps1') + writeFile file: scriptFile, text: resourceContent + withEnv(["VERSION=${version}", "TOOL=${tool}"]) { + powershell label: "Install ${tool}:${version}", script: ".\\${scriptFile}" + } + break + default: + error 'installTools: unsupported provider' + } +} diff --git a/vars/installTools.txt b/vars/installTools.txt new file mode 100644 index 000000000..877d85646 --- /dev/null +++ b/vars/installTools.txt @@ -0,0 +1,19 @@ +This step will install the list of tools + +``` +installTools([ [ tool: 'python3', version: '3.5'] ]) +installTools([ [ tool: 'python3', version: '3.5'], [tool: 'nodejs', version: '12.0' ] ]) +``` + +``` + installTools([ + [ tool: 'visualstudio2019enterprise', version: '16.4.0.0', provider: 'choco', extraArgs: '--package-parameters "--includeRecommended"' ] + ]) +``` + + +* tool: The name of the tool to be installed for the default package manager. Mandatory. +* version: The version of the tool to be installated. Mandatory. +* provider: The provider to be used for installing the tools. Default behaviour + will detect then one available for the OS. Optional. +* extraArgs: Allow to use some extra args to extend the provider. Optional.