1010# A .jsonnet file is only synced if it has a
1111# corresponding valid .golden file (upstream or already present locally), so that
1212# Scala tests always find a matching .jsonnet.golden for each .jsonnet file.
13+ #
14+ # Golden file sync strategy:
15+ # - Both success (JSON output): exact compare, update when different.
16+ # - Success<->error transition: always update (behavioral change).
17+ # - Both error: skip (sjsonnet and upstream have different error messages/formats).
18+ # - New golden files (no local copy): copied from upstream directly.
19+ #
1320# For new .jsonnet files that have no golden file after syncing,
1421# golden files are generated using sjsonnet via the per-suite refresh_golden.sh scripts.
1522#
@@ -26,21 +33,43 @@ set -euo pipefail
2633ROOT_DIR=" $( git rev-parse --show-toplevel) "
2734cd " $ROOT_DIR "
2835
36+ # Collect .jsonnet files whose golden files need regeneration via refresh_golden_outputs.sh
37+ GOLDEN_REFRESH_FILES=$( mktemp)
38+ trap_cleanup () { rm -rf " $TEMP_DIR " " $GOLDEN_REFRESH_FILES " ; }
39+
2940# --- Configuration ---
3041CPP_TEST_SUITE_DIR=" sjsonnet/test/resources/test_suite"
3142GO_TEST_SUITE_DIR=" sjsonnet/test/resources/go_test_suite"
3243
3344# --- Step 1: Clone upstream repositories into a temporary directory ---
3445echo " === Cloning upstream repositories ==="
3546TEMP_DIR=$( mktemp -d)
36- trap ' rm -rf "$TEMP_DIR"' EXIT
47+ trap ' rm -rf "$TEMP_DIR"; rm -f "$GOLDEN_REFRESH_FILES" ' EXIT
3748
3849echo " Cloning google/jsonnet (depth=1)..."
3950git clone --depth=1 --quiet https://github.com/google/jsonnet.git " $TEMP_DIR /jsonnet"
4051
4152echo " Cloning google/go-jsonnet (depth=1)..."
4253git clone --depth=1 --quiet https://github.com/google/go-jsonnet.git " $TEMP_DIR /go-jsonnet"
4354
55+ # --- Helper: Check if a golden file contains successful (non-error) output ---
56+ # Success tests output valid JSON: objects, arrays, strings, numbers, booleans, null.
57+ # Returns 0 (true) if the output looks like JSON success, 1 (false) if it looks like an error.
58+ is_success_golden () {
59+ local file=" $1 "
60+ local first_line
61+ first_line=$( head -1 " $file " )
62+ case " $first_line " in
63+ " {" * |" [" * |' "' * |" true" |" false" |" null" )
64+ return 0 ;;
65+ esac
66+ # Numbers (including negative, decimal, scientific notation)
67+ if [[ " $first_line " =~ ^-? [0-9] ]]; then
68+ return 0
69+ fi
70+ return 1
71+ }
72+
4473# --- Step 2: Sync .jsonnet and .golden files (excluding lint-related golden) ---
4574echo " "
4675echo " === Syncing test files ==="
@@ -62,7 +91,7 @@ sync_test_files() {
6291 ignore_stems_file=$( mktemp)
6392 if [ -f " $ignore_file " ]; then
6493 # Strip comments and blank lines, extract stems (remove .jsonnet extension)
65- grep -v ' ^\s*#' " $ignore_file " | grep -v ' ^\s*$' | sed ' s/\.jsonnet$//' > " $ignore_stems_file "
94+ { grep -v ' ^\s*#' " $ignore_file " | grep -v ' ^\s*$' | sed ' s/\.jsonnet$//' || true ; } > " $ignore_stems_file "
6695 local ignore_count
6796 ignore_count=$( wc -l < " $ignore_stems_file " | tr -d ' ' )
6897 echo " Syncing $suite_name ... ($ignore_count file(s) in .sync_ignore)"
@@ -182,8 +211,10 @@ sync_test_files() {
182211 done
183212
184213 # --- Phase 3: Sync golden files ---
185- # Never overwrite existing golden files — sjsonnet golden files use a different error
186- # format than upstream C++/Go implementations, so existing files must be preserved.
214+ # Golden files are synced based on error/success classification:
215+ # - Both non-error: exact compare, update when different.
216+ # - One error + one non-error (success<->error change): always update.
217+ # - Both error: skip (sjsonnet and upstream have different error messages/formats).
187218
188219 # 1) Sync *.jsonnet.golden files (already in correct naming format, skip directories)
189220 for src_file in " $source_dir " /* .jsonnet.golden; do
@@ -208,10 +239,29 @@ sync_test_files() {
208239
209240 local dest_file=" $target_dir /$basename "
210241
211- # Only copy new golden files, never overwrite existing ones
212242 if [ ! -e " $dest_file " ]; then
213243 cp -r " $src_file " " $dest_file "
214244 new_golden=$(( new_golden + 1 ))
245+ elif ! diff -q " $src_file " " $dest_file " > /dev/null 2>&1 ; then
246+ local src_ok=0 dest_ok=0
247+ is_success_golden " $src_file " && src_ok=1
248+ is_success_golden " $dest_file " && dest_ok=1
249+
250+ if [ " $src_ok " -eq 0 ] && [ " $dest_ok " -eq 0 ]; then
251+ # Both are error tests — keep sjsonnet's version (different error formats)
252+ true
253+ elif [ " $src_ok " -eq 1 ] && [ " $dest_ok " -eq 1 ]; then
254+ # Both success with different content — copy upstream golden
255+ cp -r " $src_file " " $dest_file "
256+ updated_golden=$(( updated_golden + 1 ))
257+ else
258+ # Success<->error transition — regenerate golden with sjsonnet
259+ local jsonnet_file=" $target_dir /${stem} .jsonnet"
260+ if [ -f " $jsonnet_file " ]; then
261+ echo " $jsonnet_file " >> " $GOLDEN_REFRESH_FILES "
262+ updated_golden=$(( updated_golden + 1 ))
263+ fi
264+ fi
215265 fi
216266 done
217267
@@ -248,10 +298,28 @@ sync_test_files() {
248298 if [ -f " $jsonnet_file " ]; then
249299 local dest_file=" $target_dir /${stem} .jsonnet.golden"
250300
251- # Only copy new golden files, never overwrite existing ones
252301 if [ ! -e " $dest_file " ]; then
253302 cp -r " $src_entry " " $dest_file "
254303 new_golden=$(( new_golden + 1 ))
304+ elif ! diff -q " $src_entry " " $dest_file " > /dev/null 2>&1 ; then
305+ local src_ok=0 dest_ok=0
306+ is_success_golden " $src_entry " && src_ok=1
307+ is_success_golden " $dest_file " && dest_ok=1
308+
309+ if [ " $src_ok " -eq 0 ] && [ " $dest_ok " -eq 0 ]; then
310+ true
311+ elif [ " $src_ok " -eq 1 ] && [ " $dest_ok " -eq 1 ]; then
312+ # Both success with different content — copy upstream golden
313+ cp -r " $src_entry " " $dest_file "
314+ updated_golden=$(( updated_golden + 1 ))
315+ else
316+ # Success<->error transition — regenerate golden with sjsonnet
317+ local local_jsonnet=" $target_dir /${stem} .jsonnet"
318+ if [ -f " $local_jsonnet " ]; then
319+ echo " $local_jsonnet " >> " $GOLDEN_REFRESH_FILES "
320+ updated_golden=$(( updated_golden + 1 ))
321+ fi
322+ fi
255323 fi
256324 fi
257325 done
@@ -326,6 +394,24 @@ generate_missing_golden() {
326394generate_missing_golden " $CPP_TEST_SUITE_DIR " " C++ test suite"
327395generate_missing_golden " $GO_TEST_SUITE_DIR " " Go test suite"
328396
397+ # --- Step 3b: Refresh golden files for success<->error transitions ---
398+ if [ -s " $GOLDEN_REFRESH_FILES " ]; then
399+ # Deduplicate
400+ sort -u " $GOLDEN_REFRESH_FILES " -o " $GOLDEN_REFRESH_FILES "
401+ local_refresh_count=$( wc -l < " $GOLDEN_REFRESH_FILES " | tr -d ' ' )
402+ echo " "
403+ echo " === Refreshing $local_refresh_count golden file(s) for success<->error transitions ==="
404+ REFRESH_SCRIPT=" $ROOT_DIR /sjsonnet/test/resources/refresh_golden_outputs.sh"
405+ if [ -x " $REFRESH_SCRIPT " ]; then
406+ # shellcheck disable=SC2046
407+ " $REFRESH_SCRIPT " $( cat " $GOLDEN_REFRESH_FILES " )
408+ else
409+ echo " WARNING: refresh_golden_outputs.sh not found or not executable at $REFRESH_SCRIPT "
410+ echo " Files needing refresh:"
411+ cat " $GOLDEN_REFRESH_FILES " | while read -r f; do echo " $f " ; done
412+ fi
413+ fi
414+
329415# --- Step 4: Final summary ---
330416echo " "
331417echo " === Sync complete ==="
0 commit comments