xgem-cli 2.0.0-alpha.10 → 2.0.0-alpha.14
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 +37 -63
- package/bin/xgem +46 -15
- package/bin/xgem.js +22 -20
- package/lib/bootstrap.sh +165 -0
- package/lib/ci.sh +44 -0
- package/lib/create.sh +140 -71
- package/lib/flutter.sh +10 -8
- package/lib/git.sh +291 -29
- package/lib/registry.sh +45 -0
- package/lib/release.sh +185 -0
- package/lib/scaffold.sh +21 -2
- package/lib/status.sh +42 -0
- package/lib/utils.sh +11 -0
- package/lib/version.sh +1 -1
- package/lib-win/bootstrap.js +189 -0
- package/lib-win/ci.js +43 -0
- package/lib-win/git.js +275 -21
- package/lib-win/registry.js +43 -0
- package/lib-win/release.js +143 -0
- package/lib-win/scaffold.js +64 -2
- package/lib-win/status.js +53 -0
- package/lib-win/utils.js +6 -1
- package/package.json +1 -1
- package/templates/node/build.sh.tmpl +9 -1
- package/templates/node/hard-clean.sh.tmpl +34 -2
- package/templates/node/lint.sh.tmpl +10 -0
- package/templates/node/start.sh.tmpl +9 -1
- package/templates/node/test.sh.tmpl +10 -0
- package/templates/webframework/build.sh.tmpl +10 -1
- package/templates/webframework/dev.sh.tmpl +9 -1
- package/templates/webframework/hard-clean.sh.tmpl +35 -2
- package/templates/webframework/lint.sh.tmpl +10 -0
- package/templates/webframework/test.sh.tmpl +10 -0
- package/templates-win/node/build.mjs.tmpl +8 -2
- package/templates-win/node/hard-clean.mjs.tmpl +24 -5
- package/templates-win/node/lint.mjs.tmpl +10 -0
- package/templates-win/node/start.mjs.tmpl +8 -1
- package/templates-win/node/test.mjs.tmpl +10 -0
- package/templates-win/webframework/build.mjs.tmpl +8 -1
- package/templates-win/webframework/dev.mjs.tmpl +8 -1
- package/templates-win/webframework/hard-clean.mjs.tmpl +28 -5
- package/templates-win/webframework/lint.mjs.tmpl +10 -0
- package/templates-win/webframework/test.mjs.tmpl +10 -0
package/README.md
CHANGED
|
@@ -13,7 +13,13 @@ your environment, and `xgem git` wraps a common stage → commit → rebase-pull
|
|
|
13
13
|
Flutter's iOS builds go through a dedicated engine that detects whether your
|
|
14
14
|
project uses CocoaPods or Swift Package Manager (SPM), figures out the actual
|
|
15
15
|
deployment target your resolved SPM plugins require (instead of guessing),
|
|
16
|
-
and reconciles it automatically
|
|
16
|
+
and reconciles it automatically.
|
|
17
|
+
|
|
18
|
+
**Full documentation: [docs/](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/README.md)** — getting started, every command in
|
|
19
|
+
depth, exactly what each framework's project-creation wizard does, the iOS build
|
|
20
|
+
engine explained, Windows support, and troubleshooting. This README is a summary.
|
|
21
|
+
(Absolute link on purpose — `docs/` isn't shipped inside the npm package itself,
|
|
22
|
+
so a relative link would 404 on npmjs.com's rendered README.)
|
|
17
23
|
|
|
18
24
|
## Install
|
|
19
25
|
|
|
@@ -56,6 +62,14 @@ xgem git init Setup local repo, attach remote tracker shortcuts
|
|
|
56
62
|
xgem git branch Pick, create, or switch branches; remembers your choice
|
|
57
63
|
xgem git rm-remote Drop a configured remote
|
|
58
64
|
xgem git rm-branch Safely drop local and/or remote branch
|
|
65
|
+
xgem git pr Push current branch and open a GitHub PR (gh-backed)
|
|
66
|
+
xgem git sync Rebase current branch onto the repo's base branch
|
|
67
|
+
xgem git clean-branches Delete local branches already merged into the base branch
|
|
68
|
+
xgem git hooks <install|uninstall> Manage a pre-commit lint/test hook
|
|
69
|
+
xgem release [major|minor|patch] Bump version, update CHANGELOG.md, tag, push
|
|
70
|
+
xgem status Dashboard across every xgem-tracked project
|
|
71
|
+
xgem bootstrap Clone-to-running: detect framework, install, .env, migrate, launch
|
|
72
|
+
xgem ci Run lint/test/build for every configured framework, summarized
|
|
59
73
|
xgem --version Print xgem's version
|
|
60
74
|
|
|
61
75
|
Flags (any command): --yes (skip confirmations), --dry-run (show, don't apply), --verbose
|
|
@@ -68,31 +82,13 @@ flutter, node, python, react, vue, angular, next, go, rust, docker, swift
|
|
|
68
82
|
## Creating a new project
|
|
69
83
|
|
|
70
84
|
`xgem init` asks, per framework, whether to create a brand-new project or use
|
|
71
|
-
what's already in the directory
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
- **angular**: `ng new` (via a local Angular CLI if you have one, `npx
|
|
79
|
-
@angular/cli` otherwise).
|
|
80
|
-
- **flutter**: `flutter create`, then lists available devices/simulators
|
|
81
|
-
(falling back to available-but-not-booted emulators you can launch) and
|
|
82
|
-
runs on whichever you pick.
|
|
83
|
-
- **node/python/go/rust/docker/swift**: the ecosystem's own minimal init
|
|
84
|
-
command (`npm init`, a `.venv`, `cargo new`, `go mod init`, a starter
|
|
85
|
-
Dockerfile, `swift package init`) — no sub-wizard, since these don't have
|
|
86
|
-
an equivalent "dev server" to launch.
|
|
87
|
-
|
|
88
|
-
For the frameworks with a dev server (react/vue/angular/next), after
|
|
89
|
-
dependencies install xgem offers to start it and open your default browser —
|
|
90
|
-
it tails the server's own log for the first `http://localhost:PORT` it
|
|
91
|
-
prints rather than guessing a framework's default port, so it works even if
|
|
92
|
-
that port's already taken and a different one gets picked.
|
|
93
|
-
|
|
94
|
-
Answering "existing" (the default) skips all of this and behaves exactly
|
|
95
|
-
like before — just scaffolds `.xgem-automate/` into the current directory.
|
|
85
|
+
what's already in the directory — real `create-vite`/`create-vue`/`ng new`/
|
|
86
|
+
`create-next-app`/`flutter create` scaffolding, with framework-specific
|
|
87
|
+
questions and a working dev-server/device launch at the end. Package manager
|
|
88
|
+
(npm/yarn/pnpm/bun) is auto-detected everywhere, never assumed. Answering
|
|
89
|
+
"existing" (the default) skips all of this and just scaffolds
|
|
90
|
+
`.xgem-automate/` into the current directory. Full detail, including exactly
|
|
91
|
+
what runs for each framework: **[docs/frameworks.md](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/frameworks.md)**.
|
|
96
92
|
|
|
97
93
|
## Architecture
|
|
98
94
|
|
|
@@ -118,47 +114,25 @@ of logic that can drift out of sync with two copies.
|
|
|
118
114
|
## Why the iOS build engine exists
|
|
119
115
|
|
|
120
116
|
Flutter auto-generates a wrapper Swift package, `FlutterGeneratedPluginSwiftPackage`,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
upstream Flutter bug
|
|
117
|
+
whose declared minimum iOS platform can desync from your app's own
|
|
118
|
+
`IPHONEOS_DEPLOYMENT_TARGET` — independently, even when your app's own target is
|
|
119
|
+
already high enough. This is a confirmed, currently-open upstream Flutter bug
|
|
120
|
+
([flutter/flutter#186804](https://github.com/flutter/flutter/issues/186804),
|
|
124
121
|
[#189422](https://github.com/flutter/flutter/issues/189422),
|
|
125
|
-
[#162072](https://github.com/flutter/flutter/issues/162072)).
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
1. Detects whether the project uses CocoaPods, SPM, or both.
|
|
133
|
-
2. Computes the deployment target actually required by your *resolved* SPM plugins
|
|
134
|
-
(by reading their `ios/Package.swift` manifests via `.dart_tool/package_config.json`),
|
|
135
|
-
instead of assuming a fixed value.
|
|
136
|
-
3. Shows a plan and asks for confirmation (unless `--yes`/`--dry-run`) before patching
|
|
137
|
-
*every* `IPHONEOS_DEPLOYMENT_TARGET` occurrence in `project.pbxproj`.
|
|
138
|
-
4. Forces a clean regeneration (`flutter pub get` after clearing `ios/Flutter/ephemeral`)
|
|
139
|
-
and verifies the regenerated package matches.
|
|
140
|
-
5. If it still doesn't (the upstream bug above), patches the generated package directly
|
|
141
|
-
as a documented, loudly-logged last resort — never silently.
|
|
142
|
-
|
|
143
|
-
Run `xgem doctor ios` any time for a standalone readiness report without doing a build.
|
|
122
|
+
[#162072](https://github.com/flutter/flutter/issues/162072)). `xgem run flutter build`
|
|
123
|
+
(iOS target) detects the actual requirement from your resolved SPM plugins, patches
|
|
124
|
+
every deployment-target occurrence, forces a clean regeneration, verifies it, and
|
|
125
|
+
falls back to a documented direct patch if the upstream bug is still biting — full
|
|
126
|
+
detail: **[docs/ios-build-engine.md](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/ios-build-engine.md)**. Run `xgem doctor ios`
|
|
127
|
+
any time for a standalone readiness report without doing a build.
|
|
144
128
|
|
|
145
129
|
## Windows support
|
|
146
130
|
|
|
147
|
-
Homebrew and the curl installer are macOS/Linux only, same as any bash tool
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
What works on Windows: `init`/`add`/`run`/`terminate`, `doctor`, the git workflow
|
|
153
|
-
commands, and Flutter builds for **APK, App Bundle, and Windows desktop** targets. What doesn't:
|
|
154
|
-
Flutter **iOS/macOS** builds — Xcode has no Windows equivalent, so `xgem doctor ios`
|
|
155
|
-
explains that plainly instead of pretending. `swift` isn't offered as a framework
|
|
156
|
-
choice on Windows for the same reason. If you're inside WSL, none of this applies —
|
|
157
|
-
WSL reports itself as Linux, so you get the full bash engine automatically.
|
|
158
|
-
|
|
159
|
-
On macOS/Linux, npm installs run the exact same bash engine as Homebrew/curl (`bin/xgem.js`
|
|
160
|
-
is a thin passthrough that execs the real `bin/xgem` script) — there's only one
|
|
161
|
-
implementation to trust on POSIX; Windows is the only platform with a second one.
|
|
131
|
+
Homebrew and the curl installer are macOS/Linux only, same as any bash tool. npm is
|
|
132
|
+
different: it ships a small native Windows engine (`lib-win/`) so `npm install -g
|
|
133
|
+
xgem-cli` actually works in `cmd.exe`/PowerShell, no WSL required — everything except
|
|
134
|
+
Flutter iOS/macOS builds (Xcode has no Windows equivalent) and the project-creation
|
|
135
|
+
wizards (not ported yet). Full detail: **[docs/windows.md](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/windows.md)**.
|
|
162
136
|
|
|
163
137
|
## Roadmap
|
|
164
138
|
|
package/bin/xgem
CHANGED
|
@@ -35,6 +35,16 @@ source "$XGEM_HOME/lib/flutter.sh"
|
|
|
35
35
|
source "$XGEM_HOME/lib/scaffold.sh"
|
|
36
36
|
# shellcheck source=lib/create.sh
|
|
37
37
|
source "$XGEM_HOME/lib/create.sh"
|
|
38
|
+
# shellcheck source=lib/release.sh
|
|
39
|
+
source "$XGEM_HOME/lib/release.sh"
|
|
40
|
+
# shellcheck source=lib/registry.sh
|
|
41
|
+
source "$XGEM_HOME/lib/registry.sh"
|
|
42
|
+
# shellcheck source=lib/status.sh
|
|
43
|
+
source "$XGEM_HOME/lib/status.sh"
|
|
44
|
+
# shellcheck source=lib/bootstrap.sh
|
|
45
|
+
source "$XGEM_HOME/lib/bootstrap.sh"
|
|
46
|
+
# shellcheck source=lib/ci.sh
|
|
47
|
+
source "$XGEM_HOME/lib/ci.sh"
|
|
38
48
|
|
|
39
49
|
CONFIG_DIR=".xgem-automate"
|
|
40
50
|
|
|
@@ -75,6 +85,14 @@ print_usage() {
|
|
|
75
85
|
echo " xgem git branch - Pick, create, or switch branches; remembers your choice"
|
|
76
86
|
echo " xgem git rm-remote - Drop specified target remote tracing rules"
|
|
77
87
|
echo " xgem git rm-branch - Safely drop local and remote workspace branch states"
|
|
88
|
+
echo " xgem git pr - Push current branch and open a GitHub PR (gh-backed)"
|
|
89
|
+
echo " xgem git sync - Rebase current branch onto the repo's base branch"
|
|
90
|
+
echo " xgem git clean-branches - Delete local branches already merged into the base branch"
|
|
91
|
+
echo " xgem git hooks <install|uninstall> - Manage a pre-commit lint/test hook"
|
|
92
|
+
echo " xgem release [major|minor|patch] - Bump version, update CHANGELOG.md, tag, push"
|
|
93
|
+
echo " xgem status - Dashboard across every xgem-tracked project"
|
|
94
|
+
echo " xgem bootstrap - Clone-to-running: detect framework, install, .env, migrate, launch"
|
|
95
|
+
echo " xgem ci - Run lint/test/build for every configured framework, summarized"
|
|
78
96
|
echo " xgem --version - Print xgem's version"
|
|
79
97
|
echo ""
|
|
80
98
|
echo "Flags (any command): --yes (skip confirmations), --dry-run (show, don't apply), --verbose"
|
|
@@ -91,26 +109,18 @@ case "${1:-}" in
|
|
|
91
109
|
PS3="Enter target selection number: "
|
|
92
110
|
select fw in "${ALL_FRAMEWORKS[@]}"; do
|
|
93
111
|
if [ -n "$fw" ]; then
|
|
112
|
+
# create_project_wizard handles ALL of xgem's own
|
|
113
|
+
# bookkeeping (.xgem-automate + .gitignore) internally now,
|
|
114
|
+
# at the earliest safe point for each framework — never
|
|
115
|
+
# after a slow/interruptible step, so a Ctrl-C during (say)
|
|
116
|
+
# `ng new`'s install can no longer lose it. See lib/create.sh.
|
|
94
117
|
create_project_wizard "$fw"
|
|
95
|
-
mkdir -p "$CONFIG_DIR"
|
|
96
|
-
scaffold_inject_templates "$fw" "$CONFIG_DIR"
|
|
97
|
-
log_success "Successfully appended standard scripts for: $CONFIG_DIR/$fw"
|
|
98
118
|
break
|
|
99
119
|
else
|
|
100
120
|
echo "Invalid selection."
|
|
101
121
|
fi
|
|
102
122
|
done
|
|
103
123
|
|
|
104
|
-
if [ -f .gitignore ]; then
|
|
105
|
-
if ! grep -q "$CONFIG_DIR/" .gitignore; then
|
|
106
|
-
echo -e "\n$CONFIG_DIR/" >> .gitignore
|
|
107
|
-
log_success "Added automation tracking to .gitignore"
|
|
108
|
-
fi
|
|
109
|
-
else
|
|
110
|
-
echo "$CONFIG_DIR/" > .gitignore
|
|
111
|
-
log_success "Created .gitignore and hidden tracking layer folder references."
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
124
|
_ask_launch_dev_server
|
|
115
125
|
|
|
116
126
|
# A child process (this script) can never change the parent
|
|
@@ -169,7 +179,7 @@ case "${1:-}" in
|
|
|
169
179
|
else
|
|
170
180
|
scaffold_run_script "$FRAMEWORK" "$SCRIPT_NAME" "$CONFIG_DIR"
|
|
171
181
|
fi
|
|
172
|
-
exit
|
|
182
|
+
exit $?
|
|
173
183
|
;;
|
|
174
184
|
|
|
175
185
|
terminate)
|
|
@@ -186,6 +196,7 @@ case "${1:-}" in
|
|
|
186
196
|
rm -rf "${CONFIG_DIR:?}/$fw"
|
|
187
197
|
done
|
|
188
198
|
rm -rf "$CONFIG_DIR"
|
|
199
|
+
registry_remove "$(pwd)"
|
|
189
200
|
|
|
190
201
|
if [ -f .gitignore ]; then
|
|
191
202
|
grep -v "^$CONFIG_DIR/" .gitignore > tmp_gitignore && mv tmp_gitignore .gitignore
|
|
@@ -197,7 +208,7 @@ case "${1:-}" in
|
|
|
197
208
|
;;
|
|
198
209
|
|
|
199
210
|
git)
|
|
200
|
-
[ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>"
|
|
211
|
+
[ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|branch|rm-remote|rm-branch|pr|sync|clean-branches|hooks>"
|
|
201
212
|
cmd_git "$2" "${3:-}"
|
|
202
213
|
exit 0
|
|
203
214
|
;;
|
|
@@ -207,6 +218,26 @@ case "${1:-}" in
|
|
|
207
218
|
exit 0
|
|
208
219
|
;;
|
|
209
220
|
|
|
221
|
+
release)
|
|
222
|
+
cmd_release "${2:-}"
|
|
223
|
+
exit 0
|
|
224
|
+
;;
|
|
225
|
+
|
|
226
|
+
status)
|
|
227
|
+
cmd_status
|
|
228
|
+
exit 0
|
|
229
|
+
;;
|
|
230
|
+
|
|
231
|
+
bootstrap)
|
|
232
|
+
cmd_bootstrap
|
|
233
|
+
exit 0
|
|
234
|
+
;;
|
|
235
|
+
|
|
236
|
+
ci)
|
|
237
|
+
cmd_ci
|
|
238
|
+
exit $?
|
|
239
|
+
;;
|
|
240
|
+
|
|
210
241
|
--version|-V|version)
|
|
211
242
|
print_version
|
|
212
243
|
exit 0
|
package/bin/xgem.js
CHANGED
|
@@ -21,6 +21,11 @@ const { cmdDoctor } = require('../lib-win/doctor');
|
|
|
21
21
|
const { cmdGit } = require('../lib-win/git');
|
|
22
22
|
const { cmdFlutter } = require('../lib-win/flutter');
|
|
23
23
|
const scaffold = require('../lib-win/scaffold');
|
|
24
|
+
const { cmdRelease } = require('../lib-win/release');
|
|
25
|
+
const { registryAdd, registryRemove } = require('../lib-win/registry');
|
|
26
|
+
const { cmdStatus } = require('../lib-win/status');
|
|
27
|
+
const { cmdBootstrap } = require('../lib-win/bootstrap');
|
|
28
|
+
const { cmdCi } = require('../lib-win/ci');
|
|
24
29
|
|
|
25
30
|
const CONFIG_DIR = '.xgem-automate';
|
|
26
31
|
|
|
@@ -48,6 +53,14 @@ function printUsage() {
|
|
|
48
53
|
console.log(' xgem git branch - Pick, create, or switch branches; remembers your choice');
|
|
49
54
|
console.log(' xgem git rm-remote - Drop specified target remote tracing rules');
|
|
50
55
|
console.log(' xgem git rm-branch - Safely drop local and remote workspace branch states');
|
|
56
|
+
console.log(' xgem git pr - Push current branch and open a GitHub PR (gh-backed)');
|
|
57
|
+
console.log(' xgem git sync - Rebase current branch onto the repo\'s base branch');
|
|
58
|
+
console.log(' xgem git clean-branches - Delete local branches already merged into the base branch');
|
|
59
|
+
console.log(' xgem git hooks <install|uninstall> - Manage a pre-commit lint/test hook');
|
|
60
|
+
console.log(' xgem release [major|minor|patch] - Bump version, update CHANGELOG.md, tag, push');
|
|
61
|
+
console.log(' xgem status - Dashboard across every xgem-tracked project');
|
|
62
|
+
console.log(' xgem bootstrap - Clone-to-running: detect framework, install, .env, migrate, launch');
|
|
63
|
+
console.log(' xgem ci - Run lint/test/build for every configured framework, summarized');
|
|
51
64
|
console.log(' xgem --version - Print xgem\'s version');
|
|
52
65
|
console.log('');
|
|
53
66
|
console.log('Flags (any command): --yes (skip confirmations), --dry-run (show, don\'t apply), --verbose');
|
|
@@ -61,20 +74,6 @@ async function selectFramework(options) {
|
|
|
61
74
|
return options[idx];
|
|
62
75
|
}
|
|
63
76
|
|
|
64
|
-
function updateGitignore() {
|
|
65
|
-
const gitignorePath = '.gitignore';
|
|
66
|
-
if (fs.existsSync(gitignorePath)) {
|
|
67
|
-
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
68
|
-
if (!content.includes(`${CONFIG_DIR}/`)) {
|
|
69
|
-
fs.appendFileSync(gitignorePath, `\n${CONFIG_DIR}/\n`);
|
|
70
|
-
logSuccess('Added automation tracking to .gitignore');
|
|
71
|
-
}
|
|
72
|
-
} else {
|
|
73
|
-
fs.writeFileSync(gitignorePath, `${CONFIG_DIR}/\n`);
|
|
74
|
-
logSuccess('Created .gitignore and hidden tracking layer folder references.');
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
77
|
async function cmdInit() {
|
|
79
78
|
printBanner();
|
|
80
79
|
if (fs.existsSync(CONFIG_DIR)) {
|
|
@@ -82,14 +81,12 @@ async function cmdInit() {
|
|
|
82
81
|
return;
|
|
83
82
|
}
|
|
84
83
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
84
|
+
registryAdd(process.cwd());
|
|
85
85
|
|
|
86
86
|
console.log('Select your starting framework architecture:');
|
|
87
87
|
const fw = await selectFramework(scaffold.ALL_FRAMEWORKS);
|
|
88
88
|
if (!fw) die('Invalid selection.');
|
|
89
|
-
scaffold.
|
|
90
|
-
logSuccess(`Successfully appended standard scripts for: ${CONFIG_DIR}/${fw}`);
|
|
91
|
-
|
|
92
|
-
updateGitignore();
|
|
89
|
+
await scaffold.bookkeeping(fw, CONFIG_DIR);
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
async function cmdAdd() {
|
|
@@ -139,6 +136,7 @@ async function cmdTerminate() {
|
|
|
139
136
|
fs.rmSync(path.join(CONFIG_DIR, fw), { recursive: true, force: true });
|
|
140
137
|
}
|
|
141
138
|
fs.rmSync(CONFIG_DIR, { recursive: true, force: true });
|
|
139
|
+
registryRemove(process.cwd());
|
|
142
140
|
|
|
143
141
|
if (fs.existsSync('.gitignore')) {
|
|
144
142
|
const lines = fs.readFileSync('.gitignore', 'utf8').split(/\r?\n/).filter((l) => l !== `${CONFIG_DIR}/`);
|
|
@@ -188,9 +186,13 @@ async function main() {
|
|
|
188
186
|
case 'run': return cmdRun(a2, a3);
|
|
189
187
|
case 'terminate': return cmdTerminate();
|
|
190
188
|
case 'git':
|
|
191
|
-
if (!a2) die('Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>');
|
|
192
|
-
return cmdGit(a2, a3);
|
|
189
|
+
if (!a2) die('Usage: xgem git <cmt|init|branch|rm-remote|rm-branch|pr|sync|clean-branches|hooks>');
|
|
190
|
+
return cmdGit(a2, a3, CONFIG_DIR);
|
|
193
191
|
case 'doctor': return cmdDoctor(a2);
|
|
192
|
+
case 'release': return cmdRelease(a2);
|
|
193
|
+
case 'status': return cmdStatus(CONFIG_DIR);
|
|
194
|
+
case 'bootstrap': return cmdBootstrap(CONFIG_DIR);
|
|
195
|
+
case 'ci': return cmdCi(CONFIG_DIR);
|
|
194
196
|
case '--version':
|
|
195
197
|
case '-V':
|
|
196
198
|
case 'version': {
|
package/lib/bootstrap.sh
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# xgem bootstrap: clone-to-running in one command, for a project you just
|
|
3
|
+
# checked out (not creating a new one — that's `xgem init`'s job).
|
|
4
|
+
# Depends on lib/logger.sh, lib/utils.sh, lib/scaffold.sh, lib/create.sh.
|
|
5
|
+
|
|
6
|
+
# _detect_framework -> a name from ALL_FRAMEWORKS, or empty if nothing
|
|
7
|
+
# recognizable was found. Never assumes; probes for marker files the same
|
|
8
|
+
# way lib/doctor.sh probes for tools instead of guessing.
|
|
9
|
+
_detect_framework() {
|
|
10
|
+
[ -f pubspec.yaml ] && { echo flutter; return 0; }
|
|
11
|
+
[ -f go.mod ] && { echo go; return 0; }
|
|
12
|
+
[ -f Cargo.toml ] && { echo rust; return 0; }
|
|
13
|
+
{ [ -f pyproject.toml ] || [ -f requirements.txt ] || [ -f setup.py ]; } && { echo python; return 0; }
|
|
14
|
+
[ -f Package.swift ] && { echo swift; return 0; }
|
|
15
|
+
if [ -f package.json ]; then
|
|
16
|
+
if grep -q '"next"' package.json; then echo next
|
|
17
|
+
elif grep -q '"@angular/core"' package.json; then echo angular
|
|
18
|
+
elif grep -q '"vue"' package.json; then echo vue
|
|
19
|
+
elif grep -q '"react"' package.json; then echo react
|
|
20
|
+
else echo node
|
|
21
|
+
fi
|
|
22
|
+
return 0
|
|
23
|
+
fi
|
|
24
|
+
[ -f Dockerfile ] && { echo docker; return 0; }
|
|
25
|
+
return 1
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_bootstrap_env_file() {
|
|
29
|
+
[ -f .env ] && { log_debug ".env already exists, leaving it as-is."; return 0; }
|
|
30
|
+
local example
|
|
31
|
+
for example in .env.example .env.sample; do
|
|
32
|
+
[ -f "$example" ] || continue
|
|
33
|
+
cp "$example" .env
|
|
34
|
+
log_success "Created .env from $example."
|
|
35
|
+
local missing
|
|
36
|
+
missing=$(grep -E '^[A-Za-z_][A-Za-z0-9_]*=[[:space:]]*$' .env | cut -d= -f1)
|
|
37
|
+
if [ -n "$missing" ]; then
|
|
38
|
+
log_warn "These .env keys are empty — fill them in:"
|
|
39
|
+
echo "$missing" | sed 's/^/ - /'
|
|
40
|
+
fi
|
|
41
|
+
return 0
|
|
42
|
+
done
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_bootstrap_node_pm() {
|
|
46
|
+
if [ -f pnpm-lock.yaml ]; then echo pnpm
|
|
47
|
+
elif [ -f yarn.lock ]; then echo yarn
|
|
48
|
+
elif [ -f bun.lockb ] || [ -f bun.lock ]; then echo bun
|
|
49
|
+
else echo npm
|
|
50
|
+
fi
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_bootstrap_install() {
|
|
54
|
+
local fw=$1
|
|
55
|
+
case "$fw" in
|
|
56
|
+
node|react|vue|angular|next)
|
|
57
|
+
local pm
|
|
58
|
+
pm=$(_bootstrap_node_pm)
|
|
59
|
+
log_info "Installing dependencies with $pm..."
|
|
60
|
+
case "$pm" in
|
|
61
|
+
yarn) yarn ;;
|
|
62
|
+
pnpm) pnpm install ;;
|
|
63
|
+
bun) bun install ;;
|
|
64
|
+
*) npm install ;;
|
|
65
|
+
esac
|
|
66
|
+
;;
|
|
67
|
+
flutter)
|
|
68
|
+
has_cmd flutter || { log_warn "flutter not found — skipping 'flutter pub get'."; return 0; }
|
|
69
|
+
log_info "Running flutter pub get..."
|
|
70
|
+
flutter pub get
|
|
71
|
+
;;
|
|
72
|
+
python)
|
|
73
|
+
if [ -f pyproject.toml ] && has_cmd poetry; then
|
|
74
|
+
log_info "Installing dependencies with poetry..."
|
|
75
|
+
poetry install
|
|
76
|
+
elif [ -f requirements.txt ]; then
|
|
77
|
+
has_cmd python3 || { log_warn "python3 not found — skipping install."; return 0; }
|
|
78
|
+
[ -d .venv ] || python3 -m venv .venv
|
|
79
|
+
log_info "Installing dependencies into .venv..."
|
|
80
|
+
.venv/bin/pip install -r requirements.txt
|
|
81
|
+
fi
|
|
82
|
+
;;
|
|
83
|
+
go)
|
|
84
|
+
has_cmd go || { log_warn "go not found — skipping 'go mod download'."; return 0; }
|
|
85
|
+
log_info "Running go mod download..."
|
|
86
|
+
go mod download
|
|
87
|
+
;;
|
|
88
|
+
rust)
|
|
89
|
+
has_cmd cargo || { log_warn "cargo not found — skipping 'cargo fetch'."; return 0; }
|
|
90
|
+
log_info "Running cargo fetch..."
|
|
91
|
+
cargo fetch
|
|
92
|
+
;;
|
|
93
|
+
swift)
|
|
94
|
+
has_cmd swift || { log_warn "swift not found — skipping 'swift package resolve'."; return 0; }
|
|
95
|
+
log_info "Running swift package resolve..."
|
|
96
|
+
swift package resolve
|
|
97
|
+
;;
|
|
98
|
+
docker)
|
|
99
|
+
log_debug "Docker project — nothing to install locally."
|
|
100
|
+
;;
|
|
101
|
+
esac
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_bootstrap_migrations() {
|
|
105
|
+
local fw=$1
|
|
106
|
+
if [ "$fw" = "node" ] || [ "$fw" = "react" ] || [ "$fw" = "vue" ] || [ "$fw" = "angular" ] || [ "$fw" = "next" ]; then
|
|
107
|
+
if _package_json_has_script migrate; then
|
|
108
|
+
local pm
|
|
109
|
+
pm=$(_bootstrap_node_pm)
|
|
110
|
+
confirm "Run the project's 'migrate' script (via $pm)?" || return 0
|
|
111
|
+
case "$pm" in
|
|
112
|
+
yarn) yarn migrate ;;
|
|
113
|
+
pnpm) pnpm run migrate ;;
|
|
114
|
+
bun) bun run migrate ;;
|
|
115
|
+
*) npm run migrate ;;
|
|
116
|
+
esac
|
|
117
|
+
return 0
|
|
118
|
+
fi
|
|
119
|
+
fi
|
|
120
|
+
if [ -f prisma/schema.prisma ]; then
|
|
121
|
+
confirm "Run 'npx prisma migrate dev'?" && npx prisma migrate dev
|
|
122
|
+
elif [ -f manage.py ]; then
|
|
123
|
+
has_cmd python3 && confirm "Run 'python3 manage.py migrate'?" && python3 manage.py migrate
|
|
124
|
+
fi
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_bootstrap_offer_dev_server() {
|
|
128
|
+
local fw=$1
|
|
129
|
+
local script=""
|
|
130
|
+
case "$fw" in
|
|
131
|
+
node) script=start ;;
|
|
132
|
+
react|vue|angular|next) script=dev ;;
|
|
133
|
+
*) return 0 ;;
|
|
134
|
+
esac
|
|
135
|
+
[ -f "$CONFIG_DIR/$fw/$script.sh" ] || return 0
|
|
136
|
+
confirm "Launch the dev server now ('xgem run $fw $script')?" && scaffold_run_script "$fw" "$script" "$CONFIG_DIR"
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
cmd_bootstrap() {
|
|
140
|
+
log_info "Detecting project framework..."
|
|
141
|
+
local fw
|
|
142
|
+
fw=$(_detect_framework)
|
|
143
|
+
if [ -z "$fw" ]; then
|
|
144
|
+
log_warn "Could not auto-detect the framework from any known marker file."
|
|
145
|
+
echo "Pick one:"
|
|
146
|
+
PS3="Enter target selection number: "
|
|
147
|
+
select fw in "${ALL_FRAMEWORKS[@]}"; do
|
|
148
|
+
[ -n "$fw" ] && break
|
|
149
|
+
echo "Invalid selection."
|
|
150
|
+
done
|
|
151
|
+
else
|
|
152
|
+
log_success "Detected: $fw"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
_bootstrap_env_file
|
|
156
|
+
_bootstrap_install "$fw"
|
|
157
|
+
_bootstrap_migrations "$fw"
|
|
158
|
+
|
|
159
|
+
if [ ! -d "$CONFIG_DIR" ]; then
|
|
160
|
+
confirm "Scaffold xgem automation scripts (.xgem-automate) for $fw too?" && _xgem_bookkeeping "$fw"
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
_bootstrap_offer_dev_server "$fw"
|
|
164
|
+
log_success "Bootstrap complete."
|
|
165
|
+
}
|
package/lib/ci.sh
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# xgem ci: run lint -> test -> build for every configured framework before
|
|
3
|
+
# you push, so a CI failure gets caught locally first.
|
|
4
|
+
# Depends on lib/logger.sh.
|
|
5
|
+
|
|
6
|
+
cmd_ci() {
|
|
7
|
+
[ -d "$CONFIG_DIR" ] || die "No $CONFIG_DIR found — run 'xgem init' or 'xgem add' first."
|
|
8
|
+
|
|
9
|
+
local -a steps=(lint test build)
|
|
10
|
+
local -a results=()
|
|
11
|
+
local overall_status=0
|
|
12
|
+
local fw_dir fw step
|
|
13
|
+
|
|
14
|
+
for fw_dir in "$CONFIG_DIR"/*/; do
|
|
15
|
+
[ -d "$fw_dir" ] || continue
|
|
16
|
+
fw=$(basename "$fw_dir")
|
|
17
|
+
for step in "${steps[@]}"; do
|
|
18
|
+
[ -f "$CONFIG_DIR/$fw/$step.sh" ] || continue
|
|
19
|
+
log_info "Running $fw $step..."
|
|
20
|
+
if bash "$CONFIG_DIR/$fw/$step.sh"; then
|
|
21
|
+
results+=("PASS $fw $step")
|
|
22
|
+
else
|
|
23
|
+
results+=("FAIL $fw $step")
|
|
24
|
+
overall_status=1
|
|
25
|
+
fi
|
|
26
|
+
done
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
if [ ${#results[@]} -eq 0 ]; then
|
|
30
|
+
log_warn "No lint/test/build scripts found under $CONFIG_DIR to run."
|
|
31
|
+
return 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo "=== xgem ci summary ==="
|
|
36
|
+
printf '%s\n' "${results[@]}"
|
|
37
|
+
|
|
38
|
+
if [ "$overall_status" -eq 0 ]; then
|
|
39
|
+
log_success "All checks passed."
|
|
40
|
+
else
|
|
41
|
+
log_error "Some checks failed."
|
|
42
|
+
fi
|
|
43
|
+
return "$overall_status"
|
|
44
|
+
}
|