Skip to content

Commit

Permalink
Merge pull request #159 from shlinkio/develop
Browse files Browse the repository at this point in the history
Release 7.1.0
  • Loading branch information
acelaya authored Apr 23, 2022
2 parents 309e3ff + 2e3f6ad commit 92f8093
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 34 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).

## [7.1.0] - 2022-04-23
### Added
* [#157](https://github.com/shlinkio/shlink-installer/issues/157) Added support for the timezone config option.

### Changed
* *Nothing*

### Changed
* *Nothing*

### Deprecated
* Deprecated webhook-related config options.

### Removed
* *Nothing*

### Fixed
* [#155](https://github.com/shlinkio/shlink-installer/issues/155) Fixed router config cache not getting deleted when editing config options.


## [7.0.2] - 2022-02-19
### Added
* *Nothing*
Expand Down
12 changes: 6 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
],
"require": {
"php": "^8.0",
"laminas/laminas-config": "^3.5",
"laminas/laminas-config-aggregator": "^1.5",
"laminas/laminas-servicemanager": "^3.7",
"laminas/laminas-stdlib": "^3.4",
"laminas/laminas-config": "^3.7",
"laminas/laminas-config-aggregator": "^1.7",
"laminas/laminas-servicemanager": "^3.11.2",
"laminas/laminas-stdlib": "^3.7",
"lstrojny/functional-php": "^1.17",
"shlinkio/shlink-config": "^1.5",
"shlinkio/shlink-config": "^1.6",
"symfony/console": "^6.0",
"symfony/filesystem": "^6.0",
"symfony/process": "^6.0"
Expand All @@ -27,7 +27,7 @@
"devster/ubench": "^2.0",
"infection/infection": "^0.26",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/phpstan": "^1.2",
"phpstan/phpstan": "^1.5",
"phpunit/phpunit": "^9.5",
"roave/security-advisories": "dev-master",
"shlinkio/php-coding-standard": "~2.2.0",
Expand Down
2 changes: 2 additions & 0 deletions config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
'APPLICATION' => [
'Delete short URLs > Visits threshold' => Config\Option\Visit\VisitsThresholdConfigOption::class,
'Base path' => Config\Option\BasePathConfigOption::class,
'Timezone' => Config\Option\TimezoneConfigOption::class,
'Swoole > Amount of task workers' => Config\Option\Worker\TaskWorkerNumConfigOption::class,
'Swoole > Amount of web workers' => Config\Option\Worker\WebWorkerNumConfigOption::class,
],
Expand All @@ -107,6 +108,7 @@

'factories' => [
Config\Option\BasePathConfigOption::class => InvokableFactory::class,
Config\Option\TimezoneConfigOption::class => InvokableFactory::class,
Config\Option\Visit\VisitsThresholdConfigOption::class => InvokableFactory::class,
Config\Option\Database\DatabaseDriverConfigOption::class => InvokableFactory::class,
Config\Option\Database\DatabaseNameConfigOption::class => InvokableFactory::class,
Expand Down
4 changes: 2 additions & 2 deletions src/Config/Option/BasePathConfigOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public function getEnvVar(): string
public function ask(StyleInterface $io, PathCollection $currentOptions): string
{
return $io->ask(
'What is the path from which shlink is going to be served? (Leave empty if you plan to serve '
. 'shlink from the root of the domain)',
'What is the path from which shlink is going to be served? (It must include a leading bar, like "/shlink". '
. 'Leave empty if you plan to serve shlink from the root of the domain)',
) ?? '';
}
}
28 changes: 28 additions & 0 deletions src/Config/Option/TimezoneConfigOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Shlinkio\Shlink\Installer\Config\Option;

use Shlinkio\Shlink\Config\Collection\PathCollection;
use Symfony\Component\Console\Style\StyleInterface;

class TimezoneConfigOption implements ConfigOptionInterface
{
public function getEnvVar(): string
{
return 'TIMEZONE';
}

public function shouldBeAsked(PathCollection $currentOptions): bool
{
return ! $currentOptions->pathExists([$this->getEnvVar()]);
}

public function ask(StyleInterface $io, PathCollection $currentOptions): ?string
{
return $io->ask(
'Set the timezone in which your Shlink instance is running (leave empty to use the one set in PHP config)',
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Shlinkio\Shlink\Installer\Config\Option\DependentConfigOptionInterface;
use Symfony\Component\Console\Style\StyleInterface;

/** @deprecated */
class OrphanVisitsWebhooksConfigOption extends AbstractSwooleDependentConfigOption implements
DependentConfigOptionInterface
{
Expand Down
1 change: 1 addition & 0 deletions src/Config/Option/Visit/VisitsWebhooksConfigOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use function implode;

/** @deprecated */
class VisitsWebhooksConfigOption extends AbstractSwooleDependentConfigOption
{
use ConfigOptionsValidatorsTrait;
Expand Down
20 changes: 13 additions & 7 deletions src/Service/ShlinkAssetsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ShlinkAssetsHandler implements ShlinkAssetsHandlerInterface
use AskUtilsTrait;

public const GENERATED_CONFIG_PATH = 'config/params/generated_config.php';
private const CACHED_CONFIG_PATH = 'data/cache/app_config.php';
private const CACHED_CONFIGS_PATHS = ['data/cache/app_config.php', 'data/cache/fastroute_cached_routes.php'];
private const SQLITE_DB_PATH = 'data/database.sqlite';
private const GEO_LITE_DB_PATH = 'data/GeoLite2-City.mmdb';

Expand All @@ -30,17 +30,23 @@ public function __construct(private Filesystem $filesystem)
*/
public function dropCachedConfigIfAny(StyleInterface $io): void
{
if (! $this->filesystem->exists(self::CACHED_CONFIG_PATH)) {
foreach (self::CACHED_CONFIGS_PATHS as $file) {
$this->dropCachedConfigFile($file, $io);
}
}

private function dropCachedConfigFile(string $file, StyleInterface $io): void
{
if (! $this->filesystem->exists($file)) {
return;
}

try {
$this->filesystem->remove(self::CACHED_CONFIG_PATH);
$this->filesystem->remove($file);
} catch (IOException $e) {
$io->error(sprintf(
'Could not delete cached config! You will have to manually delete the "%s" file.',
self::CACHED_CONFIG_PATH,
));
$io->error(
sprintf('Could not delete cached config! You will have to manually delete the "%s" file.', $file),
);
throw $e;
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/Config/Option/BasePathConfigOptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public function expectedQuestionIsAsked(?string $answer, string $expectedAnswer)
{
$io = $this->prophesize(StyleInterface::class);
$ask = $io->ask(
'What is the path from which shlink is going to be served? (Leave empty if you plan to serve '
. 'shlink from the root of the domain)',
'What is the path from which shlink is going to be served? (It must include a leading bar, like "/shlink". '
. 'Leave empty if you plan to serve shlink from the root of the domain)',
)->willReturn($answer);

$answer = $this->configOption->ask($io->reveal(), new PathCollection());
Expand Down
67 changes: 67 additions & 0 deletions test/Config/Option/TimezoneConfigOptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace ShlinkioTest\Shlink\Installer\Config\Option;

use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Shlinkio\Shlink\Config\Collection\PathCollection;
use Shlinkio\Shlink\Installer\Config\Option\TimezoneConfigOption;
use Symfony\Component\Console\Style\StyleInterface;

class TimezoneConfigOptionTest extends TestCase
{
use ProphecyTrait;

private TimezoneConfigOption $configOption;

public function setUp(): void
{
$this->configOption = new TimezoneConfigOption();
}

/** @test */
public function returnsExpectedEnvVar(): void
{
self::assertEquals('TIMEZONE', $this->configOption->getEnvVar());
}

/**
* @test
* @dataProvider provideValidAnswers
*/
public function expectedQuestionIsAsked(?string $answer, string $expectedAnswer): void
{
$io = $this->prophesize(StyleInterface::class);
$ask = $io->ask(
'Set the timezone in which your Shlink instance is running (leave empty to use the one set in PHP config)',
)->willReturn($answer);

$answer = $this->configOption->ask($io->reveal(), new PathCollection());

self::assertEquals($expectedAnswer, $answer);
$ask->shouldHaveBeenCalledOnce();
}

public function provideValidAnswers(): iterable
{
yield ['the_answer', 'the_answer'];
yield [null, ''];
}

/**
* @test
* @dataProvider provideCurrentOptions
*/
public function shouldBeCalledOnlyIfItDoesNotYetExist(PathCollection $currentOptions, bool $expected): void
{
self::assertEquals($expected, $this->configOption->shouldBeAsked($currentOptions));
}

public function provideCurrentOptions(): iterable
{
yield 'not exists in config' => [new PathCollection(), true];
yield 'exists in config' => [new PathCollection(['TIMEZONE' => 'America/Los_Angeles']), false];
}
}
22 changes: 11 additions & 11 deletions test/Config/Util/ConfigOptionsValidatorsTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ protected function setUp(): void
* @test
* @dataProvider provideValidUrls
*/
public function webhooksAreProperlySplitAndValidated(?string $webhooks, array $expectedResult): void
public function urlsAreProperlySplitAndValidated(?string $urls, array $expectedResult): void
{
$result = $this->validators->splitAndValidateMultipleUrls($webhooks);
$result = $this->validators->splitAndValidateMultipleUrls($urls);
self::assertEquals($expectedResult, $result);
}

public function provideValidUrls(): iterable
{
yield 'no webhooks' => [null, []];
yield 'single webhook' => ['https://foo.com/bar', ['https://foo.com/bar']];
yield 'multiple webhook' => ['https://foo.com/bar,http://bar.io/foo/bar', [
yield 'no urls' => [null, []];
yield 'single url' => ['https://foo.com/bar', ['https://foo.com/bar']];
yield 'multiple urls' => ['https://foo.com/bar,http://bar.io/foo/bar', [
'https://foo.com/bar',
'http://bar.io/foo/bar',
]];
Expand All @@ -43,18 +43,18 @@ public function provideValidUrls(): iterable
* @test
* @dataProvider provideInvalidUrls
*/
public function webhooksFailWhenProvidedValueIsNotValidUrl(string $webhooks): void
public function splitUrlsFailWhenProvidedValueIsNotValidUrl(string $urls): void
{
$this->expectException(InvalidConfigOptionException::class);
$this->validators->splitAndValidateMultipleUrls($webhooks);
$this->validators->splitAndValidateMultipleUrls($urls);
}

public function provideInvalidUrls(): iterable
{
yield 'single invalid webhook' => ['invalid'];
yield 'first invalid webhook' => ['invalid,http://bar.io/foo/bar'];
yield 'last invalid webhook' => ['http://bar.io/foo/bar,invalid'];
yield 'middle invalid webhook' => ['http://bar.io/foo/bar,invalid,https://foo.com/bar'];
yield 'single invalid url' => ['invalid'];
yield 'first invalid url' => ['invalid,http://bar.io/foo/bar'];
yield 'last invalid url' => ['http://bar.io/foo/bar,invalid'];
yield 'middle invalid url' => ['http://bar.io/foo/bar,invalid,https://foo.com/bar'];
}

/** @test */
Expand Down
18 changes: 12 additions & 6 deletions test/Service/ShlinkAssetsHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,27 @@ public function setUp(): void
* @test
* @dataProvider provideConfigExists
*/
public function cachedConfigIsDeletedIfExists(bool $exists, int $expectedRemoveCalls): void
public function cachedConfigIsDeletedIfExists(bool $appExists, bool $routesExist, int $expectedRemoveCalls): void
{
$appConfigExists = $this->filesystem->exists('data/cache/app_config.php')->willReturn($exists);
$appConfigRemove = $this->filesystem->remove('data/cache/app_config.php')->willReturn(null);
$appConfigExists = $this->filesystem->exists('data/cache/app_config.php')->willReturn($appExists);
$routesConfigExists = $this->filesystem->exists('data/cache/fastroute_cached_routes.php')->willReturn(
$routesExist,
);
$configRemove = $this->filesystem->remove(Argument::containingString('data/cache'))->willReturn(null);

$this->assetsHandler->dropCachedConfigIfAny($this->io->reveal());

$appConfigExists->shouldHaveBeenCalledOnce();
$appConfigRemove->shouldHaveBeenCalledTimes($expectedRemoveCalls);
$routesConfigExists->shouldHaveBeenCalledOnce();
$configRemove->shouldHaveBeenCalledTimes($expectedRemoveCalls);
}

public function provideConfigExists(): iterable
{
yield 'no cached config' => [false, 0];
yield 'cached config' => [true, 1];
yield 'no cached app or route config' => [false, false, 0];
yield 'cached app config' => [true, false, 1];
yield 'cached route config' => [false, true, 1];
yield 'both configs cached' => [true, true, 2];
}

/** @test */
Expand Down

0 comments on commit 92f8093

Please sign in to comment.