notebook

都内でWEB系エンジニアやってます。

RenovateでGitHub Actionsのアクションのバージョンを自動更新する

Renovateを使用して、GitHub Actionsで使用しているアクションのバージョンを自動で上げたい

少し調べてみるとIssueに上がっていた

Add support to update action in GitHub Actions workflow · Issue #5733 · renovatebot/renovate

github.com

Dockerのバージョンのみ対応しているよう

その他はregex managerでできるよという回答がされている

regex manager

正規表現のRenovateのドキュメント

Renovate Docs | Renovate Docs

docs.renovatebot.com

行けそう

正規表現でよしなに頑張る方法に関しては次エントリに書いたので詳しい方法は割愛する

Renovateで正規表現を使い独自フォーマットファイルの依存を自動更新をする

試してみる

Dockerイメージによる実行

試してみる

実行にはPersonalAccessTokenが必要なので事前に発行しておく

  • 参考

Setup using GitHub personal access token · Issue #570 · renovatebot/config-help

github.com

docker run --rm -e RENOVATE_TOKEN=xxxxxxxxxx -v "renovate-config.js:/usr/src/app/config.js" renovate/renovate --dry-run=true --log-level=debug username/reponame

RENOVATE_TOKENにあらかじめ発行したPersonalAccessTokenを指定する

dry-run

dry-runで実行ができる

PRが作成されないが更新対象かどうかなどを出力から判断できる

設定の確認とかで何度もPRが作成されてしまうみたいなのを防げる

実行

logLevel: debugで出力される内容を見ながら確認していく

  • renovate.json
{
  "extends": [
    "config:base"
  ],
  "labels": ["renovate"],
  "regexManagers": [
    {
      "fileMatch": ["^\\.github/workflows/[^/]+\\.ya?ml$"],
      "matchStrings": ["uses: (?<depName>.*?)@(?<currentValue>.*?)\n"],
      "datasourceTemplate": "github-releases"
    }
  ]
}

とりあえずregex managerを使用してみる

  • 対象
uses: actions/checkout@v1
  • 結果
{
  "packageFile": ".github/workflows/takeover-output.yml",
  "manager": "regex",
  "deps": [
    {
      "depName": "actions/checkout",
      "currentValue": "v1",
      "datasource": "github-releases",
      "replaceString": "uses: actions/checkout@v1\n",
      "depIndex": 0,
      "updates": [],
      "warnings": [],
      "skipReason": "unsupported-value"
    }
  ],
  "matchStrings": ["uses: (?<depName>.*?)@(?<currentValue>.*?)\n"]
}

よく書くActionsのフォーマット(v1など)だと未対応らしい…

  • 対象
uses: actions/checkout@v1.0.0
  • 結果
{
  "packageFile": ".github/workflows/takeover-output.yml",
  "manager": "regex",
  "deps": [
    {
      "depName": "actions/checkout",
      "currentValue": "v1.0.0",
      "datasource": "github-tags",
      "autoReplaceData": {
        "depIndex": 0,
        "replaceString": "uses: actions/checkout@v1.0.0\n"
      },
      "updates": [
        {
          "fromVersion": "v1.0.0",
          "toVersion": "v1.2.0",
          "newValue": "v1.2.0",
          "newMajor": 1,
          "newMinor": 2,
          "updateType": "minor",
          "isSingleVersion": true
        },
        {
          "fromVersion": "v1.0.0",
          "toVersion": "v2.2.0",
          "newValue": "v2.2.0",
          "newMajor": 2,
          "newMinor": 2,
          "updateType": "major",
          "isSingleVersion": true
        }
      ],
      "warnings": [],
      "sourceUrl": "https://github.com/actions/checkout"
    },
  ],
  "matchStrings": ["uses: (?<depName>.*?)@(?<currentValue>.*?)\n"]
}

semver(v1.0.0)にしたら大丈夫そう

v1などのフォーマットにも対応する

versioningにもregexが適用できないかなーなんて思っていたらやはり同じ様なことを考えた人がいるらしくすでにそういう機能も提供されていた

  • 参考

renovate/lib/versioning/regex at master · renovatebot/renovate

github.com

packageRulesを追加して再度試す

  • renovate.json
{
  "extends": [
    "config:base"
  ],
  "labels": ["renovate"],
  "regexManagers": [
    {
      "fileMatch": ["^\\.github/workflows/[^/]+\\.ya?ml$"],
      "matchStrings": ["uses: (?<depName>.*?)@(?<currentValue>.*?)\n"],
      "datasourceTemplate": "github-releases"
    }
  ],
  "packageRules": [
    {
      "packageNames": ["actions/checkout"],
      "versioning": "regex:^v(?<major>\\d+)(\\.(?<minor>\\d+))?(\\.(?<patch>\\d+))?"
    }
  ]
}
  • 結果
{
  "packageFile": ".github/workflows/takeover-output.yml",
  "manager": "regex",
  "deps": [
    {
      "depName": "actions/checkout",
      "currentValue": "v1",
      "datasource": "github-releases",
      "versioning": "regex",
      "replaceString": "uses: actions/checkout@v1\n",
      "depIndex": 0,
      "updates": [
        {
          "fromVersion": "v1",
          "toVersion": "v2.2.0",
          "newValue": "v2.2.0",
          "newMajor": 2,
          "newMinor": 2,
          "updateType": "major",
          "isSingleVersion": true,
          "releaseTimestamp": "2020-05-27T16:39:19Z"
        }
      ],
      "warnings": [],
      "sourceUrl": "https://github.com/actions/checkout"
    }
  ],
  "matchStrings": ["uses: (?<depName>.*?)@(?<currentValue>.*?)\n"]
}

判定できた

semver(v1.0.0など)のフォーマットではない場合(v1など)はpackageRules->packageNamesで対象パッケージとversioningの正規表現を指定する必要がある

ここでやっていることはパッケージ名によって正規表現で各種バージョンを解釈してくださいというような指定をしている

minor,patchに?が付いているのでv1などのバージョン指定方法でも解釈できるようになる

GitHub Actions経由でRenovateを実行する

GitHubAppsの権限では.github/以下のファイルに修正をかけてPR出すことができない模様(ソースがどこからかは失念してしまった…)

なのでGitHubActionsを使ってself hostでRenovateを実行する

  • 参考

renovatebot/github-action

github.com

公式がactionを出しているのでそれを使うとサクッとできる

最終的な設定ファイルなどは次のようになった

  • .github/workflows/renovate.yml
name: renovate

on:
  schedule:
    - cron: '0 15 * * *'

jobs:
  renovate:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2.0.0
      - name: Self-hosted Renovate
        uses: renovatebot/github-action@v21.6.3
        with:
          configurationFile: renovate-config.js
          token: ${{ secrets.PERSONAL_TOKEN }}
  • renovate-config.json
module.exports = {
  branchPrefix: 'selfhost-renovate/',
  dryRun: false,
  gitAuthor: 'Renovate Bot <bot@renovateapp.com>',
  logLevel: 'debug',
  onboarding: false,
  platform: 'github',
  includeForks: true,
  repositories: [
    'username/reponame'
  ]
};

Renovateを実行する際に使用する設定ファイル

self-hostで実行する場合この設定ファイルを指定する必要がある

余談だがツールの性質上repositoriesで複数指定できるのと、PersonalAccessTokenを使うので個人プロジェクト+self-host用のリポジトリを作ってそこでRenovateを回すという運用でも良さそう

  • renovate.json
{
  "extends": [
    "config:base"
  ],
  "labels": ["renovate"],
  "regexManagers": [
    {
      "fileMatch": ["^\\.github/workflows/[^/]+\\.ya?ml$"],
      "matchStrings": ["uses: (?<depName>.*?)@(?<currentValue>.*?)\n"],
      "datasourceTemplate": "github-releases"
    }
  ],
  "packageRules": [
    {
      "packageNames": [
        "actions/checkout",
        "actions/cache",
        "actions/upload-artifact",
        "actions/download-artifact",
        "actions/setup-ruby",
        "actions/setup-node",
        "renovatebot/github-action",
        "aws-actions/configure-aws-credentials",
        "GoogleCloudPlatform/github-actions/setup-gcloud"
      ],
      "versioning": "regex:^v(?<major>\\d+)(\\.(?<minor>\\d+))?(\\.(?<patch>\\d+))?"
    }
  ]
}

結果

f:id:swfz:20200617002317p:plain

f:id:swfz:20200617002338p:plain

v1 などの表記の場合でもPR作成できました

PRでv1.2.0のような形式になってしまいますが、自動更新であれば問題ないと思います

おわり

ここまで書いておいてあれですが「それ、dependabotでできるよ」案件です

すでにRenovate使っていて依存関係更新用のツールを2つも使うのは…っていう場合には使えますね

さらに厳密にいうとsemverではないよねっていう話もありつつそのあたりは見なかったことに…

Renovateとは大分仲良くなれそうな気がしてきました