diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f5da22fe4..1997c73d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Fixed +- Use the same `COOLIFY_BRANCH` value in all parts of a preview deployment: `pull//head`. Before, a variable that refers to `${COOLIFY_BRANCH}` got the branch of the application (for example `main`), but the container got `pull//head`. Other build packs got `pull//head:pr--coolify`, and applications from a public repository got the branch of the application ([#9572](https://github.com/coollabsio/coolify/issues/9572)) - Send the **Resource status changes** notification when an application, preview, service, or database stops unexpectedly, for example after a crash or `docker kill`. Before, Coolify sent this notification only when it restarted the proxy or a database TCP proxy. Coolify waits 2 minutes and sends the notification only when the resource is still stopped, so a container that Docker restarts, or a deployment that replaces it, sends none. A stop, restart, or redeploy from Coolify sends no notification, and the same resource sends at most one notification in 15 minutes ([#9493](https://github.com/coollabsio/coolify/issues/9493)) - Fix the "Network error" when you sign in with email in AppFlowy Web. AppFlowy Web runs on its own domain and sends a `Redirect_to` header to GoTrue on the admin domain, and GoTrue blocked the CORS preflight because it did not allow that header. The AppFlowy service template now sets `GOTRUE_CORS_ALLOWED_HEADERS=redirect_to`. For an existing AppFlowy service, add this variable to the `gotrue` service in the Docker Compose file and restart the service ([#10545](https://github.com/coollabsio/coolify/issues/10545)) - List the commit images of Docker Compose applications on the **Rollback** page and in `GET /api/v1/applications/{uuid}/rollback-images`. Since v4.5.0 the list was always empty, because a Compose build names each service image `_`. The page also shows the running commit when the Compose file has services from other images, for example a database ([#12446](https://github.com/coollabsio/coolify/issues/12446)) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 25dca2348b..d0b45e4f18 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -3380,8 +3380,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } } } - if (isset($this->application->git_branch)) { - $this->coolify_variables .= 'COOLIFY_BRANCH='.escapeShellValue($this->application->git_branch).' '; + $branch = $this->application->coolifyBranch($this->pull_request_id); + if (isset($branch)) { + $this->coolify_variables .= 'COOLIFY_BRANCH='.escapeShellValue($branch).' '; } $this->coolify_variables .= 'COOLIFY_RESOURCE_UUID='.escapeShellValue($this->application->uuid).' '; } @@ -4298,7 +4299,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); protected function generate_coolify_env_variables(bool $forBuildTime = false): Collection { $coolify_envs = collect([]); - $local_branch = $this->branch; + $local_branch = $this->application->coolifyBranch($this->pull_request_id); if ($this->pull_request_id !== 0) { // Only add SOURCE_COMMIT for runtime OR when explicitly enabled for build-time // SOURCE_COMMIT changes with each commit and breaks Docker cache if included in build diff --git a/app/Models/Application.php b/app/Models/Application.php index 96d7389471..a21d8de6ea 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1962,6 +1962,18 @@ class Application extends BaseModel return $commands; } + /** + * The COOLIFY_BRANCH value of a deployment. Preview deployments use the pull request ref. + */ + public function coolifyBranch(int $pullRequestId = 0): ?string + { + if ($pullRequestId !== 0) { + return "pull/{$pullRequestId}/head"; + } + + return $this->git_branch; + } + public function generateGitImportCommands(string $deployment_uuid, int $pull_request_id = 0, ?string $git_type = null, bool $exec_in_docker = true, bool $only_checkout = false, ?string $custom_base_dir = null, ?string $commit = null) { $branch = $this->git_branch; diff --git a/bootstrap/helpers/parsers.php b/bootstrap/helpers/parsers.php index b723993b67..14b9638432 100644 --- a/bootstrap/helpers/parsers.php +++ b/bootstrap/helpers/parsers.php @@ -2002,10 +2002,7 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int } } } - $branch = $originalResource->git_branch; - if ($pullRequestId !== 0) { - $branch = "pull/{$pullRequestId}/head"; - } + $branch = $originalResource->coolifyBranch($pullRequestId); if ($originalResource->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) { $coolifyEnvironments->put('COOLIFY_BRANCH', "\"{$branch}\""); } diff --git a/tests/Unit/ApplicationDeploymentCoolifyBranchTest.php b/tests/Unit/ApplicationDeploymentCoolifyBranchTest.php new file mode 100644 index 0000000000..089afedb57 --- /dev/null +++ b/tests/Unit/ApplicationDeploymentCoolifyBranchTest.php @@ -0,0 +1,85 @@ +} + */ +function coolifyBranchVariables(string $buildPack, int $pullRequestId, string $checkedOutBranch): array +{ + $team = Team::create(['name' => 'Branch Team', 'personal_team' => false, 'show_boarding' => false]); + $project = Project::create(['name' => 'Branch Project', 'team_id' => $team->id]); + $environment = Environment::where('project_id', $project->id)->firstOrFail(); + $server = Server::factory()->create(['team_id' => $team->id]); + $application = Application::factory()->create([ + 'environment_id' => $environment->id, + 'destination_id' => $server->standaloneDockers()->firstOrFail()->id, + 'destination_type' => StandaloneDocker::class, + 'build_pack' => $buildPack, + 'git_branch' => 'main', + ]); + $preview = $pullRequestId === 0 ? null : ApplicationPreview::create([ + 'application_id' => $application->id, + 'pull_request_id' => $pullRequestId, + 'pull_request_html_url' => 'https://github.com/coollabsio/example/pull/'.$pullRequestId, + 'fqdn' => 'https://pr.example.com', + ]); + + $job = new TestableCoolifyBranchDeploymentJob; + $reflection = new ReflectionClass(ApplicationDeploymentJob::class); + + foreach ([ + 'application' => $application->fresh(), + 'pull_request_id' => $pullRequestId, + 'preview' => $preview, + 'commit' => 'HEAD', + 'branch' => $checkedOutBranch, + ] as $property => $value) { + $reflection->getProperty($property)->setValue($job, $value); + } + + $reflection->getMethod('set_coolify_variables')->invoke($job); + + return [ + 'shell' => $reflection->getProperty('coolify_variables')->getValue($job), + 'env' => $reflection->getMethod('generate_coolify_env_variables')->invoke($job, true)->all(), + ]; +} + +it('uses the pull request ref for COOLIFY_BRANCH in compose variables of a preview deployment', function () { + $variables = coolifyBranchVariables('dockercompose', 7, 'main'); + + expect($variables['shell'])->toContain("COOLIFY_BRANCH='pull/7/head'"); +}); + +it('uses the pull request ref for COOLIFY_BRANCH in env variables of a preview deployment', function () { + $variables = coolifyBranchVariables('dockerfile', 7, 'pull/7/head:pr-7-coolify'); + + expect($variables['env']['COOLIFY_BRANCH'])->toBe('pull/7/head') + ->and($variables['shell'])->toContain("COOLIFY_BRANCH='pull/7/head'"); +}); + +it('uses the application branch for COOLIFY_BRANCH of a production deployment', function () { + $variables = coolifyBranchVariables('dockerfile', 0, 'main'); + + expect($variables['env']['COOLIFY_BRANCH'])->toBe('main') + ->and($variables['shell'])->toContain("COOLIFY_BRANCH='main'"); +});