React App and Build Pipeline with Task and Gitness
Published: 2024-04-05 14:01:13

[Task](https://taskfile.dev/) is a task runner/automation tool written in [Go](https://go.dev/) and distributed as a single binary.

A Taskfile is written in YAML, which may provide a shorter learning curve than alternative tools, like [GNU Make](https://www.gnu.org/software/make/). Task can also leverage Go's robust [template engine](https://taskfile.dev/usage/#gos-template-engine).

Task can be useful in build and test pipelines. Logic for running builds and tests can be written once in `Taskfile.yml` (or other [supported filenames](https://taskfile.dev/usage/#supported-file-names)), then used in both local development workflows and under automation.

[Gitness](https://gitness.com?utm_source=dev.to&utm_content=blog&utm_medium=blog&utm_term=gitness-task-in-ci) is an open source development platform from [Harness](https://www.harness.io?utm_source=dev.to&utm_content=blog&utm_medium=blog&utm_term=gitness-task-in-ci) that hosts your source code repositories and runs your software development lifecycle pipelines.

In this guide, we'll craft a `Taskfile.yml` for a sample [React](https://react.dev/) app, suitable for both local development and integration with your pipelines powered by Gitness.

## Prerequisites

[Install Task](https://taskfile.dev/installation/) and verify you can run `task` in your terminal.

This guide was tested with Task version 3.35.1.

```
$ task --version
Task version: v3.35.1 (h1:zjQ3tLv+LIStDDTzOQx8F97NE/8FSTanjZuwgy/hwro=)
```

[Install Docker](https://www.docker.com/products/docker-desktop/) and verify you can run `docker` in your terminal.

This guide was tested with Docker version 24.0.7.

```
$ docker --version
Docker version 24.0.7, build afdd53b
```

[Install Node](https://nodejs.org/en/download) and verify you can run `node` in your terminal.

This guide was tested with Node version 20.12.0.

```
$ node --version
v20.12.0
```

| ℹ️ Note |
|---------|
| Installing Node also installs `npm` and `npx` binaries. |

## Create React Application

Use the [Create React App](https://create-react-app.dev/) project to automatically generate the application. 

```
npx create-react-app my-react-app
```

Your `my-react-app` directory structure will look like this.

```
my-react-app/
├── README.md
├── node_modules/
├── package-lock.json
├── package.json
├── public/
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src/
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js
```

Change to the application directory.

```
cd my-react-app
```

Start the application.

```
npm start
```

Open http://localhost:3000 in your browser.
   
   ![Sample React application running in a browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/854iu180bjjtd05fn17u.png)

You now have a working React application! :tada:

In your terminal, type Ctrl-C to stop the process.

## Create `Taskfile.yml`

Create a `Taskfile.yml` file in your `my-react-app` directory with this configuration.

```yaml
version: '3'

tasks:

  npm-install:
    cmds:
      - npm install

  build:
    deps: [npm-install]
    cmds:
      - npm run build

  test:
    deps: [npm-install]
    cmds:
      - npm test
```

The `build` task runs `npm run build`, which creates a [production build](https://create-react-app.dev/docs/production-build/) of your application.

The `test` task runs `npm test`, which runs [unit tests](https://create-react-app.dev/docs/running-tests). There is only one unit test in `src/App.test.js`.

Note that `npm-install` task is a [dependency](https://taskfile.dev/usage/#task-dependencies) of the `build` and `test` tasks.

## Build and Test

Run `task build` in your terminal.

![Animated gif of the build task output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kc7r49oy6fex39pjrt3.gif)

By default, `npm test` will run tests interactively. To simulate running tests under [Continuous Integration](https://create-react-app.dev/docs/running-tests/#continuous-integration), set the CI environment variable.

Run `CI=true task test` in your terminal.

![Animated gif of the test task output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j554xflkjr2d3r1g26nh.gif)

Note that `task` passed the `CI=true` [variable](https://taskfile.dev/usage/#variables) to the `npm test` command.

## Setup Gitness

1. [Install Gitness](https://docs.gitness.com/#install-gitness)
2. [Create a project](https://docs.gitness.com/#create-a-project) named `demo`
3. Either [create a repository](https://docs.gitness.com/#create-a-repository) named `my-react-app` and push your sample app code, or [import](https://docs.gitness.com/repositories/overview#import-a-repository) the repository [jimsheldon/my-react-app](https://github.com/jimsheldon/my-react-app), which I created for this guide

## Create Pipeline

Open http://localhost:3000/demo/my-react-app/pipelines in your browser and select __New Pipeline__.

Enter `build-and-test` in the __Name__ field (this will automatically populate the __YAML Path__ field), then select __Create__.

![Create Gitness pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkycohke003skh6ghhbi.png)

Enter this Gitness [pipeline](https://docs.gitness.com/category/pipelines) in the YAML editor.

```yaml
kind: pipeline
spec:
  stages:
    - name: task example
      type: ci
      spec:
        steps:
          - name: install task
            type: run
            spec:
              container: alpine
              script: |
                apk add curl
                sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d
                ./bin/task --version

          - name: build
            type: run
            spec:
              container: node:20
              script: |
                ./bin/task build

          - name: test
            type: run
            spec:
              container: node:20
              script: |
                ./bin/task test
```

This Gitness pipeline has a single stage with three steps. The `install task` step uses the `alpine` Docker image to [install](https://taskfile.dev/installation/#install-script) the `task` binary into the workspace, where it can be reused by the following `build` and `test` steps, which run in the `node` Docker image.

Select __Save and Run__.

| ![Gitness pipeline yaml editor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zc6vpd8qmyheshdie1mf.png) |
|-|

Observe the pipeline execution.

| ![Gitness pipeline execution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0dkkplxjhaz1sq2ixk5v.png) |
|-|

## Conclusion

This workflow improves the [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) between local development and pipeline execution.

As long as the application can be built and tested with `task build` and `task test` commands, developers always keep the same workflow, and __the pipeline does not need to be modified__.

For example, the developers could [switch to yarn](https://classic.yarnpkg.com/lang/en/docs/migrating-from-npm/) by changing `Taskfile.yml` to use `yarn` commands rather than `npm` commands. This change would be transparent to developers, who would continue to run `task build` and `task test`, and the Gitness pipeline yaml would not need to be changed.

Next steps:
- See more examples of using [Task with Gitness](https://docs.gitness.com/pipelines/samples/task)
- Create [triggers](https://docs.gitness.com/pipelines/triggers) to automatically run the pipeline when commits are pushed to the repository
- Learn how Gitness [manages your data](https://docs.gitness.com/installation/data)
- Learn how to manage Gitness [projects and roles](https://docs.gitness.com/administration/project-management)