Taskfile это гошный бинарь, который мы ставим в систему и обращаемся к нему как cli инструменту. В целом тж самое что и Make, но проще, чище и лучше, и без боли make
Ставим на Ubuntu
curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.deb.sh' | sudo -E bashsudo apt install taskЕсли другая система, смотрим доку
использовать:
task command # выполнить конкретную команду из спискаtask --list # показать список доступных командtask --help # куча команд которые неизвестно пригодятся ли, цвет вывода поменять, или создать файл и т.п ...Команды в конфиге {{.PWD}} это не shel уровень, это ДО shell, т.е указатели для Task бинаря, а $CMD во время исполения - т.е shell-ом
Разница:
cmds:
- echo {{.PWD}} # подставляется Task'ом
- echo $PG_USER # подставляется shell'омПримеры использования пре подготовленных команд:
{{.PWD}} — текущая директория.
{{.ROOT_DIR}} - то же самое, что PWD, но семантически означает именно корень Task-проекта.
{{.USER_WORKING_DIR}} - директория, из которой пользователь вызвал task.
{{.TASKFILE}} - путь к текущему Taskfile
{{.TASKFILE_DIR}} - директория, в которой находится текущий Taskfile.{{.TASK}} - имя текущей выполняемой задачи.
# Пример использования:
cmds:
- echo "Running {{.TASK}}"# Читаем подробнее ниже в `### Аргументы CLI`
{{.CLI_ARGS}}{{.CHECKSUM}} - хэш текущей задачи (используется для cache-механизмов) - вряд ли пригодится.{{.CLI_ARGS}} - Аргументы CLIПример для Аргументы CLI в конфиге:
- uv run alembic revision --autogenerate -m "{{.CLI_ARGS}}"пример использования с подстановкой:
task revision -- user add field
# user add field распарсит и подставит в {{.CLI_ARGS}}разделитель -- это ключевой сепаратор/указатель того, что дальше будут аргументы команды cli
Почему так? Потому что Task поддерживает вызов нескольких задач сразу - например -> task postgres_db start <- выполнит команду запуска БД и сразу стартанет приложение(но круче указать deps(зависимость) в команде - об этом тут).
Чтобы они появились в Taskfile, просто в начале конфига прописываем команду:
version: '3'
dotenv: ['.env']
...Точно так же достаются переменные из окружение проекта если мы их к примеру подгружаем direnv
Используем переменные из .env -> $ + название переменной:
postgres:db:
desc: БД временным volumes(удалится после остановки), для разработки и тестов
cmds:
- >
docker run --name=db
-e SSL_MODE=disable
-e POSTGRES_USER=$PG_USER
-e POSTGRES_PASSWORD=$PG_PASSWORD
-e POSTGRES_DB=$PG_DB
-e TZ=GMT-3
-v {{.PWD}}/scripts/init-user-db.sh:/docker-entrypoint-initdb.d/init-user-db.sh
-p $PG_PORT:5432
-d --rm
postgis/postgis:latestВозможные вопросы:
Вопрос:
- У меня подгружены переменные из .envrc и они в области видимости проекта, и так же подгружаются переменные в начале файла из .env, что произойдет?
Ответ:
- Если переменная уже есть в области видимости файла, он не будет заменена, и будет исопльзоваться переменная подгруженная в области видимости проекта через
direnv, если переменная требуется для запуска и не была найдена в области видимости проекта, и она есть в .env то и используется из .env
Область видимости окажется главнее.
Вопрос:
- Мне нужно чтобы подгружало в Taskfile.yaml .env из разных мест?
Ответ:
- Делаем в конфиге так:
dotenv:
- service1/.env # путь до .env
- service2/.envВопрос:
- Если у меня куча
.envпо проект, и там могут быть одинаковые переменные, то получитсякто первый, тот и занял местодля переменной из подгружаемых .env ->service1/.envбудетдоминатором, и забьет место своей переменной?
Ответ:
- Так и будет, какой первый .env подгрузился, тот и за резервировал. Что делать? Переменные разве что по разном уназвать. Других вариантов нет. Такой дизайн у бинаря, чтобы все не перепуталось.
Taskfile превратился в помоку и стал раздутый, хочется плакать и никогда не заглядывать туда?!
- yaml файлы поддерживают наследование, испокон веков. Так можно и с compose файлами делать, и т.д и т.п
includes:
service1: taskfiles/service1.yml
service2: taskfiles/service2.ymlИспользовать в главном так:
includes:
service1: ./test1/Taskfile.yaml
tasks:
test:
desc: Run tests
cmds:
- task service1:testгде наследник будет таким:
version: '3'
tasks:
test1:
desc: Run tests
cmds:
- echo $i love pythonВывод:
(src) user@user:~/dev/test-project$ task test
task: [test] task service1:test1
task: [service1:test1] echo $WHAT
i love pythonЛибо можно вызвать через главный Taskfile, но не городить команду в главное для вызова из дочки:
(src) user@user:~/dev/test-project$ task service1:test1Вывод будет таким же.
Можно делать команды зависимым от других.
Т.е прежде чем запустить набранная вами команда, выполнится зависимая.
Пример:
tasks:
start:
desc: Start app with uvicorn
deps: [compose:local]
cmds:
- >
uv run uvicorn
--reload
--host $HOST
--port $PORT
"$APP_MODULE"
compose:local:
desc: Local compose
cmds:
- docker compose -f docker-compose.local.yml up -d || true
Пояснение в этом кейсе:
Команда docker compose -f docker-compose.local.yml up -d || true выполнена не как обычно, а с доп командой || true -> сделано для того чтобы если упало с ошибкой, потому что был уже до этого запущен композник, то ничего страшного, скипаем и поднимаем приложение.
Почему команды обьявлены не через snake_case как привычно, а через двоеточие :
Проект регламентирует такой подход, чтобы строить иерархию команд и под команд, чтобы проще в этом ориентироваться.
Например:
(src) user@user:~/dev/test-project$ task --list
task: Available tasks for this project:
* start: Запустить API
* test: Просто тестовый пример, на показ как работать с наследованием.
* alembic:migrate: Провести миграцию БД до последней ревизии
* alembic:revision: Создать ревизию alembic
* compose:local: Поднять локальный compose (для разработки)
* compose:produp: Поднять прод compose
* osrm:start: Запустить OSRM (предполагается, что файлы .osrm уже созданы, если нет - использовать osrm:start:zero)
* osrm:start:zero: Запустить OSRM с нуля (создаст файлы .osrm, если их нет, и запустит сервис)
* osrm:stop: Остановить OSRM
* postgres:db: БД без сохранения volumes, для разработки и тестов
* postgres:db:volume: БД с volume (данные сохраняются при удалении контейнера)
* postgres:stop: Остановить БД
* redis:up: Запустить Redis
* seed:load: Загрузить сиды в БД
* service1:test1: Run tests
* uv:install:all: Установить все зависимости
* uv:install:main: Установить только основные зависимости (без dev)Здесь видно список команд с явным префиксом, postgres:* с продолжением.
Все это лишь регламент.
Вы можете привычным snake_case описывать таски, это ни на что не влияет.