From 20f9040e48420ebe1c54873674c940eba24c08da Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sat, 14 Nov 2026 09:14:38 +0700 Subject: [PATCH] android: uploadShx sends the build commit to the SHX VPN panel: upload-apk.mjs takes it from --commit, SHX_COMMIT or git rev-parse HEAD of the repository the APK lies in, and warns when the working copy has uncommitted changes; the panel shows it in the version card and gives it to a connected model through MCP, so a report on a version leads to the code that version was built from Co-Authored-By: Claude Fable 5.2 --- src/frontends/android/scripts/upload-apk.mjs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/frontends/android/scripts/upload-apk.mjs b/src/frontends/android/scripts/upload-apk.mjs index bc2a8f518..af4ebcdf1 100644 --- a/src/frontends/android/scripts/upload-apk.mjs +++ b/src/frontends/android/scripts/upload-apk.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // Загрузка собранного APK в панель SHX VPN с компьютера сборки. Нужен только Node 18+, без зависимостей. // -// node upload-apk.mjs app-release.apk --type phone --channel beta [--publish] [--rollout 100] [--notes "Что нового"] +// node upload-apk.mjs app-release.apk --type phone --channel beta [--publish] [--rollout 100] [--notes "Что нового"] [--commit <хэш>] // // Окружение: // SHX_URL адрес консоли, например https://apk.shnt.top @@ -9,6 +9,8 @@ // // versionName и versionCode берутся из output-metadata.json, который Gradle кладёт рядом с APK, // либо из --version-name / --version-code. +// Коммит сборки (по нему нейросеть через MCP открывает код нужной версии) берётся из --commit, SHX_COMMIT +// или из git-репозитория, в котором лежит APK. // // Шаги: билет на загрузку → файл напрямую в S3 по presigned PUT → сервер проверяет SHA-256 и оформляет версию. import { execFileSync } from "node:child_process"; @@ -28,6 +30,7 @@ const { values: o, positionals } = parseArgs({ "notes-en": { type: "string", default: "" }, publish: { type: "boolean", default: false }, rollout: { type: "string", default: "100" }, + commit: { type: "string" }, help: { type: "boolean", short: "h", default: false }, }, }); @@ -72,6 +75,15 @@ if ((!versionName || !versionCode) && existsSync(meta)) { } if (!versionName || !Number.isInteger(versionCode)) die("Не удалось определить версию: передайте --version-name и --version-code"); +const git = (...args) => { + try { return execFileSync("git", args, { cwd: dirname(file), encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim(); } catch { return ""; } +}; +const commit = (o.commit ?? process.env.SHX_COMMIT ?? git("rev-parse", "HEAD")).toLowerCase(); +if (commit && !/^[0-9a-f]{7,40}$/.test(commit)) die("--commit: ожидается хэш git (7–40 шестнадцатеричных символов)"); +if (!commit) console.warn("! коммит сборки не определён (APK вне git-репозитория): версия загрузится без него"); +// сборка с правками поверх коммита: код по хэшу будет не тем, что в APK +else if (!o.commit && !process.env.SHX_COMMIT && git("status", "--porcelain", "--untracked-files=no")) console.warn("! в рабочей копии есть незакоммиченные изменения: коммит " + commit.slice(0, 12) + " не точно соответствует сборке"); + const bytes = readFileSync(file); const sha256 = createHash("sha256").update(bytes).digest("hex"); const mb = (statSync(file).size / 1048576).toFixed(1); @@ -87,7 +99,7 @@ async function api(path, body) { return data; } -console.log(`→ ${o.type} / ${o.channel} / ${versionName} (${versionCode}), ${mb} МБ, sha256 ${sha256.slice(0, 12)}…`); +console.log(`→ ${o.type} / ${o.channel} / ${versionName} (${versionCode}), ${mb} МБ, sha256 ${sha256.slice(0, 12)}…${commit ? `, коммит ${commit.slice(0, 12)}` : ""}`); const ticket = await api("/api/admin/versions/uploads", { typeId: o.type, channel: o.channel, versionName, versionCode }); if (bytes.length > ticket.maxBytes) die("Файл больше допустимого размера"); @@ -102,6 +114,7 @@ const v = await api("/api/admin/versions", { notes: { ru: o.notes, en: o["notes-en"] }, publish: o.publish, rolloutPct, + ...(commit ? { commit } : {}), }); console.log(`✓ версия оформлена: ${v.versionName}, статус ${v.status}${o.publish ? `, раскатка ${rolloutPct}%` : " (черновик: опубликуйте в консоли)"}`); console.log(` ${base}/versions/${v.id}`);