Skip to content

Commit

Permalink
Replace returned passed_name with effective command (#35)
Browse files Browse the repository at this point in the history
This is a breaking change that requires consumers to update their
workflows. Instead of returning the tox environment name to be
executed, the entire command is returned.

This also allows users to add custom commands into other_names if they
include a colon as a separator.
  • Loading branch information
ssbarnea authored Aug 12, 2024
1 parent ba3affd commit ba9da1c
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 42 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
default_python: "3.10"
other_names: lint
build:
name: ${{ matrix.name || matrix.passed_name || '?' }}
name: ${{ matrix.name || '?' }}
runs-on: ${{ matrix.os || 'ubuntu-24.04' }}
needs: pre
strategy:
Expand All @@ -51,7 +51,7 @@ jobs:
cache: pip
python-version: ${{ matrix.python_version }}
- run: pip3 install -U tox
- run: tox -e "${{ matrix.passed_name }}"
- run: "${{ matrix.command }}"
codeql:
name: codeql
runs-on: ubuntu-24.04
Expand Down
56 changes: 29 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# matrix

GitHub Action that returns a dynamic test matrix. Currently it supports
GitHub Action that returns a dynamic test matrix. Currently, it supports
projects using:

- `python` and `tox`
Expand All @@ -17,9 +17,22 @@ projects using:
- `macos`: matrix expansion strategy for MacOS, `full` or `minmax`.
- `skip_explode`: pass 1 if you want to avoid generating implicit pyXY jobs.

## Upgrading action from v2 to v3

The returned tox environment name from returned `passed_name` was replaced by
`command` which would now contain the full command to be executed like
`tox -e py39`.

```yaml
# old v2 syntax:
- run: tox -e ${{ matrix.passed_env }}
# new v3 syntax:
- run: ${{ matrix.command }}
```
## Examples
<details><summary>Simple workflow using coactions/dynamic-matrix</summary><p>
Simple workflow using coactions/dynamic-matrix
```yaml
# .github/workflows/tox.yml (your workflow file)
Expand All @@ -38,6 +51,7 @@ jobs:
other_names: |
lint
pkg
py39-all:tox -f py39
build:
name: ${{ matrix.name }}
Expand All @@ -61,51 +75,39 @@ jobs:
python -m pip install -U pip
pip install tox
- run: tox run -e ${{ matrix.passed_name }}
- run: ${{ matrix.command }}
```
</p></details>
## Q&A
<details><summary>Which projects using tox would benefit from this GitHub Action?</summary><p>
### Which projects using tox would benefit from this GitHub Action?
If your tox [envlist](https://tox.wiki/en/latest/config.html#envlist) is simple, like `lint,packaging,py{36,37,38,39}` you are among the best candidates to make use of it as that is the primary usage case it covers. If you use environments combining multiple factors, you will need to specify them in `other_names` argument.

</p></details>

<details><summary>Why this action does not just load <tt>envlist</tt> values?</summary><p>
### Why this action does not just load <tt>envlist</tt> values?

We plan to add support for this in the future but it might not be
as simple as one would assume. For historical reasons `envlist` do very often already include python versions instead of generic `py` entry or
they are outdated. The repository code is not available at the
time this action runs.

</p></details>

<details><summary>Why only Linux testing is enabled by default?</summary><p>
### Why only Linux testing is enabled by default?

Linux runners are the fastest ones and many Python projects do not need to support platforms like Windows or macOS. That is why the default platform contains only lines. Still, you can enable all of them by specifying `platforms: linux,windows,macos` in the action arguments.

</p></details>

<details><summary>Why Windows and MacOS matrix expansion strategy is different than Linux one?</summary><p>
### Why Windows and MacOS matrix expansion strategy is different than the Linux one?

The defaults for macOS and Windows are `minmax` while for Linux is `full`. This limit resource usage low while still providing a good level of testing. If your pythons are `py38,py39,py310,py311` unless you specify `windows: full` you will see only two Windows based jobs in the generated matrix: py38 and py311.
The defaults for macOS and Windows are `minmax` while for Linux is `full`. This limits resource usage while still providing a good level of testing. If your pythons are `py38,py39,py310,py311` unless you specify `windows: full` you will see only two Windows based jobs in the generated matrix: py38 and py311.

</p></details>
### Why is <tt>other_names</tt> a multiline string instead of being a comma-separated one?

<details><summary>What is the difference between <tt>name</tt> and <tt>passed_name</tt> in generated matrix?</summary><p>

`name` is aimed to be the job name displayed in GHA, while `passed_name` is the tox environment name. We did not name it `tox_env` because we plan to add support for other testing frameworks, which might use different
terminology.
We wanted to allow users to chain (group) multiple tox environments in a single command like `tox run -e lint,packaging`, and this means that we needed to allow users to use commas as part of a valid name, without
splitting on it.

</p></details>
### How to use custom test commands for some jobs.

<details><summary>Why is <tt>other_names</tt> a multiline string instead of being comma separated?</summary><p>
In v3 we allow users to add entries like `py39-all:tox -f py39` inside `other-names`. This would translated into returning the job name `py39-all` and the command `tox -f py39`.

We wanted to allow users to chain (group) multiple tox environments in a single command like `tox run -e lint,packaging`, and this means that we
needed to allow users to use commas as part of a valid name, without
splitting on it.
This is especially useful as it allows users to make use of labels (`-m`) and factor filtering (`-f`) to select groups of tox environments instead of just using the environments (`-e`) selector.

</p></details>
This allows running other test frameworks instead of tox.
46 changes: 33 additions & 13 deletions entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,18 @@
IMPLICIT_SKIP_EXPLODE = "0"


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."""
if name in result:
core.set_failed(
f"Action failed as it tried add an already a job with duplicate name {name}: {result[name]} already present while trying to add {data}",
)
result[name] = data


# loop list staring with given item
# pylint: disable=too-many-locals,too-many-branches
def main() -> None: # noqa: C901
def main() -> None: # noqa: C901,PLR0912
"""Main."""
# print all env vars starting with INPUT_
for k, v in os.environ.items():
Expand All @@ -43,7 +52,7 @@ def main() -> None: # noqa: C901

core.debug(f"Testing strategy: {strategies}")

result = []
result: dict[str, dict[str, str]] = {}
if max_python == "3.13":
python_names = KNOWN_PYTHONS[KNOWN_PYTHONS.index(min_python) :]
else:
Expand All @@ -52,17 +61,23 @@ def main() -> None: # noqa: C901
]
python_flavours = len(python_names)
core.debug("...")
for env in other_names:
for line in other_names:
if ":" in line:
name, command = line.split(":", 1)
else:
name = line
command = f"tox -e {name}"
env_python = default_python
# Check for using correct python version for other_names like py310-devel.
match = re.search(r"py(\d+)", env)
match = re.search(r"py(\d+)", name)
if match:
py_version = match.groups()[0]
env_python = f"{py_version[0]}.{py_version[1:]}"
result.append(
add_job(
result,
name,
{
"name": env,
"passed_name": env,
"command": command,
"python_version": PYTHON_REDIRECTS.get(env_python, env_python),
"os": PLATFORM_MAP["linux"],
},
Expand All @@ -78,21 +93,24 @@ def main() -> None: # noqa: C901
):
continue

result.append(
add_job(
result,
f"py{py_name}{suffix}",
{
"name": f"py{py_name}{suffix}",
"python_version": python,
"os": PLATFORM_MAP.get(platform, platform),
"passed_name": f"py{py_name}",
"command": f"tox -e py{py_name}",
},
)

core.info(f"Generated {len(result)} matrix entries.")
names = [k["name"] for k in result]
names = sorted(result.keys())
core.info(f"Job names: {', '.join(names)}")
core.info(f"matrix: {json.dumps(result, indent=2)}")
matrix_include = []
matrix_include = [dict(result[name], name=name) for name in names]

core.set_output("matrix", {"include": result})
core.set_output("matrix", {"include": matrix_include})

# pylint: disable=broad-exception-caught
except Exception as exc: # noqa: BLE001
Expand All @@ -107,7 +125,9 @@ def main() -> None: # noqa: C901
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"
os.environ["INPUT_OTHER_NAMES"] = (
"lint\npkg\npy313-devel\npy39-factor:tox -f py39"
)
os.environ["INPUT_PLATFORMS"] = "linux,macos" # macos and windows
os.environ["INPUT_SKIP_EXPLODE"] = "0"
os.environ["INPUT_WINDOWS"] = "minmax"
Expand Down

0 comments on commit ba9da1c

Please sign in to comment.