Skip to content

Commit bb73f49

Browse files
authored
Update (#68)
* Add Castor tasks and update Infection workflow This commit introduces a new Castor PHP script with different tasks for test execution, mutation testing, coding standards check, PHPStan, and others. The Infection GitHub workflow was also updated to use the new Castor 'infect' task instead of 'make ci-mu'. The 'Infection' workflow name was also corrected. * Refactor castor validation and integrate tasks in workflows The code refactors the validation of the composer configuration and autoload dumping in the 'castor.php' file. It also modifies the '.github/workflows/integrate.yml' to replace previous tasks with equivalent 'castor' commands for validation, testing, static analysis, code style checking, Deptrac analysis, and make rector. Additionally, '.castor.stub.php' is added to the '.gitignore' file to prevent it from being tracked. * Add license check functionality to castor A new function has been introduced in `castor.php` to check licenses and ensure compliance with defined acceptable licenses. This function has also been integrated into the CI process via the `integrate.yml` GitHub workflow file. It checks license compliance for each dependency before a pull request is merged.
1 parent 4de637a commit bb73f49

File tree

7 files changed

+227
-14
lines changed

7 files changed

+227
-14
lines changed

.gitattributes

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
/CODE_OF_CONDUCT.md export-ignore
99
/deptrac.yaml export-ignore
1010
/ecs.php export-ignore
11-
/infection.json.dist export-ignore
11+
/infection.json export-ignore
1212
/Makefile export-ignore
1313
/phpstan.neon export-ignore
1414
/phpstan-baseline.neon export-ignore
1515
/phpunit.xml.dist export-ignore
1616
/rector.php export-ignore
17+
/castor.php export-ignore

.github/workflows/infection.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow
22

3-
name: "Integrate"
3+
name: "Infection"
44

55
on:
66
push:
@@ -18,6 +18,7 @@ jobs:
1818
php-version: "8.3"
1919
extensions: "ctype, dom, json, libxml, mbstring, openssl, phar, simplexml, tokenizer, xml, xmlwriter"
2020
coverage: "xdebug"
21+
tools: castor
2122

2223
- name: "Checkout code"
2324
uses: "actions/checkout@v3"
@@ -32,4 +33,4 @@ jobs:
3233
composer-options: "--optimize-autoloader"
3334

3435
- name: "Execute Infection"
35-
run: "make ci-mu"
36+
run: "castor infect --ci"

.github/workflows/integrate.yml

+36-10
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ jobs:
6868
with:
6969
php-version: "${{ matrix.php-version }}"
7070
extensions: "ctype, dom, json, libxml, mbstring, openssl, phar, simplexml, tokenizer, xml, xmlwriter"
71+
tools: castor
7172
coverage: "xdebug"
7273

7374
- name: "Checkout code"
@@ -80,7 +81,7 @@ jobs:
8081
composer-options: "--optimize-autoloader"
8182

8283
- name: "Execute tests (PHP)"
83-
run: "make ci-cc"
84+
run: "castor test --coverage-text"
8485

8586
# - name: Send coverage to Coveralls
8687
# if: "matrix.php-version == '8.1' && matrix.dependencies == 'highest'"
@@ -102,25 +103,23 @@ jobs:
102103
with:
103104
php-version: "8.3"
104105
extensions: "ctype, dom, json, libxml, mbstring, openssl, phar, simplexml, tokenizer, xml, xmlwriter"
106+
tools: castor
105107
coverage: "none"
106108

107109
- name: "Checkout code"
108110
uses: "actions/checkout@v3"
109111

110112
- name: "Validate Composer configuration"
111-
run: "composer validate --strict"
113+
run: "castor validate"
112114

113115
- name: "Install dependencies"
114116
uses: "ramsey/composer-install@v3"
115117
with:
116118
dependency-versions: "highest"
117119
composer-options: "--optimize-autoloader"
118120

119-
- name: "Check PSR-4 mapping"
120-
run: "composer dump-autoload --optimize --strict-psr"
121-
122121
- name: "Execute static analysis"
123-
run: "make st"
122+
run: "castor stan"
124123

125124
coding_standards:
126125
name: "4️⃣ Coding Standards"
@@ -134,6 +133,7 @@ jobs:
134133
with:
135134
php-version: "8.3"
136135
extensions: "ctype, dom, json, libxml, mbstring, openssl, phar, simplexml, tokenizer, xml, xmlwriter"
136+
tools: castor
137137
coverage: "none"
138138

139139
- name: "Checkout code"
@@ -146,11 +146,36 @@ jobs:
146146
composer-options: "--optimize-autoloader"
147147

148148
- name: "Check coding style"
149-
run: "make ci-cs"
149+
run: "castor cs"
150150

151151
- name: "Deptrac"
152-
run: |
153-
vendor/bin/deptrac analyse --fail-on-uncovered --no-cache
152+
run: 'castor deptrac'
153+
154+
check_licenses:
155+
name: "5️⃣ Check Licenses"
156+
needs:
157+
- "byte_level"
158+
- "syntax_errors"
159+
runs-on: "ubuntu-latest"
160+
steps:
161+
- name: "Set up PHP"
162+
uses: "shivammathur/setup-php@v2"
163+
with:
164+
php-version: "8.3"
165+
extensions: "ctype, dom, json, libxml, mbstring, openssl, phar, simplexml, tokenizer, xml, xmlwriter"
166+
tools: castor
167+
168+
- name: "Checkout code"
169+
uses: "actions/checkout@v3"
170+
171+
- name: "Install dependencies"
172+
uses: "ramsey/composer-install@v3"
173+
with:
174+
dependency-versions: "highest"
175+
composer-options: "--optimize-autoloader"
176+
177+
- name: "Execute license check"
178+
run: "castor check-licenses"
154179

155180
rector_checkstyle:
156181
name: "6️⃣ Rector Checkstyle"
@@ -164,6 +189,7 @@ jobs:
164189
with:
165190
php-version: "8.3"
166191
extensions: "ctype, dom, json, libxml, mbstring, openssl, phar, simplexml, tokenizer, xml, xmlwriter"
192+
tools: castor
167193
coverage: "xdebug"
168194

169195
- name: "Checkout code"
@@ -179,7 +205,7 @@ jobs:
179205
composer-options: "--optimize-autoloader"
180206

181207
- name: "Execute Rector"
182-
run: "make rector"
208+
run: "castor rector"
183209

184210
exported_files:
185211
name: "7️⃣ Exported files"

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ yarn-error.log
88
/composer.lock
99
/vendor
1010
infection.txt
11+
/.castor.stub.php

castor.php

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Castor\Attribute\AsTask;
6+
use function Castor\io;
7+
use function Castor\run;
8+
9+
#[AsTask(description: 'Run mutation testing')]
10+
function infect(int $minMsi = 0, int $minCoveredMsi = 0, bool $ci = false): void
11+
{
12+
io()->title('Running infection');
13+
$nproc = run('nproc', quiet: true);
14+
if (! $nproc->isSuccessful()) {
15+
io()->error('Cannot determine the number of processors');
16+
return;
17+
}
18+
$threads = (int) $nproc->getOutput();
19+
$command = [
20+
'php',
21+
'vendor/bin/infection',
22+
sprintf('--min-msi=%s', $minMsi),
23+
sprintf('--min-covered-msi=%s', $minCoveredMsi),
24+
sprintf('--threads=%s', $threads),
25+
];
26+
if ($ci) {
27+
$command[] = '--logger-github';
28+
$command[] = '-s';
29+
}
30+
$environment = [
31+
'XDEBUG_MODE' => 'coverage',
32+
];
33+
run($command, environment: $environment);
34+
}
35+
36+
#[AsTask(description: 'Run tests')]
37+
function test(bool $coverageHtml = false, bool $coverageText = false, null|string $group = null): void
38+
{
39+
io()->title('Running tests');
40+
$command = ['php', 'vendor/bin/phpunit', '--color'];
41+
$environment = [
42+
'XDEBUG_MODE' => 'off',
43+
];
44+
if ($coverageHtml) {
45+
$command[] = '--coverage-html=build/coverage';
46+
$environment['XDEBUG_MODE'] = 'coverage';
47+
}
48+
if ($coverageText) {
49+
$command[] = '--coverage-text';
50+
$environment['XDEBUG_MODE'] = 'coverage';
51+
}
52+
if ($group !== null) {
53+
$command[] = sprintf('--group=%s', $group);
54+
}
55+
run($command, environment: $environment);
56+
}
57+
58+
#[AsTask(description: 'Coding standards check')]
59+
function cs(bool $fix = false): void
60+
{
61+
io()->title('Running coding standards check');
62+
$command = ['php', 'vendor/bin/ecs', 'check'];
63+
$environment = [
64+
'XDEBUG_MODE' => 'off',
65+
];
66+
if ($fix) {
67+
$command[] = '--fix';
68+
}
69+
run($command, environment: $environment);
70+
}
71+
72+
#[AsTask(description: 'Running PHPStan')]
73+
function stan(): void
74+
{
75+
io()->title('Running PHPStan');
76+
$command = ['php', 'vendor/bin/phpstan', 'analyse'];
77+
$environment = [
78+
'XDEBUG_MODE' => 'off',
79+
];
80+
run($command, environment: $environment);
81+
}
82+
83+
#[AsTask(description: 'Validate Composer configuration')]
84+
function validate(): void
85+
{
86+
io()->title('Validating Composer configuration');
87+
$command = ['composer', 'validate', '--strict'];
88+
$environment = [
89+
'XDEBUG_MODE' => 'off',
90+
];
91+
run($command, environment: $environment);
92+
93+
$command = ['composer', 'dump-autoload', '--optimize', '--strict-psr'];
94+
run($command, environment: $environment);
95+
}
96+
97+
/**
98+
* @param array<string> $allowedLicenses
99+
*/
100+
#[AsTask(description: 'Check licenses')]
101+
function checkLicenses(
102+
array $allowedLicenses = ['Apache-2.0', 'BSD-2-Clause', 'BSD-3-Clause', 'ISC', 'MIT', 'MPL-2.0', 'OSL-3.0']
103+
): void {
104+
io()->title('Checking licenses');
105+
$allowedExceptions = [];
106+
$command = ['composer', 'licenses', '-f', 'json'];
107+
$environment = [
108+
'XDEBUG_MODE' => 'off',
109+
];
110+
$result = run($command, environment: $environment, quiet: true);
111+
if (! $result->isSuccessful()) {
112+
io()->error('Cannot determine licenses');
113+
exit(1);
114+
}
115+
$licenses = json_decode($result->getOutput(), true);
116+
$disallowed = array_filter(
117+
$licenses['dependencies'],
118+
static fn (array $info, $name) => ! in_array($name, $allowedExceptions, true)
119+
&& count(array_diff($info['license'], $allowedLicenses)) === 1,
120+
\ARRAY_FILTER_USE_BOTH
121+
);
122+
$allowed = array_filter(
123+
$licenses['dependencies'],
124+
static fn (array $info, $name) => in_array($name, $allowedExceptions, true)
125+
|| count(array_diff($info['license'], $allowedLicenses)) === 0,
126+
\ARRAY_FILTER_USE_BOTH
127+
);
128+
if (count($disallowed) > 0) {
129+
io()
130+
->table(
131+
['Package', 'License'],
132+
array_map(
133+
static fn ($name, $info) => [$name, implode(', ', $info['license'])],
134+
array_keys($disallowed),
135+
$disallowed
136+
)
137+
);
138+
io()
139+
->error('Disallowed licenses found');
140+
exit(1);
141+
}
142+
io()
143+
->table(
144+
['Package', 'License'],
145+
array_map(
146+
static fn ($name, $info) => [$name, implode(', ', $info['license'])],
147+
array_keys($allowed),
148+
$allowed
149+
)
150+
);
151+
io()
152+
->success('All licenses are allowed');
153+
}
154+
155+
#[AsTask(description: 'Run Rector')]
156+
function rector(bool $fix = false): void
157+
{
158+
io()->title('Running Rector');
159+
$command = ['php', 'vendor/bin/rector', 'process', '--ansi'];
160+
if (! $fix) {
161+
$command[] = '--dry-run';
162+
}
163+
$environment = [
164+
'XDEBUG_MODE' => 'off',
165+
];
166+
run($command, environment: $environment);
167+
}
168+
169+
#[AsTask(description: 'Run Rector')]
170+
function deptrac(): void
171+
{
172+
io()->title('Running Rector');
173+
$command = ['php', 'vendor/bin/deptrac', 'analyse', '--fail-on-uncovered', '--no-cache'];
174+
$environment = [
175+
'XDEBUG_MODE' => 'off',
176+
];
177+
run($command, environment: $environment);
178+
}

ecs.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@
8787
$config->parallel();
8888
$config->paths([__DIR__]);
8989
$config->skip(
90-
[__DIR__ . '/.github', __DIR__ . '/build', __DIR__ . '/vendor', PhpUnitTestClassRequiresCoversFixer::class]
90+
[
91+
__DIR__ . '/.github',
92+
__DIR__ . '/build',
93+
__DIR__ . '/vendor',
94+
__DIR__ . '/.castor.stub.php',
95+
PhpUnitTestClassRequiresCoversFixer::class,
96+
]
9197
);
9298
};

infection.json.dist infection.json

File renamed without changes.

0 commit comments

Comments
 (0)