@@ -423,16 +423,11 @@ RUN sh /uv-installer.sh && rm /uv-installer.sh
423423
424424ENV PATH="/root/.local/bin:$PATH"
425425
426- COPY pyproject.toml uv.lock ./
426+ COPY . ./
427427
428428RUN --mount=type=cache,target=/root/.cache/uv \
429429 uv venv -p {python_version} \
430- && uv sync --locked --no-dev --no-install-project --no-editable
431-
432- COPY . /app
433-
434- RUN --mount=type=cache,target=/root/.cache/uv \
435- uv sync --locked --no-dev --no-editable
430+ && uv sync --locked --no-dev --no-editable
436431
437432
438433# Build production stage
@@ -462,6 +457,83 @@ USER appuser
462457
463458ENTRYPOINT ["./entrypoint.sh"]
464459"# ,
460+ ) ,
461+ ProjectManager :: Poetry => format ! (
462+ r#"# syntax=docker/dockerfile:1
463+
464+ FROM ubuntu:24.04 AS builder
465+
466+ WORKDIR /app
467+
468+ ENV \
469+ PYTHONUNBUFFERED=true \
470+ POETRY_NO_INTERACTION=true \
471+ POETRY_VIRTUALENVS_IN_PROJECT=true \
472+ POETRY_CACHE_DIR=/tmp/poetry_cache
473+
474+ RUN : \
475+ && apt-get update \
476+ && apt-get install -y --no-install-recommends \
477+ curl \
478+ ca-certificates \
479+ software-properties-common \
480+ && add-apt-repository ppa:deadsnakes/ppa \
481+ && apt-get update \
482+ && apt-get install -y --no-install-recommends \
483+ python{python_version} \
484+ && apt-get clean \
485+ && rm -rf /var/lib/apt/lists/*
486+
487+ # Install Poetry
488+ RUN curl -sSL https://install.python-poetry.org | python{python_version} -
489+
490+ ENV PATH="/root/.local/bin:$PATH"
491+
492+ COPY pyproject.toml poetry.lock ./
493+
494+ COPY . /app
495+
496+ RUN --mount=type=cache,target=$POETRY_CACHE_DIR \
497+ poetry config virtualenvs.in-project true \
498+ && poetry install --only=main
499+
500+
501+ # Build production stage
502+ FROM ubuntu:24.04 AS prod
503+
504+ RUN useradd appuser
505+
506+ WORKDIR /app
507+
508+ RUN chown appuser:appuser /app
509+
510+ ENV \
511+ PYTHONUNBUFFERED=true \
512+ PATH="/app/.venv/bin:$PATH" \
513+ PORT="8000"
514+
515+ RUN : \
516+ && apt-get update \
517+ && apt-get install -y --no-install-recommends\
518+ software-properties-common \
519+ && add-apt-repository ppa:deadsnakes/ppa \
520+ && apt-get update \
521+ && apt-get install -y --no-install-recommends python{python_version} \
522+ && apt-get clean \
523+ && rm -rf /var/lib/apt/lists/*
524+
525+ COPY --from=builder /app/.venv /app/.venv
526+ COPY --from=builder /app/my_project /app/my_project
527+ COPY ./scripts/entrypoint.sh /app
528+
529+ RUN chmod +x /app/entrypoint.sh
530+
531+ EXPOSE 8000
532+
533+ USER appuser
534+
535+ ENTRYPOINT ["./entrypoint.sh"]
536+ "#
465537 ) ,
466538 _ => todo ! ( "Implement this" ) ,
467539 }
@@ -540,3 +612,84 @@ pub fn save_entrypoint_script(project_info: &ProjectInfo) -> Result<()> {
540612
541613 Ok ( ( ) )
542614}
615+
616+ #[ cfg( test) ]
617+ mod tests {
618+ use super :: * ;
619+ use crate :: project_info:: { DatabaseManager , LicenseType , ProjectInfo , Pyo3PythonManager } ;
620+ use insta:: assert_yaml_snapshot;
621+ use std:: fs:: create_dir_all;
622+ use tmp_path:: tmp_path;
623+
624+ #[ tmp_path]
625+ fn project_info_dummy ( ) -> ProjectInfo {
626+ ProjectInfo {
627+ project_name : "My project" . to_string ( ) ,
628+ project_slug : "my-project" . to_string ( ) ,
629+ source_dir : "my_project" . to_string ( ) ,
630+ project_description : "This is a test" . to_string ( ) ,
631+ creator : "Arthur Dent" . to_string ( ) ,
632+ creator_email : "[email protected] " . to_string ( ) , 633+ license : LicenseType :: Mit ,
634+ copyright_year : Some ( "2023" . to_string ( ) ) ,
635+ version : "0.1.0" . to_string ( ) ,
636+ python_version : "3.11" . to_string ( ) ,
637+ min_python_version : "3.9" . to_string ( ) ,
638+ project_manager : ProjectManager :: Poetry ,
639+ pyo3_python_manager : Some ( Pyo3PythonManager :: Uv ) ,
640+ is_application : true ,
641+ is_async_project : false ,
642+ github_actions_python_test_versions : vec ! [
643+ "3.9" . to_string( ) ,
644+ "3.10" . to_string( ) ,
645+ "3.11" . to_string( ) ,
646+ "3.12" . to_string( ) ,
647+ ] ,
648+ max_line_length : 100 ,
649+ use_dependabot : true ,
650+ dependabot_schedule : None ,
651+ dependabot_day : None ,
652+ use_continuous_deployment : true ,
653+ use_release_drafter : true ,
654+ use_multi_os_ci : true ,
655+ include_docs : false ,
656+ docs_info : None ,
657+ download_latest_packages : false ,
658+ project_root_dir : Some ( tmp_path) ,
659+ is_fastapi_project : true ,
660+ database_manager : Some ( DatabaseManager :: AsyncPg ) ,
661+ }
662+ }
663+
664+ #[ test]
665+ fn test_save_dockerfile_uv ( ) {
666+ let mut project_info = project_info_dummy ( ) ;
667+ project_info. project_manager = ProjectManager :: Uv ;
668+ let base = project_info. base_dir ( ) ;
669+ create_dir_all ( & base) . unwrap ( ) ;
670+ let expected_file = base. join ( "Dockerfile" ) ;
671+ save_dockerfile ( & project_info) . unwrap ( ) ;
672+
673+ assert ! ( expected_file. is_file( ) ) ;
674+
675+ let content = std:: fs:: read_to_string ( expected_file) . unwrap ( ) ;
676+
677+ assert_yaml_snapshot ! ( content) ;
678+ }
679+
680+ #[ test]
681+ fn test_save_dockerfile_poetry ( ) {
682+ let mut project_info = project_info_dummy ( ) ;
683+ project_info. project_manager = ProjectManager :: Poetry ;
684+ let base = project_info. base_dir ( ) ;
685+ create_dir_all ( & base) . unwrap ( ) ;
686+ let expected_file = base. join ( "Dockerfile" ) ;
687+ save_dockerfile ( & project_info) . unwrap ( ) ;
688+
689+ assert ! ( expected_file. is_file( ) ) ;
690+
691+ let content = std:: fs:: read_to_string ( expected_file) . unwrap ( ) ;
692+
693+ assert_yaml_snapshot ! ( content) ;
694+ }
695+ }
0 commit comments