#!/usr/bin/env bash # Recomputes the coverage dashboard after a merge and commits what changed, as one commit # on the current branch. The one entry point for keeping the README's coverage table # current: bench/after-land.sh runs it in the primary checkout after every landing, so a # spec that edits docs/feature-map.json no longer has to run `npm run dashboard` and # commit its output. # # bench/dashboard-update.sh [--no-commit] # # Run from anywhere inside a checkout; it works on that checkout's root. Steps: # 1. refuse if docs/dashboard.json, docs/dashboard-history.json, # docs/dashboard-history.svg or README.md has uncommitted changes (they are this # script's to write) # 2. node oracle/suites/dashboard.mjs --check: when every file already matches a fresh # computation (the date alone is allowed to differ), print "unchanged" and exit 0 # with nothing written and nothing committed # 3. otherwise node oracle/suites/dashboard.mjs --render rewrites the four files # 4. commit exactly the files that changed ("dashboard: regenerate ..."), unless # --no-commit # # The computation is offline (browser-compat-data from oracle/node_modules and # docs/feature-map.json) and takes seconds, so it runs in place like # bench/web-features-update.sh. docs/feature-map.json is an input, never written here. # # Exit 0 when the dashboard is current afterwards (committed, or unchanged); 1 on any # failure, with the reason on stderr and the four files put back as they were, so a # failure never leaves the checkout dirty and never touches anything else. It never # merges, resets or pushes. Rules and format: docs/dashboard.md. set -euo pipefail NO_COMMIT=0 for arg in "$@"; do case "$arg" in --no-commit) NO_COMMIT=1 ;; *) echo "usage: bench/dashboard-update.sh [--no-commit]" >&2; exit 1 ;; esac done ROOT="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" cd "$ROOT" FILES=(docs/dashboard.json docs/dashboard-history.json docs/dashboard-history.svg README.md) if [ -n "$(git status --porcelain -- "${FILES[@]}")" ]; then echo "dashboard not updated: ${FILES[*]} has uncommitted changes" >&2 exit 1 fi DONE=0 restore() { local code=$? if [ "$DONE" = 0 ]; then git reset -q -- "${FILES[@]}" 2>/dev/null || true git checkout -q -- "${FILES[@]}" 2>/dev/null || true # A file the checkout did not track yet is removed rather than left behind. local f for f in "${FILES[@]}"; do git ls-files --error-unmatch "$f" >/dev/null 2>&1 || rm -f "$f" done fi exit "$code" } trap restore EXIT if node oracle/suites/dashboard.mjs --check >/dev/null 2>&1; then DONE=1 echo "dashboard unchanged" exit 0 fi if ! node oracle/suites/dashboard.mjs --render >&2; then echo "dashboard not updated: the generator failed" >&2 exit 1 fi CHANGED=() for f in "${FILES[@]}"; do if [ -n "$(git status --porcelain -- "$f")" ]; then CHANGED+=("$f"); fi done if [ "${#CHANGED[@]}" = 0 ]; then DONE=1 echo "dashboard unchanged" exit 0 fi if [ "$NO_COMMIT" = 1 ]; then DONE=1 echo "dashboard regenerated: ${CHANGED[*]} (not committed)" exit 0 fi AT="$(git rev-parse --short HEAD)" git add -- "${CHANGED[@]}" if ! git commit -q -m "dashboard: regenerate at $AT" -- "${CHANGED[@]}"; then echo "dashboard not updated: the commit failed" >&2 exit 1 fi DONE=1 echo "dashboard committed at $(git rev-parse --short HEAD): ${CHANGED[*]}"