Skip to content

Confidence Badge

Confidence Badge #275

Workflow file for this run

name: Confidence Badge
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 8 * * *' # Daily at 8 AM UTC
workflow_dispatch:
# Serialize Confidence Badge runs per branch ref. cancel-in-progress: true
# cancels stale in-flight runs when a new push to main arrives, eliminating
# the bulk of non-fast-forward push races. The retry loop in the Commit
# badge step below catches the residual cooperative-cancellation window.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
dogfood:
name: Generate Confidence Badge
runs-on: ubuntu-latest
permissions:
contents: write
checks: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: '1.25'
- name: Build confvis
run: go build -o confvis ./cmd/confvis
- name: Install Trivy
run: |
curl -sfL --proto =https https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
- name: Install GitLeaks
run: |
curl -sSfL --proto =https https://github.com/gitleaks/gitleaks/releases/download/v8.18.4/gitleaks_8.18.4_linux_x64.tar.gz | tar -xz -C /usr/local/bin gitleaks
- name: Install Gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Fetch Codecov metrics
run: ./confvis fetch codecov -p boinger/confvis -o coverage.json
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
continue-on-error: true
- name: Fetch SonarCloud metrics
run: ./confvis fetch sonarqube -p boinger_confvis -o quality.json
env:
SONARQUBE_URL: https://sonarcloud.io
SONARQUBE_TOKEN: ${{ secrets.SONAR_TOKEN }}
continue-on-error: true
- name: Fetch CI metrics
run: ./confvis fetch github-actions -p boinger/confvis --workflow ci.yml --count 30 -o ci.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
- name: Fetch Trivy security metrics
run: ./confvis fetch trivy -p . -o security.json
continue-on-error: true
- name: Fetch GitLeaks metrics
run: ./confvis fetch gitleaks -p . -o gitleaks.json
continue-on-error: true
- name: Fetch Gosec metrics
run: ./confvis fetch gosec -p . -o gosec.json
continue-on-error: true
- name: Aggregate confidence (with available sources)
id: aggregate
run: |
# Build list of available config files
CONFIGS=""
if [ -f coverage.json ]; then CONFIGS="$CONFIGS -c coverage.json:25"; fi
if [ -f quality.json ]; then CONFIGS="$CONFIGS -c quality.json:25"; fi
if [ -f ci.json ]; then CONFIGS="$CONFIGS -c ci.json:15"; fi
if [ -f security.json ]; then CONFIGS="$CONFIGS -c security.json:15"; fi
if [ -f gitleaks.json ]; then CONFIGS="$CONFIGS -c gitleaks.json:10"; fi
if [ -f gosec.json ]; then CONFIGS="$CONFIGS -c gosec.json:10"; fi
if [ -z "$CONFIGS" ]; then
echo "No metric files available, skipping aggregation"
echo "has_metrics=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "has_metrics=true" >> "$GITHUB_OUTPUT"
# Generate badge, dashboard, and aggregate JSON
./confvis aggregate $CONFIGS -o ./badges --badge-type flat --icon "M7 1 A6 6 0 1 1 4 1.8 L7 7 Z" --label confvis --emit-json badges/confidence.json
- name: Generate sparkline badge
if: steps.aggregate.outputs.has_metrics == 'true'
run: |
# Generate sparkline showing score trend over time
# Uses --history-auto to store history in git refs
./confvis gauge -c badges/confidence.json -o badges/sparkline.svg --badge-type sparkline --history-auto
continue-on-error: true
- name: Compare against baseline (PRs only)
if: steps.aggregate.outputs.has_metrics == 'true' && github.event_name == 'pull_request'
run: |
# Compare current score against stored baseline
# Fail if score regressed
./confvis gauge -c badges/confidence.json -o - -f text --compare-baseline --fail-on-regression
continue-on-error: true
- name: Save baseline (main only)
if: steps.aggregate.outputs.has_metrics == 'true' && github.ref == 'refs/heads/main'
run: ./confvis baseline save -c badges/confidence.json
- name: Create GitHub Check
if: steps.aggregate.outputs.has_metrics == 'true'
run: ./confvis check github -c badges/confidence.json --name "Confidence Score"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit badge
if: github.ref == 'refs/heads/main'
# Replaces stefanzweifel/git-auto-commit-action with a retry loop that
# handles the cooperative-cancellation residual race: if a stale run
# lands its push during the cancellation window, ours fails with
# non-fast-forward; we re-fetch, rewrite the commit on the new main
# HEAD, and try again.
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if [[ -z "$(git status --porcelain badges/)" ]]; then
echo "No badge changes to commit."
exit 0
fi
for attempt in 1 2 3; do
git fetch origin main
git reset --soft origin/main
git add badges/
# If --soft brought us to a tree that already matches, nothing to commit.
if git diff --cached --quiet; then
echo "Badges already up to date on origin/main (attempt $attempt)."
exit 0
fi
git commit -m "chore: update confidence badge [skip ci]"
if git push origin HEAD:main; then
echo "Push succeeded on attempt $attempt."
exit 0
fi
echo "Push attempt $attempt rejected; re-fetching and retrying."
# Jitter to avoid livelock if another run is also in retry.
sleep $((2 + RANDOM % 3))
done
echo "All push attempts exhausted." >&2
exit 1