Skip to content

Commit

Permalink
Refactor testing
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Aug 13, 2024
1 parent 6fe3c66 commit d0a6ea1
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 25 deletions.
1 change: 1 addition & 0 deletions .config/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ minmax
mkdocs
pyenv
ssbarnea
pypa
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ repos:
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
additional_dependencies:
- pytest
- repo: https://github.com/psf/black
rev: 24.8.0
hooks:
Expand All @@ -53,6 +55,7 @@ repos:
args: [--strict]
additional_dependencies:
- actions-toolkit
- pytest
- repo: https://github.com/pycqa/pylint
rev: v3.2.6
hooks:
Expand All @@ -61,3 +64,4 @@ repos:
- --output-format=colorized
additional_dependencies:
- actions-toolkit
- pytest
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"python.formatting.provider": "black"
"python.formatting.provider": "black",
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
}
1 change: 1 addition & 0 deletions cspell.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ dictionaries:
- words
- python
ignorePaths:
- .vscode/settings.json
- cspell.config.yaml
68 changes: 46 additions & 22 deletions entrypoint.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#!env python3
"""Action body."""

import json
import os
import re
from pathlib import Path
from typing import Any

from actions_toolkit import core

Expand All @@ -22,14 +25,18 @@
IMPLICIT_SKIP_EXPLODE = "0"


def sort_human(l: list[str]) -> list[str]:
def sort_human(data: list[str]) -> list[str]:
"""Sort a list using human logic, so 'py39' comes before 'py311'."""

def convert(text: str) -> str | float:
return float(text) if text.isdigit() else text
def alphanum(key):
return [convert(c) for c in re.split("([-+]?[0-9]*\\.?[0-9]*)", key)]
l.sort(key=alphanum)
return l

def alphanumeric(key: str) -> list[str | float]:
return [convert(c) for c in re.split(r"([-+]?\d*\\.?\d*)", key)]

data.sort(key=alphanumeric)
return data


def add_job(result: dict[str, dict[str, str]], name: str, data: dict[str, str]) -> None:
"""Adds a new job to the list of generated jobs."""
Expand All @@ -40,6 +47,34 @@ def add_job(result: dict[str, dict[str, str]], name: str, data: dict[str, str])
result[name] = data


def get_platforms() -> list[str]:
"""Retrieve effective list of platforms."""
platforms = []
for v in core.get_input("platforms", required=False).split(","):
platform, run_on = v.split(":") if ":" in v else (v, None)
if not platform:
continue
if run_on:
core.debug(
f"Add platform '{platform}' with run_on={run_on} to known platforms",
)
PLATFORM_MAP[platform] = run_on
platforms.append(platform)
return platforms


def produce_output(output: dict[str, Any]) -> None:
"""Produce the output."""
if "TEST_GITHUB_OUTPUT_JSON" in os.environ:
with Path(os.environ["TEST_GITHUB_OUTPUT_JSON"]).open(
"w",
encoding="utf-8",
) as f:
json.dump(output, f)
for key, value in output.items():
core.set_output(key, value)


# loop list staring with given item
# pylint: disable=too-many-locals,too-many-branches
def main() -> None: # noqa: C901,PLR0912
Expand All @@ -50,12 +85,14 @@ def main() -> None: # noqa: C901,PLR0912
core.info(f"Env var {k}={v}")
try:
other_names = core.get_input("other_names", required=False).split("\n")
platforms = core.get_input("platforms", required=False).split(",")
platforms = get_platforms()

min_python = core.get_input("min_python") or IMPLICIT_MIN_PYTHON
max_python = core.get_input("max_python") or IMPLICIT_MAX_PYTHON
default_python = core.get_input("default_python") or IMPLICIT_DEFAULT_PYTHON
skip_explode = int(core.get_input("skip_explode") or IMPLICIT_SKIP_EXPLODE)
strategies = {}

for platform in PLATFORM_MAP:
strategies[platform] = core.get_input(platform, required=False)

Expand Down Expand Up @@ -102,7 +139,7 @@ def main() -> None: # noqa: C901,PLR0912
if not skip_explode:
for platform in platforms:
for i, python in enumerate(python_names):
py_name = re.sub(r"[^0-9]", "", python.strip("."))
py_name = re.sub(r"\D", "", python.strip("."))
suffix = "" if platform == IMPLICIT_PLATFORM else f"-{platform}"
if strategies[platform] == "minmax" and (
i not in (0, python_flavours - 1)
Expand All @@ -129,26 +166,13 @@ def main() -> None: # noqa: C901,PLR0912
core.info(
f"Matrix jobs ordered by their name: {json.dumps(matrix_include, indent=2)}",
)

core.set_output("matrix", {"include": matrix_include})
output = {"matrix": {"include": matrix_include}}
produce_output(output)

# pylint: disable=broad-exception-caught
except Exception as exc: # noqa: BLE001
core.set_failed(f"Action failed due to {exc}")


if __name__ == "__main__":
# only used for local testing, emulating use from github actions
if os.getenv("GITHUB_ACTIONS") is None:
os.environ["INPUT_DEFAULT_PYTHON"] = "3.10"
os.environ["INPUT_LINUX"] = "full"
os.environ["INPUT_MACOS"] = "minmax"
os.environ["INPUT_MAX_PYTHON"] = "3.13"
os.environ["INPUT_MIN_PYTHON"] = "3.8"
os.environ["INPUT_OTHER_NAMES"] = (
"lint\npkg\npy313-devel\nall-macos:tox -e unit;tox -e integration"
)
os.environ["INPUT_PLATFORMS"] = "linux,macos" # macos and windows
os.environ["INPUT_SKIP_EXPLODE"] = "0"
os.environ["INPUT_WINDOWS"] = "minmax"
main()
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,15 @@ lint.ignore = [
"INP001", # "is part of an implicit namespace package", all false positives
"PLW2901", # PLW2901: Redefined loop variable
"RET504", # Unnecessary variable assignment before `return` statement
"S603", # https://github.com/astral-sh/ruff/issues/4045

# temporary disabled until we fix them:
]
lint.select = ["ALL"]

[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["SLF001", "S101", "FBT001"]

[tool.ruff.lint.pydocstyle]
convention = "google"

Expand Down
64 changes: 62 additions & 2 deletions tests/test_action.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,69 @@
"""Tests for github action."""

import json
import os
import sys
import tempfile
from subprocess import run

import pytest

def test_foo() -> None:

@pytest.mark.parametrize(
("passed_env", "expected"),
[
pytest.param(
{
"INPUT_DEFAULT_PYTHON": "3.8",
"INPUT_LINUX": "full",
"INPUT_MACOS": "minmax",
"INPUT_MAX_PYTHON": "3.8",
"INPUT_MIN_PYTHON": "3.8",
"INPUT_OTHER_NAMES": "all-macos:tox -e unit;tox -e integration",
"INPUT_PLATFORMS": "linux",
"INPUT_SKIP_EXPLODE": "1",
"INPUT_WINDOWS": "minmax",
},
{
"matrix": {
"include": [
{
"command": "tox -e unit",
"command2": "tox -e integration",
"name": "all-macos",
"os": "macos-13",
"python_version": "3.8",
},
],
},
},
id="1",
),
],
)
def test_action(passed_env: dict[str, str], expected: dict[str, str]) -> None:
"""Sample test."""
run([sys.executable, "entrypoint.py"], check=True, shell=False) # noqa: S603
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
env = {
**os.environ.copy(),
**passed_env,
"TEST_GITHUB_OUTPUT_JSON": temp_file.name,
}

result = run(
[sys.executable, "entrypoint.py"],
text=True,
shell=False,
check=True,
capture_output=True,
env=env,
)
assert result.returncode == 0
temp_file.seek(0)
effective = temp_file.read().decode("utf-8")
data = json.loads(effective)
assert isinstance(data, dict), data
assert len(data) == 1
assert "matrix" in data
assert data == expected
# TestCase().assertDictEqual(data, expected)

0 comments on commit d0a6ea1

Please sign in to comment.