Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: conditional task execution #12

Open
nat-n opened this issue Oct 21, 2020 · 3 comments
Open

Proposal: conditional task execution #12

nat-n opened this issue Oct 21, 2020 · 3 comments
Assignees
Labels
enhancement New feature or request Seeking feedback

Comments

@nat-n
Copy link
Owner

nat-n commented Oct 21, 2020

The goal of this project is to be the obvious choice of task runner for python projects, with the simplicity of npm scripts for simple use cases, but also with powerful features comparable to make (at least as far any python project is likely to need).

One key feature of make is being able to skip build targets that already exist.

I need to analyse this problem a bit more but so far I’m thinking an appropriate comparable feature would be for all tasks to support a condition option, which can either represent a relative path to a file or directory (with globbing?), the existence of which would make the condition false, or it could reference a python function to evaluate.

Open questions:

  • what mechanisms should be available for overriding a condition? Is if enough to have a global --force CLI flag?

  • how should this work for composite tasks? should it be possible to skip the condition for a single subtask? Or is all or nothing good enough?

  • If conditions can be defined in multiple ways then this could work similarly to tasks, which a generally defined as dictionaries which can be differentiated between different types, or as just a string which is interpreted as a default type. What should the default type be? (I'm thinking python function) Is there a better way of representing this?

@nat-n nat-n added enhancement New feature or request Seeking feedback labels Oct 21, 2020
@howeaj
Copy link
Contributor

howeaj commented Mar 26, 2021

use case:

[tool.poe.tasks.test]
help = "Run unit tests with coverage"
cmd = "pytest --cov-report=html"

[tool.poe.tasks.cov]
help = "Open HTML test coverage report"
shell = "start htmlcov/index.html"

Ideally, I'd want the cov task to conditionally run the test task first if index.html doesn't exist.

@abi-jey
Copy link

abi-jey commented Mar 30, 2022

Hi this is definitely something that I have been looking for. Imagine you need to install some thing or run tests after install for your local dev but not in prod. If we use poetry than we can run only poetry install and be done with it. 🥹

[tool.poe.poetry hooks]
post_install = "post-install"

[tool.poe.tasks.post-install]
Sequence = [
{She'll="apt install something"},
{She'll="Poe test", condition="${dev}" },
]
Args=[{name=dev, default=True, type=bool}]

@nat-n
Copy link
Owner Author

nat-n commented Jan 8, 2023

Here's what I have in mind for this feature so far. Comments welcome.

There are two distinct mechanisms for making a task conditional.

The check option specifies another task (defaults to the expr task type with assert = true) which is executed first. If it returns non-zero then the main task execution is skipped.

[tool.poe.tasks.install-deps]
cmd   = "apt install something"
check = "${ENV} != 'prod'"

The other mechanism is similar to how dependencies work in gnu make, by building on top of the existing deps mechanism. a task can declare a target option that points to a file. If a task has a target declared then it will only execute if either that file does not exist, or it has as a dependency on a task with a target file that is newer that its own.

For example here package will run build, but build will only execute if there's no build artefact. So package will always execute if build does, or if build has otherwise executed more recently than it has (judging from the last updated dates of their respective target files).

[tool.poe.tasks.clean]
cmd   = "rm -rf build"

[tool.poe.tasks.build]
cmd   = "apt install something"
target = "build/app"

[tool.poe.tasks.package]
cmd   = "..."
target = "app.zip"
deps = ["build"]

So then one way to interpret the scenario from @howeaj would be to make cov depend on test, and configure test with another new option called watch, which specifies files equivalent to a target on a dependency but without having to have another task to depend on.

[tool.poe.tasks.test]
help = "Run unit tests with coverage"
cmd = "pytest --cov-report=html"
watch = ["src/**/*.py", "tests/**/*.py"]
target = "index.html"
deps = ["_src_changed"]

[tool.poe.tasks.cov]
help = "Open HTML test coverage report"
shell = "start htmlcov/index.html"
deps = ["test"]

Although I'm not sure this is really what you'd want?

I'm open to suggestions for a more elegant or powerful approach to this problem.

@nat-n nat-n self-assigned this Apr 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Seeking feedback
Projects
None yet
Development

No branches or pull requests

3 participants