diff --git a/app/Actions/RemoteProcess/DispatchRemoteProcess.php b/app/Actions/RemoteProcess/DispatchRemoteProcess.php index 95a55bc91..c1f0e8036 100644 --- a/app/Actions/RemoteProcess/DispatchRemoteProcess.php +++ b/app/Actions/RemoteProcess/DispatchRemoteProcess.php @@ -3,7 +3,6 @@ namespace App\Actions\RemoteProcess; use App\Data\RemoteProcessArgs; -use App\Jobs\DeployRemoteProcess; use App\Jobs\ExecuteRemoteProcess; use Spatie\Activitylog\Models\Activity; diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index fbd62df91..6627c1bd7 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -14,6 +14,8 @@ class RunRemoteProcess { public Activity $activity; + public bool $hideFromOutput; + protected $timeStart; protected $currentTime; @@ -29,7 +31,7 @@ class RunRemoteProcess /** * Create a new job instance. */ - public function __construct(Activity $activity) + public function __construct(Activity $activity, bool $hideFromOutput) { if ($activity->getExtraProperty('type') !== ActivityTypes::REMOTE_PROCESS->value && $activity->getExtraProperty('type') !== ActivityTypes::DEPLOYMENT->value) { @@ -37,6 +39,7 @@ class RunRemoteProcess } $this->activity = $activity; + $this->hideFromOutput = $hideFromOutput; } public function __invoke(): ProcessResult @@ -55,7 +58,7 @@ class RunRemoteProcess $this->activity->properties = $this->activity->properties->merge([ 'exitCode' => $processResult->exitCode(), - 'stdout' => $processResult->output(), + 'stdout' => $this->hideFromOutput || $processResult->output(), 'stderr' => $processResult->errorOutput(), 'status' => $status, ]); @@ -78,6 +81,9 @@ class RunRemoteProcess protected function handleOutput(string $type, string $output) { + if ($this->hideFromOutput) { + return; + } $this->currentTime = $this->elapsedTime(); if ($type === 'out') { diff --git a/app/Data/RemoteProcessArgs.php b/app/Data/RemoteProcessArgs.php index 57c46d813..cdf13cac4 100644 --- a/app/Data/RemoteProcessArgs.php +++ b/app/Data/RemoteProcessArgs.php @@ -10,7 +10,6 @@ use Spatie\LaravelData\Data; class RemoteProcessArgs extends Data { public function __construct( - public Model|null $model, public string $server_ip, public string $private_key_location, public string|null $deployment_uuid, @@ -19,6 +18,7 @@ class RemoteProcessArgs extends Data public string $user, public string $type = ActivityTypes::REMOTE_PROCESS->value, public string $status = ProcessStatus::HOLDING->value, + public ?Model $model = null, ) { } } diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index f9bc0e8bb..50612aaa4 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -17,6 +17,7 @@ class ProjectController extends Controller } return view('project.environments', ['project' => $project]); } + public function resources() { $project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); @@ -29,6 +30,7 @@ class ProjectController extends Controller } return view('project.resources', ['project' => $project, 'environment' => $environment]); } + public function application() { $project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); @@ -62,7 +64,9 @@ class ProjectController extends Controller if (!$application) { return redirect()->route('home'); } - $activity = $application->get_deployment($deployment_uuid); - return view('project.deployment', ['activity' => $activity]); + + return view('project.deployment', [ + 'deployment_uuid' => $deployment_uuid, + ]); } } diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 342e2e2f3..5ad4e7f00 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -3,6 +3,7 @@ namespace App\Http\Livewire; use App\Jobs\ContainerStatusJob; +use App\Jobs\DeployApplicationJob; use App\Models\Application; use App\Models\CoolifyInstanceSettings; use DateTimeImmutable; @@ -35,210 +36,22 @@ class DeployApplication extends Component $this->application = Application::where('uuid', $this->application_uuid)->first(); $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); } + public function render() { return view('livewire.deploy-application'); } - private function execute_in_builder(string $command) - { - return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'"; - // if ($this->application->settings->is_debug) { - // } else { - // return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'"; - // } - } - private function start_builder_container() - { - $this->command[] = "docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder >/dev/null 2>&1"; - } - private function generate_docker_compose() - { - $docker_compose = [ - 'version' => '3.8', - 'services' => [ - $this->application->uuid => [ - 'image' => "{$this->application->uuid}:TAG", - 'container_name' => $this->application->uuid, - 'restart' => 'always', - 'labels' => $this->set_labels_for_applications(), - 'expose' => $this->application->ports_exposes, - 'networks' => [ - $this->destination->network, - ], - 'healthcheck' => [ - 'test' => [ - 'CMD-SHELL', - $this->generate_healthcheck_commands() - ], - 'interval' => $this->application->health_check_interval . 's', - 'timeout' => $this->application->health_check_timeout . 's', - 'retries' => $this->application->health_check_retries, - 'start_period' => $this->application->health_check_start_period . 's' - ], - ] - ], - 'networks' => [ - $this->destination->network => [ - 'external' => false, - 'name' => $this->destination->network, - 'attachable' => true, - ] - ] - ]; - if (count($this->application->ports_mappings) > 0) { - $docker_compose['services'][$this->application->uuid]['ports'] = $this->application->ports_mappings; - } - // if (count($volumes) > 0) { - // $docker_compose['services'][$this->application->uuid]['volumes'] = $volumes; - // } - // if (count($volume_names) > 0) { - // $docker_compose['volumes'] = $volume_names; - // } - return Yaml::dump($docker_compose); - } - private function set_labels_for_applications() - { - $labels = []; - $labels[] = 'coolify.managed=true'; - $labels[] = 'coolify.version=' . config('coolify.version'); - $labels[] = 'coolify.applicationId=' . $this->application->id; - $labels[] = 'coolify.type=application'; - $labels[] = 'coolify.name=' . $this->application->name; - if ($this->application->fqdn) { - $labels[] = "traefik.http.routers.container.rule=Host(`{$this->application->fqdn}`)"; - } - return $labels; - } - private function generate_healthcheck_commands() - { - if (!$this->application->health_check_port) { - $this->application->health_check_port = $this->application->ports_exposes[0]; - } - if ($this->application->health_check_path) { - $generated_healthchecks_commands = [ - "curl -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$this->application->health_check_port}{$this->application->health_check_path}" - ]; - } else { - $generated_healthchecks_commands = []; - foreach ($this->application->ports_exposes as $key => $port) { - $generated_healthchecks_commands = [ - "curl -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$port}/" - ]; - if (count($this->application->ports_exposes) != $key + 1) { - $generated_healthchecks_commands[] = '&&'; - } - } - } - return implode(' ', $generated_healthchecks_commands); - } - private function generate_jwt_token_for_github() - { - $signingKey = InMemory::plainText($this->source->privateKey->private_key); - $algorithm = new Sha256(); - $tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default())); - $now = new DateTimeImmutable(); - $now = $now->setTime($now->format('H'), $now->format('i')); - $issuedToken = $tokenBuilder - ->issuedBy($this->source->app_id) - ->issuedAt($now) - ->expiresAt($now->modify('+10 minutes')) - ->getToken($algorithm, $signingKey) - ->toString(); - $token = Http::withHeaders([ - 'Authorization' => "Bearer $issuedToken", - 'Accept' => 'application/vnd.github.machine-man-preview+json' - ])->post("{$this->source->api_url}/app/installations/{$this->source->installation_id}/access_tokens"); - if ($token->failed()) { - throw new \Exception("Failed to get access token for $this->application_name from " . $this->source_name . " with error: " . $token->json()['message']); - } - return $token->json()['token']; - } + + public function deploy() { - $coolify_instance_settings = CoolifyInstanceSettings::find(1); - $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); - $this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first(); - - $source_html_url = data_get($this->application, 'source.html_url'); - $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL)); - $source_html_url_host = $url['host']; - $source_html_url_scheme = $url['scheme']; - - // Get Wildcard Domain - $project_wildcard_domain = data_get($this->application, 'environment.project.settings.wildcard_domain'); - $global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain'); - $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; - // Create Deployment ID $this->deployment_uuid = new Cuid2(7); - // Set wildcard domain - if (!$this->application->settings->is_bot && !$this->application->fqdn && $wildcard_domain) { - $this->application->fqdn = $this->application->uuid . '.' . $wildcard_domain; - $this->application->save(); - } - $workdir = "/artifacts/{$this->deployment_uuid}"; - - // Start build process - $this->command[] = "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}...'"; - $this->command[] = "echo -n 'Pulling latest version of the builder image (ghcr.io/coollabsio/coolify-builder)... '"; - $this->start_builder_container(); - $this->command[] = "echo 'Done.'"; - $this->command[] = "echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} to {$workdir}... '"; - if ($this->application->source->getMorphClass() == 'App\Models\GithubApp') { - if ($this->source->is_public) { - $this->execute_in_builder("git clone -q -b {$this->application->git_branch} {$this->source->html_url}/{$this->application->git_repository}.git {$workdir}"); - } else { - $github_access_token = $this->generate_jwt_token_for_github(); - $this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$workdir}"); - } - } - $this->command[] = "echo 'Done.'"; - // Export git commit to a file - $this->command[] = "echo -n 'Checking commit sha... '"; - $this->execute_in_builder("cd {$workdir} && git rev-parse HEAD > {$workdir}/.git-commit"); - $this->command[] = "echo 'Done.'"; - // Remove .git folder - $this->command[] = "echo -n 'Removing .git folder... '"; - $this->execute_in_builder("rm -fr {$workdir}/.git"); - $this->command[] = "echo 'Done.'"; - // Create docker-compose.yml && replace TAG with git commit - $docker_compose_base64 = base64_encode($this->generate_docker_compose($this->application)); - $this->execute_in_builder("echo '{$docker_compose_base64}' | base64 -d > {$workdir}/docker-compose.yml"); - $this->execute_in_builder("sed -i \"s/TAG/$(cat {$workdir}/.git-commit)/g\" {$workdir}/docker-compose.yml"); - - $this->command[] = "echo -n 'Generating nixpacks configuration... '"; - if (str_starts_with($this->application->base_image, 'apache') || str_starts_with($this->application->base_image, 'nginx')) { - // @TODO: Add static site builds - } else { - $nixpacks_command = "nixpacks build -o {$workdir} --no-error-without-start"; - if ($this->application->install_command) { - $nixpacks_command .= " --install-cmd '{$this->application->install_command}'"; - } - if ($this->application->build_command) { - $nixpacks_command .= " --build-cmd '{$this->application->build_command}'"; - } - if ($this->application->start_command) { - $nixpacks_command .= " --start-cmd '{$this->application->start_command}'"; - } - $nixpacks_command .= " {$workdir}"; - $this->execute_in_builder($nixpacks_command); - $this->execute_in_builder("cp {$workdir}/.nixpacks/Dockerfile {$workdir}/Dockerfile"); - $this->execute_in_builder("rm -f {$workdir}/.nixpacks/Dockerfile"); - } - $this->command[] = "echo 'Done.'"; - $this->command[] = "echo -n 'Building image... '"; - - $this->execute_in_builder("docker build -f {$workdir}/Dockerfile --build-arg SOURCE_COMMIT=$(cat {$workdir}/.git-commit) --progress plain -t {$this->application->uuid}:$(cat {$workdir}/.git-commit) {$workdir}"); - $this->command[] = "echo 'Done.'"; - $this->execute_in_builder("docker rm -f {$this->application->uuid} >/dev/null 2>&1"); - - $this->command[] = "echo -n 'Deploying... '"; - - $this->execute_in_builder("docker compose --project-directory {$workdir} up -d"); - $this->command[] = "echo 'Done. 🎉'"; - $this->command[] = "docker stop -t 0 {$this->deployment_uuid} >/dev/null"; - $this->activity = remoteProcess($this->command, $this->destination->server, $this->deployment_uuid, $this->application); + dispatch(new DeployApplicationJob( + deployment_uuid: $this->deployment_uuid, + application_uuid: $this->application_uuid, + )); $currentUrl = url()->previous(); $deploymentUrl = "$currentUrl/deployment/$this->deployment_uuid"; @@ -251,10 +64,12 @@ class DeployApplication extends Component $this->application->status = 'exited'; $this->application->save(); } + public function pollingStatus() { $this->application->refresh(); } + public function checkStatus() { $output = runRemoteCommandSync($this->destination->server, ["docker ps -a --format '{{.State}}' --filter 'name={$this->application->uuid}'"]); diff --git a/app/Http/Livewire/PollActivity.php b/app/Http/Livewire/PollActivity.php index 3a7822d8a..8092f57a5 100644 --- a/app/Http/Livewire/PollActivity.php +++ b/app/Http/Livewire/PollActivity.php @@ -3,15 +3,23 @@ namespace App\Http\Livewire; use Livewire\Component; +use Spatie\Activitylog\Models\Activity; class PollActivity extends Component { public $activity; public $isKeepAliveOn = true; + public $deployment_uuid; public function polling() { - $this->activity?->refresh(); + if ( is_null($this->activity) && isset($this->deployment_uuid)) { + $this->activity = Activity::where('properties->deployment_uuid', '=', $this->deployment_uuid) + ->first(); + } else { + $this->activity?->refresh(); + } + if (data_get($this->activity, 'properties.exitCode') !== null) { $this->isKeepAliveOn = false; } diff --git a/app/Jobs/DeployApplicationJob.php b/app/Jobs/DeployApplicationJob.php new file mode 100644 index 000000000..647fb1ff1 --- /dev/null +++ b/app/Jobs/DeployApplicationJob.php @@ -0,0 +1,305 @@ +application = Application::query() + ->where('uuid', $this->application_uuid) + ->firstOrFail(); + $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); + + $server = $this->destination->server; + + $private_key_location = savePrivateKey($server); + + $remoteProcessArgs = new RemoteProcessArgs( + server_ip: $server->ip, + private_key_location: $private_key_location, + deployment_uuid: $this->deployment_uuid, + command: 'overwritten-later', + port: $server->port, + user: $server->user, + type: ActivityTypes::DEPLOYMENT->value, + ); + + $this->activity = activity() + ->performedOn($this->application) + ->withProperties($remoteProcessArgs->toArray()) + ->event(ActivityTypes::DEPLOYMENT->value) + ->log(""); + } + + /** + * Execute the job. + */ + public function handle(): void + { + $coolify_instance_settings = CoolifyInstanceSettings::find(1); + $this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first(); + + // Get Wildcard Domain + $project_wildcard_domain = data_get($this->application, 'environment.project.settings.wildcard_domain'); + $global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain'); + $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; + + // Set wildcard domain + if (!$this->application->settings->is_bot && !$this->application->fqdn && $wildcard_domain) { + $this->application->fqdn = $this->application->uuid . '.' . $wildcard_domain; + $this->application->save(); + } + $this->workdir = "/artifacts/{$this->deployment_uuid}"; + + // Pull builder image + $this->executeNow([ + "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}...'", + "echo -n 'Pulling latest version of the builder image (ghcr.io/coollabsio/coolify-builder)... '", + "docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder >/dev/null 2>&1", + "echo 'Done.'", + ], 'docker_pull_builder_image'); + + // Import git repository + $this->executeNow([ + "echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} to {$this->workdir}... '", + $this->gitImport(), + "echo 'Done.'" + ], 'importing_git_repository'); + + // Get git commit + $this->executeNow([$this->execute_in_builder("cd {$this->workdir} && git rev-parse HEAD")], 'commit_sha', hideFromOutput: true); + $this->git_commit = $this->activity->properties->get('commit_sha'); + + $this->executeNow([ + $this->execute_in_builder("rm -fr {$this->workdir}/.git") + ], hideFromOutput: true); + + $docker_compose_base64 = base64_encode($this->generate_docker_compose()); + $this->executeNow([ + $this->execute_in_builder("echo '{$docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml") + ], hideFromOutput: true); + + $this->executeNow([ + "echo -n 'Generating nixpacks configuration... '", + $this->nixpacks_build_cmd(), + $this->execute_in_builder("cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile"), + $this->execute_in_builder("rm -f {$this->workdir}/.nixpacks/Dockerfile"), + "echo 'Done.'", + "echo -n 'Building image... '", + $this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile --build-arg SOURCE_COMMIT={$this->git_commit} --progress plain -t {$this->application->uuid}:{$this->git_commit} {$this->workdir}"), + "echo 'Done.'", + $this->execute_in_builder("docker rm -f {$this->application->uuid} >/dev/null 2>&1"), + "echo -n 'Deploying... '", + $this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d"), + "echo 'Done. 🎉'", + "docker stop -t 0 {$this->deployment_uuid} >/dev/null" + ]); + } + + private function execute_in_builder(string $command) + { + return "docker exec {$this->deployment_uuid} bash -c '{$command}'"; + } + + private function generate_docker_compose() + { + + $docker_compose = [ + 'version' => '3.8', + 'services' => [ + $this->application->uuid => [ + 'image' => "{$this->application->uuid}:$this->git_commit", + 'container_name' => $this->application->uuid, + 'restart' => 'always', + 'labels' => $this->set_labels_for_applications(), + 'expose' => $this->application->ports_exposes, + 'networks' => [ + $this->destination->network, + ], + 'healthcheck' => [ + 'test' => [ + 'CMD-SHELL', + $this->generate_healthcheck_commands() + ], + 'interval' => $this->application->health_check_interval . 's', + 'timeout' => $this->application->health_check_timeout . 's', + 'retries' => $this->application->health_check_retries, + 'start_period' => $this->application->health_check_start_period . 's' + ], + ] + ], + 'networks' => [ + $this->destination->network => [ + 'external' => false, + 'name' => $this->destination->network, + 'attachable' => true, + ] + ] + ]; + if (count($this->application->ports_mappings) > 0) { + $docker_compose['services'][$this->application->uuid]['ports'] = $this->application->ports_mappings; + } + // if (count($volumes) > 0) { + // $docker_compose['services'][$this->application->uuid]['volumes'] = $volumes; + // } + // if (count($volume_names) > 0) { + // $docker_compose['volumes'] = $volume_names; + // } + return Yaml::dump($docker_compose); + } + + private function generate_healthcheck_commands() + { + if (!$this->application->health_check_port) { + $this->application->health_check_port = $this->application->ports_exposes[0]; + } + if ($this->application->health_check_path) { + $generated_healthchecks_commands = [ + "curl -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$this->application->health_check_port}{$this->application->health_check_path}" + ]; + } else { + $generated_healthchecks_commands = []; + foreach ($this->application->ports_exposes as $key => $port) { + $generated_healthchecks_commands = [ + "curl -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$port}/" + ]; + if (count($this->application->ports_exposes) != $key + 1) { + $generated_healthchecks_commands[] = '&&'; + } + } + } + return implode(' ', $generated_healthchecks_commands); + } + + private function generate_jwt_token_for_github() + { + $signingKey = InMemory::plainText($this->source->privateKey->private_key); + $algorithm = new Sha256(); + $tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default())); + $now = new DateTimeImmutable(); + $now = $now->setTime($now->format('H'), $now->format('i')); + $issuedToken = $tokenBuilder + ->issuedBy($this->source->app_id) + ->issuedAt($now) + ->expiresAt($now->modify('+10 minutes')) + ->getToken($algorithm, $signingKey) + ->toString(); + $token = Http::withHeaders([ + 'Authorization' => "Bearer $issuedToken", + 'Accept' => 'application/vnd.github.machine-man-preview+json' + ])->post("{$this->source->api_url}/app/installations/{$this->source->installation_id}/access_tokens"); + if ($token->failed()) { + throw new \Exception("Failed to get access token for $this->application->name from " . $this->source->name . " with error: " . $token->json()['message']); + } + return $token->json()['token']; + } + + private function set_labels_for_applications() + { + $labels = []; + $labels[] = 'coolify.managed=true'; + $labels[] = 'coolify.version=' . config('coolify.version'); + $labels[] = 'coolify.applicationId=' . $this->application->id; + $labels[] = 'coolify.type=application'; + $labels[] = 'coolify.name=' . $this->application->name; + if ($this->application->fqdn) { + $labels[] = "traefik.http.routers.container.rule=Host(`{$this->application->fqdn}`)"; + } + return $labels; + } + + private function executeNow(array $command, string $propertyName = null, bool $hideFromOutput = false) + { + $commandText = collect($command)->implode("\n"); + + $this->activity->properties = $this->activity->properties->merge([ + 'command' => $commandText, + ]); + $this->activity->save(); + + $remoteProcess = resolve(RunRemoteProcess::class, [ + 'activity' => $this->activity, + 'hideFromOutput' => $hideFromOutput, + ]); + + if ($propertyName) { + $result = $remoteProcess(); + $this->activity->properties = $this->activity->properties->merge([ + $propertyName => trim($result->output()), + ]); + $this->activity->save(); + } else { + $remoteProcess(); + } + } + private function gitImport() + { + $source_html_url = data_get($this->application, 'source.html_url'); + $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL)); + $source_html_url_host = $url['host']; + $source_html_url_scheme = $url['scheme']; + if ($this->application->source->getMorphClass() == 'App\Models\GithubApp') { + if ($this->source->is_public) { + return $this->execute_in_builder("git clone -q -b {$this->application->git_branch} {$this->source->html_url}/{$this->application->git_repository}.git {$this->workdir}"); + } else { + $github_access_token = $this->generate_jwt_token_for_github(); + return $this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}"); + } + } + } + private function nixpacks_build_cmd() + { + if (str_starts_with($this->application->base_image, 'apache') || str_starts_with($this->application->base_image, 'nginx')) { + // @TODO: Add static site builds + } else { + $nixpacks_command = "nixpacks build -o {$this->workdir} --no-error-without-start"; + if ($this->application->install_command) { + $nixpacks_command .= " --install-cmd '{$this->application->install_command}'"; + } + if ($this->application->build_command) { + $nixpacks_command .= " --build-cmd '{$this->application->build_command}'"; + } + if ($this->application->start_command) { + $nixpacks_command .= " --start-cmd '{$this->application->start_command}'"; + } + $nixpacks_command .= " {$this->workdir}"; + } + return $this->execute_in_builder($nixpacks_command); + } +} diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index b613cf109..d68d413b4 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -20,8 +20,8 @@ if (!function_exists('remoteProcess')) { function remoteProcess( array $command, Server $server, - string|null $deployment_uuid = null, - Model|null $model = null, + ?string $deployment_uuid = null, + ?Model $model = null, ): Activity { $command_string = implode("\n", $command); // @TODO: Check if the user has access to this server @@ -31,28 +31,29 @@ if (!function_exists('remoteProcess')) { return resolve(DispatchRemoteProcess::class, [ 'remoteProcessArgs' => new RemoteProcessArgs( - type: $deployment_uuid ? ActivityTypes::DEPLOYMENT->value : ActivityTypes::REMOTE_PROCESS->value, model: $model, server_ip: $server->ip, - deployment_uuid: $deployment_uuid, private_key_location: $private_key_location, + deployment_uuid: $deployment_uuid, command: <<port, user: $server->user, + type: $deployment_uuid ? ActivityTypes::DEPLOYMENT->value : ActivityTypes::REMOTE_PROCESS->value, ), ])(); } - // function checkTeam(string $team_id) - // { - // $found_team = auth()->user()->teams->pluck('id')->contains($team_id); - // if (!$found_team) { - // throw new \RuntimeException('You do not have access to this server.'); - // } - // } } +// function checkTeam(string $team_id) +// { +// $found_team = auth()->user()->teams->pluck('id')->contains($team_id); +// if (!$found_team) { +// throw new \RuntimeException('You do not have access to this server.'); +// } +// } + if (!function_exists('savePrivateKey')) { function savePrivateKey(Server $server) { @@ -63,7 +64,7 @@ if (!function_exists('savePrivateKey')) { } if (!function_exists('generateSshCommand')) { - function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, string $command, bool $isMux = true) + function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, string $command, bool $isMux = false) { $delimiter = 'EOF-COOLIFY-SSH'; Storage::disk('local')->makeDirectory('.ssh'); diff --git a/database/seeders/ServerSeeder.php b/database/seeders/ServerSeeder.php index 548856ba7..632d947d4 100644 --- a/database/seeders/ServerSeeder.php +++ b/database/seeders/ServerSeeder.php @@ -38,7 +38,7 @@ class ServerSeeder extends Seeder 'name' => "localhost", 'description' => "This is the local machine", 'user' => 'root', - 'ip' => "172.17.0.1", + 'ip' => "coolify-testing-host", 'team_id' => $root_team->id, 'private_key_id' => $private_key_1->id, ]); diff --git a/resources/views/livewire/poll-activity.blade.php b/resources/views/livewire/poll-activity.blade.php index 389483dc1..bc939f7d4 100644 --- a/resources/views/livewire/poll-activity.blade.php +++ b/resources/views/livewire/poll-activity.blade.php @@ -1,6 +1,5 @@
- @isset($activity?->id) -
{{ data_get($activity, 'description') }}
- @endisset - {{--
{{ data_get($activity, 'properties') }}
--}} +
+        {{ data_get($activity, 'description') }}
+    
diff --git a/resources/views/project/deployment.blade.php b/resources/views/project/deployment.blade.php index c49e8112e..750b7d9e9 100644 --- a/resources/views/project/deployment.blade.php +++ b/resources/views/project/deployment.blade.php @@ -1,4 +1,4 @@

Deployment

- +