Introduction to Taskfile: A Modern Build Tool for Efficient Project Management

Taskfile, a versatile and powerful build tool, has emerged as a popular choice among developers looking for a streamlined way to automate and manage their project’s tasks. Whether you’re dealing with complex build scripts or simple automation, Taskfile offers a solution that is both intuitive and highly customizable.

What is Taskfile?

Taskfile is an open-source build tool written in Go. It provides a declarative way to define tasks in a YAML configuration file, which can be executed with the task command. This tool is designed to be simple yet powerful, allowing you to define tasks that can run shell commands, interact with other tools, and manage dependencies between tasks.

Key Features of Taskfile

  1. Simplicity and Readability: Taskfile uses YAML for its configuration, making it easy to read and write. This format is both human-readable and machine-friendly, ensuring that your build scripts are easy to maintain and understand.
  2. Cross-Platform Compatibility: Taskfile is designed to work seamlessly on various operating systems, including Windows, macOS, and Linux. This ensures that your build processes are consistent across different environments.
  3. Task Dependencies: One of the standout features of Taskfile is its ability to define dependencies between tasks. This means you can specify which tasks need to run before others, ensuring that your build process follows a logical and efficient order.
  4. Variables and Environment Management: Taskfile allows you to define variables and manage environment settings within your tasks. This can include static values, dynamic commands, or environment variables, giving you the flexibility to configure tasks based on different contexts.
  5. Concurrency and Parallelism: To optimize performance, Taskfile supports running tasks concurrently where possible. This feature can significantly reduce build times by leveraging multi-core processors.

Getting Started with Taskfile

Installation

To get started with Taskfile, you need to install it on your system. You can do this by downloading the appropriate binary for your operating system from the Taskfile GitHub releases page or by using package managers

You can use Node and npm to install Task with following command

npm install -g @go-task/cliCode language: Java (java)

You can also use, OS specific package managers

Mac OS

brew install go-task/tap/go-taskCode language: Java (java)

or

brew install go-taskCode language: Java (java)

Ubuntu

sudo snap install task --classicCode language: Java (java)

Windows

winget install Task.TaskCode language: Java (java)

Basic Configuration

Once installed, you can create a Taskfile.yml in the root directory of your project. Here is a simple example for spring boot project

  version: '3'

  tasks:
    build:
      cmd: mvn clean package
    checkstyle:
      cmd: mvn checkstyle:check
    run:
      cmds:
        - docker-compose up -d
        - mvn spring-boot:runCode language: Java (java)

In this example:

  • The build task compiles the Go project.
  • The checkstyle task checks for code formatting rules
  • The run task removes the build artifacts.

in above file you can observer that cmd and cmds option

Use cmd option when you want to run single command, cmds option when you want to run multiple commands.

Listing the tasks

You can list the all available tasks with below command

task --list-allCode language: Java (java)

Running Tasks

To run a task, simply use the task command followed by the task name:

task build
task checkstyle
task runCode language: Java (java)

If task depends any other task, instead of repeating the commands again you can use the ‘deps’ option to specify the depending task.

  version: '3'

  tasks:
    build:
      deps:
        - checkstyle
      cmd: mvn clean package
    checkstyle:
      cmd: mvn checkstyle:check
    run:
      cmds:
        - docker-compose up -d
        - mvn spring-boot:run
Code language: YAML (yaml)

In above example, build task depends on checkstyle task, so we run

task build command, first checkstyle task will run and after that command specified in ‘cmd’ option is run.

Advanced Features

Dynamic Variables

You can define variables in your Taskfile, which can be used to make your tasks more flexible:

  version: '3'

  tasks:
    build:
      deps:
        - checkstyle
      cmd: mvn clean package
    checkstyle:
      cmd: mvn checkstyle:check
    run:
      cmds:
        - docker-compose up -d
        - mvn spring-boot:run
    test:
      cmd: mvn clean test
    sunit:
      cmd: mvn test -Dtest={{.UNIT_TEST}}Code language: Java (java)

In above example, you can pass the UNIT_TEST variable from command line to run the single unit test.

 task sunit UNIT_TEST=<unit-test-name>Code language: Java (java)

similarly you can do for same for the spring boot integration tests also

  version: '3'

  tasks:
    build:
      deps:
        - checkstyle
      cmd: mvn clean package
    checkstyle:
      cmd: mvn checkstyle:check
    run:
      cmds:
        - docker-compose up -d
        - mvn spring-boot:run
    test:
      cmd: mvn clean test
    sunit:
      cmd: mvn test -Dtest={{.UNIT_TEST}}
    it:
      cmd: mvn clean verify
    sit:
      cmd: mvn verify -Dit.test={{.IT_TEST}}Code language: Java (java)

You can also assign default value to dynamic variable inside Task file and override them from CLI

  version: '3'

  vars:
    SKIP_TEST: true

  tasks:
    build:
      deps:
        - checkstyle
      cmd: mvn clean package
    checkstyle:
      cmd: mvn checkstyle:check
    run:
      cmds:
        - docker-compose up -d
        - mvn spring-boot:run
    test:
      cmd: mvn clean test
    sunit:
      cmd: mvn test -Dtest={{.UNIT_TEST}}
    it:
      cmd: mvn clean verify
    sit:
      cmd: mvn verify -Dit.test={{.IT_TEST}}
    buildskiptests:
      cmd: mvn clean package -DskipTests={{.SKIP_TEST}}Code language: Java (java)

In above example, SKIP_TEST variable is set to true, if you want to override the default value you can pass the new value from cli

task buildskiptests SKIP_TEST=falseCode language: Java (java)

Conditional Execution

Taskfile supports conditional execution of tasks based on the status of previous tasks or conditions defined within the Taskfile:

  version: '3'

  vars:
    SKIP_TEST: true

  tasks:
    build:
      deps:
        - checkstyle
      cmd: mvn clean package
    checkstyle:
      cmd: mvn checkstyle:check
    run:
      cmds:
        - docker-compose up -d
        - mvn spring-boot:run
      preconditions:
        - sh: test -f docker-compose.yml
          msg: "docker-compose.yml file does not exist"
    test:
      cmd: mvn clean test
    sunit:
      cmd: mvn test -Dtest={{.UNIT_TEST}}
    it:
      cmd: mvn clean verify
    sit:
      cmd: mvn verify -Dit.test={{.IT_TEST}}
    buildskiptests:
      cmd: mvn clean package -DskipTests={{.SKIP_TEST}}Code language: Java (java)
task run
Code language: Java (java)

in above example, for ‘run’ task, we are checking whether docker-compose.yml file exits in the project. If file does not exits, we see error message like below

task: docker-compose.yml file does not exist
task: precondition not metCode language: Java (java)

Running a Taskfile from a subdirectory

f a Taskfile cannot be found in the current working directory, it will walk up the file tree until it finds one . When running Task from a subdirectory like this, it will behave as if you ran it from the directory containing the Taskfile.

You can use this functionality along with the special {{.USER_WORKING_DIR}} variable to create some very useful reusable tasks. For example, if you have a monorepo with directories for each microservice, you can cd into a microservice directory and run a task command to bring it up without having to create multiple tasks or Taskfiles with identical content. For example:

version: '3'

tasks:
  up:
    dir: '{{.USER_WORKING_DIR}}'
    preconditions:
      - test -f docker-compose.yml
    cmds:
      - docker-compose up -dCode language: Java (java)

Running a global Taskfile

If you call Task with the --global (alias -g) flag, it will look for your home directory instead of your working directory. In short, Task will look for a Taskfile that matches $HOME/{T,t}askfile.{yml,yaml} .

This is useful to have automation that you can run from anywhere in your system!

Place the Taskfile.yml file in your home directory with following content

version: '3'

tasks:
  from-home:
    cmds:
      - pwd

  from-working-directory:
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - pwdCode language: Java (java)
task -g from-home  // show user home directory
task -g from-working-directory // shows current working directoryCode language: Java (java)

Using Task in GitHub Actions

You can also use Task build toll in github actions with following action

- name: Install Task
  uses: arduino/setup-task@v1
  with:
    version: 3.x
    repo-token: ${{ secrets.GITHUB_TOKEN }}Code language: Java (java)

Conclusion

Taskfile is a powerful yet simple build tool that can significantly enhance your project’s build process. Its declarative approach, coupled with features like task dependencies, variable management, and cross-platform compatibility, makes it an ideal choice for developers looking to automate and streamline their workflows. Whether you are managing a small script or a large-scale application, Taskfile provides the tools you need to maintain an efficient and organized build process.

Give Taskfile a try and see how it can transform the way you manage your project builds. For more information and advanced usage, visit the Taskfile documentation.

Similar Posts