1+ #! /usr/bin/env bash
2+ # split-packages.sh - Push package changes to read-only repositories without versioning
3+ set -e
4+
5+ # Configuration
6+ GITHUB_TOKEN=" ${GITHUB_TOKEN:- $SPLIT_TOKEN_4 } "
7+ GITHUB_ORG=" cognesy"
8+ GITHUB_USER=" ddebowczyk"
9+ GITHUB_EMAIL=" ddebowczyk@gmail.com"
10+ TARGET_BRANCH=" main"
11+
12+ # Package definitions (extracted from split.yml)
13+ declare -A PACKAGES
14+ PACKAGES[" packages/addons" ]=" instructor-addons"
15+ PACKAGES[" packages/auxiliary" ]=" instructor-aux"
16+ PACKAGES[" packages/config" ]=" instructor-config"
17+ PACKAGES[" packages/evals" ]=" instructor-evals"
18+ PACKAGES[" packages/events" ]=" instructor-events"
19+ PACKAGES[" packages/http-client" ]=" instructor-http-client"
20+ PACKAGES[" packages/hub" ]=" instructor-hub"
21+ PACKAGES[" packages/instructor" ]=" instructor-struct"
22+ PACKAGES[" packages/polyglot" ]=" instructor-polyglot"
23+ PACKAGES[" packages/schema" ]=" instructor-schema"
24+ PACKAGES[" packages/schema-v6" ]=" instructor-schema-v6"
25+ PACKAGES[" packages/setup" ]=" instructor-setup"
26+ PACKAGES[" packages/tell" ]=" instructor-tell"
27+ PACKAGES[" packages/templates" ]=" instructor-templates"
28+ PACKAGES[" packages/utils" ]=" instructor-utils"
29+
30+ # Colors for output
31+ RED=' \033[0;31m'
32+ GREEN=' \033[0;32m'
33+ YELLOW=' \033[1;33m'
34+ BLUE=' \033[0;34m'
35+ NC=' \033[0m' # No Color
36+
37+ # Helper functions
38+ log_info () {
39+ echo -e " ${BLUE} ℹ️ $1 ${NC} "
40+ }
41+
42+ log_success () {
43+ echo -e " ${GREEN} ✅ $1 ${NC} "
44+ }
45+
46+ log_warning () {
47+ echo -e " ${YELLOW} ⚠️ $1 ${NC} "
48+ }
49+
50+ log_error () {
51+ echo -e " ${RED} ❌ $1 ${NC} "
52+ }
53+
54+ # Check dependencies
55+ check_dependencies () {
56+ local missing_deps=()
57+
58+ if ! command -v git & > /dev/null; then
59+ missing_deps+=(" git" )
60+ fi
61+
62+ if ! command -v splitsh-lite & > /dev/null; then
63+ log_warning " splitsh-lite not found. Installing..."
64+ if command -v brew & > /dev/null; then
65+ brew install splitsh/tap/lite
66+ elif command -v curl & > /dev/null; then
67+ curl -L https://github.com/splitsh/lite/releases/latest/download/lite_linux_amd64.tar.gz | tar -xz
68+ sudo mv splitsh-lite /usr/local/bin/
69+ else
70+ missing_deps+=(" splitsh-lite" )
71+ fi
72+ fi
73+
74+ if [ ${# missing_deps[@]} -ne 0 ]; then
75+ log_error " Missing dependencies: ${missing_deps[*]} "
76+ log_info " Please install missing dependencies and try again"
77+ exit 1
78+ fi
79+ }
80+
81+ # Validate GitHub token
82+ check_github_token () {
83+ if [ -z " $GITHUB_TOKEN " ]; then
84+ log_error " GitHub token not found!"
85+ log_info " Set GITHUB_TOKEN or SPLIT_TOKEN_4 environment variable"
86+ log_info " Example: export GITHUB_TOKEN=your_token_here"
87+ exit 1
88+ fi
89+ }
90+
91+ # Show usage information
92+ show_usage () {
93+ cat << EOF
94+ Usage: $0 [OPTIONS] [PACKAGE_NAMES...]
95+
96+ Push package changes to read-only repositories without creating a new version.
97+
98+ OPTIONS:
99+ -h, --help Show this help message
100+ -l, --list List available packages
101+ -b, --branch BRANCH Target branch (default: main)
102+ -d, --dry-run Show what would be done without executing
103+ --all Process all packages (default if no packages specified)
104+
105+ PACKAGE_NAMES:
106+ Space-separated list of package directory names (e.g., packages/utils packages/events)
107+ Or just the package names (e.g., utils events)
108+
109+ EXAMPLES:
110+ $0 --list # List all available packages
111+ $0 utils events # Split only utils and events packages
112+ $0 packages/utils packages/events # Same as above
113+ $0 --all # Split all packages
114+ $0 --dry-run utils # Show what would be done for utils package
115+
116+ ENVIRONMENT VARIABLES:
117+ GITHUB_TOKEN or SPLIT_TOKEN_4 GitHub personal access token with repo permissions
118+ EOF
119+ }
120+
121+ # List available packages
122+ list_packages () {
123+ log_info " Available packages:"
124+ for local_path in " ${! PACKAGES[@]} " ; do
125+ repo_name=" ${PACKAGES[$local_path]} "
126+ package_name=$( basename " $local_path " )
127+ echo " • $package_name ($local_path ) → $GITHUB_ORG /$repo_name "
128+ done
129+ }
130+
131+ # Normalize package name to full path
132+ normalize_package_name () {
133+ local input=" $1 "
134+
135+ # If already full path, return as-is
136+ if [[ " $input " == packages/* ]]; then
137+ echo " $input "
138+ return
139+ fi
140+
141+ # If just package name, convert to full path
142+ echo " packages/$input "
143+ }
144+
145+ # Split a single package
146+ split_package () {
147+ local local_path=" $1 "
148+ local repo_name=" ${PACKAGES[$local_path]} "
149+ local package_name=$( basename " $local_path " )
150+ local dry_run=" $2 "
151+
152+ if [ -z " $repo_name " ]; then
153+ log_error " Package $local_path not found in configuration"
154+ return 1
155+ fi
156+
157+ if [ ! -d " $local_path " ]; then
158+ log_error " Directory $local_path does not exist"
159+ return 1
160+ fi
161+
162+ log_info " Processing $package_name ($local_path → $GITHUB_ORG /$repo_name )"
163+
164+ if [ " $dry_run " = " true" ]; then
165+ log_info " [DRY RUN] Would split $local_path to $GITHUB_ORG /$repo_name "
166+ return 0
167+ fi
168+
169+ # Create split using splitsh-lite
170+ local split_sha
171+ split_sha=$( splitsh-lite --prefix=" $local_path " )
172+
173+ if [ -z " $split_sha " ]; then
174+ log_error " Failed to create split for $local_path "
175+ return 1
176+ fi
177+
178+ log_info " Split SHA: $split_sha "
179+
180+ # Configure git
181+ git config user.name " $GITHUB_USER "
182+ git config user.email " $GITHUB_EMAIL "
183+
184+ # Push to target repository
185+ local remote_url=" https://$GITHUB_TOKEN @github.com/$GITHUB_ORG /$repo_name .git"
186+
187+ log_info " Pushing to $GITHUB_ORG /$repo_name ..."
188+
189+ if git push " $remote_url " " $split_sha :refs/heads/$TARGET_BRANCH " 2> /dev/null; then
190+ log_success " Successfully pushed $package_name to $GITHUB_ORG /$repo_name "
191+ else
192+ log_error " Failed to push $package_name to $GITHUB_ORG /$repo_name "
193+ return 1
194+ fi
195+ }
196+
197+ # Main function
198+ main () {
199+ local packages_to_process=()
200+ local dry_run=" false"
201+ local target_branch=" main"
202+
203+ # Parse arguments
204+ while [[ $# -gt 0 ]]; do
205+ case $1 in
206+ -h|--help)
207+ show_usage
208+ exit 0
209+ ;;
210+ -l|--list)
211+ list_packages
212+ exit 0
213+ ;;
214+ -b|--branch)
215+ target_branch=" $2 "
216+ shift 2
217+ ;;
218+ -d|--dry-run)
219+ dry_run=" true"
220+ shift
221+ ;;
222+ --all)
223+ packages_to_process=(" ${! PACKAGES[@]} " )
224+ shift
225+ ;;
226+ -* )
227+ log_error " Unknown option: $1 "
228+ show_usage
229+ exit 1
230+ ;;
231+ * )
232+ packages_to_process+=(" $( normalize_package_name " $1 " ) " )
233+ shift
234+ ;;
235+ esac
236+ done
237+
238+ # Set target branch
239+ TARGET_BRANCH=" $target_branch "
240+
241+ # If no packages specified, process all
242+ if [ ${# packages_to_process[@]} -eq 0 ]; then
243+ packages_to_process=(" ${! PACKAGES[@]} " )
244+ log_info " No packages specified, processing all packages"
245+ fi
246+
247+ # Check dependencies and token
248+ check_dependencies
249+ check_github_token
250+
251+ # Ensure we're in a git repository
252+ if ! git rev-parse --git-dir > /dev/null 2>&1 ; then
253+ log_error " Not in a git repository"
254+ exit 1
255+ fi
256+
257+ # Check for uncommitted changes
258+ if [ " $dry_run " = " false" ] && ! git diff-index --quiet HEAD --; then
259+ log_warning " You have uncommitted changes. Consider committing them first."
260+ read -p " Continue anyway? (y/N): " -n 1 -r
261+ echo
262+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
263+ exit 1
264+ fi
265+ fi
266+
267+ log_info " Starting package split process..."
268+ log_info " Target branch: $TARGET_BRANCH "
269+ log_info " Packages to process: ${# packages_to_process[@]} "
270+
271+ if [ " $dry_run " = " true" ]; then
272+ log_warning " DRY RUN MODE - No changes will be made"
273+ fi
274+
275+ # Process each package
276+ local success_count=0
277+ local error_count=0
278+
279+ for local_path in " ${packages_to_process[@]} " ; do
280+ if split_package " $local_path " " $dry_run " ; then
281+ (( success_count++ ))
282+ else
283+ (( error_count++ ))
284+ fi
285+ echo # Add spacing between packages
286+ done
287+
288+ # Summary
289+ log_info " Split process completed"
290+ log_success " Successfully processed: $success_count packages"
291+ if [ $error_count -gt 0 ]; then
292+ log_error " Failed to process: $error_count packages"
293+ exit 1
294+ fi
295+ }
296+
297+ # Run main function with all arguments
298+ main " $@ "
0 commit comments