Skip to content

Commit af95ea6

Browse files
committed
Create a separate config file for libraries
Move MW-specific stuff to a subclass of ConfigBuilder, create a separate config file for libraries as described on phab. Bug: T334492 Change-Id: I9a9b2e1b23bc971d7baa84147c4cefbdc67595ff
1 parent 20a4069 commit af95ea6

File tree

7 files changed

+258
-145
lines changed

7 files changed

+258
-145
lines changed

.phpcs.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<ruleset>
3-
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" />
3+
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
4+
<exclude name="MediaWiki.NamingConventions.PrefixedGlobalFunctions.allowedPrefix" />
5+
</rule>
46
<file>.</file>
57
<arg name="encoding" value="UTF-8"/>
68
<arg name="extensions" value="php"/>

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
MediaWiki phan configuration
22
============================
33

4-
`src/config.php` is the standard base phan configuration for MediaWiki
5-
projects. You can include that file in your project and extend/modify
6-
it as you see fit.
4+
There are two base phan configurations for MediaWiki projects:
5+
* `config.php` for MediaWiki code, like extensions and skins
6+
* `config-libraries.php` for PHP libraries and other code external to MediaWiki
7+
8+
Choose the file more suitable for your project, then include it in the phan
9+
configuration and extend/modify it as you see fit.
710

811
See <https://www.mediawiki.org/wiki/Continuous_integration/Phan> for
912
more details.

src/ConfigBuilder.php

Lines changed: 14 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@ class ConfigBuilder {
1111
public const PROGRESS_BAR_LONG = 2;
1212

1313
/** @var array */
14-
private $options;
15-
/** @var string */
16-
private $installPath;
14+
private array $options = [];
1715

1816
/**
19-
* @param string $installPath
20-
* @param array $baseOptions Options to start with, if any. This should only be used in edge
21-
* cases, or complicated config files (e.g. the base file in this repo).
17+
* Sets an array of raw phan options. This should generally be avoided, in favour of the setters below.
18+
* @param array $options
19+
* @return self
2220
*/
23-
public function __construct( string $installPath, array $baseOptions = [] ) {
24-
$this->installPath = rtrim( $installPath, '/' );
25-
$this->options = $baseOptions;
21+
public function setRawOptions( array $options ): self {
22+
$this->options = array_replace( $this->options, $options );
23+
return $this;
2624
}
2725

2826
/**
@@ -272,45 +270,6 @@ public function setTargetPHPVersion( string $version ): self {
272270
return $this;
273271
}
274272

275-
/**
276-
* @param string[] $names
277-
* @param string $type 'extension' or 'skin'
278-
* @return string[]
279-
*/
280-
private function getDependenciesPaths( array $names, string $type ): array {
281-
return array_map(
282-
function ( string $name ) use ( $type ): string {
283-
$dir = $type === 'extension' ? 'extensions' : 'skins';
284-
return $this->installPath . "/$dir/$name";
285-
},
286-
$names
287-
);
288-
}
289-
290-
/**
291-
* @todo Exclude multiple vendor directories
292-
* @param string ...$extensions
293-
* @return $this
294-
*/
295-
public function addExtensionDependencies( string ...$extensions ): self {
296-
$extDirs = $this->getDependenciesPaths( $extensions, 'extension' );
297-
$this->addDirectories( ...$extDirs );
298-
$this->excludeDirectories( ...$extDirs );
299-
return $this;
300-
}
301-
302-
/**
303-
* @todo Exclude multiple vendor directories
304-
* @param string ...$skins
305-
* @return $this
306-
*/
307-
public function addSkinDependencies( string ...$skins ): self {
308-
$skinDirs = $this->getDependenciesPaths( $skins, 'skin' );
309-
$this->addDirectories( ...$skinDirs );
310-
$this->excludeDirectories( ...$skinDirs );
311-
return $this;
312-
}
313-
314273
/**
315274
* @internal
316275
* This should only be used by the config file in this repo.
@@ -323,10 +282,11 @@ public function enableTaintCheck(
323282
string $curDir,
324283
string $vendorPath
325284
): self {
326-
$taintCheckPath = $curDir . "/../../phan-taint-check-plugin/MediaWikiSecurityCheckPlugin.php";
285+
$taintCheckPluginName = $this->getTaintCheckPluginName();
286+
$taintCheckPath = $curDir . "/../../phan-taint-check-plugin/$taintCheckPluginName.php";
327287
if ( !file_exists( $taintCheckPath ) ) {
328288
$taintCheckPath =
329-
"$vendorPath/vendor/mediawiki/phan-taint-check-plugin/MediaWikiSecurityCheckPlugin.php";
289+
"$vendorPath/vendor/mediawiki/phan-taint-check-plugin/$taintCheckPluginName.php";
330290
}
331291
$this->options['plugins'][] = $taintCheckPath;
332292
// Taint-check specific settings. NOTE: don't remove these lines, even if they duplicate some of
@@ -343,4 +303,8 @@ public function enableTaintCheck(
343303
);
344304
return $this;
345305
}
306+
307+
protected function getTaintCheckPluginName(): string {
308+
return 'GenericSecurityCheckPlugin';
309+
}
346310
}

src/MediaWikiConfigBuilder.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
/** @noinspection PhpUnused */
3+
4+
namespace MediaWikiPhanConfig;
5+
6+
class MediaWikiConfigBuilder extends ConfigBuilder {
7+
/** @var string */
8+
private string $installPath;
9+
10+
/**
11+
* @param string $installPath
12+
*/
13+
public function __construct( string $installPath ) {
14+
$this->installPath = rtrim( $installPath, '/' );
15+
}
16+
17+
/**
18+
* @param string[] $names
19+
* @param string $type 'extension' or 'skin'
20+
* @return string[]
21+
*/
22+
private function getDependenciesPaths( array $names, string $type ): array {
23+
return array_map(
24+
function ( string $name ) use ( $type ): string {
25+
$dir = $type === 'extension' ? 'extensions' : 'skins';
26+
return $this->installPath . "/$dir/$name";
27+
},
28+
$names
29+
);
30+
}
31+
32+
/**
33+
* @todo Exclude multiple vendor directories
34+
* @param string ...$extensions
35+
* @return $this
36+
*/
37+
public function addExtensionDependencies( string ...$extensions ): self {
38+
$extDirs = $this->getDependenciesPaths( $extensions, 'extension' );
39+
$this->addDirectories( ...$extDirs );
40+
$this->excludeDirectories( ...$extDirs );
41+
return $this;
42+
}
43+
44+
/**
45+
* @todo Exclude multiple vendor directories
46+
* @param string ...$skins
47+
* @return $this
48+
*/
49+
public function addSkinDependencies( string ...$skins ): self {
50+
$skinDirs = $this->getDependenciesPaths( $skins, 'skin' );
51+
$this->addDirectories( ...$skinDirs );
52+
$this->excludeDirectories( ...$skinDirs );
53+
return $this;
54+
}
55+
56+
protected function getTaintCheckPluginName(): string {
57+
return 'MediaWikiSecurityCheckPlugin';
58+
}
59+
}

src/base-config-functions.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
use MediaWikiPhanConfig\ConfigBuilder;
4+
5+
function setBaseOptions( string $curDir, ConfigBuilder $configBuilder ): void {
6+
// TODO: Do we need to explicitly set these? If so, move to ConfigBuilder. Remove otherwise.
7+
$baseOptions = [
8+
'backward_compatibility_checks' => false,
9+
10+
'parent_constructor_required' => [
11+
],
12+
13+
'quick_mode' => false,
14+
'analyze_signature_compatibility' => true,
15+
'ignore_undeclared_variables_in_global_scope' => false,
16+
'read_type_annotations' => true,
17+
'disable_suppression' => false,
18+
'dump_ast' => false,
19+
'dump_signatures_file' => null,
20+
'processes' => 1,
21+
'whitelist_issue_types' => [],
22+
'markdown_issue_messages' => false,
23+
'generic_types_enabled' => true,
24+
'plugins' => [
25+
'PregRegexCheckerPlugin',
26+
'UnusedSuppressionPlugin',
27+
'DuplicateExpressionPlugin',
28+
'LoopVariableReusePlugin',
29+
'RedundantAssignmentPlugin',
30+
'UnreachableCodePlugin',
31+
'SimplifyExpressionPlugin',
32+
'DuplicateArrayKeyPlugin',
33+
'UseReturnValuePlugin',
34+
'AddNeverReturnTypePlugin',
35+
],
36+
'plugin_config' => [],
37+
// BC for repos not checking whether these are set
38+
'file_list' => [],
39+
'exclude_file_list' => [],
40+
];
41+
$configBuilder->setRawOptions( $baseOptions );
42+
43+
$configBuilder
44+
->excludeDirectories( $curDir . '/stubs' )
45+
->setExcludeFileRegex(
46+
'@vendor/(' .
47+
'(' . implode( '|', array_merge( [
48+
// Exclude known dev dependencies
49+
'composer/installers',
50+
'php-parallel-lint/php-console-color',
51+
'php-parallel-lint/php-console-highlighter',
52+
'php-parallel-lint/php-parallel-lint',
53+
'mediawiki/mediawiki-codesniffer',
54+
'microsoft/tolerant-php-parser',
55+
'phan/phan',
56+
'phpunit/php-code-coverage',
57+
'squizlabs/php_codesniffer',
58+
// Exclude stubs used in libraries
59+
'[^/]+/[^/]+/\.phan',
60+
], PHP_MAJOR_VERSION < 8 ? [] : [
61+
'symfony/polyfill-php80',
62+
] ) ) . ')' .
63+
'|' .
64+
// Also exclude tests folder from dependencies
65+
'.*/[Tt]ests?' .
66+
')/@'
67+
)
68+
->setMinimumSeverity( 0 )
69+
->allowMissingProperties( false )
70+
->allowNullCastsAsAnyType( false )
71+
->allowScalarImplicitCasts( false )
72+
->enableDeadCodeDetection( false )
73+
->shouldDeadCodeDetectionPreferFalseNegatives( true )
74+
// TODO Enable by default
75+
->setProgressBarMode( ConfigBuilder::PROGRESS_BAR_DISABLED )
76+
->readClassAliases( true )
77+
->enableRedundantConditionDetection( true )
78+
->setMinimumPHPVersion( '7.4' )
79+
->setTargetPHPVersion( '8.1' );
80+
81+
if ( !defined( 'MSG_EOR' ) ) {
82+
$configBuilder->addFiles( $curDir . '/stubs/sockets.windows.php' );
83+
}
84+
}
85+
86+
/**
87+
* Internal helper used to filter dirs. This is used so that we can include commonly-used dir
88+
* names without phan complaining about "directory not found". It should NOT be used in
89+
* repo-specific config files.
90+
*/
91+
function filterDirs( array $dirs ): array {
92+
return array_filter( $dirs, 'file_exists' );
93+
}

src/config-library.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
/**
3+
* This program is free software; you can redistribute it and/or modify
4+
* it under the terms of the GNU General Public License as published by
5+
* the Free Software Foundation; either version 2 of the License, or
6+
* (at your option) any later version.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along
14+
* with this program; if not, write to the Free Software Foundation, Inc.,
15+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16+
* http://www.gnu.org/copyleft/gpl.html
17+
*
18+
* @file
19+
*/
20+
21+
use MediaWikiPhanConfig\ConfigBuilder;
22+
23+
require_once __DIR__ . '/base-config-functions.php';
24+
25+
// Replace \\ by / for windows users to let exclude work correctly
26+
$DIR = str_replace( '\\', '/', __DIR__ );
27+
28+
$baseCfg = new ConfigBuilder();
29+
setBaseOptions( $DIR, $baseCfg );
30+
31+
$baseCfg = $baseCfg
32+
->setDirectoryList( filterDirs( [
33+
'includes/',
34+
'src/',
35+
'.phan/stubs/',
36+
'vendor/',
37+
] ) )
38+
->setExcludedDirectoryList( [
39+
'.phan/stubs/',
40+
'vendor/',
41+
] )
42+
->setSuppressedIssuesList( [
43+
// Covered by codesniffer
44+
'PhanUnreferencedUseNormal',
45+
'PhanUnreferencedUseFunction',
46+
'PhanUnreferencedUseConstant',
47+
'PhanDuplicateUseNormal',
48+
'PhanDuplicateUseFunction',
49+
'PhanDuplicateUseConstant',
50+
'PhanUseNormalNoEffect',
51+
'PhanUseNormalNamespacedNoEffect',
52+
'PhanUseFunctionNoEffect',
53+
'PhanUseConstantNoEffect',
54+
'PhanDeprecatedCaseInsensitiveDefine',
55+
56+
// These are quite PHP8-specific
57+
'PhanParamNameIndicatingUnused',
58+
'PhanParamNameIndicatingUnusedInClosure',
59+
'PhanProvidingUnusedParameter',
60+
61+
// Would probably have many false positives
62+
'PhanPluginMixedKeyNoKey',
63+
] )
64+
->enableTaintCheck( $DIR, 'vendor/' )
65+
->suppressIssueTypes(
66+
// PHP 7.4 functionality; suppress by default until we no longer support PHP < 7.4.
67+
// In reality, this means when MW 1.35 is EOL, expected September 2023.
68+
// This will hopefully prevent some issues with backporting.
69+
'PhanPluginDuplicateExpressionAssignmentOperation',
70+
);
71+
72+
// BC: We're not ready to use the ConfigBuilder everywhere
73+
return $baseCfg->make();

0 commit comments

Comments
 (0)