Coverage for src/footman/tasks/new.py: 87%
13 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-06 02:59 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-06 02:59 +0000
1"""Scaffold a tasks file — `fm new`, the first thing in an empty directory.
3Brand-aware through the configured world: a branded CLI writes its own
4tasks filename and teaches its own command, so one implementation serves
5every runner. Stock footman declares it in `builtin=`, which is what makes
6`fm new` answer in a directory with no tasks at all — and inside a project
7the ordinary remedy applies: mount `footman.new` from the root tasks file
8to offer it there too.
9"""
11from __future__ import annotations
13from footman import _paths, context
14from footman.context import fail
15from footman.registry import task
17# Pure ASCII on purpose: this docstring is the first help text the new
18# tasks file renders, and a console encoding narrower than UTF-8 cannot
19# print a glyph outside its codec. A starter file plants nothing a legacy
20# terminal has to degrade.
21_SCAFFOLD = '''\
22from footman import task
25@task
26def hello(name: str = "world") -> None:
27 """Say hello. Replace me with your first real task."""
28 print(f"hello {name}")
29'''
32# The built-in set defaults to needing a project; this is the one task that
33# does not — writing the first tasks file is precisely what you do where
34# there is no project yet.
35@task(expose="global_only")
36def new() -> None:
37 """Write a starter tasks file in this directory."""
38 prog = context.current().prog
39 target = context.cwd() / _paths._tasks_file
40 if target.exists(): 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 fail(
42 f"{target.name} already exists here — edit it instead, or run "
43 f"{prog} new somewhere empty"
44 )
45 target.write_text(_SCAFFOLD, encoding="utf-8")
46 print(f"wrote {target.name} — try: {prog} hello")