@gpc-cli/core 0.9.25 → 0.9.27
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/dist/index.d.ts +1 -0
- package/dist/index.js +50 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -145,6 +145,7 @@ declare function uploadRelease(client: PlayApiClient, packageName: string, fileP
|
|
|
145
145
|
releaseName?: string;
|
|
146
146
|
mappingFile?: string;
|
|
147
147
|
dryRun?: boolean;
|
|
148
|
+
onProgress?: (uploaded: number, total: number) => void;
|
|
148
149
|
}): Promise<UploadResult | DryRunUploadResult>;
|
|
149
150
|
declare function getReleasesStatus(client: PlayApiClient, packageName: string, trackFilter?: string): Promise<ReleaseStatusResult[]>;
|
|
150
151
|
declare function promoteRelease(client: PlayApiClient, packageName: string, fromTrack: string, toTrack: string, options?: {
|
package/dist/index.js
CHANGED
|
@@ -494,6 +494,9 @@ async function getAppInfo(client, packageName) {
|
|
|
494
494
|
}
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
+
// src/commands/releases.ts
|
|
498
|
+
import { stat as stat2 } from "fs/promises";
|
|
499
|
+
|
|
497
500
|
// src/utils/file-validation.ts
|
|
498
501
|
import { readFile, stat } from "fs/promises";
|
|
499
502
|
import { extname } from "path";
|
|
@@ -615,9 +618,17 @@ ${validation.errors.join("\n")}`,
|
|
|
615
618
|
"Check that the file is a valid AAB or APK and is not corrupted."
|
|
616
619
|
);
|
|
617
620
|
}
|
|
621
|
+
let fileSize = 0;
|
|
622
|
+
try {
|
|
623
|
+
const { size } = await stat2(filePath);
|
|
624
|
+
fileSize = size;
|
|
625
|
+
} catch {
|
|
626
|
+
}
|
|
627
|
+
if (options.onProgress) options.onProgress(0, fileSize);
|
|
618
628
|
const edit = await client.edits.insert(packageName);
|
|
619
629
|
try {
|
|
620
630
|
const bundle = await client.bundles.upload(packageName, edit.id, filePath);
|
|
631
|
+
if (options.onProgress) options.onProgress(fileSize, fileSize);
|
|
621
632
|
if (options.mappingFile) {
|
|
622
633
|
await client.deobfuscation.upload(
|
|
623
634
|
packageName,
|
|
@@ -998,7 +1009,7 @@ function isValidBcp47(tag) {
|
|
|
998
1009
|
}
|
|
999
1010
|
|
|
1000
1011
|
// src/utils/image-validation.ts
|
|
1001
|
-
import { stat as
|
|
1012
|
+
import { stat as stat3 } from "fs/promises";
|
|
1002
1013
|
import { extname as extname2 } from "path";
|
|
1003
1014
|
var IMAGE_SIZE_LIMITS = {
|
|
1004
1015
|
icon: { maxBytes: 1024 * 1024, label: "1 MB" },
|
|
@@ -1021,7 +1032,7 @@ async function validateImage(filePath, imageType) {
|
|
|
1021
1032
|
}
|
|
1022
1033
|
let sizeBytes;
|
|
1023
1034
|
try {
|
|
1024
|
-
const stats = await
|
|
1035
|
+
const stats = await stat3(filePath);
|
|
1025
1036
|
sizeBytes = stats.size;
|
|
1026
1037
|
if (sizeBytes === 0) {
|
|
1027
1038
|
errors.push("Image file is empty (0 bytes)");
|
|
@@ -1055,7 +1066,7 @@ function formatSize2(bytes) {
|
|
|
1055
1066
|
}
|
|
1056
1067
|
|
|
1057
1068
|
// src/utils/fastlane.ts
|
|
1058
|
-
import { readFile as readFile2, writeFile, mkdir, readdir, stat as
|
|
1069
|
+
import { readFile as readFile2, writeFile, mkdir, readdir, stat as stat4 } from "fs/promises";
|
|
1059
1070
|
import { join } from "path";
|
|
1060
1071
|
var FILE_MAP = {
|
|
1061
1072
|
"title.txt": "title",
|
|
@@ -1068,7 +1079,7 @@ var FIELD_TO_FILE = Object.fromEntries(
|
|
|
1068
1079
|
);
|
|
1069
1080
|
async function exists(path) {
|
|
1070
1081
|
try {
|
|
1071
|
-
await
|
|
1082
|
+
await stat4(path);
|
|
1072
1083
|
return true;
|
|
1073
1084
|
} catch {
|
|
1074
1085
|
return false;
|
|
@@ -1082,7 +1093,7 @@ async function readListingsFromDir(dir) {
|
|
|
1082
1093
|
for (const lang of entries) {
|
|
1083
1094
|
if (!SAFE_LANG.test(lang)) continue;
|
|
1084
1095
|
const langDir = join(dir, lang);
|
|
1085
|
-
const langStat = await
|
|
1096
|
+
const langStat = await stat4(langDir);
|
|
1086
1097
|
if (!langStat.isDirectory()) continue;
|
|
1087
1098
|
const listing = {
|
|
1088
1099
|
language: lang,
|
|
@@ -1704,7 +1715,7 @@ function validateSku(sku) {
|
|
|
1704
1715
|
}
|
|
1705
1716
|
|
|
1706
1717
|
// src/utils/release-notes.ts
|
|
1707
|
-
import { readdir as readdir3, readFile as readFile4, stat as
|
|
1718
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat5 } from "fs/promises";
|
|
1708
1719
|
import { extname as extname3, basename, join as join3 } from "path";
|
|
1709
1720
|
var MAX_NOTES_LENGTH = 500;
|
|
1710
1721
|
async function readReleaseNotesFromDir(dir) {
|
|
@@ -1724,7 +1735,7 @@ async function readReleaseNotesFromDir(dir) {
|
|
|
1724
1735
|
if (extname3(entry) !== ".txt") continue;
|
|
1725
1736
|
const language = basename(entry, ".txt");
|
|
1726
1737
|
const filePath = join3(dir, entry);
|
|
1727
|
-
const stats = await
|
|
1738
|
+
const stats = await stat5(filePath);
|
|
1728
1739
|
if (!stats.isFile()) continue;
|
|
1729
1740
|
const text = (await readFile4(filePath, "utf-8")).trim();
|
|
1730
1741
|
if (text.length === 0) continue;
|
|
@@ -1742,8 +1753,8 @@ function validateReleaseNotes(notes) {
|
|
|
1742
1753
|
}
|
|
1743
1754
|
seen.add(note.language);
|
|
1744
1755
|
if (note.text.length > MAX_NOTES_LENGTH) {
|
|
1745
|
-
|
|
1746
|
-
`Release notes for "${note.language}"
|
|
1756
|
+
warnings.push(
|
|
1757
|
+
`Release notes for "${note.language}" are ${note.text.length} chars (max ${MAX_NOTES_LENGTH}) \u2014 Google Play will reject notes exceeding this limit`
|
|
1747
1758
|
);
|
|
1748
1759
|
}
|
|
1749
1760
|
}
|
|
@@ -1751,7 +1762,7 @@ function validateReleaseNotes(notes) {
|
|
|
1751
1762
|
}
|
|
1752
1763
|
|
|
1753
1764
|
// src/commands/validate.ts
|
|
1754
|
-
import { stat as
|
|
1765
|
+
import { stat as stat6 } from "fs/promises";
|
|
1755
1766
|
var STANDARD_TRACKS = /* @__PURE__ */ new Set([
|
|
1756
1767
|
"internal",
|
|
1757
1768
|
"alpha",
|
|
@@ -1790,7 +1801,7 @@ async function validatePreSubmission(options) {
|
|
|
1790
1801
|
}
|
|
1791
1802
|
if (options.mappingFile) {
|
|
1792
1803
|
try {
|
|
1793
|
-
const stats = await
|
|
1804
|
+
const stats = await stat6(options.mappingFile);
|
|
1794
1805
|
checks.push({
|
|
1795
1806
|
name: "mapping",
|
|
1796
1807
|
passed: stats.isFile(),
|
|
@@ -1836,6 +1847,7 @@ async function validatePreSubmission(options) {
|
|
|
1836
1847
|
passed: notesResult.valid,
|
|
1837
1848
|
message: notesResult.valid ? `Release notes valid (${resolvedNotes.length} language(s))` : notesResult.errors.join("; ")
|
|
1838
1849
|
});
|
|
1850
|
+
for (const w of notesResult.warnings) resultWarnings.push(w);
|
|
1839
1851
|
}
|
|
1840
1852
|
return {
|
|
1841
1853
|
valid: checks.every((c) => c.passed),
|
|
@@ -3822,7 +3834,7 @@ async function deactivatePurchaseOption(client, packageName, purchaseOptionId) {
|
|
|
3822
3834
|
}
|
|
3823
3835
|
|
|
3824
3836
|
// src/commands/bundle-analysis.ts
|
|
3825
|
-
import { readFile as readFile9, stat as
|
|
3837
|
+
import { readFile as readFile9, stat as stat7 } from "fs/promises";
|
|
3826
3838
|
var EOCD_SIGNATURE = 101010256;
|
|
3827
3839
|
var CD_SIGNATURE = 33639248;
|
|
3828
3840
|
var MODULE_SUBDIRS = /* @__PURE__ */ new Set(["dex", "manifest", "res", "assets", "lib", "resources.pb", "root"]);
|
|
@@ -3896,7 +3908,7 @@ function detectFileType2(filePath) {
|
|
|
3896
3908
|
return "apk";
|
|
3897
3909
|
}
|
|
3898
3910
|
async function analyzeBundle(filePath) {
|
|
3899
|
-
const fileInfo = await
|
|
3911
|
+
const fileInfo = await stat7(filePath).catch(() => null);
|
|
3900
3912
|
if (!fileInfo || !fileInfo.isFile()) {
|
|
3901
3913
|
throw new Error(`File not found: ${filePath}`);
|
|
3902
3914
|
}
|
|
@@ -4189,13 +4201,22 @@ function formatTrend(current, previous) {
|
|
|
4189
4201
|
if (current < previous) return ` \u2193 from ${previous.toFixed(1)}`;
|
|
4190
4202
|
return "";
|
|
4191
4203
|
}
|
|
4204
|
+
function relativeTime(isoString) {
|
|
4205
|
+
const diffMs = Date.now() - new Date(isoString).getTime();
|
|
4206
|
+
const diffMin = Math.floor(diffMs / 6e4);
|
|
4207
|
+
if (diffMin < 1) return "just now";
|
|
4208
|
+
if (diffMin < 60) return `${diffMin} min ago`;
|
|
4209
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
4210
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
4211
|
+
return `${Math.floor(diffHr / 24)}d ago`;
|
|
4212
|
+
}
|
|
4192
4213
|
function allVitalsUnknown(vitals) {
|
|
4193
4214
|
return vitals.crashes.status === "unknown" && vitals.anr.status === "unknown" && vitals.slowStarts.status === "unknown" && vitals.slowRender.status === "unknown";
|
|
4194
4215
|
}
|
|
4195
4216
|
function formatStatusTable(status) {
|
|
4196
4217
|
const lines = [];
|
|
4197
4218
|
const sectionSet = new Set(status.sections);
|
|
4198
|
-
const cachedLabel = status.cached ? ` (cached ${
|
|
4219
|
+
const cachedLabel = status.cached ? ` (cached ${relativeTime(status.fetchedAt)})` : ` (fetched ${relativeTime(status.fetchedAt)})`;
|
|
4199
4220
|
lines.push(`App: ${status.packageName}${cachedLabel}`);
|
|
4200
4221
|
if (sectionSet.has("releases")) {
|
|
4201
4222
|
lines.push("");
|
|
@@ -4253,20 +4274,25 @@ function formatStatusSummary(status) {
|
|
|
4253
4274
|
parts.push(`v${latestRelease.versionCode} ${latestRelease.track}`);
|
|
4254
4275
|
}
|
|
4255
4276
|
const { crashes, anr } = status.vitals;
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
parts.push(
|
|
4259
|
-
}
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4277
|
+
const allVitalsUnknown2 = crashes.status === "unknown" && anr.status === "unknown";
|
|
4278
|
+
if (allVitalsUnknown2) {
|
|
4279
|
+
parts.push("no vitals");
|
|
4280
|
+
} else {
|
|
4281
|
+
if (crashes.status !== "unknown") {
|
|
4282
|
+
const arrow = crashes.trend === "up" ? " \u2191" : crashes.trend === "down" ? " \u2193" : "";
|
|
4283
|
+
parts.push(`crashes ${formatVitalValue(crashes)}${arrow} ${vitalIndicator(crashes)}`);
|
|
4284
|
+
}
|
|
4285
|
+
if (anr.status !== "unknown") {
|
|
4286
|
+
const arrow = anr.trend === "up" ? " \u2191" : anr.trend === "down" ? " \u2193" : "";
|
|
4287
|
+
parts.push(`ANR ${formatVitalValue(anr)}${arrow} ${vitalIndicator(anr)}`);
|
|
4288
|
+
}
|
|
4263
4289
|
}
|
|
4264
4290
|
const { averageRating, totalNew } = status.reviews;
|
|
4265
4291
|
if (averageRating !== void 0) {
|
|
4266
4292
|
parts.push(`avg ${averageRating.toFixed(1)}\u2605`);
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
parts.push(
|
|
4293
|
+
if (totalNew > 0) parts.push(`${totalNew} reviews`);
|
|
4294
|
+
} else {
|
|
4295
|
+
parts.push("no reviews");
|
|
4270
4296
|
}
|
|
4271
4297
|
return parts.join(" \xB7 ") + (statusHasBreach(status) ? " [ALERT]" : "");
|
|
4272
4298
|
}
|