diff --git a/cabotage/celery/tasks/build.py b/cabotage/celery/tasks/build.py index af2e65e0..9728dcf1 100644 --- a/cabotage/celery/tasks/build.py +++ b/cabotage/celery/tasks/build.py @@ -539,25 +539,25 @@ def file_path(filename): return os.path.join(image.application.subdirectory, filename) return filename + dockerfile_candidates = ["Dockerfile.cabotage", "Dockerfile"] + if image.application.dockerfile_path: + dockerfile_candidates = [image.application.dockerfile_path] + dockerfile_name = None - dockerfile_body = _fetch_github_file( - image.application.github_repository, - image.commit_sha, - access_token=access_token, - filename=file_path("Dockerfile.cabotage"), - ) - dockerfile_name = "Dockerfile.cabotage" - if dockerfile_body is None: + dockerfile_body = None + for candidate in dockerfile_candidates: dockerfile_body = _fetch_github_file( image.application.github_repository, image.commit_sha, access_token=access_token, - filename=file_path("Dockerfile"), + filename=file_path(candidate), ) - dockerfile_name = "Dockerfile" + if dockerfile_body is not None: + dockerfile_name = candidate + break if dockerfile_body is None: raise BuildError( - "No Dockerfile.cabotage or Dockerfile found in root of " + f"No Dockerfile found in " f"{git_ref(image.application.github_repository, image.commit_sha)}" ) diff --git a/cabotage/client/templates/user/project_application_settings.html b/cabotage/client/templates/user/project_application_settings.html index b7bee8e4..a313659d 100644 --- a/cabotage/client/templates/user/project_application_settings.html +++ b/cabotage/client/templates/user/project_application_settings.html @@ -25,6 +25,7 @@

Deployment Automation

{{ form_field(form.github_repository) }} {{ form_field(form.auto_deploy_branch) }} {{ form_field(form.subdirectory) }} + {{ form_field(form.dockerfile_path) }} {{ form_field(form.github_repository_is_private) }} {{ form_field(form.github_app_installation_id) }} {{ form_field(form.github_environment_name ) }} diff --git a/cabotage/server/models/projects.py b/cabotage/server/models/projects.py index 1253f2ef..949e0ea1 100644 --- a/cabotage/server/models/projects.py +++ b/cabotage/server/models/projects.py @@ -192,6 +192,11 @@ class Application(db.Model, Timestamp): nullable=True, ) + dockerfile_path = db.Column( + db.Text(), + nullable=True, + ) + auto_deploy_branch = db.Column( db.Text(), nullable=True, diff --git a/cabotage/server/user/forms.py b/cabotage/server/user/forms.py index 3858a74b..f9630910 100755 --- a/cabotage/server/user/forms.py +++ b/cabotage/server/user/forms.py @@ -262,6 +262,14 @@ class EditApplicationSettingsForm(FlaskForm): "Subdirectory", description="Subdirectory to build out of", ) + dockerfile_path = StringField( + "Dockerfile Path", + description="Custom path to Dockerfile (e.g. docker/Dockerfile), falls back to Dockerfile.cabotage then Dockerfile", + filters=[ + (lambda x: x.strip() if (x and isinstance(x, str)) else x), + (lambda x: x if x else None), + ], + ) github_app_installation_id = StringField( "GitHub Application Installation ID", description="Application Installation ID from GitHub", diff --git a/migrations/versions/a1b2c3d4e5f6_add_dockerfile_path.py b/migrations/versions/a1b2c3d4e5f6_add_dockerfile_path.py new file mode 100644 index 00000000..da3b5187 --- /dev/null +++ b/migrations/versions/a1b2c3d4e5f6_add_dockerfile_path.py @@ -0,0 +1,30 @@ +"""Add configurable dockerfile_path to applications + +Revision ID: a1b2c3d4e5f6 +Revises: c2ae2e19e1f2 +Create Date: 2026-02-17 20:30:00.000000 + +""" + +from alembic import op +import sqlalchemy as sa + +revision = "a1b2c3d4e5f6" +down_revision = "c2ae2e19e1f2" +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column( + "project_applications", sa.Column("dockerfile_path", sa.Text(), nullable=True) + ) + op.add_column( + "project_applications_version", + sa.Column("dockerfile_path", sa.Text(), autoincrement=False, nullable=True), + ) + + +def downgrade(): + op.drop_column("project_applications_version", "dockerfile_path") + op.drop_column("project_applications", "dockerfile_path")