From 574d34436542853ec07719221237f17b4f7de715 Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Thu, 30 Oct 2025 12:17:13 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20Clean=20up=20archive=20?= =?UTF-8?q?after=20uploading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fastapi_cloud_cli/commands/deploy.py | 21 ++--- tests/test_archive.py | 103 +++++++++++++---------- 2 files changed, 68 insertions(+), 56 deletions(-) diff --git a/src/fastapi_cloud_cli/commands/deploy.py b/src/fastapi_cloud_cli/commands/deploy.py index da26c03..9046a57 100644 --- a/src/fastapi_cloud_cli/commands/deploy.py +++ b/src/fastapi_cloud_cli/commands/deploy.py @@ -5,7 +5,6 @@ import tarfile import tempfile import time -import uuid from enum import Enum from itertools import cycle from pathlib import Path @@ -46,7 +45,7 @@ def _should_exclude_entry(path: Path) -> bool: return False -def archive(path: Path) -> Path: +def archive(path: Path, tar_path: Path) -> Path: logger.debug("Starting archive creation for path: %s", path) files = rignore.walk( path, @@ -54,11 +53,6 @@ def archive(path: Path) -> Path: additional_ignore_paths=[".fastapicloudignore"], ) - temp_dir = tempfile.mkdtemp() - logger.debug("Created temp directory: %s", temp_dir) - - name = f"fastapi-cloud-deploy-{uuid.uuid4()}" - tar_path = Path(temp_dir) / f"{name}.tar" logger.debug("Archive will be created at: %s", tar_path) file_count = 0 @@ -586,11 +580,14 @@ def deploy( ) raise typer.Exit(1) - logger.debug("Creating archive for deployment") - archive_path = archive(path or Path.cwd()) # noqa: F841 + with tempfile.TemporaryDirectory() as temp_dir: + logger.debug("Creating archive for deployment") + archive_path = Path(temp_dir) / "archive.tar" + archive(path or Path.cwd(), archive_path) - with toolkit.progress(title="Creating deployment") as progress: - with handle_http_errors(progress): + with toolkit.progress( + title="Creating deployment" + ) as progress, handle_http_errors(progress): logger.debug("Creating deployment for app: %s", app.id) deployment = _create_deployment(app.id) @@ -602,7 +599,7 @@ def deploy( _upload_deployment(deployment.id, archive_path) - progress.log("Deployment uploaded successfully!") + progress.log("Deployment uploaded successfully!") toolkit.print_line() diff --git a/tests/test_archive.py b/tests/test_archive.py index 8276a00..6bbcd63 100644 --- a/tests/test_archive.py +++ b/tests/test_archive.py @@ -1,76 +1,89 @@ import tarfile from pathlib import Path +import pytest + from fastapi_cloud_cli.commands.deploy import archive -def test_archive_creates_tar_file(tmp_path: Path) -> None: - (tmp_path / "main.py").write_text("print('hello')") - (tmp_path / "config.json").write_text('{"key": "value"}') - (tmp_path / "subdir").mkdir() - (tmp_path / "subdir" / "utils.py").write_text("def helper(): pass") +@pytest.fixture +def src_path(tmp_path: Path) -> Path: + path = tmp_path / "source" + path.mkdir() + return path + + +@pytest.fixture +def tar_path(tmp_path: Path) -> Path: + return tmp_path / "archive.tar" + - tar_path = archive(tmp_path) +def test_archive_creates_tar_file(src_path: Path, tar_path: Path) -> None: + (src_path / "main.py").write_text("print('hello')") + (src_path / "config.json").write_text('{"key": "value"}') + (src_path / "subdir").mkdir() + (src_path / "subdir" / "utils.py").write_text("def helper(): pass") + archive(src_path, tar_path) assert tar_path.exists() - assert tar_path.suffix == ".tar" - assert tar_path.name.startswith("fastapi-cloud-deploy-") -def test_archive_excludes_venv_and_similar_folders(tmp_path: Path) -> None: +def test_archive_excludes_venv_and_similar_folders( + src_path: Path, tar_path: Path +) -> None: """Should exclude .venv directory from archive.""" # the only files we want to include - (tmp_path / "main.py").write_text("print('hello')") - (tmp_path / "static").mkdir() - (tmp_path / "static" / "index.html").write_text("") + (src_path / "main.py").write_text("print('hello')") + (src_path / "static").mkdir() + (src_path / "static" / "index.html").write_text("") # virtualenv - (tmp_path / ".venv").mkdir() - (tmp_path / ".venv" / "lib").mkdir() - (tmp_path / ".venv" / "lib" / "package.py").write_text("# package") + (src_path / ".venv").mkdir() + (src_path / ".venv" / "lib").mkdir() + (src_path / ".venv" / "lib" / "package.py").write_text("# package") # pycache - (tmp_path / "__pycache__").mkdir() - (tmp_path / "__pycache__" / "main.cpython-311.pyc").write_text("bytecode") + (src_path / "__pycache__").mkdir() + (src_path / "__pycache__" / "main.cpython-311.pyc").write_text("bytecode") # pyc files - (tmp_path / "main.pyc").write_text("bytecode") + (src_path / "main.pyc").write_text("bytecode") # mypy/pytest - (tmp_path / ".mypy_cache").mkdir() - (tmp_path / ".mypy_cache" / "file.json").write_text("{}") - (tmp_path / ".pytest_cache").mkdir() - (tmp_path / ".pytest_cache" / "cache.db").write_text("data") + (src_path / ".mypy_cache").mkdir() + (src_path / ".mypy_cache" / "file.json").write_text("{}") + (src_path / ".pytest_cache").mkdir() + (src_path / ".pytest_cache" / "cache.db").write_text("data") - tar_path = archive(tmp_path) + archive(src_path, tar_path) with tarfile.open(tar_path, "r") as tar: names = tar.getnames() assert set(names) == {"main.py", "static/index.html"} -def test_archive_preserves_relative_paths(tmp_path: Path) -> None: - (tmp_path / "src").mkdir() - (tmp_path / "src" / "app").mkdir() - (tmp_path / "src" / "app" / "main.py").write_text("print('hello')") +def test_archive_preserves_relative_paths(src_path: Path, tar_path: Path) -> None: + (src_path / "src").mkdir() + (src_path / "src" / "app").mkdir() + (src_path / "src" / "app" / "main.py").write_text("print('hello')") - tar_path = archive(tmp_path) + archive(src_path, tar_path) with tarfile.open(tar_path, "r") as tar: names = tar.getnames() assert names == ["src/app/main.py"] -def test_archive_respects_fastapicloudignore(tmp_path: Path) -> None: +def test_archive_respects_fastapicloudignore(src_path: Path, tar_path: Path) -> None: """Should exclude files specified in .fastapicloudignore.""" # Create test files - (tmp_path / "main.py").write_text("print('hello')") - (tmp_path / "config.py").write_text("CONFIG = 'value'") - (tmp_path / "secrets.env").write_text("SECRET_KEY=xyz") - (tmp_path / "data").mkdir() - (tmp_path / "data" / "file.txt").write_text("data") + (src_path / "main.py").write_text("print('hello')") + (src_path / "config.py").write_text("CONFIG = 'value'") + (src_path / "secrets.env").write_text("SECRET_KEY=xyz") + (src_path / "data").mkdir() + (src_path / "data" / "file.txt").write_text("data") # Create .fastapicloudignore file - (tmp_path / ".fastapicloudignore").write_text("secrets.env\ndata/\n") + (src_path / ".fastapicloudignore").write_text("secrets.env\ndata/\n") # Create archive - tar_path = archive(tmp_path) + archive(src_path, tar_path) # Verify ignored files are excluded with tarfile.open(tar_path, "r") as tar: @@ -81,21 +94,23 @@ def test_archive_respects_fastapicloudignore(tmp_path: Path) -> None: } -def test_archive_respects_fastapicloudignore_unignore(tmp_path: Path) -> None: +def test_archive_respects_fastapicloudignore_unignore( + src_path: Path, tar_path: Path +) -> None: """Test we can use .fastapicloudignore to unignore files inside .gitignore""" # Create test files - (tmp_path / "main.py").write_text("print('hello')") - (tmp_path / "static/build").mkdir(exist_ok=True, parents=True) - (tmp_path / "static/build/style.css").write_text("body { background: #bada55 }") + (src_path / "main.py").write_text("print('hello')") + (src_path / "static/build").mkdir(exist_ok=True, parents=True) + (src_path / "static/build/style.css").write_text("body { background: #bada55 }") # Rignore needs a .git folder to make .gitignore work - (tmp_path / ".git").mkdir(exist_ok=True, parents=True) - (tmp_path / ".gitignore").write_text("build/") + (src_path / ".git").mkdir(exist_ok=True, parents=True) + (src_path / ".gitignore").write_text("build/") # Create .fastapicloudignore file - (tmp_path / ".fastapicloudignore").write_text("!static/build") + (src_path / ".fastapicloudignore").write_text("!static/build") # Create archive - tar_path = archive(tmp_path) + archive(src_path, tar_path) # Verify ignored files are excluded with tarfile.open(tar_path, "r") as tar: