diff --git a/scripts/check-progression.sh b/scripts/check-progression.sh new file mode 100755 index 0000000..f04d929 --- /dev/null +++ b/scripts/check-progression.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Usage: scripts/check-progression.sh +# Progression checkpoint: for each module N (that has tests in the track), build a temp copy where src/ holds the +# reference solutions of modules <= N and the untouched student stubs for the rest, then run the tests of modules +# M01..MN. All must pass: this proves a student who has finished module N has a green suite up to N, and that +# no earlier solution secretly depends on a later one. +set -uo pipefail +track="${1:?usage: check-progression.sh }" +repo="$(cd "$(dirname "$0")/.." && pwd)" +export PATH="$HOME/.dotnet:$HOME/.local/bin:$PATH" + +# Module -> files (relative to src/ and solutions/) that the module introduces. A directory entry copies it whole. +# Later tasks: extend the entries for m07+ in the Scala and F# tables. +files_for() { + case "$track:$1" in + js:01) echo "util.js todo.js" ;; + js:02) echo "model.js" ;; + js:03) echo "rules.js" ;; + js:04) echo "random.js spawn.js" ;; + js:05) echo "game.js" ;; + js:06) echo "view.js" ;; + js:07) echo "io.js" ;; + js:08) echo "stream.js" ;; + js:09) echo "input.js app.js runtime.js browser.js main.js" ;; + js:10) echo "" ;; # edits game/input/app, already included by m05/m09 + js:11) echo "pong" ;; + scala:01) echo "Util.scala" ;; + scala:02) echo "Model.scala" ;; + scala:03) echo "Rules.scala" ;; + scala:04) echo "Random.scala Spawn.scala" ;; + scala:05) echo "Game.scala" ;; + scala:06) echo "View.scala" ;; + scala:07) echo "IO.scala" ;; + scala:08) echo "Stream.scala" ;; + scala:09) echo "Input.scala App.scala Runtime.scala" ;; + scala:10) echo "" ;; + scala:11) echo "pong" ;; + fsharp:*) echo "" ;; # added by the F# tasks + *) echo "" ;; + esac +} + +case "$track" in + js) has() { compgen -G "$repo/js/test/m$1-*.test.js" >/dev/null; } ;; + scala) has() { compgen -G "$repo/scala/test/M$1*.test.scala" >/dev/null; } ;; + fsharp) has() { compgen -G "$repo/fsharp/tests/M$1*.fs" >/dev/null; } ;; + *) echo "unknown track: $track" >&2; exit 2 ;; +esac + +status=0 +for n in 01 02 03 04 05 06 07 08 09 10 11; do + has "$n" || continue + tmp="$(mktemp -d)" + tar -C "$repo" --exclude=.git --exclude=node_modules --exclude=bin --exclude=obj \ + --exclude=.scala-build --exclude=.bsp --exclude=.superpowers -cf - . | tar -C "$tmp" -xf - + for m in 01 02 03 04 05 06 07 08 09 10 11; do + [ "$m" -le "$n" ] || break + for f in $(files_for "$m"); do + [ -e "$tmp/$track/solutions/$f" ] || continue # module not (yet) present in this track + rm -rf "$tmp/$track/src/$f" + cp -r "$tmp/$track/solutions/$f" "$tmp/$track/src/$f" + done + done + ok=1 + for m in 01 02 03 04 05 06 07 08 09 10 11; do + [ "$m" -le "$n" ] || break + has "$m" || continue + if ! out="$(cd "$tmp/$track" && ./test.sh "M$m" 2>&1)"; then + echo "checkpoint M$n: FAIL (M$m tests fail with solutions up to M$n)" + echo "$out" | tail -40 + ok=0; status=1; break + fi + done + [ $ok -eq 1 ] && echo "checkpoint M$n: ok (M01..M$n pass)" + rm -rf "$tmp" +done +exit $status