From 7f11c701d07517af2c2a2a260a1ad0080d81b031 Mon Sep 17 00:00:00 2001 From: David First Date: Wed, 10 Jun 2026 08:32:09 -0400 Subject: [PATCH 1/3] ci(env-cache): fail fast, add --fix, fix e2e-only hook regex --- .circleci/config.yml | 11 +++--- .claude/hooks/check-e2e-only.sh | 2 +- scripts/check-env-cache-sync.sh | 66 +++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 239b325443f2..b28dc7b021e6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -640,11 +640,12 @@ jobs: check_env_cache_sync: <<: *defaults steps: - - attach_workspace: - at: ./ + # Only needs .bitmap and .circleci/config.yml from a plain checkout, so it + # runs (and fails) in seconds without waiting for setup_harmony. + - checkout - run: name: 'check env cache synchronization' - command: 'cd bit && ./scripts/check-env-cache-sync.sh' + command: './scripts/check-env-cache-sync.sh' generate_and_check_types: <<: *defaults @@ -1252,9 +1253,7 @@ workflows: - check_circular_dependencies: requires: - setup_harmony - - check_env_cache_sync: - requires: - - setup_harmony + - check_env_cache_sync - generate_and_check_types: requires: - setup_harmony diff --git a/.claude/hooks/check-e2e-only.sh b/.claude/hooks/check-e2e-only.sh index ce622ae6ea38..be2f6c067397 100755 --- a/.claude/hooks/check-e2e-only.sh +++ b/.claude/hooks/check-e2e-only.sh @@ -42,7 +42,7 @@ fi # 1. Tracked changes (staged + unstaged) via `git diff HEAD`. # 2. Untracked new files (e.g. a bug-repro test Claude just created but # hasn't `git add`'d yet) via `git ls-files --others --exclude-standard`. -if git diff HEAD -- 'e2e/' 2>/dev/null | grep -qE '^\+[^+].*(describe|context|it)\.only\b'; then +if git diff HEAD -- 'e2e/' 2>/dev/null | grep -qE '^\+.*\b(describe|context|it)\.only\b'; then exit 0 fi UNTRACKED=$(git ls-files --others --exclude-standard -- 'e2e/' 2>/dev/null) diff --git a/scripts/check-env-cache-sync.sh b/scripts/check-env-cache-sync.sh index 08596019180a..277ab87c024e 100755 --- a/scripts/check-env-cache-sync.sh +++ b/scripts/check-env-cache-sync.sh @@ -1,7 +1,12 @@ #!/bin/bash # This script validates that env versions in .bitmap match cache keys in .circleci/config.yml -# It prevents stale caches when env versions are upgraded +# It prevents stale caches when env versions are upgraded. +# +# Usage: +# ./scripts/check-env-cache-sync.sh # validate (used by CI); exits 1 on mismatch +# ./scripts/check-env-cache-sync.sh --fix # rewrite the cache keys to match .bitmap, +# # preserving each key's -v cache-bust suffix set -e @@ -10,9 +15,20 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color +FIX=false +if [ "${1:-}" = "--fix" ]; then + FIX=true +fi + +CONFIG_FILE=".circleci/config.yml" + echo "Checking env cache synchronization..." -# Extract core-aspect-env version from .bitmap +# Extract core-aspect-env version from .bitmap. `bit env update` writes a config +# entry for every affected component, e.g.: +# "teambit.harmony/envs/core-aspect-env@0.1.6": {} +# These entries are only present while an env change is in flight; on a normal +# branch .bitmap has none and we skip (nothing to validate). CORE_ASPECT_ENV_VERSION=$(grep -o 'teambit.harmony/envs/core-aspect-env@[0-9.]*' .bitmap | head -1 | sed 's/.*@//') if [ -z "$CORE_ASPECT_ENV_VERSION" ]; then @@ -22,22 +38,42 @@ fi echo "Found core-aspect-env version in .bitmap: $CORE_ASPECT_ENV_VERSION" -# Check if this version exists in .circleci/config.yml cache keys -# Pattern: core-aspect-env-v{VERSION}-v{ANY_NUMBER} +# Cache keys look like: core-aspect-env-v{VERSION}-v{BUMP} +# {VERSION} must match .bitmap; {BUMP} is a manual cache-bust counter we preserve. CACHE_KEY_PATTERN="core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v[0-9]+" -if grep -E "$CACHE_KEY_PATTERN" .circleci/config.yml > /dev/null; then - FOUND_KEY=$(grep -oE "core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v[0-9]+" .circleci/config.yml | head -1) +if grep -qE "$CACHE_KEY_PATTERN" "$CONFIG_FILE"; then + FOUND_KEY=$(grep -oE "core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v[0-9]+" "$CONFIG_FILE" | head -1) echo -e "${GREEN}✓ Cache key matches: $FOUND_KEY${NC}" exit 0 -else - echo -e "${RED}✗ ERROR: Cache key mismatch!${NC}" - echo -e "${YELLOW}Expected cache key pattern: core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v*${NC}" - echo "" - echo "Current cache keys in .circleci/config.yml:" - grep -oE 'core-aspect-env-v[0-9.]+-v[0-9]+' .circleci/config.yml | sort -u - echo "" - echo -e "${RED}When upgrading envs, you must update the cache keys in .circleci/config.yml${NC}" - echo "Please update all instances of 'core-aspect-env-v*' to match the version in .bitmap" +fi + +# Mismatch: the cache keys point at a different env version than .bitmap. +EXISTING_KEYS=$(grep -oE 'core-aspect-env-v[0-9.]+-v[0-9]+' "$CONFIG_FILE" | sort -u) + +if [ "$FIX" = true ]; then + # Rewrite only the version segment, keeping each key's -v{BUMP} suffix intact, + # so the manual cache-bust counter can never be dropped by accident. + TMP=$(mktemp) + sed -E "s/core-aspect-env-v[0-9.]+-v([0-9]+)/core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v\1/g" "$CONFIG_FILE" > "$TMP" + mv "$TMP" "$CONFIG_FILE" + + if grep -qE "$CACHE_KEY_PATTERN" "$CONFIG_FILE"; then + NEW_KEYS=$(grep -oE 'core-aspect-env-v[0-9.]+-v[0-9]+' "$CONFIG_FILE" | sort -u) + echo -e "${GREEN}✓ Updated cache keys in ${CONFIG_FILE}${NC}" + echo " from: $(echo "$EXISTING_KEYS" | tr '\n' ' ')" + echo " to: $(echo "$NEW_KEYS" | tr '\n' ' ')" + exit 0 + fi + + echo -e "${RED}✗ --fix found no 'core-aspect-env-v*-v*' cache keys to update in ${CONFIG_FILE}${NC}" exit 1 fi + +echo -e "${RED}✗ ERROR: Cache key mismatch!${NC}" +echo -e "${YELLOW}.bitmap has core-aspect-env@${CORE_ASPECT_ENV_VERSION}, but ${CONFIG_FILE} has:${NC}" +echo "$EXISTING_KEYS" | sed 's/^/ /' +echo "" +echo -e "${YELLOW}Run: ./scripts/check-env-cache-sync.sh --fix${NC}" +echo " (rewrites the keys to core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v, keeping the existing -v cache-bust suffix)" +exit 1 From 4e1ceee36b9c9f54770f55b94cfea6fc30e5f27a Mon Sep 17 00:00:00 2001 From: David First Date: Wed, 10 Jun 2026 09:08:38 -0400 Subject: [PATCH 2/3] fix(hook): exclude +++ diff headers from e2e .only guard --- .claude/hooks/check-e2e-only.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/hooks/check-e2e-only.sh b/.claude/hooks/check-e2e-only.sh index be2f6c067397..3bc582b9dc3b 100755 --- a/.claude/hooks/check-e2e-only.sh +++ b/.claude/hooks/check-e2e-only.sh @@ -42,7 +42,7 @@ fi # 1. Tracked changes (staged + unstaged) via `git diff HEAD`. # 2. Untracked new files (e.g. a bug-repro test Claude just created but # hasn't `git add`'d yet) via `git ls-files --others --exclude-standard`. -if git diff HEAD -- 'e2e/' 2>/dev/null | grep -qE '^\+.*\b(describe|context|it)\.only\b'; then +if git diff HEAD -- 'e2e/' 2>/dev/null | grep -vE '^\+\+\+ ' | grep -qE '^\+.*\b(describe|context|it)\.only\b'; then exit 0 fi UNTRACKED=$(git ls-files --others --exclude-standard -- 'e2e/' 2>/dev/null) From 37df7025bccfc45f00a874ce0c61d139b8c637fc Mon Sep 17 00:00:00 2001 From: David First Date: Wed, 10 Jun 2026 09:31:19 -0400 Subject: [PATCH 3/3] fix(script): use same-dir templated mktemp for atomic --fix rewrite --- scripts/check-env-cache-sync.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/check-env-cache-sync.sh b/scripts/check-env-cache-sync.sh index 277ab87c024e..058fd64fe27d 100755 --- a/scripts/check-env-cache-sync.sh +++ b/scripts/check-env-cache-sync.sh @@ -54,7 +54,10 @@ EXISTING_KEYS=$(grep -oE 'core-aspect-env-v[0-9.]+-v[0-9]+' "$CONFIG_FILE" | sor if [ "$FIX" = true ]; then # Rewrite only the version segment, keeping each key's -v{BUMP} suffix intact, # so the manual cache-bust counter can never be dropped by accident. - TMP=$(mktemp) + # Create the temp file next to the target (explicit template for BSD/macOS + # portability) so the final mv is an atomic same-filesystem rename. + TMP=$(mktemp "${CONFIG_FILE}.XXXXXX") + trap 'rm -f "$TMP"' EXIT sed -E "s/core-aspect-env-v[0-9.]+-v([0-9]+)/core-aspect-env-v${CORE_ASPECT_ENV_VERSION}-v\1/g" "$CONFIG_FILE" > "$TMP" mv "$TMP" "$CONFIG_FILE"