# Automating dependency updates

Guide on how to automate npm and hugo dependencies with GitHub actions.

## Introduction

The Hinode template uses both Hugo modules and npm packages. In this guide we will use GitHub actions to upgrade both types of dependencies automatically, ensuring our repository is always up to date. However, before we enable these automation steps, we will set up branch protection first. This guide assumes you have successfully setup a site based on the Hinode template. See the guide on [how to create a site with Hinode](creating-first-site-hinode)
 for more information.

> [!NOTE]
> This guide uses branch protection. You will require a paid plan if you have a private repository. See [GitHub's plans](https://docs.github.com/en/get-started/learning-about-github/githubs-plans) for more details.

## Step 1 - Testing the branch for the first time

The [Hinode template](https://github.com/gethinode/template.git) includes a GitHub action, or workflow, to automatically test and build the main branch upon each change. You can find the full configuration in `.github/workflows/lint-build.yml`. The workflow references two npm commands, being `lint` and `build`. By default, Hinode lints content files (extension `.md`), scripts (extension `.js`), and styles (extension `.scss`). The Hinode docs provide more background about the [coding guidelines](docs/about/contribute#coding-guidelines)
.

The `build` job depends on the `lint` job and runs sequentially after it. It installs [Dart Sass](https://sass-lang.com/dart-sass/) as a prerequisite before invoking the Hugo build. The GitHub action `lint-build.yml` is invoked on each push to the `main` repository, or a PR against the same branch. It also includes a `workflow_dispatch` trigger that enables us to run the workflow manually.

  ![Step 1. Trigger the 'lint & build' action](img/gh-lint-step01.png)

  ![Step 2. Review the jobs](img/gh-lint-step02.png)

  ![Step 3. Validate the results](img/gh-lint-step03.png)

{{< /carousel >}}

Head over the `Actions` panel of your GitHub repository. It lists two actions, of which we will select `lint & build`. Click on `Run workflow 
` and `Run workflow` to manually invoke the workflow. GitHub will then show the `lint` and `build` jobs running in sequence. The main panel shows the terminal output of a runner, which is simply a container running on GitHub's server with the specified host OS and packages. You can click on each of the jobs' steps to view the output - which should look familiar. When all jobs have finished successfully, GitHub will report the entire workflow run as completed.

## Step 2 - Configuring branch protection

Branch protection sets up rules that must be satisfied before a Pull Request can be merged with a specific branch. This should include your production branch (usually `main`), but could also include other branches that you would like to control. Branch protection acts as a safeguard to prevent any changes to break your build. Of course, it is not 100% fool proof, so it would still make sense to do regular testing of any changes before you submit them. However, minor dependency updates and security updates should (in theory) not introduce any breaking changes. If you have a stable repository and (main) branch, it is quite safe to assume that, as long as all your tests are successful, these minor updates can be automatically merged without unexpected impact.

  ![Step 1. Click on Protect this branch](img/gh-branch-protect-step01.png)

  ![Step 2. Apply settings](img/gh-branch-protect-step02.png)

  ![Step 3. Authenticate the changes](img/gh-branch-protect-step03.png)

  ![Step 4. Confirm branch protection](img/gh-branch-protect-step04.png)

{{< /carousel >}}

Navigate to the homescreen of your repository on GitHub. You should see a warning that says your main branch is not protected. Click on the button `Protect this branch` to initiate branch protection. You can set up multiple rules to your liking. The recommended rules to enforce at a minimum are the following:

- Require a pull request before merging
- Require status checks to pass before merging
  - Require branches to be up to date before merging
{.tickmark}

> [!IMPORTANT]
> GitHub does not automatically update your status checks. For example, if you rename a job in the workflow, you need to manually remove the obsolete label and add the new one.

These settings ensure all proposed changes are submitted as part of a PR and prevents any commits directly on the main branch. We can then use each PR request as a trigger to test our codebase and build. We will now select the checks we ran previously in our `lint & build` action. Add the `lint` and `build` labels to the second check (`Require status checks to pass before merging`) individually. We are now ready to automate our dependency upgrades.

## Step 3 - Enabling auto-merged npm updates

GitHub provides an action called [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates) that helps us to automate the upgrades of our npm dependencies. The Hinode template has enabled Dependabot by default. The configuration can be found in `.github/dependabot.yml`. In the default setting, Dependabot creates a Pull Request for each dependency update. You will need to review these PRs and approve them manually.

With the branch protection in place we can enable `auto-merge`. This setting, which is disabled by default, allows merges to be automated if all preconditions (~branch protection rules) have been met. We can use this feature to automatically merge Dependabot PRs into our main branch. Head over to the `general` section in the repository settings. Within the section, scroll down until you find a setting called `Allow auto-merge`. Select it to apply this setting.

  ![Step 1. Navigate to 'general' in the repository settings](img/gh-auto-merge-step01.png)

  ![Step 2. Toggle 'auto-merge'](img/gh-auto-merge-step02.png)

{{< /carousel >}}

The template repository includes a workflow created by Nícolas Iensen to [configure auto-merge for Dependabot PRs](https://nicolasiensen.github.io/2022-07-23-automating-dependency-updates-with-dependabot-github-auto-merge-and-github-actions/). It approves any PR that includes a minor or patch upgrade. Major upgrades are not automatically approved and still require manual validation.

## Step 4 - Automating Hugo module upgrades

[Dependabot is not compatible with Hugo modules yet](https://github.com/dependabot/dependabot-core/issues/6860). Instead, Hinode uses its own fork of [create-pull-request](https://github.com/peter-evans/create-pull-request) by Peter Evans, published as `gethinode-actions/create-pull-request`, to update the Hugo modules. It calls the npm `mod:update` command on a scheduled interval. It will create a new branch and a Pull Request if it finds any updates. The corresponding action with the title `Update Hugo dependencies` can be found in `.github/workflows/mod-update.yml`.

  ![Step 1. Navigate to your account settings](img/gh-token-step01.png)

  ![Step 2. Define a new fine-grained token](img/gh-token-step02.png)

  ![Step 3. Apply R/W access for contents and Pull Requests](img/gh-token-step03.png)

  ![Step 4. Generate the token](img/gh-token-step04.png)

  ![Step 5. Navigate to the repository settings](img/gh-token-step05.png)

  ![Step 6. Create a new action secret](img/gh-token-step06.png)

  ![Step 7. Define the action secret HUGO_MOD_PR](img/gh-token-step07.png)

  ![Step 8. Confirm the secret was added](img/gh-token-step08.png)

{{< /carousel >}}

> [!CAUTION]
> Be careful with using actions from the marketplace, as this introduces a security risk. Rob Bos has written an excellent [blog about the risks involved and how you can mitigate this](https://devopsjournal.io/blog/2021/02/06/GitHub-Actions-Forking-Repositories).

The `Update Hugo Dependencies` action requires elevated privileges. We will now create a new fine-grained Personal Access Token (PAT) called `HUGO_MOD_PR` to authorize this action to run on our behalf. Set up the token in the `Developer settings` of your **Account settings** on GitHub. The token requires access to your repository with the following permissions:

- Read and Write access to content (code) and pull requests
{.tickmark}

When done, head over to `action secret` in the security section of the **repository configuration**. Create a new Repository token with the name `HUGO_MOD_PR` in your repository configuration and paste the PAT as content. Click on `Add secret` to add it to your repository.

  ![Step 1. Run the action workflow](img/gh-mod-step01.png)

  ![Step 2. Review the job output](img/gh-mod-step02.png)

  ![Step 3. Open the associated PR](img/gh-mod-step03.png)

  ![Step 4. Enable auto-merge](img/gh-mod-step04.png)

  ![Step 5. Confirm auto-merge](img/gh-mod-step05.png)

  ![Step 6. Validate the auto-merge](img/gh-mod-step06.png)

  ![Step 7. Observe the merged PR](img/gh-mod-step07.png)

{{< /carousel >}}

We can now run the `Update Hugo dependencies` action. Head over to the actions overview and trigger the action manually. You can review the job output. When any modules updates have been found, the action will automatically create a PR on our behalf. Go to the Pull Requests overview and select the corresponding PR. You can now enable auto-merge for this type of PR. When all checks have been met, GitHub will automatically merge the PR with the main branch.

## Conclusion

You have now successfully configured automated updates for your Hinode site. Review the [hosting and deployment options](hosting-and-deployment) to see various options on how to (automatically) publish your site to a hosting provider.
