diff --git a/README.md b/README.md index cdcaf7ac..ab13ff88 100644 --- a/README.md +++ b/README.md @@ -111,8 +111,8 @@ The "job" element will have the following elements, but is not restricted to the ], "dependencies": "(optional) dependencies to test against; one of lowest, locked, latest. default: locked", "command": "(required) command to run to perform the check", - "ignore_platform_reqs_8": "(optional; deprecated) boolean; whether to add `--ignore-platform-req=php` to composer for PHP 8.0. default: true", - "ignore_php_platform_requirement": "(optional) boolean; whether to add `--ignore-platform-req=php` to composer for this job.", + "ignore_platform_reqs_8": "(optional; deprecated) boolean; whether to add `--ignore-platform-req=php` to Composer for PHP 8.0. default: true", + "ignore_php_platform_requirement": "(optional) boolean; whether to add `--ignore-platform-req=php` to Composer for this job.", "additional_composer_arguments": [ "(optional) list of arguments to be passed to `composer install` and `composer update`" ] @@ -200,18 +200,45 @@ The tool discovers checks first, then appends any `additional_checks` are concat ### Excluding specific jobs -The easiest way to exclude a single job is via the `name` parameter: +You can exclude specific jobs by using their names: ```json { "exclude": [ { - "name": "PHPUnit on PHP 8.0 with latest dependencies" + "name": "PHPUnit" } ] } ``` +If you want to limit the exclusion to specific PHP versions, you can additionally add a PHP version: + +```json +{ + "exclude": [ + { + "name": "PHPUnit", + "php": "8.0" + } + ] +} +``` + +In case you only want to exclude jobs for specific Composer dependency sets, add `dependencies` to the `exclude` configuration: + +```json +{ + "exclude": [ + { + "name": "PHPUnit", + "php": "8.0", + "dependencies": "latest" + } + ] +} +``` + ## Testing matrix generation locally using Docker To test matrix generation in a local checkout on your own machine, you can do the following: diff --git a/laminas-ci.schema.json b/laminas-ci.schema.json index 823f4804..ae18f86d 100644 --- a/laminas-ci.schema.json +++ b/laminas-ci.schema.json @@ -25,6 +25,11 @@ "exclude": [ { "name": "Codeception [7.4, latest]" + }, + { + "name": "Codeception", + "php": "7.4", + "dependencies": "latest" } ], "ignore_php_platform_requirements": { @@ -243,6 +248,39 @@ } ], "definitions": { + "installablePhpVersion": { + "type": "string", + "title": "Installable PHP versions from available from within the container.", + "enum": [ + "5.6", + "7.0", + "7.1", + "7.2", + "7.3", + "7.4", + "8.0", + "8.1", + "8.2", + "8.3", + "@default" + ] + }, + "php": { + "title": "The PHP version", + "type": "string", + "anyOf": [ + { + "$ref": "#/definitions/installablePhpVersion" + }, + { + "enum": [ + "*", + "@latest", + "@lowest" + ] + } + ] + }, "extensions": { "type": "array", "title": "A list of PHP extensions", @@ -285,6 +323,11 @@ [ { "name": "Codeception [7.4, latest]" + }, + { + "name": "Codeception", + "php": "7.4", + "dependencies": "latest" } ] ], @@ -294,6 +337,11 @@ "examples": [ { "name": "Codeception [7.4, latest]" + }, + { + "name": "Codeception", + "php": "7.4", + "dependencies": "latest" } ], "required": [ @@ -306,8 +354,21 @@ "description": "The name of the job to be excluded. Must be an exact match.", "minLength": 1, "examples": [ - "Codeception [7.4, latest]" + "Codeception [7.4, latest]", + "Codeception" ] + }, + "php": { + "ref": "#/definitions/php", + "description": "The PHP version to to be excluded.", + "default": "*" + }, + "dependencies": { + "type": "string", + "enum": ["latest", "lowest", "locked", "*"], + "title": "The composer dependencies to be excluded", + "description": "The composer dependencies to be excluded. If the wildcard `*` is passed, all dependencies are being excluded", + "default": "*" } }, "additionalProperties": false @@ -331,13 +392,10 @@ } }, "stablePHP": { - "type": "string", - "minLength": 1, + "$ref": "#/definitions/installablePhpVersion", "title": "The PHP version to be used for stable checks", "description": "This PHP version is used for all QA check jobs. The default depends on the `composer.json` of the project and usually reflects the minimum supported PHP version of that project.", - "examples": [ - "8.0" - ] + "default": "8.0" }, "backwardCompatibilityCheck": { "type": "boolean", @@ -361,24 +419,9 @@ ], "properties": { "php": { - "type": "string", - "title": "The php version", + "$ref": "#/definitions/php", "description": "The PHP version to be used. If the wildcard `*` is passed, a list of checks is created containing *every* supported PHP version by the project and the matrix action.", - "enum": [ - "5.6", - "7.0", - "7.1", - "7.2", - "7.3", - "7.4", - "8.0", - "8.1", - "8.2", - "8.3", - "*", - "@latest", - "@lowest" - ] + "default": "*" }, "dependencies": { "type": "string", diff --git a/src/config/app.ts b/src/config/app.ts index 8cc7cdf0..12005b8d 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -3,9 +3,28 @@ import semver from 'semver'; import parseJsonFile from '../json'; import {isToolRunningContainerDefaultPhpVersion, Tool, ToolExecutionType} from '../tools'; import {Logger} from '../logging'; -import {CURRENT_STABLE, INSTALLABLE_VERSIONS, InstallablePhpVersionType, isInstallableVersion} from './php'; +import { + CONTAINER_DEFAULT_PHP_VERSION, + CURRENT_STABLE, + INSTALLABLE_VERSIONS, + InstallablePhpVersionType, + isInstallableVersion +} from './php'; import {ComposerJson} from './composer'; -import {ConfigurationFromFile, isAdditionalChecksConfiguration, isAnyComposerDependencySet, isAnyPhpVersionType, isConfigurationContainingJobExclusions, isExplicitChecksConfiguration, isLatestPhpVersionType, isLowestPhpVersionType, JobDefinitionFromFile, JobFromFile, JobToExcludeFromFile} from './input'; +import { + ConfigurationFromFile, + isAdditionalChecksConfiguration, + isAnyComposerDependencySet, + isAnyPhpVersionType, + isConfigurationContainingJobExclusions, + isExplicitChecksConfiguration, + isLatestPhpVersionType, + isLowestPhpVersionType, + JobDefinitionFromFile, + JobFromFile, + JobToExcludeFromFile, + WILDCARD_ALIAS +} from './input'; export const OPERATING_SYSTEM = 'ubuntu-latest'; export const ACTION = 'laminas/laminas-continuous-integration-action@v1'; @@ -242,12 +261,74 @@ function isJobExcludedByDeprecatedCommandName(job: Job, exclusions: JobToExclude ); } +function isJobExcludedByName(job: Job, exclude: JobToExcludeFromFile): boolean { + if (job.name === exclude.name) { + return true; + } + + if (isJobFromTool(job)) { + return job.tool.name === exclude.name; + } + + return false; +} + +function isJobExcludedByConfiguration( + job: Job, + exclude: JobToExcludeFromFile, + config: Config, + logger: Logger +): boolean { + if (!isJobExcludedByName(job, exclude)) { + return false; + } + + const jobName = isJobFromTool(job) ? job.tool.name : job.name; + + const phpVersionToExclude = exclude.php ?? WILDCARD_ALIAS; + const dependenciesToExclude = exclude.dependencies ?? WILDCARD_ALIAS; + + if (!isAnyPhpVersionType(phpVersionToExclude)) { + const nonExcludedPhpVersionDebugMessage = `Job with name ${ jobName } is not matching exclusion rule` + + ` with name ${ exclude.name } due to non-excluded php version.`; + + if (isLowestPhpVersionType(phpVersionToExclude) && job.job.php !== config.minimumPhpVersion) { + logger.debug(nonExcludedPhpVersionDebugMessage); + + return false; + } + + if (isLatestPhpVersionType(phpVersionToExclude) && job.job.php !== config.latestPhpVersion) { + logger.debug(nonExcludedPhpVersionDebugMessage); + + return false; + } + + if (phpVersionToExclude !== job.job.php) { + logger.debug(nonExcludedPhpVersionDebugMessage); + + return false; + } + } + + if (!isAnyComposerDependencySet(dependenciesToExclude) && dependenciesToExclude !== job.job.composerDependencySet) { + logger.debug( + `Job with name ${ jobName } is not matching exclusion rule` + + ` with name ${ exclude.name } due to non-excluded Composer dependencies.` + ); + + return false; + } + + return true; +} + function isJobExcluded(job: Job, exclusions: JobToExcludeFromFile[], config: Config, logger: Logger): boolean { if (exclusions.length === 0) { return false; } - if (exclusions.some((exclude) => job.name === exclude.name)) { + if (exclusions.some((exclude) => isJobExcludedByConfiguration(job, exclude, config, logger))) { logger.info(`Job with name ${ job.name } is excluded due to application config.`); return true; @@ -385,7 +466,7 @@ function createNoOpCheck(config: Config): Job { operatingSystem : OPERATING_SYSTEM, action : ACTION, job : { - php : config.stablePhpVersion, + php : CONTAINER_DEFAULT_PHP_VERSION, phpExtensions : [], command : '', composerDependencySet : ComposerDependencySet.LOCKED, diff --git a/src/config/input.ts b/src/config/input.ts index b4f5e9b0..02958cc7 100644 --- a/src/config/input.ts +++ b/src/config/input.ts @@ -3,13 +3,15 @@ import {ComposerDependencySet, IgnorePhpPlatformRequirements} from './app'; export interface JobToExcludeFromFile { name: string; + php?: InstallablePhpVersionType, + dependencies?: ComposerDependencySet, } export interface ConfigurationFromFile { extensions?: string[]; ini?: string[]; ignore_php_platform_requirements?: IgnorePhpPlatformRequirements; - stablePHP?: string; + stablePHP?: InstallablePhpVersionType; additional_composer_arguments?: string[]; backwardCompatibilityCheck?: boolean; } diff --git a/tests/configuration-exclude-php-dependency-combination/.laminas-ci.json b/tests/configuration-exclude-php-dependency-combination/.laminas-ci.json new file mode 100644 index 00000000..808b7d40 --- /dev/null +++ b/tests/configuration-exclude-php-dependency-combination/.laminas-ci.json @@ -0,0 +1,9 @@ +{ + "exclude": [ + { + "name": "PHPUnit", + "php": "8.1", + "dependencies": "latest" + } + ] +} diff --git a/tests/configuration-exclude-php-dependency-combination/composer.json b/tests/configuration-exclude-php-dependency-combination/composer.json new file mode 100644 index 00000000..31a4819d --- /dev/null +++ b/tests/configuration-exclude-php-dependency-combination/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "~8.0.0 || ~8.1.0 || ~8.2.0" + } +} diff --git a/tests/configuration-exclude-php-dependency-combination/matrix.json b/tests/configuration-exclude-php-dependency-combination/matrix.json new file mode 100644 index 00000000..03c77801 --- /dev/null +++ b/tests/configuration-exclude-php-dependency-combination/matrix.json @@ -0,0 +1,34 @@ +{ + "include": [ + { + "name": "PHPUnit [8.0, lowest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.0\",\"extensions\":[],\"ini\":[],\"dependencies\":\"lowest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.0, latest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.0\",\"extensions\":[],\"ini\":[],\"dependencies\":\"latest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.1, lowest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.1\",\"extensions\":[],\"ini\":[],\"dependencies\":\"lowest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.2, lowest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.2\",\"extensions\":[],\"ini\":[],\"dependencies\":\"lowest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.2, latest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.2\",\"extensions\":[],\"ini\":[],\"dependencies\":\"latest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + } + ] +} diff --git a/tests/configuration-exclude-php-dependency-combination/phpunit.xml.dist b/tests/configuration-exclude-php-dependency-combination/phpunit.xml.dist new file mode 100644 index 00000000..0e632ce3 --- /dev/null +++ b/tests/configuration-exclude-php-dependency-combination/phpunit.xml.dist @@ -0,0 +1,2 @@ + + diff --git a/tests/configuration-exclude-php-dependency-combination/test.env b/tests/configuration-exclude-php-dependency-combination/test.env new file mode 100644 index 00000000..e69de29b diff --git a/tests/configuration-exclude-php-specific-version/.laminas-ci.json b/tests/configuration-exclude-php-specific-version/.laminas-ci.json new file mode 100644 index 00000000..9c05507c --- /dev/null +++ b/tests/configuration-exclude-php-specific-version/.laminas-ci.json @@ -0,0 +1,8 @@ +{ + "exclude": [ + { + "name": "PHPUnit", + "php": "8.1" + } + ] +} diff --git a/tests/configuration-exclude-php-specific-version/composer.json b/tests/configuration-exclude-php-specific-version/composer.json new file mode 100644 index 00000000..31a4819d --- /dev/null +++ b/tests/configuration-exclude-php-specific-version/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "~8.0.0 || ~8.1.0 || ~8.2.0" + } +} diff --git a/tests/configuration-exclude-php-specific-version/matrix.json b/tests/configuration-exclude-php-specific-version/matrix.json new file mode 100644 index 00000000..2cc70bf9 --- /dev/null +++ b/tests/configuration-exclude-php-specific-version/matrix.json @@ -0,0 +1,28 @@ +{ + "include": [ + { + "name": "PHPUnit [8.0, lowest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.0\",\"extensions\":[],\"ini\":[],\"dependencies\":\"lowest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.0, latest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.0\",\"extensions\":[],\"ini\":[],\"dependencies\":\"latest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.2, lowest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.2\",\"extensions\":[],\"ini\":[],\"dependencies\":\"lowest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + }, + { + "name": "PHPUnit [8.2, latest]", + "job": "{\"command\":\"./vendor/bin/phpunit\",\"php\":\"8.2\",\"extensions\":[],\"ini\":[],\"dependencies\":\"latest\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[\"xmllint --schema vendor/phpunit/phpunit/phpunit.xsd phpunit.xml.dist\"]}", + "operatingSystem": "ubuntu-latest", + "action": "laminas/laminas-continuous-integration-action@v1" + } + ] +} diff --git a/tests/configuration-exclude-php-specific-version/phpunit.xml.dist b/tests/configuration-exclude-php-specific-version/phpunit.xml.dist new file mode 100644 index 00000000..0e632ce3 --- /dev/null +++ b/tests/configuration-exclude-php-specific-version/phpunit.xml.dist @@ -0,0 +1,2 @@ + + diff --git a/tests/configuration-exclude-php-specific-version/test.env b/tests/configuration-exclude-php-specific-version/test.env new file mode 100644 index 00000000..e69de29b diff --git a/tests/no-checks-due-to-diff/matrix.json b/tests/no-checks-due-to-diff/matrix.json index c056da11..b056b800 100644 --- a/tests/no-checks-due-to-diff/matrix.json +++ b/tests/no-checks-due-to-diff/matrix.json @@ -2,7 +2,7 @@ "include": [ { "name": "No checks", - "job": "{\"command\":\"\",\"php\":\"7.4\",\"extensions\":[],\"ini\":[],\"dependencies\":\"locked\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[]}", + "job": "{\"command\":\"\",\"php\":\"@default\",\"extensions\":[],\"ini\":[],\"dependencies\":\"locked\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[]}", "operatingSystem": "ubuntu-latest", "action": "laminas/laminas-continuous-integration-action@v1" } diff --git a/tests/no-checks/matrix.json b/tests/no-checks/matrix.json index c056da11..b056b800 100644 --- a/tests/no-checks/matrix.json +++ b/tests/no-checks/matrix.json @@ -2,7 +2,7 @@ "include": [ { "name": "No checks", - "job": "{\"command\":\"\",\"php\":\"7.4\",\"extensions\":[],\"ini\":[],\"dependencies\":\"locked\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[]}", + "job": "{\"command\":\"\",\"php\":\"@default\",\"extensions\":[],\"ini\":[],\"dependencies\":\"locked\",\"ignore_platform_reqs_8\":false,\"ignore_php_platform_requirement\":false,\"additional_composer_arguments\":[],\"before_script\":[]}", "operatingSystem": "ubuntu-latest", "action": "laminas/laminas-continuous-integration-action@v1" }