mirror of
https://github.com/bitinflow/bunny-cli.git
synced 2026-03-13 21:55:54 +00:00
Improve lock file
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,5 +7,6 @@
|
|||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
.env
|
.env
|
||||||
*.bk
|
*.bk
|
||||||
|
bunny-cli.lock
|
||||||
|
bunny-cli.lock.bk
|
||||||
/dist*
|
/dist*
|
||||||
*.sha256
|
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -10,7 +10,7 @@ With Bunny CDN's Storage Edge, your web applications benefit from replicated sto
|
|||||||
|
|
||||||
Bunny CLI currently only comes with a `deploy` command. With this command, you can easily synconizise your `dist` folder with your edge storage.
|
Bunny CLI currently only comes with a `deploy` command. With this command, you can easily synconizise your `dist` folder with your edge storage.
|
||||||
|
|
||||||
> All files in the edge storage that are **not** in your local `dist` directory will be deleted.
|
> **IMPORTANT**: All files in the edge storage that are **not** in your local `dist` directory will be deleted.
|
||||||
|
|
||||||
```plain
|
```plain
|
||||||
➜ $ bunny deploy
|
➜ $ bunny deploy
|
||||||
@@ -43,6 +43,16 @@ We offer you a [GitHub Action for Bunny CLI](https://github.com/marketplace/acti
|
|||||||
args: deploy --dir=dist
|
args: deploy --dir=dist
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Secure your `.well-known/bunny-cli.lock` file
|
||||||
|
|
||||||
|
Bunny CLI generates a lock file, which by default is located at `.well-known/bunny-cli.lock`. This file locks the files of your project to a known state. To prevent this from being publicly accessible it is recommended to create a new edge rule in your pull zone. You can use the following example as a template:
|
||||||
|
|
||||||
|
Action: `Block Request`
|
||||||
|
Condition Matching: `Match Any`
|
||||||
|
Condition: If `Request URL` `Match Any` `*/.well-known/bunny-cli.lock`
|
||||||
|
|
||||||
|
Now the file should no longer be accessible. It can take a few minutes until your Edge Rule is active.
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
### Q: Is this a zero-downtime deployment?
|
### Q: Is this a zero-downtime deployment?
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ namespace App\Bunny\Filesystem;
|
|||||||
class CompareOptions
|
class CompareOptions
|
||||||
{
|
{
|
||||||
const START = 'start';
|
const START = 'start';
|
||||||
const NO_SHA256_CACHE = 'no_sha256_cache';
|
const NO_SHA256_VERIFICATION = 'no_sha256_verification';
|
||||||
const NO_SHA256_GENERATION = 'no_sha256_generation';
|
const NO_SHA256_GENERATION = 'no_sha256_generation';
|
||||||
const SHA256_NAME = 'sha256_name';
|
const LOCK_FILE = 'lock_file';
|
||||||
const DRY_RUN = 'dry-run';
|
const DRY_RUN = 'dry-run';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ namespace App\Bunny\Filesystem;
|
|||||||
|
|
||||||
use App\Bunny\Filesystem\Exceptions\FileNotFoundException;
|
use App\Bunny\Filesystem\Exceptions\FileNotFoundException;
|
||||||
use App\Bunny\Filesystem\Exceptions\FilesystemException;
|
use App\Bunny\Filesystem\Exceptions\FilesystemException;
|
||||||
|
use App\Bunny\Lock\Exceptions\LockException;
|
||||||
|
use App\Bunny\Lock\Lock;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
class EdgeStorageCache
|
class EdgeStorageCache
|
||||||
{
|
{
|
||||||
private EdgeStorage $edgeStorage;
|
private EdgeStorage $edgeStorage;
|
||||||
private string $filename = '.well-known/bunny.sha256';
|
private string $filename = Lock::DEFAULT_FILENAME;
|
||||||
|
|
||||||
public function __construct(EdgeStorage $edgeStorage)
|
public function __construct(EdgeStorage $edgeStorage)
|
||||||
{
|
{
|
||||||
@@ -47,18 +49,22 @@ class EdgeStorageCache
|
|||||||
return $response->getStatusCode() === 200;
|
return $response->getStatusCode() === 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* @throws LockException
|
||||||
|
*/
|
||||||
private function extract(string $contents): array
|
private function extract(string $contents): array
|
||||||
{
|
{
|
||||||
if (!$array = json_decode($contents, true)) {
|
$lock = Lock::parse($contents, $this->filename);
|
||||||
throw new FileNotFoundException('Cannot parse cache file.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_map(fn(array $x) => EdgeFile::fromArray($x), $array);
|
return array_map(fn(array $x) => EdgeFile::fromArray($x), $lock->getFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function hydrate(array $files, string $search = '', string $replace = ''): string
|
private function hydrate(array $files, string $search = '', string $replace = ''): string
|
||||||
{
|
{
|
||||||
return json_encode(array_map(fn(LocalFile $x) => $x->toArray($search, $replace), $files), JSON_PRETTY_PRINT);
|
return Lock::fromFiles(
|
||||||
|
array_map(fn(LocalFile $x) => $x->toArray($search, $replace), $files)
|
||||||
|
)->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFilename(string $filename)
|
public function setFilename(string $filename)
|
||||||
|
|||||||
@@ -168,9 +168,9 @@ class FileCompare
|
|||||||
*/
|
*/
|
||||||
private function getEdgeFiles(array $options, string $edge, int $expectedMax): array
|
private function getEdgeFiles(array $options, string $edge, int $expectedMax): array
|
||||||
{
|
{
|
||||||
$this->edgeStorage->getStorageCache()->setFilename($options[CompareOptions::SHA256_NAME]);
|
$this->edgeStorage->getStorageCache()->setFilename($options[CompareOptions::LOCK_FILE]);
|
||||||
|
|
||||||
if ($options[CompareOptions::NO_SHA256_CACHE]) {
|
if ($options[CompareOptions::NO_SHA256_VERIFICATION]) {
|
||||||
return $this->getAllFilesRecursive($expectedMax, $edge);
|
return $this->getAllFilesRecursive($expectedMax, $edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ class FileCompare
|
|||||||
} catch (FileNotFoundException $exception) {
|
} catch (FileNotFoundException $exception) {
|
||||||
$this->command->warn(sprintf(
|
$this->command->warn(sprintf(
|
||||||
'⚠ Cannot fetch %s from storage due "%s". Using recursive fallback...',
|
'⚠ Cannot fetch %s from storage due "%s". Using recursive fallback...',
|
||||||
$options[CompareOptions::SHA256_NAME],
|
$options[CompareOptions::LOCK_FILE],
|
||||||
$exception->getMessage()
|
$exception->getMessage()
|
||||||
));
|
));
|
||||||
return $this->getAllFilesRecursive($expectedMax, $edge);
|
return $this->getAllFilesRecursive($expectedMax, $edge);
|
||||||
|
|||||||
13
app/Bunny/Lock/Exceptions/LockException.php
Normal file
13
app/Bunny/Lock/Exceptions/LockException.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Bunny\Lock\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class LockException extends Exception
|
||||||
|
{
|
||||||
|
public static function fromInvalidVersion($version): self
|
||||||
|
{
|
||||||
|
return new self(sprintf('Your lock file version %s is not supported.', $version));
|
||||||
|
}
|
||||||
|
}
|
||||||
57
app/Bunny/Lock/Lock.php
Normal file
57
app/Bunny/Lock/Lock.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Bunny\Lock;
|
||||||
|
|
||||||
|
use App\Bunny\Filesystem\Exceptions\FileNotFoundException;
|
||||||
|
use App\Bunny\Lock\Exceptions\LockException;
|
||||||
|
|
||||||
|
class Lock
|
||||||
|
{
|
||||||
|
public const DEFAULT_FILENAME = '.well-known/bunny-cli.lock';
|
||||||
|
|
||||||
|
private array $contents;
|
||||||
|
|
||||||
|
private function __construct(array $contents)
|
||||||
|
{
|
||||||
|
$this->contents['version'] = 1;
|
||||||
|
$this->contents['_readme'] = [
|
||||||
|
'This file locks the files of your project to a known state',
|
||||||
|
'Read more about it at https://github.com/own3d/bunny-cli/wiki',
|
||||||
|
'This file is @generated automatically'
|
||||||
|
];
|
||||||
|
$this->contents['files'] = $contents['files'] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parse(string $contents, string $filename = self::DEFAULT_FILENAME): self
|
||||||
|
{
|
||||||
|
if (!$array = json_decode($contents, true)) {
|
||||||
|
throw new FileNotFoundException(sprintf('Cannot decode %s file.', $filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($array['version']) || $array['version'] !== 1) {
|
||||||
|
throw LockException::fromInvalidVersion($array['version'] ?? 'undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromFiles(array $files): self
|
||||||
|
{
|
||||||
|
return new self(['files' => $files]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFiles(): array
|
||||||
|
{
|
||||||
|
return $this->contents['files'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return $this->contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString(): string
|
||||||
|
{
|
||||||
|
return json_encode($this->toArray(), JSON_PRETTY_PRINT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,9 +19,9 @@ class DeployCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected $signature = 'deploy
|
protected $signature = 'deploy
|
||||||
{--dir=dist : Root directory to upload}
|
{--dir=dist : Root directory to upload}
|
||||||
{--no-sha256-cache : Skips .well-known/bunny.sha256 and queries the storage endpoints recursively instead}
|
{--no-sha256-verification : Skips checksum verification from bunny-cli.lock and polls the storage api recursively instead}
|
||||||
{--no-sha256-generation : Skips .well-known/bunny.sha256 generation}
|
{--no-sha256-generation : Skips checksum generation for bunny-cli.lock}
|
||||||
{--sha256-name=.well-known/bunny.sha256 : Change filename of .well-known/bunny.sha256}
|
{--lock-file=.well-known/bunny-cli.lock : Changes the location and filename of .well-known/bunny-cli.lock}
|
||||||
{--dry-run : Outputs the operations but will not execute anything}';
|
{--dry-run : Outputs the operations but will not execute anything}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,9 +62,9 @@ class DeployCommand extends Command
|
|||||||
try {
|
try {
|
||||||
$fileCompare->compare($localPath, $edgePath, [
|
$fileCompare->compare($localPath, $edgePath, [
|
||||||
CompareOptions::START => $start,
|
CompareOptions::START => $start,
|
||||||
CompareOptions::NO_SHA256_CACHE => $this->option('no-sha256-cache'),
|
CompareOptions::NO_SHA256_VERIFICATION => $this->option('no-sha256-verification'),
|
||||||
CompareOptions::NO_SHA256_GENERATION => $this->option('no-sha256-generation'),
|
CompareOptions::NO_SHA256_GENERATION => $this->option('no-sha256-generation'),
|
||||||
CompareOptions::SHA256_NAME => $this->option('sha256-name'),
|
CompareOptions::LOCK_FILE => $this->option('lock-file'),
|
||||||
CompareOptions::DRY_RUN => $this->option('dry-run'),
|
CompareOptions::DRY_RUN => $this->option('dry-run'),
|
||||||
]);
|
]);
|
||||||
} catch (FilesystemException $exception) {
|
} catch (FilesystemException $exception) {
|
||||||
|
|||||||
Reference in New Issue
Block a user