# Building GitHub Action part 1

### When to build a custom action?

Normally when a project are getting bigger with number of build and deploy arises, DevOps uses custom build action to deploy the application. \
The standard workflow look like this

Checkout ---> Build ---> Deploy

In yml representation:

```yaml
jobs:
    build_and_deploy
        steps:
            - name: Checkout
            - uses: actions/checkout@v1
            
            - name: Build
              run: make all
              
            - name: Deploy
              uses: actions/deploy@v1
              with:
                  environment: Staging
    
```

Keyword **run** is an interface to a command prompt.

Keyword **uses** lets us invoke the action. Action relies on some other command line tool to do the job. It acts like the adapters between the workflow and the command line tools.

When do we used either action or invoking the command itself?&#x20;

We need to consider 4 things:

* Control flow
* Diagnostics
* Complexity
* Reuse

{% tabs %}
{% tab title="Control Flow" %}
Imagine you want to run an npm script called build.

```yaml
- name: Build
  run: npm run build
```

Before the "run build", restore first the packages by running the npm install or npm ci command.

```yaml
- name: Build
  run: 
    npm ci
    npm run build
```

But considering that we only want to run build when the restore is done. The above code will not behave as such it will still run the build even the restore fails.&#x20;

In order  to prevent this, we use a control flow. A flow in to do something only if the certain condition is met.

```yaml
- name: Build
  run: |
    npm ci && npm run build
```

Since **run** can be interpreted via shell, we can use any control flow structures that are build into the shell itself.

The above code will requires restore to pass before the build.

\
Now imagine that we have more than one package to build this workflow. We can use the working-directory keyword to run the same command on multiple project.&#x20;

```yaml
- name: Build
  run: |
    npm ci && npm run build
  working-directories: |
    ./src/project
```

But we have to duplicate the same shell command in different places.

```yaml
- name: Build
  run: |
    npm ci && npm run build
  working-directories: |
    ./src/project
- - name: Build one
  run: |
    npm ci && npm run build
  working-directories: |
    ./src/project
- name: Build two
  run: |
    npm ci && npm run build
  working-directories: |
    ./src/project
- name: Build three
  run: |
    npm ci && npm run build
  working-directories: |
    ./src/project
```

This defeats the purpose of KISS(Keep it simple and short). This is the run keyword limitation.\
A better solution is to package the build logic inside an actions that accepts one or more working directories as an input.

```yaml
- name: Build
  uses: actions/npm-build@v1
  with:
    working-directories: |
      - /src/projectOne
      - /src/projectTwo
      - /src/projectThree 
```

There is also an option to split the commands into separate jobs

```yaml
jobs:
    install:
        steps:
            - name: Clean Install
              run: npm ci
    build:
        needs: install
        steps:
            - name: Build
              run: npm run build
```

Notice that under build jobs, it requires the install by using the keyword needs. This is almost the same as using with ampersand.
{% endtab %}

{% tab title=" Diagnostics" %}
What is we want log the error when the job fails. This is where Diagnostics comes in. \
Right now there is no way to build error handling into the workflow itself, that is to be taken care inside of an action

```yaml
jobs:
    install:
        steps:
            - name: Clean Install
              run: npm ci
    build:
        needs: install
        steps:
            - name: Build
              run: npm run build
    
```

{% endtab %}

{% tab title="Complexity" %}
Workflows being declarative in nature are design to describe processes at a high level of obstruction. Namely as a sequence of steps that run in response to certain events.

Checkout ---> Build ---> Deploy

Imagine a workflow has two jobs and will do run it in a multiple projects . The only way to do that inside in a workflow is duplicate everything and specify a working directory each instance.

```yaml
jobs:
    install:
        steps:
            - name: Clean Install
              run: npm ci
              working_directory:..
    build:
        needs: install
        steps:
            - name: Build
              run: npm run build
              working_directory:..
```

Complexity does not also exist in the workflow level, it can also exist in a individual steps

```yaml
- name: Deploy
  env:
    USER: ${{secret.USER}}
    PWD: ${{secrets.PWD}}
  run: |
    curl -Ss \
    --fail \
    -X POST \
    -T path/to/app.zip \
    -u $USER:$PWD \
    https://example.com/app \
```

Take for instance a steps need to invoke command line program with many parameters. Now imagine one of the argument we need to pass comes from a different step, like at the curl parameter we need to used **PWD.** Again we can certainly can implement it right in the workflow. But there is a better way to do it. It is by grouping multiple related steps into a single action, we can reused it not only inside the workflow but also access workflows. This comes the Reuse
{% endtab %}

{% tab title="Reused" %}
&#x20;Grouping multiple related steps into a single action, we can reused it not only inside the workflow but also access workflows. If the action does something that could be useful to many people, we can make it available to everyone by publishing it to Github market place

```
jobs:
    build_and_deploy:
        steps:
            - name: Deploy and Build
              uses: ./npm-deploy@v1
    build_and_deploy another:
        steps:
            - name: Deploy and Build
              uses: ./npm-deploy@v1
    add_another:
        steps:
            - name: Deploy and Build
              uses: ./npm-deploy@v1
```

{% endtab %}
{% endtabs %}

In summary:

<figure><img src="https://2808248181-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8eU2eqBm5NpK3wHDjfNO%2Fuploads%2Fm3V4Ig68ZWkTqnQML7FH%2Fimage.png?alt=media&#x26;token=61188424-2cb4-445a-b310-1d0ba9751ba6" alt=""><figcaption></figcaption></figure>

\ <br>

&#x20;
