Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ updates:
prefix: "ci"
labels: ["dependencies", "github_actions", "skip-changelog"]

# The digest-pinned base image the scaffold emits. These PRs fail the bump and changelog checks
# until `shared:docker`'s version in src/features/docker.ts is bumped and an entry added by hand.
# The digest-pinned base image the scaffold emits. The dependabot-bump workflow adds the
# `shared:docker` bump and a changelog line these PRs need.
- package-ecosystem: docker
directory: /packages/preset-nuxt4/templates/docker
schedule:
Expand Down
66 changes: 66 additions & 0 deletions .github/workflows/dependabot-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Dependabot feature bump

# A Dependabot PR that changes a template a scaffold emits (the Dockerfile's base image, for one)
# must bump that feature's version, or existing projects never get it on `battlestack pull`, and
# it needs a changelog line. This adds both to the PR, as a person would.
#
# `pull_request_target` runs with this repository's secrets, which a Dependabot-triggered
# `pull_request` run cannot read. The push uses RELEASE_PR_TOKEN because GitHub starts no
# workflows for a GITHUB_TOKEN push, so the required checks would never run on the new commit.
# Nothing from the PR is installed or built: the bump script needs only Node's own modules.

on:
pull_request_target:
types: [opened, synchronize, reopened]

permissions:
contents: read

jobs:
bump:
name: Bump features whose templates changed
if: github.event.pull_request.user.login == 'dependabot[bot]'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout the PR branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
token: ${{ secrets.RELEASE_PR_TOKEN }}

- name: Setup Node
uses: actions/setup-node@v7
with:
node-version: '24'

- name: Bump the features the version gate would fail on
env:
BUMP_CHECK_BASE: origin/${{ github.event.pull_request.base.ref }}
run: npx -y tsx@4.23.15 scripts/bump-check.ts --check --fix

- name: Add a changelog line
env:
TITLE: ${{ github.event.pull_request.title }}
BASE: origin/${{ github.event.pull_request.base.ref }}
run: |
git diff --quiet -- packages && exit 0
git diff --quiet "$BASE" -- CHANGELOG.md || exit 0
# "fix(docker): bump node from a to b in /x" -> "Bump node from a to b in /x."
line="$(printf '%s' "$TITLE" | sed -E 's/^[a-z]+(\([^)]*\))?!?: //; s/^./\U&/; s/\.?$/./')"
node -e '
const fs = require("fs")
const s = fs.readFileSync("CHANGELOG.md", "utf8")
const head = "## Unreleased\n\n"
if (!s.includes(head)) process.exit(1)
fs.writeFileSync("CHANGELOG.md", s.replace(head, `${head}- ${process.argv[1]}\n`))
' "$line"

- name: Commit and push
run: |
git diff --quiet && { echo "No feature needed a bump."; exit 0; }
git config user.name "battlestack-bot"
git config user.email "battlestack-bot@users.noreply.github.com"
git commit -am "chore: bump the features this dependency update changes"
git push origin HEAD:${{ github.event.pull_request.head.ref }}
11 changes: 11 additions & 0 deletions scripts/bump-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Feature version gate.
*
* pnpm bump:check [baseRef] CI gate: fail when a changed feature was not bumped
* pnpm bump:check --fix patch-bump every feature the gate would fail on
* pnpm bump --list every feature, version, status
* pnpm bump --changed only features with changes
* pnpm bump <id> <level> rewrite one version (patch|minor|major)
Expand Down Expand Up @@ -104,6 +105,16 @@ async function runCheck(argv: string[]): Promise<void> {
return
}

if (argv.includes('--fix')) {
const ids = new Set([...offenders.map((f) => f.id), ...writerOffenders.map((w) => w.writerId)])
for (const id of ids) {
const target = features.find((f) => f.id === id)
if (!target) fail(`no feature with id "${id}"`)
await applyBump(target, 'patch')
}
return
}

for (const f of offenders) {
console.log(`\nFAIL ${f.id} changed but is still ${f.version}`)
console.log(` files: ${f.ownedPaths.map(rel).join(', ')}`)
Expand Down
Loading