-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathrelease.sh
More file actions
executable file
·201 lines (160 loc) · 5.9 KB
/
release.sh
File metadata and controls
executable file
·201 lines (160 loc) · 5.9 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env bash
# Release astrameter from develop: bump version, finalize CHANGELOG, merge to main, tag, sync develop.
# Requires: git, yq (https://github.com/mikefarah/yq), clean develop, origin/develop up to date.
# Usage: ./release.sh X.Y.Z
set -euo pipefail
trap 'echo "[ERROR] release.sh failed at line ${LINENO:-?}. Check git status and branches before retrying." >&2' ERR
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
if [ -z "${1:-}" ]; then
print_error "Usage: $0 <version>"
print_info "Example: $0 1.2.0"
print_info "Run from a clean develop branch, synced with origin/develop."
exit 1
fi
VERSION="$1"
RELEASE_BRANCH="release/v${VERSION}"
if ! command -v yq >/dev/null 2>&1; then
print_error "yq is required. Install: https://github.com/mikefarah/yq"
exit 1
fi
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
print_error "Version must be semantic (e.g. 1.2.3), no v prefix."
exit 1
fi
print_info "Fetching origin..."
git fetch origin
# GitHub Actions checkout commonly leaves detached HEAD at origin/develop; only the SHA must match.
CURRENT_BRANCH=$(git branch --show-current)
if [ -n "$CURRENT_BRANCH" ] && [ "$CURRENT_BRANCH" != "develop" ]; then
print_error "You must be on branch develop (current: $CURRENT_BRANCH)"
exit 1
fi
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse origin/develop)
if [ "$LOCAL" != "$REMOTE" ]; then
print_error "HEAD is not at origin/develop. Run: git pull origin develop"
exit 1
fi
if [ -n "$(git status --porcelain)" ]; then
print_error "Working tree is not clean."
git status --short
exit 1
fi
if git show-ref --verify --quiet "refs/heads/$RELEASE_BRANCH"; then
print_error "Branch $RELEASE_BRANCH already exists locally."
exit 1
fi
if [ -n "$(git ls-remote --heads origin "$RELEASE_BRANCH" 2>/dev/null)" ]; then
print_error "Branch $RELEASE_BRANCH already exists on origin."
exit 1
fi
if git show-ref --verify --quiet "refs/tags/$VERSION"; then
print_error "Tag $VERSION already exists."
exit 1
fi
if ! grep -q '^## Next$' CHANGELOG.md; then
print_error "CHANGELOG.md must contain a line exactly: ## Next"
exit 1
fi
# Require at least one list item under ## Next (before the next ## heading)
if ! awk '
/^## Next$/ { in_next=1; found=0; next }
in_next && /^## / { exit !found }
in_next && /^[[:space:]]*- / { found=1 }
END { if (in_next) exit !found; exit 0 }
' CHANGELOG.md; then
print_error "## Next must include at least one bullet line (e.g. lines starting with \"- \")."
exit 1
fi
CURRENT_VER=$(grep -E '^version = ' pyproject.toml | head -1 | sed -E 's/^version = "([^"]+)".*/\1/')
if [ -z "$CURRENT_VER" ]; then
print_error "Could not read version from pyproject.toml (expected: version = \"…\")."
exit 1
fi
if [ "$VERSION" = "$CURRENT_VER" ]; then
print_error "Release version $VERSION equals current pyproject.toml version. Bump to a newer version."
exit 1
fi
if [ "$(printf '%s\n' "$CURRENT_VER" "$VERSION" | sort -V | tail -1)" != "$VERSION" ]; then
print_error "Release version $VERSION must be strictly greater than pyproject.toml version $CURRENT_VER."
exit 1
fi
print_info "Pre-checks passed. Starting release $VERSION"
print_info "Creating branch $RELEASE_BRANCH"
git checkout -b "$RELEASE_BRANCH"
print_info "Setting version in pyproject.toml"
sed -i.bak "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
rm -f pyproject.toml.bak
print_info "Setting ha_addon/config.yaml version"
yq eval --inplace ".version = \"$VERSION\"" ha_addon/config.yaml
print_info "Renaming ## Next to ## $VERSION in CHANGELOG.md"
LINE=$(grep -n '^## Next$' CHANGELOG.md | head -1 | cut -d: -f1)
sed -i.bak "${LINE}s/^## Next$/## $VERSION/" CHANGELOG.md
rm -f CHANGELOG.md.bak
git add pyproject.toml ha_addon/config.yaml CHANGELOG.md
git commit -m "Release v${VERSION}
- Set version in pyproject.toml and ha_addon/config.yaml
- Finalize CHANGELOG for v${VERSION}"
print_success "Release commit created on $RELEASE_BRANCH"
print_info "Pushing $RELEASE_BRANCH to origin"
git push origin "$RELEASE_BRANCH"
print_info "Checking out main and merging $RELEASE_BRANCH"
git checkout main
git pull origin main
if ! git merge "$RELEASE_BRANCH" --no-ff -m "Merge release v${VERSION}"; then
if git status --short | grep -q "^UU ha_addon/config.yaml"; then
print_info "Merge conflict in ha_addon/config.yaml; using release branch version."
git checkout --theirs ha_addon/config.yaml
git add ha_addon/config.yaml
git commit --no-edit
else
print_error "Merge failed with conflicts. Resolve manually and resume, or reset."
exit 1
fi
fi
print_info "Tagging $VERSION"
git tag "$VERSION"
print_info "Pushing main and tag $VERSION"
git push origin main
git push origin "$VERSION"
print_info "Merging main into develop"
git checkout develop
git pull origin develop
if ! git merge main --no-ff -m "Sync develop with main after release v${VERSION}"; then
print_error "Merge main into develop failed. Resolve manually."
exit 1
fi
print_info "Setting ha_addon/config.yaml version to next on develop"
yq eval --inplace '.version = "next"' ha_addon/config.yaml
needs_commit=false
if ! git diff --quiet ha_addon/config.yaml; then
git add ha_addon/config.yaml
needs_commit=true
fi
if ! grep -q '^## Next$' CHANGELOG.md; then
print_info "Prepending ## Next to CHANGELOG.md"
tmp=$(mktemp)
{
head -n1 CHANGELOG.md
echo ""
echo "## Next"
echo ""
tail -n +2 CHANGELOG.md
} >"$tmp"
mv "$tmp" CHANGELOG.md
git add CHANGELOG.md
needs_commit=true
fi
if [ "$needs_commit" = true ]; then
git commit -m "Prepare develop for next release (add-on next, ## Next)"
fi
print_info "Pushing develop"
git push origin develop
print_success "Release v${VERSION} complete."
print_info "Summary: branch $RELEASE_BRANCH kept; main and tag $VERSION pushed; develop updated."