Skip to content

Task-level config overrides #423

@bitprophet

Description

@bitprophet

Realized in real-world nontrivial usage that we're still missing a useful config level: the task level.

Scenario

  • Collection-level overrides setting, say, run.hide = True, because most of your run calls should be silent (maybe you have a lot of explicit status output stuff using spinners, progress bars, etc)
  • Now you're inside a given task that you do want to be verbose by default, for whichever reason - violating that low-level collection-specified value. What levels are available to you?
  • Config file levels are above collection-level, but those are all, well, globally applied - there's no way to limit the setting to just some tasks.
  • Env var and overrides are the highest, and could technically work here, but you'd have to remember to specify them every time, which is a no-go (and they wouldn't help if you wanted to run >1 task in a session, only one of which wants to be verbose)
  • You could manually modify your context at the top of the task, setting c.run.hide = False. Great! Limited just to this task.
  • ...until you want to re-override that override at runtime, e.g. you don't actually want the normally chatty task to be chatty for once. "Context-level" or "user-level" manipulation of a "completed" config is absolute and cares not for any other level, so using global CLI flags or env vars doesn't help.
  • You could give the task its own variant of --hide (i.e. def mytask(hide=False)), then supply that value to the 'manual' override. This works, but requires two spots of boilerplate (signature and body code) and is poorly extensible (you'd have to do this for every task and for every config value that you want this treatment on).

Solution

The obvious solution is to allow @task to specify its own config level, which is slotted in above defaults, collection-level and config files, but below env var and overrides/CLI. This would fit in the hierarchy naturally (it's closer to runtime but doesn't win over those vectors) and should be relatively easy to implement, IIRC:

  • Add configure or configuration arg to @task/Task accepting a dict just like Collection.configure does
  • Add the new level to Config, plus Config.load_task() (to mirror load_collection())
  • Executor introspects this data when it's performing config updates (in config_for probably) and calls config.load_task(task.configuration) or whatnot
  • Config handles the hierarchy business
  • The user then sees a context/config that has the settings they expect

Other thoughts

This could also be used, directly or with some wrappers, to implement things like Fabric 1's @tasks/@roles, which are similarly task-level "configuration".

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions