Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 77 additions & 2 deletions scripts/check_release_versions.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#!/bin/bash
# Pre-release version check for SMG workspace crates.
# Pre-release version check for SMG workspace crates and PyPI proto package.
#
# For each workspace crate, verifies:
# 1. Whether there are code changes since the latest git tag
# 2. Whether the crate version was bumped in its own Cargo.toml
# 3. Whether the workspace root Cargo.toml reflects the new version
#
# For the smg-grpc-proto PyPI package, verifies:
# 4. Whether proto files changed since the latest git tag
# 5. Whether the PyPI version was bumped in __init__.py
#
# Detects bump level from conventional commits:
# - feat!: or BREAKING CHANGE → major
# - feat: → minor
Expand Down Expand Up @@ -290,6 +294,61 @@ for entry in "${CRATES[@]}"; do
fi
done

# ---------------------------------------------------------------------------
# Phase 1b: Check gRPC proto / PyPI package version
# ---------------------------------------------------------------------------
PROTO_DIR="grpc_client/proto"
PYPI_VERSION_FILE="grpc_client/python/smg_grpc_proto/__init__.py"
PYPI_NEEDS_BUMP=""

# Extract __version__ from __init__.py
get_pypi_version() {
local file="$1"
grep -m1 '__version__' "$file" | sed 's/.*"\(.*\)".*/\1/'
}

# Extract __version__ at a specific git ref
get_pypi_version_at_ref() {
local file="$1"
local ref="$2"
local content
content=$(git show "$ref:$file" 2>/dev/null) || return 0
echo "$content" | grep -m1 '__version__' | sed 's/.*"\(.*\)".*/\1/'
}

# Update __version__ in __init__.py
set_pypi_version() {
local file="$1"
local new_version="$2"
sed_inplace "s/__version__ = \".*\"/__version__ = \"${new_version}\"/" "$file"
if ! grep -q "__version__ = \"${new_version}\"" "$file"; then
echo -e " ${RED}FAILED to update $file${NC}" >&2
return 1
fi
}

echo ""
echo -e "${BOLD}Checking PyPI proto package:${NC}"

proto_diff_count=$(git diff --name-only "$TAG"..HEAD -- "$PROTO_DIR/" | wc -l | tr -d ' ')
if [[ "$proto_diff_count" -eq 0 ]]; then
echo -e " ${GREEN}✓${NC} ${BOLD}smg-grpc-proto${NC} ($PROTO_DIR/) — no proto changes"
else
pypi_current=$(get_pypi_version "$PYPI_VERSION_FILE")
pypi_tag=$(get_pypi_version_at_ref "$PYPI_VERSION_FILE" "$TAG")

if [[ -z "$pypi_tag" ]]; then
echo -e " ${GREEN}✓${NC} ${BOLD}smg-grpc-proto${NC} ($PROTO_DIR/) — new package (v$pypi_current), $proto_diff_count proto file(s) changed"
elif [[ "$pypi_current" == "$pypi_tag" ]]; then
level=$(detect_bump_level "$PROTO_DIR")
echo -e " ${YELLOW}!${NC} ${BOLD}smg-grpc-proto${NC} ($PROTO_DIR/) — $proto_diff_count proto file(s) changed but PyPI version not bumped (v$pypi_current) [$(bump_label "$level")]"
PYPI_NEEDS_BUMP="$pypi_current|$level"
issues=$((issues + 1))
else
echo -e " ${GREEN}✓${NC} ${BOLD}smg-grpc-proto${NC} ($PROTO_DIR/) — v$pypi_tag → v$pypi_current ($proto_diff_count proto file(s) changed)"
fi
fi

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
Expand All @@ -306,7 +365,7 @@ echo -e "${RED}${BOLD}$issues issue(s) found.${NC}"
# ---------------------------------------------------------------------------
# Phase 2: Offer to fix
# ---------------------------------------------------------------------------
total_fixes=$(( ${#NEEDS_BUMP[@]} + ${#NEEDS_WS_SYNC[@]} ))
total_fixes=$(( ${#NEEDS_BUMP[@]} + ${#NEEDS_WS_SYNC[@]} + (${#PYPI_NEEDS_BUMP} > 0 ? 1 : 0) ))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This line introduces a syntax error. While bash's arithmetic context ((...)) supports a C-style ternary operator, the extra parentheses around the ternary expression (${#PYPI_NEEDS_BUMP} > 0 ? 1 : 0) are invalid and will cause the script to fail.

A more idiomatic and robust way to accomplish this in bash is to leverage the fact that a true condition evaluates to 1 in an arithmetic context. This is more concise and avoids the less common ternary syntax.

Suggested change
total_fixes=$(( ${#NEEDS_BUMP[@]} + ${#NEEDS_WS_SYNC[@]} + (${#PYPI_NEEDS_BUMP} > 0 ? 1 : 0) ))
total_fixes=$(( ${#NEEDS_BUMP[@]} + ${#NEEDS_WS_SYNC[@]} + (${#PYPI_NEEDS_BUMP} > 0) ))

if [[ "$total_fixes" -eq 0 ]]; then
exit 1
fi
Expand All @@ -330,6 +389,12 @@ if [[ ${#NEEDS_WS_SYNC[@]} -gt 0 ]]; then
done
fi

if [[ -n "$PYPI_NEEDS_BUMP" ]]; then
IFS='|' read -r pypi_ver pypi_level <<< "$PYPI_NEEDS_BUMP"
pypi_new=$(bump_version "$pypi_ver" "$pypi_level")
echo -e " $(bump_label "$pypi_level") smg-grpc-proto v$pypi_ver → v$pypi_new ($PYPI_VERSION_FILE)"
fi

echo ""
read -rp "Apply fixes? [y/N] " answer
if [[ "$answer" != "y" && "$answer" != "Y" ]]; then
Expand Down Expand Up @@ -376,6 +441,16 @@ if [[ ${#NEEDS_WS_SYNC[@]} -gt 0 ]]; then
done
fi

if [[ -n "$PYPI_NEEDS_BUMP" ]]; then
IFS='|' read -r pypi_ver pypi_level <<< "$PYPI_NEEDS_BUMP"
pypi_new=$(bump_version "$pypi_ver" "$pypi_level")
if set_pypi_version "$PYPI_VERSION_FILE" "$pypi_new"; then
echo -e " ${GREEN}✓${NC} $PYPI_VERSION_FILE → v$pypi_new"
else
fix_failed=$((fix_failed + 1))
fi
fi
Comment on lines +444 to +452

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to parse PYPI_NEEDS_BUMP and calculate the new version (lines 445-446) is a duplicate of the logic in Phase 2 (lines 393-394). This code duplication can lead to maintenance issues, as any changes to the format of PYPI_NEEDS_BUMP would need to be updated in two separate places.

To improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle, you could calculate the new version once in Phase 2, store it in a variable, and reuse that variable here in Phase 3.

For example:

# Before Phase 2
pypi_new_version=""

# In Phase 2 (lines 392-396)
if [[ -n "$PYPI_NEEDS_BUMP" ]]; then
    IFS='|' read -r pypi_ver pypi_level <<< "$PYPI_NEEDS_BUMP"
    pypi_new_version=$(bump_version "$pypi_ver" "$pypi_level")
    echo -e "  $(bump_label "$pypi_level") smg-grpc-proto v$pypi_ver → v$pypi_new_version ($PYPI_VERSION_FILE)"
fi

# In Phase 3 (this block)
if [[ -n "$PYPI_NEEDS_BUMP" ]]; then
    if set_pypi_version "$PYPI_VERSION_FILE" "$pypi_new_version"; then
        echo -e "  ${GREEN}✓${NC} $PYPI_VERSION_FILE → v$pypi_new_version"
    else
        fix_failed=$((fix_failed + 1))
    fi
fi


echo ""
if [[ "$fix_failed" -gt 0 ]]; then
echo -e "${RED}${BOLD}$fix_failed fix(es) failed. Check output above.${NC}"
Expand Down
Loading