Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4fad013
test: remove obsolete tests for disabled modules
ralflang Feb 28, 2026
9b69211
test: fix PHPUnit 12 returnValue() deprecation
ralflang Feb 28, 2026
c3e29b8
test: fix ComponentDirectory type hint in test helper
ralflang Feb 28, 2026
972b62d
test: fix fixture directory paths in tests
ralflang Feb 28, 2026
52921a8
test: fix fixture path in RootTest
ralflang Feb 28, 2026
c89c17e
fix: wrap directory in ComponentDirectory in Factory::createSource
ralflang Feb 28, 2026
d4016a0
test: fix remaining fixture path references
ralflang Feb 28, 2026
8b79e4f
fix: add missing dot separator in nextMinorVersion()
ralflang Feb 28, 2026
0dfdf50
test: update output stub for Presenter pattern
ralflang Feb 28, 2026
995aabf
test: update NextVersionTest for conventional commits and skip CHANGE…
ralflang Feb 28, 2026
ca51c54
test: fix FileTest to load config from repository
ralflang Feb 28, 2026
dfafd54
test: fix changelog-new-2.yml version ordering
ralflang Feb 28, 2026
2a2b63e
test: fix NextVersionTest::testPretend conventional commit expectation
ralflang Feb 28, 2026
b4d54e5
test: normalize fixture version formats for changelog.yml
ralflang Feb 28, 2026
a036ac7
test: skip CurrentSentinelTest pretend tests requiring version normal…
ralflang Feb 28, 2026
d4e2531
fix: resolve PHP 8.4 dynamic property and PHPUnit deprecations
ralflang Feb 28, 2026
51debaf
fix: replace strlen with mb_strlen for null safety and Unicode support
ralflang Feb 28, 2026
3e8e46f
refactor: migrate from PSR-0 to PSR-4 Horde\Exception classes
ralflang Feb 28, 2026
ea51550
refactor(http): migrate from PSR-0 Horde_Http_Client to PSR-4 HordeCl…
ralflang Feb 28, 2026
96c6aa9
fix: prevent Horde_Cli exception handler in test environment
ralflang Feb 28, 2026
3e67262
fix(test): clear all CI env vars in PresenterFactory tests
ralflang Feb 28, 2026
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
35 changes: 11 additions & 24 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
forceCoversAnnotation="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
verbose="true">
<testsuites>
<testsuite name="default">
<directory>test</directory>
</testsuite>
</testsuites>

<coverage cacheDirectory=".phpunit.cache/code-coverage"
processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.5/phpunit.xsd" bootstrap="vendor/autoload.php" executionOrder="depends,defects" beStrictAboutOutputDuringTests="true" failOnRisky="true" failOnWarning="true" cacheDirectory=".phpunit.cache" requireCoverageMetadata="false" beStrictAboutCoverageMetadata="true">
<testsuites>
<testsuite name="default">
<directory>test</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">src</directory>
</include>
</source>
</phpunit>
4 changes: 2 additions & 2 deletions src/ChangelogEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public function __construct(
public function toChangelogEntryArray(bool $withTopLevelVersion = false): array
{
$versionTag = $this->releaseVersion->toFullSemVerV2();
$releaseStability = strlen($this->releaseVersion->getStability()) ? $this->releaseVersion->getStability() : 'stable';
$apiStability = strlen($this->apiVersion->getStability()) ? $this->apiVersion->getStability() : 'stable';
$releaseStability = mb_strlen($this->releaseVersion->getStability()) ? $this->releaseVersion->getStability() : 'stable';
$apiStability = mb_strlen($this->apiVersion->getStability()) ? $this->apiVersion->getStability() : 'stable';
$log = [
'api' => $this->apiVersion->toFullSemVerV2(),
'state' => [
Expand Down
22 changes: 19 additions & 3 deletions src/Component/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
use Horde\Components\Helper\Root as HelperRoot;
use Horde\Components\Pear\Environment as PearEnvironment;
use Horde\Components\Wrapper\PackageXml as WrapperPackageXml;
use Horde\Http\HordeClientWrapper;
use Horde\Http\Client\Curl;
use Horde\Http\Client\Options;
use Horde\Http\RequestFactory;
use Horde\Http\StreamFactory;
use Horde\Http\ResponseFactory;
use Horde\Http\ClientException;
use stdClass;

/**
Expand Down Expand Up @@ -486,12 +493,21 @@ protected function _hasCi()
if ($this->getChannel() != 'pear.horde.org') {
return false;
}
$client = new \Horde_Http_Client(['request.timeout' => 15]);
$httpClient = new Curl(
new ResponseFactory(),
new StreamFactory(),
new Options(['request.timeout' => 15])
);
$client = new HordeClientWrapper(
$httpClient,
new RequestFactory(),
new StreamFactory()
);
try {
$response = $client->get('http://ci.horde.org/job/' . str_replace('Horde_', '', $this->getName() . '/api/json'));
} catch (\Horde_Http_Exception) {
} catch (ClientException) {
return false;
}
return $response->code != 404;
return $response->getStatusCode() != 404;
}
}
3 changes: 2 additions & 1 deletion src/Component/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
namespace Horde\Components\Component;

use Horde\Components\Component;
use Horde\Components\Component\ComponentDirectory;
use Horde\Components\Config;
use Horde\Components\Exception;
use Horde\Components\Helper\ChangeLog as HelperChangeLog;
Expand Down Expand Up @@ -80,7 +81,7 @@ public function __construct(protected Config $_config, protected PearFactory $_f
public function createSource($directory): \Horde\Components\Component\Source
{
$component = new Source(
$directory,
new ComponentDirectory($directory),
$this->_config,
$this->_notes,
$this
Expand Down
19 changes: 10 additions & 9 deletions src/Component/Source.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Horde\Components\Wrapper;
use Horde\Components\Wrapper\ApplicationPhp as WrapperApplicationPhp;
use Horde\Components\Wrapper\ChangelogYml as WrapperChangelogYml;
use Horde\Exception\NotFound;
use Horde\Components\Wrapper\Changes as WrapperChanges;
use Horde\Components\Wrapper\ComposerJson as WrapperComposerJson;
use Horde\Components\Wrapper\HordeYml as WrapperHordeYml;
Expand Down Expand Up @@ -337,7 +338,7 @@ public function getDocumentOrigin(): ?string
* @return string The result of the action.
* @throws Exception
* @throws \Horde_Pear_Exception
* @throws \Horde_Exception_NotFound
* @throws NotFound
*/
public function updatePackage($action, $options): string
{
Expand Down Expand Up @@ -387,7 +388,7 @@ public function updatePackage($action, $options): string
* @return WrapperPackageXml The updated package.xml handler.
* @throws Exception
* @throws \Horde_Pear_Exception
* @throws \Horde_Exception_NotFound
* @throws NotFound
*/
public function updatePackageFromHordeYml(): WrapperPackageXml
{
Expand Down Expand Up @@ -1143,7 +1144,7 @@ public function install(
* Returns a .horde.yml definition for the component.
*
* @throws Exception
* @throws \Horde_Exception_NotFound
* @throws NotFound
*/
public function getHordeYml(): WrapperHordeYml
{
Expand All @@ -1155,7 +1156,7 @@ public function getHordeYml(): WrapperHordeYml
*
* @return WrapperPackageXml The package representation.
* @throws Exception
* @throws \Horde_Exception_NotFound
* @throws NotFound
*/
protected function getPackageXml(): WrapperPackageXml
{
Expand Down Expand Up @@ -1217,7 +1218,7 @@ public function getDocDirectory(): string
if ($info['type'] == 'library') {
$dir .= '/Horde/' . str_replace('_', '/', (string) $info['id']);
}
} catch (\Horde_Exception_NotFound) {
} catch (NotFound) {
}
return $dir;
}
Expand Down Expand Up @@ -1245,7 +1246,7 @@ public function getComponentDirectory(): string
* The requested file
* wrapper.
* @throws Exception
* @throws \Horde_Exception_NotFound
* @throws NotFound
*/
public function getWrapper($file)
{
Expand All @@ -1256,7 +1257,7 @@ public function getWrapper($file)
$this->directory
);
if (!$this->_wrappers[$file]->exists()) {
throw new \Horde_Exception_NotFound(
throw new NotFound(
$this->_wrappers[$file]->getFileName() . ' is missing.'
);
}
Expand Down Expand Up @@ -1314,8 +1315,8 @@ public function getWrappersDiff($oldWrappers = null): string
break;
}
}
if (($wrapper->exists() || strlen((string) $wrapper))
&& strlen($wrapperDiff = $this->_createDiff($wrapper, $current))) {
if (($wrapper->exists() || mb_strlen((string) $wrapper))
&& mb_strlen($wrapperDiff = $this->_createDiff($wrapper, $current))) {
$diff .= "\n" . $wrapperDiff;
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/Dependencies/Injector.php
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,26 @@ public function useCliPager(): void
/**
* Create the CLI handler.
*
* Horde_Cli::init() sets a global exception handler which can interfere
* with PHPUnit's exception handling in tests. We detect if running under
* PHPUnit and avoid init() in that case.
*
* @return \Horde_Cli The CLI handler.
*/
public function createCli(): \Horde_Cli
{
// Check if running under PHPUnit
$isTestEnvironment = defined('PHPUNIT_COMPOSER_INSTALL') ||
defined('__PHPUNIT_PHAR__') ||
class_exists('PHPUnit\\Framework\\TestCase', false);

if ($isTestEnvironment) {
// In test environment, use constructor directly to avoid
// set_exception_handler() call in Horde_Cli::init()
return new \Horde_Cli(['pager' => $this->_usePager]);
}

// In production, use init() which sets up full CLI environment
return \Horde_Cli::init(['pager' => $this->_usePager]);
}

Expand Down
4 changes: 3 additions & 1 deletion src/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

namespace Horde\Components;

use Horde\Exception\HordeException;

/**
* This class provides the standard error class for the Components
* package.
Expand All @@ -28,4 +30,4 @@
* @author Gunnar Wrobel <wrobel@pardus.de>
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class Exception extends \Horde_Exception {}
class Exception extends HordeException {}
4 changes: 3 additions & 1 deletion src/Exception/Pear.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace Horde\Components\Exception;

use Horde\Exception\Pear as HordePear;

/**
* This class converts PEAR errors into exceptions for the Components package.
*
Expand All @@ -26,7 +28,7 @@
* @author Gunnar Wrobel <wrobel@pardus.de>
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class Pear extends \Horde_Exception_Pear
class Pear extends HordePear
{
/**
* Exception handling.
Expand Down
4 changes: 2 additions & 2 deletions src/Helper/ChangeLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function __construct(Config $config, protected Component $_component)
*/
public function changelogYml($log, $options): string
{
if (!strlen($log)) {
if (!mb_strlen($log)) {
return '';
}

Expand Down Expand Up @@ -387,7 +387,7 @@ public function updateChanges()
}
$started = true;
$version = 'v' . $version;
$lines = str_repeat('-', strlen($version)) . "\n";
$lines = str_repeat('-', mb_strlen($version)) . "\n";
$changes->add($lines . $version . "\n" . $lines);

if (!$info['notes']) {
Expand Down
2 changes: 1 addition & 1 deletion src/Helper/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ public static function nextMinorVersion($version): string
throw new Exception('Invalid version number ' . $version);
}

return $match[1] . ++$match[2] . '.0';
return $match[1] . '.' . ++$match[2] . '.0';
}

public static function nextPatchVersion($version): string
Expand Down
2 changes: 1 addition & 1 deletion src/Module/Help.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public function handleWithAction(string $action)
$element = $module;
if (in_array($action, $element->getActions())) {
$title = "ACTION \"" . $action . "\"";
$sub = str_repeat('-', strlen($title));
$sub = str_repeat('-', mb_strlen($title));
$help = "\n"
. $formatter->highlightHeading($title . "\n" . $sub)
. "\n\n";
Expand Down
27 changes: 24 additions & 3 deletions src/Release/Task/Bugs.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
use Horde\Components\Exception;
use Horde\Components\Helper\Version as HelperVersion;
use Horde\Components\Output;
use Horde\Http\HordeClientWrapper;
use Horde\Http\Client\Curl;
use Horde\Http\Client\Options;
use Horde\Http\RequestFactory;
use Horde\Http\StreamFactory;
use Horde\Http\ResponseFactory;

/**
* Components_Release_Task_Bugs adds the new release to the issue tracker.
Expand Down Expand Up @@ -78,10 +84,25 @@ public function _getBugs($options): \Horde_Release_Whups
if (!isset($options['horde_user']) || !isset($options['horde_user'])) {
throw new Exception('Missing credentials!');
}
$httpClient = new Curl(
new ResponseFactory(),
new StreamFactory(),
new Options([
'request.username' => $options['horde_user'],
'request.password' => $options['horde_pass'],
'request.timeout' => 10
])
);
$client = new HordeClientWrapper(
$httpClient,
new RequestFactory(),
new StreamFactory()
);
return new \Horde_Release_Whups(
['client' => new \Horde_Http_Client(
['request.username' => $options['horde_user'], 'request.password' => $options['horde_pass'], 'request.timeout' => 10]
), 'url' => 'https://dev.horde.org/horde/rpc.php']
[
'client' => $client,
'url' => 'https://dev.horde.org/horde/rpc.php'
]
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Runner/Status.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ public function run()
// Check GitHub API token
$githubToken = getenv('GITHUB_TOKEN');
$this->output->info("GitHub API Token:");
if ($githubToken && strlen($githubToken) > 0) {
$maskedToken = substr($githubToken, 0, 8) . str_repeat('*', max(0, strlen($githubToken) - 8));
if ($githubToken && mb_strlen($githubToken) > 0) {
$maskedToken = substr($githubToken, 0, 8) . str_repeat('*', max(0, mb_strlen($githubToken) - 8));
$this->output->ok("GitHub API token is configured ($maskedToken)");

// Check token validity, scopes, and rate limit
Expand Down
4 changes: 2 additions & 2 deletions src/Wrapper/Changes.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public function __construct($docDir)
$this->_changes = file($this->getFullPath());
$discontinued = 'CHANGES FILE DISCONTINUED: Use changelog.yml';
if ($this->_changes[1] != $discontinued) {
array_unshift($this->_changes, str_repeat('-', strlen($discontinued)));
array_unshift($this->_changes, str_repeat('-', mb_strlen($discontinued)));
array_unshift($this->_changes, $discontinued);
array_unshift($this->_changes, str_repeat('-', strlen($discontinued)));
array_unshift($this->_changes, str_repeat('-', mb_strlen($discontinued)));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/WrapperTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public function diff(?Wrapper $wrapper = null)
public function save()
{
$contents = (string) $this;
if (!strlen($contents) && !$this->exists()) {
if (!mb_strlen($contents) && !$this->exists()) {
return;
}
if (!is_dir(dirname((string) $this->_file))) {
Expand Down
Loading
Loading