قرینه از
https://github.com/matomo-org/matomo.git
synced 2025-08-21 22:47:43 +00:00

* [Coding Style] Enable rule PSR12.Files.FileHeader * Apply CS * Replace Piwik with Matomo in file headers * Unify file headers (position, no. of lines, https links) * Rebuild dist files * Apply CS * Fix system test that relies on line numbers in a file that had the file header updated --------- Co-authored-by: Stefan Giehl <stefan@matomo.org>
255 خطوط
10 KiB
PHP
255 خطوط
10 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Matomo - free/libre analytics platform
|
|
*
|
|
* @link https://matomo.org
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*/
|
|
|
|
namespace Piwik\Plugins\TestRunner\Commands;
|
|
|
|
use Piwik\Filesystem;
|
|
use Piwik\Plugin\ConsoleCommand;
|
|
use Piwik\View;
|
|
|
|
/**
|
|
* Command to generate an self-updating github action yml file either for Matomo Core or
|
|
* an individual Matomo plugin.
|
|
*/
|
|
class GenerateGitHubTestActionFile extends ConsoleCommand
|
|
{
|
|
public const COMMAND_NAME = 'generate:test-action';
|
|
public const LATEST_PHP_VERSION = '8.1';
|
|
|
|
protected $plugin = null;
|
|
protected $phpVersions = null;
|
|
protected $dependentPlugins = null;
|
|
protected $repoRootDirOverride = null;
|
|
protected $forcePHPTests = false;
|
|
protected $forceUITests = false;
|
|
protected $forceClientTests = false;
|
|
protected $protectArtifacts = false;
|
|
protected $enableRedis = true;
|
|
protected $setupScript = null;
|
|
protected $hasSubmodules = null;
|
|
protected $scheduleCron = null;
|
|
|
|
protected function configure()
|
|
{
|
|
$this->setName(self::COMMAND_NAME)
|
|
->setDescription('Generates a github action workflow file for a plugin. The file can be auto-updating based on the parameters supplied.')
|
|
->addRequiredValueOption('plugin', null, 'The plugin for whom a action yml file should be generated. If not provided yml file for core will be generated.')
|
|
->addOptionalValueOption('php-versions', null, "List of PHP versions to test against, ie, 7.2,8.1.")
|
|
->addOptionalValueOption('dependent-plugins', null, 'List of additional plugins that need to be checked out before running tests. Comma separated list. e.g. "matomo-org/plugin-CustomVariables,nickname/PluginName"')
|
|
->addRequiredValueOption('repo-root-dir', null, "Path to the repo for whom a action yml file will be generated for.")
|
|
->addNoValueOption('force-php-tests', null, "Forces the presence of the PHP tests jobs for plugin builds.")
|
|
->addNoValueOption('force-ui-tests', null, "Forces the presence of the UI tests jobs for plugin builds.")
|
|
->addNoValueOption('force-client-tests', null, "Forces the presence of the Client tests jobs for plugin builds.")
|
|
->addNoValueOption('protect-artifacts', null, "Indicates if artifacts should be stored protected on artifact server.")
|
|
->addOptionalValueOption('setup-script', null, "Shell script to run (after setup, before tests), relative to plugins directory. .i.e .github/scripts/setup.sh")
|
|
->addNoValueOption('has-submodules', null, "Defines if the repo has submodules that need to be checked out.")
|
|
->addNoValueOption('enable-redis', null, "Defines if a redis service should be set up for PHP and UI testing.")
|
|
->addOptionalValueOption('schedule-cron', null, "Value to schedule a cron. eg \"0 2 * * 6\" will run the job at 02:00 on Saturday.");
|
|
}
|
|
|
|
protected function doExecute(): int
|
|
{
|
|
$input = $this->getInput();
|
|
$output = $this->getOutput();
|
|
global $piwik_minimumPHPVersion;
|
|
|
|
$this->plugin = $input->getOption('plugin');
|
|
$this->phpVersions = array_filter(explode(',', $input->getOption('php-versions') ?? ''));
|
|
$this->dependentPlugins = array_filter(explode(',', $input->getOption('dependent-plugins') ?? ''));
|
|
$this->repoRootDirOverride = $input->getOption('repo-root-dir');
|
|
$this->forcePHPTests = !!$input->getOption('force-php-tests');
|
|
$this->forceUITests = !!$input->getOption('force-ui-tests');
|
|
$this->forceClientTests = !!$input->getOption('force-client-tests');
|
|
$this->enableRedis = !!$input->getOption('enable-redis') || empty($this->plugin);
|
|
$this->protectArtifacts = !!$input->getOption('protect-artifacts');
|
|
$this->setupScript = $input->getOption('setup-script');
|
|
$this->hasSubmodules = $input->getOption('setup-script');
|
|
$this->scheduleCron = $input->getOption('schedule-cron');
|
|
|
|
if (!empty($this->plugin)) {
|
|
if (!file_exists($this->getRepoRootDir())) {
|
|
$output->writeln('Plugin directory could not be found. Please check the plugins name or provide --repo-root-dir option');
|
|
return 1;
|
|
}
|
|
|
|
$minimalPHPVersion = $this->getPluginMinimumPhpVersion($output);
|
|
}
|
|
|
|
if (empty($minimalPHPVersion)) {
|
|
$minimalPHPVersion = $piwik_minimumPHPVersion;
|
|
}
|
|
|
|
// remove patch version
|
|
if (substr_count($minimalPHPVersion, '.') > 1) {
|
|
$minimalPHPVersion = substr($minimalPHPVersion, 0, strpos($minimalPHPVersion, '.', strpos($minimalPHPVersion, '.') + 1));
|
|
}
|
|
|
|
if (empty($this->phpVersions)) {
|
|
$this->phpVersions = array_unique([$minimalPHPVersion, self::LATEST_PHP_VERSION]);
|
|
} else {
|
|
$filteredVersions = [];
|
|
foreach ($this->phpVersions as $version) {
|
|
if (version_compare($version, $minimalPHPVersion, '>=')) {
|
|
$filteredVersions[] = $version;
|
|
}
|
|
}
|
|
if (empty($filteredVersions[0])) {
|
|
array_unshift($filteredVersions, $minimalPHPVersion);
|
|
}
|
|
$this->phpVersions = $filteredVersions;
|
|
}
|
|
|
|
if (empty($this->phpVersions)) {
|
|
$output->writeln('No php versions detectable to test against');
|
|
return 1;
|
|
}
|
|
|
|
$template = new View('@TestRunner/matomo-tests.yml.twig');
|
|
|
|
$template->assign('phpVersions', $this->phpVersions);
|
|
$template->assign('enableRedis', $this->enableRedis);
|
|
$template->assign('dependentPlugins', $this->dependentPlugins);
|
|
$template->assign('plugin', $this->plugin);
|
|
$template->assign('protectArtifacts', $this->protectArtifacts);
|
|
$template->assign('setupScript', $this->setupScript);
|
|
$template->assign('hasSubmodules', $this->hasSubmodules);
|
|
$template->assign('hasJavaScriptTests', $this->isTargetPluginContainsJavaScriptTests());
|
|
$template->assign('hasClientTests', $this->isTargetPluginContainsClientTests());
|
|
$template->assign('hasUITests', $this->isTargetPluginContainsUITests());
|
|
$template->assign('hasPluginTests', $this->isTargetPluginContainsPluginTests());
|
|
$template->assign('scheduleCron', $this->scheduleCron);
|
|
|
|
$basePath = empty($this->plugin) ? $this->getPiwikRootDir() : $this->getRepoRootDir();
|
|
$filePath = $basePath . '/.github/workflows/matomo-tests.yml';
|
|
|
|
Filesystem::mkdir(dirname($filePath));
|
|
|
|
if (!file_put_contents($filePath, $template->render())) {
|
|
$output->writeln("$filePath can not be written");
|
|
return 1;
|
|
}
|
|
|
|
$output->writeln('Action file written to ' . $filePath);
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function getPluginMinimumPhpVersion($output)
|
|
{
|
|
$pluginJsonPath = $this->getPluginJsonRootDir();
|
|
if (empty($pluginJsonPath) || !file_exists($pluginJsonPath)) {
|
|
$output->writeln("No plugin.json file found, cannot detect minimum PHP version.");
|
|
return null;
|
|
}
|
|
|
|
$pluginJsonContents = file_get_contents($pluginJsonPath);
|
|
$pluginJsonContents = json_decode($pluginJsonContents, $assoc = true);
|
|
if (empty($pluginJsonContents['require']['php'])) {
|
|
$output->writeln("No PHP version requirement in plugin.json");
|
|
return null;
|
|
}
|
|
|
|
$phpRequirement = $pluginJsonContents['require']['php'];
|
|
if (!preg_match('/>=([0-9]+\.[0-9]+\.[0-9]+)/', $phpRequirement, $matches)) {
|
|
$output->writeln("Cannot detect minimum php version from php requirement: '$phpRequirement'");
|
|
return null;
|
|
}
|
|
|
|
$phpRequirement = $matches[1];
|
|
|
|
$output->writeln("Detected minimum PHP version: '$phpRequirement'");
|
|
|
|
return $phpRequirement;
|
|
}
|
|
|
|
private function getPluginJsonRootDir()
|
|
{
|
|
return $this->getRepoRootDir() . '/plugin.json';
|
|
}
|
|
|
|
private function isTargetPluginContainsPluginTests()
|
|
{
|
|
if ($this->forcePHPTests) {
|
|
return true;
|
|
}
|
|
|
|
$pluginPath = $this->getRepoRootDir();
|
|
return $this->doesFolderContainPluginTests($pluginPath . "/tests")
|
|
|| $this->doesFolderContainPluginTests($pluginPath . "/Test");
|
|
}
|
|
|
|
private function doesFolderContainPluginTests($folderPath)
|
|
{
|
|
return $this->folderContains($folderPath, '/.*Test\.php/');
|
|
}
|
|
|
|
private function isTargetPluginContainsUITests()
|
|
{
|
|
if ($this->forceUITests) {
|
|
return true;
|
|
}
|
|
|
|
$pluginPath = $this->getRepoRootDir();
|
|
return $this->doesFolderContainUITests($pluginPath . "/tests")
|
|
|| $this->doesFolderContainUITests($pluginPath . "/Test");
|
|
}
|
|
|
|
private function isTargetPluginContainsClientTests()
|
|
{
|
|
if ($this->forceClientTests) {
|
|
return true;
|
|
}
|
|
|
|
$pluginPath = $this->getRepoRootDir();
|
|
return $this->doesFolderContainClientTests($pluginPath);
|
|
}
|
|
|
|
private function isTargetPluginContainsJavaScriptTests()
|
|
{
|
|
$pluginPath = $this->getRepoRootDir();
|
|
return file_exists($pluginPath . "/tests/javascript/index.php")
|
|
|| file_exists($pluginPath . "/Test/javascript/index.php");
|
|
}
|
|
|
|
private function doesFolderContainClientTests($folderPath)
|
|
{
|
|
return $this->folderContains($folderPath, '/.*\.spec\.js/')
|
|
|| $this->folderContains($folderPath, '/.*\.spec\.ts/');
|
|
}
|
|
|
|
private function doesFolderContainUITests($folderPath)
|
|
{
|
|
return $this->folderContains($folderPath, '/.*_spec\.js/');
|
|
}
|
|
|
|
private function folderContains($folderPath, $filePattern)
|
|
{
|
|
if (!is_dir($folderPath)) {
|
|
return false;
|
|
}
|
|
|
|
$directoryIterator = new \RecursiveDirectoryIterator($folderPath);
|
|
$flatIterator = new \RecursiveIteratorIterator($directoryIterator);
|
|
$fileIterator = new \RegexIterator($flatIterator, $filePattern, \RegexIterator::GET_MATCH);
|
|
$fileIterator->rewind();
|
|
|
|
return $fileIterator->valid();
|
|
}
|
|
|
|
protected function getRepoRootDir()
|
|
{
|
|
return $this->repoRootDirOverride ?: ($this->getPiwikRootDir() . "/plugins/{$this->plugin}");
|
|
}
|
|
|
|
protected function getPiwikRootDir()
|
|
{
|
|
return __DIR__ . "/../../..";
|
|
}
|
|
}
|