Appearance
Use as a GitHub Action
github-actions-updater ships as a composite Action alongside its npm CLI. Drop it into any workflow with:
yaml
- uses: ylabonte/github-actions-updater@v1The Action runs npx github-actions-updater@<version> under the hood — same code, same defaults, same flags. The npm package is the single source of truth; the Action is a thin manifest that wires inputs/outputs to the CLI.
Inputs and outputs
The complete tables live in the README. Highlights worth flagging here:
versiondefaults to1— the same major as the action ref (@v1). That keeps the action ref and the underlying CLI major aligned souses: …@v1can never silently jump to a future2.xCLI. Override the input to pin tighter (version: '1.2.3') for fully reproducible builds, or set it tolatestto opt into floating across majors.targetis intentionally empty by default rather thanlatest. When omitted, the Action skips--targeton the CLI invocation entirely, so anytargetvalue in the repo's data-only config file (e.g..ghaurc.json,ghau.config.json, or aghaukey inpackage.json) is honored. Set the input explicitly when you want to override the config (or want a hard guarantee against config drift):with: { target: minor }. See the config-file guide for the full precedence order and the complete list of accepted config filenames.commit: trueimplies--no-edit— no editor is invoked, the action commits the prefilled message verbatim. Withoutcommit, the workflow files are left modified for the next step to handle.fail-on-outdatedis tri-state.truemakes the action exit 1 on drift (CI gate);falseforces drift-tolerance for this run even if your repo's config setsfailOnOutdated: true; empty (the default) defers to the repo config's value or the CLI's built-in default (don't fail). Same shape applies toallow-branch-pin.github-tokendefaults to the workflow's auto-providedgithub.token. That's enough for public-repo scans. For private repos, supply a token with read access to the repository: a classic PAT with thereposcope, or a fine-grained PAT with the Contents: Read permission on the target repo. The token never leaves the in-memory Octokit instance — seesrc/core/auth.ts.changesoutput is the number of workflow files actually rewritten by the run, not the scan-time outdated count. The pathspec is scoped to the configured workflows directory (theworkflowsinput, defaulting to.github/workflows), so unrelated YAML edits elsewhere in the repo never inflate the count. Derivation: whencommit: true, the action capturesHEADbefore invoking the CLI and diffsHEAD_BEFORE..HEAD_AFTERfor the just-created commit's file list — or, on a previously unborn branch where the commit is the root commit, falls back togit diff-tree --rootagainst the empty tree. Whenwrite: truewithout--commit, the diff is taken against the working tree instead. Always0whenwrite: falseor when the workflow isn't running inside a git repository. Safe to gate downstream steps on, e.g.if: steps.ghau.outputs.changes > 0.Limitation:
changeswhenworkflowsDirlives in a config fileThe
changesdiff is scoped using theworkflowsinput only — not by reading the effectiveworkflowsDirfrom a.ghaurcconfig. If your config file setsworkflowsDirto something other than.github/workflowsand you don't pass the same path aswith: workflows: ...on the Action, files rewritten outside.github/workflowswon't be counted andchangeswill under-report (often to0). Pass the path explicitly on the Action when you rely onchangesfor gating, or check the always-accurateoutdatedoutput instead. Closing this gap properly is on the v1.2 roadmap.
Recipes
1. Auto-PR weekly (canonical)
Schedule a weekly run that opens a PR with the bumped versions.
yaml
name: Update GitHub Actions
on:
schedule:
- cron: '0 8 * * 1' # Mondays, 08:00 UTC
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ylabonte/github-actions-updater@v1
id: ghau
with:
write: true
commit: true
- uses: peter-evans/create-pull-request@v6
if: steps.ghau.outputs.changes > 0
with:
branch: chore/update-github-actions
title: 'chore(deps): update GitHub Actions'
body: |
Automated update of outdated GitHub Actions references.
See the commit message for the per-action breakdown.
delete-branch: truepermissions.pull-requests: writeis required forpeter-evans/create-pull-request.- Our
--commitmakes the commit;peter-evans/create-pull-requestdetects the existing commit and pushes it to a new branch, opening the PR. No double-commit.
2. Drift-only PR comment (no writes)
For repos that want awareness without automation: comment a summary on every PR.
yaml
name: Action drift report
on:
pull_request:
paths:
- '.github/workflows/**'
permissions:
contents: read
pull-requests: write
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ylabonte/github-actions-updater@v1
id: ghau
- name: Comment if drift
if: steps.ghau.outputs.outdated > 0
uses: actions/github-script@v7
env:
REPORT: ${{ steps.ghau.outputs.json }}
with:
script: |
const fs = require('node:fs');
const data = JSON.parse(fs.readFileSync(process.env.REPORT, 'utf8'));
const rows = data.entries.filter(e => e.outdated)
.map(e => `- \`${e.action}\` ${e.current} → ${e.latest} (${e.level})`)
.join('\n');
const body = `**${data.summary.outdated} outdated GitHub Action${data.summary.outdated === 1 ? '' : 's'}**\n\n${rows}`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});3. Hard CI gate (fail on drift)
For repos that treat outdated actions as a build failure:
yaml
- uses: ylabonte/github-actions-updater@v1
with:
fail-on-outdated: trueThe Action exits 1, the job fails, the PR can't be merged until the actions are bumped.
4. Pinning the Action version
yaml
# Latest stable v1.x.y (recommended for most users)
uses: ylabonte/github-actions-updater@v1
# Pin to an exact release for reproducible builds
uses: ylabonte/github-actions-updater@v1.2.3
# Pin to a commit SHA (most paranoid; insulates against tag re-pointing)
uses: ylabonte/github-actions-updater@<40-char-sha>The version input separately controls which npm version of the underlying CLI runs. The Action ref decides which action.yml is loaded; the input decides which CLI it dispatches to. They're independent, but typically tracked together:
yaml
uses: ylabonte/github-actions-updater@v1
with:
version: '1' # same major as the action ref5. Monorepos and non-default workflow directories
The Action scans .github/workflows by default. If your generated/synced workflow files live elsewhere, point at them:
yaml
- uses: ylabonte/github-actions-updater@v1
with:
workflows: packages/web/.github/workflowsTo scan multiple roots, run the Action multiple times and combine the JSON outputs in a follow-up step.
Marketplace
This repo is published to the GitHub Marketplace under the same name. The first publish was a one-time click on the Releases page ("Publish this Action to the Marketplace"). Subsequent releases inherit that listing automatically.
The floating v<major> tag is maintained by the release workflow — see .github/workflows/release.yml. Don't push v1 manually.