diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..4e47222
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,27 @@
+name: CI
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ ci:
+ name: CI
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: Checkout code
+ uses: actions/checkout@7884fcad6b5d53d10323aee724dc68d8b9096a2e # v2.4.2
+
+ - name: Install PHP
+ uses: shivammathur/setup-php@3eda58347216592f618bb1dff277810b6698e4ca # v2.19.1
+ with:
+ php-version: 8.1
+ extensions: yaml
+
+ - name: Install PHPUnit
+ run: wget https://phar.phpunit.de/phpunit-9.5.phar
+
+ - name: PHPUnit
+ run: php phpunit-9.5.phar --verbose --colors=always
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..165765a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.phpunit.result.cache
diff --git a/action.php b/action.php
index 52ac606..dabbdbb 100644
--- a/action.php
+++ b/action.php
@@ -4,10 +4,6 @@
include 'job_creator.php';
// Reads inputs.yml and creates a new json matrix
-$inputs = yaml_parse(file_get_contents('__inputs.yml'));
-if ($inputs === false) {
- echo 'Unable to parse __inputs.yml';
- exit(1);
-}
+$yml = file_get_contents('__inputs.yml');
$jobCreator = new JobCreator();
-echo $jobCreator->createJson($inputs);
+echo $jobCreator->createJson($yml);
diff --git a/job_creator.php b/job_creator.php
index 53a0264..d7e6e94 100644
--- a/job_creator.php
+++ b/job_creator.php
@@ -13,23 +13,29 @@ public function getInstallerVersion(string $githubRepository, string $branch): s
if (in_array($repo, NO_INSTALLER_REPOS)) {
return '';
}
- // e.g. ['4', '11']
- $portions = explode('.', $branch);
- if (count($portions) == 1) {
- return '4.x-dev';
+ // e.g. pulls/4.10/some-bugfix or pulls/4/some-feature
+ if (preg_match('#^pulls/([0-9\.]+)/#', $branch, $matches)) {
+ $branch = $matches[1];
}
- if (in_array($repo, LOCKSTEPED_REPOS)) {
- return '4.' . $portions[1] . '.x-dev';
- } else {
- // use the latest minor version of installer
- $installerVersions = array_keys(INSTALLER_TO_PHP_VERSIONS);
- // remove '4' version
- $installerVersions = array_diff($installerVersions, ['4']);
- // get the minor portions of the verisons e.g. [9, 10, 11]
- $minorPortions = array_map(fn($portions) => (int) explode('.', $portions)[1], $installerVersions);
- sort($minorPortions);
- return '4.' . $minorPortions[count($minorPortions) - 1] . '.x-dev';
+ // e.g. 4.10-release
+ $branch = preg_replace('#^([0-9\.]+)-release$#', '$1', $branch);
+ if (in_array($repo, LOCKSTEPED_REPOS) && is_numeric($branch)) {
+ // e.g. ['4', '11']
+ $portions = explode('.', $branch);
+ if (count($portions) == 1) {
+ return '4.x-dev';
+ } else {
+ return '4.' . $portions[1] . '.x-dev';
+ }
}
+ // use the latest minor version of installer
+ $installerVersions = array_keys(INSTALLER_TO_PHP_VERSIONS);
+ // remove '4' version
+ $installerVersions = array_diff($installerVersions, ['4']);
+ // get the minor portions of the verisons e.g. [9, 10, 11]
+ $minorPortions = array_map(fn($portions) => (int) explode('.', $portions)[1], $installerVersions);
+ sort($minorPortions);
+ return '4.' . $minorPortions[count($minorPortions) - 1] . '.x-dev';
}
public function createJob(int $phpIndex, array $opts): array
@@ -180,8 +186,28 @@ private function buildDynamicMatrix(
return $matrix;
}
- public function createJson(array $inputs): string
+ public function getInputs(string $yml): array
+ {
+ $message = 'Failed to parse yml';
+ try {
+ $inputs = yaml_parse($yml);
+ } catch (Exception $e) {
+ throw new Exception($message);
+ }
+ if (!$inputs) {
+ throw new Exception($message);
+ }
+ if (array_key_exists('github_my_ref', $inputs)) {
+ if (!preg_match("#github_my_ref: *'#", $yml)) {
+ throw new Exception('github_my_ref needs to be surrounded by single-quotes');
+ }
+ }
+ return $inputs;
+ }
+
+ public function createJson(string $yml): string
{
+ $inputs = $this->getInputs($yml);
// $myRef will either be a branch for push (i.e cron) and pull-request (target branch), or a semver tag
$myRef = $inputs['github_my_ref'];
$isTag = preg_match('#^[0-9]+\.[0-9]+\.[0-9]+$#', $myRef, $m);
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..f5e111b
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ tests
+
+
+
diff --git a/tests/JobCreatorTest.php b/tests/JobCreatorTest.php
new file mode 100644
index 0000000..979db8a
--- /dev/null
+++ b/tests/JobCreatorTest.php
@@ -0,0 +1,149 @@
+getInstallerVersion($githubRepository, $branch);
+ $this->assertSame($expected, $actual);
+ }
+
+ private function getLatestInstallerVersion(): string
+ {
+ $versions = array_keys(INSTALLER_TO_PHP_VERSIONS);
+ natsort($versions);
+ $versions = array_reverse($versions);
+ return $versions[0];
+ }
+
+ public function provideGetInstallerVersion(): array
+ {
+ $latest = $this->getLatestInstallerVersion() . '.x-dev';
+ return [
+ // no-installer repo
+ ['myaccount/recipe-cms', '4', ''],
+ ['myaccount/recipe-cms', '4.10', ''],
+ ['myaccount/recipe-cms', 'burger', ''],
+ ['myaccount/recipe-cms', 'pulls/4/myfeature', ''],
+ ['myaccount/recipe-cms', 'pulls/4.10/myfeature', ''],
+ ['myaccount/recipe-cms', 'pulls/burger/myfeature', ''],
+ ['myaccount/recipe-cms', '4-release', ''],
+ ['myaccount/recipe-cms', '4.10-release', ''],
+ // lockstepped repo with 4.* naming
+ ['myaccount/silverstripe-framework', '4', '4.x-dev'],
+ ['myaccount/silverstripe-framework', '4.10', '4.10.x-dev'],
+ ['myaccount/silverstripe-framework', 'burger', $latest],
+ ['myaccount/silverstripe-framework', 'pulls/4/mybugfix', '4.x-dev'],
+ ['myaccount/silverstripe-framework', 'pulls/4.10/mybugfix', '4.10.x-dev'],
+ ['myaccount/silverstripe-framework', 'pulls/burger/myfeature', $latest],
+ ['myaccount/silverstripe-framework', '4-release', '4.x-dev'],
+ ['myaccount/silverstripe-framework', '4.10-release', '4.10.x-dev'],
+ // lockstepped repo with 1.* naming
+ ['myaccount/silverstripe-admin', '1', '4.x-dev'],
+ ['myaccount/silverstripe-admin', '1.10', '4.10.x-dev'],
+ ['myaccount/silverstripe-admin', 'burger', $latest],
+ ['myaccount/silverstripe-admin', 'pulls/1/mybugfix', '4.x-dev'],
+ ['myaccount/silverstripe-admin', 'pulls/1.10/mybugfix', '4.10.x-dev'],
+ ['myaccount/silverstripe-admin', 'pulls/burger/myfeature', $latest],
+ ['myaccount/silverstripe-admin', '1-release', '4.x-dev'],
+ ['myaccount/silverstripe-admin', '1.10-release', '4.10.x-dev'],
+ // non-lockedstepped repo
+ ['myaccount/silverstripe-tagfield', '2', $latest],
+ ['myaccount/silverstripe-tagfield', '2.9', $latest],
+ ['myaccount/silverstripe-tagfield', 'burger', $latest],
+ ['myaccount/silverstripe-tagfield', 'pulls/2/mybugfix', $latest],
+ ['myaccount/silverstripe-tagfield', 'pulls/2.9/mybugfix', $latest],
+ ['myaccount/silverstripe-tagfield', 'pulls/burger/myfeature', $latest],
+ ['myaccount/silverstripe-tagfield', '2-release', $latest],
+ ['myaccount/silverstripe-tagfield', '2.9-release', $latest],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetInputsValid
+ */
+ public function testGetInputsValid(string $yml, array $expected)
+ {
+ if (!function_exists('yaml_parse')) {
+ $this->markTestSkipped('yaml extension is not installed');
+ }
+ $creator = new JobCreator();
+ $actual = $creator->getInputs($yml);
+ $this->assertSame($expected, $actual);
+ }
+
+ public function provideGetInputsValid(): array
+ {
+ return [
+ [
+ << true,
+ 'js' => true,
+ 'phpcoverage' => false,
+ 'phpcoverage_force_off' => false,
+ 'phplinting' => true,
+ 'phpunit' => true,
+ 'simple_matrix' => false,
+ 'github_repository' => 'myaccount/silverstripe-versioned',
+ 'github_my_ref'=> 'pulls/1.10/module-standards'
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetInputsInvalid
+ */
+ public function testGetInputsInvalid(string $yml, string $expectedMessage)
+ {
+ if (!function_exists('yaml_parse')) {
+ $this->markTestSkipped('yaml extension is not installed');
+ }
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage($expectedMessage);
+ $creator = new JobCreator();
+ $creator->getInputs($yml);
+ }
+
+ public function provideGetInputsInvalid(): array
+ {
+ return [
+ // missing quotes around github_my_ref (would turn into an int, so 1.10 becomes 1.1)
+ [
+ <<