@@ -195,6 +195,31 @@ class SecurityController extends Controller
|
|||||||
if (! $request->description) {
|
if (! $request->description) {
|
||||||
$request->offsetSet('description', 'Created by Coolify via API');
|
$request->offsetSet('description', 'Created by Coolify via API');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$isPrivateKeyString = str_starts_with($request->private_key, '-----BEGIN');
|
||||||
|
if (! $isPrivateKeyString) {
|
||||||
|
try {
|
||||||
|
$base64PrivateKey = base64_decode($request->private_key);
|
||||||
|
$request->offsetSet('private_key', $base64PrivateKey);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Invalid private key.',
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$isPrivateKeyValid = PrivateKey::validatePrivateKey($request->private_key);
|
||||||
|
if (! $isPrivateKeyValid) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Invalid private key.',
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
$fingerPrint = PrivateKey::generateFingerprint($request->private_key);
|
||||||
|
$isFingerPrintExists = PrivateKey::fingerprintExists($fingerPrint);
|
||||||
|
if ($isFingerPrintExists) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Private key already exists.',
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
$key = PrivateKey::create([
|
$key = PrivateKey::create([
|
||||||
'team_id' => $teamId,
|
'team_id' => $teamId,
|
||||||
'name' => $request->name,
|
'name' => $request->name,
|
||||||
|
|||||||
@@ -530,11 +530,11 @@ class ServersController extends Controller
|
|||||||
'user' => $request->user,
|
'user' => $request->user,
|
||||||
'private_key_id' => $privateKey->id,
|
'private_key_id' => $privateKey->id,
|
||||||
'team_id' => $teamId,
|
'team_id' => $teamId,
|
||||||
'proxy' => [
|
|
||||||
'type' => $proxyType,
|
|
||||||
'status' => ProxyStatus::EXITED->value,
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
|
$server->proxy->set('type', $proxyType);
|
||||||
|
$server->proxy->set('status', ProxyStatus::EXITED->value);
|
||||||
|
$server->save();
|
||||||
|
|
||||||
$server->settings()->update([
|
$server->settings()->update([
|
||||||
'is_build_server' => $request->is_build_server,
|
'is_build_server' => $request->is_build_server,
|
||||||
]);
|
]);
|
||||||
@@ -742,6 +742,9 @@ class ServersController extends Controller
|
|||||||
if ($server->definedResources()->count() > 0) {
|
if ($server->definedResources()->count() > 0) {
|
||||||
return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400);
|
return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400);
|
||||||
}
|
}
|
||||||
|
if ($server->isLocalhost()) {
|
||||||
|
return response()->json(['message' => 'Local server cannot be deleted.'], 400);
|
||||||
|
}
|
||||||
$server->delete();
|
$server->delete();
|
||||||
DeleteServer::dispatch($server);
|
DeleteServer::dispatch($server);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Models\Application;
|
|||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
|
use App\Services\DockerImageParser;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -28,12 +29,10 @@ class DockerImage extends Component
|
|||||||
$this->validate([
|
$this->validate([
|
||||||
'dockerImage' => 'required',
|
'dockerImage' => 'required',
|
||||||
]);
|
]);
|
||||||
$image = str($this->dockerImage)->before(':');
|
|
||||||
if (str($this->dockerImage)->contains(':')) {
|
$parser = new DockerImageParser;
|
||||||
$tag = str($this->dockerImage)->after(':');
|
$parser->parse($this->dockerImage);
|
||||||
} else {
|
|
||||||
$tag = 'latest';
|
|
||||||
}
|
|
||||||
$destination_uuid = $this->query['destination'];
|
$destination_uuid = $this->query['destination'];
|
||||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
@@ -53,8 +52,8 @@ class DockerImage extends Component
|
|||||||
'git_branch' => 'main',
|
'git_branch' => 'main',
|
||||||
'build_pack' => 'dockerimage',
|
'build_pack' => 'dockerimage',
|
||||||
'ports_exposes' => 80,
|
'ports_exposes' => 80,
|
||||||
'docker_registry_image_name' => $image,
|
'docker_registry_image_name' => $parser->getFullImageNameWithoutTag(),
|
||||||
'docker_registry_image_tag' => $tag,
|
'docker_registry_image_tag' => $parser->getTag(),
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $environment->id,
|
||||||
'destination_id' => $destination->id,
|
'destination_id' => $destination->id,
|
||||||
'destination_type' => $destination_class,
|
'destination_type' => $destination_class,
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ class PrivateKey extends BaseModel
|
|||||||
'private_key' => 'encrypted',
|
'private_key' => 'encrypted',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $appends = ['public_key'];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::saving(function ($key) {
|
static::saving(function ($key) {
|
||||||
@@ -64,6 +66,11 @@ class PrivateKey extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPublicKeyAttribute()
|
||||||
|
{
|
||||||
|
return self::extractPublicKeyFromPrivate($this->private_key) ?? 'Error loading private key';
|
||||||
|
}
|
||||||
|
|
||||||
public function getPublicKey()
|
public function getPublicKey()
|
||||||
{
|
{
|
||||||
return self::extractPublicKeyFromPrivate($this->private_key) ?? 'Error loading private key';
|
return self::extractPublicKeyFromPrivate($this->private_key) ?? 'Error loading private key';
|
||||||
@@ -208,15 +215,14 @@ class PrivateKey extends BaseModel
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$key = PublicKeyLoader::load($privateKey);
|
$key = PublicKeyLoader::load($privateKey);
|
||||||
$publicKey = $key->getPublicKey();
|
|
||||||
|
|
||||||
return $publicKey->getFingerprint('sha256');
|
return $key->getPublicKey()->getFingerprint('sha256');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function fingerprintExists($fingerprint, $excludeId = null)
|
public static function fingerprintExists($fingerprint, $excludeId = null)
|
||||||
{
|
{
|
||||||
$query = self::query()
|
$query = self::query()
|
||||||
->where('fingerprint', $fingerprint)
|
->where('fingerprint', $fingerprint)
|
||||||
|
|||||||
74
app/Services/DockerImageParser.php
Normal file
74
app/Services/DockerImageParser.php
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
class DockerImageParser
|
||||||
|
{
|
||||||
|
private string $registryUrl = '';
|
||||||
|
|
||||||
|
private string $imageName = '';
|
||||||
|
|
||||||
|
private string $tag = 'latest';
|
||||||
|
|
||||||
|
public function parse(string $imageString): self
|
||||||
|
{
|
||||||
|
// First split by : to handle the tag, but be careful with registry ports
|
||||||
|
$lastColon = strrpos($imageString, ':');
|
||||||
|
$hasSlash = str_contains($imageString, '/');
|
||||||
|
|
||||||
|
// If the last colon appears after the last slash, it's a tag
|
||||||
|
// Otherwise it might be a port in the registry URL
|
||||||
|
if ($lastColon !== false && (! $hasSlash || $lastColon > strrpos($imageString, '/'))) {
|
||||||
|
$mainPart = substr($imageString, 0, $lastColon);
|
||||||
|
$this->tag = substr($imageString, $lastColon + 1);
|
||||||
|
} else {
|
||||||
|
$mainPart = $imageString;
|
||||||
|
$this->tag = 'latest';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the main part by / to handle registry and image name
|
||||||
|
$pathParts = explode('/', $mainPart);
|
||||||
|
|
||||||
|
// If we have more than one part and the first part contains a dot or colon
|
||||||
|
// it's likely a registry URL
|
||||||
|
if (count($pathParts) > 1 && (str_contains($pathParts[0], '.') || str_contains($pathParts[0], ':'))) {
|
||||||
|
$this->registryUrl = array_shift($pathParts);
|
||||||
|
$this->imageName = implode('/', $pathParts);
|
||||||
|
} else {
|
||||||
|
$this->imageName = $mainPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFullImageNameWithoutTag(): string
|
||||||
|
{
|
||||||
|
return $this->registryUrl.'/'.$this->imageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRegistryUrl(): string
|
||||||
|
{
|
||||||
|
return $this->registryUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageName(): string
|
||||||
|
{
|
||||||
|
return $this->imageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTag(): string
|
||||||
|
{
|
||||||
|
return $this->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString(): string
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
if ($this->registryUrl) {
|
||||||
|
$parts[] = $this->registryUrl;
|
||||||
|
}
|
||||||
|
$parts[] = $this->imageName;
|
||||||
|
|
||||||
|
return implode('/', $parts).':'.$this->tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2872,7 +2872,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
data_forget($service, 'volumes.*.is_directory');
|
data_forget($service, 'volumes.*.is_directory');
|
||||||
data_forget($service, 'exclude_from_hc');
|
data_forget($service, 'exclude_from_hc');
|
||||||
data_set($service, 'environment', $serviceVariables->toArray());
|
data_set($service, 'environment', $serviceVariables->toArray());
|
||||||
updateCompose($savedService);
|
updateCompose($service);
|
||||||
|
|
||||||
return $service;
|
return $service;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'coolify' => [
|
'coolify' => [
|
||||||
'version' => '4.0.0-beta.382',
|
'version' => '4.0.0-beta.383',
|
||||||
'self_hosted' => env('SELF_HOSTED', true),
|
'self_hosted' => env('SELF_HOSTED', true),
|
||||||
'autoupdate' => env('AUTOUPDATE'),
|
'autoupdate' => env('AUTOUPDATE'),
|
||||||
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ set -e # Exit immediately if a command exits with a non-zero status
|
|||||||
## $1 could be empty, so we need to disable this check
|
## $1 could be empty, so we need to disable this check
|
||||||
#set -u # Treat unset variables as an error and exit
|
#set -u # Treat unset variables as an error and exit
|
||||||
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||||
CDN="https://cdn.coollabs.io/coolify"
|
CDN="https://cdn.coollabs.io/coolify-nightly"
|
||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.6"
|
VERSION="1.7"
|
||||||
DOCKER_VERSION="27.0"
|
DOCKER_VERSION="27.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
@@ -488,13 +488,13 @@ fi
|
|||||||
|
|
||||||
# Add default root user credentials from environment variables
|
# Add default root user credentials from environment variables
|
||||||
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
|
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
|
||||||
if ! grep -q "^ROOT_USERNAME=" "$ENV_FILE-$DATE"; then
|
if grep -q "^ROOT_USERNAME=" "$ENV_FILE-$DATE"; then
|
||||||
sed -i "s|^ROOT_USERNAME=.*|ROOT_USERNAME=$ROOT_USERNAME|" "$ENV_FILE-$DATE"
|
sed -i "s|^ROOT_USERNAME=.*|ROOT_USERNAME=$ROOT_USERNAME|" "$ENV_FILE-$DATE"
|
||||||
fi
|
fi
|
||||||
if ! grep -q "^ROOT_USER_EMAIL=" "$ENV_FILE-$DATE"; then
|
if grep -q "^ROOT_USER_EMAIL=" "$ENV_FILE-$DATE"; then
|
||||||
sed -i "s|^ROOT_USER_EMAIL=.*|ROOT_USER_EMAIL=$ROOT_USER_EMAIL|" "$ENV_FILE-$DATE"
|
sed -i "s|^ROOT_USER_EMAIL=.*|ROOT_USER_EMAIL=$ROOT_USER_EMAIL|" "$ENV_FILE-$DATE"
|
||||||
fi
|
fi
|
||||||
if ! grep -q "^ROOT_USER_PASSWORD=" "$ENV_FILE-$DATE"; then
|
if grep -q "^ROOT_USER_PASSWORD=" "$ENV_FILE-$DATE"; then
|
||||||
sed -i "s|^ROOT_USER_PASSWORD=.*|ROOT_USER_PASSWORD=$ROOT_USER_PASSWORD|" "$ENV_FILE-$DATE"
|
sed -i "s|^ROOT_USER_PASSWORD=.*|ROOT_USER_PASSWORD=$ROOT_USER_PASSWORD|" "$ENV_FILE-$DATE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
<h3 class="pt-6">Swarm <span class="text-xs text-neutral-500">(experimental)</span></h3>
|
||||||
<div class="pb-4">Read the docs <a class='dark:text-white'
|
<div class="pb-4">Read the docs <a class='underline dark:text-white'
|
||||||
href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.</div>
|
href='https://coolify.io/docs/knowledge-base/docker/swarm' target='_blank'>here</a>.</div>
|
||||||
@if ($is_swarm_worker || $is_build_server)
|
@if ($is_swarm_worker || $is_build_server)
|
||||||
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_manager"
|
<x-forms.checkbox disabled instantSave type="checkbox" id="is_swarm_manager"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ set -o pipefail # Cause a pipeline to return the status of the last command that
|
|||||||
CDN="https://cdn.coollabs.io/coolify"
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.6"
|
VERSION="1.7"
|
||||||
DOCKER_VERSION="27.0"
|
DOCKER_VERSION="27.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
@@ -22,6 +22,11 @@ echo -e "Welcome to Coolify Installer!"
|
|||||||
echo -e "This script will install everything for you. Sit back and relax."
|
echo -e "This script will install everything for you. Sit back and relax."
|
||||||
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
||||||
|
|
||||||
|
# Predefined root user
|
||||||
|
ROOT_USERNAME=${ROOT_USERNAME:-}
|
||||||
|
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
||||||
|
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
||||||
|
|
||||||
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||||
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||||
REQUIRED_TOTAL_SPACE=30
|
REQUIRED_TOTAL_SPACE=30
|
||||||
@@ -481,6 +486,19 @@ else
|
|||||||
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Add default root user credentials from environment variables
|
||||||
|
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
|
||||||
|
if grep -q "^ROOT_USERNAME=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USERNAME=.*|ROOT_USERNAME=$ROOT_USERNAME|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
if grep -q "^ROOT_USER_EMAIL=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USER_EMAIL=.*|ROOT_USER_EMAIL=$ROOT_USER_EMAIL|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
if grep -q "^ROOT_USER_PASSWORD=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USER_PASSWORD=.*|ROOT_USER_PASSWORD=$ROOT_USER_PASSWORD|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
echo -e "7. Propagating .env with new values - if necessary."
|
echo -e "7. Propagating .env with new values - if necessary."
|
||||||
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ fi
|
|||||||
docker network create --attachable coolify 2>/dev/null
|
docker network create --attachable coolify 2>/dev/null
|
||||||
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null
|
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null
|
||||||
|
|
||||||
|
echo "If you encounter any issues, please check the log file: $LOGFILE"
|
||||||
if [ -f /data/coolify/source/docker-compose.custom.yml ]; then
|
if [ -f /data/coolify/source/docker-compose.custom.yml ]; then
|
||||||
echo "docker-compose.custom.yml detected." >> $LOGFILE
|
echo "docker-compose.custom.yml detected." >> $LOGFILE
|
||||||
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper:${LATEST_HELPER_VERSION} bash -c "LATEST_IMAGE=${LATEST_IMAGE} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --force-recreate --wait --wait-timeout 60" >> $LOGFILE 2>&1
|
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper:${LATEST_HELPER_VERSION} bash -c "LATEST_IMAGE=${LATEST_IMAGE} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --force-recreate --wait --wait-timeout 60" >> $LOGFILE 2>&1
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:12
|
image: pgvector/pgvector:pg12
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- postgres-data:/var/lib/postgresql/data
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
94
tests/Unit/Services/DockerImageParserTest.php
Normal file
94
tests/Unit/Services/DockerImageParserTest.php
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Services;
|
||||||
|
|
||||||
|
use App\Services\DockerImageParser;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DockerImageParserTest extends TestCase
|
||||||
|
{
|
||||||
|
private DockerImageParser $parser;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->parser = new DockerImageParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_parses_simple_image_name()
|
||||||
|
{
|
||||||
|
$this->parser->parse('nginx');
|
||||||
|
|
||||||
|
$this->assertEquals('', $this->parser->getRegistryUrl());
|
||||||
|
$this->assertEquals('nginx', $this->parser->getImageName());
|
||||||
|
$this->assertEquals('latest', $this->parser->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_parses_image_with_tag()
|
||||||
|
{
|
||||||
|
$this->parser->parse('nginx:1.19');
|
||||||
|
|
||||||
|
$this->assertEquals('', $this->parser->getRegistryUrl());
|
||||||
|
$this->assertEquals('nginx', $this->parser->getImageName());
|
||||||
|
$this->assertEquals('1.19', $this->parser->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_parses_image_with_organization()
|
||||||
|
{
|
||||||
|
$this->parser->parse('coollabs/coolify:latest');
|
||||||
|
|
||||||
|
$this->assertEquals('', $this->parser->getRegistryUrl());
|
||||||
|
$this->assertEquals('coollabs/coolify', $this->parser->getImageName());
|
||||||
|
$this->assertEquals('latest', $this->parser->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_parses_image_with_registry_url()
|
||||||
|
{
|
||||||
|
$this->parser->parse('ghcr.io/coollabs/coolify:v4');
|
||||||
|
|
||||||
|
$this->assertEquals('ghcr.io', $this->parser->getRegistryUrl());
|
||||||
|
$this->assertEquals('coollabs/coolify', $this->parser->getImageName());
|
||||||
|
$this->assertEquals('v4', $this->parser->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_parses_image_with_port_in_registry()
|
||||||
|
{
|
||||||
|
$this->parser->parse('localhost:5000/my-app:dev');
|
||||||
|
|
||||||
|
$this->assertEquals('localhost:5000', $this->parser->getRegistryUrl());
|
||||||
|
$this->assertEquals('my-app', $this->parser->getImageName());
|
||||||
|
$this->assertEquals('dev', $this->parser->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_parses_image_without_tag()
|
||||||
|
{
|
||||||
|
$this->parser->parse('ghcr.io/coollabs/coolify');
|
||||||
|
|
||||||
|
$this->assertEquals('ghcr.io', $this->parser->getRegistryUrl());
|
||||||
|
$this->assertEquals('coollabs/coolify', $this->parser->getImageName());
|
||||||
|
$this->assertEquals('latest', $this->parser->getTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_converts_back_to_string()
|
||||||
|
{
|
||||||
|
$originalString = 'ghcr.io/coollabs/coolify:v4';
|
||||||
|
$this->parser->parse($originalString);
|
||||||
|
|
||||||
|
$this->assertEquals($originalString, $this->parser->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_converts_to_string_with_default_tag()
|
||||||
|
{
|
||||||
|
$this->parser->parse('nginx');
|
||||||
|
$this->assertEquals('nginx:latest', $this->parser->toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.382"
|
"version": "4.0.0-beta.383"
|
||||||
},
|
},
|
||||||
"nightly": {
|
"nightly": {
|
||||||
"version": "4.0.0-beta.383"
|
"version": "4.0.0-beta.384"
|
||||||
},
|
},
|
||||||
"helper": {
|
"helper": {
|
||||||
"version": "1.0.4"
|
"version": "1.0.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user