Skip to content

Commit

Permalink
cookiecutter tests (#21)
Browse files Browse the repository at this point in the history
* πŸ§ͺ πŸ”§  add test configuration to pytest and coverage

* πŸ”§ πŸͺ repos with - instead of _

* πŸ§ͺ βœ…  add pytest to πŸͺ and makefile

* βž• add pytest-cov pytest-cookies

* πŸ”§ βœ…  add codecov.yml file

* πŸ‘· add test github action

* πŸ“ add codecov badge to readme
  • Loading branch information
JoseRZapata committed Feb 11, 2024
1 parent c95d444 commit 33deb63
Show file tree
Hide file tree
Showing 11 changed files with 518 additions and 14 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Test

on:
pull_request:
push:
branches:
- "main"

jobs:
actionlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Download actionlint
run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.21
shell: bash
- name: Check workflow files
run: ./actionlint -color
shell: bash

pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/python-poetry-env
- run: poetry run pre-commit run --all-files

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/python-poetry-env
#{% raw %}
with:
python-version: ${{ matrix.python-version }}
#{% endraw %}
- name: Run pytest with coverage
run: poetry run pytest --cov=./ --cov-report=xml

#{% raw %}
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
slug: JoseRZapata/data-science-project-template
#{% endraw %}
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ docs_view: ## Build and serve the documentation
docs-test: ## Test if documentation can be built without warnings or errors
@poetry run mkdocs build -s

####----Tests----####
test: ## Test the code with pytest and coverage
@echo "πŸš€ Testing code: Running pytest"
@poetry run pytest --cov

####----Checks----####
actionlint: ## Check GitHub Actions
@echo "πŸš€ Checking GitHub Actions..."
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
[![pages-build-deployment](https://github.com/JoseRZapata/data-science-project-template/actions/workflows/pages/pages-build-deployment/badge.svg?branch=gh-pages)](https://github.com/JoseRZapata/data-science-project-template/actions/workflows/pages/pages-build-deployment)

[![codecov](https://codecov.io/gh/JoseRZapata/data-science-project-template/graph/badge.svg?token=7LCPX574UF)](https://codecov.io/gh/JoseRZapata/data-science-project-template)
---

A modern template for data science projects with all the necessary tools for experiment, development, testing, and deployment. From notebooks to production.
Expand All @@ -18,6 +18,7 @@ Source Code: <https://github.com/JoseRZapata/data-science-project-template>
Table of Contents

- [Data science project template](#data-science-project-template)
- [](#)
- [πŸ“ Creating a New Project](#-creating-a-new-project)
- [πŸ‘ Recommendations](#-recommendations)
- [πŸͺπŸ₯‡ Via Cruft - **recommended**](#-via-cruft---recommended)
Expand Down
28 changes: 28 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
codecov:
notify:
require_ci_to_pass: no
after_n_builds: 1 # how many uploads per commit
wait_for_ci: no


coverage:
status:
patch: # minimum coverage needed based only on the new code introduced on the PR
default: off
pr_coverage:
target: 90%
project:
default: off
minimum: # minimum target of coverage needed to pass the check
target: 90%
decrement: # maximum decrement of coverage allowed
target: auto
threshold: 0.5%
if_not_found: success
comment: # configuration of the details the bot will comment on the PR
layout: "diff, flags"
behavior: default
require_changes: false # if true: only post the comment if coverage changes
require_base: no # [yes :: must have a base report to post]
require_head: no # [yes :: must have a head report to post]
branches: null
2 changes: 1 addition & 1 deletion cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project_name": "Project Name",
"repo_name": "{{ cookiecutter.project_name.strip().replace(' ', '_').replace('-', '_').lower() }}",
"repo_name": "{{ cookiecutter.project_name.strip().replace(' ', '-').replace('_', '-').lower() }}",
"github_username": "",
"author_name": "Peter Parker",
"author_email": "[email protected]",
Expand Down
343 changes: 331 additions & 12 deletions poetry.lock

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,18 @@ mkdocs-material = "^9.5.7"
mkdocstrings = {extras = ["python"], version = "^0.24.0"}
pymdown-extensions = "^10.7"


[tool.poetry.group.test.dependencies]
pytest = "^8.0.0"
pytest-cov = "^4.1.0"
pytest-cookies = "^0.7.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.virtualenvs]
in-project = true

[tool.pytest.ini_options]
testpaths = ["tests"]
61 changes: 61 additions & 0 deletions tests/test_create_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
import re
import subprocess # nosec


def build_files_list(root_dir): # type: ignore
"""Build a list containing absolute paths to the generated files."""
return [
os.path.join(dirpath, file_path)
for dirpath, _, files in os.walk(root_dir)
for file_path in files
]


def test_run_cookiecutter_result(cookies): # type: ignore
"""Runs cookiecutter and checks a couple of things"""
project_name = "data science project template"
repo_name = "data-science-project-template"
result = cookies.bake(
extra_context={"project_name": project_name, "repo_name": repo_name}
)

assert result.exit_code == 0
assert result.exception is None
assert result.project_path.name == repo_name
assert result.project_path.is_dir()

readme_path = result.project_path / "README.md"
assert readme_path.is_file()

with open(readme_path) as f:
readme = f.read()
assert project_name in readme
assert "project_name" not in readme


def test_cookiecutter_generated_files(cookies): # type: ignore
"""tests the generated files names make sense"""
re_bad = re.compile(r"{{\s?cookiecutter\..*?}}")
result = cookies.bake()

assert all(
re_bad.search(str(file_path)) is None
for file_path in result.project_path.glob("*")
)


def test_cookiecutter_make_help(cookies): # type: ignore
"""ensure the make help command runs without error"""
result = cookies.bake()

make_proc = subprocess.Popen(
["/usr/bin/make"],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=result.project_path,
) # nosec
# stdout, stderr are for debuggin
stdout, stderr = make_proc.communicate()
assert make_proc.returncode == 0
14 changes: 14 additions & 0 deletions tests/test_create_template_no_coverage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def test_cookiecutter_conf_files(cookies) -> None: # type: ignore
"""ensures the codecov files not present"""
codecov = False
result = cookies.bake(extra_context={"codecov": codecov})

env_path = result.project_path / ".github/workflows/test.yml"
assert env_path.is_file()

with open(env_path) as f:
file_content = f.read()
assert "CODECOV_TOKEN" not in file_content

env_path = result.project_path / "codecov.yml"
assert not env_path.is_file()
13 changes: 13 additions & 0 deletions tests/test_create_template_no_mkdocs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def test_cookiecutter_mkdocs_files(cookies) -> None: # type: ignore
"""ensures the mkdocs files not present"""
mkdocs = False
result = cookies.bake(extra_context={"mkdocs": mkdocs})

env_path = result.project_path / "mkdocs.yml"
assert not env_path.is_file()

env_path = result.project_path / ".github/workflows/docs.yml"
assert not env_path.is_file()

env_path = result.project_path / "docs/index.md"
assert not env_path.is_file()
4 changes: 4 additions & 0 deletions {{cookiecutter.repo_name}}/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ build-backend = "poetry.core.masonry.api"
in-project = true

[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]

[tool.coverage.paths]
source = ["src"]

0 comments on commit 33deb63

Please sign in to comment.