What the comment says doesn't seem to be 100% true. The test framework
does restore FauxGlobalHooksArray, but all the hook handlers are lost in
the process. Re-add wgHooks to the list of stashed MW globals, so that
it's properly reset when the test ends.
Bug: T342193
Change-Id: I9a21f6475f0c729c07cdb1d174426d5ab6462daf
This reverts change I50c3d1c5df (commit b0317287bc), thus reinstating
change I7d690a1172 (commit d139eb07fe). The only change from the
original is in getHookMethodName(), additionally replacing '-' with '_'
(not just ':' and '\'). The original commit message follows:
This converts all hook handlers to the same internal representation.
This is done lazily, when the hook is run for the first time.
The logic for temporarily disabling handlers by calling scopedRegister()
with the $replace parameter set has been greatly simplified.
There are some minor changes to the class's interface and behavior,
none of which should be breaking changes:
* run() will emit deprecation warnings if and only if it was called
with the deprecationVersion option set, for all kinds of handlers.
The idea is that deprecated hooks should emit a warning either from
run(), or from emitDeprecationWarnings(). The latter happens if the
hook is listed in DeprecatedHooks.
* register() now also accepts hook handlers declared in the way that
extensions register hooks.
* Attempts to call register() with an invalid hook definition now
result in an invalidArgumentException.
* Attempts to call register() for a deprecated hook will consistently
result in a deprecation warning.
* The internal getRegisteredHooks() method has been removed in favor
of the identical getHookNames() method.
* The internal getLegacyHandlers method has been removed in favor
of getHandlerDescriptions() and getHandlerCallbacks().
* The call order changed so that dynamically registered handlers
are called last, instead of getting called before handler objects
from extensions.
Bug: T338213
Change-Id: I6efb09e314ad2b124a33a757fdda2a07ae0d8f7c
This apparently caused some change in how hook handlers are called (it
now calls e.g. AbuseFilterHookHandler::onAbuseFilter-generateUserVars()
instead of AbuseFilterHookHandler::onAbuseFilter_generateUserVars()),
causing both test failures and errors on Beta.
This reverts commit d139eb07fe.
Bug: T338213
Change-Id: I50c3d1c5dfd2d7eeac59992156a8a644cf0197e5
This converts all hook handlers to the same internal representation.
This is done lazily, when the hook is run for the first time.
The logic for temporarily disabling handlers by calling scopedRegister()
with the $replace parameter set has been greatly simplified.
There are some minor changes to the class's interface and behavior,
none of which should be breaking changes:
* run() will emit deprecation warnings if and only if it was called
with the deprecationVersion option set, for all kinds of handlers.
The idea is that deprecated hooks should emit a warning either from
run(), or from emitDeprecationWarnings(). The latter happens if the
hook is listed in DeprecatedHooks.
* register() now also accepts hook handlers declared in the way that
extensions register hooks.
* Attempts to call register() with an invalid hook definition now
result in an invalidArgumentException.
* Attempts to call register() for a deprecated hook will consistently
result in a deprecation warning.
* The internal getRegisteredHooks() method has been removed in favor
of the identical getHookNames() method.
* The internal getLegacyHandlers method has been removed in favor
of getHandlerDescriptions() and getHandlerCallbacks().
* The call order changed so that dynamically registered handlers
are called last, instead of getting called before handler objects
from extensions.
Change-Id: I7d690a1172af44a90b957b2274d68e51b7f09938
$wgHooks should be treated like a regular setting, which cannot be
manipulated after bootstrapping is complete. This will allow us to
greatly simplify the logic in HookContainer.
Replacing $wgHooks with a fake array after bootstrapping allows us to
detect any remaining live access to $wgHooks without breaking
functionality.
The plan is to have the fake array emit deprecation warnings in the 1.40
release, and make it throw exceptions in later releases.
See Iddcb760cf8961316d6527e81b9aa968657d8354c for the deprecation
warnings.
Bug: T331602
Change-Id: I0ebba9a29f81b0d86ad8fd84d478fb244f9e9c15
Previously, SettingsBuilder would allow configuration to be loaded
and modified until it was "finalized", at which point configuration
became read only. This patch introduces an intermediate stage where
registration dynamic manipulation of config values can be performed,
after all extensions have been loaded and all config schemas are known.
Motivation:
Extension registration callbacks are typically used to dynamically set
config variables, often based on other configuration. This should be
done using SettingsBuilder rather than global variables. But previously,
we could only be sure that all extensions are known after SettingsBuilder
was "finalized", at which point it would be impossible to change config
values.
Change-Id: I6f8f9f3f7252f0024282d7b005671f28a5b3acc3
This change cleans up when and how we register autoloader info for
extensions.
This bumps CACHE_VERSION to 8, to avoid issues in case this patch gets
reverted: the new code doesn't copy the map of class files into
$info['globals']['AutoloadClasses']. If old code was to read a new cache
entry, autoloading would fail.
BREAKING CHANGE: The following methods have been removed from
ExtensionRegistry without deprecation and without replacement.
They had been introduced in 1.35 for use in the testing framework,
and were not in use by any known extension:
- exportAutoloadClassesAndNamespaces
- exportTestAutoloadClassesAndNamespaces
NOTE: breaks the hack that SocialProfile has in place for T243861.
Bug: T240535
Change-Id: I6e1ceac034c443d9475f1adc1babecddd6af6d05
This introduces static methods for registering classes and namespaces,
so we don't have to mess with global variables and static members
fields.
Bug: T240535
Change-Id: I1abb27bd70898d04c9253e0b7467447fa96d15a4
This adds full integration tests for extension registration, ensuring
that ExtensionProcessor and ExtensionRegistry work together as expected.
The existing tests for ExtensionProcessor and ExtensionRegistry are
converted to "pure" unit tests.
This change is intended to protect against bugs while refactoring
ExtensionProcessor and ExtensionRegistry to better integrate with the
new SettingsBuilder class.
Bug: T297166
Change-Id: I2d9cc373b8a4aa014aef93b0a8e8d83758851783
getLazyLoadedAttribute() accounts for about 3% of load.php CPU usage in
production, mostly because each ResourceLoaderFileModule calls it for
SkinLessImportPaths, and makeCacheKey() is quite slow.
So, cache lazy attributes in a process cache. There was already
$this->lazyAttributes, which was unused since the original commit. I
assume it was meant to be used for this, so I used it.
I also added a process cache for makeCacheKey() which is invalidated
when the queue changes, so that requests for different lazy attributes
in the same request will be fast.
Change-Id: I83d22b58bb9bf5d06d934d5d2eef8ae7d5f72857
Warning now issued since skins have been updated.
Additional change:
Previously deprecations in release notes were in the wrong
section (Relating to ResourceLoaderSkinModule) these are
moved alongside the newly added deprecation note alongside
other skin deprecations.
Bug: T262067
Depends-On: I52bee67732cc72ec6857b6fc10cfbdd89ef9b8db
Depends-On: I338198878e78cb5c6f47c53fdf18d3944655e965
Change-Id: Ic60524fe3c054706dbea15cc04235e979952e9f5
When originally introduced, a skin's templateDirectory was relative
to core, rather than the skin itself. Most skins needed to set
something like "skins/Example/templates", hardcoding the default value
of $wgStyleDirectory.
skin.json will now assume that the value of templateDirectory is
relative to the skin itself. If that directory doesn't exist, we'll
fallback and assume it's using the previous behavior of being relative
to core. In practice this should not be a breaking change since no skin
is expected to have a directory like "skins/Example/templates" inside
the skin itself.
Finally, ExtensionProcessor will set a default templateDirectory if
one isn't already set, so in most cases this setting should be able
to just be removed entirely.
Bug: T262067
Change-Id: I434b8a4319f3c8b65bcaab3465224058f31e7ae8
Changes from patch set Icb93c79f4843b59dae80d3eda1a880457a1a68f2
Also some swaps from assertEquals to assertSame/True/False/Null
Change-Id: Ife497ae6cb1888b77eb25e85b76df72adc65641a
Prior to this change, if a configuration array is defined
in extension.json, array elements cannot be overridden by
setting values in the corresponding configuration variable,
as intended by the array_replace_recursive merge strategy.
This is because the order of the arrays in the
array_replace_recursive() function call need to be
reversed.
Bug: T283464
Change-Id: I55561232a994f745c5f3cd8394674b18c0529d13
Add a merge strategy which sets the whole value only if the global
has not previously been set. This can be used to allow LocalSettings.php
to remove elements from an array created by extension.json.
Bug: T142663
Change-Id: Id250f9c349ee4eafbc759452ca6ea2a918baeb11
The name change happened some time ago, and I think its
about time to start using the name name!
(Done with a find and replace)
My personal motivation for doing this is that I have started
trying out vscode as an IDE for mediawiki development, and
right now it doesn't appear to handle php aliases very well
or at all.
Change-Id: I412235d91ae26e4c1c6a62e0dbb7e7cf3c5ed4a6
DeprecatedHooks was not listed as a core attribute and so was not
extracted from extension.json. I added some code to extract and merge it
in extractHooks(), and I also made the "component" default to the name
of the extension which deprecates the hook, instead of "MediaWiki".
I added the core deprecated hooks based on the current Hooks::run() calls.
I moved emitDeprecatedHookWarnings() to HookContainer, and to reduce the
performance overhead, arranged for it to be called only on page views.
Change-Id: Idc0cfba782b49398d9e7feaa164fe7692d491bf9
New classes and modificatons to existing classes to support the new Hooks system. All changes are documented in RFC https://phabricator.wikimedia.org/T240307.
- HookContainer.php: Class for doing much of what Hooks.php has historically done, but enabling new-style hooks to be processed and registered. Changes include new ways of defining hook handler functions as an object with defined dependencies in extension.json, removing runWithoutAbort() and addit it to an $options parameter to be passed to HookContainer::run(), being able to decipher whether a hook handler is legacy or non-legacy style and run them in the appropriate way, etc.
- DeprecatedHooks.php: For marking hooks deprecated and verifying if one is deprecated
- DeprecatedHooksTest.php: Unit tests for DeprecatedHooks.php
- Hooks.php: register() will now additionally register hooks with handlers in new HooksContainer.php. getHandlers() will be a legacy wrapper for calling the newer HookContainer::getHandlers()
- MediaWikiServices.php: Added getHookContainer() for retrieving HookContainer singleton
- ExtensionProcessor.php: modified extractHooks() to be able to extract new style handler objects being registered in extension.json
- ServiceWiring.php: Added HookContainer to list of services to return
- HookContainerTest.php: Unit tests for HookContainer.php
- ExtensionProcessorTest.php: Moved file out of /unit folder and now extends MediaWikiTestCase instead of MediaWikiUnitTestCase (as the tests are not truly unit tests). Modified existing tests for ExtensionProcessor::extractHooks() to include a test case for new style handler
Bug: T240307
Change-Id: I432861d8995cfd7180e77e115251d8055b7eceec
When fetching lazy-loaded attributes in ExtensionRegistry to cache, we are saving all the values
from extension.json a second time. In doing so, we are wrongfully omitting the values
previously being defined for the "defines" attribute
(the attribute that is responsible for setting namespace constants).
This patch will make sure that we keep the value set in the "defines" attribute
so that the constants are defined when we load from cache the second time.
Bug: T245629
Change-Id: I4f151f88ece56cf718749b9de11fc8e204ccf29d
This allows us to move things that are not used on every request (e.g.
'TrackingCategories') into separate cache entries to slim down the main
one.
At the same time, fold getLazyLoadedAttribute() into the standard and
already established getAttribute(), so that client code doesn't need to
be aware of whether something is lazy-loaded or not, it'll just work.
Everything is still cached using the load queue as part of the cache key
for instant invalidation, so if an extension.json file changes, the
lazy-loaded attribute cache will invalidate too.
The cache is populated whenever loadFromQueue() happens, but if it
happens to fall out of the cache, then getLazyLoadedAttribute() will
iterate over all the loaded extension/skin.json files to read that
value. Since we end up reading everything, we populate all of the
caches again.
The caching logic was split into two more private functions
(::getCache() and ::makeCacheKey()) for easier internal reuse.
Bug: T220994
Change-Id: I290926bbedfc964195d1f576a9e06349f9e5d5ea
These attributes are only accessed at a time when performance isn't
critical (e.g. tests), so we can skip caching them and read each
extension.json file again when we do need them.
At the same time, we want to reduce the size of the array that we're
caching due to PHP 7 performance regressions with APC (T187154).
'QUnitModules' is the first attribute to be converted into a lazy-loaded
attribute.
Bug: T220994
Change-Id: I224cdace05dbac00ff947c41daecb74b07c967bb
This changeset resumes work on T89432 and related tickets
by porting an initial set of tests to the new unit test suite
separated out in I69b92db3e70093570e05cc0a64c7780a278b321a.
The tests were only ported if they worked immediately without
requiring any changes other than changing the test case class
to MediaWikiUnitTestCase and moving the test to the new suite.
If a test failed for any reason (even trivial misconfiguration),
it was NOT ported.
With this change, the unit tests suite now consits of a total
of 455 tests. As before, you can run these tests via the following
command:
$ composer phpunit:unit
Bug: T84948
Bug: T89432
Bug: T87781
Change-Id: Ibb8175981092d7f41864e641cc3c118af70a5c76
This changeset implements T89432 and related tickets and is based on exploration
done at the Prague Hackathon. The goal is to identify tests in MediaWiki core
that can be run without having to install & configure MediaWiki and its dependencies,
and provide a way to execute these tests via the standard phpunit entry point,
allowing for faster development and integration with existing tooling like IDEs.
The initial set of tests that met these criteria were identified using the work Amir did in
I88822667693d9e00ac3d4639c87bc24e5083e5e8. These tests were then moved into a new subdirectory
under phpunit/ and organized into a separate test suite. The environment for this suite
is set up via a PHPUnit bootstrap file without a custom entry point.
You can execute these tests by running:
$ vendor/bin/phpunit -d memory_limit=512M -c tests/phpunit/unit-tests.xml
Bug: T89432
Bug: T87781
Bug: T84948
Change-Id: Iad01033a0548afd4d2a6f2c1ef6fcc9debf72c0d
Extensions can specify development dependencies in extension.json under
the "dev-requires" key. It's identical to the "requires" field.
Any requirement that is needed to pass tests, including but not limited
to, PHPUnit, QUnit, structure, phan, should be documented in this new
field. The main intention is that CI will ensure that all of these
dependencies are satisfied before running tests.
At standard runtime, the development requirements will be ignored by
MediaWiki, since it only checks for real requirements. Scripts can
manually check development requirements by calling
ExtensionRegistry::setCheckDevRequires( true ) before trying to load
things.
If both "requires" and "dev-requires" are present, MediaWiki will merge
the two together, so the environment will need to satisfy both before
proceeding.
Bug: T193824
Change-Id: I9b2936666ee3c96f5c976c7a17f11c437c2c7f48
This patch adds the possibility for extensions and skins to require
certain environment abiltites that are not necessarily PHP extensions.
For now, the only ability introduced is the ability to shell out, but
the processing and testing is written in a more general way to allow
users to add more abilties later on by just changing getAbilities().
In theory, this allows using VersionChecker to check for random
abilities if they are specified in the constructor, as it is comletely
environment agnostic and not really bound to just be used for checking
extension compatibility.
Furthermore, it is possible to specify custom error messages for each of
these abilities in the constructor. Other parts of MediaWiki may use
these features to check for requirements while working with totally
different abilities.
Bug: T212472
Change-Id: Iff8512530b08ef509e7ac0b6ed8fe9578ef3e2a1
ExtensionRegistry is a rather special singleton that can't use the normal
MediaWikiServices reset due to its early initialization, so introduce
a ->setAttributeForTest method to override attributes that are typically
loaded from extension.json.
Bug: T200013
Change-Id: I9e62a02ed2044c847e9ab2dcdfab094001f88986
This change adds the possibility to specify ext-* keys under the 'platform'
key introduced in I6744cc0be2 to require given PHP extensions. Note that
it's impossible to add constraints different from '*', as there is no universal
way to retrieve PHP extension versions.
Bug: T197535
Change-Id: I510de1e6d80f5c1d92dc1d1665aaa6c25bf28bf7
While MediaWiki Core already sets requirements for PHP versions, it should be
possible for extensions to tighten these requirements. This mirrors the PHP
parameter of extension infoboxes as well.
This change introduces a new 'platform' key (in addition to 'MediaWiki', 'skins'
and 'extensions', where non-MediaWiki software requirements will be listed
in the future, starting with a PHP version constraint. Further keys are
supposed to be added to allow setting constraints against php extensions
and other abilities of the platform.
Bug: T197535
Change-Id: I6744cc0be2363b603331af9dc860eb8603a1a89a
As it's quite common that extensions and skins interact with each other, it's
useful to have a simple way to check if an extension version satisfies a
given constraint, as extensions change over time.
Bug: T202955
Change-Id: I19f9713caf89d647072a2bd7d598e739be383f4a