Skip to content

Commit d94403e

Browse files
authored
Merge pull request #71 from cloudsmith-io/ENG-8043/automate-bindings-release-via-ci-2
Added a script that automates the process of updating the API bindings.
2 parents 91843cd + ec6f1a2 commit d94403e

2 files changed

Lines changed: 343 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ Please refer to Cloudsmith's standard guide on [Open-Source Contributing](https:
44

55
## Updating bindings
66

7+
### Manual approach
8+
79
* Update `package_version` in `scripts/common.sh`
810
* Run `./scripts/build.sh` to generate bindings
911
* Create a PR specifing API and binding version
1012

13+
### Automated approach
14+
15+
* Run `./scripts/update-bindings.sh` to automatically update the bindings.
16+
* This will then provide you with the URL for the PR to release the updated bindings.
17+
* Preferred usage: `./scripts/update-bindings.sh`
18+
* For full options and usage examples, run: `./scripts/update-bindings.sh --help`
19+
1120
## Contributor License Agreement
1221

1322
By making any contributions to Cloudsmith Ltd projects you agree to be bound by the terms of the Cloudsmith Ltd [Contributor License Agreement](https://help.cloudsmith.io/docs/contributor-license-agreement).

scripts/update-bindings.sh

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
REPO_NAME="cloudsmith-api"
6+
REPO_URL="https://github.com/cloudsmith-io/cloudsmith-api"
7+
BRANCH_PREFIX="update-bindings"
8+
COMMON_SCRIPT="scripts/common.sh"
9+
BUILD_SCRIPT="scripts/build.sh"
10+
11+
RED='\033[0;31m'
12+
GREEN='\033[0;32m'
13+
YELLOW='\033[1;33m'
14+
BLUE='\033[0;34m'
15+
NC='\033[0m'
16+
17+
log_info() {
18+
echo -e "${BLUE}[INFO]${NC} $1"
19+
}
20+
21+
log_success() {
22+
echo -e "${GREEN}[SUCCESS]${NC} $1"
23+
}
24+
25+
log_warning() {
26+
echo -e "${YELLOW}[WARNING]${NC} $1"
27+
}
28+
29+
log_error() {
30+
echo -e "${RED}[ERROR]${NC} $1"
31+
}
32+
33+
check_dependencies() {
34+
log_info "Checking dependencies..."
35+
36+
local missing_deps=()
37+
38+
if ! command -v git &> /dev/null; then
39+
missing_deps+=("git")
40+
fi
41+
42+
if [ ${#missing_deps[@]} -ne 0 ]; then
43+
log_error "Missing dependencies: ${missing_deps[*]}"
44+
log_error "Please install the missing dependencies and try again."
45+
exit 1
46+
fi
47+
48+
log_success "All dependencies are installed"
49+
}
50+
51+
validate_version() {
52+
local version="$1"
53+
if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
54+
log_error "Invalid version format: $version"
55+
log_error "Version should be in format: X.Y.Z (e.g., 1.2.3)"
56+
exit 1
57+
fi
58+
}
59+
60+
get_current_version() {
61+
if [ ! -f "$COMMON_SCRIPT" ]; then
62+
log_error "File $COMMON_SCRIPT not found"
63+
exit 1
64+
fi
65+
66+
local current_version=$(grep -E "^package_version=" "$COMMON_SCRIPT" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
67+
echo "$current_version"
68+
}
69+
70+
increment_patch_version() {
71+
local version="$1"
72+
local major minor patch
73+
74+
IFS='.' read -r major minor patch <<< "$version"
75+
patch=$((patch + 1))
76+
echo "${major}.${minor}.${patch}"
77+
}
78+
79+
get_api_version() {
80+
local api_url="https://api.cloudsmith.io/"
81+
log_info "Fetching current API version from CloudSmith..." >&2
82+
83+
local api_version=$(curl -s "${api_url}status/check/basic/" 2>/dev/null | jq -r '.version' 2>/dev/null)
84+
85+
if [ "$api_version" = "null" ] || [ -z "$api_version" ]; then
86+
log_warning "Could not fetch API version from CloudSmith API" >&2
87+
return 1
88+
fi
89+
90+
echo "$api_version"
91+
}
92+
93+
update_version() {
94+
local new_version="$1"
95+
local current_version=$(get_current_version)
96+
97+
log_info "Updating version from $current_version to $new_version"
98+
99+
log_info "Current package_version line:"
100+
grep "package_version" "$COMMON_SCRIPT" || {
101+
log_error "No package_version line found in $COMMON_SCRIPT"
102+
exit 1
103+
}
104+
105+
cp "$COMMON_SCRIPT" "$COMMON_SCRIPT.backup"
106+
107+
awk -v new_ver="$new_version" '
108+
/^package_version=/ {
109+
print "package_version=\"" new_ver "\""
110+
next
111+
}
112+
{ print }
113+
' "$COMMON_SCRIPT" > "$COMMON_SCRIPT.tmp" && mv "$COMMON_SCRIPT.tmp" "$COMMON_SCRIPT"
114+
115+
local updated_version=$(get_current_version)
116+
if [ "$updated_version" != "$new_version" ]; then
117+
log_error "Failed to update version in $COMMON_SCRIPT"
118+
log_error "Expected: $new_version, Got: $updated_version"
119+
120+
log_error "Updated package_version line:"
121+
grep "package_version" "$COMMON_SCRIPT" || log_error "No package_version line found"
122+
123+
mv "$COMMON_SCRIPT.backup" "$COMMON_SCRIPT"
124+
exit 1
125+
fi
126+
127+
rm "$COMMON_SCRIPT.backup"
128+
log_success "Version updated successfully"
129+
}
130+
131+
generate_bindings() {
132+
log_info "Generating bindings..."
133+
134+
if [ ! -x "$BUILD_SCRIPT" ]; then
135+
log_warning "Making $BUILD_SCRIPT executable"
136+
chmod +x "$BUILD_SCRIPT"
137+
fi
138+
139+
if ./"$BUILD_SCRIPT"; then
140+
log_success "Bindings generated successfully"
141+
else
142+
log_error "Failed to generate bindings"
143+
exit 1
144+
fi
145+
}
146+
147+
create_and_push_branch() {
148+
local version="$1"
149+
local api_version="$2"
150+
local branch_name="${BRANCH_PREFIX}-v${version}"
151+
152+
log_info "Creating branch: $branch_name"
153+
154+
if git show-ref --verify --quiet "refs/heads/$branch_name"; then
155+
log_warning "Branch $branch_name already exists locally. Deleting it."
156+
git branch -D "$branch_name"
157+
fi
158+
159+
if git ls-remote --heads origin "$branch_name" | grep -q "$branch_name"; then
160+
log_warning "Branch $branch_name already exists on remote."
161+
read -p "Do you want to delete the remote branch and create a new one? (y/N): " -n 1 -r
162+
echo
163+
if [[ $REPLY =~ ^[Yy]$ ]]; then
164+
log_info "Deleting remote branch $branch_name..."
165+
git push origin --delete "$branch_name" || {
166+
log_warning "Could not delete remote branch (it might not exist or you might not have permissions)"
167+
}
168+
else
169+
local timestamp=$(date +"%Y%m%d-%H%M%S")
170+
branch_name="${BRANCH_PREFIX}-v${version}-${timestamp}"
171+
log_info "Using unique branch name: $branch_name"
172+
fi
173+
fi
174+
175+
git checkout -b "$branch_name"
176+
git add .
177+
178+
if git diff --staged --quiet; then
179+
log_warning "No changes to commit. The bindings might already be up to date."
180+
return 1
181+
fi
182+
183+
git commit -m "Update API bindings to version $version
184+
185+
Binding version: $version
186+
CloudSmith API version: $api_version
187+
188+
- Updated package_version in scripts/common.sh
189+
- Regenerated bindings for Python, Ruby, and Java
190+
- Ready for automated deployment via CircleCI"
191+
192+
log_info "Pushing branch to origin..."
193+
if ! git push origin "$branch_name"; then
194+
log_warning "Normal push failed, trying force push..."
195+
git push origin "$branch_name" --force-with-lease || {
196+
log_error "Failed to push branch even with force. Check your permissions."
197+
exit 1
198+
}
199+
fi
200+
201+
log_success "Branch created and pushed successfully"
202+
echo "$branch_name"
203+
}
204+
205+
usage() {
206+
echo "Usage: $0 [OPTIONS]"
207+
echo ""
208+
echo "Preferred usage (no arguments - auto-increments patch version):"
209+
echo " $0 # Auto-increment patch version and fetch latest API version"
210+
echo ""
211+
echo "Options:"
212+
echo " -v, --version VERSION Specific binding version (optional)"
213+
echo " -h, --help Show this help message"
214+
echo ""
215+
echo "Examples:"
216+
echo " $0 # Preferred: auto-increment patch version"
217+
echo " $0 -v 2.1.0 # Specify custom version (e.g. minor/major bump)"
218+
echo " $0 --version 2.0.19 # Long form"
219+
echo ""
220+
echo "Note:"
221+
echo " - When run without arguments, the script will:"
222+
echo " * Auto-increment the patch version (e.g. 2.0.18 -> 2.0.19)"
223+
echo " * Auto-fetch the latest CloudSmith API version"
224+
echo " - Use -v only for larger version increments (minor/major bumps)"
225+
}
226+
227+
main() {
228+
local new_version=""
229+
local auto_increment=true
230+
231+
while [[ $# -gt 0 ]]; do
232+
case $1 in
233+
-v|--version)
234+
new_version="$2"
235+
auto_increment=false
236+
shift 2
237+
;;
238+
-h|--help)
239+
usage
240+
exit 0
241+
;;
242+
*)
243+
log_error "Unknown option: $1"
244+
usage
245+
exit 1
246+
;;
247+
esac
248+
done
249+
250+
check_dependencies
251+
252+
local current_version=$(get_current_version)
253+
log_info "Current version: $current_version"
254+
255+
if [ "$auto_increment" = true ]; then
256+
new_version=$(increment_patch_version "$current_version")
257+
log_info "Auto-incrementing patch version to: $new_version"
258+
else
259+
validate_version "$new_version"
260+
log_info "Using specified version: $new_version"
261+
fi
262+
263+
local api_version
264+
if api_version=$(get_api_version); then
265+
log_info "Auto-fetched API version: $api_version"
266+
else
267+
log_error "Failed to auto-fetch API version"
268+
exit 1
269+
fi
270+
271+
validate_version "$new_version"
272+
validate_version "$api_version"
273+
274+
log_info "Starting CloudSmith API bindings update process..."
275+
log_info "New binding version: $new_version"
276+
log_info "API version: $api_version"
277+
278+
if [ "$current_version" = "$new_version" ]; then
279+
log_warning "Version $new_version is the same as current version"
280+
read -p "Do you want to continue anyway? (y/N): " -n 1 -r
281+
echo
282+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
283+
log_info "Operation cancelled"
284+
exit 0
285+
fi
286+
fi
287+
288+
local current_branch=$(git branch --show-current)
289+
log_info "Current branch: $current_branch"
290+
291+
if [[ "$current_branch" == "main" || "$current_branch" == "master" ]]; then
292+
log_info "Already on main branch ($current_branch)"
293+
else
294+
if ! git diff-index --quiet HEAD --; then
295+
log_error "You have uncommitted changes. Please commit or stash them first:"
296+
git status --short
297+
exit 1
298+
fi
299+
300+
log_info "Switching to main branch..."
301+
302+
if git show-ref --verify --quiet refs/heads/main; then
303+
git checkout main || {
304+
log_error "Could not switch to main branch"
305+
exit 1
306+
}
307+
elif git show-ref --verify --quiet refs/heads/master; then
308+
git checkout master || {
309+
log_error "Could not switch to master branch"
310+
exit 1
311+
}
312+
else
313+
log_error "Neither 'main' nor 'master' branch found"
314+
log_error "Available branches:"
315+
git branch -a
316+
exit 1
317+
fi
318+
fi
319+
320+
log_info "Pulling latest changes..."
321+
git pull origin $(git branch --show-current)
322+
323+
update_version "$new_version"
324+
generate_bindings
325+
326+
local branch_name
327+
if branch_name=$(create_and_push_branch "$new_version" "$api_version"); then
328+
log_success "Automation completed successfully!"
329+
else
330+
log_warning "No changes detected. The bindings may already be up to date."
331+
fi
332+
}
333+
334+
main "$@"

0 commit comments

Comments
 (0)