Repository navigation
ci(dependabot): target dev for all update ecosystems - #14
singlerider wants to merge 2 commits into
Conversation
Without target-branch, Dependabot opens every update against the default branch, so bumps land on the release branch instead of dev and have to be closed by hand. Dependabot only reads this file from the default branch, so the fix has to land there to take effect.
en0f
left a comment
There was a problem hiding this comment.
Reviewed at 6cacec4.
🔴 Targets stable instead of dev
This PR goes from a feature branch straight into stable. The README (How changes land) says stable takes a pull request from dev, the org CONTRIBUTING says to open pull requests against dev, and every PR merged into stable so far (#3, #6, #8, #12) came from dev. You're right that Dependabot only reads dependabot.yml from the default branch, but that just means the line takes effect with the next release. Retarget with gh pr edit 14 --base dev. The diff will also show merge commit 1213919 from stable, which carries no content.
🔴 Validation doesn't show Dependabot opening a PR against dev
The validation shows the file parses, not that Dependabot opens its update PRs against dev, which is the point of the change. git.md (Pull requests) asks for the commands run and their real output. On your fork, enable Dependabot version updates with this dependabot.yml on the fork's default branch, and paste the PR it opens with base dev, for example gh pr list --repo <fork> --author app/dependabot --json number,baseRefName.
Reproduce this review
# save the script below as verify-14.sh, then:
bash verify-14.sh blacklanternsecurity/release-workflows 6cacec4276ec2999f379292ac3e70bf36a4122c2
# expected: SUMMARY 4 PASS, 2 FAIL, 0 SKIP, 0 BROKEN
# control: bash verify-14.sh blacklanternsecurity/release-workflows 12139195c6f35d8b4478bb8ec3df94aa275da01e -> V01=FAIL#!/usr/bin/env bash
# verify-14.sh: reproducible checks for blacklanternsecurity/release-workflows#14
# Usage: bash verify-14.sh <owner/repo> <sha> [<control-patch>]
# Changes nothing outside a mktemp directory and nothing on GitHub (PR-VF-02).
# V03-V06 read GitHub state through gh api --method GET; rerun them after the PR changes.
#
# CONTROL: sha 12139195c6f35d8b4478bb8ec3df94aa275da01e
# CONTROL-EXPECT: V01=FAIL
set -uo pipefail
REPO="${1:?owner/repo}"; SHA="${2:?sha}"; PATCH="${3:-}"
PR=14
PASS=0; FAIL=0; SKIP=0; BROKEN=0
pass() { echo "PASS $1 $2"; PASS=$((PASS+1)); }
fail() { echo "FAIL $1 $2 -- $3"; FAIL=$((FAIL+1)); }
skip() { echo "SKIP $1 $2 -- $3"; SKIP=$((SKIP+1)); }
broken() { echo "BROKEN $1 $2 -- $3"; BROKEN=$((BROKEN+1)); }
summary() { echo "SUMMARY $PASS PASS, $FAIL FAIL, $SKIP SKIP, $BROKEN BROKEN"; [ "$FAIL" -eq 0 ] && [ "$BROKEN" -eq 0 ]; }
echo "script_sha256 $(shasum -a 256 "$0" | cut -d' ' -f1)"
echo "git $(git --version | cut -d' ' -f3)"
echo "gh $(gh --version | head -1 | cut -d' ' -f3)"
echo "jq $(jq --version)"
WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_TERMINAL_PROMPT=0
GIT=(git -c credential.helper= -c 'credential.helper=!gh auth git-credential')
"${GIT[@]}" clone --quiet --filter=blob:none --no-checkout "https://github.com/$REPO.git" "$WORK/src" || { broken V00 "clone" "clone failed"; summary; exit 1; }
cd "$WORK/src"
"${GIT[@]}" cat-file -e "$SHA^{commit}" 2>/dev/null || "${GIT[@]}" fetch --quiet origin "+refs/pull/*/head:refs/remotes/pr/*" || true
"${GIT[@]}" checkout --quiet --detach "$SHA" || { broken V00 "checkout $SHA" "checkout failed"; summary; exit 1; }
[ "$(git rev-parse HEAD)" = "$SHA" ] || { broken V00 "HEAD is $SHA" "HEAD mismatch"; summary; exit 1; }
if [ -n "$PATCH" ]; then git apply "$PATCH" || { broken V00 "apply control patch" "git apply failed"; summary; exit 1; }; fi
GET() { gh api --method GET "$@"; }
# ---- checks: each line states the desired property --------------------------
# V01: every Dependabot update entry targets dev.
F=.github/dependabot.yml
if [ ! -f "$F" ]; then broken V01 "every dependabot update entry sets target-branch: dev" "$F missing"
else
ECO=$(grep -cE '^[[:space:]]*-[[:space:]]+package-ecosystem:' "$F")
TGT=$(grep -cE '^[[:space:]]+target-branch:[[:space:]]*"?dev"?[[:space:]]*$' "$F")
if [ "$ECO" -gt 0 ] && [ "$ECO" -eq "$TGT" ]; then pass V01 "every dependabot update entry sets target-branch: dev ($TGT/$ECO)"
else fail V01 "every dependabot update entry sets target-branch: dev" "$TGT of $ECO entries"; fi
fi
# V02: the branch Dependabot is pointed at exists.
if GET "repos/$REPO/branches/dev" --jq .name >/dev/null 2>&1; then pass V02 "branch dev exists"
else fail V02 "branch dev exists" "GET branches/dev failed"; fi
# V03: the PR targets dev (README.md, How changes land: stable takes pull requests from dev).
BASE_REF=$(GET "repos/$REPO/pulls/$PR" --jq .base.ref 2>/dev/null) || BASE_REF=""
if [ -z "$BASE_REF" ]; then broken V03 "PR #$PR targets dev" "could not read the PR"
elif [ "$BASE_REF" = dev ]; then pass V03 "PR #$PR targets dev"
else fail V03 "PR #$PR targets dev" "base is $BASE_REF"; fi
# V04: every merged pull request into stable came from dev (the precedent the README rule describes).
OTHER=$(GET "repos/$REPO/pulls?state=closed&base=stable&per_page=100" --jq '[.[]|select(.merged_at!=null and .head.ref!="dev")|.number]|length' 2>/dev/null) || OTHER=""
if [ -z "$OTHER" ]; then broken V04 "every merged PR into stable came from dev" "could not list PRs"
elif [ "$OTHER" -eq 0 ]; then pass V04 "every merged PR into stable came from dev"
else fail V04 "every merged PR into stable came from dev" "$OTHER did not"; fi
# V05: Dependabot has opened at least one pull request in this repository (the outcome the PR configures).
DB=$(GET "repos/$REPO/pulls?state=all&per_page=100" --jq '[.[]|select(.user.login=="dependabot[bot]")]|length' 2>/dev/null) || DB=""
if [ -z "$DB" ]; then broken V05 "dependabot has opened a PR in $REPO" "could not list PRs"
elif [ "$DB" -gt 0 ]; then pass V05 "dependabot has opened a PR in $REPO ($DB)"
else fail V05 "dependabot has opened a PR in $REPO" "0 PRs by dependabot[bot], although its run of 2026-11-04 (actions run 41886869590) logged 'Creating a pull request for github-actions'"; fi
# V06: a merge to stable at this version publishes nothing (v<version> already tagged, release-check.yml sets release=false).
VER=$(sed -nE 's/^version = "([^"]+)"/\1/p' pyproject.toml | head -1)
if [ -z "$VER" ]; then broken V06 "v<version> already tagged" "no version in pyproject.toml"
elif GET "repos/$REPO/git/ref/tags/v$VER" --jq .ref >/dev/null 2>&1; then pass V06 "v$VER already tagged, so a merge to stable publishes nothing"
else fail V06 "v$VER already tagged" "tag v$VER not found"; fi
# ------------------------------------------------------------------------------
summary
Without
target-branch, Dependabot opens every update against the default branch, so bumps land on the release branch instead ofdevand get closed by hand.Dependabot only reads
dependabot.ymlfrom the default branch, so this targets it directly.Related (closed, opened against the default branch): none yet; preventive, matching the org pattern
Validated:
python -c "import yaml; yaml.safe_load(open('.github/dependabot.yml'))"parses cleanly.