diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 5a31a2c..1ff7d83 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -3,7 +3,6 @@ name: Deploy VitePress site to Pages on: - # TODO: Change to tag? push: tags: - "v*" diff --git a/.github/workflows/run-lint.yml b/.github/workflows/run-lint.yml index fbec156..244438c 100644 --- a/.github/workflows/run-lint.yml +++ b/.github/workflows/run-lint.yml @@ -1,12 +1,22 @@ name: Lint on: push jobs: - pint: + mago: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: "laravel-pint" - uses: aglipanci/laravel-pint-action@2.0.0 + - name: "checkout" + uses: "actions/checkout@v4" + + - name: "installing PHP" + uses: "shivammathur/setup-php@v2" with: - verboseMode: true - testMode: true + php-version: "8.3" + + - name: "installing dependencies" + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: "formatting" + run: php vendor/bin/mago fmt --dry-run + + - name: "linting" + run: php vendor/bin/mago lint --reporting-format=github diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 0a3bdcd..6e111e0 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/composer.json b/composer.json index 6fe13fa..0f28b9e 100644 --- a/composer.json +++ b/composer.json @@ -14,10 +14,10 @@ "pixelfear/composer-dist-plugin": "^0.1.6" }, "require-dev": { - "laravel/pint": "^1.13", "orchestra/testbench": "^9.0", "pestphp/pest": "^3.0", - "pestphp/pest-plugin-laravel": "^3.0" + "pestphp/pest-plugin-laravel": "^3.0", + "carthage-software/mago": "^0.10.0" }, "autoload": { "psr-4": { @@ -48,12 +48,16 @@ "@php vendor/bin/testbench serve" ], "lint": [ - "@php vendor/bin/pint" + "@php vendor/bin/mago lint" + ], + "format": [ + "@php vendor/bin/mago format" ], "test": [ "XDEBUG_MODE=coverage vendor/bin/pest --coverage" ], "qa": [ + "@format", "@lint", "@test" ] @@ -76,7 +80,8 @@ "config": { "allow-plugins": { "pixelfear/composer-dist-plugin": true, - "pestphp/pest-plugin": true + "pestphp/pest-plugin": true, + "carthage-software/mago": true } } } diff --git a/composer.lock b/composer.lock index 8930772..b386177 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": "abcd34c90b4301ed7a554eda9022b6a1", + "content-hash": "a80f70290c736807dcdb304d5eeb05f7", "packages": [ { "name": "ajthinking/archetype", @@ -7792,6 +7792,59 @@ ], "time": "2024-12-11T14:50:44+00:00" }, + { + "name": "carthage-software/mago", + "version": "0.10.0", + "source": { + "type": "git", + "url": "https://github.com/carthage-software/mago.git", + "reference": "1d5a58f3c7892e08c8ed826216ad289e4fa6a305" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/carthage-software/mago/zipball/1d5a58f3c7892e08c8ed826216ad289e4fa6a305", + "reference": "1d5a58f3c7892e08c8ed826216ad289e4fa6a305", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.6", + "php": "~8.1 || ~8.2 || ~8.3 || ~8.4" + }, + "require-dev": { + "composer/composer": "^2.8" + }, + "bin": [ + "composer/bin/mago" + ], + "type": "composer-plugin", + "extra": { + "class": "Mago\\MagoPlugin" + }, + "autoload": { + "psr-4": { + "Mago\\": "composer/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT OR Apache-2.0" + ], + "description": "Mago is a toolchain for PHP that aims to provide a set of tools to help developers write better code.", + "keywords": [ + "dev" + ], + "support": { + "issues": "https://github.com/carthage-software/mago/issues", + "source": "https://github.com/carthage-software/mago/tree/0.10.0" + }, + "funding": [ + { + "url": "https://github.com/azjezz", + "type": "github" + } + ], + "time": "2025-02-16T02:32:40+00:00" + }, { "name": "doctrine/deprecations", "version": "1.1.4", @@ -8220,72 +8273,6 @@ }, "time": "2024-10-23T12:56:23+00:00" }, - { - "name": "laravel/pint", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/laravel/pint.git", - "reference": "8169513746e1bac70c85d6ea1524d9225d4886f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/8169513746e1bac70c85d6ea1524d9225d4886f0", - "reference": "8169513746e1bac70c85d6ea1524d9225d4886f0", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "ext-tokenizer": "*", - "ext-xml": "*", - "php": "^8.1.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.66.0", - "illuminate/view": "^10.48.25", - "larastan/larastan": "^2.9.12", - "laravel-zero/framework": "^10.48.25", - "mockery/mockery": "^1.6.12", - "nunomaduro/termwind": "^1.17.0", - "pestphp/pest": "^2.36.0" - }, - "bin": [ - "builds/pint" - ], - "type": "project", - "autoload": { - "psr-4": { - "App\\": "app/", - "Database\\Seeders\\": "database/seeders/", - "Database\\Factories\\": "database/factories/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "An opinionated code formatter for PHP.", - "homepage": "https://laravel.com", - "keywords": [ - "format", - "formatter", - "lint", - "linter", - "php" - ], - "support": { - "issues": "https://github.com/laravel/pint/issues", - "source": "https://github.com/laravel/pint" - }, - "time": "2024-12-30T16:20:10+00:00" - }, { "name": "laravel/tinker", "version": "v2.10.0", diff --git a/mago.toml b/mago.toml new file mode 100644 index 0000000..077fd1a --- /dev/null +++ b/mago.toml @@ -0,0 +1,11 @@ +[source] +paths = ["src", "tests"] +includes = ["vendor"] + +[format] +method_chain_break_threshold = 2 +null_type_hint = "question" + +[[linter.rules]] +name = "strictness/require-return-type" +ignore_arrow_function = true diff --git a/pint.json b/pint.json deleted file mode 100644 index 684f282..0000000 --- a/pint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "preset": "psr12" -} diff --git a/src/Abstracts/BackupPipe.php b/src/Abstracts/BackupPipe.php index de9f2d9..5dfbfc4 100644 --- a/src/Abstracts/BackupPipe.php +++ b/src/Abstracts/BackupPipe.php @@ -18,13 +18,17 @@ abstract public static function getKey(): string; * Run the restore process. * * @param string $path The path to the root of the backup file. + * @param Closure(string $path):string $next The next pipe in the chain. */ - abstract public function restore(string $path, Closure $next); + abstract public function restore(string $path, Closure $next): string; /** * Run the backup process. + * + * @param Zipper $zip The zipper instance. + * @param Closure(Zipper $zip):Zipper $next The next pipe in the chain. */ - abstract public function backup(Zipper $zip, Closure $next); + abstract public function backup(Zipper $zip, Closure $next): Zipper; /** * Get the directory path for the current pipe. @@ -37,7 +41,7 @@ protected function getDirectoryPath(string $path): string /** * Mark pipe as skipped. */ - protected function skip(string $reason, Closure $next, Zipper $zip) + protected function skip(string $reason, Closure $next, Zipper $zip): Zipper { $zip->addMeta(static::class, ['skipped' => $reason]); return $next($zip); diff --git a/src/Backuper.php b/src/Backuper.php index 00887c7..408f1cf 100644 --- a/src/Backuper.php +++ b/src/Backuper.php @@ -5,6 +5,8 @@ namespace Itiden\Backup; use Exception; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Pipeline; use Itiden\Backup\Contracts\Repositories\BackupRepository; use Itiden\Backup\Support\Zipper; @@ -15,7 +17,7 @@ final class Backuper { public function __construct( - protected BackupRepository $repository + protected BackupRepository $repository, ) { } @@ -36,7 +38,9 @@ public function backup(): BackupDto ->through(config('backup.pipeline')) ->thenReturn(); - if ($password = config('backup.password')) { + $password = config('backup.password'); + + if ($password) { $zipper->encrypt($password); } @@ -50,17 +54,23 @@ public function backup(): BackupDto $metadata = $backup->getMetadata(); - if ($user = auth()->user()) { + $user = auth()->user(); + + if ($user) { $metadata->setCreatedBy($user); } - $zipMeta->each(fn ($meta, $key) => match ($key) { - 'skipped' => $meta->each(fn (string $reason, string $pipe) => $metadata->addSkippedPipe($pipe, $reason)), - }); + $zipMeta->each( + static fn(Collection $meta, string $key): mixed => match ($key) { + 'skipped' => $meta->each(function (string $reason, string $pipe) use ($metadata): void { + $metadata->addSkippedPipe(pipe: $pipe, reason: $reason); + }), + }, + ); event(new BackupCreated($backup)); - @unlink($temp_zip_path); + File::delete($temp_zip_path); $this->enforceMaxBackups(); @@ -76,17 +86,22 @@ public function backup(): BackupDto } } - private function resolveMetaFromZip(Zipper $zip) + /** + * @return Collection> + */ + private function resolveMetaFromZip(Zipper $zip): Collection { - $metadata = collect([ - 'skipped' => collect(), - ]); - - $zip->getMeta()->each(function ($meta, $key) use ($metadata) { - if (isset($meta['skipped'])) { - $metadata->get('skipped')->put($key, $meta['skipped']); - } - }); + $metadata = collect(['skipped' => collect()]); + + $zip + ->getMeta() + ->each(static function (array|string $meta, string $key) use ($metadata): void { + if (is_array($meta) && isset($meta['skipped'])) { + $metadata + ->get('skipped') + ->put($key, $meta['skipped']); + } + }); return $metadata; } @@ -96,16 +111,17 @@ private function resolveMetaFromZip(Zipper $zip) */ private function enforceMaxBackups(): void { - if (!$max_backups = config('backup.max_backups', false)) { + $maxBackups = config('backup.max_backups', false); + if (!$maxBackups) { return; } $backups = $this->repository->all(); - if ($backups->count() > $max_backups) { - $backups->slice($max_backups)->each(function ($backup) { - $this->repository->remove($backup->timestamp); - }); + if ($backups->count() > $maxBackups) { + $backups + ->slice($maxBackups) + ->each(fn(BackupDto $backup): ?BackupDto => $this->repository->remove($backup->timestamp)); } } } diff --git a/src/Console/Commands/BackupCommand.php b/src/Console/Commands/BackupCommand.php index 82dfc6c..98dcaaf 100644 --- a/src/Console/Commands/BackupCommand.php +++ b/src/Console/Commands/BackupCommand.php @@ -5,6 +5,7 @@ namespace Itiden\Backup\Console\Commands; use Illuminate\Console\Command; +use Itiden\Backup\DataTransferObjects\BackupDto; use Itiden\Backup\Facades\Backuper; use function Laravel\Prompts\{info, spin}; @@ -18,9 +19,9 @@ final class BackupCommand extends Command protected $description = 'Run the backup pipeline'; - public function handle() + public function handle(): void { - $backup = spin(fn () => Backuper::backup(), 'Backing up...'); + $backup = spin(Backuper::backup(...), 'Backing up...'); info('Backup saved to ' . $backup->path); } diff --git a/src/Console/Commands/ClearFilesCommand.php b/src/Console/Commands/ClearFilesCommand.php index c58e601..6869e31 100644 --- a/src/Console/Commands/ClearFilesCommand.php +++ b/src/Console/Commands/ClearFilesCommand.php @@ -18,7 +18,7 @@ final class ClearFilesCommand extends Command protected $description = 'Clear the backup temp directory'; - public function handle() + public function handle(): void { if (!File::exists(config('backup.temp_path'))) { info('Backup temp directory does not exist, no need to clear it.'); diff --git a/src/Console/Commands/RestoreCommand.php b/src/Console/Commands/RestoreCommand.php index d54520b..25ea252 100644 --- a/src/Console/Commands/RestoreCommand.php +++ b/src/Console/Commands/RestoreCommand.php @@ -20,30 +20,33 @@ final class RestoreCommand extends Command protected $description = 'Reset or restore content from a directory / backup'; - public function handle(BackupRepository $repo) + public function handle(BackupRepository $repo): void { /* @var BackupDto $backup */ $backup = match (true) { (bool) $this->option('path') => BackupDto::fromAbsolutePath($this->option('path')), - default => BackupDto::fromFile(select( + default + => BackupDto::fromFile(select( label: 'Which backup do you want to restore to?', scroll: 10, - options: $repo->all()->flatMap( - fn (BackupDto $backup) => [$backup->path => $backup->path] - ), - required: true + options: $repo + ->all() + ->flatMap(static fn(BackupDto $backup): array => [$backup->path => $backup->path]), + required: true, )), }; if ( - $this->option('force') - || confirm( - label: "Are you sure you want to restore your content?", - hint: "This will overwrite your current content with state from {$backup->created_at->format('Y-m-d H:i:s')}", - required: true - ) + $this->option('force') || + confirm( + label: 'Are you sure you want to restore your content?', + hint: "This will overwrite your current content with state from {$backup->created_at->format( + 'Y-m-d H:i:s', + )}", + required: true, + ) ) { - spin(fn () => Restorer::restore($backup), 'Restoring backup'); + spin(static fn() => Restorer::restore($backup), 'Restoring backup'); info('Backup restored!'); } diff --git a/src/DataTransferObjects/BackupDto.php b/src/DataTransferObjects/BackupDto.php index b04ff47..cd461a5 100644 --- a/src/DataTransferObjects/BackupDto.php +++ b/src/DataTransferObjects/BackupDto.php @@ -31,7 +31,10 @@ public function getMetadata(): Metadata */ public static function fromFile(string $path): self { - $timestamp = str(basename($path))->afterLast('-')->before('.zip')->toString(); + $timestamp = str(basename($path)) + ->afterLast('-') + ->before('.zip') + ->toString(); $bytes = Storage::disk(config('backup.destination.disk'))->size($path); return new self( @@ -48,7 +51,10 @@ public static function fromFile(string $path): self */ public static function fromAbsolutePath(string $path): self { - $timestamp = str(basename($path))->afterLast('-')->before('.zip')->toString(); + $timestamp = str(basename($path)) + ->afterLast('-') + ->before('.zip') + ->toString(); $bytes = File::size($path); return new self( diff --git a/src/DataTransferObjects/ChunkyTestDto.php b/src/DataTransferObjects/ChunkyTestDto.php index 08f4c41..e29b016 100644 --- a/src/DataTransferObjects/ChunkyTestDto.php +++ b/src/DataTransferObjects/ChunkyTestDto.php @@ -18,9 +18,9 @@ public function __construct( /** * Create a new ChunkyTestDto from a request */ - public static function fromRequest(Request $request) + public static function fromRequest(Request $request): static { - return new self( + return new static( path: 'temp/' . $request->input('resumableIdentifier'), filename: $request->input('resumableFilename'), currentChunk: (int) $request->input('resumableChunkNumber'), diff --git a/src/DataTransferObjects/ChunkyUploadDto.php b/src/DataTransferObjects/ChunkyUploadDto.php index 1357cfb..605009e 100644 --- a/src/DataTransferObjects/ChunkyUploadDto.php +++ b/src/DataTransferObjects/ChunkyUploadDto.php @@ -9,6 +9,7 @@ final readonly class ChunkyUploadDto { + // @mago-ignore maintainability/excessive-parameter-list public function __construct( public string $path, public string $filename, @@ -23,9 +24,9 @@ public function __construct( /** * Create a new ChunkyUploadDto from a request */ - public static function fromRequest(Request $request) + public static function fromRequest(Request $request): static { - return new self( + return new static( path: 'temp/' . $request->input('resumableIdentifier'), filename: $request->input('resumableFilename'), totalChunks: (int) $request->input('resumableTotalChunks'), diff --git a/src/DataTransferObjects/SkippedPipeDto.php b/src/DataTransferObjects/SkippedPipeDto.php index bbe71ab..b09cce2 100644 --- a/src/DataTransferObjects/SkippedPipeDto.php +++ b/src/DataTransferObjects/SkippedPipeDto.php @@ -26,11 +26,8 @@ public function toArray(): array ]; } - public static function fromArray(array $array): self + public static function fromArray(array $array): static { - return new self( - pipe: $array['pipe'], - reason: $array['reason'], - ); + return new static(pipe: $array['pipe'], reason: $array['reason']); } } diff --git a/src/DataTransferObjects/UserActionDto.php b/src/DataTransferObjects/UserActionDto.php index ab42812..1dde8ba 100644 --- a/src/DataTransferObjects/UserActionDto.php +++ b/src/DataTransferObjects/UserActionDto.php @@ -35,11 +35,8 @@ public function toArray(): array ]; } - public static function fromArray(array $data): self + public static function fromArray(array $data): static { - return new self( - userId: $data['user_id'], - timestamp: $data['timestamp'], - ); + return new static(userId: $data['user_id'], timestamp: $data['timestamp']); } } diff --git a/src/Events/BackupCreated.php b/src/Events/BackupCreated.php index a1f4214..121aad7 100644 --- a/src/Events/BackupCreated.php +++ b/src/Events/BackupCreated.php @@ -8,7 +8,8 @@ final readonly class BackupCreated { - public function __construct(public BackupDto $backup) - { + public function __construct( + public BackupDto $backup, + ) { } } diff --git a/src/Events/BackupDeleted.php b/src/Events/BackupDeleted.php index 1045e6f..7920886 100644 --- a/src/Events/BackupDeleted.php +++ b/src/Events/BackupDeleted.php @@ -8,7 +8,8 @@ final readonly class BackupDeleted { - public function __construct(public BackupDto $backup) - { + public function __construct( + public BackupDto $backup, + ) { } } diff --git a/src/Events/BackupFailed.php b/src/Events/BackupFailed.php index 0e8304d..5b2d551 100644 --- a/src/Events/BackupFailed.php +++ b/src/Events/BackupFailed.php @@ -8,7 +8,8 @@ final readonly class BackupFailed { - public function __construct(public Exceptions\BackupFailed $exception) - { + public function __construct( + public Exceptions\BackupFailed $exception, + ) { } } diff --git a/src/Events/BackupRestored.php b/src/Events/BackupRestored.php index 99f6e59..04de420 100644 --- a/src/Events/BackupRestored.php +++ b/src/Events/BackupRestored.php @@ -9,7 +9,7 @@ final readonly class BackupRestored { public function __construct( - public BackupDto $backup + public BackupDto $backup, ) { } } diff --git a/src/Events/RestoreFailed.php b/src/Events/RestoreFailed.php index d6e7580..dd58880 100644 --- a/src/Events/RestoreFailed.php +++ b/src/Events/RestoreFailed.php @@ -8,7 +8,8 @@ final readonly class RestoreFailed { - public function __construct(public Exceptions\RestoreFailed $exception) - { + public function __construct( + public Exceptions\RestoreFailed $exception, + ) { } } diff --git a/src/Exceptions/RestoreFailed.php b/src/Exceptions/RestoreFailed.php index 5b7a0e1..8a735c7 100644 --- a/src/Exceptions/RestoreFailed.php +++ b/src/Exceptions/RestoreFailed.php @@ -12,11 +12,11 @@ final class RestoreFailed extends Exception { public function __construct( public BackupDto $backup, - ?Throwable $previous = null + ?Throwable $previous = null, ) { parent::__construct( message: __('statamic-backup::backup.restore.failed', ['name' => $backup->name]), - previous: $previous + previous: $previous, ); } } diff --git a/src/Facades/Backuper.php b/src/Facades/Backuper.php index b28bbf8..8923c2c 100644 --- a/src/Facades/Backuper.php +++ b/src/Facades/Backuper.php @@ -15,7 +15,7 @@ */ final class Backuper extends Facade { - public static function getFacadeAccessor() + public static function getFacadeAccessor(): string { return BackuperService::class; } diff --git a/src/Facades/Restorer.php b/src/Facades/Restorer.php index 3283912..eca9cfa 100644 --- a/src/Facades/Restorer.php +++ b/src/Facades/Restorer.php @@ -15,7 +15,7 @@ */ final class Restorer extends Facade { - public static function getFacadeAccessor() + public static function getFacadeAccessor(): string { return RestorerService::class; } diff --git a/src/Http/Controllers/Api/BackupController.php b/src/Http/Controllers/Api/BackupController.php index 118557c..b508671 100644 --- a/src/Http/Controllers/Api/BackupController.php +++ b/src/Http/Controllers/Api/BackupController.php @@ -14,28 +14,27 @@ public function __invoke(BackupRepository $repo): AnonymousResourceCollection { $backups = $repo->all(); - return BackupResource::collection($backups) - ->additional(['meta' => [ - // Required by statamic to render the table - 'columns' => [ - [ - 'label' => 'Name', - 'field' => 'name', - 'visible' => true, - ], - [ - 'label' => 'Created at', - 'field' => 'created_at', - 'visible' => true, - 'sortable' => true, - ], - [ - 'label' => 'Size', - 'field' => 'size', - 'visible' => true, - 'sortable' => true, - ] - ] - ]]); + return BackupResource::collection($backups)->additional(['meta' => [ + // Required by statamic to render the table + 'columns' => [ + [ + 'label' => 'Name', + 'field' => 'name', + 'visible' => true, + ], + [ + 'label' => 'Created at', + 'field' => 'created_at', + 'visible' => true, + 'sortable' => true, + ], + [ + 'label' => 'Size', + 'field' => 'size', + 'visible' => true, + 'sortable' => true, + ], + ], + ]]); } } diff --git a/src/Http/Controllers/Api/DestroyBackupController.php b/src/Http/Controllers/Api/DestroyBackupController.php index dfe4387..e89046c 100644 --- a/src/Http/Controllers/Api/DestroyBackupController.php +++ b/src/Http/Controllers/Api/DestroyBackupController.php @@ -14,8 +14,8 @@ public function __invoke(string $timestamp, BackupRepository $repo): JsonRespons { $backup = $repo->remove($timestamp); - return response()->json([ - 'message' => __('statamic-backup::backup.destroy.success', ['name' => $backup->name]) - ]); + return response()->json(['message' => __('statamic-backup::backup.destroy.success', [ + 'name' => $backup->name, + ])]); } } diff --git a/src/Http/Controllers/Api/RestoreController.php b/src/Http/Controllers/Api/RestoreController.php index f317290..210dce7 100644 --- a/src/Http/Controllers/Api/RestoreController.php +++ b/src/Http/Controllers/Api/RestoreController.php @@ -13,8 +13,6 @@ public function __invoke(string $timestamp): JsonResponse { Restorer::restoreFromTimestamp($timestamp); - return response()->json([ - 'message' => __('statamic-backup::backup.restore.success'), - ]); + return response()->json(['message' => __('statamic-backup::backup.restore.success')]); } } diff --git a/src/Http/Controllers/Api/RestoreFromPathController.php b/src/Http/Controllers/Api/RestoreFromPathController.php index cbc1356..5817ff4 100644 --- a/src/Http/Controllers/Api/RestoreFromPathController.php +++ b/src/Http/Controllers/Api/RestoreFromPathController.php @@ -20,8 +20,6 @@ public function __invoke(RestoreFromPathRequest $request): JsonResponse File::delete($request->validated('path')); } - return response()->json([ - 'message' => __('statamic-backup::backup.restore.success'), - ]); + return response()->json(['message' => __('statamic-backup::backup.restore.success')]); } } diff --git a/src/Http/Controllers/Api/StoreBackupController.php b/src/Http/Controllers/Api/StoreBackupController.php index ddf13fa..e4d7699 100644 --- a/src/Http/Controllers/Api/StoreBackupController.php +++ b/src/Http/Controllers/Api/StoreBackupController.php @@ -13,8 +13,6 @@ public function __invoke(): JsonResponse { $backup = Backuper::backup(); - return response()->json([ - 'message' => __('statamic-backup::backup.created', ['name' => $backup->name]), - ]); + return response()->json(['message' => __('statamic-backup::backup.created', ['name' => $backup->name])]); } } diff --git a/src/Http/Controllers/DownloadBackupController.php b/src/Http/Controllers/DownloadBackupController.php index 13fde5b..833625c 100644 --- a/src/Http/Controllers/DownloadBackupController.php +++ b/src/Http/Controllers/DownloadBackupController.php @@ -17,7 +17,9 @@ public function __invoke(string $timestamp, BackupRepository $repo): StreamedRes { $backup = $repo->find($timestamp); - $backup->getMetadata()->addDownload(auth()->user()); + $backup + ->getMetadata() + ->addDownload(auth()->user()); return Storage::disk(config('backup.destination.disk'))->download($backup->path); } diff --git a/src/Http/Controllers/UploadController.php b/src/Http/Controllers/UploadController.php index ceb371b..4dd1ba9 100644 --- a/src/Http/Controllers/UploadController.php +++ b/src/Http/Controllers/UploadController.php @@ -20,8 +20,6 @@ public function __invoke(ChunkyUploadRequest $request): JsonResponse public function test(Request $request): JsonResponse { - return Chunky::exists( - ChunkyTestDto::fromRequest($request) - ); + return Chunky::exists(ChunkyTestDto::fromRequest($request)); } } diff --git a/src/Http/Requests/ChunkyUploadRequest.php b/src/Http/Requests/ChunkyUploadRequest.php index a634869..8e4021a 100644 --- a/src/Http/Requests/ChunkyUploadRequest.php +++ b/src/Http/Requests/ChunkyUploadRequest.php @@ -8,7 +8,7 @@ final class ChunkyUploadRequest extends FormRequest { - public function rules() + public function rules(): array { return [ 'resumableIdentifier' => 'required|string', diff --git a/src/Http/Requests/RestoreFromPathRequest.php b/src/Http/Requests/RestoreFromPathRequest.php index d5fea8e..fb5c47f 100644 --- a/src/Http/Requests/RestoreFromPathRequest.php +++ b/src/Http/Requests/RestoreFromPathRequest.php @@ -8,7 +8,7 @@ final class RestoreFromPathRequest extends FormRequest { - public function rules() + public function rules(): array { return [ 'path' => 'required|string', diff --git a/src/Http/Resources/BackupResource.php b/src/Http/Resources/BackupResource.php index b516576..46a8293 100644 --- a/src/Http/Resources/BackupResource.php +++ b/src/Http/Resources/BackupResource.php @@ -11,7 +11,7 @@ */ final class BackupResource extends JsonResource { - public function toArray($request) + public function toArray($request): array { return [ 'name' => $this->name, @@ -19,7 +19,7 @@ public function toArray($request) 'path' => $this->path, 'timestamp' => $this->timestamp, 'size' => $this->size, - 'metadata' => new MetadataResource(resource: $this->getMetadata()), + 'metadata' => new MetadataResource(resource: $this->getMetadata()), ]; } } diff --git a/src/Http/Resources/MetadataResource.php b/src/Http/Resources/MetadataResource.php index a7de5d8..357d272 100644 --- a/src/Http/Resources/MetadataResource.php +++ b/src/Http/Resources/MetadataResource.php @@ -12,16 +12,18 @@ */ final class MetadataResource extends JsonResource { - public function toArray($request) + public function toArray($request): array { return [ 'created_by' => $this->getCreatedBy(), 'downloads' => $this->getDownloads(), 'restores' => $this->getRestores(), - 'skipped_pipes' => $this->getSkippedPipes()->map(fn (SkippedPipeDto $pipe) => [ - 'pipe' => $pipe->pipe::getKey(), - 'reason' => $pipe->reason, - ]), + 'skipped_pipes' => $this + ->getSkippedPipes() + ->map(static fn(SkippedPipeDto $pipe): array => [ + 'pipe' => $pipe->pipe::getKey(), + 'reason' => $pipe->reason, + ]), ]; } } diff --git a/src/Listeners/BackupDeletedListener.php b/src/Listeners/BackupDeletedListener.php index 5610b7e..5e8e278 100644 --- a/src/Listeners/BackupDeletedListener.php +++ b/src/Listeners/BackupDeletedListener.php @@ -8,8 +8,10 @@ final class BackupDeletedListener { - public function handle(BackupDeleted $event) + public function handle(BackupDeleted $event): void { - $event->backup->getMetadata()->delete(); + $event->backup + ->getMetadata() + ->delete(); } } diff --git a/src/Models/Metadata.php b/src/Models/Metadata.php index 7d79148..ccaf161 100644 --- a/src/Models/Metadata.php +++ b/src/Models/Metadata.php @@ -15,12 +15,12 @@ use Itiden\Backup\DataTransferObjects\SkippedPipeDto; use Itiden\Backup\DataTransferObjects\UserActionDto; +// @mago-ignore maintainability/too-many-methods final class Metadata { private Filesystem $filesystem; - /** @var int|string|null */ - private $createdBy = null; + private string|int|null $createdBy = null; /** @var UserActionDto[] */ private array $downloads; @@ -39,7 +39,7 @@ public function __construct( 'root' => config('backup.metadata_path') . '/.meta', ]); - $yaml = YAML::parse($this->filesystem->get($this->backup->timestamp) ?? ""); + $yaml = YAML::parse($this->filesystem->get($this->backup->timestamp) ?? ''); $this->createdBy = $yaml['created_by'] ?? null; $this->downloads = array_map(UserActionDto::fromArray(...), $yaml['downloads'] ?? []); @@ -56,29 +56,23 @@ public function getCreatedBy(): ?Authenticatable return User::find($this->createdBy); } - public function setCreatedBy(Authenticatable $user) + public function setCreatedBy(Authenticatable $user): void { $this->createdBy = $user->getAuthIdentifier(); $this->save(); } - public function addDownload(Authenticatable $user) + public function addDownload(Authenticatable $user): void { - $this->downloads[] = new UserActionDto( - userId: $user->getAuthIdentifier(), - timestamp: now()->toString(), - ); + $this->downloads[] = new UserActionDto(userId: $user->getAuthIdentifier(), timestamp: now()->toString()); $this->save(); } - public function addRestore(Authenticatable $user) + public function addRestore(Authenticatable $user): void { - $this->restores[] = new UserActionDto( - userId: $user->getAuthIdentifier(), - timestamp: now()->toString(), - ); + $this->restores[] = new UserActionDto(userId: $user->getAuthIdentifier(), timestamp: now()->toString()); $this->save(); } @@ -104,29 +98,28 @@ public function getSkippedPipes(): Collection * @param class-string $pipe The pipe that was skipped. * @param string $reason The reason why the pipe was skipped. */ - public function addSkippedPipe(string $pipe, string $reason) + public function addSkippedPipe(string $pipe, string $reason): void { - $this->skippedPipes[] = new SkippedPipeDto( - pipe: $pipe, - reason: $reason, - ); + $this->skippedPipes[] = new SkippedPipeDto(pipe: $pipe, reason: $reason); $this->save(); } - public function delete() + public function delete(): void { $this->filesystem->delete($this->backup->timestamp); } - - private function save() + private function save(): void { - $this->filesystem->put($this->backup->timestamp, YAML::dump([ - 'created_by' => $this->createdBy, - 'downloads' => array_map(fn (UserActionDto $action) => $action->toArray(), $this->downloads), - 'restores' => array_map(fn (UserActionDto $action) => $action->toArray(), $this->restores), - 'skipped_pipes' => array_map(fn (SkippedPipeDto $dto) => $dto->toArray(), $this->skippedPipes), - ])); + $this->filesystem->put( + $this->backup->timestamp, + YAML::dump([ + 'created_by' => $this->createdBy, + 'downloads' => array_map(fn(UserActionDto $action): array => $action->toArray(), $this->downloads), + 'restores' => array_map(fn(UserActionDto $action): array => $action->toArray(), $this->restores), + 'skipped_pipes' => array_map(fn(SkippedPipeDto $dto): array => $dto->toArray(), $this->skippedPipes), + ]), + ); } } diff --git a/src/Pipes/Assets.php b/src/Pipes/Assets.php index 3713fc9..8d59c5d 100644 --- a/src/Pipes/Assets.php +++ b/src/Pipes/Assets.php @@ -18,23 +18,26 @@ public static function getKey(): string return 'assets'; } - public function restore(string $backupPath, Closure $next) + public function restore(string $backupPath, Closure $next): string { AssetContainer::all() ->filter(static::isLocal(...)) - ->each(function ($container) use ($backupPath) { + ->each(function (Container $container) use ($backupPath): void { File::cleanDirectory($container->diskPath()); - File::copyDirectory("{$this->getDirectoryPath($backupPath)}/{$container->handle()}", $container->diskPath()); + File::copyDirectory( + "{$this->getDirectoryPath($backupPath)}/{$container->handle()}", + $container->diskPath(), + ); }); return $next($backupPath); } - public function backup(Zipper $zip, Closure $next) + public function backup(Zipper $zip, Closure $next): Zipper { AssetContainer::all() ->filter(static::isLocal(...)) - ->each(function ($container) use ($zip) { + ->each(function (Container $container) use ($zip): void { $zip->addDirectory($container->diskPath(), static::getKey() . '/' . $container->handle()); }); diff --git a/src/Pipes/Content.php b/src/Pipes/Content.php index 2725b77..9d1e687 100644 --- a/src/Pipes/Content.php +++ b/src/Pipes/Content.php @@ -16,7 +16,7 @@ public static function getKey(): string return 'content'; } - public function restore(string $restoringFromPath, Closure $next) + public function restore(string $restoringFromPath, Closure $next): string { $destination = config('backup.content_path'); @@ -26,12 +26,16 @@ public function restore(string $restoringFromPath, Closure $next) return $next($restoringFromPath); } - public function backup(Zipper $zip, Closure $next) + public function backup(Zipper $zip, Closure $next): Zipper { $contentPath = config('backup.content_path'); if (!File::exists($contentPath)) { - return $this->skip(reason: 'Content directory didn\'t exist, is it configured correctly?', next: $next, zip: $zip); + return $this->skip( + reason: 'Content directory didn\'t exist, is it configured correctly?', + next: $next, + zip: $zip, + ); } $zip->addDirectory($contentPath, static::getKey()); diff --git a/src/Pipes/Users.php b/src/Pipes/Users.php index a574c34..252d517 100644 --- a/src/Pipes/Users.php +++ b/src/Pipes/Users.php @@ -17,7 +17,7 @@ public static function getKey(): string return 'users'; } - public function restore(string $restoringFromPath, Closure $next) + public function restore(string $restoringFromPath, Closure $next): string { $destination = Stache::store('users')?->directory(); $users = $this->getDirectoryPath($restoringFromPath); @@ -27,16 +27,12 @@ public function restore(string $restoringFromPath, Closure $next) return $next($restoringFromPath); } - public function backup(Zipper $zip, Closure $next) + public function backup(Zipper $zip, Closure $next): Zipper { $usersDir = Stache::store('users')?->directory(); if (!File::exists($usersDir)) { - return $this->skip( - reason: 'No users found.', - next: $next, - zip: $zip - ); + return $this->skip(reason: 'No users found.', next: $next, zip: $zip); } $zip->addDirectory($usersDir, static::getKey()); diff --git a/src/Repositories/FileBackupRepository.php b/src/Repositories/FileBackupRepository.php index 1e0f7ba..1ed0c27 100644 --- a/src/Repositories/FileBackupRepository.php +++ b/src/Repositories/FileBackupRepository.php @@ -49,7 +49,7 @@ public function add(string $path): BackupDto $this->filesystem->putFileAs( path: $this->path, file: new StreamableFile($path), - name: $this->makeFilename($timestamp) + name: $this->makeFilename($timestamp), ); return $this->find($timestamp); @@ -83,7 +83,9 @@ public function remove(string $timestamp): ?BackupDto public function empty(): bool { - $this->all()->each(fn (BackupDto $backup) => $this->remove($backup->timestamp)); + $this + ->all() + ->each(fn(BackupDto $backup): ?BackupDto => $this->remove($backup->timestamp)); return Storage::disk(config('backup.destination.disk'))->deleteDirectory(config('backup.destination.path')); } } diff --git a/src/Restorer.php b/src/Restorer.php index 7909d55..ee4accf 100644 --- a/src/Restorer.php +++ b/src/Restorer.php @@ -19,7 +19,7 @@ final class Restorer { public function __construct( - protected BackupRepository $repository + protected BackupRepository $repository, ) { } @@ -64,8 +64,11 @@ public function restore(BackupDto $backup): void event(new BackupRestored($backup)); - if ($user = auth()->user()) { - $backup->getMetadata()->addRestore($user); + $user = auth()->user(); + if ($user) { + $backup + ->getMetadata() + ->addRestore($user); } File::cleanDirectory(config('backup.temp_path')); @@ -126,10 +129,12 @@ private function unzip(string $path): string { $target = config('backup.temp_path') . DIRECTORY_SEPARATOR . 'unzipping'; - Zipper::open($path, true)->extractTo($target, config('backup.password'))->close(); + Zipper::open($path, true) + ->extractTo($target, config('backup.password')) + ->close(); if (!collect(File::allFiles($target))->count()) { - throw new Exception("This backup is empty, perhaps you used the wrong password?"); + throw new Exception('This backup is empty, perhaps you used the wrong password?'); } return $target; diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index c9df63d..5fb0caf 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -10,6 +10,8 @@ use Itiden\Backup\Console\Commands\RestoreCommand; use Itiden\Backup\Contracts\Repositories\BackupRepository; use Itiden\Backup\Events\BackupDeleted; +use Statamic\Auth\Permissions as PermissionContract; +use Statamic\CP\Navigation\Nav as Navigation; use Statamic\Facades\CP\Nav; use Statamic\Facades\Permission; use Statamic\Providers\AddonServiceProvider; @@ -35,30 +37,21 @@ final class ServiceProvider extends AddonServiceProvider ], ]; - public function bootAddon() + public function bootAddon(): void { - $this->publishes([ - __DIR__ . '/../config/backup.php' => config_path('backup.php'), - ], 'backup-config'); - - $this->setUpPermissions(); - - Nav::extend(function ($nav) { - $nav->content('Backups') - ->can('manage backups') - ->section('Tools') - ->route('itiden.backup.index') - ->icon('table'); - }); + $this->publishes( + [ + __DIR__ . '/../config/backup.php' => config_path('backup.php'), + ], + 'backup-config', + ); - $this->commands([ - RestoreCommand::class, - BackupCommand::class, - ClearFilesCommand::class, - ]); + $this->configurePermissions(); + $this->configureNavigation(); + $this->configureCommands(); } - public function schedule(Schedule $schedule) + public function schedule(Schedule $schedule): void { if (!config('backup.schedule')) { return; @@ -66,35 +59,59 @@ public function schedule(Schedule $schedule) $frequency = config('backup.schedule.frequency'); - $schedule->command('statamic:backup')->$frequency(config('backup.schedule.time')); + $schedule + ->command('statamic:backup') + ->$frequency(config('backup.schedule.time')); } - public function register() + public function register(): void { - $this->mergeConfigFrom( - __DIR__ . '/../config/backup.php', - 'backup' - ); + $this->mergeConfigFrom(__DIR__ . '/../config/backup.php', 'backup'); - $this->app->bind( - BackupRepository::class, - config('backup.repository') - ); + $this->app->bind(BackupRepository::class, config('backup.repository')); + } + + private function configureCommands(): void + { + $this->commands([ + RestoreCommand::class, + BackupCommand::class, + ClearFilesCommand::class, + ]); + } + + private function configureNavigation(): void + { + Nav::extend(static function (Navigation $nav): void { + $nav + ->content('Backups') + ->can('manage backups') + ->section('Tools') + ->route('itiden.backup.index') + ->icon('table'); + }); } - private function setUpPermissions() + private function configurePermissions(): void { - Permission::extend(function () { - Permission::group('itiden-backup', 'Backup', function () { - Permission::register('manage backups') - ->label('Manage Backups') - ->children([ - Permission::make('create backups')->label('Create Backups'), - Permission::make('restore backups')->label('Restore From Backups'), - Permission::make('download backups')->label('Download Backups'), - Permission::make('delete backups')->label('Delete Backups'), - ]); - }); + Permission::extend(static function (PermissionContract $permission): void { + $permission->group('itiden-backup', 'Backup', static fn() => $permission + ->register('manage backups') + ->label('Manage Backups') + ->children([ + $permission + ->make('create backups') + ->label('Create Backups'), + $permission + ->make('restore backups') + ->label('Restore From Backups'), + $permission + ->make('download backups') + ->label('Download Backups'), + $permission + ->make('delete backups') + ->label('Delete Backups'), + ])); }); } } diff --git a/src/Support/Chunky.php b/src/Support/Chunky.php index 1fb29b9..0e3bb45 100644 --- a/src/Support/Chunky.php +++ b/src/Support/Chunky.php @@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Storage; use Itiden\Backup\DataTransferObjects\ChunkyTestDto; use Itiden\Backup\DataTransferObjects\ChunkyUploadDto; +use SplFileInfo; final class Chunky { @@ -40,14 +41,24 @@ public function put(ChunkyUploadDto $dto): JsonResponse return response()->json(['message' => 'Error saving chunk'], Response::HTTP_INTERNAL_SERVER_ERROR); } - $chunksOnDiskSize = collect($this->disk->allFiles($dto->path))->reduce(fn ($carry, $item) => $carry + $this->disk->size($item), 0); + $chunksOnDiskSize = collect($this->disk->allFiles($dto->path))->reduce( + fn(int $carry, string $item): int => $carry + $this->disk->size($item), + 0, + ); if ($chunksOnDiskSize < $dto->totalSize) { - return response()->json(['message' => 'uploaded ' . $dto->currentChunk . ' of ' . $dto->totalChunks], Response::HTTP_CREATED); + return response()->json( + ['message' => 'uploaded ' . $dto->currentChunk . ' of ' . $dto->totalChunks], + Response::HTTP_CREATED, + ); } - if ($completeFile = $this->mergeChunksIntoFile($dto->path, $dto->filename, $dto->totalChunks)) { - return response()->json(['message' => 'File successfully uploaded', 'file' => $completeFile], Response::HTTP_CREATED); + $completeFile = $this->mergeChunksIntoFile($dto->path, $dto->filename, $dto->totalChunks); + if ($completeFile) { + return response()->json( + ['message' => 'File successfully uploaded', 'file' => $completeFile], + Response::HTTP_CREATED, + ); } return response()->json(['message' => 'Error restoring file'], Response::HTTP_INTERNAL_SERVER_ERROR); @@ -59,9 +70,9 @@ public function put(ChunkyUploadDto $dto): JsonResponse public function mergeChunksIntoFile(string $path, string $filename, int $totalChunks): string { $fullPath = $this->path($path . '/' . $filename); - + $file = fopen($fullPath, 'w'); // create the complete file - if (($file = fopen($fullPath, 'w')) !== false) { + if ($file !== false) { for ($i = 1; $i <= $totalChunks; $i++) { fwrite($file, file_get_contents($fullPath . '.part' . $i)); info('writing chunk ' . $i); diff --git a/src/Support/Zipper.php b/src/Support/Zipper.php index 0f0f719..7607f20 100644 --- a/src/Support/Zipper.php +++ b/src/Support/Zipper.php @@ -28,7 +28,7 @@ public function __construct(string $path, int $flags = ZipArchive::CREATE | ZipA */ public static function open(string $path, bool $readOnly = false): self { - $flags = $readOnly ? ZipArchive::RDONLY : ZipArchive::CREATE | ZipArchive::OVERWRITE; + $flags = $readOnly ? ZipArchive::RDONLY : (ZipArchive::CREATE | ZipArchive::OVERWRITE); return new static($path, $flags); } @@ -48,7 +48,10 @@ public function encrypt(string $password): self { $this->zip->setPassword($password); - collect(range(0, $this->zip->numFiles - 1))->each(fn ($file) => $this->zip->setEncryptionIndex($file, ZipArchive::EM_AES_256)); + collect(range(0, $this->zip->numFiles - 1))->each(fn(int $file): bool => $this->zip->setEncryptionIndex( + $file, + ZipArchive::EM_AES_256, + )); return $this; } @@ -56,7 +59,7 @@ public function encrypt(string $password): self /** * Add a file to the archive. */ - public function addFile(string $path, string $name = null): self + public function addFile(string $path, ?string $name = null): self { $this->zip->addFile($path, $name ?? basename($path)); @@ -76,9 +79,9 @@ public function addFromString(string $name, string $content): self /** * Add a directory to the archive. */ - public function addDirectory(string $path, string $prefix = null): self + public function addDirectory(string $path, ?string $prefix = null): self { - collect(File::allFiles($path))->each(function (SplFileInfo $file) use ($prefix) { + collect(File::allFiles($path))->each(function (SplFileInfo $file) use ($prefix): void { $this->addFile($file->getPathname(), $prefix . '/' . $file->getRelativePathname()); }); @@ -131,7 +134,9 @@ public function addMeta(string $key, array|string $meta): self */ public function getMeta(): Collection { - if ($comment = $this->zip->getArchiveComment()) { + $comment = $this->zip->getArchiveComment(); + + if ($comment) { $this->meta = json_decode($comment, true); } diff --git a/tests/ArchitectureTest.php b/tests/ArchitectureTest.php index 8e6c4ac..1ceda52 100644 --- a/tests/ArchitectureTest.php +++ b/tests/ArchitectureTest.php @@ -1,12 +1,23 @@ preset()->strict()->ignoring(BackupPipe::class); - arch(null)->preset()->php(); - arch(null)->preset()->security(); - arch(null)->preset()->laravel(); +describe('arch', function (): void { + arch() + ->preset() + ->strict() + ->ignoring(BackupPipe::class); + arch() + ->preset() + ->php(); + arch() + ->preset() + ->security(); + arch() + ->preset() + ->laravel(); test('dtos are readonly') ->expect('Itiden\Backup\DataTransferObjects') diff --git a/tests/Feature/BackupMetadataTest.php b/tests/Feature/BackupMetadataTest.php index 7515234..c41e901 100644 --- a/tests/Feature/BackupMetadataTest.php +++ b/tests/Feature/BackupMetadataTest.php @@ -1,5 +1,7 @@ getMetadata(); @@ -18,7 +19,7 @@ expect($metadata)->toBeInstanceOf(Metadata::class); }); - it('creates a file if its missing', function () { + it('creates a file if its missing', function (): void { $backup = Backuper::backup(); $metadata = $backup->getMetadata(); @@ -32,7 +33,7 @@ expect($metadata)->toBeInstanceOf(Metadata::class); }); - it('can get the user that created the backup', function () { + it('can get the user that created the backup', function (): void { $backup = Backuper::backup(); $metadata = $backup->getMetadata(); @@ -46,7 +47,7 @@ expect($metadata->getCreatedBy())->toBe($user); }); - it('can get the downloads for a backup', function () { + it('can get the downloads for a backup', function (): void { Carbon::setTestNow('2021-01-01 00:00:00'); $backup = Backuper::backup(); @@ -59,12 +60,21 @@ $metadata->addDownload($user); expect($metadata->getDownloads())->toHaveCount(1); - expect($metadata->getDownloads()->first())->toBeInstanceOf(UserActionDto::class); - expect($metadata->getDownloads()->first()->getUser()->getAuthIdentifier())->toBe($user->getAuthIdentifier()); - expect($metadata->getDownloads()->first()->getTimestamp())->toEqual(Carbon::now()); + expect($metadata + ->getDownloads() + ->first())->toBeInstanceOf(UserActionDto::class); + expect($metadata + ->getDownloads() + ->first() + ->getUser() + ->getAuthIdentifier())->toBe($user->getAuthIdentifier()); + expect($metadata + ->getDownloads() + ->first() + ->getTimestamp())->toEqual(Carbon::now()); }); - it('can get the restores for a backup', function () { + it('can get the restores for a backup', function (): void { Carbon::setTestNow('2021-01-01 00:00:00'); $backup = Backuper::backup(); @@ -77,12 +87,21 @@ $metadata->addRestore($user); expect($metadata->getRestores())->toHaveCount(1); - expect($metadata->getRestores()->first())->toBeInstanceOf(UserActionDto::class); - expect($metadata->getRestores()->first()->getUser()->getAuthIdentifier())->toBe($user->getAuthIdentifier()); - expect($metadata->getRestores()->first()->getTimestamp())->toEqual(Carbon::now()); + expect($metadata + ->getRestores() + ->first())->toBeInstanceOf(UserActionDto::class); + expect($metadata + ->getRestores() + ->first() + ->getUser() + ->getAuthIdentifier())->toBe($user->getAuthIdentifier()); + expect($metadata + ->getRestores() + ->first() + ->getTimestamp())->toEqual(Carbon::now()); }); - it('can get the skipped pipes for a backup', function () { + it('can get the skipped pipes for a backup', function (): void { $backup = Backuper::backup(); $metadata = $backup->getMetadata(); @@ -92,11 +111,19 @@ $metadata->addSkippedPipe(pipe: UserPipe::class, reason: 'Some reason'); expect($metadata->getSkippedPipes())->toHaveCount(1); - expect($metadata->getSkippedPipes()->first()->pipe)->toBe(UserPipe::class); - expect($metadata->getSkippedPipes()->first()->reason)->toBe('Some reason'); + expect( + $metadata + ->getSkippedPipes() + ->first()->pipe, + )->toBe(UserPipe::class); + expect( + $metadata + ->getSkippedPipes() + ->first()->reason, + )->toBe('Some reason'); }); - it('stores metadata files in the correct directory', function () { + it('stores metadata files in the correct directory', function (): void { $backup = Backuper::backup(); $metadata = $backup->getMetadata(); diff --git a/tests/Feature/ClearTempTest.php b/tests/Feature/ClearTempTest.php index f016331..829fd0a 100644 --- a/tests/Feature/ClearTempTest.php +++ b/tests/Feature/ClearTempTest.php @@ -1,27 +1,31 @@ artisan('statamic:backup:temp-clear')->assertExitCode(0); + $this + ->artisan('statamic:backup:temp-clear') + ->assertExitCode(0); }); - it("will clear temp path when running backup clear command", function () { + it('will clear temp path when running backup clear command', function (): void { $temp_path = config('backup.temp_path'); File::ensureDirectoryExists($temp_path); File::put($temp_path . '/testfile.txt', 'lorem ipsum'); - expect(File::allFiles($temp_path))->toHaveCount(1); + expect(File::files($temp_path))->toHaveCount(1); $this->artisan('statamic:backup:temp-clear'); - expect(File::allFiles($temp_path))->toHaveCount(0); + expect(File::files($temp_path))->toHaveCount(0); }); })->group('console'); diff --git a/tests/Feature/CreateBackupTest.php b/tests/Feature/CreateBackupTest.php index 1f3ea77..734b654 100644 --- a/tests/Feature/CreateBackupTest.php +++ b/tests/Feature/CreateBackupTest.php @@ -1,5 +1,7 @@ status())->toBe(401); }); - it('cant create a backup by a user without permissons a backup', function () { + it('cant create a backup by a user without permissons a backup', function (): void { actingAs(user()); $responseJson = postJson(cp_route('api.itiden.backup.store')); @@ -28,49 +30,64 @@ expect($responseJson->status())->toBe(403); }); - it('can create a backup by a user with create backups permission', function () { + it('can create a backup by a user with create backups permission', function (): void { $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); actingAs($user); $responseJson = postJson(cp_route('api.itiden.backup.store')); - $responseJson->assertJsonStructure([ 'message', ]); - expect(app(BackupRepository::class)->all()->count())->toBe(1); + expect(app(BackupRepository::class) + ->all() + ->count())->toBe(1); }); - it('can create backup from command', function () { - expect(app(BackupRepository::class)->all()->count())->toBe(0); + it('can create backup from command', function (): void { + expect(app(BackupRepository::class) + ->all() + ->count())->toBe(0); - $this->artisan('statamic:backup') + $this + ->artisan('statamic:backup') ->assertExitCode(0); - expect(app(BackupRepository::class)->all()->count())->toBe(1); + expect(app(BackupRepository::class) + ->all() + ->count())->toBe(1); }); - it('dispatches backup created event', function () { + it('dispatches backup created event', function (): void { Event::fake(); $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); actingAs($user); postJson(cp_route('api.itiden.backup.store')); - Event::assertDispatched(BackupCreated::class, function ($event) { - return $event->backup->name === app(BackupRepository::class)->all()->first()->name; + Event::assertDispatched(BackupCreated::class, function (BackupCreated $event): bool { + return ( + $event->backup->name === + app(BackupRepository::class) + ->all() + ->first()->name + ); }); }); - it('dispatches failed event when error occurs', function () { + it('dispatches failed event when error occurs', function (): void { Event::fake(); // Set invalid pipeline to force an error @@ -78,7 +95,9 @@ $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); actingAs($user); @@ -87,22 +106,30 @@ Event::assertDispatched(BackupFailed::class); }); - it('sets created by metadata when user is authenticated', function () { + it('sets created by metadata when user is authenticated', function (): void { $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); actingAs($user); postJson(cp_route('api.itiden.backup.store')); - expect(app(BackupRepository::class)->all()->first()->getMetadata()->getCreatedBy())->toBe($user); + expect(app(BackupRepository::class) + ->all() + ->first() + ->getMetadata() + ->getCreatedBy())->toBe($user); }); - it('adds skipped pipes to meta', function () { + it('adds skipped pipes to meta', function (): void { $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); config()->set('backup.pipeline', [ ...config('backup.pipeline'), @@ -113,17 +140,23 @@ postJson(cp_route('api.itiden.backup.store')); - expect(app(BackupRepository::class)->all()->first()->getMetadata()->getSkippedPipes())->toHaveCount(1); + expect(app(BackupRepository::class) + ->all() + ->first() + ->getMetadata() + ->getSkippedPipes())->toHaveCount(1); }); - it('can encrypt backup with password', function () { + it('can encrypt backup with password', function (): void { config()->set('backup.password', 'password'); $backup = Backuper::backup(); config()->set('backup.password', null); - expect(fn () => Restorer::restore($backup))->toThrow(RestoreFailed::class, trans('statamic-backup::backup.restore.failed', ['name' => $backup->name])); + expect(static fn() => Restorer::restore($backup))->toThrow( + RestoreFailed::class, + trans('statamic-backup::backup.restore.failed', ['name' => $backup->name]), + ); }); -}) - ->group('create backup'); +})->group('create backup'); diff --git a/tests/Feature/DeleteBackupTest.php b/tests/Feature/DeleteBackupTest.php index c99216f..8de3da9 100644 --- a/tests/Feature/DeleteBackupTest.php +++ b/tests/Feature/DeleteBackupTest.php @@ -1,13 +1,15 @@ timestamp)); @@ -16,7 +18,7 @@ expect(app(BackupRepository::class)->all())->toHaveCount(1); }); - it('cant be deleted by a user without delete permisson', function () { + it('cant be deleted by a user without delete permisson', function (): void { $backup = Backuper::backup(); actingAs(user()); @@ -27,12 +29,14 @@ expect(app(BackupRepository::class)->all())->toHaveCount(1); }); - it('can be deleted by a user with delete backups permission', function () { + it('can be deleted by a user with delete backups permission', function (): void { $backup = Backuper::backup(); $user = user(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); diff --git a/tests/Feature/DownloadBackupTest.php b/tests/Feature/DownloadBackupTest.php index 8acbc99..75efe38 100644 --- a/tests/Feature/DownloadBackupTest.php +++ b/tests/Feature/DownloadBackupTest.php @@ -1,5 +1,7 @@ timestamp)); @@ -17,7 +18,7 @@ expect($responseJson->status())->toBe(401); }); - it('cant be downloaded by a user without permissons a backup', function () { + it('cant be downloaded by a user without permissons a backup', function (): void { $backup = Backuper::backup(); actingAs(user()); @@ -27,7 +28,7 @@ expect($responseJson->status())->toBe(403); }); - it('can be downloaded by a user with download backups permission', function (string $disk) { + it('can be downloaded by a user with download backups permission', function (string $disk): void { Storage::fake($disk); config()->set('backup.destination.disk', $disk); @@ -35,7 +36,9 @@ $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); actingAs($user); @@ -44,12 +47,14 @@ expect($response)->assertDownload(); })->with(['s3', 'local']); - it('adds a download action to the metadata', function () { + it('adds a download action to the metadata', function (): void { $backup = Backuper::backup(); $user = user(); - $user->assignRole('admin')->save(); + $user + ->assignRole('admin') + ->save(); actingAs($user); diff --git a/tests/Feature/RestoreBackupTest.php b/tests/Feature/RestoreBackupTest.php index 7b5973d..316a464 100644 --- a/tests/Feature/RestoreBackupTest.php +++ b/tests/Feature/RestoreBackupTest.php @@ -1,5 +1,7 @@ status())->toBe(Response::HTTP_UNAUTHORIZED); }); - it('cant restore by timestamp by a user without permissons a backup', function () { + it('cant restore by timestamp by a user without permissons a backup', function (): void { actingAs(user()); $response = postJson(cp_route('api.itiden.backup.restore', 'timestamp')); @@ -25,10 +27,12 @@ expect($response->status())->toBe(Response::HTTP_FORBIDDEN); }); - it('returns error if backup is not found', function () { + it('returns error if backup is not found', function (): void { $user = user(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); @@ -37,12 +41,14 @@ expect($response->status())->toBe(Response::HTTP_INTERNAL_SERVER_ERROR); }); - it('can restore by timestamp', function () { + it('can restore by timestamp', function (): void { $backup = Backuper::backup(); $user = user(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); @@ -51,60 +57,73 @@ expect($response->status())->toBe(Response::HTTP_OK); }); - it('dispatches backup restored event', function () { + it('dispatches backup restored event', function (): void { Event::fake(); $backup = Backuper::backup(); $user = user(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); $response = postJson(cp_route('api.itiden.backup.restore', $backup->timestamp)); - Event::assertDispatched(BackupRestored::class, function ($event) use ($backup) { + Event::assertDispatched(BackupRestored::class, function (BackupRestored $event) use ($backup): bool { return $event->backup->timestamp === $backup->timestamp; }); expect($response->status())->toBe(Response::HTTP_OK); }); - it('will not restore from command if you say no', function () { + it('will not restore from command if you say no', function (): void { $backup = Backuper::backup(); File::cleanDirectory(config('backup.content_path')); - $this->artisan('statamic:backup:restore', ['--path' => Storage::path($backup->path)]) + $this + ->artisan('statamic:backup:restore', ['--path' => Storage::path($backup->path)]) ->expectsConfirmation('Are you sure you want to restore your content?', 'no'); expect(File::isEmptyDirectory(config('backup.content_path')))->toBeTrue(); - $this->artisan('statamic:backup:restore', ['--path' => Storage::path($backup->path), '--force' => true]) + $this + ->artisan('statamic:backup:restore', ['--path' => Storage::path($backup->path), '--force' => true]) ->assertExitCode(0); }); - it('can restore from path command', function () { + it('can restore from path command', function (): void { $backup = Backuper::backup(); - $this->artisan('statamic:backup:restore', ['--path' => Storage::path($backup->path), '--force' => true]) + $this + ->artisan('statamic:backup:restore', ['--path' => Storage::path($backup->path), '--force' => true]) ->assertExitCode(0); expect(File::isEmptyDirectory(config('backup.content_path')))->toBeFalse(); }); - it('will add an restore entry to metadata', function () { + it('will add an restore entry to metadata', function (): void { $backup = Backuper::backup(); $user = user(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); $response = postJson(cp_route('api.itiden.backup.restore', $backup->timestamp)); expect($response->status())->toBe(Response::HTTP_OK); - expect($backup->getMetadata()->getRestores())->toHaveCount(1); - expect($backup->getMetadata()->getRestores()[0]->userId)->toBe($user->id); + expect($backup + ->getMetadata() + ->getRestores())->toHaveCount(1); + expect( + $backup + ->getMetadata() + ->getRestores()[0]->userId, + )->toBe($user->id); }); })->group('restore backup'); diff --git a/tests/Feature/RestoreCommandTest.php b/tests/Feature/RestoreCommandTest.php index 89cfa55..aa81705 100644 --- a/tests/Feature/RestoreCommandTest.php +++ b/tests/Feature/RestoreCommandTest.php @@ -1,13 +1,15 @@ empty(); Backuper::backup(); @@ -15,20 +17,19 @@ $backups = app(BackupRepository::class)->all(); artisan('statamic:backup:restore') - ->expectsQuestion( - question: 'Which backup do you want to restore to?', - answer: $backups->first()->path - ) + ->expectsQuestion(question: 'Which backup do you want to restore to?', answer: $backups->first()->path) ->expectsConfirmation('Are you sure you want to restore your content?') ->assertFailed(); }); - it('can restore from a specific path', function () { + it('can restore from a specific path', function (): void { app(BackupRepository::class)->empty(); $backup = Backuper::backup(); - artisan('statamic:backup:restore', ['--path' => Storage::disk(config('backup.destination.disk'))->path($backup->path)]) + artisan('statamic:backup:restore', ['--path' => Storage::disk(config('backup.destination.disk'))->path( + $backup->path, + )]) ->expectsConfirmation('Are you sure you want to restore your content?') ->assertFailed(); }); diff --git a/tests/Feature/RestoreFromPathTest.php b/tests/Feature/RestoreFromPathTest.php index f98b6b0..2e7f9cd 100644 --- a/tests/Feature/RestoreFromPathTest.php +++ b/tests/Feature/RestoreFromPathTest.php @@ -1,5 +1,7 @@ assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); @@ -30,12 +34,14 @@ expect($response->status())->toBe(Response::HTTP_OK); }); - it('can restore from path and delete after', function () { + it('can restore from path and delete after', function (): void { $backup = Backuper::backup(); $user = user(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); @@ -50,7 +56,7 @@ expect(File::exists($path))->toBeFalse(); }); - it("will not restore empty archives and dispatches failed event", function () { + it('will not restore empty archives and dispatches failed event', function (): void { Event::fake(); $user = user(); @@ -62,7 +68,9 @@ ->encrypt('not-the-password-we-decrypt-with') ->close(); - $user->assignRole('super admin')->save(); + $user + ->assignRole('super admin') + ->save(); actingAs($user); @@ -75,7 +83,8 @@ expect($response->status())->toBe(Response::HTTP_INTERNAL_SERVER_ERROR); }); -})->group('restore-from-path') - ->afterEach(function () { +}) + ->group('restore-from-path') + ->afterEach(function (): void { File::cleanDirectory(config('backup.temp_path')); }); diff --git a/tests/Feature/ViewBackupsTest.php b/tests/Feature/ViewBackupsTest.php index b2adff2..cf09b62 100644 --- a/tests/Feature/ViewBackupsTest.php +++ b/tests/Feature/ViewBackupsTest.php @@ -1,5 +1,7 @@ get(cp_route('itiden.backup.index')) +describe('api:view', function (): void { + test('guest cant view backups', function (): void { + $this + ->get(cp_route('itiden.backup.index')) ->assertRedirect(cp_route('login')); }); - test('user without permission cant view backups', function () { + test('user without permission cant view backups', function (): void { $this->withoutVite(); actingAs(user()); - get(cp_route('itiden.backup.index')) - ->assertRedirect(); + get(cp_route('itiden.backup.index'))->assertRedirect(); }); - test('user with permission can view backups', function () { + test('user with permission can view backups', function (): void { $this->withoutVite(); $user = user(); - $user->set('roles', ['admin'])->save(); + $user + ->set('roles', ['admin']) + ->save(); actingAs($user); @@ -36,62 +40,62 @@ ->assertViewIs('itiden-backup::backups'); }); - test('user without permission cant get backups from api', function () { + test('user without permission cant get backups from api', function (): void { $this->withoutVite(); $user = user(); actingAs($user); - getJson(cp_route('api.itiden.backup.index')) - ->assertForbidden(); + getJson(cp_route('api.itiden.backup.index'))->assertForbidden(); }); - test('user with permission can get backups from api', function () { + test('user with permission can get backups from api', function (): void { $this->withoutVite(); $this->withoutExceptionHandling(); $user = user(); - $user->set('roles', ['admin'])->save(); + $user + ->set('roles', ['admin']) + ->save(); actingAs($user); $backup = Backuper::backup(); // Set some metadata so we can test it has correct structure - $backup->getMetadata()->addDownload($user); - $backup->getMetadata()->addRestore($user); - $backup->getMetadata()->addSkippedPipe(Users::class, 'Oh no it failed!'); - + $backup + ->getMetadata() + ->addDownload($user); + $backup + ->getMetadata() + ->addRestore($user); + $backup + ->getMetadata() + ->addSkippedPipe(Users::class, 'Oh no it failed!'); getJson(cp_route('api.itiden.backup.index')) ->assertOk() ->assertJsonStructure([ - 'data' => [ - '*' => [ - 'name', - 'size', - 'path', - 'created_at', - 'timestamp', - 'metadata' => [ - 'created_by', - 'downloads', - 'restores', - 'skipped_pipes', - ] + 'data' => ['*' => [ + 'name', + 'size', + 'path', + 'created_at', + 'timestamp', + 'metadata' => [ + 'created_by', + 'downloads', + 'restores', + 'skipped_pipes', ], - ], - 'meta' => [ - 'columns' => [ - '*' => [ - 'label', - 'field', - 'visible', - ], - ] - ] + ]], + 'meta' => ['columns' => ['*' => [ + 'label', + 'field', + 'visible', + ]]], ]); }); })->group('view'); diff --git a/tests/Helpers.php b/tests/Helpers.php index 57ed9d0..f296006 100644 --- a/tests/Helpers.php +++ b/tests/Helpers.php @@ -2,12 +2,17 @@ declare(strict_types=1); +namespace Itiden\Backup\Tests; + +use Illuminate\Support\Collection; use Illuminate\Support\Facades\File; /** * Split a file into chunks + * + * @return Collection */ -function chunkFile(string $file, string $path, int $buffer = 1024) +function chunk_file(string $file, string $path, int $buffer = 1024): Collection { File::ensureDirectoryExists($path); diff --git a/tests/Pest.php b/tests/Pest.php index 31cb057..42bfa11 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,7 @@ afterEach(fn () => app(BackupRepository::class)->empty()) + ->afterEach(fn(): bool => app(BackupRepository::class)->empty()) ->in(__DIR__); function user(): StatamicUser diff --git a/tests/SkippingPipe.php b/tests/SkippingPipe.php index 07f9001..8e1c4f5 100644 --- a/tests/SkippingPipe.php +++ b/tests/SkippingPipe.php @@ -1,5 +1,7 @@ skip(reason: 'This pipe is skipped', next: $next, zip: $zip); } diff --git a/tests/TestCase.php b/tests/TestCase.php index c2ba058..56c60a8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,5 +1,7 @@ 'app-with-many-dashes']); $fakeTime = Carbon::parse('2021-01-01 12:00:00'); diff --git a/tests/Unit/BackupRepositoryTest.php b/tests/Unit/BackupRepositoryTest.php index ec9691b..b1f9ad1 100644 --- a/tests/Unit/BackupRepositoryTest.php +++ b/tests/Unit/BackupRepositoryTest.php @@ -1,5 +1,7 @@ all(); @@ -18,7 +20,7 @@ expect($backups->first())->toBeInstanceOf(BackupDto::class); }); - it('can get backup by timestamp', function () { + it('can get backup by timestamp', function (): void { $backup = Backuper::backup(); $backupByTimestamp = app(BackupRepository::class)->find($backup->timestamp); @@ -27,20 +29,22 @@ expect($backupByTimestamp)->toEqual($backup); }); - it("returns null when timestamp doesnt exist", function () { + it('returns null when timestamp doesnt exist', function (): void { $backup = app(BackupRepository::class)->find('1234567890'); expect($backup)->toBeNull(); }); - it('can remove all backups', function () { + it('can remove all backups', function (): void { Backuper::backup(); app(BackupRepository::class)->empty(); - expect(app(BackupRepository::class)->all()->count())->toBe(0); + expect(app(BackupRepository::class) + ->all() + ->count())->toBe(0); }); - it('dispatches backup removed event', function () { + it('dispatches backup removed event', function (): void { Event::fake(); $backup = Backuper::backup(); @@ -49,7 +53,7 @@ Event::assertDispatched(BackupDeleted::class); }); - it('removes all metadata files when removing all backups', function () { + it('removes all metadata files when removing all backups', function (): void { Backuper::backup(); app(BackupRepository::class)->empty(); @@ -57,14 +61,14 @@ expect(Storage::disk('local')->files(storage_path('statamic-backup/.metadata')))->toBeEmpty(); }); - - it('can delete backup by timestamp', function () { + it('can delete backup by timestamp', function (): void { $backup = Backuper::backup(); $backup = app(BackupRepository::class)->remove($backup->timestamp); expect($backup)->toBeInstanceOf(BackupDto::class); - expect(Storage::disk(config('backup.destination.disk')) - ->exists(config('backup.destination.path') . "/{$backup->name}.zip"))->toBeFalse(); + expect(Storage::disk(config('backup.destination.disk'))->exists( + config('backup.destination.path') . "/{$backup->name}.zip", + ))->toBeFalse(); }); })->group('backuprepository'); diff --git a/tests/Unit/BackuperTest.php b/tests/Unit/BackuperTest.php index b0b43a4..09479c1 100644 --- a/tests/Unit/BackuperTest.php +++ b/tests/Unit/BackuperTest.php @@ -1,5 +1,7 @@ toBeInstanceOf(BackupDto::class); - expect(Storage::disk(config('backup.destination.disk')) - ->exists(config('backup.destination.path') . "/{$backup->name}.zip"))->toBeTrue(); + expect(Storage::disk(config('backup.destination.disk'))->exists( + config('backup.destination.path') . "/{$backup->name}.zip", + ))->toBeTrue(); }); - it('backups correct files', function () { + it('backups correct files', function (): void { $backup = Backuper::backup(); $unzipped = config('backup.temp_path') . '/unzipped'; - Zipper::open( - Storage::disk(config('backup.destination.disk')) - ->path($backup->path), - true - ) - ->extractTo( - $unzipped, - config('backup.password'), - ); - - expect(File::allFiles($unzipped)[0]->getRelativePathname()) - ->toEqual('content/collections/pages/homepage.yaml'); + Zipper::open(Storage::disk(config('backup.destination.disk'))->path($backup->path), true)->extractTo( + $unzipped, + config('backup.password'), + ); + + expect(File::allFiles($unzipped)[0]->getRelativePathname())->toEqual('content/collections/pages/homepage.yaml'); }); - it('can enforce max backups', function () { + it('can enforce max backups', function (): void { config()->set('backup.max_backups', 5); for ($i = 0; $i < 10; $i++) { @@ -44,18 +41,22 @@ Carbon::setTestNow(Carbon::now()->addDays($i)); Backuper::backup(); - expect(app(BackupRepository::class)->all()->count())->toBeLessThanOrEqual(5); + expect(app(BackupRepository::class) + ->all() + ->count())->toBeLessThanOrEqual(5); } }); - it('doesnt enforce max backups when it is disabled', function () { + it('doesnt enforce max backups when it is disabled', function (): void { config()->set('backup.max_backups', false); for ($i = 0; $i < 10; $i++) { Carbon::setTestNow(Carbon::now()->addDays($i)); Backuper::backup(); - expect(app(BackupRepository::class)->all()->count())->toBe($i + 1); + expect(app(BackupRepository::class) + ->all() + ->count())->toBe($i + 1); } }); })->group('backuper'); diff --git a/tests/Unit/ChunkyTest.php b/tests/Unit/ChunkyTest.php index ad3e666..e46aa72 100644 --- a/tests/Unit/ChunkyTest.php +++ b/tests/Unit/ChunkyTest.php @@ -1,23 +1,20 @@ create('test', 1000); - $dto = new ChunkyUploadDto( - 'dir/test', - 'name', - 1, - 1, - 1000, - $file->hashName(), - $file - ); + $dto = new ChunkyUploadDto('dir/test', 'name', 1, 1, 1000, $file->hashName(), $file); $res = Chunky::put($dto); @@ -26,33 +23,38 @@ expect(Chunky::path() . '/dir/test/' . $dto->filename . '.part1')->toBeFile(); }); - it('can assemble file', function () { - - $chunks = chunkFile( + it('can assemble file', function (): void { + $chunks = chunk_file( __DIR__ . '/../__fixtures__/content/collections/pages/homepage.yaml', config('backup.temp_path') . '/chunks/', - 10 + 10, ); - $dtos = $chunks->map(fn ($chunk, $index) => new ChunkyUploadDto( - 'dir/test', - 'homepage.yaml', - $chunks->count(), - $index + 1, - File::size(__DIR__ . '/../__fixtures__/content/collections/pages/homepage.yaml'), - basename($chunk), - new UploadedFile($chunk, basename($chunk)) - )); + $totalSize = File::size(__DIR__ . '/../__fixtures__/content/collections/pages/homepage.yaml'); + + $dtos = $chunks->map( + fn(string $chunk, int $index): ChunkyUploadDto => new ChunkyUploadDto( + path: 'dir/test', + filename: 'homepage.yaml', + totalChunks: $chunks->count(), + currentChunk: $index + 1, + totalSize: $totalSize, + identifier: basename($chunk), + file: new UploadedFile($chunk, basename($chunk)), + ), + ); - $responses = $dtos->map(fn ($dto) => Chunky::put($dto)); + $responses = $dtos->map(Chunky::put(...)); - expect($responses->every(fn ($res) => $res->getStatusCode() === 201))->toBeTrue(); - expect($responses->last()->getData(true))->toHaveKey('file'); + expect($responses->every(fn(JsonResponse $res): bool => $res->getStatusCode() === 201))->toBeTrue(); + expect($responses + ->last() + ->getData(true))->toHaveKey('file'); expect(Chunky::path() . '/backups/homepage.yaml')->toBeFile(); - expect(File::get(Chunky::path() . '/backups/homepage.yaml'))->toBe( - File::get(__DIR__ . '/../__fixtures__/content/collections/pages/homepage.yaml') - ); + expect(File::get(Chunky::path() . '/backups/homepage.yaml'))->toBe(File::get( + __DIR__ . '/../__fixtures__/content/collections/pages/homepage.yaml', + )); File::deleteDirectory(Chunky::path()); File::deleteDirectory(config('backup.temp_path') . '/chunks'); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php index 013c597..0cfaafb 100644 --- a/tests/Unit/ExampleTest.php +++ b/tests/Unit/ExampleTest.php @@ -1,5 +1,6 @@ toBe('testing'); }); diff --git a/tests/Unit/PipeTest.php b/tests/Unit/PipeTest.php index 69f843c..723ef33 100644 --- a/tests/Unit/PipeTest.php +++ b/tests/Unit/PipeTest.php @@ -1,5 +1,7 @@ make($pipe)->backup($zipper, fn ($z) => $z))->toBeInstanceOf(Zipper::class); + expect(app() + ->make($pipe) + ->backup($zipper, fn(Zipper $z): Zipper => $z))->toBeInstanceOf(Zipper::class); $zipper->close(); @@ -25,14 +29,16 @@ Assets::class, ]); - test('restore pipes can pass closure', function (string $pipe) { + test('restore pipes can pass closure', function (string $pipe): void { app(BackupRepository::class)->empty(); $fixtues_path = __DIR__ . '/../__fixtures__'; $fixtures_backup_path = Storage::path(config('backup.destination.path')); File::copyDirectory($fixtues_path, $fixtures_backup_path); $path = config('backup.temp_path') . '/backup'; - expect(app()->make($pipe)->restore($path, fn ($z) => $z))->toBe($path); + expect(app() + ->make($pipe) + ->restore($path, fn(string $z): string => $z))->toBe($path); File::deleteDirectory($fixtues_path); File::copyDirectory($fixtures_backup_path, $fixtues_path); @@ -42,11 +48,11 @@ Assets::class, ]); - test('can skip a pipe with users', function () { + test('can skip a pipe with users', function (): void { /** @var Users::class $pipe */ $pipe = app()->make(Users::class); - $callable = function ($z) { + $callable = function (Zipper $z): Zipper { return $z; }; @@ -56,18 +62,17 @@ $pipe->backup(zip: $zipper, next: $callable); - expect($zipper->getMeta())->toHaveKey(Users::class); expect($zipper->getMeta()[Users::class])->toHaveKey('skipped', 'No users found.'); $zipper->close(); }); - test('can skip a pipe with content', function () { + test('can skip a pipe with content', function (): void { /** @var Users::class $pipe */ $pipe = app()->make(Content::class); - $callable = function ($z) { + $callable = function (Zipper $z): Zipper { return $z; }; @@ -78,9 +83,11 @@ $pipe->backup(zip: $zipper, next: $callable); - expect($zipper->getMeta())->toHaveKey(Content::class); - expect($zipper->getMeta()[Content::class])->toHaveKey('skipped', 'Content directory didn\'t exist, is it configured correctly?'); + expect($zipper->getMeta()[Content::class])->toHaveKey( + 'skipped', + 'Content directory didn\'t exist, is it configured correctly?', + ); $zipper->close(); diff --git a/tests/Unit/RestorerTest.php b/tests/Unit/RestorerTest.php index 548fa3d..2b9f912 100644 --- a/tests/Unit/RestorerTest.php +++ b/tests/Unit/RestorerTest.php @@ -1,13 +1,15 @@ toBeFalse(); }); - it('throws an exception if the backup path does not exist', function () { - Restorer::restore(new BackupDto( - name: 'test', - created_at: now(), - size: 0, - path: 'test/path', - timestamp: now()->timestamp, - )); + it('throws an exception if the backup path does not exist', function (): void { + Restorer::restore( + new BackupDto( + name: 'test', + created_at: now(), + size: '0', + path: 'test/path', + timestamp: (string) now()->timestamp, + ), + ); })->throws(RestoreFailed::class); })->group('restorer'); diff --git a/tests/Unit/ZipperTest.php b/tests/Unit/ZipperTest.php index b434463..d9f431e 100644 --- a/tests/Unit/ZipperTest.php +++ b/tests/Unit/ZipperTest.php @@ -1,23 +1,24 @@ toBeInstanceOf(Zipper::class); }); - it('can get the zipArchive instance', function () { + it('can get the zipArchive instance', function (): void { $zip = new Zipper(storage_path('test.zip')); expect($zip->getArchive())->toBeInstanceOf(ZipArchive::class); }); - it('can zip file from string', function () { + it('can zip file from string', function (): void { $target = storage_path('test.zip'); Zipper::open($target) @@ -29,7 +30,7 @@ expect(File::mimeType($target))->toBe('application/zip'); }); - it('can zip file from path', function () { + it('can zip file from path', function (): void { $target = storage_path('test.zip'); Zipper::open($target) @@ -41,17 +42,16 @@ expect(File::mimeType($target))->toBe('application/zip'); }); - it('can zip directory', function () { + it('can zip directory', function (): void { $path = storage_path('test.zip'); - Zipper::open($path) - ->addDirectory(config('backup.content_path'), 'example'); + Zipper::open($path)->addDirectory(config('backup.content_path'), 'example'); expect($path)->toBeString(); expect(file_exists($path))->toBeTrue(); }); - it('can unzip file', function () { + it('can unzip file', function (): void { $target = storage_path('test.zip'); Zipper::open($target) @@ -67,41 +67,45 @@ expect(file_exists($unzip))->toBeTrue(); }); - it('can unzip file to directory', function () { + it('can unzip file to directory', function (): void { $target = storage_path('test.zip'); Zipper::open($target)->addFromString('test.txt', 'test'); $unzip = storage_path('test'); - Zipper::open($target, true)->extractTo($unzip)->close(); + Zipper::open($target, true) + ->extractTo($unzip) + ->close(); expect(file_exists($unzip))->toBeTrue(); expect(file_exists(storage_path('test') . '/test.txt'))->toBeTrue(); }); - it('can unzip directory', function () { - $files = collect(File::allFiles(config('backup.content_path')))->map(function (SplFileInfo $file) { - return $file->getPathname(); - }); + it('can unzip directory', function (): void { + $files = collect(File::allFiles(config('backup.content_path')))->map( + fn(SplFileInfo $file): string => $file->getPathname(), + ); $target = storage_path('test.zip'); - Zipper::open($target) - ->addDirectory(config('backup.content_path'), 'example'); + Zipper::open($target)->addDirectory(config('backup.content_path'), 'example'); $unzip = storage_path('unzipdir'); - Zipper::open($target, true)->extractTo($unzip)->close(); + Zipper::open($target, true) + ->extractTo($unzip) + ->close(); expect(file_exists($unzip))->toBeTrue(); expect(file_exists(storage_path('unzipdir') . '/example'))->toBeTrue(); - $files->each(function ($file) { + $files->each(function (string $file): void { expect(file_exists($file))->toBeTrue(); }); }); - it('can encrypt when zipping', function () { + it('can encrypt when zipping', function (): void { $target = storage_path('test.zip'); + // @mago-ignore security/no-literal-password $password = 'password'; Zipper::open($target) @@ -118,11 +122,11 @@ ->extractTo($unzip, $password) ->close(); - expect(File::allFiles($unzip)[0]->getRelativePathname())->toBe("test.txt"); + expect(File::allFiles($unzip)[0]->getRelativePathname())->toBe('test.txt'); expect(File::get($unzip . '/test.txt'))->toBe('test'); }); - it('can write meta to zip', function () { + it('can write meta to zip', function (): void { $target = storage_path('test.zip'); Zipper::open($target) @@ -133,7 +137,9 @@ $zip = Zipper::open($target, true); expect($zip->getMeta())->toHaveKey('test'); - expect($zip->getMeta())->get('test')->toBe('test'); + expect($zip->getMeta()) + ->get('test') + ->toBe('test'); $zip->close(); });