diff --git a/README.md b/README.md index 34f52ef..480733a 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ Commands can use `server` or `servers` interchangeably. - `--base-directory ` - Base directory - `--publish-directory ` - Publish directory - `--dockerfile ` - Dockerfile content + - `--dockerfile-location ` - Path to the Dockerfile relative to the base directory, e.g. `/api/Dockerfile` - `--docker-image ` - Docker image name - `--docker-tag ` - Docker image tag - `--ports-exposes ` - Exposed ports @@ -208,7 +209,7 @@ Commands can use `server` or `servers` interchangeably. - `--ports-exposes ` - Exposed ports, e.g., '3000' or '3000,8080' (required) - `--domains ` - Domain(s) for the application - `--instant-deploy` - Deploy immediately after creation - - More flags: `--name`, `--description`, `--base-directory`, `--publish-directory`, `--build-command`, `--start-command`, `--install-command`, `--health-check-enabled`, `--health-check-path`, `--limits-memory`, `--limits-cpus`, `--ports-mappings`, `--git-commit-sha`, `--destination-uuid`, `--dockerfile-target-build` + - More flags: `--name`, `--description`, `--base-directory`, `--publish-directory`, `--build-command`, `--start-command`, `--install-command`, `--health-check-enabled`, `--health-check-path`, `--limits-memory`, `--limits-cpus`, `--ports-mappings`, `--git-commit-sha`, `--destination-uuid`, `--dockerfile-target-build`, `--dockerfile-location` - `coolify app create github` - Create an application from a private repository using a GitHub App - Same flags as `public`, plus `--github-app-uuid ` (required) - `--git-repository` takes the `owner/repo` format diff --git a/cmd/application/application_test.go b/cmd/application/application_test.go index 051d680..3ef14d8 100644 --- a/cmd/application/application_test.go +++ b/cmd/application/application_test.go @@ -38,7 +38,7 @@ func TestNewApplicationCommands_ExposeParityFlags(t *testing.T) { "is-git-shallow-clone-enabled", "is-git-submodules-enabled", "is-gzip-enabled", "is-pr-deployments-public-enabled", "is-preview-deployments-enabled", "is-raw-compose-deployment-enabled", "is-stripprefix-enabled", "stop-grace-period", - "use-build-secrets", + "use-build-secrets", "dockerfile-location", } { assert.NotNil(t, NewUpdateCommand().Flags().Lookup(flag), "missing --%s", flag) } diff --git a/cmd/application/create/create_test.go b/cmd/application/create/create_test.go index bfb7bb1..0cb5eee 100644 --- a/cmd/application/create/create_test.go +++ b/cmd/application/create/create_test.go @@ -38,3 +38,17 @@ func TestGitCreateCommands_ExposeComposeDomainFlag(t *testing.T) { assert.Nil(t, NewDockerfileCommand().Flags().Lookup("compose-domain")) assert.Nil(t, NewDockerImageCommand().Flags().Lookup("compose-domain")) } + +func TestGitCreateCommands_ExposeDockerfileLocationFlag(t *testing.T) { + commands := []*cobra.Command{ + NewPublicCommand(), NewGitHubCommand(), NewDeployKeyCommand(), + } + + for _, command := range commands { + assert.NotNil(t, command.Flags().Lookup("dockerfile-location"), "%s missing --dockerfile-location", command.Name()) + } + + // the inline Dockerfile and the pre-built image have no repository to point into + assert.Nil(t, NewDockerfileCommand().Flags().Lookup("dockerfile-location")) + assert.Nil(t, NewDockerImageCommand().Flags().Lookup("dockerfile-location")) +} diff --git a/cmd/application/create/deploy_key.go b/cmd/application/create/deploy_key.go index 0301904..ef913eb 100644 --- a/cmd/application/create/deploy_key.go +++ b/cmd/application/create/deploy_key.go @@ -102,6 +102,7 @@ Examples: setOptionalBoolFlag(cmd, "health-check-enabled", &req.HealthCheckEnabled) setOptionalStringFlag(cmd, "health-check-path", &req.HealthCheckPath) setOptionalStringFlag(cmd, "dockerfile-target-build", &req.DockerfileTargetBuild) + setOptionalStringFlag(cmd, "dockerfile-location", &req.DockerfileLocation) appflags.ApplySettingsFlags(cmd, &req.ApplicationSettingsRequest) appflags.ApplyTagsFlag(cmd, &req.Tags) @@ -160,6 +161,7 @@ Examples: cmd.Flags().Bool("health-check-enabled", false, "Enable health checks") cmd.Flags().String("health-check-path", "", "Health check path") cmd.Flags().String("dockerfile-target-build", "", "Dockerfile target build stage") + cmd.Flags().String("dockerfile-location", "", "Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile") appflags.BindSettingsFlags(cmd) appflags.BindTagsFlag(cmd) cmd.MarkFlagsMutuallyExclusive("domains", "compose-domain") diff --git a/cmd/application/create/github.go b/cmd/application/create/github.go index 569a0eb..d864a45 100644 --- a/cmd/application/create/github.go +++ b/cmd/application/create/github.go @@ -103,6 +103,7 @@ Examples: setOptionalBoolFlag(cmd, "health-check-enabled", &req.HealthCheckEnabled) setOptionalStringFlag(cmd, "health-check-path", &req.HealthCheckPath) setOptionalStringFlag(cmd, "dockerfile-target-build", &req.DockerfileTargetBuild) + setOptionalStringFlag(cmd, "dockerfile-location", &req.DockerfileLocation) appflags.ApplySettingsFlags(cmd, &req.ApplicationSettingsRequest) appflags.ApplyTagsFlag(cmd, &req.Tags) @@ -161,6 +162,7 @@ Examples: cmd.Flags().Bool("health-check-enabled", false, "Enable health checks") cmd.Flags().String("health-check-path", "", "Health check path") cmd.Flags().String("dockerfile-target-build", "", "Dockerfile target build stage") + cmd.Flags().String("dockerfile-location", "", "Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile") appflags.BindSettingsFlags(cmd) appflags.BindTagsFlag(cmd) cmd.MarkFlagsMutuallyExclusive("domains", "compose-domain") diff --git a/cmd/application/create/public.go b/cmd/application/create/public.go index cc6a7b4..54bf5d9 100644 --- a/cmd/application/create/public.go +++ b/cmd/application/create/public.go @@ -94,6 +94,7 @@ Examples: setOptionalBoolFlag(cmd, "health-check-enabled", &req.HealthCheckEnabled) setOptionalStringFlag(cmd, "health-check-path", &req.HealthCheckPath) setOptionalStringFlag(cmd, "dockerfile-target-build", &req.DockerfileTargetBuild) + setOptionalStringFlag(cmd, "dockerfile-location", &req.DockerfileLocation) appflags.ApplySettingsFlags(cmd, &req.ApplicationSettingsRequest) appflags.ApplyTagsFlag(cmd, &req.Tags) @@ -151,6 +152,7 @@ Examples: cmd.Flags().Bool("health-check-enabled", false, "Enable health checks") cmd.Flags().String("health-check-path", "", "Health check path") cmd.Flags().String("dockerfile-target-build", "", "Dockerfile target build stage") + cmd.Flags().String("dockerfile-location", "", "Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile") appflags.BindSettingsFlags(cmd) appflags.BindTagsFlag(cmd) cmd.MarkFlagsMutuallyExclusive("domains", "compose-domain") diff --git a/cmd/application/update.go b/cmd/application/update.go index 1d7c600..98fd148 100644 --- a/cmd/application/update.go +++ b/cmd/application/update.go @@ -121,6 +121,11 @@ Example: req.DockerfileTargetBuild = &targetBuild hasUpdates = true } + if cmd.Flags().Changed("dockerfile-location") { + location, _ := cmd.Flags().GetString("dockerfile-location") + req.DockerfileLocation = &location + hasUpdates = true + } if cmd.Flags().Changed("health-check-enabled") { enabled, _ := cmd.Flags().GetBool("health-check-enabled") req.HealthCheckEnabled = &enabled @@ -177,6 +182,7 @@ Example: cmd.Flags().String("docker-image", "", "Docker image name") cmd.Flags().String("docker-tag", "", "Docker image tag") cmd.Flags().String("dockerfile-target-build", "", "Dockerfile target build stage") + cmd.Flags().String("dockerfile-location", "", "Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile") cmd.Flags().String("ports-exposes", "", "Exposed ports") cmd.Flags().String("ports-mappings", "", "Port mappings") cmd.Flags().Bool("health-check-enabled", false, "Enable health check") diff --git a/internal/models/application.go b/internal/models/application.go index 5c81e01..0a68dc5 100644 --- a/internal/models/application.go +++ b/internal/models/application.go @@ -202,6 +202,7 @@ type ApplicationUpdateRequest struct { // Docker configuration Dockerfile *string `json:"dockerfile,omitempty"` DockerfileTargetBuild *string `json:"dockerfile_target_build,omitempty"` + DockerfileLocation *string `json:"dockerfile_location,omitempty"` DockerRegistryImageName *string `json:"docker_registry_image_name,omitempty"` DockerRegistryImageTag *string `json:"docker_registry_image_tag,omitempty"` CustomDockerRunOptions *string `json:"custom_docker_run_options,omitempty"` @@ -530,6 +531,7 @@ type ApplicationCreatePublicRequest struct { CustomDockerRunOptions *string `json:"custom_docker_run_options,omitempty"` CustomLabels *string `json:"custom_labels,omitempty"` DockerfileTargetBuild *string `json:"dockerfile_target_build,omitempty"` + DockerfileLocation *string `json:"dockerfile_location,omitempty"` // Health checks HealthCheckEnabled *bool `json:"health_check_enabled,omitempty"` @@ -578,6 +580,7 @@ type ApplicationCreateGitHubAppRequest struct { CustomDockerRunOptions *string `json:"custom_docker_run_options,omitempty"` CustomLabels *string `json:"custom_labels,omitempty"` DockerfileTargetBuild *string `json:"dockerfile_target_build,omitempty"` + DockerfileLocation *string `json:"dockerfile_location,omitempty"` HealthCheckEnabled *bool `json:"health_check_enabled,omitempty"` HealthCheckPath *string `json:"health_check_path,omitempty"` HealthCheckPort *string `json:"health_check_port,omitempty"` @@ -622,6 +625,7 @@ type ApplicationCreateDeployKeyRequest struct { CustomDockerRunOptions *string `json:"custom_docker_run_options,omitempty"` CustomLabels *string `json:"custom_labels,omitempty"` DockerfileTargetBuild *string `json:"dockerfile_target_build,omitempty"` + DockerfileLocation *string `json:"dockerfile_location,omitempty"` HealthCheckEnabled *bool `json:"health_check_enabled,omitempty"` HealthCheckPath *string `json:"health_check_path,omitempty"` HealthCheckPort *string `json:"health_check_port,omitempty"` diff --git a/internal/models/application_test.go b/internal/models/application_test.go index ade4611..913c70b 100644 --- a/internal/models/application_test.go +++ b/internal/models/application_test.go @@ -84,6 +84,50 @@ func TestApplicationCreateSettings_MarshalNewAPIFields(t *testing.T) { } } +func TestDockerfileLocation_MarshalRequestShape(t *testing.T) { + location := "/api/Dockerfile" + tests := []struct { + name string + req any + }{ + {name: "public create", req: ApplicationCreatePublicRequest{DockerfileLocation: &location}}, + {name: "github create", req: ApplicationCreateGitHubAppRequest{DockerfileLocation: &location}}, + {name: "deploy key create", req: ApplicationCreateDeployKeyRequest{DockerfileLocation: &location}}, + {name: "update", req: ApplicationUpdateRequest{DockerfileLocation: &location}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := json.Marshal(tt.req) + require.NoError(t, err) + + var body map[string]any + require.NoError(t, json.Unmarshal(data, &body)) + assert.Equal(t, location, body["dockerfile_location"]) + }) + } +} + +func TestDockerfileLocation_OmittedWhenUnset(t *testing.T) { + requests := map[string]any{ + "public create": ApplicationCreatePublicRequest{}, + "github create": ApplicationCreateGitHubAppRequest{}, + "deploy key create": ApplicationCreateDeployKeyRequest{}, + "update": ApplicationUpdateRequest{}, + } + + for name, req := range requests { + t.Run(name, func(t *testing.T) { + data, err := json.Marshal(req) + require.NoError(t, err) + + var body map[string]any + require.NoError(t, json.Unmarshal(data, &body)) + assert.NotContains(t, body, "dockerfile_location") + }) + } +} + func TestDockerComposeDomains_MarshalRequestShape(t *testing.T) { domains := []DockerComposeDomain{ {Name: "litellm", Domain: "https://litellm.example.com"}, diff --git a/llms-full.txt b/llms-full.txt index c7d02ba..da9184c 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -271,6 +271,10 @@ Parameters: description: Number of Docker images to retain required: false default: 0 + - name: --dockerfile-location + type: string + description: Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile + required: false - name: --dockerfile-target-build type: string description: Dockerfile target build stage @@ -918,6 +922,10 @@ Parameters: description: Number of Docker images to retain required: false default: 0 + - name: --dockerfile-location + type: string + description: Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile + required: false - name: --dockerfile-target-build type: string description: Dockerfile target build stage @@ -1159,6 +1167,10 @@ Parameters: description: Number of Docker images to retain required: false default: 0 + - name: --dockerfile-location + type: string + description: Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile + required: false - name: --dockerfile-target-build type: string description: Dockerfile target build stage @@ -2007,6 +2019,10 @@ Parameters: type: string description: Dockerfile content required: false + - name: --dockerfile-location + type: string + description: Path to the Dockerfile relative to the base directory, e.g. /api/Dockerfile + required: false - name: --dockerfile-target-build type: string description: Dockerfile target build stage