From 5247185933e4138e71c941599af3f3937d4bf5c0 Mon Sep 17 00:00:00 2001 From: Ossama Lafhel Date: Sat, 13 Sep 2025 04:28:27 +0200 Subject: [PATCH 1/4] feat(add-watch-paths-for-services): show watch paths field for docker compose applications - Fix UI template to display Watch Paths for all GitHub-based applications - Remove condition that limited Watch Paths to private repositories only - Add comprehensive unit tests for isWatchPathsTriggered() method - Test various pattern matching scenarios (wildcards, globs, etc.) - Watch Paths now works for Docker Compose apps with both public and private repos --- .../project/application/general.blade.php | 10 +- tests/Unit/ApplicationWatchPathsTest.php | 165 ++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/ApplicationWatchPathsTest.php diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index 315385593..3ffe074fa 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -265,6 +265,14 @@ class="underline" href="https://coolify.io/docs/knowledge-base/docker/registry" helper="If you use this, you need to specify paths relatively and should use the same compose file in the custom command, otherwise the automatically configured labels / etc won't work.

So in your case, use: docker compose -f .{{ Str::start($application->base_directory . $application->docker_compose_location, '/') }} up -d" label="Custom Start Command" /> + @if ($this->application->is_github_based()) +
+ +
+ @endif @else
@@ -296,7 +304,7 @@ class="underline" href="https://coolify.io/docs/knowledge-base/docker/registry" @endif
- @if ($this->application->is_github_based() && !$this->application->is_public_repository()) + @if ($this->application->is_github_based())
watch_paths = null; + + $modified_files = collect(['docker-compose.yml', 'README.md']); + + $this->assertFalse($application->isWatchPathsTriggered($modified_files)); + } + + public function test_is_watch_paths_triggered_with_exact_match() + { + $application = new Application(); + $application->watch_paths = "docker-compose.yml\nDockerfile"; + + // Exact match should return true + $this->assertTrue($application->isWatchPathsTriggered(collect(['docker-compose.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['Dockerfile']))); + + // Non-matching file should return false + $this->assertFalse($application->isWatchPathsTriggered(collect(['README.md']))); + } + + public function test_is_watch_paths_triggered_with_wildcard_patterns() + { + $application = new Application(); + $application->watch_paths = "*.yml\nsrc/**/*.php\nconfig/*"; + + // Wildcard matches + $this->assertTrue($application->isWatchPathsTriggered(collect(['docker-compose.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['production.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['src/Controllers/UserController.php']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['src/Models/User.php']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['config/app.php']))); + + // Non-matching files + $this->assertFalse($application->isWatchPathsTriggered(collect(['README.md']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['src/index.js']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['configurations/deep/file.php']))); + } + + public function test_is_watch_paths_triggered_with_multiple_files() + { + $application = new Application(); + $application->watch_paths = "docker-compose.yml\n*.env"; + + // At least one file matches + $modified_files = collect(['README.md', 'docker-compose.yml', 'package.json']); + $this->assertTrue($application->isWatchPathsTriggered($modified_files)); + + // No files match + $modified_files = collect(['README.md', 'package.json', 'src/index.js']); + $this->assertFalse($application->isWatchPathsTriggered($modified_files)); + } + + public function test_is_watch_paths_triggered_with_complex_patterns() + { + $application = new Application(); + // fnmatch doesn't support {a,b} syntax, so we need to use separate patterns + $application->watch_paths = "**/*.js\n**/*.jsx\n**/*.ts\n**/*.tsx"; + + // JavaScript/TypeScript files should match + $this->assertTrue($application->isWatchPathsTriggered(collect(['src/index.js']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['components/Button.jsx']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['types/user.ts']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['pages/Home.tsx']))); + + // Deeply nested files should match + $this->assertTrue($application->isWatchPathsTriggered(collect(['src/components/ui/Button.tsx']))); + + // Non-matching files + $this->assertFalse($application->isWatchPathsTriggered(collect(['README.md']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['package.json']))); + } + + public function test_is_watch_paths_triggered_with_question_mark_pattern() + { + $application = new Application(); + $application->watch_paths = "test?.txt\nfile-?.yml"; + + // Single character wildcard matches + $this->assertTrue($application->isWatchPathsTriggered(collect(['test1.txt']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['testA.txt']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['file-1.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['file-B.yml']))); + + // Non-matching files + $this->assertFalse($application->isWatchPathsTriggered(collect(['test.txt']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['test12.txt']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['file.yml']))); + } + + public function test_is_watch_paths_triggered_with_character_set_pattern() + { + $application = new Application(); + $application->watch_paths = "[abc]test.txt\nfile[0-9].yml"; + + // Character set matches + $this->assertTrue($application->isWatchPathsTriggered(collect(['atest.txt']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['btest.txt']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['ctest.txt']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['file1.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['file9.yml']))); + + // Non-matching files + $this->assertFalse($application->isWatchPathsTriggered(collect(['dtest.txt']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['test.txt']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['fileA.yml']))); + } + + public function test_is_watch_paths_triggered_with_empty_watch_paths() + { + $application = new Application(); + $application->watch_paths = ''; + + $this->assertFalse($application->isWatchPathsTriggered(collect(['any-file.txt']))); + } + + public function test_is_watch_paths_triggered_with_whitespace_only_patterns() + { + $application = new Application(); + $application->watch_paths = "\n \n\t\n"; + + $this->assertFalse($application->isWatchPathsTriggered(collect(['any-file.txt']))); + } + + public function test_is_watch_paths_triggered_for_dockercompose_typical_patterns() + { + $application = new Application(); + $application->watch_paths = "docker-compose*.yml\n.env*\nDockerfile*\nservices/**"; + + // Docker Compose related files + $this->assertTrue($application->isWatchPathsTriggered(collect(['docker-compose.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['docker-compose.prod.yml']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['docker-compose-dev.yml']))); + + // Environment files + $this->assertTrue($application->isWatchPathsTriggered(collect(['.env']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['.env.local']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['.env.production']))); + + // Dockerfile variations + $this->assertTrue($application->isWatchPathsTriggered(collect(['Dockerfile']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['Dockerfile.prod']))); + + // Service files + $this->assertTrue($application->isWatchPathsTriggered(collect(['services/api/app.js']))); + $this->assertTrue($application->isWatchPathsTriggered(collect(['services/web/index.html']))); + + // Non-matching files (e.g., documentation, configs outside services) + $this->assertFalse($application->isWatchPathsTriggered(collect(['README.md']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['package.json']))); + $this->assertFalse($application->isWatchPathsTriggered(collect(['config/nginx.conf']))); + } +} \ No newline at end of file From 7160b889000f81fa8791ace0af58485996169f03 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 24 Sep 2025 15:58:16 +0000 Subject: [PATCH 2/4] docs: update changelog --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 177012001..b08d963ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ # Changelog ## [unreleased] +### 🐛 Bug Fixes + +- *(PreviewCompose)* Adds port to preview urls + +### 📚 Documentation + +- Update changelog + +## [4.0.0-beta.429] - 2025-09-23 + ### 🚀 Features - *(environment)* Replace is_buildtime_only with is_runtime and is_buildtime flags for environment variables, updating related logic and views @@ -23,6 +33,8 @@ ### 🚀 Features - *(cloud-check)* Enhance CloudCheckSubscription command with fix options - *(stripe)* Enhance subscription handling and verification process - *(private-key-refresh)* Add refresh dispatch on private key update and connection check +- *(comments)* Add automated comments for labeled pull requests to guide documentation updates +- *(comments)* Ping PR author ### 🐛 Bug Fixes @@ -42,6 +54,8 @@ ### 🐛 Bug Fixes - *(environment-variables)* Correct method call syntax in analyzeBuildVariable function - *(clears-global-search-cache)* Refine team retrieval logic in getTeamIdForCache method - *(subscription-job)* Enhance retry logic for VerifyStripeSubscriptionStatusJob +- *(environment-variable)* Update checkbox visibility and helper text for build and runtime options +- *(deployment-job)* Escape single quotes in build arguments for Docker Compose command ### 🚜 Refactor @@ -75,6 +89,8 @@ ### 🎨 Styling ### ⚙️ Miscellaneous Tasks - Change order of runtime and buildtime +- *(docker-compose)* Update soketi image version to 1.0.10 in production and Windows configurations +- *(versions)* Update coolify version numbers to 4.0.0-beta.430 and 4.0.0-beta.431 in configuration files ## [4.0.0-beta.428] - 2025-09-15 From 78be85dbbcef1fd2d4513fe8f3ba4d1426732fae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 24 Sep 2025 16:20:52 +0000 Subject: [PATCH 3/4] docs: update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b08d963ff..e5a6049eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,11 @@ ## [unreleased] ### 🐛 Bug Fixes - *(PreviewCompose)* Adds port to preview urls +- *(deployment-job)* Enhance build time variable analysis ### 📚 Documentation +- Update changelog - Update changelog ## [4.0.0-beta.429] - 2025-09-23 From d086f9fc50e1ed2e236e0956f23ee0a9d3a0ee79 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 24 Sep 2025 18:55:40 +0000 Subject: [PATCH 4/4] docs: update changelog --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5a6049eb..04b99c646 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,21 @@ ## [unreleased] ### 🐛 Bug Fixes +- *(docker)* Adjust openssh-client installation in Dockerfile to avoid version bug +- *(docker)* Streamline openssh-client installation in Dockerfile + +### 📚 Documentation + +- Update changelog + +### ⚙️ Miscellaneous Tasks + +- *(versions)* Increment coolify version numbers to 4.0.0-beta.431 and 4.0.0-beta.432 in configuration files + +## [4.0.0-beta.430] - 2025-09-24 + +### 🐛 Bug Fixes + - *(PreviewCompose)* Adds port to preview urls - *(deployment-job)* Enhance build time variable analysis