xgem-cli 2.0.0-alpha.6 → 2.0.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/bin/xgem +2 -1
- package/bin/xgem.js +3 -2
- package/lib/flutter.sh +12 -10
- package/lib/git.sh +81 -2
- package/lib/version.sh +1 -1
- package/lib-win/flutter.js +6 -2
- package/lib-win/git.js +61 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ xgem doctor ios [path] Report on iOS build readiness: CocoaPods vs SPM, d
|
|
|
49
49
|
targets per config, and whether they're reconciled
|
|
50
50
|
xgem git cmt "message" Auto-stage, commit, rebase-pull, and push
|
|
51
51
|
xgem git init Setup local repo, attach remote tracker shortcuts
|
|
52
|
+
xgem git branch Pick, create, or switch branches; remembers your choice
|
|
52
53
|
xgem git rm-remote Drop a configured remote
|
|
53
54
|
xgem git rm-branch Safely drop local and/or remote branch
|
|
54
55
|
xgem --version Print xgem's version
|
|
@@ -70,7 +71,7 @@ lib/
|
|
|
70
71
|
doctor.sh environment + feature detection ("xgem doctor")
|
|
71
72
|
ios.sh the SwiftPM-aware iOS build engine
|
|
72
73
|
flutter.sh flutter command group (build/hard-clean/build-runner), delegates iOS builds to ios.sh
|
|
73
|
-
git.sh git cmt/init/rm-remote/rm-branch
|
|
74
|
+
git.sh git cmt/init/branch/rm-remote/rm-branch
|
|
74
75
|
scaffold.sh generic clean/build/dev handling for the other, simpler frameworks
|
|
75
76
|
templates/ the actual clean/build/dev script content xgem scaffolds into your project's .xgem-automate/
|
|
76
77
|
```
|
|
@@ -115,7 +116,7 @@ engine (`lib-win/`, driven by `bin/xgem.js`) so `npm install -g xgem-cli` actual
|
|
|
115
116
|
in `cmd.exe`/PowerShell, no WSL required.
|
|
116
117
|
|
|
117
118
|
What works on Windows: `init`/`add`/`run`/`terminate`, `doctor`, the git workflow
|
|
118
|
-
commands, and Flutter builds for **APK and Windows desktop** targets. What doesn't:
|
|
119
|
+
commands, and Flutter builds for **APK, App Bundle, and Windows desktop** targets. What doesn't:
|
|
119
120
|
Flutter **iOS/macOS** builds — Xcode has no Windows equivalent, so `xgem doctor ios`
|
|
120
121
|
explains that plainly instead of pretending. `swift` isn't offered as a framework
|
|
121
122
|
choice on Windows for the same reason. If you're inside WSL, none of this applies —
|
package/bin/xgem
CHANGED
|
@@ -70,6 +70,7 @@ print_usage() {
|
|
|
70
70
|
echo " xgem doctor [ios] - Report on your environment / iOS SwiftPM build readiness"
|
|
71
71
|
echo " xgem git cmt \"message\" - Auto-stage, commit, rebase-pull, and push"
|
|
72
72
|
echo " xgem git init - Setup local repo, attach remote tracker shortcuts"
|
|
73
|
+
echo " xgem git branch - Pick, create, or switch branches; remembers your choice"
|
|
73
74
|
echo " xgem git rm-remote - Drop specified target remote tracing rules"
|
|
74
75
|
echo " xgem git rm-branch - Safely drop local and remote workspace branch states"
|
|
75
76
|
echo " xgem --version - Print xgem's version"
|
|
@@ -182,7 +183,7 @@ case "${1:-}" in
|
|
|
182
183
|
;;
|
|
183
184
|
|
|
184
185
|
git)
|
|
185
|
-
[ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|rm-remote|rm-branch>"
|
|
186
|
+
[ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>"
|
|
186
187
|
cmd_git "$2" "${3:-}"
|
|
187
188
|
exit 0
|
|
188
189
|
;;
|
package/bin/xgem.js
CHANGED
|
@@ -45,6 +45,7 @@ function printUsage() {
|
|
|
45
45
|
console.log(' xgem doctor [ios] - Report on your environment / iOS build availability');
|
|
46
46
|
console.log(' xgem git cmt "message" - Auto-stage, commit, rebase-pull, and push');
|
|
47
47
|
console.log(' xgem git init - Setup local repo, attach remote tracker shortcuts');
|
|
48
|
+
console.log(' xgem git branch - Pick, create, or switch branches; remembers your choice');
|
|
48
49
|
console.log(' xgem git rm-remote - Drop specified target remote tracing rules');
|
|
49
50
|
console.log(' xgem git rm-branch - Safely drop local and remote workspace branch states');
|
|
50
51
|
console.log(' xgem --version - Print xgem\'s version');
|
|
@@ -164,7 +165,7 @@ function printFrameworkHelp(fw) {
|
|
|
164
165
|
}
|
|
165
166
|
if (fw === 'flutter') {
|
|
166
167
|
console.log('');
|
|
167
|
-
logInfo("Flutter builds on Windows support APK and Windows desktop targets. Run 'xgem doctor ios' for why iOS/macOS aren't available here.");
|
|
168
|
+
logInfo("Flutter builds on Windows support APK, App Bundle, and Windows desktop targets. Run 'xgem doctor ios' for why iOS/macOS aren't available here.");
|
|
168
169
|
}
|
|
169
170
|
console.log('');
|
|
170
171
|
}
|
|
@@ -187,7 +188,7 @@ async function main() {
|
|
|
187
188
|
case 'run': return cmdRun(a2, a3);
|
|
188
189
|
case 'terminate': return cmdTerminate();
|
|
189
190
|
case 'git':
|
|
190
|
-
if (!a2) die('Usage: xgem git <cmt|init|rm-remote|rm-branch>');
|
|
191
|
+
if (!a2) die('Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>');
|
|
191
192
|
return cmdGit(a2, a3);
|
|
192
193
|
case 'doctor': return cmdDoctor(a2);
|
|
193
194
|
case '--version':
|
package/lib/flutter.sh
CHANGED
|
@@ -189,20 +189,21 @@ cmd_flutter_build() {
|
|
|
189
189
|
echo ""
|
|
190
190
|
echo "Select Target Platform:"
|
|
191
191
|
echo "1) APK (Android)"
|
|
192
|
-
echo "2)
|
|
193
|
-
echo "3)
|
|
194
|
-
echo "4)
|
|
195
|
-
echo "5)
|
|
192
|
+
echo "2) App Bundle (Android, .aab — required for Play Store uploads)"
|
|
193
|
+
echo "3) iOS"
|
|
194
|
+
echo "4) macOS"
|
|
195
|
+
echo "5) Windows"
|
|
196
|
+
echo "6) Linux"
|
|
196
197
|
local platform_choice
|
|
197
|
-
read -r -p "Choose [1-
|
|
198
|
-
if ! [[ "$platform_choice" =~ ^[1-
|
|
198
|
+
read -r -p "Choose [1-6]: " platform_choice
|
|
199
|
+
if ! [[ "$platform_choice" =~ ^[1-6]$ ]]; then
|
|
199
200
|
die "Invalid platform choice '$platform_choice'."
|
|
200
201
|
fi
|
|
201
202
|
|
|
202
203
|
local mode="--release"
|
|
203
204
|
[[ "$is_release" == "n" || "$is_release" == "N" ]] && mode="--debug"
|
|
204
205
|
|
|
205
|
-
if [ "$platform_choice" -eq
|
|
206
|
+
if [ "$platform_choice" -eq 3 ]; then
|
|
206
207
|
_flutter_build_ios "$build_name" "$build_number" "$mode"
|
|
207
208
|
return
|
|
208
209
|
fi
|
|
@@ -210,9 +211,10 @@ cmd_flutter_build() {
|
|
|
210
211
|
log_info "Initializing Flutter Build ($mode) for version $build_name+$build_number..."
|
|
211
212
|
case $platform_choice in
|
|
212
213
|
1) flutter build apk "$mode" "--build-name=$build_name" "--build-number=$build_number" ;;
|
|
213
|
-
|
|
214
|
-
4) flutter build
|
|
215
|
-
5) flutter build
|
|
214
|
+
2) flutter build appbundle "$mode" "--build-name=$build_name" "--build-number=$build_number" ;;
|
|
215
|
+
4) flutter build macos "$mode" "--build-name=$build_name" "--build-number=$build_number" ;;
|
|
216
|
+
5) flutter build windows "$mode" "--build-name=$build_name" "--build-number=$build_number" ;;
|
|
217
|
+
6) flutter build linux "$mode" "--build-name=$build_name" "--build-number=$build_number" ;;
|
|
216
218
|
esac
|
|
217
219
|
}
|
|
218
220
|
|
package/lib/git.sh
CHANGED
|
@@ -46,6 +46,29 @@ cmd_git_cmt() {
|
|
|
46
46
|
return 0
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
|
+
# A pull needs something to pull FROM. If this branch has never been
|
|
50
|
+
# pushed before, there's no remote ref to pull, and `git pull --rebase`
|
|
51
|
+
# fails with "couldn't find remote ref <branch>" — which is not a
|
|
52
|
+
# connection problem or a conflict, just a brand-new branch. Check for
|
|
53
|
+
# that specific case first so it gets its own accurate message instead
|
|
54
|
+
# of being lumped in with real connectivity failures.
|
|
55
|
+
git ls-remote --exit-code --heads "$remote_name" "$current_branch" >/dev/null 2>&1
|
|
56
|
+
local ls_remote_status=$?
|
|
57
|
+
|
|
58
|
+
if [ "$ls_remote_status" -eq 2 ]; then
|
|
59
|
+
log_info "'$current_branch' doesn't exist on '$remote_name' yet — pushing to create it..."
|
|
60
|
+
if git push -u "$remote_name" "$current_branch"; then
|
|
61
|
+
log_success "Git workflow complete! Branch created and pushed."
|
|
62
|
+
else
|
|
63
|
+
die "Push operation failed."
|
|
64
|
+
fi
|
|
65
|
+
return 0
|
|
66
|
+
elif [ "$ls_remote_status" -ne 0 ]; then
|
|
67
|
+
log_error "Could not reach '$remote_name' to check for '$current_branch' — this looks like a real connection problem."
|
|
68
|
+
log_warn "Your commit is safe locally. Re-run 'xgem git cmt' once connectivity is restored, or push manually: git push $remote_name $current_branch"
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
49
72
|
local ahead_count
|
|
50
73
|
ahead_count=$(git rev-list --count "$remote_name/$current_branch..$current_branch" 2>/dev/null)
|
|
51
74
|
if [ "$ahead_count" = "0" ]; then
|
|
@@ -163,13 +186,69 @@ cmd_git_rm_branch() {
|
|
|
163
186
|
fi
|
|
164
187
|
}
|
|
165
188
|
|
|
166
|
-
#
|
|
189
|
+
# cmd_git_branch: lists local branches, lets the user pick one (or create a
|
|
190
|
+
# new one), checks it out, and remembers it as this repo's default so
|
|
191
|
+
# there's a quick way back to it later. `xgem git cmt` always operates on
|
|
192
|
+
# whatever's actually checked out (that's the only thing that's correct for
|
|
193
|
+
# a commit), so this command's job is the checkout + remembering, not
|
|
194
|
+
# changing how cmt picks its branch.
|
|
195
|
+
cmd_git_branch() {
|
|
196
|
+
local -a branches=()
|
|
197
|
+
while IFS= read -r line; do
|
|
198
|
+
[ -n "$line" ] && branches+=("$line")
|
|
199
|
+
done < <(git branch --format='%(refname:short)' 2>/dev/null)
|
|
200
|
+
|
|
201
|
+
[ ${#branches[@]} -gt 0 ] || die "No local branches found."
|
|
202
|
+
|
|
203
|
+
local current_branch
|
|
204
|
+
current_branch=$(git branch --show-current 2>/dev/null)
|
|
205
|
+
|
|
206
|
+
echo "Available branches:"
|
|
207
|
+
local i=1 b
|
|
208
|
+
for b in "${branches[@]}"; do
|
|
209
|
+
if [ "$b" = "$current_branch" ]; then
|
|
210
|
+
echo "$i) $b (current)"
|
|
211
|
+
else
|
|
212
|
+
echo "$i) $b"
|
|
213
|
+
fi
|
|
214
|
+
i=$((i + 1))
|
|
215
|
+
done
|
|
216
|
+
local create_option=$i
|
|
217
|
+
echo "$create_option) Create new branch"
|
|
218
|
+
|
|
219
|
+
local choice
|
|
220
|
+
read -r -p "Select [1-$create_option]: " choice
|
|
221
|
+
|
|
222
|
+
if [ "$choice" = "$create_option" ]; then
|
|
223
|
+
local new_branch
|
|
224
|
+
read -r -p "Enter new branch name: " new_branch
|
|
225
|
+
[ -n "$new_branch" ] || die "Branch name cannot be empty."
|
|
226
|
+
git checkout -b "$new_branch" || die "Could not create branch '$new_branch'."
|
|
227
|
+
git config --local xgem.default-branch "$new_branch"
|
|
228
|
+
log_success "Created and switched to '$new_branch', set as default for this repo."
|
|
229
|
+
return 0
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
if ! [[ "$choice" =~ ^[0-9]+$ ]] || [ "$choice" -lt 1 ] || [ "$choice" -gt ${#branches[@]} ]; then
|
|
233
|
+
die "Invalid selection."
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
local selected="${branches[$((choice - 1))]}"
|
|
237
|
+
if [ "$selected" != "$current_branch" ]; then
|
|
238
|
+
git checkout "$selected" || die "Could not switch to branch '$selected'."
|
|
239
|
+
fi
|
|
240
|
+
git config --local xgem.default-branch "$selected"
|
|
241
|
+
log_success "Switched to '$selected' and set as default for this repo."
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
# xgem git <cmt|init|rm-remote|rm-branch|branch> ...
|
|
167
245
|
cmd_git() {
|
|
168
246
|
case "$1" in
|
|
169
247
|
cmt) cmd_git_cmt "$2" ;;
|
|
170
248
|
init) cmd_git_init ;;
|
|
171
249
|
rm-remote) cmd_git_rm_remote ;;
|
|
172
250
|
rm-branch) cmd_git_rm_branch ;;
|
|
173
|
-
|
|
251
|
+
branch) cmd_git_branch ;;
|
|
252
|
+
*) die "Unknown git subcommand '$1'. Usage: xgem git <cmt|init|rm-remote|rm-branch|branch>" ;;
|
|
174
253
|
esac
|
|
175
254
|
}
|
package/lib/version.sh
CHANGED
package/lib-win/flutter.js
CHANGED
|
@@ -67,9 +67,10 @@ async function cmdBuild() {
|
|
|
67
67
|
|
|
68
68
|
console.log('\nSelect Target Platform:');
|
|
69
69
|
console.log('1) APK (Android)');
|
|
70
|
-
console.log('2)
|
|
70
|
+
console.log('2) App Bundle (Android, .aab — required for Play Store uploads)');
|
|
71
|
+
console.log('3) Windows');
|
|
71
72
|
console.log('(iOS/macOS require a Mac; Linux desktop can\'t be cross-built from Windows.)');
|
|
72
|
-
const platformChoice = await prompt('Choose [1-
|
|
73
|
+
const platformChoice = await prompt('Choose [1-3]');
|
|
73
74
|
|
|
74
75
|
const mode = (isRelease === 'n') ? '--debug' : '--release';
|
|
75
76
|
const buildArgs = [`--build-name=${buildName}`, `--build-number=${buildNumber}`];
|
|
@@ -78,6 +79,9 @@ async function cmdBuild() {
|
|
|
78
79
|
logInfo(`Building APK (${mode})...`);
|
|
79
80
|
flutter(['build', 'apk', mode, ...buildArgs]);
|
|
80
81
|
} else if (platformChoice === '2') {
|
|
82
|
+
logInfo(`Building App Bundle (${mode})...`);
|
|
83
|
+
flutter(['build', 'appbundle', mode, ...buildArgs]);
|
|
84
|
+
} else if (platformChoice === '3') {
|
|
81
85
|
logInfo(`Building Windows desktop app (${mode})...`);
|
|
82
86
|
flutter(['build', 'windows', mode, ...buildArgs]);
|
|
83
87
|
} else {
|
package/lib-win/git.js
CHANGED
|
@@ -60,6 +60,26 @@ async function cmdCmt(commitMsg) {
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// A pull needs something to pull FROM. If this branch has never been
|
|
64
|
+
// pushed before, there's no remote ref, and `git pull --rebase` fails
|
|
65
|
+
// with "couldn't find remote ref <branch>" — not a connection problem
|
|
66
|
+
// or a conflict, just a brand-new branch. Check for that case first.
|
|
67
|
+
const lsRemoteStatus = spawnSync('git', ['ls-remote', '--exit-code', '--heads', remoteName, currentBranch]).status;
|
|
68
|
+
|
|
69
|
+
if (lsRemoteStatus === 2) {
|
|
70
|
+
logInfo(`'${currentBranch}' doesn't exist on '${remoteName}' yet — pushing to create it...`);
|
|
71
|
+
if (git(['push', '-u', remoteName, currentBranch]).status === 0) {
|
|
72
|
+
logSuccess('Git workflow complete! Branch created and pushed.');
|
|
73
|
+
} else {
|
|
74
|
+
die('Push operation failed.');
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
} else if (lsRemoteStatus !== 0) {
|
|
78
|
+
logError(`Could not reach '${remoteName}' to check for '${currentBranch}' — this looks like a real connection problem.`);
|
|
79
|
+
logWarn(`Your commit is safe locally. Re-run 'xgem git cmt' once connectivity is restored, or push manually: git push ${remoteName} ${currentBranch}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
63
83
|
const aheadCount = gitCapture(['rev-list', '--count', `${remoteName}/${currentBranch}..${currentBranch}`]);
|
|
64
84
|
if (aheadCount === '0') {
|
|
65
85
|
logSuccess(`Already up to date with '${remoteName}/${currentBranch}' — nothing to push.`);
|
|
@@ -168,13 +188,53 @@ async function cmdRmBranch() {
|
|
|
168
188
|
}
|
|
169
189
|
}
|
|
170
190
|
|
|
191
|
+
// Lists local branches, lets the user pick one (or create a new one),
|
|
192
|
+
// checks it out, and remembers it as this repo's default. cmt always
|
|
193
|
+
// operates on whatever's actually checked out — this command's job is the
|
|
194
|
+
// checkout + remembering, not changing how cmt picks its branch.
|
|
195
|
+
async function cmdBranch() {
|
|
196
|
+
const branches = gitCapture(['branch', '--format=%(refname:short)']).split(/\r?\n/).filter(Boolean);
|
|
197
|
+
if (branches.length === 0) die('No local branches found.');
|
|
198
|
+
|
|
199
|
+
const currentBranch = gitCapture(['branch', '--show-current']);
|
|
200
|
+
|
|
201
|
+
console.log('Available branches:');
|
|
202
|
+
branches.forEach((b, i) => {
|
|
203
|
+
console.log(`${i + 1}) ${b}${b === currentBranch ? ' (current)' : ''}`);
|
|
204
|
+
});
|
|
205
|
+
const createOption = branches.length + 1;
|
|
206
|
+
console.log(`${createOption}) Create new branch`);
|
|
207
|
+
|
|
208
|
+
const choice = await prompt(`Select [1-${createOption}]`);
|
|
209
|
+
|
|
210
|
+
if (choice === String(createOption)) {
|
|
211
|
+
const newBranch = await prompt('Enter new branch name');
|
|
212
|
+
if (!newBranch) die('Branch name cannot be empty.');
|
|
213
|
+
if (git(['checkout', '-b', newBranch]).status !== 0) die(`Could not create branch '${newBranch}'.`);
|
|
214
|
+
git(['config', '--local', 'xgem.default-branch', newBranch]);
|
|
215
|
+
logSuccess(`Created and switched to '${newBranch}', set as default for this repo.`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const idx = parseInt(choice, 10) - 1;
|
|
220
|
+
if (Number.isNaN(idx) || idx < 0 || idx >= branches.length) die('Invalid selection.');
|
|
221
|
+
|
|
222
|
+
const selected = branches[idx];
|
|
223
|
+
if (selected !== currentBranch) {
|
|
224
|
+
if (git(['checkout', selected]).status !== 0) die(`Could not switch to branch '${selected}'.`);
|
|
225
|
+
}
|
|
226
|
+
git(['config', '--local', 'xgem.default-branch', selected]);
|
|
227
|
+
logSuccess(`Switched to '${selected}' and set as default for this repo.`);
|
|
228
|
+
}
|
|
229
|
+
|
|
171
230
|
async function cmdGit(sub, arg) {
|
|
172
231
|
switch (sub) {
|
|
173
232
|
case 'cmt': return cmdCmt(arg);
|
|
174
233
|
case 'init': return cmdInit();
|
|
234
|
+
case 'branch': return cmdBranch();
|
|
175
235
|
case 'rm-remote': return cmdRmRemote();
|
|
176
236
|
case 'rm-branch': return cmdRmBranch();
|
|
177
|
-
default: die(`Unknown git subcommand '${sub}'. Usage: xgem git <cmt|init|rm-remote|rm-branch>`);
|
|
237
|
+
default: die(`Unknown git subcommand '${sub}'. Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>`);
|
|
178
238
|
}
|
|
179
239
|
}
|
|
180
240
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xgem-cli",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.8",
|
|
4
4
|
"description": "Framework-aware automation CLI: scaffolds and runs clean/build/dev scripts per project type, an environment doctor, a SwiftPM-aware iOS build engine, and a git workflow helper. Runs natively on macOS, Linux, and Windows.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"xgem": "bin/xgem.js"
|