Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/Enums/NodePackageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public function getText(): string
public function installCommand(): string
{
return match ($this) {
self::Npm => 'npm install',
self::Pnpm => 'pnpm install',
self::Yarn => 'yarn install',
self::Npm => 'npm ci',
self::Pnpm => 'pnpm install --frozen-lockfile',
self::Yarn => 'yarn install --frozen-lockfile',
};
}

Expand Down
43 changes: 43 additions & 0 deletions app/Providers/SiteTypeServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use App\Plugins\RegisterSiteType;
use App\SiteTypes\Laravel;
use App\SiteTypes\LoadBalancer;
use App\SiteTypes\MiseBun;
use App\SiteTypes\MiseNodeJS;
use App\SiteTypes\NodeJS;
use App\SiteTypes\PHPBlank;
Expand All @@ -30,6 +31,7 @@ public function boot(): void
$this->laravel();
$this->nodeJS();
$this->miseNodeJS();
$this->miseBun();
$this->loadBalancer();
$this->phpMyAdmin();
$this->wordpress();
Expand Down Expand Up @@ -208,6 +210,47 @@ private function miseNodeJS(): void
->register();
}

private function miseBun(): void
{
RegisterSiteType::make(MiseBun::id())
->label('Bun')
->handler(MiseBun::class)
->form(DynamicForm::make([
DynamicField::make('bun_version')
->select()
->label('Bun Version')
->options(MiseBun::BUN_VERSIONS)
->default('1.2'),
DynamicField::make('source_control')
->component()
->label('Source Control'),
DynamicField::make('port')
->text()
->label('Port')
->placeholder('3000')
->description('On which port your app will be running'),
DynamicField::make('repository')
->text()
->label('Repository')
->placeholder('organization/repository'),
DynamicField::make('branch')
->text()
->label('Branch')
->default('main'),
DynamicField::make('build_command')
->text()
->label('Build Command')
->placeholder('e.g., bun run build')
->description('Command to build your application. Leave empty to use the build script of package.json'),
DynamicField::make('start_command')
->text()
->label('Start Command')
->placeholder('e.g., bun run start')
->description('Command to start your application. Leave empty to use the start script of package.json'),
]))
->register();
}

public function loadBalancer(): void
{
RegisterSiteType::make(LoadBalancer::id())
Expand Down
232 changes: 232 additions & 0 deletions app/SiteTypes/MiseBun.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
<?php

namespace App\SiteTypes;

use App\Actions\Worker\CreateWorker;
use App\Actions\Worker\ManageWorker;
use App\Exceptions\FailedToDeployGitKey;
use App\Exceptions\SSHError;
use App\Models\Site;
use App\Models\Worker;
use App\SSH\OS\Git;
use Illuminate\Contracts\View\View;
use Illuminate\Validation\Rule;

class MiseBun extends MiseSiteType
{
public const BUN_VERSIONS = [
'1.2',
'1.1',
'1.0',
];

public static function id(): string
{
return 'mise_bun';
}

public function requiredServices(): array
{
return [
'webserver',
'process_manager',
];
}

public function language(): string
{
return 'bun';
}

protected function runtime(): string
{
return 'bun';
}

protected function runtimeVersion(): string
{
return $this->site->type_data['bun_version'] ?? '1.2';
}

public static function make(): self
{
return new self(new Site(['type' => self::id()]));
}

public function createRules(array $input): array
{
return [
'source_control' => [
'required',
Rule::exists('source_controls', 'id'),
],
'repository' => [
'required',
],
'branch' => [
'required',
],
'port' => [
'required',
'numeric',
'between:1,65535',
],
'bun_version' => [
'required',
Rule::in(self::BUN_VERSIONS),
],
'build_command' => [
'nullable',
'string',
],
'start_command' => [
'nullable',
'string',
],
];
}

public function createFields(array $input): array
{
return [
'source_control_id' => $input['source_control'] ?? '',
'repository' => $input['repository'] ?? '',
'branch' => $input['branch'] ?? '',
'port' => $input['port'] ?? '',
];
}

public function data(array $input): array
{
return [
'bun_version' => $input['bun_version'] ?? '1.2',
'build_command' => ! empty($input['build_command']) ? $input['build_command'] : 'bun run build',
'start_command' => ! empty($input['start_command']) ? $input['start_command'] : 'bun run start',
];
}

protected function buildCommand(): string
{
return $this->site->type_data['build_command'] ?? 'bun run build';
}

protected function startCommand(): string
{
return $this->site->type_data['start_command'] ?? 'bun run start';
}

/**
* @throws FailedToDeployGitKey
* @throws SSHError
*/
public function install(): void
{
$this->isolate();
$this->progress(10);

$this->setupRuntime();
$this->progress(25);

$this->site->webserver()->createVHost($this->site);
$this->progress(35);

$this->deployKey();
$this->progress(45);

app(Git::class)->clone($this->site);
$this->progress(55);

$this->runInstall();
$this->progress(70);

$this->runBuild();
$this->progress(85);

$this->createWorker();
$this->progress(100);
}

/**
* @throws SSHError
*/
protected function runInstall(): void
{
$this->site->server->ssh($this->site->user)->exec(
$this->wrapCommand('bun install --frozen-lockfile', true),
'bun-install',
$this->site->id
);
}

/**
* @throws SSHError
*/
protected function runBuild(): void
{
$this->site->server->ssh($this->site->user)->exec(
$this->wrapCommand($this->buildCommand(), true),
'build',
$this->site->id
);
}

protected function createWorker(): void
{
/** @var ?Worker $worker */
$worker = $this->site->workers()->where('name', 'app')->first();
if ($worker) {
app(ManageWorker::class)->restart($worker);
} else {
app(CreateWorker::class)->create(
$this->site->server,
[
'name' => 'app',
'command' => $this->workerCommand(),
'user' => $this->site->user ?? $this->site->server->getSshUser(),
'auto_start' => true,
'auto_restart' => true,
'numprocs' => 1,
'environment' => $this->workerEnvironment(),
],
$this->site,
);
}
}

public function baseCommands(): array
{
return [];
}

public function vhost(string $webserver): string|View
{
if ($webserver === 'nginx') {
return view('ssh.services.webserver.nginx.vhost', [
'header' => [
view('ssh.services.webserver.nginx.vhost-blocks.force-ssl', ['site' => $this->site]),
],
'main' => [
view('ssh.services.webserver.nginx.vhost-blocks.port', ['site' => $this->site]),
view('ssh.services.webserver.nginx.vhost-blocks.core', ['site' => $this->site]),
view('ssh.services.webserver.nginx.vhost-blocks.reverse-proxy', ['site' => $this->site]),
view('ssh.services.webserver.nginx.vhost-blocks.redirects', ['site' => $this->site]),
],
]);
}

if ($webserver === 'caddy') {
return view('ssh.services.webserver.caddy.vhost', [
'site' => $this->site,
'main' => [
view('ssh.services.webserver.caddy.vhost-blocks.force-ssl', ['site' => $this->site]),
view('ssh.services.webserver.caddy.vhost-blocks.port', ['site' => $this->site]),
view('ssh.services.webserver.caddy.vhost-blocks.core', ['site' => $this->site]),
view('ssh.services.webserver.caddy.vhost-blocks.reverse-proxy', ['site' => $this->site]),
view('ssh.services.webserver.caddy.vhost-blocks.redirects', ['site' => $this->site]),
],
]);
}

return '';
}
}
27 changes: 27 additions & 0 deletions tests/Feature/SitesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use App\Models\SourceControl;
use App\SiteTypes\Laravel;
use App\SiteTypes\LoadBalancer;
use App\SiteTypes\MiseBun;
use App\SiteTypes\MiseNodeJS;
use App\SiteTypes\NodeJS;
use App\SiteTypes\PHPBlank;
Expand Down Expand Up @@ -710,6 +711,32 @@ public static function create_data(): array
'user' => 'example',
],
],
[
[
'type' => MiseBun::id(),
'domain' => 'example.com',
'aliases' => ['www.example.com'],
'bun_version' => '1.2',
'port' => '3000',
'repository' => 'test/test',
'branch' => 'main',
'user' => 'example',
],
],
[
[
'type' => MiseBun::id(),
'domain' => 'example.com',
'aliases' => ['www.example.com'],
'bun_version' => '1.1',
'port' => '3000',
'repository' => 'test/test',
'branch' => 'main',
'build_command' => 'bun run build:prod',
'start_command' => 'bun run start:prod',
'user' => 'example',
],
],
];
}

Expand Down
Loading