[GitHub Actions] How to Automatically Run npm Update and Create a Pull Request
Tags: githubactions, npm
Published: 2023-12-05 03:46:16

## Background

There was a need to regularly run `npm update` to keep dependency packages up to date, but doing it manually was cumbersome, so I wanted to automate it using GitHub Actions.

## Specifications

1. Execute the workflow every Monday.
2. Run `npm update`.
3. Check if `package-lock.json` has been updated.
4. Commit `package-lock.json` and create a Pull Request.

## Implementation

### 1. Execute the Workflow Every Monday

```yaml
on:
  schedule:
    - cron: '0 0 * * 1'
```

### 2. Run `npm update`

```yaml
- name: Update packages
  run: npm update
```

### 3. Check for Changes in `package-lock.json`

```yaml
- name: Check for changes
  id: git-check
  run: |
    git diff --exit-code || echo "changes=true" >> $GITHUB_OUTPUT
```

Check for differences using `git diff --exit-code`. If there are changes, the `exit code` becomes 1, and `changes=true` is added to `$GITHUB_OUTPUT`.

### 4. Create a Pull Request

First, execute only if there are changes using `if: ${{ steps.git-check.outputs.changes == 'true' }}`.

For creating Pull Requests, use the action [peter-evans/create-pull-request](https://github.com/marketplace/actions/create-pull-request). This action allows batch specification of commits (`add-paths`), so it handles everything from committing `package-lock.json` to creating the Pull Request.

> The Create Pull Request action will:
> 
> 1. Check for repository changes in the Actions workspace. This includes:
>     - untracked (new) files
>     - tracked (modified) files
>     - commits made during the workflow that have not been pushed
> 2. Commit all changes to a new branch, or update an existing pull request branch.
> 3. Create a pull request to merge the new branch into the base—the branch checked out in the workflow.

The definition is as follows:

```yaml
- name: Create Pull Request
  if: ${{ steps.git-check.outputs.changes == 'true' }}
  uses: peter-evans/create-pull-request@v5
  with:
    token: ${{ secrets.BOT_TOKEN }}
    base: develop
    add-paths: package-lock.json
    commit-message: Update npm dependencies
    title: '[Automated] Update npm dependencies'
    body: 'Automated changes by GitHub Actions'
    branch: automated-npm-update
    delete-branch: true
```

Specifying `token` as `${{ secrets.GITHUB_TOKEN }}` is also fine, but if you want to trigger another Actions workflow, you need to prepare a different token.

Additionally, even if executed consecutively, commits will be made to the same branch, and the Pull Request will be updated (without failing to create a new Pull Request).

## Final Workflow

The workflow created is broadly as follows:

```yaml
name: Automated npm update

on:
  schedule:
    - cron: '0 0 * * 1'
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write

jobs:
  npm-update:
    env:
      pr_title: '[Automated] Update NPM dependencies'

    runs-on: ubuntu-latest

    steps:
      - name: Check out repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version-file: '.node-version'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Update packages
        run: npm update

      - name: Check for changes
        id: git-check
        run: |
          git diff --exit-code || echo "changes=true" >> $GITHUB_OUTPUT

      - name: Create Pull Request
        if: ${{ steps.git-check.outputs.changes == 'true' }}
        uses: peter-evans/create-pull-request@v5
        with:
          token: ${{ secrets

.BOT_TOKEN }}
          base: develop
          add-paths: package-lock.json
          commit-message: Update npm dependencies
          title: ${{ env.pr_title }}
          body: 'Automated changes by GitHub Actions'
          branch: automated-npm-update
          delete-branch: true
```