CluPilotCloud/tests/Feature/ReleaseVersionTest.php

126 lines
4.5 KiB
PHP

<?php
use App\Models\User;
use App\Services\Deployment\Release;
use Illuminate\Support\Facades\File;
/**
* What the console says it is running. The point of the distinction is that a
* bug report has to name the right code: a deployment somewhere after 1.0.0 is
* not 1.0.0, and reporting it as one sends someone reading the wrong source.
*/
function writeManifest(array $manifest): void
{
File::ensureDirectoryExists(storage_path('app'));
File::put(storage_path('app/deployment.json'), json_encode($manifest));
}
afterEach(fn () => File::delete(storage_path('app/deployment.json')));
it('reads the release number from the VERSION file', function () {
// One source of truth, and it is a file — a source archive, a shallow CI
// checkout and a container built without .git have no tags to describe.
expect(config('app.version'))->toBe(trim(File::get(base_path('VERSION'))))
->and(config('app.version'))->toMatch('/^\d+\.\d+\.\d+$/');
});
it('reports a pinned release as that release', function () {
writeManifest([
'version' => config('app.version'),
'commit' => 'abc1234567890',
'source' => 'refs/tags/v'.config('app.version'),
'mode' => 'release',
'deployed_at' => now()->toIso8601String(),
]);
$release = Release::current();
expect($release->isTaggedRelease)->toBeTrue()
->and($release->label())->toBe(config('app.version').' (abc1234)');
});
it('does not call a deployment after the release by the release\'s name', function () {
// Every commit after v1.0.0 still carries VERSION=1.0.0 and is not 1.0.0.
writeManifest([
'commit' => 'def4567890123',
'source' => 'main',
'mode' => 'branch',
'deployed_at' => now()->toIso8601String(),
]);
$release = Release::current();
expect($release->isTaggedRelease)->toBeFalse()
->and($release->label())->toBe(config('app.version').'-dev (def4567) · main');
});
it('keeps reporting the deployed version when an update fails halfway', function () {
// The checkout moves before the migrations run, so a run that dies in
// between leaves a newer VERSION on disk than is actually serving. Pairing
// that number with the still-deployed commit would describe a build that
// never existed.
writeManifest([
'version' => '0.9.0',
'commit' => 'aaa1111222333',
'source' => 'refs/tags/v0.9.0',
'mode' => 'release',
'deployed_at' => now()->subDay()->toIso8601String(),
]);
$release = Release::current();
expect($release->version)->toBe('0.9.0')
->and($release->version)->not->toBe(config('app.version'))
// Still a clean release label: 0.9.0 is genuinely what is running.
->and($release->isTaggedRelease)->toBeTrue()
->and($release->label())->toBe('0.9.0 (aaa1111)');
});
it('says something sensible before anything has been deployed', function () {
File::delete(storage_path('app/deployment.json'));
expect(Release::current()->commit)->toBeNull()
->and(Release::current()->label())->toBe(config('app.version').'-dev');
});
it('does not take the console down over an unparseable timestamp', function () {
writeManifest([
'version' => '1.0.0',
'commit' => 'abc1234567890',
'source' => 'main',
'mode' => 'branch',
'deployed_at' => 'not-a-date',
]);
// A line of small print in the sidebar must not 500 every admin page.
expect(Release::current()->deployedAt)->toBeNull()
->and(Release::current()->label())->toBe('1.0.0-dev (abc1234) · main');
$this->actingAs(User::factory()->operator()->create())
->get(route('admin.overview'))
->assertOk();
});
it('survives a manifest that is not readable json', function () {
File::ensureDirectoryExists(storage_path('app'));
File::put(storage_path('app/deployment.json'), '{ half-written');
// The console reporting nothing is a nuisance; the console 500ing because
// a deployment was interrupted mid-write is an outage.
expect(Release::current()->label())->toBe(config('app.version').'-dev');
});
it('shows the running version in the console', function () {
writeManifest([
'commit' => 'abc1234567890',
'source' => 'refs/tags/v'.config('app.version'),
'mode' => 'release',
'deployed_at' => now()->toIso8601String(),
]);
$this->actingAs(User::factory()->operator()->create())
->get(route('admin.overview'))
->assertOk()
->assertSee(config('app.version').' (abc1234)');
});