Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 76 additions & 28 deletions src/TaskRunner/Commands/ComponentCheckCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public function componentCheck(ConsoleIO $io, array $options = [
JunitXmlGenerator::addTestCase('Component check', "$label components");
}
$this->{$function}($io);
$io->newLine();
$io->newLine(2);
}

$this->printComponentResults($io);
Expand Down Expand Up @@ -701,39 +701,61 @@ public function componentComposer(ConsoleIO $io)
}
}

// Do not allow setting enable-patching.
if (!empty($composerJson['extra']['enable-patching'])) {
$this->composerFailed = true;
$message = "The composer property 'extra.enable-patching' cannot be set to true.";
$this->writeln($message);
$this->addJunitResult('Composer components', $message);
}

// Enforce setting composer-exit-on-patch-failure if using cweagans/composer-patches version 1.
$exitOnPatchFail = !empty($composerJson['extra']['composer-exit-on-patch-failure']);
$composerPatchesVersion = ToolCommands::getPackagePropertyFromComposer('cweagans/composer-patches', 'version');
if ($composerPatchesVersion && str_starts_with($composerPatchesVersion, '1.') && !$exitOnPatchFail) {
$this->composerFailed = true;
$message = "The composer property 'extra.composer-exit-on-patch-failure' must be set to true.";
$this->writeln($message);
$this->addJunitResult('Composer components', $message);
}
$composerPatchesVersion = ToolCommands::getPackagePropertyFromComposer('cweagans/composer-patches');
// If composer-patches is used validate the patches and settings.
if ($composerPatchesVersion) {
// For composer-patches v1, enforce the correct settings.
if (str_starts_with($composerPatchesVersion, '1.')) {
// Do not allow setting enable-patching.
if (!empty($composerJson['extra']['enable-patching'])) {
$this->composerFailed = true;
$message = "The composer property 'extra.enable-patching' cannot be set to true.";
$this->writeln($message);
$this->addJunitResult('Composer components', $message);
}
// Enforce setting composer-exit-on-patch-failure.
if (empty($composerJson['extra']['composer-exit-on-patch-failure'])) {
$this->composerFailed = true;
$message = "The composer property 'extra.composer-exit-on-patch-failure' must be set to true.";
$this->writeln($message);
$this->addJunitResult('Composer components', $message);
}
}

// Do not allow remote patches. Check if patches from drupal.org are allowed.
if (!empty($composerJson['extra']['patches'])) {
$allowDOrgPatches = !empty($this->getConfig()->get('toolkit.components.composer.drupal_patches'));
foreach ($composerJson['extra']['patches'] as $packagePatches) {
foreach ($packagePatches as $patch) {
$hostname = parse_url($patch, PHP_URL_HOST);
$isDOrg = str_ends_with($hostname ?? '', 'drupal.org');
if ($hostname && (!$allowDOrgPatches || !$isDOrg)) {
$message = "The patch '$patch' is not valid.";
$this->writeln($message);
// For composer-patches v2, check for deprecated settings.
if (str_starts_with($composerPatchesVersion, '2.')) {
$deprecated = ['enable-patching', 'composer-exit-on-patch-failure'];
foreach ($deprecated as $item) {
if (isset($composerJson['extra'][$item])) {
$this->composerFailed = true;
$message = "The composer property 'extra.$item' is deprecated in version 2 of cweagans/composer-patches.";
$this->writeln($message);
$this->addJunitResult('Composer components', $message);
}
}
}

// Do not allow remote patches. Check if patches from drupal.org are allowed.
if (!empty($patches = $this->getPatches())) {
$allowDOrgPatches = !empty($this->getConfig()->get('toolkit.components.composer.drupal_patches'));
foreach ($patches as $packagePatches) {
foreach ($packagePatches as $patch) {
$hostname = parse_url($patch, PHP_URL_HOST);
$isDOrg = str_ends_with($hostname ?? '', 'drupal.org');
if ($hostname && (!$allowDOrgPatches || !$isDOrg)) {
$message = "The patch '$patch' is not valid.";
$this->writeln($message);
$this->composerFailed = true;
$this->addJunitResult('Composer components', $message);
}
}
}
} else {
$message = 'Using package cweagans/composer-patches but no patches were found.';
$this->writeln($message);
$this->composerFailed = true;
$this->addJunitResult('Composer components', $message);
}
}

// Make sure that the forbidden/obsolete entry is not present in the composer.json file.
Expand Down Expand Up @@ -1411,4 +1433,30 @@ private function addJunitResult(string $testCase, string $message, string $type
JunitXmlGenerator::addResult('Component check', $testCase, $message, $type);
}

/**
* Returns the project patches.
*
* @return array<mixed>
* The existing patches in the form of package => patches.
*/
private function getPatches(): array
{
$composerJson = $this->getJson('composer.json');

// Both v1 and v2 of composer-patches allow to define patches under extra.patches.
if (!empty($composerJson['extra']['patches'])) {
return $composerJson['extra']['patches'];
}

// For v2, after running composer install the file patches.lock.json exists.
if (file_exists('patches.lock.json')) {
$patchesFile = $this->getJson('patches.lock.json')['patches'] ?? [];
return array_map(function ($patches) {
return array_column($patches, 'url');
}, $patchesFile);
}

return [];
}

}
72 changes: 61 additions & 11 deletions tests/fixtures/commands/component-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
content: |
{
"name": "ec-europa/toolkit",
"extra": { "composer-exit-on-patch-failure": true },
"extra": {
"composer-exit-on-patch-failure": true,
"patches": { "fake/package": [ "./resources/local.patch" ] }
},
"config": { "allow-plugins": { "ec-europa/toolkit-composer-plugin": true } }
}
expectations:
Expand Down Expand Up @@ -179,7 +182,10 @@
content: |
{
"name": "ec-europa/toolkit",
"extra": { "composer-exit-on-patch-failure": true },
"extra": {
"composer-exit-on-patch-failure": true,
"patches": { "fake/package": [ "./resources/local.patch" ] }
},
"config": { "allow-plugins": { "ec-europa/toolkit-composer-plugin": true } }
}
- from: sample-composer.lock
Expand Down Expand Up @@ -234,10 +240,17 @@
resources:
- file: composer.json
content: |
{ "extra": { "enable-patching": true } }
{ "extra": {
"enable-patching": true,
"patches": { "test/package": [ "./resources/local.patch" ] }
} }
- file: composer.lock
content: |
{ "packages": [ { "name": "test/package", "type": "library", "version": "1.0.0" } ] }
{ "packages": [
{ "name": "test/package", "type": "library", "version": "1.0.0" },
{ "name": "cweagans/composer-patches", "type": "composer-plugin", "version": "1.7.3" }
] }

expectations:
- string_contains: The composer property 'extra.enable-patching' cannot be set to true.
- not_string_contains: Composer validation check passed
Expand All @@ -250,7 +263,11 @@
content: |
{
"name": "ec-europa/toolkit",
"extra": { "enable-patching": false, "composer-exit-on-patch-failure": true },
"extra": {
"enable-patching": false,
"composer-exit-on-patch-failure": true,
"patches": { "fake/package": [ "./resources/local.patch" ] }
},
"config": { "allow-plugins": { "ec-europa/toolkit-composer-plugin": true } }
}
- file: composer.lock
Expand All @@ -268,7 +285,10 @@
- file: composer.json
content: |
{
"extra": { "composer-exit-on-patch-failure": true },
"extra": {
"composer-exit-on-patch-failure": true,
"patches": { "fake/package": [ "./resources/local.patch" ] }
},
"config": { "allow-plugins": { "ec-europa/toolkit-composer-plugin": true } }
}
- file: composer.lock
Expand Down Expand Up @@ -299,7 +319,31 @@
- not_string_contains: composer-exit-on-patch-failure
- string_contains: Composer validation check passed

# test composer-exit-on-patch-failure should only report in version 1.
# test that composer-exit-on-patch-failure is not allowed in version 2.
- command: 'check:composer'
configuration: [ ]
tokens: ''
resources:
- file: composer.json
content: |
{
"extra": {
"composer-exit-on-patch-failure": false,
"patches": { "fake/package": [ "./resources/local.patch" ] }
},
"config": { "allow-plugins": { "ec-europa/toolkit-composer-plugin": true } }
}
- file: composer.lock
content: |
{ "packages": [
{ "name": "test/package", "type": "library", "version": "1.0.0" },
{ "name": "cweagans/composer-patches", "type": "composer-plugin", "version": "2.0.0" }
] }
expectations:
- string_contains: The composer property 'extra.composer-exit-on-patch-failure' is deprecated in version 2
- not_string_contains: Composer validation check passed

# if composer-patches is used, then we expect at least one patch.
- command: 'check:composer'
configuration: [ ]
tokens: ''
Expand All @@ -317,8 +361,8 @@
{ "name": "cweagans/composer-patches", "type": "composer-plugin", "version": "2.0.0" }
] }
expectations:
- not_string_contains: composer-exit-on-patch-failure
- string_contains: Composer validation check passed
- string_contains: Using package cweagans/composer-patches but no patches were found
- not_string_contains: Composer validation check passed

- command: 'check:composer'
configuration:
Expand Down Expand Up @@ -365,7 +409,10 @@
resources:
- file: composer.lock
content: |
{ "packages": [ { "name": "test/dummy", "type": "library", "version": "1.0.0" } ] }
{ "packages": [
{ "name": "test/dummy", "type": "library", "version": "1.0.0" },
{ "name": "cweagans/composer-patches", "type": "composer-plugin", "version": "1.7.3" }
] }
- file: composer.json
content: |
{
Expand Down Expand Up @@ -920,7 +967,10 @@
content: |
{
"name": "ec-europa/toolkit",
"extra": { "composer-exit-on-patch-failure": true },
"extra": {
"composer-exit-on-patch-failure": true,
"patches": { "fake/package": [ "./resources/local.patch" ] }
},
"config": { "allow-plugins": { "ec-europa/toolkit-composer-plugin": true } }
}
expectations:
Expand Down