From 13840e548d17156a2d1e75d2fafa1305424ad1bb Mon Sep 17 00:00:00 2001 From: nre Date: Thu, 14 Sep 2023 16:31:57 +0000 Subject: [PATCH 01/12] Cleanup: refactor duplicated string to variable --- test/com/ableton/PyenvTest.groovy | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index 0844ed1..686aa8c 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -199,12 +199,13 @@ class PyenvTest extends BasePipelineTest { 2.2.3 2.3.7 ''' - helper.addShMock('/pyenv/bin/pyenv install --list', mockPyenvVersions, 0) + String pyenvRoot = '/pyenv' + helper.addShMock("${pyenvRoot}/bin/pyenv install --list", mockPyenvVersions, 0) helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } - assertTrue(new Pyenv(script, '/pyenv').versionSupported('2.1.3')) - assertFalse(new Pyenv(script, '/pyenv').versionSupported('2.1.3333')) + assertTrue(new Pyenv(script, pyenvRoot).versionSupported('2.1.3')) + assertFalse(new Pyenv(script, pyenvRoot).versionSupported('2.1.3333')) } @Test From a2daa8a1910cfc24cccecaa806dd4260534e6521 Mon Sep 17 00:00:00 2001 From: nre Date: Thu, 28 Jul 2022 10:43:34 +0200 Subject: [PATCH 02/12] Print environment variables in integration tests --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 1619a98..717e313 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -35,6 +35,8 @@ eventRecorder.timedStage('Integration Test') { nodeLabel = 'generic-mac-xcode12.2' } eventRecorder.timedNode(nodeLabel) { + sh 'env | sort' + echo 'Test VirtualEnv.create' Object venv = virtualenv.create('python3') String venvVersion = venv.run(returnStdout: true, script: 'python --version') From 1143c0fb89b54027f6662d3eb7d758e9a082f8d3 Mon Sep 17 00:00:00 2001 From: nre Date: Thu, 14 Sep 2023 16:00:55 +0000 Subject: [PATCH 03/12] Add a helper method to reduce duplicated test code --- test/com/ableton/PyenvTest.groovy | 74 ++++++++----------------------- 1 file changed, 19 insertions(+), 55 deletions(-) diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index 686aa8c..964268c 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -54,17 +54,7 @@ class PyenvTest extends BasePipelineTest { String pyenvRoot = '/mock/pyenv/root' helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } - // Indentation must match the actual command - helper.addShMock(""" - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${pythonVersion} - pyenv shell ${pythonVersion} - pip install virtualenv - virtualenv /workspace/.venv/${TEST_RANDOM_NAME} - """, '', 0) + helper.addShMock(installCommands(pyenvRoot, pythonVersion), '', 0) helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) helper.addShMock("${pyenvRoot}/bin/pyenv install --list", '1.2.3', 0) @@ -79,17 +69,7 @@ class PyenvTest extends BasePipelineTest { String pyenvRoot = '/mock/pyenv/root' helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } - // Indentation must match the actual command - helper.addShMock(""" - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${pythonVersion} - pyenv shell ${pythonVersion} - pip install virtualenv - virtualenv /workspace/.venv/${TEST_RANDOM_NAME} - """, '', 0) + helper.addShMock(installCommands(pyenvRoot, pythonVersion), '', 1) helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) helper.addShMock("${pyenvRoot}/bin/pyenv install --list", '1.2.3', 0) @@ -105,17 +85,7 @@ class PyenvTest extends BasePipelineTest { helper.with { registerAllowedMethod('fileExists', [String]) { return true } registerAllowedMethod('isUnix', []) { return true } - // Indentation must match the actual command - addShMock(""" - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${pythonVersion} - pyenv shell ${pythonVersion} - pip install virtualenv - virtualenv /workspace/.venv/${TEST_RANDOM_NAME} - """, '', 1) + addShMock(installCommands(pyenvRoot, pythonVersion), '', 1) addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) addShMock("${pyenvRoot}/bin/pyenv install --list", '1.2.3', 0) } @@ -141,17 +111,7 @@ class PyenvTest extends BasePipelineTest { addShMock("${pyenvRoot}/bin/pyenv install --list", '''Available versions: 1.2.3 ''', 0) - // Indentation must match the actual command - addShMock(""" - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${pythonVersion} - pyenv shell ${pythonVersion} - pip install virtualenv - virtualenv /workspace/.venv/${TEST_RANDOM_NAME} - """, '', 1) + addShMock(installCommands(pyenvRoot, pythonVersion), '', 1) } assertThrows(Exception) { @@ -174,17 +134,7 @@ class PyenvTest extends BasePipelineTest { helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) - // Indentation must match the actual command - helper.addShMock(""" - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${pythonVersion} - pyenv shell ${pythonVersion} - pip install virtualenv - virtualenv /workspace/.venv/${TEST_RANDOM_NAME} - """, '', 1) + helper.addShMock(installCommands(pyenvRoot, pythonVersion), '', 1) assertThrows(Exception) { new Pyenv(script, pyenvRoot).createVirtualEnv(pythonVersion, 1) @@ -214,4 +164,18 @@ class PyenvTest extends BasePipelineTest { assertThrows(Exception) { new Pyenv(script, 'C:\\pyenv').versionSupported('1.2.3') } } + + private String installCommands(String pyenvRoot, String pythonVersion) { + // Indentation must match the actual command + return """ + export PYENV_ROOT=${pyenvRoot} + export PATH=\$PYENV_ROOT/bin:\$PATH + eval "\$(pyenv init --path)" + eval "\$(pyenv init -)" + pyenv install --skip-existing ${pythonVersion} + pyenv shell ${pythonVersion} + pip install virtualenv + virtualenv /workspace/.venv/${TEST_RANDOM_NAME} + """ + } } From b2a4ff8b90d462ad486a011c400e67ff09774e23 Mon Sep 17 00:00:00 2001 From: nre Date: Fri, 29 Nov 2024 10:57:58 +0100 Subject: [PATCH 04/12] Store installation commands in a list In future commits, we'll need to modify the commands used depending on the platform (and some other factors as well). Storing them in a list will make this easier to manipulate. --- src/com/ableton/Pyenv.groovy | 21 +++++++++++---------- test/com/ableton/PyenvTest.groovy | 23 ++++++++++++----------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/com/ableton/Pyenv.groovy b/src/com/ableton/Pyenv.groovy index f3eb10d..684cb0e 100644 --- a/src/com/ableton/Pyenv.groovy +++ b/src/com/ableton/Pyenv.groovy @@ -62,18 +62,19 @@ class Pyenv implements Serializable { VirtualEnv venv = new VirtualEnv(script, randomSeed) script.retry(INSTALLATION_RETRIES) { + List installCommands = [ + "export PYENV_ROOT=${pyenvRoot}", + "export PATH=\$PYENV_ROOT/bin:\$PATH", + "eval \"\$(pyenv init --path)\"", + "eval \"\$(pyenv init -)\"", + "pyenv install --skip-existing ${trimmedPythonVersion}", + "pyenv shell ${trimmedPythonVersion}", + 'pip install virtualenv', + "virtualenv ${venv.venvRootDir}", + ] venv.script.sh( label: "Install Python version ${trimmedPythonVersion} with pyenv", - script: """ - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${trimmedPythonVersion} - pyenv shell ${trimmedPythonVersion} - pip install virtualenv - virtualenv ${venv.venvRootDir} - """, + script: installCommands.join('\n') + '\n', ) } diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index 964268c..3c69b3f 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -166,16 +166,17 @@ class PyenvTest extends BasePipelineTest { } private String installCommands(String pyenvRoot, String pythonVersion) { - // Indentation must match the actual command - return """ - export PYENV_ROOT=${pyenvRoot} - export PATH=\$PYENV_ROOT/bin:\$PATH - eval "\$(pyenv init --path)" - eval "\$(pyenv init -)" - pyenv install --skip-existing ${pythonVersion} - pyenv shell ${pythonVersion} - pip install virtualenv - virtualenv /workspace/.venv/${TEST_RANDOM_NAME} - """ + List installCommands = [ + "export PYENV_ROOT=${pyenvRoot}", + "export PATH=\$PYENV_ROOT/bin:\$PATH", + "eval \"\$(pyenv init --path)\"", + "eval \"\$(pyenv init -)\"", + "pyenv install --skip-existing ${pythonVersion}", + "pyenv shell ${pythonVersion}", + 'pip install virtualenv', + "virtualenv /workspace/.venv/${TEST_RANDOM_NAME}", + ] + + return installCommands.join('\n') + '\n' } } From f132d020f67ff46866230682d5d2281c0797f45c Mon Sep 17 00:00:00 2001 From: nre Date: Wed, 13 Sep 2023 13:39:06 +0000 Subject: [PATCH 05/12] Use pyenv exec when running pip install This will facilitate Windows support, which will be added in a future commit. --- src/com/ableton/Pyenv.groovy | 4 ++-- test/com/ableton/PyenvTest.groovy | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/ableton/Pyenv.groovy b/src/com/ableton/Pyenv.groovy index 684cb0e..9d57c11 100644 --- a/src/com/ableton/Pyenv.groovy +++ b/src/com/ableton/Pyenv.groovy @@ -69,8 +69,8 @@ class Pyenv implements Serializable { "eval \"\$(pyenv init -)\"", "pyenv install --skip-existing ${trimmedPythonVersion}", "pyenv shell ${trimmedPythonVersion}", - 'pip install virtualenv', - "virtualenv ${venv.venvRootDir}", + 'pyenv exec pip install virtualenv', + "pyenv exec virtualenv ${venv.venvRootDir}", ] venv.script.sh( label: "Install Python version ${trimmedPythonVersion} with pyenv", diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index 3c69b3f..4b174b2 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -173,8 +173,8 @@ class PyenvTest extends BasePipelineTest { "eval \"\$(pyenv init -)\"", "pyenv install --skip-existing ${pythonVersion}", "pyenv shell ${pythonVersion}", - 'pip install virtualenv', - "virtualenv /workspace/.venv/${TEST_RANDOM_NAME}", + 'pyenv exec pip install virtualenv', + "pyenv exec virtualenv /workspace/.venv/${TEST_RANDOM_NAME}", ] return installCommands.join('\n') + '\n' From 8b8f02c84b62c0b96a1853b4fd081761d88d9529 Mon Sep 17 00:00:00 2001 From: nre Date: Wed, 13 Sep 2023 13:40:29 +0000 Subject: [PATCH 06/12] Export PYENV_VERSION rather than using pyenv shell This is needed to support pyenv on Windows. --- src/com/ableton/Pyenv.groovy | 29 +++++++++++++++-------------- test/com/ableton/PyenvTest.groovy | 1 - 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/com/ableton/Pyenv.groovy b/src/com/ableton/Pyenv.groovy index 9d57c11..530872d 100644 --- a/src/com/ableton/Pyenv.groovy +++ b/src/com/ableton/Pyenv.groovy @@ -62,20 +62,21 @@ class Pyenv implements Serializable { VirtualEnv venv = new VirtualEnv(script, randomSeed) script.retry(INSTALLATION_RETRIES) { - List installCommands = [ - "export PYENV_ROOT=${pyenvRoot}", - "export PATH=\$PYENV_ROOT/bin:\$PATH", - "eval \"\$(pyenv init --path)\"", - "eval \"\$(pyenv init -)\"", - "pyenv install --skip-existing ${trimmedPythonVersion}", - "pyenv shell ${trimmedPythonVersion}", - 'pyenv exec pip install virtualenv', - "pyenv exec virtualenv ${venv.venvRootDir}", - ] - venv.script.sh( - label: "Install Python version ${trimmedPythonVersion} with pyenv", - script: installCommands.join('\n') + '\n', - ) + script.withEnv(["PYENV_VERSION=${trimmedPythonVersion}"]) { + List installCommands = [ + "export PYENV_ROOT=${pyenvRoot}", + "export PATH=\$PYENV_ROOT/bin:\$PATH", + "eval \"\$(pyenv init --path)\"", + "eval \"\$(pyenv init -)\"", + "pyenv install --skip-existing ${trimmedPythonVersion}", + 'pyenv exec pip install virtualenv', + "pyenv exec virtualenv ${venv.venvRootDir}", + ] + venv.script.sh( + label: "Install Python version ${trimmedPythonVersion} with pyenv", + script: installCommands.join('\n') + '\n', + ) + } } return venv diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index 4b174b2..7c6c0ee 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -172,7 +172,6 @@ class PyenvTest extends BasePipelineTest { "eval \"\$(pyenv init --path)\"", "eval \"\$(pyenv init -)\"", "pyenv install --skip-existing ${pythonVersion}", - "pyenv shell ${pythonVersion}", 'pyenv exec pip install virtualenv', "pyenv exec virtualenv /workspace/.venv/${TEST_RANDOM_NAME}", ] From 7dd8d6861b011d090c7bae305d5bcf5cc78ccf6f Mon Sep 17 00:00:00 2001 From: nre Date: Wed, 29 Jun 2022 17:38:03 +0200 Subject: [PATCH 07/12] Introduce a method to convert Windows paths This will be needed to fully support Windows, which will happen in a future commit. --- src/com/ableton/VirtualEnv.groovy | 8 ++++++++ test/com/ableton/VirtualEnvTest.groovy | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/com/ableton/VirtualEnv.groovy b/src/com/ableton/VirtualEnv.groovy index 695045d..5656e96 100644 --- a/src/com/ableton/VirtualEnv.groovy +++ b/src/com/ableton/VirtualEnv.groovy @@ -70,6 +70,14 @@ class VirtualEnv implements Serializable { this.venvBinDir = "${venvRootDir}/${activateSubDir}" } + @NonCPS + static final String posixPath(String path) { + if (path[1] == ':') { + return "/${path[0].toLowerCase()}/${path.substring(3).replaceAll('\\\\', '/')}" + } + return path.replaceAll('\\\\', '/') + } + /** * Removes the virtualenv from disk. You can call this method in the cleanup stage of * the pipeline to avoid cluttering the build node with temporary files. Note that the diff --git a/test/com/ableton/VirtualEnvTest.groovy b/test/com/ableton/VirtualEnvTest.groovy index 99b1e28..88c0474 100644 --- a/test/com/ableton/VirtualEnvTest.groovy +++ b/test/com/ableton/VirtualEnvTest.groovy @@ -124,6 +124,14 @@ class VirtualEnvTest extends BasePipelineTest { assertTrue(exceptionThrown) } + @Test + void posixPath() { + assertEquals('/c/foo/bar', VirtualEnv.posixPath('/c/foo/bar')) + assertEquals('/c/foo/bar', VirtualEnv.posixPath('C:\\foo\\bar')) + assertEquals('foo/bar', VirtualEnv.posixPath('foo\\bar')) + assertEquals('foo/bar', VirtualEnv.posixPath('foo/bar')) + } + @Test void randomName() { assertEquals('58734446', VirtualEnv.randomName(1)) From 8476517e8c9b7f482878fdc0ffbd3a11b840bd70 Mon Sep 17 00:00:00 2001 From: nre Date: Wed, 29 Jun 2022 17:38:57 +0200 Subject: [PATCH 08/12] Use posixPath when creating Windows venvs This is needed to support pyenv on Windows, which will be added in a future commit. --- src/com/ableton/VirtualEnv.groovy | 7 +++++-- test/com/ableton/VirtualEnvTest.groovy | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/com/ableton/VirtualEnv.groovy b/src/com/ableton/VirtualEnv.groovy index 5656e96..18d5818 100644 --- a/src/com/ableton/VirtualEnv.groovy +++ b/src/com/ableton/VirtualEnv.groovy @@ -62,7 +62,7 @@ class VirtualEnv implements Serializable { activateSubDir = 'bin' } else { activateSubDir = 'Scripts' - workspace = workspace.replace('\\', '/') + workspace = posixPath(workspace) } long seed = randomSeed ?: System.currentTimeMillis() * this.hashCode() @@ -83,9 +83,12 @@ class VirtualEnv implements Serializable { * the pipeline to avoid cluttering the build node with temporary files. Note that the * virtualenv is stored underneath the workspace, so removing the workspace will have * the same effect. + * + * We use `sh` here rather than `deleteDir` because the latter doesn't work with CygWin + * paths on Windows. */ void cleanup() { - script.dir(venvRootDir) { script.deleteDir() } + script.sh "rm -rf ${venvRootDir}" } /** diff --git a/test/com/ableton/VirtualEnvTest.groovy b/test/com/ableton/VirtualEnvTest.groovy index 88c0474..6a34ced 100644 --- a/test/com/ableton/VirtualEnvTest.groovy +++ b/test/com/ableton/VirtualEnvTest.groovy @@ -87,7 +87,7 @@ class VirtualEnvTest extends BasePipelineTest { assertNotNull(venv) assertNotNull(venv.script) assertNotNull(venv.venvRootDir) - assertEquals("C:/workspace/.venv/${TEST_RANDOM_NAME}" as String, venv.venvRootDir) + assertEquals("/c/workspace/.venv/${TEST_RANDOM_NAME}" as String, venv.venvRootDir) } @Test From c71656b5c74984e530441519dbd96f8038d71423 Mon Sep 17 00:00:00 2001 From: nre Date: Mon, 25 Sep 2023 14:26:25 +0000 Subject: [PATCH 09/12] Use posixPath to make safe paths This will be needed to support pyenv on Windows, which will happen in a subsequent commit. --- src/com/ableton/Pyenv.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/ableton/Pyenv.groovy b/src/com/ableton/Pyenv.groovy index 530872d..3b4b3cf 100644 --- a/src/com/ableton/Pyenv.groovy +++ b/src/com/ableton/Pyenv.groovy @@ -23,7 +23,7 @@ class Pyenv implements Serializable { Pyenv(Object script, String pyenvRoot) { this.script = script - this.pyenvRoot = pyenvRoot + this.pyenvRoot = pyenvRoot ? VirtualEnv.posixPath(pyenvRoot) : null } /** From 719bc1d4faabd465c82d4acf3f0b40d1e3f2cbe8 Mon Sep 17 00:00:00 2001 From: nre Date: Thu, 14 Sep 2023 16:17:40 +0000 Subject: [PATCH 10/12] Run pyenv to assert the pyenv root path exists To support Windows (which will be done in a subsequent commit), we'll need to translate Windows-style paths to Cygwin-style paths (for example, C:\foo\bar -> /c/foo/bar). The fileExists step only supports Windows-style paths when run on Windows, which means that we need to actually run pyenv to assert that it exists. --- src/com/ableton/Pyenv.groovy | 4 ++-- test/com/ableton/PyenvTest.groovy | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/com/ableton/Pyenv.groovy b/src/com/ableton/Pyenv.groovy index 3b4b3cf..fc18fc8 100644 --- a/src/com/ableton/Pyenv.groovy +++ b/src/com/ableton/Pyenv.groovy @@ -118,8 +118,8 @@ class Pyenv implements Serializable { protected void assertPyenvRoot() { assert pyenvRoot - if (!script.fileExists(pyenvRoot)) { - script.error "pyenv root path '${pyenvRoot}' does not exist" + if (script.sh(returnStatus: true, script: "${pyenvRoot}/bin/pyenv --version")) { + script.error "pyenv executable not found in '${pyenvRoot}'" } } } diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index 7c6c0ee..bcf54b3 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -35,8 +35,8 @@ class PyenvTest extends BasePipelineTest { @Test void assertPyenvRootInvalidRoot() { String pyenvRoot = '/mock/pyenv/root' - helper.registerAllowedMethod('fileExists', [String]) { return false } helper.registerAllowedMethod('isUnix', []) { return true } + helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) assertThrows(Exception) { new Pyenv(script, '1.2.3', pyenvRoot).createVirtualEnv() } } @@ -52,7 +52,6 @@ class PyenvTest extends BasePipelineTest { void createVirtualEnv() { String pythonVersion = '1.2.3' String pyenvRoot = '/mock/pyenv/root' - helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } helper.addShMock(installCommands(pyenvRoot, pythonVersion), '', 0) helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) @@ -131,7 +130,6 @@ class PyenvTest extends BasePipelineTest { String pythonVersion = '6.6.6' String pyenvRoot = '/mock/pyenv/root' helper.registerAllowedMethod('error', [String]) { errorCalled = true } - helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) helper.addShMock(installCommands(pyenvRoot, pythonVersion), '', 1) @@ -150,8 +148,8 @@ class PyenvTest extends BasePipelineTest { 2.3.7 ''' String pyenvRoot = '/pyenv' + helper.addShMock("${pyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) helper.addShMock("${pyenvRoot}/bin/pyenv install --list", mockPyenvVersions, 0) - helper.registerAllowedMethod('fileExists', [String]) { return true } helper.registerAllowedMethod('isUnix', []) { return true } assertTrue(new Pyenv(script, pyenvRoot).versionSupported('2.1.3')) From 2f88943c9b1d63112889fa15e0e50dba9c863ff7 Mon Sep 17 00:00:00 2001 From: nre Date: Fri, 29 Nov 2024 11:31:08 +0100 Subject: [PATCH 11/12] Support pyenv on Windows --- Jenkinsfile | 13 ++++------- src/com/ableton/Pyenv.groovy | 24 +++++++++---------- test/com/ableton/PyenvTest.groovy | 38 +++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 717e313..bea39ed 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -42,14 +42,11 @@ eventRecorder.timedStage('Integration Test') { String venvVersion = venv.run(returnStdout: true, script: 'python --version') assert venvVersion.startsWith('Python 3') - if (isUnix()) { - echo 'Test VirtualEnv.createWithPyenv' - Object pyvenv = pyenv.createVirtualEnv('3.10.3') - String pyvenvVersion = - pyvenv.run(returnStdout: true, script: 'python --version') - echo pyvenvVersion - assert pyvenvVersion.trim() == 'Python 3.10.3' - } + echo 'Test VirtualEnv.createWithPyenv' + Object pyvenv = pyenv.createVirtualEnv('3.10.3') + String pyvenvVersion = pyvenv.run(returnStdout: true, script: 'python --version') + echo pyvenvVersion + assert pyvenvVersion.trim() == 'Python 3.10.3' } } } diff --git a/src/com/ableton/Pyenv.groovy b/src/com/ableton/Pyenv.groovy index fc18fc8..db9559f 100644 --- a/src/com/ableton/Pyenv.groovy +++ b/src/com/ableton/Pyenv.groovy @@ -44,10 +44,6 @@ class Pyenv implements Serializable { String trimmedPythonVersion = pythonVersion.trim() - if (!script.isUnix()) { - script.error 'This method is not supported on Windows' - } - if (!versionSupported(trimmedPythonVersion)) { script.withEnv(["PYENV_ROOT=${pyenvRoot}"]) { String pyenvVersion = script.sh( @@ -63,11 +59,17 @@ class Pyenv implements Serializable { VirtualEnv venv = new VirtualEnv(script, randomSeed) script.retry(INSTALLATION_RETRIES) { script.withEnv(["PYENV_VERSION=${trimmedPythonVersion}"]) { - List installCommands = [ - "export PYENV_ROOT=${pyenvRoot}", - "export PATH=\$PYENV_ROOT/bin:\$PATH", - "eval \"\$(pyenv init --path)\"", - "eval \"\$(pyenv init -)\"", + List installCommands = ["export PYENV_ROOT=${pyenvRoot}"] + if (script.isUnix()) { + installCommands += [ + "export PATH=\$PYENV_ROOT/bin:\$PATH", + "eval \"\$(pyenv init --path)\"", + "eval \"\$(pyenv init -)\"", + ] + } else { + installCommands.add("export PATH=${pyenvRoot}/shims:${pyenvRoot}/bin:\$PATH") + } + installCommands += [ "pyenv install --skip-existing ${trimmedPythonVersion}", 'pyenv exec pip install virtualenv', "pyenv exec virtualenv ${venv.venvRootDir}", @@ -94,10 +96,6 @@ class Pyenv implements Serializable { assertPyenvRoot() boolean result = false - if (!script.isUnix()) { - script.error 'This method is not supported on Windows' - } - script.withEnv(["PYENV_ROOT=${pyenvRoot}"]) { String allVersions = script.sh( label: 'Get Python versions supported by Pyenv', diff --git a/test/com/ableton/PyenvTest.groovy b/test/com/ableton/PyenvTest.groovy index bcf54b3..04273d3 100644 --- a/test/com/ableton/PyenvTest.groovy +++ b/test/com/ableton/PyenvTest.groovy @@ -120,9 +120,19 @@ class PyenvTest extends BasePipelineTest { @Test void createVirtualEnvWindows() { + String pythonVersion = '1.2.3' + String pyenvRoot = 'C:\\mock\\pyenv\\root' + String cygwinPyenvRoot = '/c/mock/pyenv/root' helper.registerAllowedMethod('isUnix', []) { return false } + helper.addShMock("${cygwinPyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) + helper.addShMock("${cygwinPyenvRoot}/bin/pyenv install --list", '''Available versions: + 1.2.3 +''', 0) + helper.addShMock(installCommands(cygwinPyenvRoot, pythonVersion, false), '', 0) - assertThrows(Exception) { new Pyenv(script, 'C:\\pyenv').createVirtualEnv('1.2.3') } + Object venv = new Pyenv(script, pyenvRoot).createVirtualEnv(pythonVersion, 1) + + assertEquals("/workspace/.venv/${TEST_RANDOM_NAME}" as String, venv.venvRootDir) } @Test @@ -158,17 +168,35 @@ class PyenvTest extends BasePipelineTest { @Test void versionSupportedWindows() { + // Resembles pyenv's output, at least as of version 2.3.x + String mockPyenvVersions = '''Available versions: + 2.1.3 + 2.2.3 + 2.3.7 +''' + String cygwinPyenvRoot = '/c/pyenv' + helper.addShMock("${cygwinPyenvRoot}/bin/pyenv --version", 'pyenv 1.2.3', 0) + helper.addShMock("${cygwinPyenvRoot}/bin/pyenv install --list", mockPyenvVersions, 0) helper.registerAllowedMethod('isUnix', []) { return false } - assertThrows(Exception) { new Pyenv(script, 'C:\\pyenv').versionSupported('1.2.3') } + assertTrue(new Pyenv(script, cygwinPyenvRoot).versionSupported('2.1.3')) + assertFalse(new Pyenv(script, cygwinPyenvRoot).versionSupported('2.1.3333')) } - private String installCommands(String pyenvRoot, String pythonVersion) { + private String installCommands( + String pyenvRoot, String pythonVersion, boolean isUnix = true + ) { List installCommands = [ "export PYENV_ROOT=${pyenvRoot}", "export PATH=\$PYENV_ROOT/bin:\$PATH", - "eval \"\$(pyenv init --path)\"", - "eval \"\$(pyenv init -)\"", + ] + if (isUnix) { + installCommands += [ + "eval \"\$(pyenv init --path)\"", + "eval \"\$(pyenv init -)\"", + ] + } + installCommands += [ "pyenv install --skip-existing ${pythonVersion}", 'pyenv exec pip install virtualenv', "pyenv exec virtualenv /workspace/.venv/${TEST_RANDOM_NAME}", From 493487763f8a83f3c154d0fbe9233068c42a4864 Mon Sep 17 00:00:00 2001 From: nre Date: Mon, 25 Sep 2023 14:29:11 +0000 Subject: [PATCH 12/12] Version 0.14.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ebf55b3..a803cc2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.13.6 +0.14.0