From 66fb253228e2a133f5773812deee19b1d8e722ce Mon Sep 17 00:00:00 2001 From: Gunther Xing Date: Thu, 23 Jul 2026 19:46:14 +0800 Subject: [PATCH] fix(ci): use non-bash shell compatible command for pre-commit hooks --- scripts/ci/license-headers.sh | 6 +++-- scripts/ci/python-sdk-version-sync.sh | 10 +++++--- scripts/ci/sync-python-interpreter-version.sh | 25 +++++++++++++------ scripts/ci/sync-rustc-version.sh | 12 ++++++--- scripts/verify-crates-publish.sh | 7 ++++-- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/scripts/ci/license-headers.sh b/scripts/ci/license-headers.sh index 8a7fc531cf..0f61e12ead 100755 --- a/scripts/ci/license-headers.sh +++ b/scripts/ci/license-headers.sh @@ -194,14 +194,16 @@ find_duplicate_license_headers() { local path : > "$output_file" - mapfile -t LICENSE_EXCLUDES < <(load_license_excludes) + LICENSE_EXCLUDES=() + while IFS= read -r _hdr_tmp; do LICENSE_EXCLUDES+=("$_hdr_tmp"); done < <(load_license_excludes) while IFS= read -r -d '' path; do if is_license_excluded "$path"; then continue fi - if ! LC_ALL=C grep -Iq . "$path"; then + # short-circuit the symlink that may point to dir. + if [ ! -f "$path" ] || ! LC_ALL=C grep -Iq . "$path"; then continue fi diff --git a/scripts/ci/python-sdk-version-sync.sh b/scripts/ci/python-sdk-version-sync.sh index 3788573bc4..f71e7649be 100755 --- a/scripts/ci/python-sdk-version-sync.sh +++ b/scripts/ci/python-sdk-version-sync.sh @@ -139,9 +139,9 @@ compare_versions() { dev2="0" fi - # Compare base versions using sort -V + # Compare base versions using POSIX sort (X.Y.Z numeric per component). local sorted - sorted=$(printf '%s\n%s' "$base1" "$base2" | sort -V | head -1) + sorted=$(printf '%s\n%s' "$base1" "$base2" | sort -t. -k1,1n -k2,2n -k3,3n | head -1) if [ "$base1" != "$base2" ]; then if [ "$sorted" = "$base1" ]; then @@ -196,13 +196,15 @@ elif [ "$MODE" = "fix" ]; then # Cargo version is newer, update pyproject.toml NEW_PYPROJECT_VERSION="$CARGO_NORMALIZED" echo -e "${YELLOW}Cargo.toml has newer version, updating pyproject.toml...${NC}" - sed -i "s/^version = \"$PYPROJECT_VERSION\"/version = \"$NEW_PYPROJECT_VERSION\"/" "$PYPROJECT_TOML" + sed -i.bak "s/^version = \"$PYPROJECT_VERSION\"/version = \"$NEW_PYPROJECT_VERSION\"/" "$PYPROJECT_TOML" + rm -f "$PYPROJECT_TOML.bak" echo -e "${GREEN}✓ Updated $PYPROJECT_TOML: $PYPROJECT_VERSION -> $NEW_PYPROJECT_VERSION${NC}" elif [ "$COMPARISON" = "2" ]; then # pyproject version is newer, update Cargo.toml NEW_CARGO_VERSION=$(to_cargo_format "$PYPROJECT_NORMALIZED") echo -e "${YELLOW}pyproject.toml has newer version, updating Cargo.toml...${NC}" - sed -i "s/^version = \"$CARGO_VERSION\"/version = \"$NEW_CARGO_VERSION\"/" "$CARGO_TOML" + sed -i.bak "s/^version = \"$CARGO_VERSION\"/version = \"$NEW_CARGO_VERSION\"/" "$CARGO_TOML" + rm -f "$CARGO_TOML.bak" echo -e "${GREEN}✓ Updated $CARGO_TOML: $CARGO_VERSION -> $NEW_CARGO_VERSION${NC}" fi diff --git a/scripts/ci/sync-python-interpreter-version.sh b/scripts/ci/sync-python-interpreter-version.sh index bc6a2de293..b876644aec 100755 --- a/scripts/ci/sync-python-interpreter-version.sh +++ b/scripts/ci/sync-python-interpreter-version.sh @@ -122,7 +122,8 @@ ensure_line() { fi if [ "$MODE" = "fix" ]; then - sed -i -E "s|$current_pattern|$replacement|" "$file" + sed -i.bak -E "s|$current_pattern|$replacement|" "$file" + rm -f "$file.bak" FIXED_CHECKS=$((FIXED_CHECKS + 1)) echo -e "${GREEN}Fixed${NC} $file: $description" else @@ -149,7 +150,8 @@ ensure_classifiers() { return fi - mapfile -t versions < <(sed -nE 's/^ "Programming Language :: Python :: ([0-9]+\.[0-9]+)",$/\1/p' "$file") + versions=() + while IFS= read -r _py_ver_tmp; do versions+=("$_py_ver_tmp"); done < <(sed -nE 's/^ "Programming Language :: Python :: ([0-9]+\.[0-9]+)",$/\1/p' "$file") if [ "${#versions[@]}" -eq 0 ]; then echo -e "${RED}✗${NC} $file: could not find Python version classifiers" @@ -187,12 +189,18 @@ ensure_classifiers() { version_number=$((version_major * 100 + version_minor)) if [ "$version_number" -lt "$PYTHON_VERSION_NUMBER" ]; then - sed -i -E "/^ \"Programming Language :: Python :: ${version//./\\.}\",$/d" "$file" + sed -i.bak -E "/^ \"Programming Language :: Python :: ${version//./\\.}\",$/d" "$file" + rm -f "$file.bak" fi done if [ "$has_minimum" -eq 0 ]; then - sed -i -E "/^ \"Programming Language :: Python :: ${PYTHON_VERSION_MAJOR}\",$/a\\ \"Programming Language :: Python :: ${PYTHON_VERSION}\"," "$file" + awk -v major="$PYTHON_VERSION_MAJOR" -v version="$PYTHON_VERSION" ' + { print } + $0 == " \"Programming Language :: Python :: " major "\"," { + printf " \"Programming Language :: Python :: %s\",\n", version + } + ' "$file" > "$file.new" && mv "$file.new" "$file" fi FIXED_CHECKS=$((FIXED_CHECKS + 1)) @@ -244,7 +252,8 @@ ensure_lock_python_requirement() { fi if [ "$MODE" = "fix" ]; then - sed -i -E "1,${top_level_end}s|$current_pattern|$replacement|" "$file" + sed -i.bak -E "1,${top_level_end}s|$current_pattern|$replacement|" "$file" + rm -f "$file.bak" FIXED_CHECKS=$((FIXED_CHECKS + 1)) echo -e "${GREEN}Fixed${NC} $file: lock file Python requirement" else @@ -270,7 +279,8 @@ ensure_wheel_interpreters() { return fi - mapfile -t classifier_versions < <(sed -nE 's/^ "Programming Language :: Python :: ([0-9]+\.[0-9]+)",$/\1/p' "$SOURCE_FILE") + classifier_versions=() + while IFS= read -r _py_cls_tmp; do classifier_versions+=("$_py_cls_tmp"); done < <(sed -nE 's/^ "Programming Language :: Python :: ([0-9]+\.[0-9]+)",$/\1/p' "$SOURCE_FILE") if [ "${#classifier_versions[@]}" -eq 0 ]; then echo -e "${RED}✗${NC} $SOURCE_FILE: could not find Python version classifiers" @@ -303,7 +313,8 @@ ensure_wheel_interpreters() { fi if [ "$MODE" = "fix" ]; then - sed -i -E "s|(--interpreter ).*$|\\1${expected_interpreters}|" "$file" + sed -i.bak -E "s|(--interpreter ).*$|\\1${expected_interpreters}|" "$file" + rm -f "$file.bak" FIXED_CHECKS=$((FIXED_CHECKS + 1)) echo -e "${GREEN}Fixed${NC} $file: wheel interpreter versions" else diff --git a/scripts/ci/sync-rustc-version.sh b/scripts/ci/sync-rustc-version.sh index 1d25027f69..189c1b10f2 100755 --- a/scripts/ci/sync-rustc-version.sh +++ b/scripts/ci/sync-rustc-version.sh @@ -156,13 +156,17 @@ for dockerfile in $DOCKERFILES; do elif [ "$MODE" = "fix" ]; then if { [ -n "$SOURCE" ] && [ "$CURRENT_VERSION" != "$EXPECTED_VERSION" ]; } || [ "$RUST_IMAGE_MISMATCH" = "true" ]; then if [ -n "$SOURCE" ] && [ "$CURRENT_VERSION" != "$EXPECTED_VERSION" ] && [ "$SOURCE" = "arg" ]; then - sed -i "s/^ARG RUST_VERSION=.*/ARG RUST_VERSION=$EXPECTED_VERSION/" "$dockerfile" + sed -i.bak "s/^ARG RUST_VERSION=.*/ARG RUST_VERSION=$EXPECTED_VERSION/" "$dockerfile" + rm -f "$dockerfile.bak" elif [ -n "$SOURCE" ] && [ "$CURRENT_VERSION" != "$EXPECTED_VERSION" ]; then - sed -i -E "/FROM[[:space:]].*\\brust:[0-9]/ s#(\\brust:)[0-9]+\\.[0-9]+(\\.[0-9]+)?#\\1$EXPECTED_VERSION#g" "$dockerfile" + sed -i.bak -E "/FROM[[:space:]].*\\brust:[0-9]/ s#(\\brust:)[0-9]+\\.[0-9]+(\\.[0-9]+)?#\\1$EXPECTED_VERSION#g" "$dockerfile" + rm -f "$dockerfile.bak" fi if [ "$RUST_IMAGE_MISMATCH" = "true" ]; then - sed -i -E "/$RUST_IMAGE_PATTERN/ s#$RUST_IMAGE_TAG_PATTERN-[^[:space:]]+#\\1-$RUST_IMAGE_VARIANT#g" "$dockerfile" - sed -i -E "/$RUST_IMAGE_PATTERN/ { /-$RUST_IMAGE_VARIANT([[:space:]]|$)/! s#$RUST_IMAGE_TAG_PATTERN([[:space:]]|$)#\\1-$RUST_IMAGE_VARIANT\\2#g; }" "$dockerfile" + sed -i.bak -E "/$RUST_IMAGE_PATTERN/ s#$RUST_IMAGE_TAG_PATTERN-[^[:space:]]+#\\1-$RUST_IMAGE_VARIANT#g" "$dockerfile" + rm -f "$dockerfile.bak" + sed -i.bak -E "/$RUST_IMAGE_PATTERN/ { /-$RUST_IMAGE_VARIANT([[:space:]]|$)/! s#$RUST_IMAGE_TAG_PATTERN([[:space:]]|$)#\\1-$RUST_IMAGE_VARIANT\\2#g; }" "$dockerfile" + rm -f "$dockerfile.bak" fi FIXED_FILES=$((FIXED_FILES + 1)) MESSAGE="" diff --git a/scripts/verify-crates-publish.sh b/scripts/verify-crates-publish.sh index f78cce945f..7cb4a9204c 100755 --- a/scripts/verify-crates-publish.sh +++ b/scripts/verify-crates-publish.sh @@ -60,6 +60,7 @@ cp Cargo.toml "$CARGO_TOML_BACKUP" AUTO_INSTALL="${AUTO_INSTALL:-0}" # Ordered topologically: each crate depends only on the ones before it. +# MUST be lowercase (crates-index path is derived from the name directly). CRATES=( iggy_binary_protocol iggy_common @@ -84,6 +85,7 @@ cleanup() { if [[ "$CARGO_TOML_PATCHED" == "true" ]]; then log "Reverting Cargo.toml patch" cp "$CARGO_TOML_BACKUP" Cargo.toml + rm -f Cargo.toml.bak fi rm -f "$CARGO_TOML_BACKUP" @@ -254,12 +256,13 @@ log "Patching workspace.dependencies to target local-dev" CARGO_TOML_PATCHED=true # Injects `, registry = "local-dev"` before the closing brace of the line. # Match by crate name + path + version so we do not touch unrelated entries. -sed -i -E \ +sed -i.bak -E \ -e 's|^(iggy_binary_protocol = \{ path = "[^"]+", version = "[^"]+")( \})$|\1, registry = "local-dev"\2|' \ -e 's|^(iggy_common = \{ path = "[^"]+", version = "[^"]+")( \})$|\1, registry = "local-dev"\2|' \ -e 's|^(iggy = \{ path = "[^"]+", version = "[^"]+")( \})$|\1, registry = "local-dev"\2|' \ -e 's|^(iggy-cli = \{ path = "[^"]+", version = "[^"]+")( \})$|\1, registry = "local-dev"\2|' \ Cargo.toml +rm -f Cargo.toml.bak # Sanity check: all four lines must now carry the registry marker. This # catches formatting drift in Cargo.toml before it becomes a confusing @@ -310,7 +313,7 @@ log "Verifying all four crates appear in the local registry" # Every published iggy crate is >=4 chars, so the shorter-name buckets # (1/, 2/, 3//) from the full layout are intentionally not handled. for crate in "${CRATES[@]}"; do - lc="${crate,,}" + lc="$crate" # relies on CRATES entries being lowercase (see definition above) rel="${lc:0:2}/${lc:2:2}/$lc" if [[ ! -f "$REGISTRY_DIR/$rel" ]]; then err "Crate ${crate} missing from local registry (expected at $rel)"