@huoye/app-ship 0.1.0 → 0.1.2
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/LICENSE +57 -0
- package/README.md +315 -299
- package/dist/cli.js +931 -519
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +927 -515
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -41
- package/dist/index.d.ts +141 -41
- package/dist/index.js +927 -515
- package/dist/index.js.map +1 -1
- package/package.json +37 -9
package/dist/cli.js
CHANGED
|
@@ -7,25 +7,519 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
// src/utils/upload-manager.ts
|
|
10
|
-
import
|
|
10
|
+
import path10 from "path";
|
|
11
|
+
|
|
12
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
13
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
14
|
+
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
15
|
+
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
16
|
+
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
17
|
+
var styles = {
|
|
18
|
+
modifier: {
|
|
19
|
+
reset: [0, 0],
|
|
20
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
21
|
+
bold: [1, 22],
|
|
22
|
+
dim: [2, 22],
|
|
23
|
+
italic: [3, 23],
|
|
24
|
+
underline: [4, 24],
|
|
25
|
+
overline: [53, 55],
|
|
26
|
+
inverse: [7, 27],
|
|
27
|
+
hidden: [8, 28],
|
|
28
|
+
strikethrough: [9, 29]
|
|
29
|
+
},
|
|
30
|
+
color: {
|
|
31
|
+
black: [30, 39],
|
|
32
|
+
red: [31, 39],
|
|
33
|
+
green: [32, 39],
|
|
34
|
+
yellow: [33, 39],
|
|
35
|
+
blue: [34, 39],
|
|
36
|
+
magenta: [35, 39],
|
|
37
|
+
cyan: [36, 39],
|
|
38
|
+
white: [37, 39],
|
|
39
|
+
// Bright color
|
|
40
|
+
blackBright: [90, 39],
|
|
41
|
+
gray: [90, 39],
|
|
42
|
+
// Alias of `blackBright`
|
|
43
|
+
grey: [90, 39],
|
|
44
|
+
// Alias of `blackBright`
|
|
45
|
+
redBright: [91, 39],
|
|
46
|
+
greenBright: [92, 39],
|
|
47
|
+
yellowBright: [93, 39],
|
|
48
|
+
blueBright: [94, 39],
|
|
49
|
+
magentaBright: [95, 39],
|
|
50
|
+
cyanBright: [96, 39],
|
|
51
|
+
whiteBright: [97, 39]
|
|
52
|
+
},
|
|
53
|
+
bgColor: {
|
|
54
|
+
bgBlack: [40, 49],
|
|
55
|
+
bgRed: [41, 49],
|
|
56
|
+
bgGreen: [42, 49],
|
|
57
|
+
bgYellow: [43, 49],
|
|
58
|
+
bgBlue: [44, 49],
|
|
59
|
+
bgMagenta: [45, 49],
|
|
60
|
+
bgCyan: [46, 49],
|
|
61
|
+
bgWhite: [47, 49],
|
|
62
|
+
// Bright color
|
|
63
|
+
bgBlackBright: [100, 49],
|
|
64
|
+
bgGray: [100, 49],
|
|
65
|
+
// Alias of `bgBlackBright`
|
|
66
|
+
bgGrey: [100, 49],
|
|
67
|
+
// Alias of `bgBlackBright`
|
|
68
|
+
bgRedBright: [101, 49],
|
|
69
|
+
bgGreenBright: [102, 49],
|
|
70
|
+
bgYellowBright: [103, 49],
|
|
71
|
+
bgBlueBright: [104, 49],
|
|
72
|
+
bgMagentaBright: [105, 49],
|
|
73
|
+
bgCyanBright: [106, 49],
|
|
74
|
+
bgWhiteBright: [107, 49]
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
78
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
79
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
80
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
81
|
+
function assembleStyles() {
|
|
82
|
+
const codes = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
84
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
85
|
+
styles[styleName] = {
|
|
86
|
+
open: `\x1B[${style[0]}m`,
|
|
87
|
+
close: `\x1B[${style[1]}m`
|
|
88
|
+
};
|
|
89
|
+
group[styleName] = styles[styleName];
|
|
90
|
+
codes.set(style[0], style[1]);
|
|
91
|
+
}
|
|
92
|
+
Object.defineProperty(styles, groupName, {
|
|
93
|
+
value: group,
|
|
94
|
+
enumerable: false
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
Object.defineProperty(styles, "codes", {
|
|
98
|
+
value: codes,
|
|
99
|
+
enumerable: false
|
|
100
|
+
});
|
|
101
|
+
styles.color.close = "\x1B[39m";
|
|
102
|
+
styles.bgColor.close = "\x1B[49m";
|
|
103
|
+
styles.color.ansi = wrapAnsi16();
|
|
104
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
105
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
106
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
107
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
108
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
109
|
+
Object.defineProperties(styles, {
|
|
110
|
+
rgbToAnsi256: {
|
|
111
|
+
value(red, green, blue) {
|
|
112
|
+
if (red === green && green === blue) {
|
|
113
|
+
if (red < 8) {
|
|
114
|
+
return 16;
|
|
115
|
+
}
|
|
116
|
+
if (red > 248) {
|
|
117
|
+
return 231;
|
|
118
|
+
}
|
|
119
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
120
|
+
}
|
|
121
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
122
|
+
},
|
|
123
|
+
enumerable: false
|
|
124
|
+
},
|
|
125
|
+
hexToRgb: {
|
|
126
|
+
value(hex) {
|
|
127
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
128
|
+
if (!matches) {
|
|
129
|
+
return [0, 0, 0];
|
|
130
|
+
}
|
|
131
|
+
let [colorString] = matches;
|
|
132
|
+
if (colorString.length === 3) {
|
|
133
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
134
|
+
}
|
|
135
|
+
const integer = Number.parseInt(colorString, 16);
|
|
136
|
+
return [
|
|
137
|
+
/* eslint-disable no-bitwise */
|
|
138
|
+
integer >> 16 & 255,
|
|
139
|
+
integer >> 8 & 255,
|
|
140
|
+
integer & 255
|
|
141
|
+
/* eslint-enable no-bitwise */
|
|
142
|
+
];
|
|
143
|
+
},
|
|
144
|
+
enumerable: false
|
|
145
|
+
},
|
|
146
|
+
hexToAnsi256: {
|
|
147
|
+
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
148
|
+
enumerable: false
|
|
149
|
+
},
|
|
150
|
+
ansi256ToAnsi: {
|
|
151
|
+
value(code) {
|
|
152
|
+
if (code < 8) {
|
|
153
|
+
return 30 + code;
|
|
154
|
+
}
|
|
155
|
+
if (code < 16) {
|
|
156
|
+
return 90 + (code - 8);
|
|
157
|
+
}
|
|
158
|
+
let red;
|
|
159
|
+
let green;
|
|
160
|
+
let blue;
|
|
161
|
+
if (code >= 232) {
|
|
162
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
163
|
+
green = red;
|
|
164
|
+
blue = red;
|
|
165
|
+
} else {
|
|
166
|
+
code -= 16;
|
|
167
|
+
const remainder = code % 36;
|
|
168
|
+
red = Math.floor(code / 36) / 5;
|
|
169
|
+
green = Math.floor(remainder / 6) / 5;
|
|
170
|
+
blue = remainder % 6 / 5;
|
|
171
|
+
}
|
|
172
|
+
const value = Math.max(red, green, blue) * 2;
|
|
173
|
+
if (value === 0) {
|
|
174
|
+
return 30;
|
|
175
|
+
}
|
|
176
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
177
|
+
if (value === 2) {
|
|
178
|
+
result += 60;
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
},
|
|
182
|
+
enumerable: false
|
|
183
|
+
},
|
|
184
|
+
rgbToAnsi: {
|
|
185
|
+
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
|
186
|
+
enumerable: false
|
|
187
|
+
},
|
|
188
|
+
hexToAnsi: {
|
|
189
|
+
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
|
190
|
+
enumerable: false
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return styles;
|
|
194
|
+
}
|
|
195
|
+
var ansiStyles = assembleStyles();
|
|
196
|
+
var ansi_styles_default = ansiStyles;
|
|
197
|
+
|
|
198
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
199
|
+
import process2 from "process";
|
|
200
|
+
import os from "os";
|
|
201
|
+
import tty from "tty";
|
|
202
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
203
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
204
|
+
const position = argv.indexOf(prefix + flag);
|
|
205
|
+
const terminatorPosition = argv.indexOf("--");
|
|
206
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
207
|
+
}
|
|
208
|
+
var { env } = process2;
|
|
209
|
+
var flagForceColor;
|
|
210
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
211
|
+
flagForceColor = 0;
|
|
212
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
213
|
+
flagForceColor = 1;
|
|
214
|
+
}
|
|
215
|
+
function envForceColor() {
|
|
216
|
+
if ("FORCE_COLOR" in env) {
|
|
217
|
+
if (env.FORCE_COLOR === "true") {
|
|
218
|
+
return 1;
|
|
219
|
+
}
|
|
220
|
+
if (env.FORCE_COLOR === "false") {
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
223
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function translateLevel(level) {
|
|
227
|
+
if (level === 0) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
level,
|
|
232
|
+
hasBasic: true,
|
|
233
|
+
has256: level >= 2,
|
|
234
|
+
has16m: level >= 3
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
238
|
+
const noFlagForceColor = envForceColor();
|
|
239
|
+
if (noFlagForceColor !== void 0) {
|
|
240
|
+
flagForceColor = noFlagForceColor;
|
|
241
|
+
}
|
|
242
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
243
|
+
if (forceColor === 0) {
|
|
244
|
+
return 0;
|
|
245
|
+
}
|
|
246
|
+
if (sniffFlags) {
|
|
247
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
248
|
+
return 3;
|
|
249
|
+
}
|
|
250
|
+
if (hasFlag("color=256")) {
|
|
251
|
+
return 2;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
255
|
+
return 1;
|
|
256
|
+
}
|
|
257
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
const min = forceColor || 0;
|
|
261
|
+
if (env.TERM === "dumb") {
|
|
262
|
+
return min;
|
|
263
|
+
}
|
|
264
|
+
if (process2.platform === "win32") {
|
|
265
|
+
const osRelease = os.release().split(".");
|
|
266
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
267
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
268
|
+
}
|
|
269
|
+
return 1;
|
|
270
|
+
}
|
|
271
|
+
if ("CI" in env) {
|
|
272
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
273
|
+
return 3;
|
|
274
|
+
}
|
|
275
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
276
|
+
return 1;
|
|
277
|
+
}
|
|
278
|
+
return min;
|
|
279
|
+
}
|
|
280
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
281
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
282
|
+
}
|
|
283
|
+
if (env.COLORTERM === "truecolor") {
|
|
284
|
+
return 3;
|
|
285
|
+
}
|
|
286
|
+
if (env.TERM === "xterm-kitty") {
|
|
287
|
+
return 3;
|
|
288
|
+
}
|
|
289
|
+
if (env.TERM === "xterm-ghostty") {
|
|
290
|
+
return 3;
|
|
291
|
+
}
|
|
292
|
+
if (env.TERM === "wezterm") {
|
|
293
|
+
return 3;
|
|
294
|
+
}
|
|
295
|
+
if ("TERM_PROGRAM" in env) {
|
|
296
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
297
|
+
switch (env.TERM_PROGRAM) {
|
|
298
|
+
case "iTerm.app": {
|
|
299
|
+
return version >= 3 ? 3 : 2;
|
|
300
|
+
}
|
|
301
|
+
case "Apple_Terminal": {
|
|
302
|
+
return 2;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
307
|
+
return 2;
|
|
308
|
+
}
|
|
309
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
310
|
+
return 1;
|
|
311
|
+
}
|
|
312
|
+
if ("COLORTERM" in env) {
|
|
313
|
+
return 1;
|
|
314
|
+
}
|
|
315
|
+
return min;
|
|
316
|
+
}
|
|
317
|
+
function createSupportsColor(stream, options = {}) {
|
|
318
|
+
const level = _supportsColor(stream, {
|
|
319
|
+
streamIsTTY: stream && stream.isTTY,
|
|
320
|
+
...options
|
|
321
|
+
});
|
|
322
|
+
return translateLevel(level);
|
|
323
|
+
}
|
|
324
|
+
var supportsColor = {
|
|
325
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
326
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
327
|
+
};
|
|
328
|
+
var supports_color_default = supportsColor;
|
|
329
|
+
|
|
330
|
+
// node_modules/chalk/source/utilities.js
|
|
331
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
332
|
+
let index = string.indexOf(substring);
|
|
333
|
+
if (index === -1) {
|
|
334
|
+
return string;
|
|
335
|
+
}
|
|
336
|
+
const substringLength = substring.length;
|
|
337
|
+
let endIndex = 0;
|
|
338
|
+
let returnValue = "";
|
|
339
|
+
do {
|
|
340
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
341
|
+
endIndex = index + substringLength;
|
|
342
|
+
index = string.indexOf(substring, endIndex);
|
|
343
|
+
} while (index !== -1);
|
|
344
|
+
returnValue += string.slice(endIndex);
|
|
345
|
+
return returnValue;
|
|
346
|
+
}
|
|
347
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
348
|
+
let endIndex = 0;
|
|
349
|
+
let returnValue = "";
|
|
350
|
+
do {
|
|
351
|
+
const gotCR = string[index - 1] === "\r";
|
|
352
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
353
|
+
endIndex = index + 1;
|
|
354
|
+
index = string.indexOf("\n", endIndex);
|
|
355
|
+
} while (index !== -1);
|
|
356
|
+
returnValue += string.slice(endIndex);
|
|
357
|
+
return returnValue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// node_modules/chalk/source/index.js
|
|
361
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
362
|
+
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
363
|
+
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
364
|
+
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
365
|
+
var levelMapping = [
|
|
366
|
+
"ansi",
|
|
367
|
+
"ansi",
|
|
368
|
+
"ansi256",
|
|
369
|
+
"ansi16m"
|
|
370
|
+
];
|
|
371
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
372
|
+
var applyOptions = (object, options = {}) => {
|
|
373
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
374
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
375
|
+
}
|
|
376
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
377
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
378
|
+
};
|
|
379
|
+
var chalkFactory = (options) => {
|
|
380
|
+
const chalk2 = (...strings) => strings.join(" ");
|
|
381
|
+
applyOptions(chalk2, options);
|
|
382
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
383
|
+
return chalk2;
|
|
384
|
+
};
|
|
385
|
+
function createChalk(options) {
|
|
386
|
+
return chalkFactory(options);
|
|
387
|
+
}
|
|
388
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
389
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
390
|
+
styles2[styleName] = {
|
|
391
|
+
get() {
|
|
392
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
393
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
394
|
+
return builder;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
styles2.visible = {
|
|
399
|
+
get() {
|
|
400
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
401
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
402
|
+
return builder;
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
var getModelAnsi = (model, level, type, ...arguments_) => {
|
|
406
|
+
if (model === "rgb") {
|
|
407
|
+
if (level === "ansi16m") {
|
|
408
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
409
|
+
}
|
|
410
|
+
if (level === "ansi256") {
|
|
411
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
412
|
+
}
|
|
413
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
414
|
+
}
|
|
415
|
+
if (model === "hex") {
|
|
416
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
417
|
+
}
|
|
418
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
419
|
+
};
|
|
420
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
421
|
+
for (const model of usedModels) {
|
|
422
|
+
styles2[model] = {
|
|
423
|
+
get() {
|
|
424
|
+
const { level } = this;
|
|
425
|
+
return function(...arguments_) {
|
|
426
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
427
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
432
|
+
styles2[bgModel] = {
|
|
433
|
+
get() {
|
|
434
|
+
const { level } = this;
|
|
435
|
+
return function(...arguments_) {
|
|
436
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
437
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
var proto = Object.defineProperties(() => {
|
|
443
|
+
}, {
|
|
444
|
+
...styles2,
|
|
445
|
+
level: {
|
|
446
|
+
enumerable: true,
|
|
447
|
+
get() {
|
|
448
|
+
return this[GENERATOR].level;
|
|
449
|
+
},
|
|
450
|
+
set(level) {
|
|
451
|
+
this[GENERATOR].level = level;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
var createStyler = (open, close, parent) => {
|
|
456
|
+
let openAll;
|
|
457
|
+
let closeAll;
|
|
458
|
+
if (parent === void 0) {
|
|
459
|
+
openAll = open;
|
|
460
|
+
closeAll = close;
|
|
461
|
+
} else {
|
|
462
|
+
openAll = parent.openAll + open;
|
|
463
|
+
closeAll = close + parent.closeAll;
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
open,
|
|
467
|
+
close,
|
|
468
|
+
openAll,
|
|
469
|
+
closeAll,
|
|
470
|
+
parent
|
|
471
|
+
};
|
|
472
|
+
};
|
|
473
|
+
var createBuilder = (self, _styler, _isEmpty) => {
|
|
474
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
475
|
+
Object.setPrototypeOf(builder, proto);
|
|
476
|
+
builder[GENERATOR] = self;
|
|
477
|
+
builder[STYLER] = _styler;
|
|
478
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
479
|
+
return builder;
|
|
480
|
+
};
|
|
481
|
+
var applyStyle = (self, string) => {
|
|
482
|
+
if (self.level <= 0 || !string) {
|
|
483
|
+
return self[IS_EMPTY] ? "" : string;
|
|
484
|
+
}
|
|
485
|
+
let styler = self[STYLER];
|
|
486
|
+
if (styler === void 0) {
|
|
487
|
+
return string;
|
|
488
|
+
}
|
|
489
|
+
const { openAll, closeAll } = styler;
|
|
490
|
+
if (string.includes("\x1B")) {
|
|
491
|
+
while (styler !== void 0) {
|
|
492
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
493
|
+
styler = styler.parent;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const lfIndex = string.indexOf("\n");
|
|
497
|
+
if (lfIndex !== -1) {
|
|
498
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
499
|
+
}
|
|
500
|
+
return openAll + string + closeAll;
|
|
501
|
+
};
|
|
502
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
503
|
+
var chalk = createChalk();
|
|
504
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
505
|
+
var source_default = chalk;
|
|
11
506
|
|
|
12
507
|
// src/utils/logger.ts
|
|
13
|
-
import chalk from "chalk";
|
|
14
508
|
var ConsoleLogger = class {
|
|
15
509
|
info(message) {
|
|
16
|
-
console.log(
|
|
510
|
+
console.log(source_default.blue("\u2139\uFE0F " + message));
|
|
17
511
|
}
|
|
18
512
|
success(message) {
|
|
19
|
-
console.log(
|
|
513
|
+
console.log(source_default.green("\u2705 " + message));
|
|
20
514
|
}
|
|
21
515
|
warn(message) {
|
|
22
|
-
console.log(
|
|
516
|
+
console.log(source_default.yellow("\u26A0\uFE0F " + message));
|
|
23
517
|
}
|
|
24
518
|
error(message) {
|
|
25
|
-
console.log(
|
|
519
|
+
console.log(source_default.red("\u274C " + message));
|
|
26
520
|
}
|
|
27
521
|
title(message) {
|
|
28
|
-
console.log(
|
|
522
|
+
console.log(source_default.bold.cyan("\n" + message + "\n"));
|
|
29
523
|
}
|
|
30
524
|
newLine() {
|
|
31
525
|
console.log("");
|
|
@@ -134,12 +628,7 @@ var RetryStrategy = class {
|
|
|
134
628
|
logger.warn(`${operationName} failed (Attempt ${attempt}): ${errorMessage} [${category}]`);
|
|
135
629
|
if (!this.shouldRetry(error, attempt)) {
|
|
136
630
|
logger.error(`${operationName} failed with non-retryable error: ${errorMessage}`);
|
|
137
|
-
|
|
138
|
-
success: false,
|
|
139
|
-
error,
|
|
140
|
-
totalAttempts: attempt,
|
|
141
|
-
lastError: errorMessage
|
|
142
|
-
};
|
|
631
|
+
throw error;
|
|
143
632
|
}
|
|
144
633
|
if (attempt <= this.config.maxRetries) {
|
|
145
634
|
const delayMs = this.calculateDelay(attempt - 1);
|
|
@@ -150,12 +639,7 @@ var RetryStrategy = class {
|
|
|
150
639
|
}
|
|
151
640
|
}
|
|
152
641
|
}
|
|
153
|
-
|
|
154
|
-
success: false,
|
|
155
|
-
error: lastError || new Error(`${operationName} failed after all retries`),
|
|
156
|
-
totalAttempts: attempt,
|
|
157
|
-
lastError: lastError?.message
|
|
158
|
-
};
|
|
642
|
+
throw lastError || new Error(`${operationName} failed after all retries`);
|
|
159
643
|
}
|
|
160
644
|
};
|
|
161
645
|
var DEFAULT_RETRY_CONFIG = {
|
|
@@ -699,27 +1183,39 @@ var HuaweiUploader = class _HuaweiUploader {
|
|
|
699
1183
|
clientId,
|
|
700
1184
|
appId
|
|
701
1185
|
};
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1186
|
+
const artifacts = typeof metadata.artifactPath === "object" ? metadata.artifactPath : { universal: filePath || metadata.artifactPath || "" };
|
|
1187
|
+
logger.info(`[Huawei] \u5904\u7406\u4EA7\u7269\u6570\u91CF: ${Object.keys(artifacts).length}`);
|
|
1188
|
+
const uploadResults = [];
|
|
1189
|
+
const uploadPromises = Object.entries(artifacts).map(async ([abi, p]) => {
|
|
1190
|
+
if (!p || !fs4.existsSync(p)) return;
|
|
1191
|
+
const currentSuffix = path2.extname(p).substring(1);
|
|
1192
|
+
logger.info(`[Huawei] \u6B63\u5728\u4E0A\u4F20 ${abi} \u5305: ${path2.basename(p)}`);
|
|
1193
|
+
const uploadInfo = await retryStrategy.execute(
|
|
1194
|
+
() => this.getUploadUrl(ctx, currentSuffix),
|
|
1195
|
+
`Huawei get upload URL for ${abi}`
|
|
1196
|
+
);
|
|
1197
|
+
if (!uploadInfo.success || !uploadInfo.data) {
|
|
1198
|
+
throw uploadInfo.error || new Error(`Failed to get upload URL for ${abi}`);
|
|
1199
|
+
}
|
|
1200
|
+
const uploadFileRes = await retryStrategy.execute(
|
|
1201
|
+
() => this.executeUploadRequest(uploadInfo.data.uploadUrl, uploadInfo.data.authCode, p),
|
|
1202
|
+
`Huawei upload file for ${abi}`
|
|
1203
|
+
);
|
|
1204
|
+
if (!uploadFileRes.success || !uploadFileRes.data || uploadFileRes.data.length === 0) {
|
|
1205
|
+
throw uploadFileRes.error || new Error(`File upload failed for ${abi}`);
|
|
1206
|
+
}
|
|
1207
|
+
uploadResults.push({
|
|
1208
|
+
fileName: path2.basename(p),
|
|
1209
|
+
fileDestUrl: uploadFileRes.data[0].fileDestUrl
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1212
|
+
await Promise.all(uploadPromises);
|
|
1213
|
+
if (uploadResults.length === 0) {
|
|
1214
|
+
throw new Error("No files were successfully uploaded");
|
|
718
1215
|
}
|
|
719
|
-
|
|
720
|
-
logger.info("Linking file to app...");
|
|
1216
|
+
logger.info(`[Huawei] \u6B63\u5728\u5173\u8054 ${uploadResults.length} \u4E2A\u6587\u4EF6\u5230\u5E94\u7528...`);
|
|
721
1217
|
const updateInfoResult = await retryStrategy.execute(
|
|
722
|
-
() => this.updateAppFileInfo(ctx,
|
|
1218
|
+
() => this.updateAppFileInfo(ctx, uploadResults, filePath),
|
|
723
1219
|
"Huawei update file info"
|
|
724
1220
|
);
|
|
725
1221
|
if (!updateInfoResult.success) {
|
|
@@ -923,14 +1419,17 @@ var HuaweiUploader = class _HuaweiUploader {
|
|
|
923
1419
|
throw new Error("Upload succeeded but fileDestUrl not found in response");
|
|
924
1420
|
}
|
|
925
1421
|
/** 更新应用文件信息 */
|
|
926
|
-
async updateAppFileInfo(ctx,
|
|
927
|
-
const
|
|
928
|
-
const fileType =
|
|
1422
|
+
async updateAppFileInfo(ctx, files, anyFilePath) {
|
|
1423
|
+
const hasAab = files.some((f) => f.fileName.toLowerCase().endsWith(".aab"));
|
|
1424
|
+
const fileType = hasAab ? 7 /* AAB */ : 5 /* APP_PACKAGE */;
|
|
929
1425
|
const res = await axios2.put(
|
|
930
1426
|
`${ctx.apiRoot}/app-file-info`,
|
|
931
1427
|
{
|
|
932
1428
|
fileType,
|
|
933
|
-
files:
|
|
1429
|
+
files: files.map((f) => ({
|
|
1430
|
+
fileName: f.fileName,
|
|
1431
|
+
fileDestUrl: f.fileDestUrl
|
|
1432
|
+
}))
|
|
934
1433
|
},
|
|
935
1434
|
{
|
|
936
1435
|
params: { appId: ctx.appId },
|
|
@@ -1100,6 +1599,7 @@ var HuaweiUploader = class _HuaweiUploader {
|
|
|
1100
1599
|
|
|
1101
1600
|
// src/adapters/xiaomi_uploader.ts
|
|
1102
1601
|
import fs5 from "fs-extra";
|
|
1602
|
+
import path3 from "path";
|
|
1103
1603
|
import axios3 from "axios";
|
|
1104
1604
|
import FormData3 from "form-data";
|
|
1105
1605
|
import crypto3 from "crypto";
|
|
@@ -1350,80 +1850,39 @@ ${lines.join("\n")}
|
|
|
1350
1850
|
const xiaomiConfig = config.publish?.xiaomi;
|
|
1351
1851
|
const { userName, privateKey, publicKeyPath } = xiaomiConfig.auth;
|
|
1352
1852
|
const updateDesc = metadata.changelog || xiaomiConfig?.description || "App Update";
|
|
1353
|
-
const
|
|
1354
|
-
if (!fs5.existsSync(filePath)) {
|
|
1355
|
-
return {
|
|
1356
|
-
platform: "xiaomi",
|
|
1357
|
-
success: false,
|
|
1358
|
-
message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1853
|
+
const artifacts = typeof metadata.artifactPath === "object" ? metadata.artifactPath : { universal: filePath || (typeof metadata.artifactPath === "string" ? metadata.artifactPath : "") };
|
|
1361
1854
|
const resolvedPublicKey = await this.resolvePublicKey(publicKeyPath);
|
|
1362
1855
|
if (!resolvedPublicKey) {
|
|
1363
|
-
|
|
1364
|
-
platform: "xiaomi",
|
|
1365
|
-
success: false,
|
|
1366
|
-
message: "\u65E0\u6CD5\u83B7\u53D6 RSA \u516C\u94A5: publicKeyPath \u672A\u63D0\u4F9B\u6216\u6587\u4EF6\u4E0D\u5B58\u5728"
|
|
1367
|
-
};
|
|
1368
|
-
}
|
|
1369
|
-
const packageName = xiaomiConfig.packageName || this.inferPackageName(filePath);
|
|
1370
|
-
if (!packageName) {
|
|
1371
|
-
return {
|
|
1372
|
-
platform: "xiaomi",
|
|
1373
|
-
success: false,
|
|
1374
|
-
message: "\u7F3A\u5C11 packageName \u914D\u7F6E, \u4E14\u65E0\u6CD5\u4ECE\u6587\u4EF6\u540D\u63A8\u65AD\u5E94\u7528\u5305\u540D"
|
|
1375
|
-
};
|
|
1856
|
+
throw new Error("\u65E0\u6CD5\u83B7\u53D6 RSA \u516C\u94A5");
|
|
1376
1857
|
}
|
|
1377
|
-
const appName = xiaomiConfig.appName || this.inferAppName(packageName);
|
|
1378
|
-
if (!appName) {
|
|
1379
|
-
return {
|
|
1380
|
-
platform: "xiaomi",
|
|
1381
|
-
success: false,
|
|
1382
|
-
message: "\u7F3A\u5C11 appName \u914D\u7F6E, \u4E14\u65E0\u6CD5\u4ECE\u5305\u540D\u63A8\u65AD\u5E94\u7528\u540D\u79F0"
|
|
1383
|
-
};
|
|
1384
|
-
}
|
|
1385
|
-
logger.info("\u5F00\u59CB\u4E0A\u4F20\u5230\u5C0F\u7C73\u5E94\u7528\u5546\u5E97...");
|
|
1386
|
-
logger.info(`\u6587\u4EF6: ${filePath}`);
|
|
1387
|
-
logger.info(`\u5305\u540D: ${packageName}`);
|
|
1388
|
-
logger.info(`\u5E94\u7528\u540D: ${appName}`);
|
|
1389
1858
|
const publicKeyObj = this.extractPublicKey(resolvedPublicKey);
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
logger.info("\u6B63\u5728\u67E5\u8BE2\u5E94\u7528\u4FE1\u606F...");
|
|
1395
|
-
const status = await this.queryAppStatus(userName, packageName, privateKey, publicKeyObj);
|
|
1396
|
-
uploadType = status.type;
|
|
1397
|
-
existingAppInfo = status.appInfo;
|
|
1398
|
-
} else {
|
|
1399
|
-
uploadType = configUploadType;
|
|
1400
|
-
}
|
|
1401
|
-
const uploadTypeDesc = uploadType === "update" ? "\u5E94\u7528\u66F4\u65B0 (synchroType=1)" : "\u65B0\u589E\u5E94\u7528 (synchroType=0)";
|
|
1402
|
-
logger.info(`\u4E0A\u4F20\u7C7B\u578B: ${uploadTypeDesc}`);
|
|
1403
|
-
if (uploadType === "new" && xiaomiConfig.uploadType === "new") {
|
|
1404
|
-
const missing = [];
|
|
1405
|
-
if (xiaomiConfig.category == null) missing.push("category (\u5206\u7C7BID)");
|
|
1406
|
-
if (!xiaomiConfig.desc) missing.push("desc (\u5E94\u7528\u4ECB\u7ECD)");
|
|
1407
|
-
if (missing.length > 0) {
|
|
1408
|
-
return {
|
|
1409
|
-
platform: "xiaomi",
|
|
1410
|
-
success: false,
|
|
1411
|
-
message: `\u9996\u6B21\u63D0\u5BA1\u6A21\u5F0F\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5: ${missing.join(", ")}\u3002\u8BF7\u5728\u540E\u53F0\u8865\u5168\u6216\u5728\u914D\u7F6E\u4E2D\u6DFB\u52A0\u3002`
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1859
|
+
const anyPath = Object.values(artifacts)[0];
|
|
1860
|
+
const packageName = xiaomiConfig.packageName || this.inferPackageName(anyPath);
|
|
1861
|
+
if (!packageName) throw new Error("\u7F3A\u5C11 packageName");
|
|
1862
|
+
const appName = xiaomiConfig.appName || this.inferAppName(packageName);
|
|
1415
1863
|
try {
|
|
1416
|
-
|
|
1864
|
+
logger.info(`\u5F00\u59CB\u4E0A\u4F20\u5230\u5C0F\u7C73\u5E94\u7528\u5546\u5E97 (\u5305\u542B ${Object.keys(artifacts).length} \u4E2A\u5305)...`);
|
|
1865
|
+
let uploadType = xiaomiConfig.uploadType || "auto";
|
|
1866
|
+
let finalUploadType;
|
|
1867
|
+
let existingAppInfo = null;
|
|
1868
|
+
if (uploadType === "auto") {
|
|
1869
|
+
const status = await this.queryAppStatus(userName, packageName, privateKey, publicKeyObj);
|
|
1870
|
+
finalUploadType = status.type;
|
|
1871
|
+
existingAppInfo = status.appInfo;
|
|
1872
|
+
} else {
|
|
1873
|
+
finalUploadType = uploadType;
|
|
1874
|
+
}
|
|
1875
|
+
const retryStrategy = createUploadRetryStrategy(config.retry);
|
|
1417
1876
|
const result = await retryStrategy.execute(
|
|
1418
1877
|
() => this.performUpload({
|
|
1419
|
-
|
|
1878
|
+
artifacts,
|
|
1420
1879
|
userName,
|
|
1421
1880
|
privateKey,
|
|
1422
1881
|
publicKey: resolvedPublicKey,
|
|
1882
|
+
uploadType: finalUploadType,
|
|
1423
1883
|
packageName,
|
|
1424
|
-
appName,
|
|
1884
|
+
appName: appName || "",
|
|
1425
1885
|
updateDesc,
|
|
1426
|
-
uploadType,
|
|
1427
1886
|
category: xiaomiConfig.category || existingAppInfo?.category,
|
|
1428
1887
|
keyWords: xiaomiConfig.keyWords || existingAppInfo?.keyWords,
|
|
1429
1888
|
desc: xiaomiConfig.desc || existingAppInfo?.desc,
|
|
@@ -1433,50 +1892,19 @@ ${lines.join("\n")}
|
|
|
1433
1892
|
}),
|
|
1434
1893
|
"Xiaomi push upload"
|
|
1435
1894
|
);
|
|
1436
|
-
if (!result.success) {
|
|
1437
|
-
throw result.error || new Error("Upload failed");
|
|
1438
|
-
}
|
|
1439
|
-
logger.success("\u4E0A\u4F20\u5230\u5C0F\u7C73\u5E94\u7528\u5546\u5E97\u6210\u529F!");
|
|
1440
1895
|
return {
|
|
1441
1896
|
platform: "xiaomi",
|
|
1442
1897
|
success: true,
|
|
1443
|
-
message: "\u4E0A\u4F20\u6210\u529F
|
|
1444
|
-
data: result.data,
|
|
1898
|
+
message: "\u4E0A\u4F20\u6210\u529F",
|
|
1445
1899
|
consoleUrl: "https://dev.mi.com/distribute/app/details"
|
|
1446
1900
|
};
|
|
1447
1901
|
} catch (error) {
|
|
1448
|
-
logger.error(`\u4E0A\u4F20\
|
|
1449
|
-
|
|
1450
|
-
logger.info(`\u9519\u8BEF\u8BE6\u60C5: ${JSON.stringify(error.response.data)}`);
|
|
1451
|
-
}
|
|
1452
|
-
return {
|
|
1453
|
-
platform: "xiaomi",
|
|
1454
|
-
success: false,
|
|
1455
|
-
message: error.message,
|
|
1456
|
-
error
|
|
1457
|
-
};
|
|
1902
|
+
logger.error(`\u5C0F\u7C73\u4E0A\u4F20\u5931\u8D25: ${error.message}`);
|
|
1903
|
+
return { platform: "xiaomi", success: false, message: error.message, error };
|
|
1458
1904
|
}
|
|
1459
1905
|
}
|
|
1460
|
-
/**
|
|
1461
|
-
* 执行实际的上传操作
|
|
1462
|
-
*/
|
|
1463
1906
|
async performUpload(params) {
|
|
1464
|
-
const {
|
|
1465
|
-
filePath,
|
|
1466
|
-
userName,
|
|
1467
|
-
privateKey,
|
|
1468
|
-
publicKey,
|
|
1469
|
-
packageName,
|
|
1470
|
-
appName,
|
|
1471
|
-
updateDesc,
|
|
1472
|
-
uploadType,
|
|
1473
|
-
category,
|
|
1474
|
-
keyWords,
|
|
1475
|
-
desc,
|
|
1476
|
-
brief,
|
|
1477
|
-
privacyUrl,
|
|
1478
|
-
assets
|
|
1479
|
-
} = params;
|
|
1907
|
+
const { artifacts, userName, privateKey, publicKey, packageName, appName, updateDesc, uploadType, category, keyWords, desc, brief, privacyUrl, assets } = params;
|
|
1480
1908
|
const publicKeyObj = this.extractPublicKey(publicKey);
|
|
1481
1909
|
const requestData = this.buildRequestData({
|
|
1482
1910
|
userName,
|
|
@@ -1490,67 +1918,55 @@ ${lines.join("\n")}
|
|
|
1490
1918
|
brief,
|
|
1491
1919
|
privacyUrl
|
|
1492
1920
|
});
|
|
1493
|
-
logger.info("RequestData \u5DF2\u6784\u5EFA");
|
|
1494
|
-
logger.info(`RequestData: ${requestData}`);
|
|
1495
1921
|
const requestDataMD5 = this.calculateStringMD5(requestData);
|
|
1496
|
-
|
|
1497
|
-
|
|
1922
|
+
let mainPath;
|
|
1923
|
+
let secondPath = void 0;
|
|
1924
|
+
const artifactEntries = Object.entries(artifacts);
|
|
1925
|
+
const arm64 = artifactEntries.find(([abi]) => abi === "arm64-v8a");
|
|
1926
|
+
const arm32 = artifactEntries.find(([abi]) => abi === "armeabi-v7a");
|
|
1927
|
+
if (arm64 && arm32) {
|
|
1928
|
+
mainPath = arm64[1];
|
|
1929
|
+
secondPath = arm32[1];
|
|
1930
|
+
logger.info(`[Xiaomi] \u8BC6\u522B\u5230\u591A\u67B6\u6784\u5206\u5305: \u4E3B\u5305(64\u4F4D)=${path3.basename(mainPath)}, \u6B21\u5305(32\u4F4D)=${path3.basename(secondPath)}`);
|
|
1931
|
+
} else {
|
|
1932
|
+
mainPath = artifactEntries[0][1];
|
|
1933
|
+
if (artifactEntries.length > 1) {
|
|
1934
|
+
secondPath = artifactEntries[1][1];
|
|
1935
|
+
logger.info(`[Xiaomi] \u8BC6\u522B\u5230\u591A\u4E2A\u5305\uFF08\u975E\u6807\u51C6\u540D\uFF09\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u987A\u5E8F: \u4E3B\u5305=${path3.basename(mainPath)}, \u6B21\u5305=${path3.basename(secondPath)}`);
|
|
1936
|
+
} else {
|
|
1937
|
+
logger.info(`[Xiaomi] \u4F7F\u7528\u5355\u5305\u6A21\u5F0F: ${path3.basename(mainPath)}`);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
const mainMD5 = await this.calculateFileMD5(mainPath);
|
|
1498
1941
|
const extraSigItems = [];
|
|
1499
|
-
|
|
1942
|
+
if (secondPath) {
|
|
1943
|
+
const secondMD5 = await this.calculateFileMD5(secondPath);
|
|
1944
|
+
extraSigItems.push({ name: "secondApk", hash: secondMD5 });
|
|
1945
|
+
}
|
|
1500
1946
|
if (assets?.icon && fs5.existsSync(assets.icon)) {
|
|
1501
|
-
|
|
1502
|
-
const iconMD5 = await this.calculateFileMD5(iconPath);
|
|
1503
|
-
extraSigItems.push({ name: "icon", hash: iconMD5 });
|
|
1504
|
-
}
|
|
1505
|
-
const screenshotPaths = [];
|
|
1506
|
-
if (assets?.screenshots) {
|
|
1507
|
-
for (let i = 0; i < assets.screenshots.length && i < 4; i++) {
|
|
1508
|
-
const ssPath = assets.screenshots[i];
|
|
1509
|
-
if (fs5.existsSync(ssPath)) {
|
|
1510
|
-
screenshotPaths.push(ssPath);
|
|
1511
|
-
const ssMD5 = await this.calculateFileMD5(ssPath);
|
|
1512
|
-
extraSigItems.push({ name: `screenshot_${i + 1}`, hash: ssMD5 });
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1947
|
+
extraSigItems.push({ name: "icon", hash: await this.calculateFileMD5(assets.icon) });
|
|
1515
1948
|
}
|
|
1516
|
-
const sig = this.generateUploadSIG(
|
|
1517
|
-
requestDataMD5,
|
|
1518
|
-
apkFileMD5,
|
|
1519
|
-
privateKey,
|
|
1520
|
-
publicKeyObj,
|
|
1521
|
-
extraSigItems.length > 0 ? extraSigItems : void 0
|
|
1522
|
-
);
|
|
1523
|
-
logger.info("SIG \u7B7E\u540D\u5DF2\u751F\u6210");
|
|
1949
|
+
const sig = this.generateUploadSIG(requestDataMD5, mainMD5, privateKey, publicKeyObj, extraSigItems);
|
|
1524
1950
|
const form = new FormData3();
|
|
1525
1951
|
form.append("RequestData", requestData);
|
|
1526
1952
|
form.append("SIG", sig);
|
|
1527
|
-
form.append("apk", fs5.createReadStream(
|
|
1528
|
-
if (
|
|
1529
|
-
form.append("
|
|
1530
|
-
logger.info(`\u9644\u52A0 icon: ${iconPath}`);
|
|
1953
|
+
form.append("apk", fs5.createReadStream(mainPath));
|
|
1954
|
+
if (secondPath) {
|
|
1955
|
+
form.append("secondApk", fs5.createReadStream(secondPath));
|
|
1531
1956
|
}
|
|
1532
|
-
|
|
1533
|
-
form.append(
|
|
1534
|
-
logger.info(`\u9644\u52A0 screenshot_${i + 1}: ${screenshotPaths[i]}`);
|
|
1957
|
+
if (assets?.icon && fs5.existsSync(assets.icon)) {
|
|
1958
|
+
form.append("icon", fs5.createReadStream(assets.icon));
|
|
1535
1959
|
}
|
|
1536
|
-
logger.info(`POST ${_XiaomiUploader.PUSH_API}`);
|
|
1537
1960
|
const response = await axios3.post(_XiaomiUploader.PUSH_API, form, {
|
|
1538
|
-
headers:
|
|
1539
|
-
...form.getHeaders()
|
|
1540
|
-
},
|
|
1961
|
+
headers: form.getHeaders(),
|
|
1541
1962
|
maxContentLength: Infinity,
|
|
1542
1963
|
maxBodyLength: Infinity,
|
|
1543
|
-
timeout:
|
|
1544
|
-
// 60 秒请求超时
|
|
1964
|
+
timeout: 12e4
|
|
1545
1965
|
});
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
if (data?.result !== 0) {
|
|
1549
|
-
const errMsg = data?.message || data?.msg || JSON.stringify(data);
|
|
1550
|
-
throw new Error(`\u5C0F\u7C73 API \u8FD4\u56DE\u9519\u8BEF (result=${data?.result}): ${errMsg}`);
|
|
1966
|
+
if (response.data?.result !== 0) {
|
|
1967
|
+
throw new Error(`\u5C0F\u7C73 API \u9519\u8BEF: ${response.data?.message || JSON.stringify(response.data)}`);
|
|
1551
1968
|
}
|
|
1552
|
-
|
|
1553
|
-
return data;
|
|
1969
|
+
return response.data;
|
|
1554
1970
|
}
|
|
1555
1971
|
/**
|
|
1556
1972
|
* 解析公钥: 优先使用内容字段, 其次从文件路径读取
|
|
@@ -1592,7 +2008,7 @@ ${lines.join("\n")}
|
|
|
1592
2008
|
|
|
1593
2009
|
// src/adapters/apple_store_uploader.ts
|
|
1594
2010
|
import fs6 from "fs-extra";
|
|
1595
|
-
import
|
|
2011
|
+
import path4 from "path";
|
|
1596
2012
|
import { exec as exec2 } from "child_process";
|
|
1597
2013
|
import { promisify as promisify2 } from "util";
|
|
1598
2014
|
import axios4 from "axios";
|
|
@@ -1758,7 +2174,7 @@ var AppleStoreUploader = class {
|
|
|
1758
2174
|
appPassword,
|
|
1759
2175
|
"-showTransferRate"
|
|
1760
2176
|
].join(" ");
|
|
1761
|
-
logger.info(`[Transporter] Uploading: ${
|
|
2177
|
+
logger.info(`[Transporter] Uploading: ${path4.basename(ipaPath)}`);
|
|
1762
2178
|
try {
|
|
1763
2179
|
const { stdout, stderr } = await execAsync(command, {
|
|
1764
2180
|
timeout: 30 * 60 * 1e3,
|
|
@@ -1809,7 +2225,7 @@ Stderr: ${error.stderr || ""}`);
|
|
|
1809
2225
|
});
|
|
1810
2226
|
command = innerArgs.join(" ");
|
|
1811
2227
|
}
|
|
1812
|
-
logger.info(`[altool] Uploading: ${
|
|
2228
|
+
logger.info(`[altool] Uploading: ${path4.basename(ipaPath)}`);
|
|
1813
2229
|
logger.info(`[altool] Command prefix: ${tool.command}`);
|
|
1814
2230
|
try {
|
|
1815
2231
|
const { stdout, stderr } = await execAsync(command, {
|
|
@@ -2393,7 +2809,7 @@ var TestFlightUploader = class _TestFlightUploader {
|
|
|
2393
2809
|
|
|
2394
2810
|
// src/adapters/adhoc_uploader.ts
|
|
2395
2811
|
import fs8 from "fs-extra";
|
|
2396
|
-
import
|
|
2812
|
+
import path5 from "path";
|
|
2397
2813
|
import { execSync } from "child_process";
|
|
2398
2814
|
var AdHocUploader = class {
|
|
2399
2815
|
name = "AdHoc";
|
|
@@ -2526,8 +2942,8 @@ var AdHocUploader = class {
|
|
|
2526
2942
|
* @param changelog 更新日志
|
|
2527
2943
|
*/
|
|
2528
2944
|
async createManifest(ipaPath, version, bundleId, changelog) {
|
|
2529
|
-
const ipaFileName =
|
|
2530
|
-
const appName = bundleId ||
|
|
2945
|
+
const ipaFileName = path5.basename(ipaPath);
|
|
2946
|
+
const appName = bundleId || path5.parse(ipaFileName).name;
|
|
2531
2947
|
const ipaUrl = `itms-services://?action=download-manifest&url=https://your-distribution-server.com/manifests/${ipaFileName}.plist`;
|
|
2532
2948
|
const manifestContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
2533
2949
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -2586,14 +3002,14 @@ var AdHocUploader = class {
|
|
|
2586
3002
|
*/
|
|
2587
3003
|
async setupDistributionDirectory(ipaPath, manifestPath) {
|
|
2588
3004
|
const projectRoot = process.cwd();
|
|
2589
|
-
const distributionDir =
|
|
3005
|
+
const distributionDir = path5.join(projectRoot, "build", "adhoc-distribution");
|
|
2590
3006
|
await fs8.ensureDir(distributionDir);
|
|
2591
|
-
await fs8.ensureDir(
|
|
2592
|
-
await fs8.ensureDir(
|
|
2593
|
-
await fs8.ensureDir(
|
|
2594
|
-
const ipaFileName =
|
|
2595
|
-
await fs8.copy(ipaPath,
|
|
2596
|
-
await fs8.copy(manifestPath,
|
|
3007
|
+
await fs8.ensureDir(path5.join(distributionDir, "apps"));
|
|
3008
|
+
await fs8.ensureDir(path5.join(distributionDir, "manifests"));
|
|
3009
|
+
await fs8.ensureDir(path5.join(distributionDir, "icons"));
|
|
3010
|
+
const ipaFileName = path5.basename(ipaPath);
|
|
3011
|
+
await fs8.copy(ipaPath, path5.join(distributionDir, "apps", ipaFileName));
|
|
3012
|
+
await fs8.copy(manifestPath, path5.join(distributionDir, "manifests", `${ipaFileName}.plist`));
|
|
2597
3013
|
logger.info(`Distribution directory: ${distributionDir}`);
|
|
2598
3014
|
return distributionDir;
|
|
2599
3015
|
}
|
|
@@ -2603,7 +3019,7 @@ var AdHocUploader = class {
|
|
|
2603
3019
|
* @param bundleId Bundle ID
|
|
2604
3020
|
*/
|
|
2605
3021
|
generateInstallUrl(distributionPath, bundleId) {
|
|
2606
|
-
const manifestPath =
|
|
3022
|
+
const manifestPath = path5.join(distributionPath, "manifests", `*.plist`);
|
|
2607
3023
|
return `itms-services://?action=download-manifest&url=file://${manifestPath}`;
|
|
2608
3024
|
}
|
|
2609
3025
|
/**
|
|
@@ -2612,7 +3028,7 @@ var AdHocUploader = class {
|
|
|
2612
3028
|
* @param distributionPath 分发目录
|
|
2613
3029
|
*/
|
|
2614
3030
|
async generateQRCode(url, distributionPath) {
|
|
2615
|
-
const qrCodePath =
|
|
3031
|
+
const qrCodePath = path5.join(distributionPath, "install-qrcode.png");
|
|
2616
3032
|
try {
|
|
2617
3033
|
logger.info(`QR code would be saved to: ${qrCodePath}`);
|
|
2618
3034
|
logger.info(`Install URL: ${url}`);
|
|
@@ -2639,8 +3055,8 @@ var AdHocUploader = class {
|
|
|
2639
3055
|
logger.newLine();
|
|
2640
3056
|
logger.info("\u{1F4E6} Distribution Files:");
|
|
2641
3057
|
logger.info(` Directory: ${distributionPath}`);
|
|
2642
|
-
logger.info(` IPA: ${
|
|
2643
|
-
logger.info(` Manifest: ${
|
|
3058
|
+
logger.info(` IPA: ${path5.join(distributionPath, "apps", "*.ipa")}`);
|
|
3059
|
+
logger.info(` Manifest: ${path5.join(distributionPath, "manifests", "*.plist")}`);
|
|
2644
3060
|
logger.info(` QR Code: ${qrCodePath}`);
|
|
2645
3061
|
logger.newLine();
|
|
2646
3062
|
logger.info("\u{1F517} Installation Link:");
|
|
@@ -2699,7 +3115,7 @@ var AdHocUploader = class {
|
|
|
2699
3115
|
|
|
2700
3116
|
// src/adapters/harmony_uploader.ts
|
|
2701
3117
|
import fs9 from "fs-extra";
|
|
2702
|
-
import
|
|
3118
|
+
import path6 from "path";
|
|
2703
3119
|
import axios6 from "axios";
|
|
2704
3120
|
import FormData5 from "form-data";
|
|
2705
3121
|
var HarmonyUploader = class _HarmonyUploader {
|
|
@@ -2729,7 +3145,7 @@ var HarmonyUploader = class _HarmonyUploader {
|
|
|
2729
3145
|
const clientSecret = harmonyConfig.auth.clientSecret;
|
|
2730
3146
|
const appId = harmonyConfig.appId;
|
|
2731
3147
|
const releaseType = harmonyConfig.releaseType || "draft";
|
|
2732
|
-
const suffix =
|
|
3148
|
+
const suffix = path6.extname(filePath).substring(1);
|
|
2733
3149
|
const retryConfig = config.retry;
|
|
2734
3150
|
logger.info("Starting HarmonyOS AppGallery upload...");
|
|
2735
3151
|
try {
|
|
@@ -2846,7 +3262,7 @@ var HarmonyUploader = class _HarmonyUploader {
|
|
|
2846
3262
|
* @param filePath 文件路径
|
|
2847
3263
|
*/
|
|
2848
3264
|
async updateAppFileInfo(token, appId, authCode, filePath) {
|
|
2849
|
-
const fileName =
|
|
3265
|
+
const fileName = path6.basename(filePath);
|
|
2850
3266
|
const body = {
|
|
2851
3267
|
fileType: 7,
|
|
2852
3268
|
// 鸿蒙包的 fileType(需要根据华为最新文档确认)
|
|
@@ -2869,7 +3285,7 @@ var HarmonyUploader = class _HarmonyUploader {
|
|
|
2869
3285
|
|
|
2870
3286
|
// src/adapters/oppo_uploader.ts
|
|
2871
3287
|
import fs10 from "fs-extra";
|
|
2872
|
-
import
|
|
3288
|
+
import path7 from "path";
|
|
2873
3289
|
import axios7 from "axios";
|
|
2874
3290
|
import FormData6 from "form-data";
|
|
2875
3291
|
import crypto4 from "crypto";
|
|
@@ -2910,7 +3326,7 @@ var OppoUploader = class _OppoUploader {
|
|
|
2910
3326
|
* 尝试从文件名推断包名
|
|
2911
3327
|
*/
|
|
2912
3328
|
inferPackageName(filePath) {
|
|
2913
|
-
const fileName =
|
|
3329
|
+
const fileName = path7.basename(filePath);
|
|
2914
3330
|
const match = fileName.match(/^([\w.]+?)(?:-(?:release|debug|unsigned))?\.apk$/i);
|
|
2915
3331
|
if (match && match[1].includes(".")) {
|
|
2916
3332
|
return match[1];
|
|
@@ -2928,110 +3344,47 @@ var OppoUploader = class _OppoUploader {
|
|
|
2928
3344
|
}
|
|
2929
3345
|
async upload(filePath, config, metadata) {
|
|
2930
3346
|
const oppoConfig = config.publish.oppo;
|
|
2931
|
-
const
|
|
2932
|
-
const clientSecret = oppoConfig.auth.clientSecret;
|
|
3347
|
+
const accessToken = await this.getAccessToken(oppoConfig.auth.clientId, oppoConfig.auth.clientSecret);
|
|
2933
3348
|
const packageName = oppoConfig.packageName || this.inferPackageName(filePath);
|
|
2934
|
-
if (!packageName) {
|
|
2935
|
-
return {
|
|
2936
|
-
platform: "oppo",
|
|
2937
|
-
success: false,
|
|
2938
|
-
message: "\u65E0\u6CD5\u83B7\u53D6\u5305\u540D (packageName)\uFF0C\u8BF7\u5728\u914D\u7F6E\u4E2D\u6307\u5B9A\u6216\u786E\u4FDD\u6587\u4EF6\u540D\u5305\u542B\u5305\u540D",
|
|
2939
|
-
consoleUrl: "https://open.oppomobile.com/new/ecology/app"
|
|
2940
|
-
};
|
|
2941
|
-
}
|
|
2942
|
-
const retryConfig = config.retry;
|
|
2943
3349
|
const consoleUrl = "https://open.oppomobile.com/new/ecology/app";
|
|
2944
|
-
if (!
|
|
2945
|
-
return {
|
|
2946
|
-
platform: "oppo",
|
|
2947
|
-
success: false,
|
|
2948
|
-
message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`,
|
|
2949
|
-
consoleUrl
|
|
2950
|
-
};
|
|
3350
|
+
if (!packageName) {
|
|
3351
|
+
return { platform: "oppo", success: false, message: "\u65E0\u6CD5\u83B7\u53D6\u5305\u540D", consoleUrl };
|
|
2951
3352
|
}
|
|
2952
|
-
|
|
2953
|
-
logger.info(`\u6587\u4EF6: ${filePath}`);
|
|
3353
|
+
const artifacts = typeof metadata.artifactPath === "object" ? metadata.artifactPath : { universal: filePath || (typeof metadata.artifactPath === "string" ? metadata.artifactPath : "") };
|
|
2954
3354
|
try {
|
|
2955
|
-
const retryStrategy = createUploadRetryStrategy(
|
|
2956
|
-
|
|
2957
|
-
const
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
(
|
|
2968
|
-
|
|
2969
|
-
);
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
throw uploadUrlResult.error || new Error("Failed to get upload URL");
|
|
2984
|
-
}
|
|
2985
|
-
const { uploadUrl, sign: uploadSign } = uploadUrlResult.data;
|
|
2986
|
-
logger.info("\u6B63\u5728\u4E0A\u4F20 APK \u6587\u4EF6...");
|
|
2987
|
-
const uploadFileResult = await retryStrategy.execute(
|
|
2988
|
-
() => this.uploadFile(uploadUrl, uploadSign, filePath),
|
|
2989
|
-
"OPPO file upload"
|
|
2990
|
-
);
|
|
2991
|
-
if (!uploadFileResult.success || !uploadFileResult.data) {
|
|
2992
|
-
throw uploadFileResult.error || new Error("File upload failed");
|
|
2993
|
-
}
|
|
2994
|
-
const rawUrl = uploadFileResult.data.url;
|
|
2995
|
-
const fileUrl = rawUrl.replace(/^http:\/\//i, "https://").replace("storedl1.nearme.com.cn", "storedl.nearme.com.cn");
|
|
2996
|
-
const md5 = uploadFileResult.data.md5;
|
|
2997
|
-
logger.info("\u6B63\u5728\u63D0\u4EA4\u7248\u672C\u4FE1\u606F...");
|
|
2998
|
-
const submitResult = await retryStrategy.execute(
|
|
2999
|
-
() => this.submitVersion({
|
|
3000
|
-
accessToken,
|
|
3001
|
-
clientSecret,
|
|
3002
|
-
packageName,
|
|
3003
|
-
appName: oppoConfig.appName || metadata.appName || onlineAppInfo.app_name || this.inferAppName(packageName),
|
|
3004
|
-
fileUrl,
|
|
3005
|
-
fileMd5: md5,
|
|
3006
|
-
versionName: metadata.version,
|
|
3007
|
-
versionCode: metadata.buildNumber,
|
|
3008
|
-
updateDesc: metadata.changelog || "App Update",
|
|
3009
|
-
onlineType: oppoConfig.onlineType,
|
|
3010
|
-
// 从配置读取
|
|
3011
|
-
onlineAppInfo
|
|
3012
|
-
// 传入线上信息
|
|
3013
|
-
}),
|
|
3014
|
-
"OPPO submit version"
|
|
3015
|
-
);
|
|
3016
|
-
if (!submitResult.success) {
|
|
3017
|
-
throw submitResult.error || new Error("Submit version failed");
|
|
3018
|
-
}
|
|
3355
|
+
const retryStrategy = createUploadRetryStrategy(config.retry);
|
|
3356
|
+
const onlineAppInfo = await this.getAppInfo(accessToken, oppoConfig.auth.clientSecret, packageName) || {};
|
|
3357
|
+
const uploadResults = [];
|
|
3358
|
+
const uploadPromises = Object.entries(artifacts).map(async ([abi, p]) => {
|
|
3359
|
+
if (!p || !fs10.existsSync(p)) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${p}`);
|
|
3360
|
+
logger.info(`[OPPO] \u6B63\u5728\u5904\u7406 ${abi} \u67B6\u6784\u5305...`);
|
|
3361
|
+
const { uploadUrl, sign } = await this.getUploadUrl(accessToken, oppoConfig.auth.clientSecret);
|
|
3362
|
+
const uploadFileResult = await this.uploadFile(uploadUrl, sign, p);
|
|
3363
|
+
const fileUrl = uploadFileResult.url.replace(/^http:\/\//i, "https://").replace("storedl1.nearme.com.cn", "storedl.nearme.com.cn");
|
|
3364
|
+
let cpu_code = 0;
|
|
3365
|
+
if (abi === "arm64-v8a") cpu_code = 3;
|
|
3366
|
+
else if (abi === "armeabi-v7a") cpu_code = 4;
|
|
3367
|
+
uploadResults.push({ url: fileUrl, md5: uploadFileResult.md5, cpu_code });
|
|
3368
|
+
});
|
|
3369
|
+
await Promise.all(uploadPromises);
|
|
3370
|
+
logger.info(`[OPPO] \u6B63\u5728\u63D0\u4EA4\u6D41\u6C34\u53F7\u7EC4: ${JSON.stringify(uploadResults)}`);
|
|
3371
|
+
await this.submitVersion({
|
|
3372
|
+
accessToken,
|
|
3373
|
+
clientSecret: oppoConfig.auth.clientSecret,
|
|
3374
|
+
packageName,
|
|
3375
|
+
appName: oppoConfig.appName || onlineAppInfo.app_name || metadata.appName || this.inferAppName(packageName),
|
|
3376
|
+
apkUrls: uploadResults,
|
|
3377
|
+
versionName: metadata.version,
|
|
3378
|
+
versionCode: metadata.buildNumber,
|
|
3379
|
+
updateDesc: metadata.changelog || "App Update",
|
|
3380
|
+
onlineType: oppoConfig.onlineType,
|
|
3381
|
+
onlineAppInfo
|
|
3382
|
+
});
|
|
3019
3383
|
logger.success("\u4E0A\u4F20\u5230 OPPO \u5E94\u7528\u5546\u5E97\u6210\u529F!");
|
|
3020
|
-
return {
|
|
3021
|
-
platform: "oppo",
|
|
3022
|
-
success: true,
|
|
3023
|
-
message: "\u4E0A\u4F20\u6210\u529F, \u8BF7\u524D\u5F80\u540E\u53F0\u786E\u8BA4\u5E76\u63D0\u4EA4\u5BA1\u6838",
|
|
3024
|
-
consoleUrl
|
|
3025
|
-
};
|
|
3384
|
+
return { platform: "oppo", success: true, message: "\u4E0A\u4F20\u6210\u529F, \u8BF7\u786E\u8BA4", consoleUrl };
|
|
3026
3385
|
} catch (error) {
|
|
3027
3386
|
logger.error(`\u4E0A\u4F20\u5230 OPPO \u5931\u8D25: ${error.message}`);
|
|
3028
|
-
return {
|
|
3029
|
-
platform: "oppo",
|
|
3030
|
-
success: false,
|
|
3031
|
-
message: this.formatError(error),
|
|
3032
|
-
error,
|
|
3033
|
-
consoleUrl
|
|
3034
|
-
};
|
|
3387
|
+
return { platform: "oppo", success: false, message: error.message, error, consoleUrl };
|
|
3035
3388
|
}
|
|
3036
3389
|
}
|
|
3037
3390
|
/**
|
|
@@ -3152,16 +3505,7 @@ var OppoUploader = class _OppoUploader {
|
|
|
3152
3505
|
const signParams = {
|
|
3153
3506
|
access_token: params.accessToken,
|
|
3154
3507
|
timestamp,
|
|
3155
|
-
|
|
3156
|
-
// cpu_code: 0=通用包, 3=arm64-v8a, 4=armeabi-v7a, 5=x86_64
|
|
3157
|
-
apk_url: JSON.stringify([
|
|
3158
|
-
{
|
|
3159
|
-
url: params.fileUrl,
|
|
3160
|
-
md5: params.fileMd5,
|
|
3161
|
-
cpu_code: 0
|
|
3162
|
-
// 通用包
|
|
3163
|
-
}
|
|
3164
|
-
]),
|
|
3508
|
+
apk_url: JSON.stringify(params.apkUrls),
|
|
3165
3509
|
version_name: params.versionName.split("+")[0],
|
|
3166
3510
|
// 仅保留版本名部分
|
|
3167
3511
|
version_code: vCode,
|
|
@@ -3263,7 +3607,7 @@ var OppoUploader = class _OppoUploader {
|
|
|
3263
3607
|
|
|
3264
3608
|
// src/adapters/vivo_uploader.ts
|
|
3265
3609
|
import fs11 from "fs-extra";
|
|
3266
|
-
import
|
|
3610
|
+
import path8 from "path";
|
|
3267
3611
|
import axios8 from "axios";
|
|
3268
3612
|
import FormData7 from "form-data";
|
|
3269
3613
|
import crypto5 from "crypto";
|
|
@@ -3271,26 +3615,14 @@ var VivoUploader = class _VivoUploader {
|
|
|
3271
3615
|
name = "vivo";
|
|
3272
3616
|
/** vivo 开放 API 基础地址 */
|
|
3273
3617
|
static API_BASE = "https://developer-api.vivo.com.cn/router/rest";
|
|
3274
|
-
/**
|
|
3275
|
-
* vivo API 签名生成
|
|
3276
|
-
* 规则: 所有参数按 ASCII 码排序后拼接为 key=val&... 字符串,
|
|
3277
|
-
* 以 accessSecret 为密钥进行 HMAC-SHA256 加密,结果转为小写 16 进制字符串
|
|
3278
|
-
*/
|
|
3279
3618
|
generateSign(params, accessSecret) {
|
|
3280
3619
|
const sorted = Object.keys(params).sort().filter((key) => params[key] !== void 0 && params[key] !== null).map((key) => `${key}=${params[key]}`).join("&");
|
|
3281
|
-
|
|
3282
|
-
logger.info(`[VIVO DEBUG] \u5F85\u7B7E\u540D\u4E32: ${sorted}
|
|
3283
|
-
-> \u7B7E\u540D\u7ED3\u679C: ${sign}`);
|
|
3284
|
-
return sign;
|
|
3620
|
+
return crypto5.createHmac("sha256", accessSecret).update(sorted).digest("hex");
|
|
3285
3621
|
}
|
|
3286
3622
|
validateConfig(config) {
|
|
3287
3623
|
if (!config?.publish?.vivo?.enable) return false;
|
|
3288
3624
|
const vivo = config.publish.vivo;
|
|
3289
|
-
|
|
3290
|
-
logger.error("vivo config missing: accessKey or accessSecret");
|
|
3291
|
-
return false;
|
|
3292
|
-
}
|
|
3293
|
-
return true;
|
|
3625
|
+
return !!(vivo.auth?.accessKey && vivo.auth?.accessSecret);
|
|
3294
3626
|
}
|
|
3295
3627
|
canHandle(filePath) {
|
|
3296
3628
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
@@ -3300,67 +3632,51 @@ var VivoUploader = class _VivoUploader {
|
|
|
3300
3632
|
const vivoConfig = config.publish.vivo;
|
|
3301
3633
|
const accessKey = vivoConfig.auth.accessKey;
|
|
3302
3634
|
const accessSecret = vivoConfig.auth.accessSecret;
|
|
3303
|
-
const retryConfig = config.retry;
|
|
3304
3635
|
const consoleUrl = "https://dev.vivo.com.cn/manage/app";
|
|
3305
|
-
|
|
3306
|
-
return {
|
|
3307
|
-
platform: "vivo",
|
|
3308
|
-
success: false,
|
|
3309
|
-
message: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`,
|
|
3310
|
-
consoleUrl
|
|
3311
|
-
};
|
|
3312
|
-
}
|
|
3313
|
-
const fileSize = fs11.statSync(filePath).size;
|
|
3314
|
-
logger.info("\u5F00\u59CB\u4E0A\u4F20\u5230 vivo \u5E94\u7528\u5546\u5E97...");
|
|
3315
|
-
logger.info(`\u6587\u4EF6: ${filePath} (${(fileSize / 1024 / 1024).toFixed(2)} MB)`);
|
|
3636
|
+
const artifacts = typeof metadata.artifactPath === "object" ? metadata.artifactPath : { universal: filePath || (typeof metadata.artifactPath === "string" ? metadata.artifactPath : "") };
|
|
3316
3637
|
try {
|
|
3317
|
-
const
|
|
3318
|
-
const
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3638
|
+
const uploadResults = {};
|
|
3639
|
+
const uploadPromises = Object.entries(artifacts).map(async ([abi, p]) => {
|
|
3640
|
+
if (!p || !fs11.existsSync(p)) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${p}`);
|
|
3641
|
+
const md5 = await this.calculateFileMD5(p);
|
|
3642
|
+
logger.info(`[vivo] \u6B63\u5728\u5904\u7406 ${abi} \u67B6\u6784\u5305: ${path8.basename(p)}`);
|
|
3643
|
+
const serialnumber = await this.uploadApk(accessKey, accessSecret, p, vivoConfig.packageName || "", md5);
|
|
3644
|
+
const pkgInfo = await parsePackageInfo(p, { androidSdkPath: config.globalSettings?.androidSdkPath });
|
|
3645
|
+
const nativeCodes = pkgInfo?.nativeCode || [];
|
|
3646
|
+
const has64Bit = nativeCodes.includes("arm64-v8a") || nativeCodes.includes("x86_64") || abi === "arm64-v8a";
|
|
3647
|
+
const has32Bit = nativeCodes.includes("armeabi-v7a") || nativeCodes.includes("armeabi") || abi === "armeabi-v7a";
|
|
3648
|
+
uploadResults[abi] = { serialnumber, md5, is64Bit: has64Bit && !has32Bit };
|
|
3649
|
+
});
|
|
3650
|
+
await Promise.all(uploadPromises);
|
|
3651
|
+
const arm64Result = uploadResults["arm64-v8a"] || Object.values(uploadResults).find((r) => r.is64Bit);
|
|
3652
|
+
const arm32Result = uploadResults["armeabi-v7a"] || Object.values(uploadResults).find((r) => !r.is64Bit);
|
|
3653
|
+
const submitData = {
|
|
3654
|
+
packageName: vivoConfig.packageName,
|
|
3655
|
+
versionCode: parseInt(metadata.buildNumber) || 1,
|
|
3656
|
+
updateDesc: metadata.changelog || "App Update"
|
|
3657
|
+
};
|
|
3658
|
+
if (arm64Result) {
|
|
3659
|
+
submitData.serialnumber = arm64Result.serialnumber;
|
|
3660
|
+
submitData.fileMd5 = arm64Result.md5;
|
|
3327
3661
|
}
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
updateDesc: metadata.changelog || "App Update"
|
|
3337
|
-
}),
|
|
3338
|
-
"vivo submit version"
|
|
3339
|
-
);
|
|
3340
|
-
if (!submitResult.success) {
|
|
3341
|
-
throw submitResult.error || new Error("Submit version failed");
|
|
3662
|
+
if (arm32Result) {
|
|
3663
|
+
submitData.apk32 = arm32Result.serialnumber;
|
|
3664
|
+
submitData.md532 = arm32Result.md5;
|
|
3665
|
+
}
|
|
3666
|
+
if (!submitData.serialnumber && !submitData.apk32) {
|
|
3667
|
+
const single = Object.values(uploadResults)[0];
|
|
3668
|
+
submitData.serialnumber = single.serialnumber;
|
|
3669
|
+
submitData.fileMd5 = single.md5;
|
|
3342
3670
|
}
|
|
3671
|
+
logger.info(`[vivo] \u6B63\u5728\u63D0\u4EA4\u5BA1\u6838\u7533\u62A5: ${JSON.stringify(submitData)}`);
|
|
3672
|
+
await this.submitVersion(accessKey, accessSecret, submitData);
|
|
3343
3673
|
logger.success("\u4E0A\u4F20\u5230 vivo \u5E94\u7528\u5546\u5E97\u6210\u529F!");
|
|
3344
|
-
return {
|
|
3345
|
-
platform: "vivo",
|
|
3346
|
-
success: true,
|
|
3347
|
-
message: "\u4E0A\u4F20\u6210\u529F, \u8BF7\u524D\u5F80\u540E\u53F0\u786E\u8BA4\u5E76\u63D0\u4EA4\u5BA1\u6838",
|
|
3348
|
-
consoleUrl
|
|
3349
|
-
};
|
|
3674
|
+
return { platform: "vivo", success: true, message: "\u4E0A\u4F20\u5E76\u63D0\u4EA4\u5BA1\u6838\u6210\u529F", consoleUrl };
|
|
3350
3675
|
} catch (error) {
|
|
3351
3676
|
logger.error(`\u4E0A\u4F20\u5230 vivo \u5931\u8D25: ${error.message}`);
|
|
3352
|
-
return {
|
|
3353
|
-
platform: "vivo",
|
|
3354
|
-
success: false,
|
|
3355
|
-
message: this.formatError(error),
|
|
3356
|
-
error,
|
|
3357
|
-
consoleUrl
|
|
3358
|
-
};
|
|
3677
|
+
return { platform: "vivo", success: false, message: error.message, error, consoleUrl };
|
|
3359
3678
|
}
|
|
3360
3679
|
}
|
|
3361
|
-
/**
|
|
3362
|
-
* 计算文件 MD5
|
|
3363
|
-
*/
|
|
3364
3680
|
calculateFileMD5(filePath) {
|
|
3365
3681
|
return new Promise((resolve, reject) => {
|
|
3366
3682
|
const hash = crypto5.createHash("md5");
|
|
@@ -3370,14 +3686,9 @@ var VivoUploader = class _VivoUploader {
|
|
|
3370
3686
|
stream.on("error", reject);
|
|
3371
3687
|
});
|
|
3372
3688
|
}
|
|
3373
|
-
/**
|
|
3374
|
-
* 上传 APK 文件并获取流水号
|
|
3375
|
-
* 将公共参数与业务参数放入一个 multipart 请求中直接上传至 API_BASE
|
|
3376
|
-
*/
|
|
3377
3689
|
async uploadApk(accessKey, accessSecret, filePath, packageName, fileMd5) {
|
|
3378
3690
|
const timestamp = String(Date.now());
|
|
3379
|
-
const
|
|
3380
|
-
// 公共参数
|
|
3691
|
+
const params = {
|
|
3381
3692
|
access_key: accessKey,
|
|
3382
3693
|
timestamp,
|
|
3383
3694
|
format: "json",
|
|
@@ -3385,41 +3696,19 @@ var VivoUploader = class _VivoUploader {
|
|
|
3385
3696
|
sign_method: "hmac",
|
|
3386
3697
|
target_app_key: "developer",
|
|
3387
3698
|
method: "app.upload.apk.app",
|
|
3388
|
-
// 业务参数
|
|
3389
3699
|
packageName,
|
|
3390
3700
|
fileMd5
|
|
3391
3701
|
};
|
|
3392
|
-
const sign = this.generateSign(
|
|
3702
|
+
const sign = this.generateSign(params, accessSecret);
|
|
3393
3703
|
const form = new FormData7();
|
|
3394
|
-
|
|
3395
|
-
form.append(key, value);
|
|
3396
|
-
}
|
|
3704
|
+
Object.entries(params).forEach(([k, v]) => form.append(k, v));
|
|
3397
3705
|
form.append("sign", sign);
|
|
3398
|
-
form.append("file", fs11.createReadStream(filePath), {
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
logger.info(
|
|
3403
|
-
`[VIVO DEBUG] \u5F00\u59CB\u4E0A\u4F20 APK (API\u8BF7\u6C42) \u53C2\u6570(\u4E0D\u542B\u6587\u4EF6): ${JSON.stringify({ ...paramsForSign, sign })}`
|
|
3404
|
-
);
|
|
3405
|
-
const res = await axios8.post(_VivoUploader.API_BASE, form, {
|
|
3406
|
-
headers: form.getHeaders(),
|
|
3407
|
-
maxContentLength: Infinity,
|
|
3408
|
-
maxBodyLength: Infinity,
|
|
3409
|
-
timeout: 3e5
|
|
3410
|
-
});
|
|
3411
|
-
logger.info(`[VIVO DEBUG] \u4E0A\u4F20\u54CD\u5E94: ${JSON.stringify(res.data)}`);
|
|
3412
|
-
if (res.data.code !== 0) {
|
|
3413
|
-
throw new Error(`\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25: ${res.data.msg || JSON.stringify(res.data)}`);
|
|
3414
|
-
}
|
|
3415
|
-
const serialnumber = res.data.data?.serialnumber || res.data.data;
|
|
3416
|
-
logger.info(`APK \u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210\uFF0C\u6D41\u6C34\u53F7: ${serialnumber}`);
|
|
3417
|
-
return serialnumber;
|
|
3706
|
+
form.append("file", fs11.createReadStream(filePath), { filename: path8.basename(filePath) });
|
|
3707
|
+
const res = await axios8.post(_VivoUploader.API_BASE, form, { headers: form.getHeaders(), timeout: 3e5 });
|
|
3708
|
+
if (res.data.code !== 0) throw new Error(`\u4E0A\u4F20\u5305\u5931\u8D25: ${res.data.msg}`);
|
|
3709
|
+
return res.data.data?.serialnumber || res.data.data;
|
|
3418
3710
|
}
|
|
3419
|
-
|
|
3420
|
-
* 提交版本更新信息
|
|
3421
|
-
*/
|
|
3422
|
-
async submitVersion(accessKey, accessSecret, params) {
|
|
3711
|
+
async submitVersion(accessKey, accessSecret, data) {
|
|
3423
3712
|
const timestamp = String(Date.now());
|
|
3424
3713
|
const reqParams = {
|
|
3425
3714
|
access_key: accessKey,
|
|
@@ -3429,51 +3718,32 @@ var VivoUploader = class _VivoUploader {
|
|
|
3429
3718
|
sign_method: "hmac",
|
|
3430
3719
|
target_app_key: "developer",
|
|
3431
3720
|
method: "app.sync.update.app",
|
|
3432
|
-
packageName:
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
apk: params.serialnumber,
|
|
3437
|
-
// 文档中的 apk 字段即为上传接口返回的 serialnumber
|
|
3438
|
-
fileMd5: params.fileMd5,
|
|
3439
|
-
// 文档必填
|
|
3721
|
+
packageName: data.packageName || "",
|
|
3722
|
+
versionCode: String(data.versionCode),
|
|
3723
|
+
apk: data.serialnumber || "",
|
|
3724
|
+
fileMd5: data.fileMd5 || "",
|
|
3440
3725
|
onlineType: "1",
|
|
3441
|
-
// 1:立即上架 2:定时上架 (必填)
|
|
3442
3726
|
compatibleDevice: "1",
|
|
3443
|
-
|
|
3444
|
-
updateDesc: params.updateDesc
|
|
3727
|
+
updateDesc: data.updateDesc
|
|
3445
3728
|
};
|
|
3729
|
+
if (data.apk32) {
|
|
3730
|
+
reqParams.apk32 = data.apk32;
|
|
3731
|
+
if (data.md532) reqParams.md532 = data.md532;
|
|
3732
|
+
}
|
|
3446
3733
|
reqParams.sign = this.generateSign(reqParams, accessSecret);
|
|
3447
3734
|
const formData = new URLSearchParams();
|
|
3448
|
-
|
|
3449
|
-
formData.append(key, value);
|
|
3450
|
-
}
|
|
3735
|
+
Object.entries(reqParams).forEach(([k, v]) => formData.append(k, v));
|
|
3451
3736
|
const res = await axios8.post(_VivoUploader.API_BASE, formData.toString(), {
|
|
3452
|
-
headers: {
|
|
3453
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
3454
|
-
},
|
|
3737
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
3455
3738
|
timeout: 3e4
|
|
3456
3739
|
});
|
|
3457
|
-
if (res.data.code !== 0) {
|
|
3458
|
-
throw new Error(`\u63D0\u4EA4\u7248\u672C\u5931\u8D25: ${res.data.msg || JSON.stringify(res.data)}`);
|
|
3459
|
-
}
|
|
3460
|
-
logger.info("\u7248\u672C\u4FE1\u606F\u5DF2\u63D0\u4EA4");
|
|
3461
|
-
}
|
|
3462
|
-
/**
|
|
3463
|
-
* 格式化错误信息
|
|
3464
|
-
*/
|
|
3465
|
-
formatError(error) {
|
|
3466
|
-
if (error.response?.data) {
|
|
3467
|
-
const data = error.response.data;
|
|
3468
|
-
return data.msg || data.message || error.message;
|
|
3469
|
-
}
|
|
3470
|
-
return error.message;
|
|
3740
|
+
if (res.data.code !== 0) throw new Error(`\u63D0\u4EA4\u5931\u8D25: ${res.data.msg}`);
|
|
3471
3741
|
}
|
|
3472
3742
|
};
|
|
3473
3743
|
|
|
3474
3744
|
// src/adapters/tencent_uploader.ts
|
|
3475
3745
|
import fs12 from "fs-extra";
|
|
3476
|
-
import
|
|
3746
|
+
import path9 from "path";
|
|
3477
3747
|
import axios9 from "axios";
|
|
3478
3748
|
import crypto6 from "crypto";
|
|
3479
3749
|
var TencentUploader = class _TencentUploader {
|
|
@@ -3505,54 +3775,71 @@ var TencentUploader = class _TencentUploader {
|
|
|
3505
3775
|
async upload(filePath, config, metadata) {
|
|
3506
3776
|
const tencentConfig = config.publish.tencent;
|
|
3507
3777
|
const auth = tencentConfig.auth;
|
|
3508
|
-
logger.info(`Tencent \u8FD0\u884C\u65F6\u914D\u7F6E: ${JSON.stringify(tencentConfig)}`);
|
|
3509
3778
|
const consoleUrl = "https://app.open.qq.com";
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
}
|
|
3779
|
+
const pkgName = tencentConfig.packageName || "";
|
|
3780
|
+
const artifacts = typeof metadata.artifactPath === "object" ? metadata.artifactPath : { universal: filePath || (typeof metadata.artifactPath === "string" ? metadata.artifactPath : "") };
|
|
3513
3781
|
try {
|
|
3514
|
-
const
|
|
3515
|
-
const
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3782
|
+
const uploadResults = {};
|
|
3783
|
+
const uploadPromises = Object.entries(artifacts).map(async ([abi, p]) => {
|
|
3784
|
+
if (!p || !fs12.existsSync(p)) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${p}`);
|
|
3785
|
+
const stats = fs12.statSync(p);
|
|
3786
|
+
const fileName = path9.basename(p);
|
|
3787
|
+
logger.info(`[Tencent] \u6B63\u5728\u5904\u7406 ${abi} \u67B6\u6784\u5305: ${fileName}`);
|
|
3788
|
+
const uploadInfo = await this.getFileUploadInfo(auth, stats.size, fileName, pkgName);
|
|
3789
|
+
await this.uploadToCos(uploadInfo.pre_sign_url, p, stats.size);
|
|
3790
|
+
const pkgInfo = await parsePackageInfo(p, {
|
|
3791
|
+
androidSdkPath: config.globalSettings?.androidSdkPath
|
|
3792
|
+
});
|
|
3793
|
+
const nativeCodes = pkgInfo?.nativeCode || [];
|
|
3794
|
+
const has64Bit = nativeCodes.includes("arm64-v8a") || nativeCodes.includes("x86_64") || abi === "arm64-v8a";
|
|
3795
|
+
const has32Bit = nativeCodes.includes("armeabi-v7a") || nativeCodes.includes("armeabi") || nativeCodes.includes("x86") || abi === "armeabi-v7a";
|
|
3796
|
+
uploadResults[abi] = {
|
|
3797
|
+
serial_number: uploadInfo.serial_number,
|
|
3798
|
+
is64Bit: has64Bit && !has32Bit,
|
|
3799
|
+
md5: pkgInfo?.md5 || ""
|
|
3800
|
+
};
|
|
3801
|
+
});
|
|
3802
|
+
await Promise.all(uploadPromises);
|
|
3803
|
+
logger.info("[Tencent] \u6B63\u5728\u83B7\u53D6\u7EBF\u4E0A\u5E94\u7528\u8BE6\u60C5...");
|
|
3804
|
+
const anyPkgPath = Object.values(artifacts)[0];
|
|
3805
|
+
const samplePkgInfo = await parsePackageInfo(anyPkgPath, {
|
|
3524
3806
|
androidSdkPath: config.globalSettings?.androidSdkPath
|
|
3525
3807
|
});
|
|
3526
|
-
const nativeCodes = pkgInfo?.nativeCode || [];
|
|
3527
|
-
const has64Bit = nativeCodes.includes("arm64-v8a") || nativeCodes.includes("x86_64");
|
|
3528
|
-
const has32Bit = nativeCodes.includes("armeabi-v7a") || nativeCodes.includes("armeabi") || nativeCodes.includes("x86");
|
|
3529
|
-
const is64Bit = has64Bit && !has32Bit;
|
|
3530
|
-
const md5 = pkgInfo?.md5;
|
|
3531
3808
|
const onlineDetail = await this.queryAppDetail(
|
|
3532
3809
|
auth,
|
|
3533
|
-
|
|
3810
|
+
pkgName || samplePkgInfo?.packageName || ""
|
|
3534
3811
|
);
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3812
|
+
const submitData = {
|
|
3813
|
+
...onlineDetail,
|
|
3814
|
+
pkg_name: pkgName || samplePkgInfo?.packageName || onlineDetail.pkg_name || "",
|
|
3815
|
+
update_desc: metadata.changelog || "\u7248\u672C\u66F4\u65B0"
|
|
3816
|
+
};
|
|
3817
|
+
const arm64Result = uploadResults["arm64-v8a"] || Object.values(uploadResults).find((r) => r.is64Bit);
|
|
3818
|
+
const arm32Result = uploadResults["armeabi-v7a"] || Object.values(uploadResults).find((r) => !r.is64Bit);
|
|
3819
|
+
if (arm64Result) {
|
|
3820
|
+
submitData.apk64_serial_number = arm64Result.serial_number;
|
|
3821
|
+
submitData.apk64_md5 = arm64Result.md5;
|
|
3822
|
+
}
|
|
3823
|
+
if (arm32Result) {
|
|
3824
|
+
submitData.apk32_serial_number = arm32Result.serial_number;
|
|
3825
|
+
submitData.apk32_md5 = arm32Result.md5;
|
|
3826
|
+
}
|
|
3827
|
+
if (Object.keys(uploadResults).length === 1 && !submitData.apk64_serial_number && !submitData.apk32_serial_number) {
|
|
3828
|
+
const single = Object.values(uploadResults)[0];
|
|
3829
|
+
if (single.is64Bit) {
|
|
3830
|
+
submitData.apk64_serial_number = single.serial_number;
|
|
3831
|
+
submitData.apk64_md5 = single.md5;
|
|
3832
|
+
} else {
|
|
3833
|
+
submitData.apk32_serial_number = single.serial_number;
|
|
3834
|
+
submitData.apk32_md5 = single.md5;
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
logger.info("[Tencent] \u6B63\u5728\u63D0\u4EA4\u5BA1\u6838\u7533\u62A5...");
|
|
3838
|
+
await this.submitModifyAppInfo(auth, submitData, { timeout: tencentConfig.timeout || 6e4 });
|
|
3551
3839
|
logger.success("\u817E\u8BAF\u5E94\u7528\u5B9D\u4E0A\u4F20\u5E76\u63D0\u4EA4\u6210\u529F!");
|
|
3552
3840
|
return { platform: "tencent", success: true, message: "\u4E0A\u4F20\u5E76\u63D0\u4EA4\u5BA1\u6838\u6210\u529F", consoleUrl };
|
|
3553
3841
|
} catch (error) {
|
|
3554
|
-
logger.error(`\u817E\u8BAF\u4E0A\u4F20\u5931\u8D25: ${
|
|
3555
|
-
logger.error(`\u817E\u8BAF\u4E0A\u4F20\u5931\u8D25: ${error.stack}`);
|
|
3842
|
+
logger.error(`\u817E\u8BAF\u4E0A\u4F20\u5931\u8D25: ${error.message}`);
|
|
3556
3843
|
return { platform: "tencent", success: false, message: error.message, error, consoleUrl };
|
|
3557
3844
|
}
|
|
3558
3845
|
}
|
|
@@ -3666,16 +3953,22 @@ var TencentUploader = class _TencentUploader {
|
|
|
3666
3953
|
signParams[key] = String(data[key]);
|
|
3667
3954
|
}
|
|
3668
3955
|
});
|
|
3669
|
-
if (data.
|
|
3670
|
-
signParams.apk64_file_serial_number = String(data.
|
|
3671
|
-
if (data.
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
signParams.
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3956
|
+
if (data.apk64_serial_number) {
|
|
3957
|
+
signParams.apk64_file_serial_number = String(data.apk64_serial_number);
|
|
3958
|
+
if (data.apk64_md5) signParams.apk64_file_md5 = data.apk64_md5;
|
|
3959
|
+
}
|
|
3960
|
+
if (data.apk32_serial_number) {
|
|
3961
|
+
signParams.apk32_file_serial_number = String(data.apk32_serial_number);
|
|
3962
|
+
if (data.apk32_md5) signParams.apk32_file_md5 = data.apk32_md5;
|
|
3963
|
+
}
|
|
3964
|
+
if (!data.apk64_serial_number && !data.apk32_serial_number && data.serial_number) {
|
|
3965
|
+
if (data.is64Bit) {
|
|
3966
|
+
signParams.apk64_file_serial_number = String(data.serial_number || "");
|
|
3967
|
+
if (data.md5) signParams.apk64_file_md5 = data.md5;
|
|
3968
|
+
} else {
|
|
3969
|
+
signParams.apk32_file_serial_number = String(data.serial_number || "");
|
|
3970
|
+
if (data.md5) signParams.apk32_file_md5 = data.md5;
|
|
3971
|
+
}
|
|
3679
3972
|
}
|
|
3680
3973
|
const sign = this.generateSign(signParams, accessSecret);
|
|
3681
3974
|
const formParams = {
|
|
@@ -3695,6 +3988,7 @@ var TencentUploader = class _TencentUploader {
|
|
|
3695
3988
|
};
|
|
3696
3989
|
|
|
3697
3990
|
// src/utils/upload-manager.ts
|
|
3991
|
+
var GROUPED_ARTIFACT_PLATFORMS = /* @__PURE__ */ new Set(["huawei", "xiaomi", "oppo", "vivo", "tencent"]);
|
|
3698
3992
|
var UploadManager = class {
|
|
3699
3993
|
uploaders;
|
|
3700
3994
|
config;
|
|
@@ -3794,30 +4088,64 @@ var UploadManager = class {
|
|
|
3794
4088
|
};
|
|
3795
4089
|
}
|
|
3796
4090
|
const files = Array.isArray(filePaths) ? filePaths : [filePaths];
|
|
3797
|
-
|
|
3798
|
-
|
|
4091
|
+
const tasks = [];
|
|
4092
|
+
validPlatforms.forEach((platform) => {
|
|
3799
4093
|
const uploader = this.uploaders.get(platform);
|
|
3800
|
-
const
|
|
3801
|
-
if (
|
|
4094
|
+
const matchedFiles = files.filter((f) => uploader.canHandle(f));
|
|
4095
|
+
if (matchedFiles.length === 0) {
|
|
3802
4096
|
logger.warn(`[${platform}] No compatible file found in provided files`);
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
4097
|
+
} else {
|
|
4098
|
+
if (this.shouldGroupArtifacts(platform)) {
|
|
4099
|
+
const artifactSelection = this.resolveArtifactSelection(platform, matchedFiles, metadata);
|
|
4100
|
+
if (!artifactSelection) {
|
|
4101
|
+
logger.warn(`[${platform}] Failed to build grouped artifact selection`);
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
tasks.push({
|
|
4105
|
+
platform,
|
|
4106
|
+
file: this.getRepresentativeFilePath(artifactSelection),
|
|
4107
|
+
artifactSelection
|
|
4108
|
+
});
|
|
4109
|
+
} else {
|
|
4110
|
+
matchedFiles.forEach((file) => {
|
|
4111
|
+
tasks.push({ platform, file, artifactSelection: file });
|
|
4112
|
+
});
|
|
4113
|
+
}
|
|
3808
4114
|
}
|
|
3809
|
-
|
|
3810
|
-
|
|
4115
|
+
});
|
|
4116
|
+
if (tasks.length === 0) {
|
|
4117
|
+
logger.error("No valid platform-file matches found");
|
|
4118
|
+
return {
|
|
4119
|
+
totalUploads: validPlatforms.length,
|
|
4120
|
+
successCount: 0,
|
|
4121
|
+
failureCount: validPlatforms.length,
|
|
4122
|
+
successPlatforms: [],
|
|
4123
|
+
failurePlatforms: validPlatforms,
|
|
4124
|
+
results: [],
|
|
4125
|
+
totalDurationMs: Date.now() - startTime,
|
|
4126
|
+
summary: "No compatible files found for any of the selected platforms"
|
|
4127
|
+
};
|
|
4128
|
+
}
|
|
4129
|
+
logger.info(`Scheduled ${tasks.length} upload task(s) for ${validPlatforms.length} platform(s)`);
|
|
4130
|
+
const uploadPromises = tasks.map((task) => {
|
|
4131
|
+
logger.info(`[${task.platform}] Matched file: ${path10.basename(task.file)}`);
|
|
4132
|
+
return this.uploadToPlatform(
|
|
4133
|
+
task.platform,
|
|
4134
|
+
task.file,
|
|
4135
|
+
config,
|
|
4136
|
+
metadata,
|
|
4137
|
+
task.artifactSelection
|
|
4138
|
+
);
|
|
3811
4139
|
});
|
|
3812
4140
|
const results = await Promise.all(uploadPromises);
|
|
3813
|
-
const report = this.aggregateResults(results,
|
|
4141
|
+
const report = this.aggregateResults(results, tasks.length, startTime);
|
|
3814
4142
|
this.printReport(report);
|
|
3815
4143
|
return report;
|
|
3816
4144
|
}
|
|
3817
4145
|
/**
|
|
3818
4146
|
* 上传到单个平台
|
|
3819
4147
|
*/
|
|
3820
|
-
async uploadToPlatform(platform, filePath, config, metadata) {
|
|
4148
|
+
async uploadToPlatform(platform, filePath, config, metadata, artifactSelection = filePath) {
|
|
3821
4149
|
if (this.config.cancellationToken?.isCancelled) {
|
|
3822
4150
|
logger.warn(`[${platform.toUpperCase()}] Upload skipped due to cancellation`);
|
|
3823
4151
|
return {
|
|
@@ -3838,25 +4166,30 @@ var UploadManager = class {
|
|
|
3838
4166
|
if (this.config.verbose) {
|
|
3839
4167
|
logger.info(`[${platform.toUpperCase()}] Starting upload...`);
|
|
3840
4168
|
}
|
|
4169
|
+
const effectiveMetadata = {
|
|
4170
|
+
...metadata,
|
|
4171
|
+
artifactPath: artifactSelection
|
|
4172
|
+
};
|
|
4173
|
+
await this.validateArtifactSelection(platform, artifactSelection, effectiveMetadata);
|
|
3841
4174
|
const pkgInfo = await parsePackageInfo(filePath, {
|
|
3842
|
-
androidSdkPath:
|
|
4175
|
+
androidSdkPath: effectiveMetadata.globalSettings?.androidSdkPath
|
|
3843
4176
|
});
|
|
3844
4177
|
if (pkgInfo) {
|
|
3845
4178
|
if (pkgInfo.versionName) {
|
|
3846
|
-
|
|
4179
|
+
effectiveMetadata.version = pkgInfo.versionName;
|
|
3847
4180
|
}
|
|
3848
4181
|
if (pkgInfo.versionCode) {
|
|
3849
|
-
|
|
4182
|
+
effectiveMetadata.buildNumber = pkgInfo.versionCode;
|
|
3850
4183
|
}
|
|
3851
4184
|
if (pkgInfo.packageName) {
|
|
3852
4185
|
;
|
|
3853
|
-
|
|
4186
|
+
effectiveMetadata.packageName = pkgInfo.packageName;
|
|
3854
4187
|
}
|
|
3855
4188
|
logger.info(
|
|
3856
|
-
`[${platform.toUpperCase()}] \u5DF2\u6821\u51C6\u7248\u672C\u4FE1\u606F: v${
|
|
4189
|
+
`[${platform.toUpperCase()}] \u5DF2\u6821\u51C6\u7248\u672C\u4FE1\u606F: v${effectiveMetadata.version}+${effectiveMetadata.buildNumber}`
|
|
3857
4190
|
);
|
|
3858
4191
|
}
|
|
3859
|
-
const result = await uploader.upload(filePath, config,
|
|
4192
|
+
const result = await uploader.upload(filePath, config, effectiveMetadata);
|
|
3860
4193
|
return result;
|
|
3861
4194
|
} catch (error) {
|
|
3862
4195
|
const errorMessage = error.message || String(error);
|
|
@@ -3869,6 +4202,85 @@ var UploadManager = class {
|
|
|
3869
4202
|
};
|
|
3870
4203
|
}
|
|
3871
4204
|
}
|
|
4205
|
+
shouldGroupArtifacts(platform) {
|
|
4206
|
+
return GROUPED_ARTIFACT_PLATFORMS.has(platform);
|
|
4207
|
+
}
|
|
4208
|
+
resolveArtifactSelection(platform, matchedFiles, metadata) {
|
|
4209
|
+
const explicitArtifacts = metadata.platformArtifacts?.[platform];
|
|
4210
|
+
if (explicitArtifacts) {
|
|
4211
|
+
if (typeof explicitArtifacts === "string") {
|
|
4212
|
+
return explicitArtifacts;
|
|
4213
|
+
}
|
|
4214
|
+
if (Object.keys(explicitArtifacts).length > 0) {
|
|
4215
|
+
return explicitArtifacts;
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
if (matchedFiles.length === 0) {
|
|
4219
|
+
return null;
|
|
4220
|
+
}
|
|
4221
|
+
if (matchedFiles.length === 1) {
|
|
4222
|
+
return matchedFiles[0];
|
|
4223
|
+
}
|
|
4224
|
+
return this.buildArtifactMapFromFiles(matchedFiles);
|
|
4225
|
+
}
|
|
4226
|
+
buildArtifactMapFromFiles(files) {
|
|
4227
|
+
return files.reduce(
|
|
4228
|
+
(acc, filePath, index) => {
|
|
4229
|
+
acc[this.inferArtifactKey(filePath, index)] = filePath;
|
|
4230
|
+
return acc;
|
|
4231
|
+
},
|
|
4232
|
+
{}
|
|
4233
|
+
);
|
|
4234
|
+
}
|
|
4235
|
+
inferArtifactKey(filePath, index) {
|
|
4236
|
+
const fileName = path10.basename(filePath).toLowerCase();
|
|
4237
|
+
if (fileName.includes("arm64-v8a")) return "arm64-v8a";
|
|
4238
|
+
if (fileName.includes("armeabi-v7a")) return "armeabi-v7a";
|
|
4239
|
+
if (fileName.includes("x86_64")) return "x86_64";
|
|
4240
|
+
if (fileName.includes("universal")) return "universal";
|
|
4241
|
+
return `artifact_${index + 1}`;
|
|
4242
|
+
}
|
|
4243
|
+
getRepresentativeFilePath(artifactSelection) {
|
|
4244
|
+
if (typeof artifactSelection === "string") {
|
|
4245
|
+
return artifactSelection;
|
|
4246
|
+
}
|
|
4247
|
+
return Object.values(artifactSelection)[0];
|
|
4248
|
+
}
|
|
4249
|
+
async validateArtifactSelection(platform, artifactSelection, metadata) {
|
|
4250
|
+
if (typeof artifactSelection === "string") {
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4253
|
+
const artifactPaths = Object.values(artifactSelection).filter(Boolean);
|
|
4254
|
+
if (artifactPaths.length < 2) {
|
|
4255
|
+
return;
|
|
4256
|
+
}
|
|
4257
|
+
const parsedInfos = await Promise.all(
|
|
4258
|
+
artifactPaths.map(
|
|
4259
|
+
(artifactPath) => parsePackageInfo(artifactPath, {
|
|
4260
|
+
androidSdkPath: metadata.globalSettings?.androidSdkPath
|
|
4261
|
+
})
|
|
4262
|
+
)
|
|
4263
|
+
);
|
|
4264
|
+
const availableInfos = parsedInfos.filter((info) => !!info);
|
|
4265
|
+
if (availableInfos.length < 2) {
|
|
4266
|
+
logger.warn(
|
|
4267
|
+
`[${platform.toUpperCase()}] Unable to fully validate multi-artifact package info; continuing with upload.`
|
|
4268
|
+
);
|
|
4269
|
+
return;
|
|
4270
|
+
}
|
|
4271
|
+
const [baseInfo, ...restInfos] = availableInfos;
|
|
4272
|
+
for (const info of restInfos) {
|
|
4273
|
+
if (baseInfo?.packageName && info?.packageName && baseInfo.packageName !== info.packageName) {
|
|
4274
|
+
throw new Error("\u53CC\u5305\u4E0A\u4F20\u5931\u8D25\uFF1A\u6240\u9009\u5B89\u88C5\u5305\u7684 packageName \u4E0D\u4E00\u81F4");
|
|
4275
|
+
}
|
|
4276
|
+
if (baseInfo?.versionName && info?.versionName && baseInfo.versionName !== info.versionName) {
|
|
4277
|
+
throw new Error("\u53CC\u5305\u4E0A\u4F20\u5931\u8D25\uFF1A\u6240\u9009\u5B89\u88C5\u5305\u7684 versionName \u4E0D\u4E00\u81F4");
|
|
4278
|
+
}
|
|
4279
|
+
if (baseInfo?.versionCode && info?.versionCode && baseInfo.versionCode !== info.versionCode) {
|
|
4280
|
+
throw new Error("\u53CC\u5305\u4E0A\u4F20\u5931\u8D25\uFF1A\u6240\u9009\u5B89\u88C5\u5305\u7684 versionCode \u4E0D\u4E00\u81F4");
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
3872
4284
|
/**
|
|
3873
4285
|
* 聚合上传结果
|
|
3874
4286
|
*/
|
|
@@ -4086,7 +4498,7 @@ var ConfigValidator = class {
|
|
|
4086
4498
|
};
|
|
4087
4499
|
|
|
4088
4500
|
// src/cli.ts
|
|
4089
|
-
import
|
|
4501
|
+
import path11 from "path";
|
|
4090
4502
|
import fs14 from "fs-extra";
|
|
4091
4503
|
import yaml2 from "js-yaml";
|
|
4092
4504
|
var VERSION = "0.1.0";
|
|
@@ -4152,8 +4564,8 @@ async function cmdUpload(args) {
|
|
|
4152
4564
|
logger.error("Missing file path. Use: app-ship upload -c <config.yaml> -f <file>");
|
|
4153
4565
|
process.exit(1);
|
|
4154
4566
|
}
|
|
4155
|
-
const absConfig =
|
|
4156
|
-
const absFile =
|
|
4567
|
+
const absConfig = path11.resolve(configPath);
|
|
4568
|
+
const absFile = path11.resolve(filePath);
|
|
4157
4569
|
if (!fs14.existsSync(absFile)) {
|
|
4158
4570
|
logger.error(`File not found: ${absFile}`);
|
|
4159
4571
|
process.exit(1);
|