From 2a852562f4fed7b805b451b4d53fa267d406dbe2 Mon Sep 17 00:00:00 2001 From: Mark Elliot <123787712+mark-thm@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:31:27 -0400 Subject: [PATCH] Add docs about how to update multitool's lockfile (#31) We've added a companion CLI called (creatively) `multitool`, that supports updating GitHub release based artifacts. In practice this is most of the artifacts we end up working with, and adding support for other, limited artifact sources seems tractable. In an ideal world, we'll ultimately teach Renovate how to run updates to our lockfile. However, looking at [Renovate's support for Bazel](https://github.com/renovatebot/renovate/blob/d6d1e57763ffefa04767a4d01b028b1d39f27188/lib/modules/manager/bazel/index.ts#L17-L22) artifact updates: Renovate will update GitHub releases, GitHub tags, Go datasources, and docker datasources. This is relatively limited, and our read is that GitHub releases covers the bulk of the artifacts one expects to encounter. Additionally, we'd like to make it easy to add new tools and more generally to manage the lockfile, and plan to add `add`, `remove`, and `lint` commands to our CLI down the road. We think that'll be useful even if we had full Renovate support. In addition to describing that the CLI exists, this PR includes sample GitHub Actions to use within one's repo. Publicly, one can see the download-and-execute example in [rules_uv](https://github.com/theoremlp/rules_uv/blob/main/.github/workflows/periodic-update-multitool.yml). Partial solution to #28. --- docs/automation.md | 125 +++++++++++++++++++++++++++++++++++++++++++++ readme.md | 6 +++ 2 files changed, 131 insertions(+) create mode 100644 docs/automation.md diff --git a/docs/automation.md b/docs/automation.md new file mode 100644 index 0000000..3f58f23 --- /dev/null +++ b/docs/automation.md @@ -0,0 +1,125 @@ +# GitHub Action Automation for Updating Tools + +## Using rules_multitool + +Configure your multitool lockfile to supply the multitool CLI. The action below assumes the tool name is set to "multitool". + +Then, make sure you have a GitHub Application to supply a token for creating a PR to your repository. The application will generally need 'Read & Write' on 'Pull Requests'. Ensure that your repository has access to two secrets related to your application: + +1. AUTOMATION_APP_ID: the application's integer id (visible to administrators of the application at the top of the General page) +2. AUTOMATION_PRIVATE_KEY: a private key generated in the 'Private Keys' section of the General page + +Create an action as follows, be sure to update the LOCKFILE environment variable to match your lockfile location, adjust secret names if they differ from the names above, and to update the committer in the final step. + +```yaml +name: Periodic - Update Multitool Versions +on: + workflow_dispatch: {} + schedule: + # run every hour on the 5 between 9am and 5pm (4am and 12pm UTC), M-F + - cron: "5 14-22 * * 1-5" +jobs: + update-requirement: + name: Update Multitool Versions + runs-on: ubuntu-latest + permissions: + contents: read + # disable running on anything but main + if: ${{ github.ref == 'refs/heads/main' }} + env: + LOCKFILE: ./multitool.lock.json + steps: + - name: Get Token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.AUTOMATION_APP_ID }} + private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} + - uses: actions/checkout@v4 + with: + token: ${{ steps.app-token.outputs.token }} + + - name: Find Updates and Render Lockfile + run: bazel run @multitool//tools/multitool:cwd -- --lockfile "$LOCKFILE" update + + - name: Commit Changes + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + BRANCH_NAME: "automation/update-multitool-lockfile" + run: | + if [[ -n "$(git diff "$LOCKFILE")" ]] + then + git config --local user.name 'Automation' + git config --local user.email 'app-name[bot]@users.noreply.github.com' + git checkout -b "${BRANCH_NAME}" + git add "$LOCKFILE" + git commit -m "Update Multitool Versions + + Updated with [update-multitool](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) by *${GITHUB_ACTOR}* + " + git push origin "${BRANCH_NAME}" -f + gh pr create --fill --label "automerge" >> "$GITHUB_STEP_SUMMARY" + fi +``` + +## Using the multitool CLI directly + +An alternative approach is to use the multitool CLI directly by downloading it. + +The preparation for this is largely the same, but you may skip including the multitool CLI in your lockfile. + +```yaml +name: Periodic - Update Multitool Versions +on: + workflow_dispatch: {} + schedule: + # run every hour on the 5 between 9am and 5pm (4am and 12pm UTC), M-F + - cron: "5 14-22 * * 1-5" +jobs: + update-requirement: + name: Update Multitool Versions + runs-on: ubuntu-latest + permissions: + contents: read + # disable running on anything but main + if: ${{ github.ref == 'refs/heads/main' }} + env: + LOCKFILE: ./multitool.lock.json + steps: + - name: Get Token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.AUTOMATION_APP_ID }} + private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} + - uses: actions/checkout@v4 + with: + token: ${{ steps.app-token.outputs.token }} + - name: Download and Extract Latest Multitool + run: | + latest="$(curl https://api.github.com/repos/theoremlp/multitool/releases/latest | jq -r '.assets[].browser_download_url | select(. | test("linux-gnu.tar.xz$"))')" + wget -O multitool.tar.xz "$latest" + tar --strip-components=1 -xf multitool.tar.xz + + - name: Find Updates and Render Lockfile + run: ./multitool --lockfile "$LOCKFILE" update + + - name: Commit Changes + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + BRANCH_NAME: "automation/update-multitool-lockfile" + run: | + if [[ -n "$(git diff "$LOCKFILE")" ]] + then + git config --local user.name 'Automation' + git config --local user.email 'app-name[bot]@users.noreply.github.com' + git checkout -b "${BRANCH_NAME}" + git add "$LOCKFILE" + git commit -m "Update Multitool Versions + + Updated with [update-multitool](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) by *${GITHUB_ACTOR}* + " + git push origin "${BRANCH_NAME}" -f + gh pr create --fill --label "automerge" >> "$GITHUB_STEP_SUMMARY" + fi +``` diff --git a/readme.md b/readme.md index 19d6849..64a7f67 100644 --- a/readme.md +++ b/readme.md @@ -74,3 +74,9 @@ A common pattern we recommend to further simplify invoking tools for repository bazel run "@multitool//tools/$( basename $0 ):cwd" -- "$@" ``` 1. Create symlinks of `tools/tool-name` to `tools/_run_multitool.sh` + +### Keeping Tools Up-to-Date + +We provide a companion CLI [multitool](https://github.com/theoremlp/multitool) to help manage multitool lockfiles. The CLI supports basic updating of artifacts that come from GitHub releases, and may be extended in the future to support other common release channels. + +See [our docs](docs/automation.md) on configuring a GitHub Action to check for updates and open PRs periodically.