Renovate를 이용한 의존성 자동 업데이트

renovate 로고

1) 의존성 자동 업데이트가 왜 필요한가

요즘은 소프트웨어 개발할 때 라이브러리를 편리하게 많이 사용한다.

예를 들어 내가 만든 크롬 확장(sh-cho/open-via-menlo)의 의존성을 보면 아래와 같은데, 작은 앱도 이렇게 많은 패키지 의존성을 가지고 있다.

{
  "devDependencies": {
    "@ant-design/icons": "^5.2.6",
    "@babel/cli": "^7.23.0",
    "@babel/core": "^7.23.2",
    "@babel/plugin-transform-modules-commonjs": "^7.23.0",
    "@babel/plugin-transform-runtime": "^7.23.2",
    "@babel/preset-env": "^7.23.2",
    "@babel/preset-react": "^7.22.15",
    "@babel/preset-typescript": "^7.23.2",
    "@types/chrome": "^0.0.268",
    "@types/eslint": "^8.44.4",
    "@types/jest": "^29.5.5",
    "@types/lodash": "^4.14.199",
    "@types/minimatch": "^5.1.2",
    "@types/node": "^20.8.6",
    "@types/react": "^18.2.28",
    "@types/react-dom": "^18.2.13",
    "@typescript-eslint/eslint-plugin": "^6.8.0",
    "@typescript-eslint/parser": "^6.8.0",
    "antd": "^5.10.1",
    "babel-jest": "^29.7.0",
    "clean-webpack-plugin": "^4.0.0",
    "copy-webpack-plugin": "^12.0.0",
    "css-loader": "^6.8.1",
    "dotenv-webpack": "^8.0.1",
    "eslint": "^8.51.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-prettier": "^9.0.0",
    "eslint-import-resolver-typescript": "^3.6.1",
    "eslint-plugin-import": "^2.28.1",
    "eslint-plugin-jsx-a11y": "^6.7.1",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "html-webpack-plugin": "^5.5.3",
    "jest": "^29.7.0",
    "lodash": "^4.17.21",
    "minimatch": "^9.0.3",
    "prettier": "^3.0.3",
    "process": "^0.11.10",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "recoil": "^0.7.7",
    "style-loader": "^3.3.3",
    "terser-webpack-plugin": "^5.3.9",
    "ts-jest": "^29.1.1",
    "ts-loader": "^9.5.0",
    "typescript": "^5.2.2",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-merge": "^5.10.0"
  },
}

package.json 일부

이렇게 많은 의존성들을 손수 업데이트 한다는건 매우 고된 일이다. 또한 위와 같이 앱에서 사용되는 npm 패키지 뿐 아니라, 도커(docker) 이미지, 헬름(helm) 차트, github-actions 등 여러 서드파티의 버전관리를 손수 한다는 것은 불가능에 가깝다.

버전 관리가 어렵다고 해서 업그레이드를 하지 않고 초기 세팅했을 때의 버전으로 계속 사용한다면 각종 취약점이나 버그에 노출될 수 있다.

따라서 요즘은 자동으로 의존성을 업데이트하는 봇을 많이 사용하는 추세고, 대표적인 봇을 꼽자면 아래와 같다

dependabot과 renovate bot이 생성한 PR 예시
dependabot, renovate PR 예시

이번 글에서는 Renovate에 대해 간단히 소개해보겠다

2) Renovate

Renovate(레노베이트)는 Mend에서 유지보수하는 의존성 관리 툴이다.

의존성 업데이트는 Pull Request로 올라오며, 자동으로 머지하도록 설정할 수 있다. 또한 일, 주 단위 등으로 의존성 검사할 스케줄을 정할 수 있다.

major 버전 업데이트는 수동, minor/patch 버전 업데이트는 자동으로 머지 되도록 하는 등 세부적인 설정도 가능해 입맛에 맞게 사용할 수 있다.

2-1) Renovate vs Dependabot

깃허브 Dependabot과 비교했을 때 여러 이점이 있는데, GitLab 등 다른 플랫폼에서도 사용 가능하며, 모노레포 패키지 업데이트시 뭉쳐주기도 하고, 셀프 호스팅도 가능하다.

더 자세한 비교 항목들은 위 링크를 참고한다

2-2) Renovate 사용법

GitHub에서 Renovate를 한번 사용해보자. 기타 자세한 사용법은 문서를 참고하자.

먼저 아래 링크에서 Renovate app 설치가 필요하다.

설치할 때, 모든 리파지토리에 적용하거나 적용할 리파지토리를 수동으로 선택할 수 있다.

Renovate github app
Renovate GitHub App

그 다음, renovate 봇이 올린 PR을 확인한다. renovate/configure 브랜치를 보면 renovate.json 파일이 추가되어 있을 것이다.

내 설정에 맞게 수정한 뒤 renovate 봇의 PR을 머지하면 된다. 또는, 직접 파일을 만들어서 main 브랜치에 푸시해도 된다. 이 경우 PR은 자동으로 close 된다

Renovate 설정 PR
Renovate 설정 PR

머지가 되었다면 이제 renovate가 수시로 업데이트를 PR로 올리게 된다.

PR이 꽤나 많이 올라오기 때문에 자동 머지되도록 설정하는게 편한데, CI가 통과될 때만 머지가 되기 때문에 테스트 환경을 잘 만들어둬야 한다.

2-3) Renovate 설정 예시

일주일에 한 번만 버전 체크하고, 마이너 버전 업데이트까지는 자동 머지하도록 하고, lockfile 업데이트 등을 설정한 예시는 아래와 같다.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended"],
  "packageRules": [
    {
      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
      "automerge": true,
      "automergeType": "branch"
    },
    {
      "matchDepTypes": ["devDependencies"],
      "automerge": true,
      "automergeType": "branch"
    }
  ],
  "lockFileMaintenance": {
    "enabled": true
  },
  "automerge": true,
  "platformAutomerge": true,
  "schedule": ["before 4am on monday"]
}

renovate.json example