From e076f4840f9b92a80de8effa79a72ef6b66f778e Mon Sep 17 00:00:00 2001 From: Ruslan Kabalin Date: Thu, 22 Aug 2024 12:54:27 +0100 Subject: [PATCH] Add nvm installation. Install 0.39.7 explicitly as part of vendor installation, so we have control over the version we use. For cases where nvm is not required (pre-installed in the image, use --no-nvm param for install command) Fixes #309 --- .github/workflows/test.yml | 4 --- docs/CLI.md | 12 ++++++++- docs/GHAFileExplained.md | 3 +-- gha.dist.yml | 1 - src/Command/InstallCommand.php | 2 ++ src/Installer/InstallerFactory.php | 3 ++- src/Installer/VendorInstaller.php | 35 +++++++++++++++++++++++- tests/Installer/VendorInstallerTest.php | 36 ++++++++++++++++++++----- 8 files changed, 79 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 934c05bb..d0e73b24 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -120,8 +120,6 @@ jobs: echo "CI_BUILD_DIR="$(cd ../moodle-local_ci; pwd) >> $GITHUB_ENV # PHPUnit depends on en_AU.UTF-8 locale sudo locale-gen en_AU.UTF-8 - # Define NVM_DIR pointing to nvm installation. - echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV - name: Install moodle-plugin-ci run: moodle-plugin-ci install -vvv @@ -238,8 +236,6 @@ jobs: echo "CI_BUILD_DIR="$(cd ../moodle-local_ci; pwd) >> $GITHUB_ENV # PHPUnit depends on en_AU.UTF-8 locale sudo locale-gen en_AU.UTF-8 - # Define NVM_DIR pointing to nvm installation. - echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV - name: Download PHAR artifact uses: actions/download-artifact@v4 diff --git a/docs/CLI.md b/docs/CLI.md index d11fcd7d..cf155124 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -859,7 +859,7 @@ Install everything required for CI testing ### Usage -* `install [--moodle MOODLE] [--data DATA] [--repo REPO] [--branch BRANCH] [--plugin PLUGIN] [--db-type DB-TYPE] [--db-user DB-USER] [--db-pass DB-PASS] [--db-name DB-NAME] [--db-host DB-HOST] [--db-port DB-PORT] [--not-paths NOT-PATHS] [--not-names NOT-NAMES] [--extra-plugins EXTRA-PLUGINS] [--no-init] [--no-plugin-node] [--node-version NODE-VERSION]` +* `install [--moodle MOODLE] [--data DATA] [--repo REPO] [--branch BRANCH] [--plugin PLUGIN] [--db-type DB-TYPE] [--db-user DB-USER] [--db-pass DB-PASS] [--db-name DB-NAME] [--db-host DB-HOST] [--db-port DB-PORT] [--not-paths NOT-PATHS] [--not-names NOT-NAMES] [--extra-plugins EXTRA-PLUGINS] [--no-init] [--no-nvm] [--no-plugin-node] [--node-version NODE-VERSION]` Install everything required for CI testing @@ -1015,6 +1015,16 @@ Prevent PHPUnit and Behat initialization * Is negatable: no * Default: `false` +#### `--no-nvm` + +Prevent nvm installation + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--no-plugin-node` Prevent Node.js plugin dependencies installation diff --git a/docs/GHAFileExplained.md b/docs/GHAFileExplained.md index 74ea744d..0d1d9313 100644 --- a/docs/GHAFileExplained.md +++ b/docs/GHAFileExplained.md @@ -97,14 +97,13 @@ jobs: coverage: none # Install this project into a directory called "ci", updating PATH and - # locale, define nvm location. + # locale. - name: Initialise moodle-plugin-ci run: | composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 echo $(cd ci/bin; pwd) >> $GITHUB_PATH echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH sudo locale-gen en_AU.UTF-8 - echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV # Run the default install. # Optionally, it is possible to specify a different Moodle repo to use diff --git a/gha.dist.yml b/gha.dist.yml index 3cdfd061..c2b4df2e 100644 --- a/gha.dist.yml +++ b/gha.dist.yml @@ -56,7 +56,6 @@ jobs: echo $(cd ci/bin; pwd) >> $GITHUB_PATH echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH sudo locale-gen en_AU.UTF-8 - echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV - name: Install moodle-plugin-ci run: moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 diff --git a/src/Command/InstallCommand.php b/src/Command/InstallCommand.php index 827bf0ed..5d182166 100644 --- a/src/Command/InstallCommand.php +++ b/src/Command/InstallCommand.php @@ -102,6 +102,7 @@ protected function configure(): void ->addOption('not-names', null, InputOption::VALUE_REQUIRED, 'CSV of file names to exclude', $names) ->addOption('extra-plugins', null, InputOption::VALUE_REQUIRED, 'Directory of extra plugins to install', $extra) ->addOption('no-init', null, InputOption::VALUE_NONE, 'Prevent PHPUnit and Behat initialization') + ->addOption('no-nvm', null, InputOption::VALUE_NONE, 'Prevent nvm installation') ->addOption('no-plugin-node', null, InputOption::VALUE_NONE, 'Prevent Node.js plugin dependencies installation') ->addOption('node-version', null, InputOption::VALUE_REQUIRED, 'Node.js version to use for nvm install (this will override one defined in .nvmrc)', $node); } @@ -175,6 +176,7 @@ public function initializeInstallerFactory(InputInterface $input): InstallerFact $factory->dumper = $this->initializePluginConfigDumper($input); $factory->pluginsDir = $pluginsDir; $factory->noInit = $input->getOption('no-init'); + $factory->noNvm = $input->getOption('no-nvm'); $factory->noPluginNode = $input->getOption('no-plugin-node'); $factory->nodeVer = $input->getOption('node-version'); $factory->database = $resolver->resolveDatabase( diff --git a/src/Installer/InstallerFactory.php b/src/Installer/InstallerFactory.php index 5421a356..2d2d8b20 100644 --- a/src/Installer/InstallerFactory.php +++ b/src/Installer/InstallerFactory.php @@ -33,6 +33,7 @@ class InstallerFactory public ConfigDumper $dumper; public ?string $pluginsDir; public bool $noInit; + public bool $noNvm; public bool $noPluginNode; public ?string $nodeVer; @@ -52,7 +53,7 @@ public function addInstallers(InstallerCollection $installers): void } $installers->add(new PluginInstaller($this->moodle, $this->plugin, $this->pluginsDir, $this->dumper)); - $installers->add(new VendorInstaller($this->moodle, $this->plugin, $this->execute, $this->noPluginNode, $this->nodeVer)); + $installers->add(new VendorInstaller($this->moodle, $this->plugin, $this->execute, $this->noPluginNode, $this->nodeVer, $this->noNvm)); if ($this->noInit) { return; diff --git a/src/Installer/VendorInstaller.php b/src/Installer/VendorInstaller.php index 3f1fb3bc..d70694a9 100644 --- a/src/Installer/VendorInstaller.php +++ b/src/Installer/VendorInstaller.php @@ -25,6 +25,7 @@ class VendorInstaller extends AbstractInstaller private Moodle $moodle; private MoodlePlugin $plugin; private Execute $execute; + private bool $noNvm; private bool $noPluginNode; public ?string $nodeVer; /** @@ -38,17 +39,22 @@ class VendorInstaller extends AbstractInstaller * @param Execute $execute * @param string|null $nodeVer */ - public function __construct(Moodle $moodle, MoodlePlugin $plugin, Execute $execute, bool $noPluginNode, ?string $nodeVer) + public function __construct(Moodle $moodle, MoodlePlugin $plugin, Execute $execute, bool $noPluginNode, ?string $nodeVer, bool $noNvm) { $this->moodle = $moodle; $this->plugin = $plugin; $this->execute = $execute; $this->nodeVer = $nodeVer; $this->noPluginNode = $noPluginNode; + $this->noNvm = $noNvm; } public function install(): void { + if ($this->canInstallNvm()) { + $this->getOutput()->step('Installing nvm'); + $this->installNvm(); + } if ($this->canInstallNode()) { $this->getOutput()->step('Installing Node.js'); $this->installNode(); @@ -85,10 +91,37 @@ public function install(): void public function stepCount(): int { return 2 + // Normally 2 steps: global dependencies and Moodle npm dependencies. + ($this->canInstallNvm() ? 1 : 0) + // Plus nvm installation. ($this->canInstallNode() ? 1 : 0) + // Plus Node.js installation. ((!$this->noPluginNode && $this->plugin->hasNodeDependencies()) ? 1 : 0); // Plus plugin npm dependencies step. } + /** + * Check if we have to install nvm. + * + * @return bool + */ + public function canInstallNvm(): bool + { + return !$this->noNvm; + } + + /** + * Install nvm. + */ + public function installNvm(): void + { + $cmd = 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash'; + $process = $this->execute->passThroughProcess( + Process::fromShellCommandline($cmd, $this->moodle->directory, null, null, null) + ); + if (!$process->isSuccessful()) { + throw new \RuntimeException('nvm installation failed.'); + } + $home = getenv('HOME'); + putenv("NVM_DIR={$home}/.nvm"); + } + /** * Check if we have nvm to proceed with Node.js installation step. * diff --git a/tests/Installer/VendorInstallerTest.php b/tests/Installer/VendorInstallerTest.php index 432715da..bfd41901 100644 --- a/tests/Installer/VendorInstallerTest.php +++ b/tests/Installer/VendorInstallerTest.php @@ -27,7 +27,8 @@ public function testInstall() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - null + null, + false, ); $installer->install(); @@ -41,7 +42,8 @@ public function testInstallNodeNoNvmrc() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - null + null, + false, ); // Remove .nvmrc @@ -53,6 +55,22 @@ public function testInstallNodeNoNvmrc() $this->assertSame('lts/carbon', file_get_contents($this->moodleDir . '/.nvmrc')); } + public function testInstallNoNvm() + { + $installer = new VendorInstaller( + new DummyMoodle($this->moodleDir), + new MoodlePlugin($this->pluginDir), + new DummyExecute(), + false, + null, + true, + ); + + $installer->install(); + + $this->assertSame(3, $installer->getOutput()->getStepCount()); + } + public function testInstallNodeUserVersion() { $userVersion = '8.9'; @@ -61,8 +79,10 @@ public function testInstallNodeUserVersion() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - $userVersion + $userVersion, + false, ); + $installer->installNode(); // Expect .nvmrc containing user specified version. @@ -77,14 +97,15 @@ public function testInstallNodePluginDependencies() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - null + null, + false, ); $this->fs->copy(__DIR__ . '/../Fixture/plugin/package.json', $this->pluginDir . '/package.json'); $installer->install(); - $this->assertSame(4, $installer->getOutput()->getStepCount()); + $this->assertSame(5, $installer->getOutput()->getStepCount()); } public function testSkipNodePluginDependencies() @@ -94,13 +115,14 @@ public function testSkipNodePluginDependencies() new MoodlePlugin($this->pluginDir), new DummyExecute(), true, - null + null, + false, ); $this->fs->copy(__DIR__ . '/../Fixture/plugin/package.json', $this->pluginDir . '/package.json'); $installer->install(); - $this->assertSame(3, $installer->getOutput()->getStepCount()); + $this->assertSame(4, $installer->getOutput()->getStepCount()); } }