From b16a63a74d98c9bf364a1c9d5edd0fc1af64591f Mon Sep 17 00:00:00 2001 From: Ruslan Kabalin Date: Thu, 22 Aug 2024 12:54:27 +0100 Subject: [PATCH] Add nvm installation to install step. 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/CHANGELOG.md | 5 +++ 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 | 36 ++++++++++++++++++++- tests/Installer/VendorInstallerTest.php | 43 +++++++++++++++++++++---- 9 files changed, 92 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/CHANGELOG.md b/docs/CHANGELOG.md index 26634f5a..77fe0deb 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com). ## [Unreleased] +### Added +- Install stable release of nvm as part of install command. This is now a default + behaviour, to bypass nvm installation use `--no-nvm` param for install command. +- ACTION SUGGESTED: Update your workflows and remove `echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV` in "Initialise moodle-plugin-ci" step, this is not required anymore. + ## [4.5.3] - 2024-07-05 ### Added - Support for version 4.4 of the app, that uses new defaults and Chrome (Selenium 4) version. 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..cd12903f 100644 --- a/src/Installer/VendorInstaller.php +++ b/src/Installer/VendorInstaller.php @@ -27,6 +27,8 @@ class VendorInstaller extends AbstractInstaller private Execute $execute; private bool $noPluginNode; public ?string $nodeVer; + private bool $noNvm; + /** * Define legacy Node version to use when .nvmrc is absent (Moodle < 3.5). */ @@ -38,17 +40,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 +92,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..ecc528ba 100644 --- a/tests/Installer/VendorInstallerTest.php +++ b/tests/Installer/VendorInstallerTest.php @@ -27,10 +27,15 @@ public function testInstall() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - null + null, + false, ); + // Unset NVM_DIR. + putenv('NVM_DIR'); + $installer->install(); + $this->assertNotEmpty(getenv('NVM_DIR')); $this->assertSame($installer->stepCount(), $installer->getOutput()->getStepCount()); } @@ -41,7 +46,8 @@ public function testInstallNodeNoNvmrc() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - null + null, + false, ); // Remove .nvmrc @@ -53,6 +59,25 @@ 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, + ); + // Unset NVM_DIR. + putenv('NVM_DIR'); + + $installer->install(); + + $this->assertFalse(getenv('NVM_DIR')); + $this->assertSame(2, $installer->getOutput()->getStepCount()); + } + public function testInstallNodeUserVersion() { $userVersion = '8.9'; @@ -61,8 +86,10 @@ public function testInstallNodeUserVersion() new MoodlePlugin($this->pluginDir), new DummyExecute(), false, - $userVersion + $userVersion, + false, ); + $installer->installNode(); // Expect .nvmrc containing user specified version. @@ -77,14 +104,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 +122,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()); } }