#!/usr/bin/env bash # e2e-needed: does a diff touch anything the Windows e2e binaries are built from? # e2e-needed [--range | --since REV] [--to REV] [--closure] (run in a jj workspace root) # The Windows e2e runs komorebi.exe, komorebic.exe and komorebi-testwin.exe (windows-komorebi-testwin-e2e in flake.nix). Their # inputs are (a) the source directories of the workspace crates they depend on, from `cargo tree # --target x86_64-pc-windows-msvc -e normal,build` (dev-dependencies are not in the binaries), # (b) files pulled in with include_str!/include_bytes!/include! from those crates, (c) fixed # inputs: Cargo.lock, the root Cargo.toml, rust-toolchain.toml, flake.nix, flake.lock, build # scripts, and the e2e harness itself (e2e/). Anything else cannot change those binaries. # Verdict NO means: every touched file is outside all of that, so a passing e2e of the previous # binaries carries over unchanged. Verdict YES prints which files decided it. Files that are not # understood count as YES. Uses `cargo tree --offline` (about 1-2 s, no build). Never writes. # NOT covered by this verdict: the other gates (nextest, clippy, the bar screenshot, KDE VM, schema oracles). # shellcheck disable=SC2001 # the sed one-liners indent multi-line output set -uo pipefail FROM=""; TO="@"; SHOWCL=0 while [ $# -gt 0 ]; do case "$1" in --range) FROM='trunk()' ;; --since) shift; FROM="${1:?--since needs a revset}" ;; --to) shift; TO="${1:?--to needs a revset}" ;; --closure) SHOWCL=1 ;; -h|--help) sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "usage: e2e-needed [--range | --since REV] [--to REV] [--closure]" >&2; exit 2 ;; esac shift done ROOT="$(jj root 2>/dev/null)" || { echo "e2e-needed: not in a jj workspace" >&2; exit 2; } cd "$ROOT" || exit 2 if [ -n "$FROM" ]; then FILES="$(jj diff --name-only --from "$FROM" --to "$TO")"; else FILES="$(jj diff --name-only -r "$TO")"; fi [ -n "$FILES" ] || { echo "NO (nothing changed in @; use --since REV)"; exit 0; } # (a) closure: workspace crate directories (relative to root) CL="" for p in komorebi komorebi-windows komorebic komorebi-testwin; do CL+="$(CARGO_BUILD_JOBS=1 nice -n 19 cargo tree --offline --locked -p "$p" --target x86_64-pc-windows-msvc \ --prefix none -e normal,build 2>/dev/null | grep -o "(${ROOT}[^)]*)" | tr -d '()' | sed "s#^${ROOT}/\{0,1\}##")"$'\n' done CL="$(echo "$CL" | sed '/^$/d' | sort -u)" [ -n "$CL" ] || { echo "YES (could not compute the dependency closure: cargo tree failed; treating as needed)"; exit 0; } [ $SHOWCL = 1 ] && { echo "closure directories:"; echo "$CL" | sed 's/^/ /'; } # (b) include!-ed files, resolved against the including file INC="" while IFS= read -r d; do [ -d "$d" ] || continue while IFS=: read -r f _ rest; do rel="$(grep -o 'include[a-z_]*!("[^"]*")' <<<"$rest" | sed 's/.*("\(.*\)")/\1/')" for r in $rel; do case "$r" in /*) continue ;; esac INC+="$(realpath -m --relative-to="$ROOT" "$(dirname "$f")/$r")"$'\n' done done < <(grep -rn 'include[a-z_]*!(' "$d" --include='*.rs' 2>/dev/null) done <<<"$CL" INC="$(echo "$INC" | sed '/^$/d' | sort -u)" [ $SHOWCL = 1 ] && { echo "include-d files:"; echo "$INC" | sed 's/^/ /'; } yes=(); while IFS= read -r f; do [ -n "$f" ] || continue reason="" case "$f" in Cargo.lock|Cargo.toml|rust-toolchain.toml|flake.nix|flake.lock|nix/windows/*|nix/workspace-src.nix|nix/lib.nix|nix/common.nix) reason="fixed input" ;; e2e/*|crates/komorebi-e2e-agent/*) reason="e2e harness / guest" ;; */build.rs) reason="build script" ;; crates/komorebi-linux/*|crates/komorebi-hotkeys/*|crates/komorebi-macos/*|nix/linux/*|nix/macos/*|scripts/linux/*|schemas/linux/*|schemas/macos/*) ;; # the other platforms, not in the Windows closure *.md|docs/*|tools/*|.github/*) ;; # docs and dev tools (include!-ed docs are caught below) esac if [ -z "$reason" ]; then while IFS= read -r d; do case "$f" in "$d"/*) reason="in closure crate $d"; break ;; esac done <<<"$CL" fi if [ -z "$reason" ]; then while IFS= read -r i; do [ -n "$i" ] || continue case "$f" in "$i"|"$i"/*) reason="include-d by a closure crate"; break ;; esac done <<<"$INC" fi if [ -z "$reason" ]; then case "$f" in crates/komorebi-linux/*|crates/komorebi-hotkeys/*|crates/komorebi-macos/*|nix/linux/*|nix/macos/*|scripts/linux/*|schemas/linux/*|schemas/macos/*|*.md|docs/*|tools/*|.github/*) ;; komorebi-bar/*|komorebi-gui/*|komorebi-shortcuts/*|komorebic-no-console/*|crates/komorebi-bar-core/*|schemas/windows/*|schema*.json|komorebic.lib.ahk|wix/*|justfile|mkdocs.yml|deny.toml|rustfmt.toml|*.json) # known Windows-tree paths outside the closure (crates not in the closure were checked above) case "$f" in */*.json|*.json) [ "$f" = dependencies.json ] || [ "${f#schema}" != "$f" ] || reason="json file outside known oracle files: treated as needed" ;; esac ;; *) reason="not understood: treated as needed" ;; esac fi [ -n "$reason" ] && yes+=("$f ($reason)") done <<<"$FILES" if [ ${#yes[@]} -eq 0 ]; then echo "NO: none of $(echo "$FILES" | wc -l) touched files is an input of komorebi.exe, komorebic.exe or komorebi-testwin.exe" else echo "YES: ${#yes[@]} touched file(s) are inputs of the e2e binaries or the harness:" printf ' %s\n' "${yes[@]}" | head -15 [ ${#yes[@]} -gt 15 ] && echo " ... and $(( ${#yes[@]} - 15 )) more" fi