GitHub Actions 101: Creating Your First Node js workflow
Tags: devops, githubactions, cicd, tutorial
Published: 2023-07-12 17:28:19

__GitHub Actions__ is a powerful CI/CD platform provided by GitHub. It allows you to automate workflows, build and test code, and deploy applications directly from your GitHub repositories. Here are some key points to understand:
- GitHub Actions provides a flexible and scalable infrastructure for running CI/CD processes. It supports various programming languages, frameworks, and platforms.
- Workflows in GitHub Actions are defined using YAML files that specify the series of steps to be executed when triggered by certain events, such as pushes or pull requests.

# The components of GitHub Actions

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/88cj8kcj3bvq04bujte1.png)

### Workflows
A workflow is a configurable automated process that will run one or more jobs. Workflows are defined by a YAML file checked in to your repository and will run when triggered by an event in your repository, or they can be triggered manually, or at a defined schedule.
```
.github/
├── workflows/
│   ├── build.yaml
│   ├── deploy.yaml
│   └── ...
└── ...
```
> Workflows are defined in the `.github/workflows` directory in a repository, and a repository can have multiple workflows, each of which can perform a different set of tasks. For example, you can have one workflow to build and test pull requests, another workflow to deploy your application every time a release is created. For a GitHub Actions Workflow syntax , see [Syntax for workflows](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#about-yaml-syntax-for-workflows)

### Events 
An event is a specific activity in a repository that triggers a workflow run. For example, activity can originate from GitHub when someone creates a pull request, opens an issue, or pushes a commit to a repository. You can also trigger a workflow to run on a schedule, by posting to a REST API, or manually.

> For a complete list of events that can be used to trigger workflows, see [Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows).

### Jobs
A job is a set of steps in a workflow that is executed on the same runner. Each step is either a shell script that will be executed, or an action that will be run. Steps are executed in order and are dependent on each other. Since each step is executed on the same runner, you can share data from one step to another. For example, you can have a step that builds your application followed by a step that tests the application that was built.

>You can configure a job's dependencies with other jobs; by default, jobs have no dependencies and run in parallel with each other. When a job takes a dependency on another job, it will wait for the dependent job to complete before it can run. 

### Actions
An action is a Custom applications that perform complex, reusable tasks within workflows. Actions reduce repetitive code and can handle tasks like pulling code from repositories or setting up build environments.

### Runners
A runner is a server that runs your workflows when they're triggered. Each runner can run a single job at a time. GitHub provides Ubuntu Linux, Microsoft Windows, and macOS runners to run your workflows; each workflow run executes in a fresh, newly-provisioned virtual machine. 

## 👩‍💻 Create an example workflow
To get started with GitHub Actions, let's create an example workflow. Follow these steps:
1. In your repository, create the `.github/workflows/` directory to store your workflow files.
2. In the `.github/workflows/` directory, create a new file called `build.yml` and add the following code.

```yaml
name: Build
on:
  pull_request:
    types: [assigned, opened, synchronize, reopened]
    branches: [ main ]

env:
  IMAGE_NAME: "service-api"

permissions:
  checks: write
  pull-requests: write
  contents: read
  packages: read

jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Install Node
        uses: actions/setup-node@v3
        with:
          node-version: '18.12.1'
      - name: Install dependencies
        run: |
          npm install
      - name: Run Lint
        run: |
          npm run lint
      - name: Run Test & Report Coverage
        uses: ArtiomTr/jest-coverage-report-action@v2
        with:
          skip-step: install
          test-script: npm run test:unit

  docker_build_test:
    name: API Docker Build Check
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3
      - name: Docker Build Test API
        run: |
          docker build --rm -f ./Dockerfile --tag $IMAGE_NAME:test .
      - name: Docker Build Clean Up
        run: |
          docker rmi -f $IMAGE_NAME:test 
```

## Understanding the workflow file
To help you understand how YAML syntax is used to create a workflow file, this section explains each line of the introduction's example:

```yaml
name: Build
on:
  pull_request:
    types: [assigned, opened, synchronize, reopened]
    branches: [main]

env:
  IMAGE_NAME: "service-api"

permissions:
  checks: write
  pull-requests: write
  contents: read
  packages: read

jobs: 
  # ...
```
- The `name` field specifies the name of the workflow.
- The `on` field defines the events that trigger the workflow. In this example, the workflow is triggered when a pull request is assigned, opened, synchronized, or reopened on the main branch.
- The `env` field sets an environment variable named `IMAGE_NAME` with the value "service-api".
- The `permissions` field defines the required permissions for the workflow, such as writing checks, writing to pull requests, reading repository contents, and reading packages.

#### Test job
```yaml
  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
```
- This job is named "Test".
- The `runs-on` field sets the runner environment to `ubuntu-latest`.
- The first step checks out the repository code using the [actions/checkout](https://github.com/actions/checkout) action.
```yaml
   - name: Install Node
        uses: actions/setup-node@v3
        with:
          node-version: '18.12.1'
```
- This step uses the [actions/setup-node](https://github.com/actions/setup-node) action to install a specific version of Node.js (in this case, version 18.12.1).
```yaml
      - name: Install dependencies
        run: |
          npm install
```
- This step runs the `npm install` command to install the project dependencies.
``` yaml
      - name: Run Lint
        run: |
          npm run lint
```
- This step runs the `npm run lint` command to perform linting checks on the codebase.
``` yaml
      - name: Run Test & Report Coverage
        uses: ArtiomTr/jest-coverage-report-action@v2
        with:
          skip-step: install
          test-script: npm run test:unit
```
- This step utilizes a custom action [ArtiomTr/jest-coverage-report-action](https://github.com/ArtiomTr/jest-coverage-report-action) to run tests and generate a coverage report. It skips the install step and runs the `npm run test:unit` command.

#### API Docker Build Check job
```yaml
  docker_build_test:
    name: API Docker Build Check
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3
```
- This job is named "API Docker Build Check".
- The `needs` field specifies that this job depends on the completion of the previous test job.
- The `runs-on` field sets the runner environment to `ubuntu-latest`.
- The first step checks out the repository code using the [actions/checkout](https://github.com/actions/checkout) action.
```yaml
      - name: Docker Build Test API
        run: |
          docker build --rm -f ./Dockerfile --tag $IMAGE_NAME:test .
```
- This step builds a Docker image for the API by running the `docker build` command with the provided Dockerfile. The image is tagged with the value of the `IMAGE_NAME` environment variable.
```yaml
      - name: Docker Build Clean Up
        run: |
          docker rmi -f $IMAGE_NAME:test
```
- The final step removes the Docker image created in the previous step using the `docker rmi` command.

## 🚀 Summary
Once you have created the `build.yml` file in your repository, GitHub Actions will automatically run this workflow when triggered by pull requests on the main branch. You can customize the steps and actions based on your project's requirements.

Make sure to adapt the workflow code to match your project's structure and requirements. Happy automating with __GitHub Actions!__