Skip to content

Commit ff59e13

Browse files
committed
feat(rector): Add strict config for new code
Signed-off-by: provokateurin <kate@provokateurin.de>
1 parent 89e3493 commit ff59e13

File tree

6 files changed

+171
-82
lines changed

6 files changed

+171
-82
lines changed

.github/workflows/rector.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
2+
# SPDX-License-Identifier: AGPL-3.0-or-later
3+
name: Rector
4+
5+
on:
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: rector-${{ github.head_ref || github.run_id }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
strict:
17+
runs-on: ubuntu-latest
18+
19+
if: ${{ github.event_name != 'push' && github.repository_owner != 'nextcloud-gmbh' }}
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
24+
with:
25+
persist-credentials: false
26+
submodules: true
27+
28+
- name: Set up php
29+
uses: shivammathur/setup-php@ec406be512d7077f68eed36e63f4d91bc006edc4 #v2.35.4
30+
with:
31+
php-version: '8.2'
32+
extensions: apcu,ctype,curl,dom,fileinfo,ftp,gd,imagick,intl,json,ldap,mbstring,openssl,pdo_sqlite,posix,sqlite,xml,zip
33+
coverage: none
34+
env:
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
37+
- name: Composer install
38+
run: composer i
39+
40+
- name: Rector
41+
run: composer run rector:strict
42+
43+
- name: Show changes
44+
if: always()
45+
run: git diff --exit-code -- . ':!lib/composer'

build/files-checker.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
'package.json',
7474
'psalm-ncu.xml',
7575
'psalm-ocp.xml',
76+
'psalm-strict.xml',
7677
'psalm.xml',
7778
'public.php',
7879
'remote.php',

build/rector-shared.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-only
8+
*/
9+
10+
use Nextcloud\Rector\Set\NextcloudSets;
11+
use PhpParser\Node;
12+
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
13+
use Rector\Config\RectorConfig;
14+
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
15+
use Rector\PHPUnit\Set\PHPUnitSetList;
16+
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
17+
use Rector\ValueObject\Application\File;
18+
19+
$nextcloudDir = dirname(__DIR__);
20+
21+
class NextcloudNamespaceSkipVoter implements ClassNameImportSkipVoterInterface {
22+
private array $namespacePrefixes = [
23+
'OC',
24+
'OCA',
25+
'OCP',
26+
];
27+
private array $skippedClassNames = [
28+
'Backend',
29+
'Connection',
30+
'Exception',
31+
'IManager',
32+
'IProvider',
33+
'Manager',
34+
'Plugin',
35+
'Provider',
36+
];
37+
public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedObjectType, Node $node) : bool {
38+
if (in_array($fullyQualifiedObjectType->getShortName(), $this->skippedClassNames)) {
39+
// Skip common class names to avoid confusion
40+
return true;
41+
}
42+
foreach ($this->namespacePrefixes as $prefix) {
43+
if (str_starts_with($fullyQualifiedObjectType->getClassName(), $prefix . '\\')) {
44+
// Import Nextcloud namespaces
45+
return false;
46+
}
47+
}
48+
// Skip everything else
49+
return true;
50+
}
51+
}
52+
53+
$config = RectorConfig::configure()
54+
->withSkip([
55+
$nextcloudDir . '/apps/*/3rdparty/*',
56+
$nextcloudDir . '/apps/*/build/stubs/*',
57+
$nextcloudDir . '/apps/*/composer/*',
58+
$nextcloudDir . '/apps/*/config/*',
59+
// The mock classes are excluded, as the tests explicitly test the annotations which should not be migrated to attributes
60+
$nextcloudDir . '/tests/lib/AppFramework/Middleware/Mock/*',
61+
$nextcloudDir . '/tests/lib/AppFramework/Middleware/Security/Mock/*',
62+
])
63+
// uncomment to reach your current PHP version
64+
// ->withPhpSets()
65+
->withImportNames(importShortClasses:false)
66+
->withConfiguredRule(ClassPropertyAssignToConstructorPromotionRector::class, [
67+
'inline_public' => true,
68+
'rename_property' => true,
69+
])
70+
->withSets([
71+
NextcloudSets::NEXTCLOUD_27,
72+
PHPUnitSetList::PHPUNIT_100,
73+
]);
74+
75+
$config->registerService(NextcloudNamespaceSkipVoter::class, tag:ClassNameImportSkipVoterInterface::class);
76+
77+
/* Ignore all files ignored by git */
78+
$ignoredEntries = shell_exec('git status --porcelain --ignored ' . escapeshellarg($nextcloudDir));
79+
$ignoredEntries = explode("\n", $ignoredEntries);
80+
$ignoredEntries = array_filter($ignoredEntries, static fn (string $line) => str_starts_with($line, '!! '));
81+
$ignoredEntries = array_map(static fn (string $line) => substr($line, 3), $ignoredEntries);
82+
$ignoredEntries = array_values($ignoredEntries);
83+
84+
foreach ($ignoredEntries as $ignoredEntry) {
85+
if (str_ends_with($ignoredEntry, '/')) {
86+
$config->withSkip([$ignoredEntry . '*']);
87+
} else {
88+
$config->withSkip([$ignoredEntry . '/*']);
89+
}
90+
}
91+
92+
return $config;

build/rector-strict.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
$nextcloudDir = dirname(__DIR__);
9+
10+
return (require __DIR__ . '/rector-shared.php')
11+
->withPaths([
12+
$nextcloudDir . '/build/rector-strict.php',
13+
])
14+
->withPreparedSets(
15+
deadCode: true,
16+
codeQuality: true,
17+
codingStyle: true,
18+
typeDeclarations: true,
19+
typeDeclarationDocblocks: true,
20+
privatization: true,
21+
instanceOf: true,
22+
earlyReturn: true,
23+
rectorPreset: true,
24+
phpunitCodeQuality: true,
25+
doctrineCodeQuality: true,
26+
symfonyCodeQuality: true,
27+
symfonyConfigs: true,
28+
)->withPhpSets(
29+
php82: true,
30+
);

build/rector.php

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,9 @@
77
* SPDX-License-Identifier: AGPL-3.0-only
88
*/
99

10-
use Nextcloud\Rector\Set\NextcloudSets;
11-
use PhpParser\Node;
12-
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
13-
use Rector\Config\RectorConfig;
14-
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
15-
use Rector\PHPUnit\Set\PHPUnitSetList;
16-
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
17-
use Rector\ValueObject\Application\File;
18-
1910
$nextcloudDir = dirname(__DIR__);
2011

21-
class NextcloudNamespaceSkipVoter implements ClassNameImportSkipVoterInterface {
22-
private array $namespacePrefixes = [
23-
'OC',
24-
'OCA',
25-
'OCP',
26-
];
27-
private array $skippedClassNames = [
28-
'Backend',
29-
'Connection',
30-
'Exception',
31-
'IManager',
32-
'IProvider',
33-
'Manager',
34-
'Plugin',
35-
'Provider',
36-
];
37-
public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedObjectType, Node $node) : bool {
38-
if (in_array($fullyQualifiedObjectType->getShortName(), $this->skippedClassNames)) {
39-
// Skip common class names to avoid confusion
40-
return true;
41-
}
42-
foreach ($this->namespacePrefixes as $prefix) {
43-
if (str_starts_with($fullyQualifiedObjectType->getClassName(), $prefix . '\\')) {
44-
// Import Nextcloud namespaces
45-
return false;
46-
}
47-
}
48-
// Skip everything else
49-
return true;
50-
}
51-
}
52-
53-
$config = RectorConfig::configure()
12+
return (require 'rector-shared.php')
5413
->withPaths([
5514
$nextcloudDir . '/apps',
5615
$nextcloudDir . '/core',
@@ -71,43 +30,4 @@ public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedO
7130
// $nextcloudDir . '/lib',
7231
// $nextcloudDir . '/themes',
7332
])
74-
->withSkip([
75-
$nextcloudDir . '/apps/*/3rdparty/*',
76-
$nextcloudDir . '/apps/*/build/stubs/*',
77-
$nextcloudDir . '/apps/*/composer/*',
78-
$nextcloudDir . '/apps/*/config/*',
79-
// The mock classes are excluded, as the tests explicitly test the annotations which should not be migrated to attributes
80-
$nextcloudDir . '/tests/lib/AppFramework/Middleware/Mock/*',
81-
$nextcloudDir . '/tests/lib/AppFramework/Middleware/Security/Mock/*',
82-
])
83-
// uncomment to reach your current PHP version
84-
// ->withPhpSets()
85-
->withImportNames(importShortClasses:false)
86-
->withTypeCoverageLevel(0)
87-
->withConfiguredRule(ClassPropertyAssignToConstructorPromotionRector::class, [
88-
'inline_public' => true,
89-
'rename_property' => true,
90-
])
91-
->withSets([
92-
NextcloudSets::NEXTCLOUD_27,
93-
PHPUnitSetList::PHPUNIT_100,
94-
]);
95-
96-
$config->registerService(NextcloudNamespaceSkipVoter::class, tag:ClassNameImportSkipVoterInterface::class);
97-
98-
/* Ignore all files ignored by git */
99-
$ignoredEntries = shell_exec('git status --porcelain --ignored ' . escapeshellarg($nextcloudDir));
100-
$ignoredEntries = explode("\n", $ignoredEntries);
101-
$ignoredEntries = array_filter($ignoredEntries, static fn (string $line) => str_starts_with($line, '!! '));
102-
$ignoredEntries = array_map(static fn (string $line) => substr($line, 3), $ignoredEntries);
103-
$ignoredEntries = array_values($ignoredEntries);
104-
105-
foreach ($ignoredEntries as $ignoredEntry) {
106-
if (str_ends_with($ignoredEntry, '/')) {
107-
$config->withSkip([$ignoredEntry . '*']);
108-
} else {
109-
$config->withSkip([$ignoredEntry . '/*']);
110-
}
111-
}
112-
113-
return $config;
33+
->withTypeCoverageLevel(0);

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"test:db": "@composer run test -- --group DB --group SLOWDB",
7777
"test:files_external": "phpunit --fail-on-warning --fail-on-risky --display-warnings --display-deprecations --display-phpunit-deprecations --colors=always --configuration tests/phpunit-autotest-external.xml",
7878
"rector": "rector --config=build/rector.php && composer cs:fix",
79+
"rector:strict": "rector --config=build/rector-strict.php && composer cs:fix",
7980
"openapi": "./build/openapi-checker.sh"
8081
},
8182
"extra": {

0 commit comments

Comments
 (0)