diff --git a/.gitignore b/.gitignore index 6be398ad1b..889bbd303c 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ patches npm-debug.log yarn-error.log composer.phar +composer.plugins.json _ide_helper.php _ide_helper_models.php resources/views/menu/custom.blade.php diff --git a/LibreNMS/ComposerHelper.php b/LibreNMS/ComposerHelper.php index 8f0232047c..6686c70a0b 100644 --- a/LibreNMS/ComposerHelper.php +++ b/LibreNMS/ComposerHelper.php @@ -63,6 +63,58 @@ class ComposerHelper { } + public static function addPlugin(string $package, string $version = null): int + { + $package = escapeshellarg($package . ($version ? ":$version" : null)); + + $cmds = [ + 'COMPOSER=composer.plugins.json ' . PHP_BINARY . " ./scripts/composer_wrapper.php require --no-update $package", + ]; + + return self::exec($cmds); + } + + public static function addPackage(string $package, string $version = null): int + { + $package = escapeshellarg($package . ($version ? ":$version" : null)); + + $cmds = [ + 'FORCE=1 ' . PHP_BINARY . " ./scripts/composer_wrapper.php require --update-no-dev $package", + ]; + + return self::exec($cmds); + } + + public static function removePlugin(string $package): int + { + $package = escapeshellarg($package); + + $cmds = [ + 'COMPOSER=composer.plugins.json ' . PHP_BINARY . " ./scripts/composer_wrapper.php remove --no-update $package", + ]; + + return self::exec($cmds); + } + + public static function removePackage(string $package): int + { + $package = escapeshellarg($package); + + $cmds = [ + 'FORCE=1 ' . PHP_BINARY . " ./scripts/composer_wrapper.php remove --update-no-dev $package", + ]; + + return self::exec($cmds); + } + + public static function getPlugins(): array + { + $plugins = is_file('composer.plugins.json') ? + json_decode(file_get_contents('composer.plugins.json'), true) : []; + + return $plugins['require'] ?? []; + } + /** * Initially populate .env file */ @@ -120,9 +172,11 @@ class ComposerHelper * * @param string|array $cmds */ - private static function exec($cmds) + private static function exec($cmds): int { $cmd = "set -v\n" . implode(PHP_EOL, (array) $cmds); - passthru($cmd); + passthru($cmd, $result_code); + + return $result_code; } } diff --git a/LibreNMS/Validations/Updates.php b/LibreNMS/Validations/Updates.php index 8a4993b1d8..0d28bfb212 100644 --- a/LibreNMS/Validations/Updates.php +++ b/LibreNMS/Validations/Updates.php @@ -28,6 +28,7 @@ namespace LibreNMS\Validations; use DateTime; use DateTimeZone; use Exception; +use LibreNMS\ComposerHelper; use LibreNMS\Config; use LibreNMS\Util\EnvHelper; use LibreNMS\Util\Git; @@ -101,12 +102,17 @@ class Updates extends BaseValidation $modifiedcmd = 'git diff --name-only --exit-code'; $validator->execAsUser($modifiedcmd, $cmdoutput, $code); if ($code !== 0 && ! empty($cmdoutput)) { - $result = ValidationResult::warn( - 'Your local git contains modified files, this could prevent automatic updates.', - 'You can fix this with ./scripts/github-remove' - ); - $result->setList('Modified Files', $cmdoutput); - $validator->result($result); + + // Check so it's not only plugins that "pests" the diff + if (! ($cmdoutput === ['composer.json', 'composer.lock'] && ComposerHelper::getPlugins())) { + $result = ValidationResult::warn( + 'Your local git contains modified files, this could prevent automatic updates.', + 'You can fix this with ./scripts/github-remove' + ); + + $result->setList('Modified Files', $cmdoutput); + $validator->result($result); + } } } } diff --git a/app/Console/Commands/PluginAddCommand.php b/app/Console/Commands/PluginAddCommand.php new file mode 100644 index 0000000000..aa0f818df7 --- /dev/null +++ b/app/Console/Commands/PluginAddCommand.php @@ -0,0 +1,48 @@ +argument('package'), $this->argument('version')) == 0) { + return ComposerHelper::addPlugin($this->argument('package'), $this->argument('version')); + } + + return 1; + } +} diff --git a/app/Console/Commands/PluginRemoveCommand.php b/app/Console/Commands/PluginRemoveCommand.php new file mode 100644 index 0000000000..21bd7234cb --- /dev/null +++ b/app/Console/Commands/PluginRemoveCommand.php @@ -0,0 +1,48 @@ +argument('package')); + ComposerHelper::removePackage($this->argument('package')); + + return 0; + } +} diff --git a/daily.php b/daily.php index 0f7c163b5e..42eb840375 100644 --- a/daily.php +++ b/daily.php @@ -14,10 +14,6 @@ use LibreNMS\Config; use LibreNMS\Util\Debug; use LibreNMS\Validations\Php; -$init_modules = ['alerts']; -require __DIR__ . '/includes/init.php'; -include_once __DIR__ . '/includes/notifications.php'; - $options = getopt('df:o:t:r:'); if (isset($options['d'])) { @@ -25,6 +21,31 @@ if (isset($options['d'])) { Debug::set(); } +/** + * Scripts without dependencies + */ +if ($options['f'] === 'composer_get_plugins') { + $output = []; + + $plugins = is_file('composer.plugins.json') ? + json_decode(file_get_contents('composer.plugins.json')) : []; + + foreach ($plugins->require ?? [] as $package => $version) { + $output[] = "$package:$version"; + } + + echo implode(' ', $output); + + return; +} + +/** + * Scripts with dependencies + */ +$init_modules = ['alerts']; +require __DIR__ . '/includes/init.php'; +include_once __DIR__ . '/includes/notifications.php'; + if ($options['f'] === 'update') { if (! Config::get('update')) { exit(0); diff --git a/daily.sh b/daily.sh index 865f241cd5..b2f08490b7 100755 --- a/daily.sh +++ b/daily.sh @@ -286,6 +286,9 @@ main () { check_dependencies php_ver_ret=$? + # Restore composer files if user installed plugins + git checkout --quiet -- composer.json composer.lock + update_res=0 if [[ "$up" == "1" ]] || [[ "$php_ver_ret" == "1" ]]; then # Update current branch to latest @@ -343,6 +346,13 @@ main () { # re-check dependencies after pull with the new code check_dependencies + # Insert user installed plugins before calling composer install + + PLUGINS=$(call_daily_php "composer_get_plugins") + if [ -n "$PLUGINS" ]; then + # shellcheck disable=SC2086 + FORCE=1 ${COMPOSER} require --update-no-dev --no-install $PLUGINS + fi status_run 'Updating Composer packages' "${COMPOSER} install --no-dev" 'update' # Check if we need to revert (Must be in post pull so we can update it) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 784faf7ee9..36170b17bc 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1635,11 +1635,6 @@ parameters: count: 1 path: LibreNMS/Component.php - - - message: "#^Method LibreNMS\\\\ComposerHelper\\:\\:exec\\(\\) has no return type specified\\.$#" - count: 1 - path: LibreNMS/ComposerHelper.php - - message: "#^Method LibreNMS\\\\ComposerHelper\\:\\:populateEnv\\(\\) has no return type specified\\.$#" count: 1