diff --git a/job_creator.php b/job_creator.php index 08f032c..7d8c598 100644 --- a/job_creator.php +++ b/job_creator.php @@ -150,6 +150,7 @@ public function createJob(int $phpIndex, array $opts): array 'endtoend' => false, 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => false, 'doclinting' => false, 'install_in_memory_cache_exts' => false, @@ -386,6 +387,28 @@ private function doRunPhpCoverage(array $run): bool return $run['phpcoverage']; } + /** + * Recursively finds all nested files matching an extension in a directory + */ + private function getFilesMatchingExtension($dir, $extension, &$filepaths = []): array + { + $files = scandir($dir); + foreach ($files as $file) { + if (in_array($file, ['.', '..'])) { + continue; + } + if (is_dir("$dir/$file")) { + $this->getFilesMatchingExtension("$dir/$file", $extension, $filepaths); + } else { + $ext = pathinfo($file, PATHINFO_EXTENSION); + if ($ext === $extension) { + $filepaths[] = "$dir/$file"; + } + } + } + return $filepaths; + } + private function buildDynamicMatrix( array $matrix, array $run, @@ -436,27 +459,49 @@ private function buildDynamicMatrix( } // endtoend / behat if ($run['endtoend'] && file_exists('behat.yml')) { - $graphql3 = !$simpleMatrix && $cmsMajor == '4'; - $job = $this->createJob(0, [ - 'endtoend' => true, - 'endtoend_suite' => 'root', - 'composer_require_extra' => $graphql3 ? 'silverstripe/graphql:^3' : '' - ]); - // use minimum version of 7.4 for endtoend because was having apt dependency issues - // in CI when using php 7.3: - // The following packages have unmet dependencies: - // libpcre2-dev : Depends: libpcre2-8-0 (= 10.39-3+ubuntu20.04.1+deb.sury.org+2) but - // 10.40-1+ubuntu20.04.1+deb.sury.org+1 is to be installed - if ($job['php'] == '7.3') { - $job['php'] = '7.4'; - } - $matrix['include'][] = $job; - if (!$simpleMatrix && !$composerInstall) { - $matrix['include'][] = $this->createJob(3, [ - 'db' => DB_MYSQL_80, + $jobTags = []; + $filepaths = $this->getFilesMatchingExtension(getcwd(), 'feature'); + foreach ($filepaths as $filepath) { + $contents = file_get_contents($filepath); + if (preg_match('#@(job[0-9]+)#', $contents, $matches)) { + $jobTags[] = $matches[1]; + } + } + $jobTagsCount = count($jobTags); + $jobTags = array_unique($jobTags); + if ($jobTagsCount === 0) { + $jobTags = ['']; + } else { + if ($jobTagsCount !== count($filepaths)) { + throw new RuntimeException('At least one .feature files missing a @job[0-9]+ tag'); + } + } + sort($jobTags); + foreach ($jobTags as $jobTag) { + $graphql3 = !$simpleMatrix && $cmsMajor == '4'; + $job = $this->createJob(0, [ 'endtoend' => true, - 'endtoend_suite' => 'root' + 'endtoend_suite' => 'root', + 'endtoend_tags' => $jobTag, + 'composer_require_extra' => $graphql3 ? 'silverstripe/graphql:^3' : '', ]); + // use minimum version of 7.4 for endtoend because was having apt dependency issues + // in CI when using php 7.3: + // The following packages have unmet dependencies: + // libpcre2-dev : Depends: libpcre2-8-0 (= 10.39-3+ubuntu20.04.1+deb.sury.org+2) but + // 10.40-1+ubuntu20.04.1+deb.sury.org+1 is to be installed + if ($job['php'] == '7.3') { + $job['php'] = '7.4'; + } + $matrix['include'][] = $job; + if (!$simpleMatrix && !$composerInstall) { + $matrix['include'][] = $this->createJob(3, [ + 'db' => DB_MYSQL_80, + 'endtoend' => true, + 'endtoend_suite' => 'root', + 'endtoend_tags' => $jobTag, + ]); + } } } // javascript tests @@ -624,6 +669,9 @@ public function createJson(string $yml): string if ($job['endtoend'] == 'true') { $name[] = 'endtoend'; $name[] = $job['endtoend_suite'] ?: 'root'; + if ($job['endtoend_tags']) { + $name[] = $job['endtoend_tags']; + } } if ($job['js'] == 'true') { $name[] = 'js'; diff --git a/tests/JobCreatorTest.php b/tests/JobCreatorTest.php index 844e054..07d3f19 100644 --- a/tests/JobCreatorTest.php +++ b/tests/JobCreatorTest.php @@ -45,6 +45,7 @@ public function provideCreateJob(): array 'endtoend' => false, 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => false, 'doclinting' => false, 'needs_full_setup' => false, @@ -205,16 +206,51 @@ public function provideGetInstallerVersion(): array /** * @dataProvider provideCreateJson */ - public function testCreateJson(string $yml, array $expected) - { + public function testCreateJson( + string $yml, + bool $behatFile, + bool $featureFiles, + bool $featureFileMissingTag, + array $expected + ) { if (!function_exists('yaml_parse')) { $this->markTestSkipped('yaml extension is not installed'); } - $creator = new JobCreator(); - $json = json_decode($creator->createJson($yml)); - for ($i = 0; $i < count($expected); $i++) { - foreach ($expected[$i] as $key => $expectedVal) { - $this->assertSame($expectedVal, $json->include[$i]->$key); + try { + if ($behatFile) { + file_put_contents('behat.yml', ''); + } + if ($featureFiles && !file_exists('_test_features')) { + mkdir('_test_features'); + file_put_contents('_test_features/feature1.feature', '@job1'); + file_put_contents('_test_features/feature2.feature', '@job2'); + if ($featureFileMissingTag) { + file_put_contents('_test_features/feature2.feature', '@missing'); + } + } + if ($featureFileMissingTag) { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('At least one .feature files missing a @job[0-9]+ tag'); + } + $creator = new JobCreator(); + $json = json_decode($creator->createJson($yml)); + $this->assertSame(count($expected), count($json->include)); + for ($i = 0; $i < count($expected); $i++) { + foreach ($expected[$i] as $key => $expectedVal) { + $this->assertSame($expectedVal, $json->include[$i]->$key, "\$i is $i, \$key is $key"); + } + } + } finally { + if (file_exists('behat.yml')) { + unlink('behat.yml'); + } + if (file_exists('_test_features')) { + foreach (scandir('_test_features') as $file) { + if ($file !== '.' && $file !== '..') { + unlink('_test_features/' . $file); + } + } + rmdir('_test_features'); } } } @@ -222,6 +258,293 @@ public function testCreateJson(string $yml, array $expected) public function provideCreateJson(): array { return [ + // behat without @job1/@job2 test + [ + implode("\n", [ + $this->getGenericYml(), + << '5.x-dev', + 'php' => '8.1', + 'db' => DB_MYSQL_57, + 'composer_require_extra' => '', + 'composer_args' => '--prefer-lowest', + 'name_suffix' => '', + 'phpunit' => 'true', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'false', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.1 prf-low mysql57 phpunit all', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.2', + 'db' => DB_MARIADB, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'true', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'false', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.2 mariadb phpunit all', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.3', + 'db' => DB_MYSQL_80, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'true', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'false', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.3 mysql80 phpunit all', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.1', + 'db' => DB_MYSQL_57, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'false', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'true', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.1 mysql57 endtoend root', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.3', + 'db' => DB_MYSQL_80, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'false', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'true', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.3 mysql80 endtoend root', + ], + ] + ], + // behat with @job1/@job2 test + [ + implode("\n", [ + $this->getGenericYml(), + << '5.x-dev', + 'php' => '8.1', + 'db' => DB_MYSQL_57, + 'composer_require_extra' => '', + 'composer_args' => '--prefer-lowest', + 'name_suffix' => '', + 'phpunit' => 'true', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'false', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.1 prf-low mysql57 phpunit all', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.2', + 'db' => DB_MARIADB, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'true', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'false', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.2 mariadb phpunit all', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.3', + 'db' => DB_MYSQL_80, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'true', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'false', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => '', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.3 mysql80 phpunit all', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.1', + 'db' => DB_MYSQL_57, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'false', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'true', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => 'job1', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.1 mysql57 endtoend root job1', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.3', + 'db' => DB_MYSQL_80, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'false', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'true', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => 'job1', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.3 mysql80 endtoend root job1', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.1', + 'db' => DB_MYSQL_57, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'false', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'true', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => 'job2', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.1 mysql57 endtoend root job2', + ], + [ + 'installer_version' => '5.x-dev', + 'php' => '8.3', + 'db' => DB_MYSQL_80, + 'composer_require_extra' => '', + 'composer_args' => '', + 'name_suffix' => '', + 'phpunit' => 'false', + 'phpunit_suite' => 'all', + 'phplinting' => 'false', + 'phpcoverage' => 'false', + 'endtoend' => 'true', + 'endtoend_suite' => 'root', + 'endtoend_config' => '', + 'endtoend_tags' => 'job2', + 'js' => 'false', + 'doclinting' => 'false', + 'needs_full_setup' => 'true', + 'name' => '8.3 mysql80 endtoend root job2', + ], + ] + ], + // behat with @job1/@job2 test with missing @job tag + [ + implode("\n", [ + $this->getGenericYml(), + << '4.11.x-dev', @@ -248,6 +574,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -268,6 +595,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -288,6 +616,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -305,6 +634,9 @@ public function provideCreateJson(): array parent_branch: '' EOT ]), + false, + false, + false, [ [ 'installer_version' => '5.x-dev', @@ -320,6 +652,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -339,6 +672,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -358,6 +692,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -375,6 +710,9 @@ public function provideCreateJson(): array parent_branch: '' EOT ]), + false, + false, + false, [ [ 'installer_version' => '6.x-dev', @@ -390,6 +728,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -409,6 +748,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -428,6 +768,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -445,6 +786,9 @@ public function provideCreateJson(): array parent_branch: '' EOT ]), + false, + false, + false, [ [ 'installer_version' => '5.1.x-dev', @@ -460,6 +804,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -479,6 +824,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -498,6 +844,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -515,6 +862,9 @@ public function provideCreateJson(): array parent_branch: '' EOT ]), + false, + false, + false, [ [ 'installer_version' => '5.2.x-dev', @@ -530,6 +880,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -549,6 +900,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', @@ -568,6 +920,7 @@ public function provideCreateJson(): array 'endtoend' => 'false', 'endtoend_suite' => 'root', 'endtoend_config' => '', + 'endtoend_tags' => '', 'js' => 'false', 'doclinting' => 'false', 'needs_full_setup' => 'true', diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 6832380..4d4826a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,6 @@