DEV Community

Freek Van der Herten
Freek Van der Herten

Posted on • Originally published at freek.dev on

★ laravel-backup v6 has been released

laravel-backup is a Laravel package that can backup your application.

It can create a zip containing a dump of your database together with other files that you can select. Using the power of Laravel's filesystem abstraction this zip can than be uploaded to one or more remote filesystems. The package can also monitor the health of your backups and notify if anything goes wrong.

We recently released v6 of the laravel-backup. Though it's a new major version it's mostly a cleanup of the internals. The only new feature added is the support for creating custom health checks.

Support for custom health checks

In previous versions of the package health was determined by the size and the age of last backup. If the backup was too large or the last backups was already a day old, we'd send a notification.

In the new version of the package you can write your own health check. You could for instance check if the size of your backup grows. If it doesn't get larger over time, something might be wrong, and a notification can be sent.

Writing your own health check is pretty easy. You need to create a class that implements Spatie\Backup\Tasks\Monitor\HealthCheck and register your class in the config file. Want to know more, head over to the docs.

Rewritten tests

The first versions of the package supported Laravel 5.1. The core testsuite of the package was written with the testing facilities Laravel had at that time. Meanwhile a lot of niceties have been added to Laravel: faking the filesystem, faking notifications, testing console commands, ...

For v6 of laravel-backup, I took to the time to rewrite the testsuite to make use of these new features.

Let's take a look at the package can clean up old backups. In this test we create 1000 backups with different ages. Then we run the backup:clean command and verify that some backups are still there and some have been deleted.

Here's the old code first. I edited it slightly for brevity. In this old code I still had to setup a temp directory and to fake a filesystem myself.

/** @test */
public function it_can_remove_old_backups_from_the_backup_directory()
{
    $allBackups = collect();

    collect(range(0, 1000))->each(function (int $numberOfDays) use ($allBackups) {
        $date = Carbon::now()->subDays($numberOfDays);

        $allBackups->push($this->testHelper->createTempFileWithAge("mysite/test_{$date->format('Ymd')}_first.zip", $date));
        $allBackups->push($this->testHelper->createTempFileWithAge("mysite/test_{$date->format('Ymd')}_second.zip", $date->addHour(2)));
    });

    $remainingBackups = collect([
        'mysite/test_20131231_first.zip',
        'mysite/test_20141231_first.zip',
        'mysite/test_20150630_first.zip',
        // ...
    ]);

    Artisan::call('backup:clean');

    $this->assertTempFilesExist($remainingBackups->toArray());

    $deletedBackups = $allBackups
        ->map(function ($fullPath) {
            $tempPath = str_replace($this->testHelper->getTempDirectory().'/', '', $fullPath);

            return $tempPath;
        })
        ->reject(function (string $deletedPath) use ($remainingBackups) {
            return $remainingBackups->contains($deletedPath);
        });

    $this->assertTempFilesNotExist($deletedBackups->toArray());
}

And here's the new version. Here we can just make use a faked filesystem and use some cool collection methods that were added to recent Laravel versions. It's not less lines of code, but the intent of the code is more clear.

/** @test */
public function it_can_remove_old_backups_from_the_backup_directory()
{
    $this->setNow(2016, 1, 1);

    [$expectedRemainingBackups, $expectedDeletedBackups] = Collection::times(1000)
        ->flatMap(function (int $numberOfDays) {
            $date = now()->subDays($numberOfDays);

            return [
                $this->createFileOnDisk('local', "mysite/test_{$date->format('Ymd')}_first.zip", $date),
                $this->createFileOnDisk('local', "mysite/test_{$date->format('Ymd')}_second.zip", $date->addHour(2)),
            ];
        })->partition(function (string $backupPath) {
            return in_array($backupPath, [
                'mysite/test_20131231_first.zip',
                'mysite/test_20141231_first.zip',
                'mysite/test_20150630_first.zip',
                // ... 
            ]);
        });

    $this->artisan('backup:clean')->assertExitCode(0);

    Storage::disk('local')
       ->assertExists($expectedRemainingBackups->toArray())
       ->assertMissing($expectedDeletedBackups->toArray());
}

It's great to see just how the features added to Laravel enabled me to write clearer code. Though regular users will never see them, these rewritten tests will improve the experience that contributors will have when working on the package.

In closing

Don't think that using backups of your hosting provider is enough. They can fuck up too. If you want to know more about the features of laravel-backup itself, go read the docs.

Top comments (0)