Skip to content

Latest commit

 

History

History
300 lines (211 loc) · 11.4 KB

File metadata and controls

300 lines (211 loc) · 11.4 KB

Taskfile.md

Taskfile это гошный бинарь, который мы ставим в систему и обращаемся к нему как cli инструменту. В целом тж самое что и Make, но проще, чище и лучше, и без боли make

Навигация

install

Ставим на Ubuntu

curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.deb.sh' | sudo -E bash
sudo apt install task

Если другая система, смотрим доку

Базовая работа с Taskfile.yaml

использовать:

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

{{.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(зависимость) в команде - об этом тут).

Переменные из .env

Чтобы они появились в 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 описывать таски, это ни на что не влияет.