sloss-cli 1.2.2 → 1.3.1
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/bin/sloss.js +4 -4
- package/build.sh +274 -0
- package/package.json +2 -1
- package/src/commands/build.js +28 -103
package/bin/sloss.js
CHANGED
|
@@ -120,15 +120,15 @@ program
|
|
|
120
120
|
// Build command
|
|
121
121
|
program
|
|
122
122
|
.command('build')
|
|
123
|
-
.description('
|
|
123
|
+
.description('Run a local EAS build and upload to Sloss')
|
|
124
124
|
.option('--platform <platform>', 'Platform (ios or android)', 'ios')
|
|
125
125
|
.option('--profile <profile>', 'Build profile (development, preview, production)', 'development')
|
|
126
126
|
.option('--bump <type>', 'Version bump type for production (patch, minor, major)', 'patch')
|
|
127
|
-
.option('--dir <path>', 'Project directory (default: current directory)'
|
|
127
|
+
.option('--dir <path>', 'Project directory (default: current directory)')
|
|
128
|
+
.option('--yes', 'Skip confirmation prompt')
|
|
128
129
|
.action(async (options) => {
|
|
129
130
|
try {
|
|
130
|
-
|
|
131
|
-
await buildCommand(options, config);
|
|
131
|
+
await buildCommand(options);
|
|
132
132
|
} catch (error) {
|
|
133
133
|
console.error(`Error: ${error.message}`);
|
|
134
134
|
process.exit(1);
|
package/build.sh
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# sloss build — Local EAS build + Sloss upload for Expo apps
|
|
3
|
+
# Invoked by the `sloss build` Node CLI command.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
# ─── Defaults ───────────────────────────────────────────────────────────────
|
|
7
|
+
PLATFORM="ios"
|
|
8
|
+
PROFILE="development"
|
|
9
|
+
BUMP="patch"
|
|
10
|
+
PROJECT_DIR="$(pwd)"
|
|
11
|
+
YES=false
|
|
12
|
+
|
|
13
|
+
# ─── Flag parsing ───────────────────────────────────────────────────────────
|
|
14
|
+
while [[ $# -gt 0 ]]; do
|
|
15
|
+
case "$1" in
|
|
16
|
+
--platform) PLATFORM="$2"; shift 2 ;;
|
|
17
|
+
--profile) PROFILE="$2"; shift 2 ;;
|
|
18
|
+
--bump) BUMP="$2"; shift 2 ;;
|
|
19
|
+
--dir) PROJECT_DIR="$2"; shift 2 ;;
|
|
20
|
+
--yes|-y) YES=true; shift ;;
|
|
21
|
+
--help|-h)
|
|
22
|
+
echo "Usage: sloss build [options]"
|
|
23
|
+
echo ""
|
|
24
|
+
echo "Options:"
|
|
25
|
+
echo " --platform ios|android Target platform (default: ios)"
|
|
26
|
+
echo " --profile <name> EAS build profile (default: development)"
|
|
27
|
+
echo " --bump patch|minor|major Version bump type (default: patch)"
|
|
28
|
+
echo " --dir <path> Project directory (default: cwd)"
|
|
29
|
+
echo " --yes, -y Skip confirmation prompt"
|
|
30
|
+
echo " --help, -h Show this help"
|
|
31
|
+
exit 0
|
|
32
|
+
;;
|
|
33
|
+
*) echo "Unknown flag: $1"; exit 1 ;;
|
|
34
|
+
esac
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
# ─── Helpers ────────────────────────────────────────────────────────────────
|
|
38
|
+
# Use node for all JSON parsing (jq not guaranteed).
|
|
39
|
+
json_get() {
|
|
40
|
+
# json_get <file> <key> — read a top-level string value
|
|
41
|
+
node -e "const f=require('fs').readFileSync('$1','utf8'); console.log(JSON.parse(f)['$2'])"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
json_set() {
|
|
45
|
+
# json_set <file> <key> <value> — set a top-level string value, preserve formatting
|
|
46
|
+
node -e "
|
|
47
|
+
const fs=require('fs'), p='$1', k='$2', v='$3';
|
|
48
|
+
const obj=JSON.parse(fs.readFileSync(p,'utf8'));
|
|
49
|
+
obj[k]=v;
|
|
50
|
+
fs.writeFileSync(p, JSON.stringify(obj, null, 2)+'\n');
|
|
51
|
+
"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
json_nested() {
|
|
55
|
+
# json_nested <file> <path.to.key> — read a nested value via dot path
|
|
56
|
+
node -e "
|
|
57
|
+
const fs=require('fs'), p='$1', keys='$2'.split('.');
|
|
58
|
+
let obj=JSON.parse(fs.readFileSync(p,'utf8'));
|
|
59
|
+
for(const k of keys) obj=obj[k];
|
|
60
|
+
console.log(obj);
|
|
61
|
+
"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
plist_set() {
|
|
65
|
+
# plist_set <file> <key> <value> — update a value in an XML plist
|
|
66
|
+
/usr/libexec/PlistBuddy -c "Set :$2 $3" "$1" 2>/dev/null || \
|
|
67
|
+
sed -i '' "s|<key>$2</key>.*<string>[^<]*</string>|<key>$2</key>\n\t<string>$3</string>|" "$1"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
bump_version() {
|
|
71
|
+
# bump_version <current> <patch|minor|major> → new version string
|
|
72
|
+
node -e "
|
|
73
|
+
const [M,m,p]='$1'.split('.').map(Number);
|
|
74
|
+
const t='$2';
|
|
75
|
+
if(t==='major') console.log((M+1)+'.0.0');
|
|
76
|
+
else if(t==='minor') console.log(M+'.'+(m+1)+'.0');
|
|
77
|
+
else console.log(M+'.'+m+'.'+(p+1));
|
|
78
|
+
"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# ─── Validate inputs ───────────────────────────────────────────────────────
|
|
82
|
+
if [[ "$PLATFORM" != "ios" && "$PLATFORM" != "android" ]]; then
|
|
83
|
+
echo "Error: --platform must be ios or android"; exit 1
|
|
84
|
+
fi
|
|
85
|
+
if [[ "$BUMP" != "patch" && "$BUMP" != "minor" && "$BUMP" != "major" ]]; then
|
|
86
|
+
echo "Error: --bump must be patch, minor, or major"; exit 1
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ─── Read .sloss.json ──────────────────────────────────────────────────────
|
|
90
|
+
CONFIG="$PROJECT_DIR/.sloss.json"
|
|
91
|
+
if [[ ! -f "$CONFIG" ]]; then
|
|
92
|
+
echo "Error: No .sloss.json found in $PROJECT_DIR"
|
|
93
|
+
exit 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
APP_NAME=$(json_get "$CONFIG" "app_name")
|
|
97
|
+
BUNDLE_ID=$(json_get "$CONFIG" "bundle_id")
|
|
98
|
+
VERSION_FILE="$PROJECT_DIR/$(json_get "$CONFIG" "version_file")"
|
|
99
|
+
IOS_PLIST="$PROJECT_DIR/$(json_get "$CONFIG" "ios_plist")"
|
|
100
|
+
BUNDLE_SUFFIX=$(json_nested "$CONFIG" "profiles.$PROFILE.bundle_id_suffix")
|
|
101
|
+
|
|
102
|
+
FULL_BUNDLE_ID="${BUNDLE_ID}${BUNDLE_SUFFIX}"
|
|
103
|
+
|
|
104
|
+
# ─── Read current version info ─────────────────────────────────────────────
|
|
105
|
+
CURRENT_VERSION=$(json_get "$VERSION_FILE" "version")
|
|
106
|
+
CURRENT_BUILD=$(json_get "$VERSION_FILE" "buildNumber")
|
|
107
|
+
NEW_BUILD=$((CURRENT_BUILD + 1))
|
|
108
|
+
|
|
109
|
+
# Marketing version bump (production only)
|
|
110
|
+
if [[ "$PROFILE" == "production" ]]; then
|
|
111
|
+
NEW_VERSION=$(bump_version "$CURRENT_VERSION" "$BUMP")
|
|
112
|
+
else
|
|
113
|
+
NEW_VERSION="$CURRENT_VERSION"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# ─── Confirmation ───────────────────────────────────────────────────────────
|
|
117
|
+
echo ""
|
|
118
|
+
echo "╔══════════════════════════════════════════╗"
|
|
119
|
+
echo "║ Sloss Build Summary ║"
|
|
120
|
+
echo "╠══════════════════════════════════════════╣"
|
|
121
|
+
echo "║ App: $APP_NAME"
|
|
122
|
+
echo "║ Bundle ID: $FULL_BUNDLE_ID"
|
|
123
|
+
echo "║ Platform: $PLATFORM"
|
|
124
|
+
echo "║ Profile: $PROFILE"
|
|
125
|
+
echo "║ Version: $CURRENT_VERSION → $NEW_VERSION"
|
|
126
|
+
echo "║ Build: $CURRENT_BUILD → $NEW_BUILD"
|
|
127
|
+
echo "╚══════════════════════════════════════════╝"
|
|
128
|
+
echo ""
|
|
129
|
+
|
|
130
|
+
if [[ "$YES" != true ]]; then
|
|
131
|
+
read -r -p "Proceed? [y/N] " confirm
|
|
132
|
+
if [[ "$confirm" != [yY] && "$confirm" != [yY][eE][sS] ]]; then
|
|
133
|
+
echo "Aborted."
|
|
134
|
+
exit 0
|
|
135
|
+
fi
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# ─── Bump versions ─────────────────────────────────────────────────────────
|
|
139
|
+
echo "📦 Bumping build number: $CURRENT_BUILD → $NEW_BUILD"
|
|
140
|
+
json_set "$VERSION_FILE" "buildNumber" "$NEW_BUILD"
|
|
141
|
+
|
|
142
|
+
# Update Info.plist CFBundleVersion
|
|
143
|
+
if [[ -f "$IOS_PLIST" ]]; then
|
|
144
|
+
plist_set "$IOS_PLIST" "CFBundleVersion" "$NEW_BUILD"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
if [[ "$PROFILE" == "production" ]]; then
|
|
148
|
+
echo "📦 Bumping marketing version: $CURRENT_VERSION → $NEW_VERSION ($BUMP)"
|
|
149
|
+
json_set "$VERSION_FILE" "version" "$NEW_VERSION"
|
|
150
|
+
if [[ -f "$IOS_PLIST" ]]; then
|
|
151
|
+
plist_set "$IOS_PLIST" "CFBundleShortVersionString" "$NEW_VERSION"
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# ─── Run EAS build ──────────────────────────────────────────────────────────
|
|
156
|
+
echo ""
|
|
157
|
+
echo "🔨 Starting EAS local build..."
|
|
158
|
+
echo " eas build --profile $PROFILE --platform $PLATFORM --local --non-interactive"
|
|
159
|
+
echo ""
|
|
160
|
+
|
|
161
|
+
BUILD_LOG=$(mktemp)
|
|
162
|
+
ARTIFACT_PATH=""
|
|
163
|
+
|
|
164
|
+
# Run build, tee output so user sees it and we can parse it
|
|
165
|
+
set +e
|
|
166
|
+
(cd "$PROJECT_DIR" && eas build --profile "$PROFILE" --platform "$PLATFORM" --local --non-interactive 2>&1) | tee "$BUILD_LOG"
|
|
167
|
+
BUILD_EXIT=${PIPESTATUS[0]}
|
|
168
|
+
set -e
|
|
169
|
+
|
|
170
|
+
if [[ $BUILD_EXIT -ne 0 ]]; then
|
|
171
|
+
echo ""
|
|
172
|
+
echo "❌ EAS build failed (exit code $BUILD_EXIT). Skipping upload."
|
|
173
|
+
rm -f "$BUILD_LOG"
|
|
174
|
+
exit 1
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# ─── Find artifact ──────────────────────────────────────────────────────────
|
|
178
|
+
# EAS outputs lines like:
|
|
179
|
+
# "Build artifact: /path/to/build-xxxx.ipa"
|
|
180
|
+
# or the artifact path on its own line ending in .ipa/.apk
|
|
181
|
+
if [[ "$PLATFORM" == "ios" ]]; then
|
|
182
|
+
EXT="ipa"
|
|
183
|
+
else
|
|
184
|
+
EXT="apk"
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
ARTIFACT_PATH=$(grep -oE '/[^ ]+\.'$EXT "$BUILD_LOG" | tail -1 || true)
|
|
188
|
+
|
|
189
|
+
# Fallback: check common EAS output directory
|
|
190
|
+
if [[ -z "$ARTIFACT_PATH" || ! -f "$ARTIFACT_PATH" ]]; then
|
|
191
|
+
ARTIFACT_PATH=$(find "$PROJECT_DIR" -maxdepth 1 -name "*.$EXT" -newer "$VERSION_FILE" -print -quit 2>/dev/null || true)
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
rm -f "$BUILD_LOG"
|
|
195
|
+
|
|
196
|
+
if [[ -z "$ARTIFACT_PATH" || ! -f "$ARTIFACT_PATH" ]]; then
|
|
197
|
+
echo ""
|
|
198
|
+
echo "⚠️ Could not locate build artifact. Check the build output above."
|
|
199
|
+
echo " Expected a .$EXT file."
|
|
200
|
+
exit 1
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
echo ""
|
|
204
|
+
echo "✅ Build artifact: $ARTIFACT_PATH"
|
|
205
|
+
|
|
206
|
+
# ─── Upload to Sloss ───────────────────────────────────────────────────────
|
|
207
|
+
echo ""
|
|
208
|
+
echo "📤 Uploading to Sloss..."
|
|
209
|
+
|
|
210
|
+
# Resolve Sloss URL and API key
|
|
211
|
+
UPLOAD_URL="${SLOSS_URL:-https://sloss.ngrok.app}/upload"
|
|
212
|
+
|
|
213
|
+
if [[ -z "${SLOSS_API_KEY:-}" ]]; then
|
|
214
|
+
CREDS_FILE="$HOME/.config/sloss/credentials.json"
|
|
215
|
+
if [[ -f "$CREDS_FILE" ]]; then
|
|
216
|
+
SLOSS_API_KEY=$(node -e "console.log(JSON.parse(require('fs').readFileSync('$CREDS_FILE','utf8')).api_key)")
|
|
217
|
+
else
|
|
218
|
+
echo "❌ No SLOSS_API_KEY env var and no ~/.config/sloss/credentials.json found."
|
|
219
|
+
echo " Artifact is at: $ARTIFACT_PATH"
|
|
220
|
+
exit 1
|
|
221
|
+
fi
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
# Upload — field name is 'ipa' for iOS, 'apk' for Android
|
|
225
|
+
FIELD_NAME="$EXT"
|
|
226
|
+
set +e
|
|
227
|
+
UPLOAD_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
|
228
|
+
-H "Authorization: Bearer $SLOSS_API_KEY" \
|
|
229
|
+
-F "${FIELD_NAME}=@${ARTIFACT_PATH}" \
|
|
230
|
+
-F "app_name=${APP_NAME}" \
|
|
231
|
+
-F "bundle_id=${FULL_BUNDLE_ID}" \
|
|
232
|
+
-F "version=${NEW_VERSION}" \
|
|
233
|
+
-F "build_number=${NEW_BUILD}" \
|
|
234
|
+
-F "profile=${PROFILE}" \
|
|
235
|
+
"$UPLOAD_URL")
|
|
236
|
+
UPLOAD_EXIT=$?
|
|
237
|
+
set -e
|
|
238
|
+
|
|
239
|
+
if [[ $UPLOAD_EXIT -ne 0 ]]; then
|
|
240
|
+
echo "❌ Upload failed (curl error)."
|
|
241
|
+
echo " Artifact is at: $ARTIFACT_PATH"
|
|
242
|
+
exit 1
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
HTTP_CODE=$(echo "$UPLOAD_RESPONSE" | tail -1)
|
|
246
|
+
RESPONSE_BODY=$(echo "$UPLOAD_RESPONSE" | sed '$d')
|
|
247
|
+
|
|
248
|
+
if [[ "$HTTP_CODE" -lt 200 || "$HTTP_CODE" -ge 300 ]]; then
|
|
249
|
+
echo "❌ Upload failed (HTTP $HTTP_CODE)."
|
|
250
|
+
echo " $RESPONSE_BODY"
|
|
251
|
+
echo " Artifact is at: $ARTIFACT_PATH"
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# ─── Print results ──────────────────────────────────────────────────────────
|
|
256
|
+
PAGE_URL=$(node -e "try{console.log(JSON.parse(process.argv[1]).page_url||'')}catch{console.log('')}" "$RESPONSE_BODY")
|
|
257
|
+
INSTALL_URL=$(node -e "try{console.log(JSON.parse(process.argv[1]).install_url||'')}catch{console.log('')}" "$RESPONSE_BODY")
|
|
258
|
+
|
|
259
|
+
echo ""
|
|
260
|
+
echo "╔══════════════════════════════════════════╗"
|
|
261
|
+
echo "║ 🎉 Build Complete! ║"
|
|
262
|
+
echo "╠══════════════════════════════════════════╣"
|
|
263
|
+
echo "║ App: $APP_NAME"
|
|
264
|
+
echo "║ Version: $NEW_VERSION ($NEW_BUILD)"
|
|
265
|
+
echo "║ Profile: $PROFILE"
|
|
266
|
+
echo "║ Platform: $PLATFORM"
|
|
267
|
+
echo "║ Artifact: $ARTIFACT_PATH"
|
|
268
|
+
if [[ -n "$PAGE_URL" ]]; then
|
|
269
|
+
echo "║ Page: $PAGE_URL"
|
|
270
|
+
fi
|
|
271
|
+
if [[ -n "$INSTALL_URL" ]]; then
|
|
272
|
+
echo "║ Install: $INSTALL_URL"
|
|
273
|
+
fi
|
|
274
|
+
echo "╚══════════════════════════════════════════╝"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sloss-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "CLI for Sloss — a self-hosted IPA/APK distribution server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
11
|
"src/",
|
|
12
|
+
"build.sh",
|
|
12
13
|
"skills/",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
package/src/commands/build.js
CHANGED
|
@@ -1,115 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Build command
|
|
2
|
+
* Build command — thin wrapper that execs cli/build.sh with CLI flags passed through.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { execSync } from 'child_process';
|
|
9
|
-
import { tmpdir } from 'os';
|
|
10
|
-
import { join } from 'path';
|
|
11
|
-
import { formatBuild } from '../format.js';
|
|
5
|
+
import { resolve, dirname, join } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { execFileSync } from 'child_process';
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const profile = (options.profile || 'development').toLowerCase();
|
|
16
|
-
const bump = options.bump || 'patch';
|
|
17
|
-
const projectDir = resolve(options.dir || '.');
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const BUILD_SCRIPT = resolve(__dirname, '../../build.sh');
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
throw new Error('Platform must be "ios" or "android"');
|
|
22
|
-
}
|
|
12
|
+
export async function buildCommand(options) {
|
|
13
|
+
const args = [];
|
|
23
14
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
throw new Error('Profile must be "development", "preview", or "production"');
|
|
15
|
+
if (options.platform) {
|
|
16
|
+
args.push('--platform', options.platform);
|
|
27
17
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const slossConfigPath = join(projectDir, '.sloss.json');
|
|
31
|
-
if (!existsSync(slossConfigPath)) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`.sloss.json not found in ${projectDir}\n` +
|
|
34
|
-
' Create a .sloss.json config file in your project root.\n' +
|
|
35
|
-
' See: https://github.com/aualdrich/sloss#build-agent'
|
|
36
|
-
);
|
|
18
|
+
if (options.profile) {
|
|
19
|
+
args.push('--profile', options.profile);
|
|
37
20
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const slossConfig = JSON.parse(readFileSync(slossConfigPath, 'utf8'));
|
|
41
|
-
|
|
42
|
-
console.log('╔══════════════════════════════════════════╗');
|
|
43
|
-
console.log('║ SLOSS BUILD ║');
|
|
44
|
-
console.log('╠══════════════════════════════════════════╣');
|
|
45
|
-
console.log(`║ app : ${(slossConfig.app_name || '—').padEnd(27)} ║`);
|
|
46
|
-
console.log(`║ platform : ${platform.padEnd(27)} ║`);
|
|
47
|
-
console.log(`║ profile : ${profile.padEnd(27)} ║`);
|
|
48
|
-
console.log(`║ bump : ${bump.padEnd(27)} ║`);
|
|
49
|
-
console.log(`║ server : ${config.baseUrl.padEnd(27)} ║`);
|
|
50
|
-
console.log('╚══════════════════════════════════════════╝');
|
|
51
|
-
console.log('');
|
|
52
|
-
|
|
53
|
-
// Create tarball
|
|
54
|
-
console.log('📦 Packaging project...');
|
|
55
|
-
const tarballPath = join(tmpdir(), `sloss-build-${Date.now()}.tar.gz`);
|
|
56
|
-
|
|
57
|
-
// Use git archive if in a git repo (respects .gitignore), otherwise tar with excludes
|
|
58
|
-
let tarCmd;
|
|
59
|
-
try {
|
|
60
|
-
execSync('git rev-parse --git-dir', { cwd: projectDir, stdio: 'pipe' });
|
|
61
|
-
// git archive from the repo root, only including the project subdir if needed
|
|
62
|
-
const gitRoot = execSync('git rev-parse --show-toplevel', { cwd: projectDir, encoding: 'utf8' }).trim();
|
|
63
|
-
const relPath = projectDir.replace(gitRoot, '').replace(/^\//, '');
|
|
64
|
-
|
|
65
|
-
if (relPath) {
|
|
66
|
-
// Project is in a subdirectory — include only that dir
|
|
67
|
-
tarCmd = `cd "${gitRoot}" && git archive --format=tar HEAD -- "${relPath}" | gzip > "${tarballPath}"`;
|
|
68
|
-
} else {
|
|
69
|
-
tarCmd = `cd "${projectDir}" && git archive --format=tar.gz HEAD > "${tarballPath}"`;
|
|
70
|
-
}
|
|
71
|
-
} catch {
|
|
72
|
-
// Not a git repo — fall back to tar with common excludes
|
|
73
|
-
tarCmd = `cd "${projectDir}" && tar czf "${tarballPath}" --exclude=node_modules --exclude=.git --exclude=ios/build --exclude=android/build .`;
|
|
21
|
+
if (options.bump) {
|
|
22
|
+
args.push('--bump', options.bump);
|
|
74
23
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const tarSize = statSync(tarballPath).size;
|
|
81
|
-
const sizeMB = (tarSize / (1024 * 1024)).toFixed(1);
|
|
82
|
-
console.log(` → ${sizeMB} MB`);
|
|
83
|
-
|
|
84
|
-
// Read version info from .sloss.json's version_file
|
|
85
|
-
let version = '';
|
|
86
|
-
let buildNumber = '';
|
|
87
|
-
if (slossConfig.version_file) {
|
|
88
|
-
const versionFilePath = join(projectDir, slossConfig.version_file);
|
|
89
|
-
if (existsSync(versionFilePath)) {
|
|
90
|
-
const versionData = JSON.parse(readFileSync(versionFilePath, 'utf8'));
|
|
91
|
-
version = versionData.version || '';
|
|
92
|
-
buildNumber = versionData.buildNumber || '';
|
|
93
|
-
}
|
|
24
|
+
if (options.dir) {
|
|
25
|
+
args.push('--dir', resolve(options.dir));
|
|
26
|
+
}
|
|
27
|
+
if (options.yes) {
|
|
28
|
+
args.push('--yes');
|
|
94
29
|
}
|
|
95
30
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
version,
|
|
106
|
-
buildNumber,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Clean up tarball
|
|
110
|
-
const { unlinkSync } = await import('fs');
|
|
111
|
-
try { unlinkSync(tarballPath); } catch { /* ignore */ }
|
|
112
|
-
|
|
113
|
-
console.log('');
|
|
114
|
-
console.log(formatBuild(result, config.jsonMode));
|
|
31
|
+
try {
|
|
32
|
+
execFileSync('bash', [BUILD_SCRIPT, ...args], {
|
|
33
|
+
stdio: 'inherit',
|
|
34
|
+
env: process.env,
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
// build.sh handles its own error messages; just exit with the same code
|
|
38
|
+
process.exit(error.status || 1);
|
|
39
|
+
}
|
|
115
40
|
}
|