From d98983fdeca7cd6e28925546dd2ff140f363f720 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Fri, 10 Jul 2026 14:34:37 +0200 Subject: [PATCH] ci: add regctl and undock dependency update workflow Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- .github/workflows/update-deps.yml | 167 ++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 .github/workflows/update-deps.yml diff --git a/.github/workflows/update-deps.yml b/.github/workflows/update-deps.yml new file mode 100644 index 0000000..a5b4fee --- /dev/null +++ b/.github/workflows/update-deps.yml @@ -0,0 +1,167 @@ +name: update-deps + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + workflow_dispatch: + schedule: + - cron: '0 9 * * *' + push: + branches: + - 'master' + +jobs: + update: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + permissions: + contents: write + pull-requests: write + strategy: + fail-fast: false + matrix: + dep: + - regctl + - undock + steps: + - + name: GitHub auth token from GitHub App + id: write-app + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ secrets.GHACTIONS_REPO_WRITE_APP_ID }} + private-key: ${{ secrets.GHACTIONS_REPO_WRITE_APP_PRIVATE_KEY }} + owner: docker + repositories: setup-docker-action + permission-contents: write + permission-pull-requests: write + - + name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + token: ${{ steps.write-app.outputs.token }} + fetch-depth: 0 + persist-credentials: false + - + name: Update dependency + id: update + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + INPUT_DEP: ${{ matrix.dep }} + with: + script: | + const fs = require('fs'); + const path = require('path'); + + const dep = core.getInput('dep', {required: true}); + + function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + + function tsConstStringPattern(key) { + return new RegExp(`^(const ${escapeRegExp(key)} = ')([^']*)(';)$`, 'm'); + } + + async function readJsonFromActionsToolkit(relativePath) { + const response = await github.rest.repos.getContent({ + owner: 'docker', + repo: 'actions-toolkit', + path: relativePath, + ref: 'main' + }); + if (Array.isArray(response.data) || response.data.type !== 'file') { + throw new Error(`Expected ${relativePath} to be a file`); + } + return JSON.parse(Buffer.from(response.data.content, response.data.encoding).toString('utf8')); + } + + async function readLatestTag(relativePath) { + const tag = (await readJsonFromActionsToolkit(relativePath))?.latest?.tag_name; + if (!tag) { + throw new Error(`Unable to resolve latest tag from ${relativePath}`); + } + return tag; + } + + const dependencyConfigs = { + regctl: { + name: 'Regctl version', + branch: 'deps/regctl-version', + sourcePath: '.github/regclient-releases.json', + sourceUrl: 'https://github.com/docker/actions-toolkit/blob/main/.github/regclient-releases.json', + key: 'regctlDefaultVersion' + }, + undock: { + name: 'Undock version', + branch: 'deps/undock-version', + sourcePath: '.github/undock-releases.json', + sourceUrl: 'https://github.com/docker/actions-toolkit/blob/main/.github/undock-releases.json', + key: 'undockDefaultVersion' + } + }; + + const config = dependencyConfigs[dep]; + if (!config) { + core.setFailed(`Unknown dependency ${dep}`); + return; + } + + const version = await readLatestTag(config.sourcePath); + const targetPath = 'src/main.ts'; + const absolutePath = path.join(process.env.GITHUB_WORKSPACE, targetPath); + const content = fs.readFileSync(absolutePath, 'utf8'); + const pattern = tsConstStringPattern(config.key); + const match = content.match(pattern); + if (!match) { + throw new Error(`Missing ${config.key} in ${targetPath}`); + } + + const previousVersion = match[2]; + const changed = previousVersion !== version; + if (changed) { + fs.writeFileSync( + absolutePath, + content.replace(pattern, `$1${version}$3`), + 'utf8' + ); + core.info(`New ${config.name} ${version} found`); + } else { + core.info(`No workspace changes needed for ${config.name}`); + } + + core.info(`Resolved ${config.name} from ${config.sourceUrl}`); + core.setOutput('changed', String(changed)); + core.setOutput('branch', config.branch); + core.setOutput('title', `chore(deps): update ${config.name} from ${previousVersion} to ${version}`); + core.setOutput('before', previousVersion); + core.setOutput('after', version); + core.setOutput('source-url', config.sourceUrl); + - + name: Build + if: steps.update.outputs.changed == 'true' + uses: docker/bake-action@6614cfa25eff9a0b2b2697efb0b6159e7680d584 # v7.2.0 + with: + source: . + targets: build + - + name: Create pull request + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + base: master + branch: ${{ steps.update.outputs.branch }} + token: ${{ steps.write-app.outputs.token }} + commit-message: ${{ steps.update.outputs.title }} + title: ${{ steps.update.outputs.title }} + signoff: true + sign-commits: true + delete-branch: true + body: | + This updates the pinned default in `src/main.ts` from `${{ steps.update.outputs.before }}` to `${{ steps.update.outputs.after }}` and refreshes generated `dist` content. + + The source of truth for this update is ${{ steps.update.outputs.source-url }}.