Skip to content

Verify Dependabot Coverage #365

Verify Dependabot Coverage

Verify Dependabot Coverage #365

name: Verify Dependabot Coverage
on:
pull_request:
paths:
- '.github/dependabot.yml'
- '.github/workflows/dependabot-verify.yml'
- 'package.json'
- 'packages/*/package.json'
push:
branches: [main]
paths:
- '.github/dependabot.yml'
- '.github/workflows/dependabot-verify.yml'
- 'package.json'
- 'packages/*/package.json'
schedule:
# Run weekly on Monday at 04:00 UTC (after Dependabot runs at 03:00)
- cron: '0 4 * * 1'
workflow_dispatch:
permissions:
contents: read
jobs:
verify-coverage:
name: Verify Package Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24.x'
- name: Verify all packages are covered
run: |
echo "🔍 Checking Dependabot configuration coverage..."
# Find all package.json files (excluding node_modules)
packages=$(find . -name "package.json" -not -path "*/node_modules/*" -type f)
# Read dependabot config
config_file=".github/dependabot.yml"
if [ ! -f "$config_file" ]; then
echo "❌ Dependabot configuration not found!"
exit 1
fi
echo "📦 Found package.json files:"
echo "$packages"
echo ""
# Extract directories from dependabot.yml
echo "📋 Dependabot monitored directories:"
grep -A 1 "package-ecosystem: 'npm'" "$config_file" | grep "directory:" | awk '{print $2}' | tr -d "'"
echo ""
# Check if root package.json has workspaces configured
has_workspaces=$(jq -r '.workspaces // empty' package.json 2>/dev/null)
root_npm_config=$(grep -A 1 "package-ecosystem: 'npm'" "$config_file" | grep "directory: '/'")
if [ -n "$has_workspaces" ] && [ -n "$root_npm_config" ]; then
echo "ℹ️ npm workspaces detected with root Dependabot config"
echo " Root configuration covers all workspace packages"
echo ""
# Extract all dependabot directories for checking
dependabot_dirs=$(grep -A 1 "package-ecosystem: 'npm'" "$config_file" | grep "directory:" | awk '{print $2}' | tr -d "'")
# Verify all packages are covered (either in workspace or have individual config)
coverage_ok=true
for pkg in $packages; do
pkg_dir=$(dirname "$pkg")
if [ "$pkg_dir" = "." ]; then
echo "✅ $pkg_dir is covered (root)"
else
pkg_dir=${pkg_dir#./}
# Check if package is in workspace
if echo "$has_workspaces" | jq -e --arg dir "$pkg_dir" 'any(. == $dir or . == ($dir | split("/")[0] + "/*"))' >/dev/null 2>&1; then
echo "✅ $pkg_dir is covered (workspace)"
# Check if package has individual dependabot config
elif echo "$dependabot_dirs" | grep -q "^/$pkg_dir$"; then
echo "✅ $pkg_dir is covered (individual config)"
else
echo "❌ $pkg_dir is NOT covered!"
coverage_ok=false
fi
fi
done
else
# No workspaces - check each package directory individually
echo "ℹ️ No npm workspaces detected - verifying individual package coverage"
echo ""
coverage_ok=true
for pkg in $packages; do
# Get directory relative to root
pkg_dir=$(dirname "$pkg")
# For root package.json, directory should be "/"
if [ "$pkg_dir" = "." ]; then
search_dir="directory: '/'"
else
# Remove leading ./ if present
pkg_dir=${pkg_dir#./}
search_dir="directory: '/$pkg_dir'"
fi
# Check if this directory is in dependabot.yml
if grep -q "$search_dir" "$config_file"; then
echo "✅ $pkg_dir is covered"
else
echo "❌ $pkg_dir is NOT covered by Dependabot!"
coverage_ok=false
fi
done
fi
echo ""
if [ "$coverage_ok" = true ]; then
echo "✅ All packages are covered by Dependabot configuration"
else
echo "❌ Some packages are missing from Dependabot configuration"
echo ""
echo "Please update .github/dependabot.yml to include all package directories"
exit 1
fi
- name: Validate dependabot.yml against schema
uses: marocchino/validate-dependabot@d8ae5c0d03dd75fbd0ad5f8ab4ba8101ebbd4b37 # v3
with:
path: .github/dependabot.yml
- name: Check for duplicate directories
run: |
echo "🔍 Checking for duplicate directory entries..."
config_file=".github/dependabot.yml"
# Extract all npm directories
directories=$(grep -A 1 "package-ecosystem: 'npm'" "$config_file" | grep "directory:" | awk '{print $2}' | sort)
# Check for duplicates
duplicates=$(echo "$directories" | uniq -d)
if [ -n "$duplicates" ]; then
echo "❌ Found duplicate directory entries:"
echo "$duplicates"
exit 1
else
echo "✅ No duplicate directory entries found"
fi
- name: Verify group configurations
run: |
echo "🔍 Verifying group configurations..."
config_file=".github/dependabot.yml"
# Check that groups are defined
if ! grep -q "groups:" "$config_file"; then
echo "⚠️ No groups defined in Dependabot configuration"
echo "Consider adding groups to reduce PR volume"
else
echo "✅ Groups are configured"
# Count number of groups
group_count=$(grep -c "^ [a-z-]*:" "$config_file" || echo "0")
echo "📊 Found $group_count group(s) configured"
fi
- name: Validate @types/node ignore matches Node.js engines
run: |
echo "🔍 Validating @types/node ignore configuration..."
# Extract minimum Node.js version from package.json
node_version=$(jq -r '.engines.node // empty' package.json | grep -oP '>=\K[0-9]+' || echo "")
if [ -z "$node_version" ]; then
echo "⚠️ No Node.js version constraint found in package.json engines"
exit 0
fi
echo "📦 Minimum Node.js version: $node_version"
# Calculate expected @types/node ignore version (node_version + 1)
expected_ignore_version=$((node_version + 1))
echo "🎯 Expected @types/node ignore: >=$expected_ignore_version"
# Check if @types/node ignore rule exists and matches
config_file=".github/dependabot.yml"
if ! grep -q "dependency-name: '@types/node'" "$config_file"; then
echo "⚠️ No @types/node ignore rule found in Dependabot config"
echo "💡 Consider pinning @types/node to v$node_version to prevent using APIs unavailable in Node.js $node_version"
exit 0
fi
# Extract the version from the ignore rule
# Looking for pattern like: versions: ['>=21']
actual_ignore=$(grep -A 3 "dependency-name: '@types/node'" "$config_file" | grep "versions:" | grep -oP '>=\K[0-9]+' || echo "")
if [ -z "$actual_ignore" ]; then
echo "❌ Could not parse @types/node ignore version from Dependabot config"
exit 1
fi
echo "📋 Actual @types/node ignore: >=$actual_ignore"
if [ "$actual_ignore" -eq "$expected_ignore_version" ]; then
echo "✅ @types/node ignore configuration matches Node.js engines (pinned to v$node_version types)"
else
echo "❌ @types/node ignore mismatch!"
echo ""
echo "Expected: >=$expected_ignore_version (to pin to @types/node v$node_version)"
echo "Actual: >=$actual_ignore"
echo ""
echo "Please update .github/dependabot.yml ignore rule to:"
echo " ignore:"
echo " - dependency-name: \"@types/node\""
echo " update-types: [\"version-update:semver-major\"]"
echo " versions: [\">=$expected_ignore_version\"]"
exit 1
fi
- name: Summary
if: success()
run: |
echo "🎉 Dependabot configuration verification completed successfully!"
echo ""
echo "Configuration summary:"
echo "- All package directories are covered"
echo "- Configuration conforms to Dependabot schema"
echo "- No duplicate entries"
echo "- Groups are properly configured"
echo "- @types/node pinned to minimum Node.js version"