Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

GitHub Actionsで独自にversionをupdateするpull reqをbotから出す仕組みを作る

「独自に」とは

scala-stewardやdependabotやrenovateなどがあるけど、それらでupdate出来ない状態のもの」

も、無理やり自動updateさせたい、という話です。

大抵「勝手に最新版をinstallする」という設定なら難しくないのですが、それだと実行する日時によってinstallされるversionが変わり、最悪、何もしていないのに壊れたり、意図しない挙動の変化に遭遇する可能性があるので、理想としては、大体全てのものについて

「versionは明示しつつも、そのversionのupdateは自動でbotからpull reqくるようにして欲しい」

となると思います。

こんなもの普通に誰か作っている気がする、かつ、そもそもそういう状態を避け、出来るだけ公式のそれらの「dependabotやrenovateなど」でupdateされる状態にするためにそれぞれの言語の公式のビルドツール、パッケージマネージャーなどを使うのが良いと思いますが、

個人的にgithub actionsで独自に頑張るのに良くも悪くも慣れてしまい、この程度なら簡単に作れるので、作ったものを貼っておきます。

例えば、シングルバイナリで提供されてgithubなどからdownloadするだけのものを、わざわざ自動updateのためだけにその言語のパッケージマネージャーというか、ビルドファイル作って書いておくのは、あり得なくもないが、それはそれで若干面倒ですしね(?)

あとは、公式の actions/create-github-app-tokenactions/github-script だけで作れるメリットも大きいです。

例えばwartremoverに以下のようなものを入れました。

https://github.com/wartremover/wartremover/blob/226450ca50d8fefabb91d890658d090e601d933a/.github/workflows/update-nightly.yml

これは頑張ってscala-stewardにやらせるようにbuildファイルを書いてもよかったのですが、試しにあえてやってみた面が大きいです。

これは、xpathxml処理できるツールを入れて、maven centralのmetadata取ってきてそこからlatest version取得しています。

他には、githubのlatestのrelease versionをとってくるとしたら、例えば以下のような感じになります。

あくまでversionが書かれただけのtext fileを更新するだけなので、それを読み取って利用する側は別途独自に頑張る必要はあります。

on:
  schedule:
  - cron: '0 10 * * *' # いい感じに設定
  workflow_dispatch:
jobs:
  update:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    strategy:
      fail-fast: false
      matrix:
        # 適当な例としておいておくが、これらも別に頑張ればrenovateやdependabotにやらせるのは不可能ではなさそう
        # CIコストをギリギリまで節約するなら、matrixではなく1つのjob内部でloopさせた方がいいかも
        repo:
        - "reviewdog/reviewdog"
        - "bufbuild/buf"
    steps:
    # github appや独自に設定したtokenでpull req出さないとCI動かないので
    - id: generate_token
      uses: actions/create-github-app-token@v1
      with:
        app-id: ${{ secrets.自分で設定したKEY }}
        private-key: ${{ secrets.自分で設定したKEY }}
    - uses: actions/checkout@v4
      with:
        # 後でそのままpush出来るように、作ったtoken指定でcheckout
        token: ${{ steps.generate_token.outputs.token }}
    # `uses: actions/github-script@v7` でもghでもなんでもいいが、
    # API呼び出してlatest取得して、それを適当なtest fileに書き込む
    # 書き込むテキストファイルの置き場は好きなところにしてください
    - run: |
        REPO_NAME="${{ matrix.repo }}"
        gh api \
          -H "Accept: application/vnd.github+json" \
          -H "X-GitHub-Api-Version: 2022-11-28" \
          "/repos/${{ matrix.repo }}/releases/latest" | jq --raw-output ".tag_name" > ".github/${REPO_NAME##*/}_version.txt"
      env:
        GH_TOKEN: ${{ github.token }}
    - id: push
      run: |
        BRANCH_NAME="update-${{ matrix.repo }}"
        git checkout -b $BRANCH_NAME
        git add -u
        git config --global user.email "自分のgithub-appのemailアドレス@users.noreply.github.com"
        git config --global user.name "自分のgithub-appのid[bot]"
        # これで差分あった時だけcommitしてpushしてpull reqになるはず
        if git commit -m "update ${{ matrix.repo }}"; then
          git push origin $BRANCH_NAME
          echo "pushed=true"  >> $GITHUB_OUTPUT
        else
          echo "pushed=false" >> $GITHUB_OUTPUT
        fi
    - uses: actions/github-script@v7
      if: steps.push.outputs.pushed == 'true'
      with:
        github-token: ${{ steps.generate_token.outputs.token }}
        script: |
           // 最低限のtitleだけだが、もっとbodyに色々入れるなどした方が親切ではある
          await github.rest.pulls.create({
            owner: context.repo.owner,
            repo: context.repo.repo,
            head: "update-${{ matrix.repo }}",
            base: "${{ github.ref_name }}",
            title: "update ${{ matrix.repo }}"
          });