Merge pull request #1002 from coollabsio/ijpatricio-wip-1
First SSH command on remote host.
This commit is contained in:
commit
1bb3117b05
27
.env.example
27
.env.example
@ -1,39 +1,24 @@
|
||||
############################################################################################################
|
||||
# Development Environment
|
||||
|
||||
# Userid for the user that will run the application inside the container
|
||||
# User and group id for the user that will run the application inside the container
|
||||
# Run in your terminal: `id -u` and `id -g` and that's the results
|
||||
USERID=
|
||||
GROUPID=
|
||||
############################################################################################################
|
||||
|
||||
APP_NAME=Laravel
|
||||
APP_SERVICE=php
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=postgres
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=coolify
|
||||
DB_USERNAME=sail
|
||||
DB_USERNAME=coolify
|
||||
DB_PASSWORD=password
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailpit
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
QUEUE_CONNECTION=database
|
||||
|
29
.github/workflows/docker-image.yml
vendored
Normal file
29
.github/workflows/docker-image.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: Docker Image CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "*" ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build the Docker image
|
||||
run: |
|
||||
docker run --rm -u "$(id -u):$(id -g)" \
|
||||
-v "$(pwd):/app" \
|
||||
-w /app composer:2 \
|
||||
composer install --ignore-platform-reqs
|
||||
TAG=$(date +%s) ./vendor/bin/sail build
|
||||
TAG=$(date +%s) ./vendor/bin/sail up -d
|
||||
sleep 1
|
||||
./vendor/bin/sail ps
|
||||
# Now to create .env
|
||||
# Await database is created
|
||||
# pest
|
26
Dockerfile
26
Dockerfile
@ -1,26 +0,0 @@
|
||||
FROM serversideup/php:8.2-fpm-nginx
|
||||
|
||||
ARG NODE_VERSION=18
|
||||
ARG POSTGRES_VERSION=15
|
||||
|
||||
RUN apt-get update \
|
||||
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npm install -g npm
|
||||
|
||||
RUN apt-get install -y php-pgsql
|
||||
|
||||
RUN apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
||||
|
||||
# Adding test ssh key
|
||||
RUN mkdir -p ~/.ssh
|
||||
RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\
|
||||
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\
|
||||
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\
|
||||
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\
|
||||
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\
|
||||
-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519
|
||||
RUN chmod 0600 ~/.ssh/id_ed25519
|
54
app/Http/Livewire/RunCommand.php
Executable file
54
app/Http/Livewire/RunCommand.php
Executable file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class RunCommand extends Component
|
||||
{
|
||||
public $activity;
|
||||
|
||||
public $isKeepAliveOn = false;
|
||||
|
||||
public $manualKeepAlive = false;
|
||||
|
||||
public $command = 'ls';
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.run-command');
|
||||
}
|
||||
|
||||
public function runCommand()
|
||||
{
|
||||
$this->isKeepAliveOn = true;
|
||||
|
||||
$this->activity = coolifyProcess($this->command, 'testing-host');
|
||||
}
|
||||
|
||||
public function runSleepingBeauty()
|
||||
{
|
||||
$this->isKeepAliveOn = true;
|
||||
|
||||
$this->activity = coolifyProcess('x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', 'testing-host');
|
||||
}
|
||||
|
||||
public function runDummyProjectBuild()
|
||||
{
|
||||
$this->isKeepAliveOn = true;
|
||||
|
||||
$this->activity = coolifyProcess(<<<EOT
|
||||
cd projects/dummy-project
|
||||
~/.docker/cli-plugins/docker-compose build --no-cache
|
||||
EOT, 'testing-host');
|
||||
}
|
||||
|
||||
public function polling()
|
||||
{
|
||||
$this->activity?->refresh();
|
||||
|
||||
if (data_get($this->activity, 'properties.exitCode') !== null) {
|
||||
$this->isKeepAliveOn = false;
|
||||
}
|
||||
}
|
||||
}
|
132
app/Jobs/ExecuteCoolifyProcess.php
Executable file
132
app/Jobs/ExecuteCoolifyProcess.php
Executable file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Services\ProcessStatus;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Process\InvokedProcess;
|
||||
use Illuminate\Process\ProcessResult;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Spatie\Activitylog\Contracts\Activity;
|
||||
|
||||
class ExecuteCoolifyProcess implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $throttleIntervalMS = 500;
|
||||
|
||||
protected $timeStart;
|
||||
|
||||
protected $currentTime;
|
||||
|
||||
protected $lastWriteAt = 0;
|
||||
|
||||
protected string $stdOutIncremental = '';
|
||||
|
||||
protected string $stdErrIncremental = '';
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public Activity $activity,
|
||||
){}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): ProcessResult
|
||||
{
|
||||
$this->timeStart = hrtime(true);
|
||||
|
||||
$user = $this->activity->getExtraProperty('user');
|
||||
$destination = $this->activity->getExtraProperty('destination');
|
||||
$port = $this->activity->getExtraProperty('port');
|
||||
$command = $this->activity->getExtraProperty('command');
|
||||
|
||||
$delimiter = 'EOF-COOLIFY-SSH';
|
||||
|
||||
$sshCommand = 'ssh '
|
||||
. '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
|
||||
. '-o PasswordAuthentication=no '
|
||||
. '-o RequestTTY=no '
|
||||
// Quiet mode. Causes most warning and diagnostic messages to be suppressed.
|
||||
// Errors are still out put. This is to silence for example, that warning
|
||||
// Permanently added <host and key type> to the list of known hosts.
|
||||
. '-q '
|
||||
. "-p {$port} "
|
||||
. "{$user}@{$destination} "
|
||||
. " 'bash -se' << \\$delimiter" . PHP_EOL
|
||||
. $command . PHP_EOL
|
||||
. $delimiter;
|
||||
|
||||
$process = Process::start($sshCommand, $this->handleOutput(...));
|
||||
|
||||
$processResult = $process->wait();
|
||||
|
||||
$status = match ($processResult->exitCode()) {
|
||||
0 => ProcessStatus::FINISHED,
|
||||
default => ProcessStatus::ERROR,
|
||||
};
|
||||
|
||||
$this->activity->properties = $this->activity->properties->merge([
|
||||
'exitCode' => $processResult->exitCode(),
|
||||
'stdout' => $processResult->output(),
|
||||
'stderr' => $processResult->errorOutput(),
|
||||
'status' => $status,
|
||||
]);
|
||||
|
||||
$this->activity->save();
|
||||
|
||||
return $processResult;
|
||||
}
|
||||
|
||||
protected function handleOutput(string $type, string $output)
|
||||
{
|
||||
$this->currentTime = $this->elapsedTime();
|
||||
|
||||
if ($type === 'out') {
|
||||
$this->stdOutIncremental .= $output;
|
||||
} else {
|
||||
$this->stdErrIncremental .= $output;
|
||||
}
|
||||
|
||||
$this->activity->description .= $output;
|
||||
|
||||
if ($this->isAfterLastThrottle()) {
|
||||
// Let's write to database.
|
||||
DB::transaction(function () {
|
||||
$this->activity->save();
|
||||
$this->lastWriteAt = $this->currentTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides if it's time to write again to database.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAfterLastThrottle()
|
||||
{
|
||||
// If DB was never written, then we immediately decide we have to write.
|
||||
if ($this->lastWriteAt === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ($this->currentTime - $this->throttleIntervalMS) > $this->lastWriteAt;
|
||||
}
|
||||
|
||||
protected function elapsedTime(): int
|
||||
{
|
||||
$timeMs = (hrtime(true) - $this->timeStart) / 1_000_000;
|
||||
|
||||
return intval($timeMs);
|
||||
}
|
||||
}
|
47
app/Services/CoolifyProcess.php
Normal file
47
app/Services/CoolifyProcess.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Jobs\ExecuteCoolifyProcess;
|
||||
use Illuminate\Process\ProcessResult;
|
||||
use Spatie\Activitylog\Contracts\Activity;
|
||||
|
||||
class CoolifyProcess
|
||||
{
|
||||
protected Activity $activity;
|
||||
|
||||
// TODO Left 'root' as default user instead of 'coolify' because
|
||||
// there's a task at TODO.md to run docker without sudo
|
||||
public function __construct(
|
||||
protected string $destination,
|
||||
protected string $command,
|
||||
protected ?int $port = 22,
|
||||
protected ?string $user = 'root',
|
||||
){
|
||||
$this->activity = activity()
|
||||
->withProperties([
|
||||
'type' => 'COOLIFY_PROCESS',
|
||||
'user' => $this->user,
|
||||
'destination' => $this->destination,
|
||||
'port' => $this->port,
|
||||
'command' => $this->command,
|
||||
'status' => ProcessStatus::HOLDING,
|
||||
])
|
||||
->log("Awaiting to start command...\n\n");
|
||||
}
|
||||
|
||||
public function __invoke(): Activity|ProcessResult
|
||||
{
|
||||
$job = new ExecuteCoolifyProcess($this->activity);
|
||||
|
||||
if (app()->environment('testing')) {
|
||||
return $job->handle();
|
||||
}
|
||||
|
||||
dispatch($job);
|
||||
|
||||
return $this->activity;
|
||||
}
|
||||
|
||||
|
||||
}
|
11
app/Services/ProcessStatus.php
Normal file
11
app/Services/ProcessStatus.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
enum ProcessStatus: string
|
||||
{
|
||||
case HOLDING = 'holding';
|
||||
case IN_PROGRESS = 'in_progress';
|
||||
case FINISHED = 'finished';
|
||||
case ERROR = 'error';
|
||||
}
|
24
bootstrap/helpers.php
Normal file
24
bootstrap/helpers.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use App\Services\CoolifyProcess;
|
||||
use Illuminate\Process\ProcessResult;
|
||||
use Spatie\Activitylog\Contracts\Activity;
|
||||
|
||||
if (! function_exists('coolifyProcess')) {
|
||||
|
||||
/**
|
||||
* Run a Coolify Process, which SSH's into a machine to run the command(s).
|
||||
*
|
||||
*/
|
||||
function coolifyProcess($command, $destination): Activity|ProcessResult
|
||||
{
|
||||
$process = resolve(CoolifyProcess::class, [
|
||||
'destination' => $destination,
|
||||
'command' => $command,
|
||||
]);
|
||||
|
||||
$activityLog = $process();
|
||||
|
||||
return $activityLog;
|
||||
}
|
||||
}
|
@ -9,7 +9,10 @@
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/sanctum": "^3.2",
|
||||
"laravel/tinker": "^2.8"
|
||||
"laravel/tinker": "^2.8",
|
||||
"livewire/livewire": "^2.12",
|
||||
"spatie/laravel-activitylog": "^4.7",
|
||||
"spatie/laravel-ray": "^1.32"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
@ -17,10 +20,14 @@
|
||||
"laravel/sail": "^1.18",
|
||||
"mockery/mockery": "^1.4.4",
|
||||
"nunomaduro/collision": "^7.0",
|
||||
"pestphp/pest": "^2.0",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"spatie/laravel-ignition": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
|
1821
composer.lock
generated
1821
composer.lock
generated
File diff suppressed because it is too large
Load Diff
108
config/ray.php
Normal file
108
config/ray.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
* This setting controls whether data should be sent to Ray.
|
||||
*
|
||||
* By default, `ray()` will only transmit data in non-production environments.
|
||||
*/
|
||||
'enable' => env('RAY_ENABLED', true),
|
||||
|
||||
/*
|
||||
* When enabled, all cache events will automatically be sent to Ray.
|
||||
*/
|
||||
'send_cache_to_ray' => env('SEND_CACHE_TO_RAY', false),
|
||||
|
||||
/*
|
||||
* When enabled, all things passed to `dump` or `dd`
|
||||
* will be sent to Ray as well.
|
||||
*/
|
||||
'send_dumps_to_ray' => env('SEND_DUMPS_TO_RAY', true),
|
||||
|
||||
/*
|
||||
* When enabled all job events will automatically be sent to Ray.
|
||||
*/
|
||||
'send_jobs_to_ray' => env('SEND_JOBS_TO_RAY', false),
|
||||
|
||||
/*
|
||||
* When enabled, all things logged to the application log
|
||||
* will be sent to Ray as well.
|
||||
*/
|
||||
'send_log_calls_to_ray' => env('SEND_LOG_CALLS_TO_RAY', true),
|
||||
|
||||
/*
|
||||
* When enabled, all queries will automatically be sent to Ray.
|
||||
*/
|
||||
'send_queries_to_ray' => env('SEND_QUERIES_TO_RAY', false),
|
||||
|
||||
/**
|
||||
* When enabled, all duplicate queries will automatically be sent to Ray.
|
||||
*/
|
||||
'send_duplicate_queries_to_ray' => env('SEND_DUPLICATE_QUERIES_TO_RAY', false),
|
||||
|
||||
/*
|
||||
* When enabled, slow queries will automatically be sent to Ray.
|
||||
*/
|
||||
'send_slow_queries_to_ray' => env('SEND_SLOW_QUERIES_TO_RAY', false),
|
||||
|
||||
/**
|
||||
* Queries that are longer than this number of milliseconds will be regarded as slow.
|
||||
*/
|
||||
'slow_query_threshold_in_ms' => env('RAY_SLOW_QUERY_THRESHOLD_IN_MS', 500),
|
||||
|
||||
/*
|
||||
* When enabled, all requests made to this app will automatically be sent to Ray.
|
||||
*/
|
||||
'send_requests_to_ray' => env('SEND_REQUESTS_TO_RAY', false),
|
||||
|
||||
/**
|
||||
* When enabled, all Http Client requests made by this app will be automatically sent to Ray.
|
||||
*/
|
||||
'send_http_client_requests_to_ray' => env('SEND_HTTP_CLIENT_REQUESTS_TO_RAY', false),
|
||||
|
||||
/*
|
||||
* When enabled, all views that are rendered automatically be sent to Ray.
|
||||
*/
|
||||
'send_views_to_ray' => env('SEND_VIEWS_TO_RAY', false),
|
||||
|
||||
/*
|
||||
* When enabled, all exceptions will be automatically sent to Ray.
|
||||
*/
|
||||
'send_exceptions_to_ray' => env('SEND_EXCEPTIONS_TO_RAY', true),
|
||||
|
||||
/*
|
||||
* When enabled, all deprecation notices will be automatically sent to Ray.
|
||||
*/
|
||||
'send_deprecated_notices_to_ray' => env('SEND_DEPRECATED_NOTICES_TO_RAY', false),
|
||||
|
||||
/*
|
||||
* The host used to communicate with the Ray app.
|
||||
* When using Docker on Mac or Windows, you can replace localhost with 'host.docker.internal'
|
||||
* When using Docker on Linux, you can replace localhost with '172.17.0.1'
|
||||
* When using Homestead with the VirtualBox provider, you can replace localhost with '10.0.2.2'
|
||||
* When using Homestead with the Parallels provider, you can replace localhost with '10.211.55.2'
|
||||
*/
|
||||
'host' => env('RAY_HOST', 'host.docker.internal'),
|
||||
|
||||
/*
|
||||
* The port number used to communicate with the Ray app.
|
||||
*/
|
||||
'port' => env('RAY_PORT', 23517),
|
||||
|
||||
/*
|
||||
* Absolute base path for your sites or projects in Homestead,
|
||||
* Vagrant, Docker, or another remote development server.
|
||||
*/
|
||||
'remote_path' => env('RAY_REMOTE_PATH', null),
|
||||
|
||||
/*
|
||||
* Absolute base path for your sites or projects on your local
|
||||
* computer where your IDE or code editor is running on.
|
||||
*/
|
||||
'local_path' => env('RAY_LOCAL_PATH', null),
|
||||
|
||||
/*
|
||||
* When this setting is enabled, the package will not try to format values sent to Ray.
|
||||
*/
|
||||
'always_send_raw_values' => false,
|
||||
];
|
27
database/migrations/2023_03_20_112410_create_activity_log_table.php
Executable file
27
database/migrations/2023_03_20_112410_create_activity_log_table.php
Executable file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateActivityLogTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::connection(config('activitylog.database_connection'))->create(config('activitylog.table_name'), function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('log_name')->nullable();
|
||||
$table->text('description');
|
||||
$table->nullableMorphs('subject', 'subject');
|
||||
$table->nullableMorphs('causer', 'causer');
|
||||
$table->json('properties')->nullable();
|
||||
$table->timestamps();
|
||||
$table->index('log_name');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name'));
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddEventColumnToActivityLogTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||
$table->string('event')->nullable()->after('subject_type');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||
$table->dropColumn('event');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddBatchUuidColumnToActivityLogTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||
$table->uuid('batch_uuid')->nullable()->after('properties');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||
$table->dropColumn('batch_uuid');
|
||||
});
|
||||
}
|
||||
}
|
32
database/migrations/2023_03_20_112810_create_jobs_table.php
Executable file
32
database/migrations/2023_03_20_112810_create_jobs_table.php
Executable file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
};
|
@ -1,24 +1,32 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
php:
|
||||
image: "coolify:${TAG:-4}"
|
||||
build:
|
||||
context: .
|
||||
context: ./docker/dev
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
WWWGROUP: '${WWWGROUP}'
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:80"
|
||||
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
||||
environment:
|
||||
PGID: "${USERID:-9999}"
|
||||
PUID: "${USERID:-9999}"
|
||||
SSL_MODE: 'off'
|
||||
WWWUSER: "${WWWUSER}"
|
||||
LARAVEL_SAIL: 1
|
||||
XDEBUG_MODE: "${SAIL_XDEBUG_MODE:-off}"
|
||||
XDEBUG_CONFIG: "${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}"
|
||||
volumes:
|
||||
- .:/var/www/html:cached
|
||||
- .:/var/www/html
|
||||
networks:
|
||||
- coolify
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
ports:
|
||||
- "${FORWARD_DB_PORT:-5432}:5432"
|
||||
volumes:
|
||||
- db-coolify:/var/lib/postgresql/data
|
||||
networks:
|
||||
- coolify
|
||||
environment:
|
||||
POSTGRES_USER: "${DB_USERNAME}"
|
||||
POSTGRES_PASSWORD: "${DB_PASSWORD}"
|
||||
@ -34,11 +42,22 @@ services:
|
||||
]
|
||||
retries: 3
|
||||
timeout: 5s
|
||||
mailpit:
|
||||
image: "axllent/mailpit:latest"
|
||||
ports:
|
||||
- "${FORWARD_MAILPIT_PORT:-1025}:1025"
|
||||
- "${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025"
|
||||
testing-host:
|
||||
container_name: coolify-testing-host
|
||||
image: coolify-testing-host
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
context: ./docker/testing-host
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./docker/testing-host/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf
|
||||
networks:
|
||||
- coolify
|
||||
|
||||
volumes:
|
||||
db-coolify:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
coolify:
|
||||
driver: bridge
|
||||
|
93
docker/dev/Dockerfile
Normal file
93
docker/dev/Dockerfile
Normal file
@ -0,0 +1,93 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG WWWGROUP
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
ARG NODE_VERSION=18
|
||||
ARG POSTGRES_VERSION=14
|
||||
|
||||
# https://download.docker.com/linux/static/stable/
|
||||
ARG DOCKER_VERSION=20.10.18
|
||||
# https://github.com/docker/compose/releases
|
||||
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
|
||||
ARG DOCKER_COMPOSE_VERSION=2.6.1
|
||||
# https://github.com/buildpacks/pack/releases
|
||||
ARG PACK_VERSION=v0.27.0
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV TZ=UTC
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \
|
||||
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y php8.2-cli php8.2-dev \
|
||||
php8.2-pgsql php8.2-sqlite3 php8.2-gd \
|
||||
php8.2-curl \
|
||||
php8.2-imap php8.2-mysql php8.2-mbstring \
|
||||
php8.2-xml php8.2-zip php8.2-bcmath php8.2-soap \
|
||||
php8.2-intl php8.2-readline \
|
||||
php8.2-ldap \
|
||||
php8.2-msgpack php8.2-igbinary php8.2-redis php8.2-swoole \
|
||||
php8.2-memcached php8.2-pcov php8.2-xdebug \
|
||||
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
|
||||
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npm install -g npm \
|
||||
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn.gpg >/dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
|
||||
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y yarn \
|
||||
&& apt-get install -y mysql-client \
|
||||
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2
|
||||
|
||||
RUN groupadd --force -g $WWWGROUP sail
|
||||
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
|
||||
|
||||
USER sail
|
||||
RUN mkdir -p ~/.ssh
|
||||
RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\
|
||||
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\
|
||||
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\
|
||||
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\
|
||||
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\
|
||||
-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519
|
||||
RUN chmod 0600 ~/.ssh/id_ed25519
|
||||
|
||||
USER root
|
||||
|
||||
COPY start-container /usr/local/bin/start-container
|
||||
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY php.ini /etc/php/8.2/cli/conf.d/99-sail.ini
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
# Install Docker CLI, Docker Compose, and Pack
|
||||
RUN mkdir -p ~/.docker/cli-plugins
|
||||
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
|
||||
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose -o /home/sail/.docker/cli-plugins/docker-compose
|
||||
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
|
||||
RUN curl -sSL https://nixpacks.com/install.sh | bash
|
||||
|
||||
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
|
||||
RUN chmod +x /usr/local/bin/pack
|
||||
|
||||
RUN mkdir -p /home/sail/.docker/cli-plugins
|
||||
RUN cp ~/.docker/cli-plugins/docker-compose /home/sail/.docker/cli-plugins/docker-compose
|
||||
RUN chown -R sail:sail /home/sail
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT ["start-container"]
|
4
docker/dev/php.ini
Normal file
4
docker/dev/php.ini
Normal file
@ -0,0 +1,4 @@
|
||||
[PHP]
|
||||
post_max_size = 100M
|
||||
upload_max_filesize = 100M
|
||||
variables_order = EGPCS
|
17
docker/dev/start-container
Normal file
17
docker/dev/start-container
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ ! -z "$WWWUSER" ]; then
|
||||
usermod -u $WWWUSER sail
|
||||
fi
|
||||
|
||||
if [ ! -d /.composer ]; then
|
||||
mkdir /.composer
|
||||
fi
|
||||
|
||||
chmod -R ugo+rw /.composer
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
exec gosu $WWWUSER "$@"
|
||||
else
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
fi
|
27
docker/dev/supervisord.conf
Normal file
27
docker/dev/supervisord.conf
Normal file
@ -0,0 +1,27 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:php]
|
||||
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80
|
||||
user=sail
|
||||
environment=LARAVEL_SAIL="1"
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:laravel-worker]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan queue:listen
|
||||
user=sail
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
numprocs=8
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/www/html/storage/logs/worker.log
|
||||
stopwaitsecs=3600
|
20
docker/staging/Dockerfile
Normal file
20
docker/staging/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
FROM serversideup/php:8.2-fpm-nginx
|
||||
|
||||
ARG NODE_VERSION=18
|
||||
ARG POSTGRES_VERSION=15
|
||||
|
||||
RUN apt-get update \
|
||||
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& npm install -g npm
|
||||
|
||||
RUN apt-get install -y php-pgsql openssh-client
|
||||
|
||||
RUN apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
||||
|
||||
USER root
|
||||
|
||||
# S6 Overlay config
|
||||
COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/
|
2
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/run
Normal file
2
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/run
Normal file
@ -0,0 +1,2 @@
|
||||
#!/command/execlineb -P
|
||||
su webuser -c "php /var/www/html/artisan queue:listen --tries=3"
|
1
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/type
Normal file
1
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/type
Normal file
@ -0,0 +1 @@
|
||||
longrun
|
67
docker/testing-host/Dockerfile
Normal file
67
docker/testing-host/Dockerfile
Normal file
@ -0,0 +1,67 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# https://download.docker.com/linux/static/stable/
|
||||
ARG DOCKER_VERSION=20.10.18
|
||||
# https://github.com/docker/compose/releases
|
||||
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
|
||||
ARG DOCKER_COMPOSE_VERSION=2.6.1
|
||||
# https://github.com/buildpacks/pack/releases
|
||||
ARG PACK_VERSION=v0.27.0
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV TZ=UTC
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor \
|
||||
sqlite3 libcap2-bin libpng-dev python2 dnsutils openssh-server sudo \
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Setup sshd
|
||||
RUN ssh-keygen -A
|
||||
RUN mkdir -p /run/sshd
|
||||
|
||||
# Install Docker CLI, Docker Compose, and Pack
|
||||
RUN mkdir -p ~/.docker/cli-plugins
|
||||
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
|
||||
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose
|
||||
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
|
||||
RUN curl -sSL https://nixpacks.com/install.sh | bash
|
||||
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
|
||||
RUN groupadd docker
|
||||
|
||||
# Setup coolify user
|
||||
RUN useradd -ms /bin/bash coolify
|
||||
RUN usermod -aG sudo coolify
|
||||
RUN usermod -aG docker coolify
|
||||
RUN echo 'coolify ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
# Setup ssh'ing into the destination as Coolify User
|
||||
USER coolify
|
||||
RUN mkdir -p ~/.ssh
|
||||
RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys
|
||||
|
||||
USER root
|
||||
|
||||
# Setup ssh'ing into the destination as Root
|
||||
RUN mkdir -p ~/.ssh
|
||||
RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys
|
||||
|
||||
EXPOSE 22
|
||||
|
||||
COPY start-container /usr/local/bin/start-container
|
||||
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
# Prepare projects
|
||||
RUN mkdir -p projects
|
||||
COPY dummy-project projects/dummy-project
|
||||
|
||||
ENTRYPOINT ["start-container"]
|
31
docker/testing-host/dummy-project/Dockerfile
Normal file
31
docker/testing-host/dummy-project/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG WWWGROUP
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV TZ=UTC
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \
|
||||
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y php8.2-cli php8.2-dev \
|
||||
php8.2-curl php8.2-mbstring php8.2-xml php8.2-zip php8.2-bcmath \
|
||||
php8.2-intl php8.2-readline php8.2-msgpack php8.2-igbinary \
|
||||
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
COPY . .
|
||||
|
||||
ENTRYPOINT ["php", "-S", "0.0.0.0:8000"]
|
10
docker/testing-host/dummy-project/docker-compose.yml
Normal file
10
docker/testing-host/dummy-project/docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
dummy-project:
|
||||
image: dummy-project
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
3
docker/testing-host/dummy-project/index.php
Normal file
3
docker/testing-host/dummy-project/index.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo "Hello World! " . date('Y-m-d H:i:s');
|
3
docker/testing-host/start-container
Normal file
3
docker/testing-host/start-container
Normal file
@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
13
docker/testing-host/supervisord.conf
Normal file
13
docker/testing-host/supervisord.conf
Normal file
@ -0,0 +1,13 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:sshd]
|
||||
command=/usr/sbin/sshd -D
|
||||
user=root
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
@ -1,3 +1,3 @@
|
||||
@tailwind base;
|
||||
/* @tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities; */
|
||||
|
3
resources/views/components/button.blade.php
Normal file
3
resources/views/components/button.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<button wire:loading.remove {{ $attributes }} class="btn btn-primary rounded-none btn-xs no-animation"> {{ $slot }} </button>
|
||||
|
||||
<button wire:loading class="btn btn-disabled rounded-none btn-xs no-animation"> {{ $slot }}</button>
|
24
resources/views/components/layout.blade.php
Normal file
24
resources/views/components/layout.blade.php
Normal file
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" data-theme="light" class="h-full">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ $title ?? 'Coolify' }}</title>
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
||||
@livewireStyles
|
||||
</head>
|
||||
|
||||
<body class="h-full">
|
||||
@auth
|
||||
<x-navbar />
|
||||
@endauth
|
||||
<main class="h-full pt-10 p-4">
|
||||
{{ $slot }}
|
||||
</main>
|
||||
|
||||
@livewireScripts
|
||||
</body>
|
||||
|
||||
</html>
|
15
resources/views/components/navbar.blade.php
Normal file
15
resources/views/components/navbar.blade.php
Normal file
@ -0,0 +1,15 @@
|
||||
<nav class="flex space-x-4 p-2 fixed right-0">
|
||||
@env('local')
|
||||
<a href="/run-command">Run command</a>
|
||||
{{-- <livewire:create-token /> --}}
|
||||
<a href="/debug">Debug</a>
|
||||
<a href="/debug/logs" target="_blank">Debug Logs</a>
|
||||
{{-- <a href="/debug/inertia">Debug(inertia)</a> --}}
|
||||
@endenv
|
||||
<a href="/">Dashboard</a>
|
||||
<a href="/profile">Profile</a>
|
||||
<form action="/logout" method="POST">
|
||||
@csrf
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
</nav>
|
5
resources/views/demo.blade.php
Normal file
5
resources/views/demo.blade.php
Normal file
@ -0,0 +1,5 @@
|
||||
<x-layout>
|
||||
|
||||
<livewire:run-command />
|
||||
|
||||
</x-layout>
|
29
resources/views/livewire/run-command.blade.php
Executable file
29
resources/views/livewire/run-command.blade.php
Executable file
@ -0,0 +1,29 @@
|
||||
<div>
|
||||
<div>
|
||||
<label for="command">
|
||||
<input class="py-2 rounded ring-1" id="command" wire:model="command" type="text" />
|
||||
</label>
|
||||
<button wire:click="runCommand">Run command</button>
|
||||
|
||||
<button wire:click="runSleepingBeauty">Run sleeping beauty</button>
|
||||
<button wire:click="runDummyProjectBuild">Build DummyProject</button>
|
||||
</div>
|
||||
<div>
|
||||
<input id="manualKeepAlive" name="manualKeepAlive" type="checkbox" wire:model="manualKeepAlive">
|
||||
<label for="manualKeepAlive">Real-time logs</label>
|
||||
@if ($isKeepAliveOn || $manualKeepAlive)
|
||||
Polling...
|
||||
@endif
|
||||
</div>
|
||||
@isset($activity?->id)
|
||||
<div>
|
||||
Activity: <span>{{ $activity?->id ?? 'waiting' }}</span>
|
||||
</div>
|
||||
<pre style="width: 100%;overflow-y: scroll;"
|
||||
@if ($isKeepAliveOn || $manualKeepAlive) wire:poll.750ms="polling" @endif> {{ data_get($activity, 'description') }}</pre>
|
||||
<div>
|
||||
<div>Details:</div>
|
||||
<pre style="width: 100%;overflow-y: scroll;">{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}</pre>
|
||||
</div>
|
||||
@endisset
|
||||
</div>
|
@ -11,8 +11,12 @@
|
||||
|
||||
<body class="antialiased">
|
||||
<h1 class="text-3xl font-bold">
|
||||
Hello from Coolify!
|
||||
Coolify v4
|
||||
</h1>
|
||||
|
||||
<p class="mt-4">
|
||||
<a href="/demo"> See demo </a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -16,3 +16,5 @@
|
||||
Route::get('/', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
|
||||
Route::view('/demo', 'demo');
|
||||
|
39
run
Executable file
39
run
Executable file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Inspired on https://github.com/adriancooney/Taskfile
|
||||
# Install an alias, to be able to simply execute `run` => echo 'alias run=./run' >> ~/.aliases
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
function help {
|
||||
echo "$0 <task> <args>"
|
||||
echo "Tasks:"
|
||||
compgen -A function | cat -n
|
||||
}
|
||||
|
||||
function default {
|
||||
help
|
||||
}
|
||||
|
||||
function bash {
|
||||
docker-compose exec -u $(id -u) php bash
|
||||
}
|
||||
|
||||
# The user with native SSH capability
|
||||
function coolify-bash {
|
||||
docker-compose exec -u coolify php bash
|
||||
}
|
||||
|
||||
function root-bash {
|
||||
docker-compose exec php bash
|
||||
}
|
||||
|
||||
# Usage: ./Taskfile envFile:set FOOBAR abc
|
||||
# This will set the FOOBAR variable to "abc" in the .env file
|
||||
function envFile:set {
|
||||
sed -i "s#^$1=.*#$1=$2#g" .env
|
||||
}
|
||||
|
||||
TIMEFORMAT="Task completed in %3lR"
|
||||
time "${@:-default}"
|
32
tests/Feature/DockerCommandsTest.php
Normal file
32
tests/Feature/DockerCommandsTest.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Tests\Support\Output;
|
||||
|
||||
it('starts a docker container correctly', function () {
|
||||
|
||||
$coolifyNamePrefix = 'coolify_test_';
|
||||
$format = '{"ID":"{{ .ID }}", "Image": "{{ .Image }}", "Names":"{{ .Names }}"}';
|
||||
$areThereCoolifyTestContainers = "docker ps --filter=\"name={$coolifyNamePrefix}*\" --format '{$format}' ";
|
||||
|
||||
// Generate a known name
|
||||
$containerName = 'coolify_test_' . now()->format('Ymd_his');
|
||||
$host = 'testing-host';
|
||||
|
||||
// Assert there's no containers start with coolify_test_*
|
||||
$processResult = coolifyProcess($areThereCoolifyTestContainers, $host);
|
||||
$containers = Output::containerList($processResult->output());
|
||||
expect($containers)->toBeEmpty();
|
||||
|
||||
// start a container nginx -d --name = $containerName
|
||||
$processResult = coolifyProcess("docker run -d --name {$containerName} nginx", $host);
|
||||
expect($processResult->successful())->toBeTrue();
|
||||
|
||||
// docker ps name = $container
|
||||
$processResult = coolifyProcess($areThereCoolifyTestContainers, $host);
|
||||
$containers = Output::containerList($processResult->output());
|
||||
expect($containers->where('Names', $containerName)->count())->toBe(1);
|
||||
|
||||
// Stop testing containers
|
||||
$processResult = coolifyProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host);
|
||||
expect($processResult->successful())->toBeTrue();
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
// use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic test example.
|
||||
*/
|
||||
public function test_the_application_returns_a_successful_response(): void
|
||||
{
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
}
|
48
tests/Pest.php
Normal file
48
tests/Pest.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Test Case
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||
| need to change it using the "uses()" function to bind a different classes or traits.
|
||||
|
|
||||
*/
|
||||
|
||||
uses(
|
||||
Tests\TestCase::class,
|
||||
// Illuminate\Foundation\Testing\RefreshDatabase::class,
|
||||
)->in('Feature');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expectations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
return $this->toBe(1);
|
||||
});
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
|
||||
function something()
|
||||
{
|
||||
// ..
|
||||
}
|
17
tests/Support/Output.php
Normal file
17
tests/Support/Output.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class Output
|
||||
{
|
||||
public static function containerList($rawOutput): Collection
|
||||
{
|
||||
$outputLines = explode(PHP_EOL, $rawOutput);
|
||||
|
||||
return collect($outputLines)
|
||||
->reject(fn($line) => empty($line))
|
||||
->map(fn($outputLine) => json_decode($outputLine, flags: JSON_THROW_ON_ERROR));
|
||||
}
|
||||
}
|
@ -1,16 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic test example.
|
||||
*/
|
||||
public function test_that_true_is_true(): void
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
test('that true is true', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user