-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy.sh
More file actions
executable file
·150 lines (134 loc) · 6.13 KB
/
deploy.sh
File metadata and controls
executable file
·150 lines (134 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
# ── Usage ─────────────────────────────────────────────────────────
usage() {
echo "Usage: $0 [patch|minor|major|<version>] [-m <description>]"
echo ""
echo " patch bump patch version (default)"
echo " minor bump minor version"
echo " major bump major version"
echo " <x.y.z> set custom version"
echo " -m <description> release description (default: 'release vX.Y.Z')"
echo ""
echo "Examples:"
echo " $0 # interactive mode"
echo " $0 patch # auto patch bump"
echo " $0 minor -m 'new feature'"
exit 0
}
[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && usage
# ── Get current version ────────────────────────────────────────────
CURRENT=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
MINOR=$(echo "$CURRENT" | cut -d. -f2)
PATCH=$(echo "$CURRENT" | cut -d. -f3)
# ── Auto-increment options ─────────────────────────────────────────
NEXT_PATCH="$MAJOR.$MINOR.$((PATCH + 1))"
NEXT_MINOR="$MAJOR.$((MINOR + 1)).0"
NEXT_MAJOR="$((MAJOR + 1)).0.0"
# ── Parse args or prompt interactively ─────────────────────────────
BUMP="${1:-}"
DESCRIPTION=""
# Parse -m flag (can be $2/$3 or $1/$2)
shift_count=0
while [[ $# -gt 0 ]]; do
case "${1:-}" in
-m) DESCRIPTION="${2:-}"; shift 2 ;;
patch|minor|major) [[ -z "$BUMP" ]] && BUMP="$1"; shift ;;
*) [[ -z "$BUMP" ]] && BUMP="$1"; shift ;;
esac
done
if [[ -n "$BUMP" ]]; then
# Non-interactive: resolve version from arg
case "$BUMP" in
patch) NEW_VERSION="$NEXT_PATCH" ;;
minor) NEW_VERSION="$NEXT_MINOR" ;;
major) NEW_VERSION="$NEXT_MAJOR" ;;
*.*.*) NEW_VERSION="$BUMP" ;;
*) echo "Invalid bump type: $BUMP"; exit 1 ;;
esac
DESCRIPTION="${DESCRIPTION:-release v$NEW_VERSION}"
echo "Current version: $CURRENT"
else
# Interactive mode
echo "Current version: $CURRENT"
echo ""
echo " 1) patch → $NEXT_PATCH (bug fixes, small changes)"
echo " 2) minor → $NEXT_MINOR (new features, backwards compatible)"
echo " 3) major → $NEXT_MAJOR (breaking changes)"
echo " 4) custom"
echo ""
read -rp "Bump type [1]: " CHOICE
CHOICE=${CHOICE:-1}
case "$CHOICE" in
1|patch) NEW_VERSION="$NEXT_PATCH" ;;
2|minor) NEW_VERSION="$NEXT_MINOR" ;;
3|major) NEW_VERSION="$NEXT_MAJOR" ;;
4|custom)
read -rp "Version: " NEW_VERSION
if [[ -z "$NEW_VERSION" ]]; then
echo "No version provided. Aborting."
exit 1
fi
;;
*) echo "Invalid choice. Aborting."; exit 1 ;;
esac
read -rp "Short description: " DESCRIPTION
DESCRIPTION="${DESCRIPTION:-release v$NEW_VERSION}"
fi
# ── Bump version in both files ─────────────────────────────────────
echo ""
echo "Bumping $CURRENT → $NEW_VERSION..."
sed -i "s/^version = \"$CURRENT\"/version = \"$NEW_VERSION\"/" pyproject.toml
sed -i "s/__version__ = \"$CURRENT\"/__version__ = \"$NEW_VERSION\"/" jhcontext/__init__.py
# ── Verify versions match ──────────────────────────────────────────
V_TOML=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
V_INIT=$(grep '__version__' jhcontext/__init__.py | sed 's/.*"\(.*\)"/\1/')
if [[ "$V_TOML" != "$NEW_VERSION" || "$V_INIT" != "$NEW_VERSION" ]]; then
echo "ERROR: Version mismatch after bump (toml=$V_TOML, init=$V_INIT)"
exit 1
fi
echo " pyproject.toml: $V_TOML"
echo " __init__.py: $V_INIT"
# ── Run tests ──────────────────────────────────────────────────────
# Surgical revert helper: undoes ONLY the version-line bump if tests fail,
# so unrelated in-flight changes in pyproject.toml / __init__.py survive.
revert_version_only() {
sed -i "s/^version = \"$NEW_VERSION\"/version = \"$CURRENT\"/" pyproject.toml
sed -i "s/__version__ = \"$NEW_VERSION\"/__version__ = \"$CURRENT\"/" jhcontext/__init__.py
}
echo "Running tests..."
# Prefer uv (the project's dependency manager) so pytest + extras resolve
# correctly; fall back to a bare python only if uv is unavailable.
if command -v uv >/dev/null 2>&1; then
TEST_CMD=(uv run --all-extras python -m pytest tests/ --ignore=tests/test_example.py -q)
else
PYTHON="${PYTHON:-$(command -v python3 || command -v python || true)}"
if [[ -z "$PYTHON" ]]; then
echo "ERROR: no uv, python3, or python found on PATH"
revert_version_only
exit 1
fi
TEST_CMD=("$PYTHON" -m pytest tests/ --ignore=tests/test_example.py -q)
fi
"${TEST_CMD[@]}" || {
echo "Tests failed. Fix before releasing."
revert_version_only
exit 1
}
# ── Git commit + tag + push ────────────────────────────────────────
# Pushing the tag triggers GitHub Actions → build → upload to PyPI
echo "Committing and tagging..."
git add -A
git commit -m "v$NEW_VERSION — $DESCRIPTION"
git tag "v$NEW_VERSION"
# Push commit first, then tag separately — pushing together causes
# GitHub Actions to fire only the branch event, skipping the publish job.
git push origin main
git push origin "v$NEW_VERSION"
echo ""
echo "=== v$NEW_VERSION pushed ==="
echo " GitHub Actions will build and publish to PyPI automatically."
echo " Watch: https://github.com/jhcontext/jhcontext-sdk/actions"
echo " PyPI: https://pypi.org/project/jhcontext/$NEW_VERSION/ (after CI completes)"