Skip to content

Commit

Permalink
fix: Catch permission errors when creating a new project (meltano#6652)
Browse files Browse the repository at this point in the history
* fix: error handling on project init

* Except other errors and not OSError

* Fix lint errors, catch unhandled expections

* Add tests for ProjectInitService

* Use pushd fixture

* Fix tests for windows

* Fix test on windows

* Add cause to ProjectInitServiceErrors, quotes

Co-authored-by: Will Da Silva <will@willdasilva.xyz>
Co-authored-by: Edgar R. M <edgarrm358@gmail.com>
  • Loading branch information
3 people committed Aug 30, 2022
1 parent 9bed498 commit dbd94d8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 3 deletions.
15 changes: 12 additions & 3 deletions src/meltano/core/project_init_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,19 @@ def init(self, activate: bool = True, add_discovery: bool = False) -> Project:
"""
try:
os.mkdir(self.project_name)
except Exception as exp: # noqa: F841
except FileExistsError as ex:
raise ProjectInitServiceError(
f"Directory {self.project_name} already exists."
)
f"Directory {self.project_name!r} already exists."
) from ex
except PermissionError as ex:
raise ProjectInitServiceError(
f"Permission denied to create {self.project_name!r}."
) from ex
except Exception as ex:
raise ProjectInitServiceError(
f"Could not create directory {self.project_name!r}. {ex}"
) from ex

click.secho("Created", fg="blue", nl=False)
click.echo(f" {self.project_name}")

Expand Down
64 changes: 64 additions & 0 deletions tests/meltano/core/test_project_init_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from __future__ import annotations

import platform
import stat
from typing import TYPE_CHECKING

import pytest

from meltano.core.project_init_service import (
ProjectInitService,
ProjectInitServiceError,
)

if TYPE_CHECKING:
from pathlib import Path


def test_project_init_directory_exists(tmp_path: Path, pushd):
project_name = "test_project"

projects_dir = tmp_path.joinpath("exists")
projects_dir.joinpath(project_name).mkdir(parents=True)
pushd(projects_dir)
with pytest.raises(
ProjectInitServiceError,
match=f"Directory {project_name!r} already exists",
):
ProjectInitService(project_name).init(activate=False, add_discovery=False)


def test_project_init_no_write_permission(tmp_path: Path, pushd):
if platform.system() == "Windows":
pytest.xfail(
"Windows can still create new directories inside a read-only directory."
)
project_name = "test_project"

protected_dir = tmp_path.joinpath("protected")
protected_dir.mkdir()
protected_dir.chmod(stat.S_IREAD | stat.S_IEXEC) # read and execute, but not write
pushd(protected_dir)
with pytest.raises(
ProjectInitServiceError,
match=f"Permission denied to create {project_name!r}",
):
ProjectInitService(project_name).init(activate=False, add_discovery=False)


def test_project_init_missing_parent_directory(tmp_path: Path, pushd):
if platform.system() == "Windows":
pytest.xfail(
"Windows can't remove a directory that is in use. See https://docs.python.org/3/library/os.html#os.remove"
)
project_name = "test_project"

missing_dir = tmp_path.joinpath("missing")
missing_dir.mkdir()
pushd(missing_dir)
missing_dir.rmdir() # remove the parent directory
with pytest.raises(
ProjectInitServiceError,
match=f"Could not create directory {project_name!r}.",
):
ProjectInitService(project_name).init(activate=False, add_discovery=False)

0 comments on commit dbd94d8

Please sign in to comment.