From 0c791f6c15e048a69b010f7c549220c4ef51d91c Mon Sep 17 00:00:00 2001 From: Alexis Saettler Date: Tue, 28 Dec 2021 00:06:27 +0100 Subject: [PATCH] feat: improve reliability of pingversion (#5723) --- .github/workflows/tests.yml | 6 +- app/Console/Commands/PingVersionServer.php | 69 +++++--------- app/Http/Middleware/CheckVersion.php | 7 +- composer.json | 1 + composer.lock | 104 ++++++++++----------- database/factories/InstanceFactory.php | 6 +- tests/Commands/PingVersionServerTest.php | 77 +++++++++++++++ 7 files changed, 170 insertions(+), 100 deletions(-) create mode 100644 tests/Commands/PingVersionServerTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 911144eb54e..0faf6b76443 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -74,7 +74,8 @@ jobs: - name: Prepare environment run: | cp scripts/ci/.env.${{ matrix.connection }} .env - touch config/.version config/.release config/.commit + echo 'v2.17.0' > config/.version + touch config/.release config/.commit mkdir -p public/js public/css results/coverage {\ echo "{"; \ @@ -212,7 +213,8 @@ jobs: - name: Prepare environment run: | cp scripts/ci/.env.${{ matrix.connection }} .env - touch config/.version config/.release config/.commit + echo 'v2.17.0' > config/.version + touch config/.release config/.commit mkdir -p results/coverage results/cov results/console chmod -R 777 storage bootstrap/cache diff --git a/app/Console/Commands/PingVersionServer.php b/app/Console/Commands/PingVersionServer.php index 890d4664d6b..be1cbac50c4 100644 --- a/app/Console/Commands/PingVersionServer.php +++ b/app/Console/Commands/PingVersionServer.php @@ -2,12 +2,14 @@ namespace App\Console\Commands; -use GuzzleHttp\Client; -use function Safe\json_decode; +use PharIo\Version\Version; use App\Models\Contact\Contact; use Illuminate\Console\Command; use App\Models\Instance\Instance; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Http; use Illuminate\Console\ConfirmableTrait; +use Illuminate\Http\Client\RequestException; use Symfony\Component\Console\Output\OutputInterface; class PingVersionServer extends Command @@ -43,65 +45,44 @@ public function handle() } $instance = Instance::first(); + $instance->current_version = config('monica.app_version'); - // Prepare the json to query version.monicahq.com - $json = [ - 'uuid' => $instance->uuid, - 'version' => $instance->current_version, - 'contacts' => Contact::count(), - ]; - - $data = [ - 'uuid' => $instance->uuid, - 'version' => $instance->current_version, - 'contacts' => Contact::count(), - ]; - - // Send the JSON + // Query version.monicahq.com try { - $this->log('Call url:'.config('monica.weekly_ping_server_url')); - $client = new Client(); - $response = $client->post(config('monica.weekly_ping_server_url'), [ - 'json' => $data, - ]); - } catch (\GuzzleHttp\Exception\ConnectException $e) { - $this->log('ConnectException...'); - - return; - } catch (\GuzzleHttp\Exception\TransferException $e) { - $this->log('TransferException...'); + $this->log('Call url: '.config('monica.weekly_ping_server_url')); + $response = Http::acceptJson() + ->post(config('monica.weekly_ping_server_url'), [ + 'uuid' => $instance->uuid, + 'version' => $instance->current_version, + 'contacts' => Contact::count(), + ]) + ->throw(); + } catch (RequestException $e) { + $this->error('Error calling "'.config('monica.weekly_ping_server_url').'": '.$e->getMessage()); + Log::error(__CLASS__.' Error calling "'.config('monica.weekly_ping_server_url').'": '.$e->getMessage(), [$e]); return; } // Receive the JSON - $json = json_decode($response->getBody(), true); - - if (json_last_error() !== JSON_ERROR_NONE) { - // JSON is invalid - // The function json_last_error returns the last error occurred during the JSON encoding and decoding - $this->log('json error...'); + $json = $response->json(); - return; - } + $this->log('instance version: '.$instance->current_version); + $this->log('current version: '.$json['latest_version']); - // make sure the JSON has all the fields we need - if (! isset($json['latest_version']) || ! isset($json['new_version']) || ! isset($json['number_of_versions_since_user_version'])) { - return; - } + $latestVersion = new Version($json['latest_version']); + $currentVersion = new Version($instance->current_version); - $this->log('instance version:'.$instance->current_version); - $this->log('current version:'.$json['latest_version']); - if ($json['latest_version'] != $instance->current_version) { + if ($latestVersion > $currentVersion) { $instance->latest_version = $json['latest_version']; $instance->latest_release_notes = $json['notes']; $instance->number_of_versions_since_current_version = $json['number_of_versions_since_user_version']; - $instance->save(); } else { $instance->latest_release_notes = null; $instance->number_of_versions_since_current_version = null; - $instance->save(); } + + $instance->save(); } public function log($string) diff --git a/app/Http/Middleware/CheckVersion.php b/app/Http/Middleware/CheckVersion.php index b75b733f490..ba66a79b2b2 100644 --- a/app/Http/Middleware/CheckVersion.php +++ b/app/Http/Middleware/CheckVersion.php @@ -3,6 +3,7 @@ namespace App\Http\Middleware; use Closure; +use PharIo\Version\Version; use App\Models\Instance\Instance; class CheckVersion @@ -18,7 +19,11 @@ public function handle($request, Closure $next) { $instance = Instance::first(); - if ($instance->latest_version == config('monica.app_version')) { + $appVersion = new Version(config('monica.app_version')); + $latestVersion = new Version($instance->latest_version ?? '0.0.0'); + $currentVersion = new Version($instance->current_version ?? '0.0.0'); + + if ($latestVersion == $appVersion && $currentVersion != $latestVersion) { // The instance has been updated to the latest version. We reset // the ping data. diff --git a/composer.json b/composer.json index 19ddaab4f49..18e52c6beb5 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "monicahq/laravel-cloudflare": "^1.0", "monicahq/laravel-sabre": "^1.2", "ok/ipstack-client": "^1.2", + "phar-io/version": "^3.1", "pragmarx/countries-laravel": "^0", "pragmarx/google2fa": "^8.0", "pragmarx/google2fa-laravel": "^1.3", diff --git a/composer.lock b/composer.lock index 074f7267f18..e9a2bae76a7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c0c0b45e6b8264564db678658a42159c", + "content-hash": "0de09f23b917a3dfbe1fb19973079389", "packages": [ { "name": "asbiin/laravel-webauthn", @@ -5928,6 +5928,57 @@ }, "time": "2020-10-15T08:29:30+00:00" }, + { + "name": "phar-io/version", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "bae7c545bef187884426f042434e561ab1ddb182" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.1.0" + }, + "time": "2021-02-23T14:00:09+00:00" + }, { "name": "phenx/php-font-lib", "version": "0.5.4", @@ -15567,57 +15618,6 @@ }, "time": "2021-07-20T11:28:43+00:00" }, - { - "name": "phar-io/version", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" - }, - "time": "2021-02-23T14:00:09+00:00" - }, { "name": "php-webdriver/webdriver", "version": "1.12.0", diff --git a/database/factories/InstanceFactory.php b/database/factories/InstanceFactory.php index 7e4853b87fb..daffc277d6e 100644 --- a/database/factories/InstanceFactory.php +++ b/database/factories/InstanceFactory.php @@ -21,7 +21,11 @@ }); $factory->define(App\Models\Instance\Instance::class, function (Faker\Generator $faker) { - return []; + return [ + 'uuid' => $faker->uuid, + 'latest_version' => '1.0.0', + 'current_version' => '1.0.0', + ]; }); $factory->define(App\Models\Instance\Emotion\Emotion::class, function (Faker\Generator $faker) { diff --git a/tests/Commands/PingVersionServerTest.php b/tests/Commands/PingVersionServerTest.php new file mode 100644 index 00000000000..de3ca2251ad --- /dev/null +++ b/tests/Commands/PingVersionServerTest.php @@ -0,0 +1,77 @@ + 'https://version.test/ping']); + config(['monica.app_version' => '2.9.0']); + + Instance::all()->each(function ($instance) { + $instance->delete(); + }); + $instance = factory(Instance::class)->create(); + + $ret = [ + 'new_version' => true, + 'latest_version' => '3.1.0', + 'number_of_versions_since_user_version' => 2, + 'notes' => 'notes', + ]; + + Http::fake([ + 'https://version.test/*' => Http::response($ret, 200), + ]); + + $this->artisan('monica:ping'); + + $instance->refresh(); + + $this->assertEquals('3.1.0', $instance->latest_version); + $this->assertEquals('notes', $instance->latest_release_notes); + $this->assertEquals(2, $instance->number_of_versions_since_current_version); + } + + /** @test */ + public function it_clear_instance() + { + config(['monica.weekly_ping_server_url' => 'https://version.test/ping']); + config(['monica.app_version' => '3.1.0']); + + Instance::all()->each(function ($instance) { + $instance->delete(); + }); + $instance = factory(Instance::class)->create([ + 'latest_version' => '3.1.0', + ]); + + $ret = [ + 'new_version' => false, + 'latest_version' => '2.9.0', + 'number_of_versions_since_user_version' => 0, + 'notes' => '', + ]; + + Http::fake([ + 'https://version.test/*' => Http::response($ret, 200), + ]); + + $this->artisan('monica:ping'); + + $instance->refresh(); + + $this->assertEquals('3.1.0', $instance->latest_version); + $this->assertNull($instance->latest_release_notes); + $this->assertNull($instance->number_of_versions_since_current_version); + } +}