Skip to content

Commit

Permalink
fix: failure to instantiate template if project repo url was missing
Browse files Browse the repository at this point in the history
  • Loading branch information
a.pirogov committed Feb 13, 2024
1 parent 3e975c5 commit 0d8d97c
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 19 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Here we provide notes that summarize the most important changes in each released

Please consult the changelog to inform yourself about breaking changes and security issues.

## [v0.2.1](https://github.com/Materials-Data-Science-and-Informatics/fair-python-cookiecutter/tree/v0.2.1) <small>(2024-02-13)</small> { id="0.2.1" }

* fixed a bug where instantiation of template fails if no repository URL is provided
* improve usability and description of some CLI fields

## [v0.2.0](https://github.com/Materials-Data-Science-and-Informatics/fair-python-cookiecutter/tree/v0.2.0) <small>(2024-01-05)</small> { id="0.2.0" }

* Refactored into custom tool `fair-python-cookiecutter` for more versatility and convenience
Expand Down
3 changes: 3 additions & 0 deletions src/fair_python_cookiecutter/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ def prompt_config(ccconf: CookiecutterConfig):
ccconf.fair_python_cookiecutter.infer_from_repo_url(repo_url)
# go through and confirm all the other fields, with loaded + inferred values
ccconf.fair_python_cookiecutter.prompt_fields(exclude=["project_repo_url"])
# infer URL from provided information if it was not given at some point
if not ccconf.fair_python_cookiecutter.project_repo_url:
ccconf.fair_python_cookiecutter.infer_repo_url()


@app.command()
Expand Down
17 changes: 12 additions & 5 deletions src/fair_python_cookiecutter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def to_spdx_license(s: str):
OrcidUrl = Annotated[str, Field(pattern=r"^https://orcid.org/(\d{4}-){3}\d{3}(\d|X)$")]
SemVerStr = Annotated[str, Field(pattern=r"^\d+\.\d+\.\d+$")]
SPDXLicense = Annotated[str, AfterValidator(to_spdx_license)]
DomainName = Annotated[
MyHttpUrl = Annotated[
HttpUrl,
BeforeValidator(
lambda s: f"https://{s}" if s and not str(s).startswith("https://") else s
Expand Down Expand Up @@ -261,13 +261,13 @@ def is_default(self) -> bool:
exclude=True,
)

project_hoster: DomainName = Field(
project_hoster: MyHttpUrl = Field(
None,
description="Domain of the hosting service used for the repository (e.g. [b]github.com[/b], [b]gitlab.com[/b] or other GitLab instance).",
)
project_org: str = Field(
None,
description="GitHub Organization, GitLab Group or Git[Hub|Lab] Username (where the remote repository is located).",
description="GitHub Organization, GitLab Group or Git[Hub|Lab] Username (where the remote repository is/will be located).",
)
project_slug: str = Field(
None,
Expand All @@ -278,9 +278,9 @@ def is_default(self) -> bool:
None,
description="Domain where the GitHub/GitLab Pages are served (e.g. github.com -> [b]github.io[/b], gitlab.com -> [b]gitlab.io[/b], helmholtz.cloud -> [b]pages.hzdr.de[/b])",
)
project_pages_url: HttpUrl = Field(
project_pages_url: MyHttpUrl = Field(
None,
description="URL where the Git[Hub|Lab] Pages will be served.",
description="URL where the project Git[Hub|Lab] Pages will be served (if you don't know yet, enter some fake URL and change it later).",
exclude=True,
)

Expand Down Expand Up @@ -350,6 +350,13 @@ def infer_from_repo_url(self, url: Union[str, HttpUrl]):
rest_path = "" if not subgroups else f"/{subgroups}"
self.project_pages_url = f"https://{main_group}.{self.project_pages_domain}{rest_path}/{self.project_slug}"

def infer_repo_url(self):
"""Infer and set repo URL from other fields."""
url = (
f"https://{self.project_hoster.host}/{self.project_org}/{self.project_slug}"
)
self.project_repo_url = url


class CookiecutterConfig(BaseModel):
"""Wrapper class to load cookiecutter configuration file.
Expand Down
27 changes: 15 additions & 12 deletions src/fair_python_cookiecutter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,22 @@ def remove_unneeded_code(proj_root: Path, conf: CookiecutterConfig):
file.unlink()


def download_licenses(proj_root: Path, conf: CookiecutterConfig):
def download_licenses(
proj_root: Path, conf: CookiecutterConfig, *, force_download: bool = False
):
"""Download all needed licenses and create main LICENSE file."""
# only install reuse/pipx if it is not found
reuse_cmd = "reuse --suppress-deprecation download --all"
if not which("reuse"):
reuse_cmd = "pipx run " + reuse_cmd
if not which("pipx"):
run_cmd("poetry run pip install pipx", cwd=proj_root)
reuse_cmd = "poetry run " + reuse_cmd
# download licenses
print(reuse_cmd, "root:", proj_root)
run_cmd(reuse_cmd, cwd=proj_root)
# download licenses if no licenses dir is in the project dir
if force_download or not (proj_root / "LICENSES").is_dir():
# only install reuse/pipx if it is not found
reuse_cmd = "reuse --suppress-deprecation download --all"
if not which("reuse"):
reuse_cmd = "pipx run " + reuse_cmd
if not which("pipx"):
run_cmd("poetry run pip install pipx", cwd=proj_root)
reuse_cmd = "poetry run " + reuse_cmd
# download licenses
run_cmd(reuse_cmd, cwd=proj_root)

# copy main license over from resulting licenses directory
license_name = conf.fair_python_cookiecutter.project_license
license = Path(proj_root) / "LICENSE"
Expand All @@ -78,7 +82,6 @@ def download_licenses(proj_root: Path, conf: CookiecutterConfig):

def finalize_repository(proj_root: Path, conf: CookiecutterConfig):
"""Finalize instantiated repository based on configuration."""
# remove unneeded and create needed files
create_gl_issue_template_from_gh(proj_root)
remove_unneeded_code(proj_root, conf)
download_licenses(proj_root, conf)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env bash
: # Magic to deactivate current Python venv (if one is enabled) in a cross-platform way
: # See https://stackoverflow.com/questions/17510688/single-script-to-run-in-both-windows-batch-and-linux-bash
:<<"::CMDLITERAL"
Expand All @@ -9,7 +10,7 @@ GOTO :COMMON
# ---- bash-specific code ----
venv=$(python -c "import sys; print(sys.prefix if sys.base_prefix != sys.prefix else '')")
if [[ -n "$venv" ]]; then
echo WARNING: deactivating currently active virtual environment "$venv"
echo Deactivating currently active virtual environment "$venv" ...
source "$venv/bin/activate" # make sure we have 'deactivate' available
deactivate
fi
Expand All @@ -26,6 +27,10 @@ git init
poetry install --with docs
poetry run poe init-dev

echo "Downloading required license texts ..."
poetry run pip install pipx
poetry run pipx run reuse download --all

echo "Creating CITATION.cff and codemeta.json using somesy ..."

git add .
Expand All @@ -42,7 +47,7 @@ echo "Ensuring that the default branch is called 'main' ..."

git branch -M main

echo "All done! Your project repository is ready :)"
echo "--------> All done! Your project repository is ready :) <--------"


: # TODO: only do following in test mode
Expand Down
7 changes: 7 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,10 @@ def test_configured(tmp_path):
# and the expected license (Unlicense)
first_license_line = open(dir / "LICENSE", "r").readline()
assert first_license_line.find("public domain") > 0


# TODO: sanity-check after generation that all main tasks work locally:
# poetry install --with docs
# poetry run poe lint --all-files
# poetry run poe test
# poetry run poe docs

0 comments on commit 0d8d97c

Please sign in to comment.