Merge branch 'next' into patch-1
This commit is contained in:
commit
9f223959a4
20 changed files with 314 additions and 61 deletions
8
.github/workflows/coolify-helper-next.yml
vendored
8
.github/workflows/coolify-helper-next.yml
vendored
|
|
@ -44,8 +44,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
@ -86,8 +86,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
|
|||
8
.github/workflows/coolify-helper.yml
vendored
8
.github/workflows/coolify-helper.yml
vendored
|
|
@ -44,8 +44,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
@ -85,8 +85,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
@ -91,8 +91,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
|
|||
8
.github/workflows/coolify-realtime-next.yml
vendored
8
.github/workflows/coolify-realtime-next.yml
vendored
|
|
@ -48,8 +48,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
@ -90,8 +90,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
|
|||
8
.github/workflows/coolify-realtime.yml
vendored
8
.github/workflows/coolify-realtime.yml
vendored
|
|
@ -48,8 +48,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
@ -90,8 +90,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Get Version
|
||||
id: version
|
||||
|
|
|
|||
8
.github/workflows/coolify-staging-build.yml
vendored
8
.github/workflows/coolify-staging-build.yml
vendored
|
|
@ -64,8 +64,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and Push Image (${{ matrix.arch }})
|
||||
uses: docker/build-push-action@v6
|
||||
|
|
@ -110,8 +110,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
||||
run: |
|
||||
|
|
|
|||
8
.github/workflows/coolify-testing-host.yml
vendored
8
.github/workflows/coolify-testing-host.yml
vendored
|
|
@ -44,8 +44,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and Push Image (${{ matrix.arch }})
|
||||
uses: docker/build-push-action@v6
|
||||
|
|
@ -81,8 +81,8 @@ jobs:
|
|||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -670,13 +670,20 @@ private function deploy_docker_compose_buildpack()
|
|||
$build_command = "DOCKER_BUILDKIT=1 {$build_command}";
|
||||
}
|
||||
|
||||
// Append build arguments if not using build secrets (matching default behavior)
|
||||
// Inject build arguments after build subcommand if not using build secrets
|
||||
if (! $this->application->settings->use_build_secrets && $this->build_args instanceof \Illuminate\Support\Collection && $this->build_args->isNotEmpty()) {
|
||||
$build_args_string = $this->build_args->implode(' ');
|
||||
// Escape single quotes for bash -c context used by executeInDocker
|
||||
$build_args_string = str_replace("'", "'\\''", $build_args_string);
|
||||
$build_command .= " {$build_args_string}";
|
||||
$this->application_deployment_queue->addLogEntry('Adding build arguments to custom Docker Compose build command.');
|
||||
|
||||
// Inject build args right after 'build' subcommand (not at the end)
|
||||
$original_command = $build_command;
|
||||
$build_command = injectDockerComposeBuildArgs($build_command, $build_args_string);
|
||||
|
||||
// Only log if build args were actually injected (command was modified)
|
||||
if ($build_command !== $original_command) {
|
||||
$this->application_deployment_queue->addLogEntry('Adding build arguments to custom Docker Compose build command.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->execute_remote_command(
|
||||
|
|
|
|||
|
|
@ -1018,11 +1018,27 @@ public function getDockerComposeBuildCommandPreviewProperty(): string
|
|||
// Use relative path for clarity in preview (e.g., ./backend/docker-compose.yaml)
|
||||
// Actual deployment uses absolute path: /artifacts/{deployment_uuid}{base_directory}{docker_compose_location}
|
||||
// Build-time env path references ApplicationDeploymentJob::BUILD_TIME_ENV_PATH as source of truth
|
||||
return injectDockerComposeFlags(
|
||||
$command = injectDockerComposeFlags(
|
||||
$this->dockerComposeCustomBuildCommand,
|
||||
".{$normalizedBase}{$this->dockerComposeLocation}",
|
||||
\App\Jobs\ApplicationDeploymentJob::BUILD_TIME_ENV_PATH
|
||||
);
|
||||
|
||||
// Inject build args if not using build secrets
|
||||
if (! $this->application->settings->use_build_secrets) {
|
||||
$buildTimeEnvs = $this->application->environment_variables()
|
||||
->where('is_buildtime', true)
|
||||
->get();
|
||||
|
||||
if ($buildTimeEnvs->isNotEmpty()) {
|
||||
$buildArgs = generateDockerBuildArgs($buildTimeEnvs);
|
||||
$buildArgsString = $buildArgs->implode(' ');
|
||||
|
||||
$command = injectDockerComposeBuildArgs($command, $buildArgsString);
|
||||
}
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
public function getDockerComposeStartCommandPreviewProperty(): string
|
||||
|
|
|
|||
|
|
@ -82,6 +82,21 @@ public function instantSave()
|
|||
}
|
||||
}
|
||||
|
||||
public function instantSaveSettings()
|
||||
{
|
||||
try {
|
||||
$this->authorize('update', $this->application);
|
||||
// Save checkbox states without port validation
|
||||
$this->application->is_gzip_enabled = $this->isGzipEnabled;
|
||||
$this->application->is_stripprefix_enabled = $this->isStripprefixEnabled;
|
||||
$this->application->exclude_from_status = $this->excludeFromStatus;
|
||||
$this->application->save();
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
|
||||
public function instantSaveAdvanced()
|
||||
{
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -43,9 +43,19 @@ public function toMail($notifiable = null): MailMessage
|
|||
$mail = new MailMessage;
|
||||
$count = $this->servers->count();
|
||||
|
||||
// Transform servers to include URLs
|
||||
$serversWithUrls = $this->servers->map(function ($server) {
|
||||
return [
|
||||
'name' => $server->name,
|
||||
'uuid' => $server->uuid,
|
||||
'url' => base_url().'/server/'.$server->uuid.'/proxy',
|
||||
'outdatedInfo' => $server->outdatedInfo ?? [],
|
||||
];
|
||||
});
|
||||
|
||||
$mail->subject("Coolify: Traefik proxy outdated on {$count} server(s)");
|
||||
$mail->view('emails.traefik-version-outdated', [
|
||||
'servers' => $this->servers,
|
||||
'servers' => $serversWithUrls,
|
||||
'count' => $count,
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1376,3 +1376,62 @@ function injectDockerComposeFlags(string $command, string $composeFilePath, stri
|
|||
// Replace only first occurrence to avoid modifying comments/strings/chained commands
|
||||
return preg_replace('/docker\s+compose/', $dockerComposeReplacement, $command, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject build arguments right after build-related subcommands in docker/docker compose commands.
|
||||
* This ensures build args are only applied to build operations, not to push, pull, up, etc.
|
||||
*
|
||||
* Supports:
|
||||
* - docker compose build
|
||||
* - docker buildx build
|
||||
* - docker builder build
|
||||
* - docker build (legacy)
|
||||
*
|
||||
* Examples:
|
||||
* - Input: "docker compose -f file.yml build"
|
||||
* Output: "docker compose -f file.yml build --build-arg X --build-arg Y"
|
||||
*
|
||||
* - Input: "docker buildx build --platform linux/amd64"
|
||||
* Output: "docker buildx build --build-arg X --build-arg Y --platform linux/amd64"
|
||||
*
|
||||
* - Input: "docker builder build --tag myimage:latest"
|
||||
* Output: "docker builder build --build-arg X --build-arg Y --tag myimage:latest"
|
||||
*
|
||||
* - Input: "docker compose build && docker compose push"
|
||||
* Output: "docker compose build --build-arg X --build-arg Y && docker compose push"
|
||||
*
|
||||
* - Input: "docker compose push"
|
||||
* Output: "docker compose push" (unchanged - no build command found)
|
||||
*
|
||||
* @param string $command The docker command
|
||||
* @param string $buildArgsString The build arguments to inject (e.g., "--build-arg X --build-arg Y")
|
||||
* @return string The modified command with build args injected after build subcommand
|
||||
*/
|
||||
function injectDockerComposeBuildArgs(string $command, string $buildArgsString): string
|
||||
{
|
||||
// Early return if no build args to inject
|
||||
if (empty(trim($buildArgsString))) {
|
||||
return $command;
|
||||
}
|
||||
|
||||
// Match build-related commands:
|
||||
// - ' builder build' (docker builder build)
|
||||
// - ' buildx build' (docker buildx build)
|
||||
// - ' build' (docker compose build, docker build)
|
||||
// Followed by either:
|
||||
// - whitespace (allowing service names, flags, or any valid arguments)
|
||||
// - end of string ($)
|
||||
// This regex ensures we match build subcommands, not "build" in other contexts
|
||||
// IMPORTANT: Order matters - check longer patterns first (builder build, buildx build) before ' build'
|
||||
$pattern = '/( builder build| buildx build| build)(?=\s|$)/';
|
||||
|
||||
// Replace the first occurrence of build command with build command + build-args
|
||||
$modifiedCommand = preg_replace(
|
||||
$pattern,
|
||||
'$1 '.$buildArgsString,
|
||||
$command,
|
||||
1 // Only replace first occurrence
|
||||
);
|
||||
|
||||
return $modifiedCommand ?? $command;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
return [
|
||||
'coolify' => [
|
||||
'version' => '4.0.0-beta.452',
|
||||
'version' => '4.0.0-beta.453',
|
||||
'helper_version' => '1.0.12',
|
||||
'realtime_version' => '1.0.10',
|
||||
'self_hosted' => env('SELF_HOSTED', true),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.452"
|
||||
"version": "4.0.0-beta.453"
|
||||
},
|
||||
"nightly": {
|
||||
"version": "4.0.0-beta.453"
|
||||
"version": "4.0.0-beta.454"
|
||||
},
|
||||
"helper": {
|
||||
"version": "1.0.12"
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@
|
|||
|
||||
@foreach ($servers as $server)
|
||||
@php
|
||||
$info = $server->outdatedInfo ?? [];
|
||||
$current = $info['current'] ?? 'unknown';
|
||||
$latest = $info['latest'] ?? 'unknown';
|
||||
$isPatch = ($info['type'] ?? 'patch_update') === 'patch_update';
|
||||
$serverName = data_get($server, 'name', 'Unknown Server');
|
||||
$serverUrl = data_get($server, 'url', '#');
|
||||
$info = data_get($server, 'outdatedInfo', []);
|
||||
$current = data_get($info, 'current', 'unknown');
|
||||
$latest = data_get($info, 'latest', 'unknown');
|
||||
$isPatch = (data_get($info, 'type', 'patch_update') === 'patch_update');
|
||||
$hasNewerBranch = isset($info['newer_branch_target']);
|
||||
$hasUpgrades = $hasUpgrades ?? false;
|
||||
if (!$isPatch || $hasNewerBranch) {
|
||||
|
|
@ -19,8 +21,9 @@
|
|||
$latest = str_starts_with($latest, 'v') ? $latest : "v{$latest}";
|
||||
|
||||
// For minor upgrades, use the upgrade_target (e.g., "v3.6")
|
||||
if (!$isPatch && isset($info['upgrade_target'])) {
|
||||
$upgradeTarget = str_starts_with($info['upgrade_target'], 'v') ? $info['upgrade_target'] : "v{$info['upgrade_target']}";
|
||||
if (!$isPatch && data_get($info, 'upgrade_target')) {
|
||||
$upgradeTarget = data_get($info, 'upgrade_target');
|
||||
$upgradeTarget = str_starts_with($upgradeTarget, 'v') ? $upgradeTarget : "v{$upgradeTarget}";
|
||||
} else {
|
||||
// For patch updates, show the full version
|
||||
$upgradeTarget = $latest;
|
||||
|
|
@ -28,22 +31,23 @@
|
|||
|
||||
// Get newer branch info if available
|
||||
if ($hasNewerBranch) {
|
||||
$newerBranchTarget = $info['newer_branch_target'];
|
||||
$newerBranchLatest = str_starts_with($info['newer_branch_latest'], 'v') ? $info['newer_branch_latest'] : "v{$info['newer_branch_latest']}";
|
||||
$newerBranchTarget = data_get($info, 'newer_branch_target', 'unknown');
|
||||
$newerBranchLatest = data_get($info, 'newer_branch_latest', 'unknown');
|
||||
$newerBranchLatest = str_starts_with($newerBranchLatest, 'v') ? $newerBranchLatest : "v{$newerBranchLatest}";
|
||||
}
|
||||
@endphp
|
||||
@if ($isPatch && $hasNewerBranch)
|
||||
- **{{ $server->name }}**: {{ $current }} → {{ $upgradeTarget }} (patch update available) | Also available: {{ $newerBranchTarget }} (latest patch: {{ $newerBranchLatest }}) - new minor version
|
||||
- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} → {{ $upgradeTarget }} (patch update available) | Also available: {{ $newerBranchTarget }} (latest patch: {{ $newerBranchLatest }}) - new minor version
|
||||
@elseif ($isPatch)
|
||||
- **{{ $server->name }}**: {{ $current }} → {{ $upgradeTarget }} (patch update available)
|
||||
- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} → {{ $upgradeTarget }} (patch update available)
|
||||
@else
|
||||
- **{{ $server->name }}**: {{ $current }} (latest patch: {{ $latest }}) → {{ $upgradeTarget }} (new minor version available)
|
||||
- [**{{ $serverName }}**]({{ $serverUrl }}): {{ $current }} (latest patch: {{ $latest }}) → {{ $upgradeTarget }} (new minor version available)
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
## Recommendation
|
||||
|
||||
It is recommended to test the new Traefik version before switching it in production environments. You can update your proxy configuration through your [Coolify Dashboard]({{ config('app.url') }}).
|
||||
It is recommended to test the new Traefik version before switching it in production environments. You can update your proxy configuration by clicking on any server name above.
|
||||
|
||||
@if ($hasUpgrades ?? false)
|
||||
**Important for minor version upgrades:** Before upgrading to a new minor version, please read the [Traefik changelog](https://github.com/traefik/traefik/releases) to understand breaking changes and new features.
|
||||
|
|
@ -58,5 +62,5 @@
|
|||
|
||||
---
|
||||
|
||||
You can manage your server proxy settings in your Coolify Dashboard.
|
||||
Click on any server name above to manage its proxy settings.
|
||||
</x-emails.layout>
|
||||
|
|
|
|||
|
|
@ -56,18 +56,18 @@
|
|||
<h3 class="py-2 pt-4">Advanced</h3>
|
||||
<div class="w-96 flex flex-col gap-1">
|
||||
@if (str($application->image)->contains('pocketbase'))
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="isGzipEnabled"
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave="instantSaveSettings" id="isGzipEnabled"
|
||||
label="Enable Gzip Compression"
|
||||
helper="Pocketbase does not need gzip compression, otherwise SSE will not work." disabled />
|
||||
@else
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="isGzipEnabled"
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave="instantSaveSettings" id="isGzipEnabled"
|
||||
label="Enable Gzip Compression"
|
||||
helper="You can disable gzip compression if you want. Some services are compressing data by default. In this case, you do not need this." />
|
||||
@endif
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave id="isStripprefixEnabled"
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave="instantSaveSettings" id="isStripprefixEnabled"
|
||||
label="Strip Prefixes"
|
||||
helper="Strip Prefix is used to remove prefixes from paths. Like /api/ to /api." />
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave label="Exclude from service status"
|
||||
<x-forms.checkbox canGate="update" :canResource="$application" instantSave="instantSaveSettings" label="Exclude from service status"
|
||||
helper="If you do not need to monitor this resource, enable. Useful if this service is optional."
|
||||
id="excludeFromStatus"></x-forms.checkbox>
|
||||
<x-forms.checkbox canGate="update" :canResource="$application"
|
||||
|
|
|
|||
|
|
@ -18,28 +18,28 @@ class="flex flex-col h-full gap-8 sm:flex-row">
|
|||
<div class="flex flex-col gap-1">
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="is_registration_enabled"
|
||||
helper="If enabled, users can register themselves. If disabled, only administrators can create new users."
|
||||
helper="Allow users to self-register. If disabled, only administrators can create accounts."
|
||||
label="Registration Allowed" />
|
||||
</div>
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="do_not_track"
|
||||
helper="If enabled, Coolify will not track any data. This is useful if you are concerned about privacy."
|
||||
helper="Opt out of reporting this instance to coolify.io's installation count. No other data is collected."
|
||||
label="Do Not Track" />
|
||||
</div>
|
||||
<h4 class="pt-4">DNS Settings</h4>
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="is_dns_validation_enabled"
|
||||
helper="If you set a custom domain, Coolify will validate the domain in your DNS provider."
|
||||
helper="Verify that custom domains are correctly configured in DNS before deployment. Prevents deployment failures from DNS misconfigurations."
|
||||
label="DNS Validation" />
|
||||
</div>
|
||||
|
||||
<x-forms.input id="custom_dns_servers" label="Custom DNS Servers"
|
||||
helper="DNS servers to validate domains against. A comma separated list of DNS servers."
|
||||
helper="Custom DNS servers for domain validation. Comma-separated list (e.g., 1.1.1.1,8.8.8.8). Leave empty to use system defaults."
|
||||
placeholder="1.1.1.1,8.8.8.8" />
|
||||
<h4 class="pt-4">API Settings</h4>
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id="is_api_enabled" label="API Access"
|
||||
helper="If enabled, the API will be enabled. If disabled, the API will be disabled." />
|
||||
helper="If enabled, authenticated requests to Coolify's REST API will be allowed. Configure API tokens in Security > API Tokens." />
|
||||
</div>
|
||||
<x-forms.input id="allowed_ips" label="Allowed IPs for API Access"
|
||||
helper="Allowed IP addresses or subnets for API access.<br>Supports single IPs (192.168.1.100) and CIDR notation (192.168.1.0/24).<br>Use comma to separate multiple entries.<br>Use 0.0.0.0 or leave empty to allow from anywhere."
|
||||
|
|
@ -53,7 +53,7 @@ class="flex flex-col h-full gap-8 sm:flex-row">
|
|||
<h4 class="pt-4">Confirmation Settings</h4>
|
||||
<div class="md:w-96">
|
||||
<x-forms.checkbox instantSave id=" is_sponsorship_popup_enabled" label="Show Sponsorship Popup"
|
||||
helper="When enabled, sponsorship popups will be shown monthly to users. When disabled, the sponsorship popup will be permanently hidden for all users." />
|
||||
helper="Show monthly sponsorship reminders to support Coolify development. Disable to hide these messages permanently." />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
|
|
|
|||
|
|
@ -214,3 +214,90 @@
|
|||
expect($notification->servers)->toHaveCount(1);
|
||||
expect($notification->servers->first()->outdatedInfo['type'])->toBe('patch_update');
|
||||
});
|
||||
|
||||
it('notification generates correct server proxy URLs', function () {
|
||||
$team = Team::factory()->create();
|
||||
$server = Server::factory()->create([
|
||||
'name' => 'Test Server',
|
||||
'team_id' => $team->id,
|
||||
'uuid' => 'test-uuid-123',
|
||||
]);
|
||||
|
||||
$server->outdatedInfo = [
|
||||
'current' => '3.5.0',
|
||||
'latest' => '3.5.6',
|
||||
'type' => 'patch_update',
|
||||
];
|
||||
|
||||
$notification = new TraefikVersionOutdated(collect([$server]));
|
||||
$mail = $notification->toMail($team);
|
||||
|
||||
// Verify the mail has the transformed servers with URLs
|
||||
expect($mail->viewData['servers'])->toHaveCount(1);
|
||||
expect($mail->viewData['servers'][0]['name'])->toBe('Test Server');
|
||||
expect($mail->viewData['servers'][0]['uuid'])->toBe('test-uuid-123');
|
||||
expect($mail->viewData['servers'][0]['url'])->toBe(base_url().'/server/test-uuid-123/proxy');
|
||||
expect($mail->viewData['servers'][0]['outdatedInfo'])->toBeArray();
|
||||
});
|
||||
|
||||
it('notification transforms multiple servers with URLs correctly', function () {
|
||||
$team = Team::factory()->create();
|
||||
$server1 = Server::factory()->create([
|
||||
'name' => 'Server 1',
|
||||
'team_id' => $team->id,
|
||||
'uuid' => 'uuid-1',
|
||||
]);
|
||||
$server1->outdatedInfo = [
|
||||
'current' => '3.5.0',
|
||||
'latest' => '3.5.6',
|
||||
'type' => 'patch_update',
|
||||
];
|
||||
|
||||
$server2 = Server::factory()->create([
|
||||
'name' => 'Server 2',
|
||||
'team_id' => $team->id,
|
||||
'uuid' => 'uuid-2',
|
||||
]);
|
||||
$server2->outdatedInfo = [
|
||||
'current' => '3.4.0',
|
||||
'latest' => '3.6.0',
|
||||
'type' => 'minor_upgrade',
|
||||
'upgrade_target' => 'v3.6',
|
||||
];
|
||||
|
||||
$servers = collect([$server1, $server2]);
|
||||
$notification = new TraefikVersionOutdated($servers);
|
||||
$mail = $notification->toMail($team);
|
||||
|
||||
// Verify both servers have URLs
|
||||
expect($mail->viewData['servers'])->toHaveCount(2);
|
||||
|
||||
expect($mail->viewData['servers'][0]['name'])->toBe('Server 1');
|
||||
expect($mail->viewData['servers'][0]['url'])->toBe(base_url().'/server/uuid-1/proxy');
|
||||
|
||||
expect($mail->viewData['servers'][1]['name'])->toBe('Server 2');
|
||||
expect($mail->viewData['servers'][1]['url'])->toBe(base_url().'/server/uuid-2/proxy');
|
||||
});
|
||||
|
||||
it('notification uses base_url helper not config app.url', function () {
|
||||
$team = Team::factory()->create();
|
||||
$server = Server::factory()->create([
|
||||
'name' => 'Test Server',
|
||||
'team_id' => $team->id,
|
||||
'uuid' => 'test-uuid',
|
||||
]);
|
||||
|
||||
$server->outdatedInfo = [
|
||||
'current' => '3.5.0',
|
||||
'latest' => '3.5.6',
|
||||
'type' => 'patch_update',
|
||||
];
|
||||
|
||||
$notification = new TraefikVersionOutdated(collect([$server]));
|
||||
$mail = $notification->toMail($team);
|
||||
|
||||
// Verify URL starts with base_url() not config('app.url')
|
||||
$generatedUrl = $mail->viewData['servers'][0]['url'];
|
||||
expect($generatedUrl)->toStartWith(base_url());
|
||||
expect($generatedUrl)->not->toContain('localhost');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -615,3 +615,58 @@
|
|||
expect($path)->not->toContain('//', "Double slash found for baseDir: {$case['baseDir']}");
|
||||
}
|
||||
});
|
||||
|
||||
// Tests for injectDockerComposeBuildArgs() helper function
|
||||
it('injects build args when building specific service', function () {
|
||||
$command = 'docker compose build web';
|
||||
$buildArgs = '--build-arg ENV=prod';
|
||||
|
||||
$result = injectDockerComposeBuildArgs($command, $buildArgs);
|
||||
|
||||
expect($result)->toBe('docker compose build --build-arg ENV=prod web');
|
||||
});
|
||||
|
||||
it('injects build args with service name containing hyphens', function () {
|
||||
$command = 'docker compose build my-service-name';
|
||||
$buildArgs = '--build-arg TEST=value';
|
||||
|
||||
$result = injectDockerComposeBuildArgs($command, $buildArgs);
|
||||
|
||||
expect($result)->toBe('docker compose build --build-arg TEST=value my-service-name');
|
||||
});
|
||||
|
||||
it('injects build args with service name containing underscores', function () {
|
||||
$command = 'docker compose build my_service_name';
|
||||
$buildArgs = '--build-arg TEST=value';
|
||||
|
||||
$result = injectDockerComposeBuildArgs($command, $buildArgs);
|
||||
|
||||
expect($result)->toBe('docker compose build --build-arg TEST=value my_service_name');
|
||||
});
|
||||
|
||||
it('injects build args before service name and existing flags', function () {
|
||||
$command = 'docker compose build backend --no-cache';
|
||||
$buildArgs = '--build-arg FOO=bar';
|
||||
|
||||
$result = injectDockerComposeBuildArgs($command, $buildArgs);
|
||||
|
||||
expect($result)->toBe('docker compose build --build-arg FOO=bar backend --no-cache');
|
||||
});
|
||||
|
||||
it('handles buildx with target and flags', function () {
|
||||
$command = 'docker buildx build --platform linux/amd64 -t myimage:latest .';
|
||||
$buildArgs = '--build-arg VERSION=1.0';
|
||||
|
||||
$result = injectDockerComposeBuildArgs($command, $buildArgs);
|
||||
|
||||
expect($result)->toBe('docker buildx build --build-arg VERSION=1.0 --platform linux/amd64 -t myimage:latest .');
|
||||
});
|
||||
|
||||
it('handles docker compose build with no arguments', function () {
|
||||
$command = 'docker compose build';
|
||||
$buildArgs = '--build-arg FOO=bar';
|
||||
|
||||
$result = injectDockerComposeBuildArgs($command, $buildArgs);
|
||||
|
||||
expect($result)->toBe('docker compose build --build-arg FOO=bar');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.452"
|
||||
"version": "4.0.0-beta.453"
|
||||
},
|
||||
"nightly": {
|
||||
"version": "4.0.0-beta.453"
|
||||
"version": "4.0.0-beta.454"
|
||||
},
|
||||
"helper": {
|
||||
"version": "1.0.12"
|
||||
|
|
|
|||
Loading…
Reference in a new issue