From 080684570db59281297800d3491bc7791fe55a60 Mon Sep 17 00:00:00 2001 From: Andrey Prokopyuk Date: Sat, 19 Sep 2026 12:17:30 +0300 Subject: [PATCH 1/4] Add Fastlane Google Play release upload lane --- README.md | 5 +++++ docs/en/fastlane.md | 53 ++++++++++++++++++++++++++++++++++++++++++++ docs/ru/fastlane.md | 54 +++++++++++++++++++++++++++++++++++++++++++++ fastlane/Fastfile | 50 +++++++++++++++++++++++++++++++++++++++++ fastlane/README.md | 4 +++- 5 files changed, 165 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6983334..ea2962f 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,11 @@ and `SHA256SUMS` are written to `dist/release`. The App Bundle contains every su stores generate and serve optimized device-specific APK splits from it. Go native symbols are provided as `mega-proxy-native-debug-symbols.zip` for upload in Play Console. +To upload the AAB and native symbols through Fastlane, configure a Play service account and run +`bundle exec fastlane android play_release` (internal draft by default). See the +[Google Play release instructions](docs/en/fastlane.md#google-play-releases) +([по-русски](docs/ru/fastlane.md#релизы-в-google-play)) for credentials, validation and production uploads. + Pushing a version tag runs the same Fastlane release lane in GitHub Actions, builds and verifies every APK and the App Bundle, and attaches the artifacts to a GitHub Release. The tag must match `v` followed by the current `versionName` in `app/build.gradle.kts`. Create that tag with diff --git a/docs/en/fastlane.md b/docs/en/fastlane.md index fae3313..bb95636 100644 --- a/docs/en/fastlane.md +++ b/docs/en/fastlane.md @@ -46,6 +46,7 @@ That command lists the lanes available in the checked-out version of the project | `bundle exec fastlane android test` | Runs `native_tests` and `android_checks`; this is the normal pre-commit command. | | `bundle exec fastlane android debug_artifact` | Builds `app/build/outputs/apk/debug/app-debug.apk`. | | `bundle exec fastlane android release_artifacts` | Builds and verifies the signed release APKs, AAB, native debug symbols, and `SHA256SUMS` in `dist/release`. | +| `bundle exec fastlane android play_release` | Uploads an existing signed AAB and native symbols to Google Play; defaults to an internal draft. | The release lane requires the signing configuration described in [Signed release builds](../../README.md#signed-release-builds). It builds artifacts but does not @@ -65,6 +66,58 @@ creates or updates one APK-links comment on the pull request. It does not check execute pull-request code or artifacts. These are test artifacts only: neither APK is signed with the MegaProxy release key, and neither is published as a GitHub Release or sent to an app store. +## Google Play releases + +`play_release` uploads an existing signed AAB and its matching native symbols for +`net.megaproxy487`. Build them with `release_artifacts` or download both from the same verified +GitHub Release. The lane does not build or sign files. Use an unused, increasing `versionCode`. +The AAB must be signed with the upload key registered in Play Console. + +Before the first API upload, create the app in Play Console, configure Play App Signing and upload +an initial build manually. Enable the Google Play Developer API in a Google Cloud project, create +a service account and invite its email in Play Console with access to this app and permissions +for the intended test/production tracks. Store its JSON key outside the repository. +See [Google API setup](https://developers.google.com/android-publisher/getting_started) and +[Fastlane supply setup](https://docs.fastlane.tools/actions/upload_to_play_store/#setup). + +Run from the repository root: + +```shell +export MEGAPROXY_PLAY_JSON_KEY="$HOME/.my-tokens/megaproxy-play.json" +bundle exec fastlane android release_artifacts +bundle exec fastlane android play_release validate_only:true +bundle exec fastlane android play_release +``` + +The default upload creates a **draft on the internal track**. `validate_only:true` uploads to a +temporary Google Play edit and asks the API to validate it without committing a release; it needs +credentials and network access and is not an offline dry run. Review/complete a draft in Play Console. +For a new AAB that should be released directly to testers or production, explicitly select: + +```shell +bundle exec fastlane android play_release track:internal release_status:completed +bundle exec fastlane android play_release track:production release_status:completed +``` + +Run only the command for the intended destination. Google review, app eligibility and managed +publishing can still delay availability. To promote an already uploaded version, use Play Console; +this lane uploads a new AAB and does not promote existing releases. + +| Option | Default / behavior | +| --- | --- | +| `aab` | `dist/release/mega-proxy.aab` | +| `symbols` | `dist/release/mega-proxy-native-debug-symbols.zip`; required and must match the AAB | +| `json_key` | JSON file path; falls back to `MEGAPROXY_PLAY_JSON_KEY` | +| `track` | `internal`; also accepts `alpha`, `beta`, `production` or a custom track ID | +| `release_status` | `draft`; supports `draft` or `completed` | +| `validate_only` | `false`; accepts only `true` or `false` | + +`MEGAPROXY_RELEASE_DIR` overrides the default artifact directory. Relative file paths are resolved +from the repository root. Metadata, changelogs, images and screenshots are not uploaded; the +F-Droid listing under `fastlane/metadata/android` is left separate from Play listing management. +The existing tag workflow still publishes only to GitHub. PR CI must not receive the Play JSON key +or invoke `play_release`. + ## Updating Fastlane Update Fastlane deliberately and commit both dependency files: diff --git a/docs/ru/fastlane.md b/docs/ru/fastlane.md index f7fe382..c2267b8 100644 --- a/docs/ru/fastlane.md +++ b/docs/ru/fastlane.md @@ -47,6 +47,7 @@ bundle exec fastlane lanes | `bundle exec fastlane android test` | Выполняет `native_tests` и `android_checks`; основная команда перед коммитом. | | `bundle exec fastlane android debug_artifact` | Собирает `app/build/outputs/apk/debug/app-debug.apk`. | | `bundle exec fastlane android release_artifacts` | Собирает и проверяет подписанные APK, AAB, native debug symbols и `SHA256SUMS` в `dist/release`. | +| `bundle exec fastlane android play_release` | Загружает готовый подписанный AAB и native symbols в Google Play; по умолчанию создаёт internal-черновик. | Для release lane нужна конфигурация подписи из раздела [Signed release builds](../../README.md#signed-release-builds). Lane только собирает артефакты: он @@ -67,6 +68,59 @@ checkout, не скачивает и не исполняет код или ар один из APK не подписан официальным release-ключом MegaProxy, не публикуется в GitHub Releases и не отправляется в магазин приложений. +## Релизы в Google Play + +`play_release` загружает готовый подписанный AAB и соответствующие native symbols для +`net.megaproxy487`. Соберите их через `release_artifacts` или скачайте оба файла из одного +проверенного GitHub Release. Lane не собирает и не подписывает файлы. Для нового релиза нужен +неиспользованный возрастающий `versionCode`. AAB должен быть подписан upload key, +зарегистрированным в Play Console. + +Перед первой загрузкой через API создайте приложение в Play Console, настройте Play App Signing +и вручную загрузите первоначальную сборку. Включите Google Play Developer API в проекте Google +Cloud, создайте сервисный аккаунт и пригласите его email в Play Console с доступом к приложению +и правами для нужных тестовых/production-треков. Храните JSON-ключ вне репозитория. +См. [настройку Google API](https://developers.google.com/android-publisher/getting_started) и +[настройку Fastlane supply](https://docs.fastlane.tools/actions/upload_to_play_store/#setup). + +Запускайте из корня репозитория: + +```shell +export MEGAPROXY_PLAY_JSON_KEY="$HOME/.my-tokens/megaproxy-play.json" +bundle exec fastlane android release_artifacts +bundle exec fastlane android play_release validate_only:true +bundle exec fastlane android play_release +``` + +По умолчанию создаётся **черновик в треке internal**. `validate_only:true` загружает файлы во +временную транзакцию Google Play и проверяет её через API без сохранения релиза; нужны ключ +и сеть, это не локальный dry run. Проверьте и завершите черновик в Play Console. +Для нового AAB, который нужно сразу отправить тестировщикам или в production, явно укажите: + +```shell +bundle exec fastlane android play_release track:internal release_status:completed +bundle exec fastlane android play_release track:production release_status:completed +``` + +Выполняйте только команду для нужного направления. Проверка Google, доступность публикации для +приложения и managed publishing могут задержать появление релиза. Уже загруженную версию +продвигайте через Play Console: lane загружает новый AAB и не продвигает существующие релизы. + +| Параметр | Значение по умолчанию / поведение | +| --- | --- | +| `aab` | `dist/release/mega-proxy.aab` | +| `symbols` | `dist/release/mega-proxy-native-debug-symbols.zip`; обязателен и должен соответствовать AAB | +| `json_key` | Путь к JSON-файлу; при отсутствии используется `MEGAPROXY_PLAY_JSON_KEY` | +| `track` | `internal`; также принимает `alpha`, `beta`, `production` или ID пользовательского трека | +| `release_status` | `draft`; поддерживаются `draft` и `completed` | +| `validate_only` | `false`; принимает только `true` или `false` | + +`MEGAPROXY_RELEASE_DIR` меняет каталог артефактов по умолчанию. Относительные пути считаются от +корня репозитория. Метаданные, changelog, изображения и скриншоты не загружаются; каталог F-Droid +`fastlane/metadata/android` остаётся отдельным от управления карточкой Play. +Существующий workflow по тегу по-прежнему публикует только в GitHub. CI для PR не должен получать +JSON-ключ Play или вызывать `play_release`. + ## Обновление Fastlane Fastlane следует обновлять явно, после чего проверить и закоммитить оба файла зависимостей: diff --git a/fastlane/Fastfile b/fastlane/Fastfile index ba4ff8b..5133117 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -119,4 +119,54 @@ platform :android do sh(File.join(project_root, "scripts", "build-release-bundle.sh")) UI.success("Release artifacts: dist/release") end + + desc "Upload a signed release AAB and native symbols to Google Play (internal draft by default)" + lane :play_release do |options| + allowed_options = %i[aab symbols json_key track release_status validate_only] + unknown_options = options.keys - allowed_options + UI.user_error!("Unknown play_release options: #{unknown_options.join(', ')}") unless unknown_options.empty? + + track = options.fetch(:track, "internal").to_s + UI.user_error!("track must not be empty") if track.strip.empty? + release_status = options.fetch(:release_status, "draft").to_s + unless %w[draft completed].include?(release_status) + UI.user_error!("release_status must be draft or completed") + end + validate_only = options.fetch(:validate_only, false).to_s + unless %w[true false].include?(validate_only) + UI.user_error!("validate_only must be true or false") + end + + json_key = options[:json_key] || ENV["MEGAPROXY_PLAY_JSON_KEY"] + if json_key.to_s.strip.empty? + UI.user_error!("Set MEGAPROXY_PLAY_JSON_KEY or pass json_key with the service-account JSON file path") + end + release_dir = File.expand_path(ENV.fetch("MEGAPROXY_RELEASE_DIR", "dist/release"), project_root) + files = { + json_key: File.expand_path(json_key, project_root), + aab: File.expand_path(options.fetch(:aab, File.join(release_dir, "mega-proxy.aab")), project_root), + mapping: File.expand_path(options.fetch(:symbols, File.join(release_dir, "mega-proxy-native-debug-symbols.zip")), project_root) + } + files.each do |name, path| + unless File.file?(path) && File.readable?(path) && File.size?(path) + UI.user_error!("#{name} must be a readable, non-empty file: #{path}") + end + end + UI.user_error!("aab must have the .aab extension") unless File.extname(files[:aab]) == ".aab" + UI.user_error!("symbols must have the .zip extension") unless File.extname(files[:mapping]) == ".zip" + + upload_to_play_store( + **files, + package_name: "net.megaproxy487", + track: track, + release_status: release_status, + validate_only: validate_only == "true", + skip_upload_apk: true, + skip_upload_aab: false, + skip_upload_metadata: true, + skip_upload_changelogs: true, + skip_upload_images: true, + skip_upload_screenshots: true + ) + end end diff --git a/fastlane/README.md b/fastlane/README.md index fee6a39..2d674ce 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -14,9 +14,11 @@ Fastlane is the supported entry point for tests and build artifacts. Install Rub | `bundle exec fastlane android test` | Run all native and Android checks | | `bundle exec fastlane android debug_artifact` | Produce `app/build/outputs/apk/debug/app-debug.apk` | | `bundle exec fastlane android release_artifacts` | Produce signed APKs, AAB, native symbols, and checksums in `dist/release` | +| `bundle exec fastlane android play_release` | Upload AAB and native symbols to Google Play (internal draft by default) | The release lane deliberately delegates signing and artifact verification to the repository's existing release scripts. It requires the signing environment documented in the root README. -Publishing to an app store is not performed by any lane. +`play_release` uploads an existing signed AAB and matching native symbols to Google Play. It +defaults to an internal draft and requires `MEGAPROXY_PLAY_JSON_KEY`; see the setup guides below. Full setup and CI scope rules: [English](../docs/en/fastlane.md) / [Русский](../docs/ru/fastlane.md). From bf79af2ae750de2eb9713d3689d9dd8db5435a2f Mon Sep 17 00:00:00 2001 From: Andrey Prokopyuk Date: Sat, 19 Sep 2026 13:00:56 +0300 Subject: [PATCH 2/4] Use standard Fastlane JSON credentials environment variable --- docs/en/fastlane.md | 23 ++++++++++++++++++++--- docs/ru/fastlane.md | 23 ++++++++++++++++++++--- fastlane/Fastfile | 19 ++++++++++++++----- fastlane/README.md | 2 +- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/docs/en/fastlane.md b/docs/en/fastlane.md index bb95636..df66611 100644 --- a/docs/en/fastlane.md +++ b/docs/en/fastlane.md @@ -76,19 +76,37 @@ The AAB must be signed with the upload key registered in Play Console. Before the first API upload, create the app in Play Console, configure Play App Signing and upload an initial build manually. Enable the Google Play Developer API in a Google Cloud project, create a service account and invite its email in Play Console with access to this app and permissions -for the intended test/production tracks. Store its JSON key outside the repository. +for the intended test/production tracks. Keep the JSON key outside the repository and supply its contents through `SUPPLY_JSON_KEY_DATA`. See [Google API setup](https://developers.google.com/android-publisher/getting_started) and [Fastlane supply setup](https://docs.fastlane.tools/actions/upload_to_play_store/#setup). Run from the repository root: ```shell -export MEGAPROXY_PLAY_JSON_KEY="$HOME/.my-tokens/megaproxy-play.json" +export SUPPLY_JSON_KEY_DATA="$(cat "$HOME/.my-tokens/megaproxy-play.json")" bundle exec fastlane android release_artifacts bundle exec fastlane android play_release validate_only:true bundle exec fastlane android play_release ``` +`SUPPLY_JSON_KEY_DATA` is Fastlane's standard environment variable for the complete JSON key, +not a file path or Base64 string. If your local environment already supplies it, omit the `export` +above. The file in that example is only a local storage option; the lane does not read key files. + +In GitHub, create an Actions secret named `SUPPLY_JSON_KEY_DATA` containing the same complete JSON. +Pass it to the upload step in a trusted release workflow: + +```yaml +- name: Upload Google Play draft + env: + SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }} + run: bundle exec fastlane android play_release +``` + +That step requires the AAB and symbols from the same release in `dist/release`. This is a configuration +example; this PR does not add automatic Play uploads to the tag workflow. Do not pass the key as a +lane argument or print it in logs. PR workflows must not receive it. + The default upload creates a **draft on the internal track**. `validate_only:true` uploads to a temporary Google Play edit and asks the API to validate it without committing a release; it needs credentials and network access and is not an offline dry run. Review/complete a draft in Play Console. @@ -107,7 +125,6 @@ this lane uploads a new AAB and does not promote existing releases. | --- | --- | | `aab` | `dist/release/mega-proxy.aab` | | `symbols` | `dist/release/mega-proxy-native-debug-symbols.zip`; required and must match the AAB | -| `json_key` | JSON file path; falls back to `MEGAPROXY_PLAY_JSON_KEY` | | `track` | `internal`; also accepts `alpha`, `beta`, `production` or a custom track ID | | `release_status` | `draft`; supports `draft` or `completed` | | `validate_only` | `false`; accepts only `true` or `false` | diff --git a/docs/ru/fastlane.md b/docs/ru/fastlane.md index c2267b8..25ea0ff 100644 --- a/docs/ru/fastlane.md +++ b/docs/ru/fastlane.md @@ -79,19 +79,37 @@ checkout, не скачивает и не исполняет код или ар Перед первой загрузкой через API создайте приложение в Play Console, настройте Play App Signing и вручную загрузите первоначальную сборку. Включите Google Play Developer API в проекте Google Cloud, создайте сервисный аккаунт и пригласите его email в Play Console с доступом к приложению -и правами для нужных тестовых/production-треков. Храните JSON-ключ вне репозитория. +и правами для нужных тестовых/production-треков. Храните JSON-ключ вне репозитория и передавайте его содержимое через `SUPPLY_JSON_KEY_DATA`. См. [настройку Google API](https://developers.google.com/android-publisher/getting_started) и [настройку Fastlane supply](https://docs.fastlane.tools/actions/upload_to_play_store/#setup). Запускайте из корня репозитория: ```shell -export MEGAPROXY_PLAY_JSON_KEY="$HOME/.my-tokens/megaproxy-play.json" +export SUPPLY_JSON_KEY_DATA="$(cat "$HOME/.my-tokens/megaproxy-play.json")" bundle exec fastlane android release_artifacts bundle exec fastlane android play_release validate_only:true bundle exec fastlane android play_release ``` +`SUPPLY_JSON_KEY_DATA` — штатная переменная окружения Fastlane с полным содержимым JSON-ключа, +а не путём к файлу или строкой Base64. Если локальное окружение уже задаёт её, пропустите `export` +выше. Файл в примере — лишь вариант локального хранения; сам lane файлы ключей не читает. + +В GitHub создайте Actions secret `SUPPLY_JSON_KEY_DATA` с тем же полным JSON. +Передайте его шагу загрузки в доверенном release-workflow: + +```yaml +- name: Upload Google Play draft + env: + SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }} + run: bundle exec fastlane android play_release +``` + +Для шага нужны AAB и symbols одного релиза в `dist/release`. Это пример настройки; +данный PR не добавляет автоматическую загрузку в Play в workflow по тегу. Не передавайте ключ +аргументом lane и не выводите его в логи. Workflow для PR не должны получать этот ключ. + По умолчанию создаётся **черновик в треке internal**. `validate_only:true` загружает файлы во временную транзакцию Google Play и проверяет её через API без сохранения релиза; нужны ключ и сеть, это не локальный dry run. Проверьте и завершите черновик в Play Console. @@ -110,7 +128,6 @@ bundle exec fastlane android play_release track:production release_status:comple | --- | --- | | `aab` | `dist/release/mega-proxy.aab` | | `symbols` | `dist/release/mega-proxy-native-debug-symbols.zip`; обязателен и должен соответствовать AAB | -| `json_key` | Путь к JSON-файлу; при отсутствии используется `MEGAPROXY_PLAY_JSON_KEY` | | `track` | `internal`; также принимает `alpha`, `beta`, `production` или ID пользовательского трека | | `release_status` | `draft`; поддерживаются `draft` и `completed` | | `validate_only` | `false`; принимает только `true` или `false` | diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 5133117..2e484a1 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -122,7 +122,7 @@ platform :android do desc "Upload a signed release AAB and native symbols to Google Play (internal draft by default)" lane :play_release do |options| - allowed_options = %i[aab symbols json_key track release_status validate_only] + allowed_options = %i[aab symbols track release_status validate_only] unknown_options = options.keys - allowed_options UI.user_error!("Unknown play_release options: #{unknown_options.join(', ')}") unless unknown_options.empty? @@ -137,13 +137,21 @@ platform :android do UI.user_error!("validate_only must be true or false") end - json_key = options[:json_key] || ENV["MEGAPROXY_PLAY_JSON_KEY"] - if json_key.to_s.strip.empty? - UI.user_error!("Set MEGAPROXY_PLAY_JSON_KEY or pass json_key with the service-account JSON file path") + json_key_data = ENV["SUPPLY_JSON_KEY_DATA"] + if json_key_data.to_s.strip.empty? + UI.user_error!("Set SUPPLY_JSON_KEY_DATA to the service-account JSON contents") + end + begin + credentials = JSON.parse(json_key_data) + rescue JSON::ParserError + UI.user_error!("SUPPLY_JSON_KEY_DATA must contain valid JSON") + end + unless credentials.is_a?(Hash) && credentials["type"] == "service_account" && + %w[client_email private_key token_uri].all? { |key| credentials[key].is_a?(String) && !credentials[key].strip.empty? } + UI.user_error!("SUPPLY_JSON_KEY_DATA must contain a service-account key with client_email, private_key and token_uri") end release_dir = File.expand_path(ENV.fetch("MEGAPROXY_RELEASE_DIR", "dist/release"), project_root) files = { - json_key: File.expand_path(json_key, project_root), aab: File.expand_path(options.fetch(:aab, File.join(release_dir, "mega-proxy.aab")), project_root), mapping: File.expand_path(options.fetch(:symbols, File.join(release_dir, "mega-proxy-native-debug-symbols.zip")), project_root) } @@ -157,6 +165,7 @@ platform :android do upload_to_play_store( **files, + json_key_data: json_key_data, package_name: "net.megaproxy487", track: track, release_status: release_status, diff --git a/fastlane/README.md b/fastlane/README.md index 2d674ce..5fb7c21 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -19,6 +19,6 @@ Fastlane is the supported entry point for tests and build artifacts. Install Rub The release lane deliberately delegates signing and artifact verification to the repository's existing release scripts. It requires the signing environment documented in the root README. `play_release` uploads an existing signed AAB and matching native symbols to Google Play. It -defaults to an internal draft and requires `MEGAPROXY_PLAY_JSON_KEY`; see the setup guides below. +defaults to an internal draft and requires the JSON key contents in `SUPPLY_JSON_KEY_DATA`; see the setup guides below. Full setup and CI scope rules: [English](../docs/en/fastlane.md) / [Русский](../docs/ru/fastlane.md). From 4ff454a78d0f9b495a755767219e311460db158f Mon Sep 17 00:00:00 2001 From: Andrey Prokopyuk Date: Sat, 19 Sep 2026 13:06:09 +0300 Subject: [PATCH 3/4] Upload Google Play internal drafts from release workflow --- .github/workflows/release.yml | 5 +++++ AGENTS.md | 3 +++ README.md | 4 +++- docs/en/fastlane.md | 25 ++++++++++++++++++------- docs/ru/fastlane.md | 26 +++++++++++++++++++------- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 643fc2a..dfd6a30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -110,3 +110,8 @@ jobs: --generate-notes \ --title "MegaProxy ${GITHUB_REF_NAME}" fi + + - name: Upload Google Play internal draft + env: + SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }} + run: bundle exec fastlane android play_release track:internal release_status:draft diff --git a/AGENTS.md b/AGENTS.md index 9db592c..e2f6012 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,6 +54,9 @@ branch names, credentials, signing material, or other secrets. - Release builds and signing are separate from PR CI. Release artifacts are created only through the dedicated release workflow/Fastlane lane. +- Google Play uploads use `SUPPLY_JSON_KEY_DATA` with the complete service-account JSON in both + local env and GitHub Actions secrets. The tag release workflow uploads an internal draft after + publishing GitHub artifacts; PR workflows must never receive this secret. - After creating and verifying a release, update the corresponding F-Droid submission/build recipe when required. The repository's F-Droid-related files are for reproducible verification, not an excuse to maintain a duplicate unused build path. diff --git a/README.md b/README.md index ea2962f..cfab9a3 100644 --- a/README.md +++ b/README.md @@ -348,7 +348,9 @@ To upload the AAB and native symbols through Fastlane, configure a Play service ([по-русски](docs/ru/fastlane.md#релизы-в-google-play)) for credentials, validation and production uploads. Pushing a version tag runs the same Fastlane release lane in GitHub Actions, builds and verifies -every APK and the App Bundle, and attaches the artifacts to a GitHub Release. The tag must match +every APK and the App Bundle, attaches the artifacts to a GitHub Release, then uploads the AAB +and native symbols as a Google Play internal draft. Configure the repository Actions secret +`SUPPLY_JSON_KEY_DATA` with the complete service-account JSON key for that upload. The tag must match `v` followed by the current `versionName` in `app/build.gradle.kts`. Create that tag with `git tag` and push the specific tag with `git push origin`; do not reuse a historical release tag. diff --git a/docs/en/fastlane.md b/docs/en/fastlane.md index df66611..2062258 100644 --- a/docs/en/fastlane.md +++ b/docs/en/fastlane.md @@ -94,18 +94,29 @@ not a file path or Base64 string. If your local environment already supplies it, above. The file in that example is only a local storage option; the lane does not read key files. In GitHub, create an Actions secret named `SUPPLY_JSON_KEY_DATA` containing the same complete JSON. -Pass it to the upload step in a trusted release workflow: +The existing tag-triggered release workflow passes it only to the upload step: ```yaml - name: Upload Google Play draft env: SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }} - run: bundle exec fastlane android play_release + run: bundle exec fastlane android play_release track:internal release_status:draft ``` -That step requires the AAB and symbols from the same release in `dist/release`. This is a configuration -example; this PR does not add automatic Play uploads to the tag workflow. Do not pass the key as a -lane argument or print it in logs. PR workflows must not receive it. +After building and verifying the artifacts and publishing the GitHub Release, the workflow uploads +the matching AAB and symbols from `dist/release` as an internal draft. A missing secret or failed +Play upload fails the workflow; the already published GitHub Release remains available. Do not +pass the key as a lane argument or print it in logs. PR workflows must not receive it. + +For an existing local shell env file, add `export SUPPLY_JSON_KEY_DATA=...` using a shell-quoted JSON +value and source that file before running Fastlane. For example, with the local release configuration: + +```shell +source "$HOME/.config/megaproxy/release.env" +bundle exec fastlane android play_release +``` + +Keep the env file outside the repository with permissions `0600`. The default upload creates a **draft on the internal track**. `validate_only:true` uploads to a temporary Google Play edit and asks the API to validate it without committing a release; it needs @@ -132,8 +143,8 @@ this lane uploads a new AAB and does not promote existing releases. `MEGAPROXY_RELEASE_DIR` overrides the default artifact directory. Relative file paths are resolved from the repository root. Metadata, changelogs, images and screenshots are not uploaded; the F-Droid listing under `fastlane/metadata/android` is left separate from Play listing management. -The existing tag workflow still publishes only to GitHub. PR CI must not receive the Play JSON key -or invoke `play_release`. +The tag workflow publishes a GitHub Release and a Google Play internal draft. PR CI must not +receive the Play JSON key or invoke `play_release`. ## Updating Fastlane diff --git a/docs/ru/fastlane.md b/docs/ru/fastlane.md index 25ea0ff..4709289 100644 --- a/docs/ru/fastlane.md +++ b/docs/ru/fastlane.md @@ -97,18 +97,30 @@ bundle exec fastlane android play_release выше. Файл в примере — лишь вариант локального хранения; сам lane файлы ключей не читает. В GitHub создайте Actions secret `SUPPLY_JSON_KEY_DATA` с тем же полным JSON. -Передайте его шагу загрузки в доверенном release-workflow: +Существующий release-workflow по тегу передаёт его только шагу загрузки: ```yaml - name: Upload Google Play draft env: SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }} - run: bundle exec fastlane android play_release + run: bundle exec fastlane android play_release track:internal release_status:draft ``` -Для шага нужны AAB и symbols одного релиза в `dist/release`. Это пример настройки; -данный PR не добавляет автоматическую загрузку в Play в workflow по тегу. Не передавайте ключ -аргументом lane и не выводите его в логи. Workflow для PR не должны получать этот ключ. +После сборки и проверки артефактов и публикации GitHub Release workflow загружает соответствующие +AAB и symbols из `dist/release` как internal-черновик. Отсутствие секрета или ошибка загрузки в Play +завершает workflow с ошибкой; уже опубликованный GitHub Release остаётся доступным. Не передавайте +ключ аргументом lane и не выводите его в логи. Workflow для PR не должны получать этот ключ. + +В существующий локальный shell env-файл добавьте `export SUPPLY_JSON_KEY_DATA=...` с JSON в +корректных shell-кавычках и загрузите файл перед запуском Fastlane. Например, для локальной +релизной конфигурации: + +```shell +source "$HOME/.config/megaproxy/release.env" +bundle exec fastlane android play_release +``` + +Храните env-файл вне репозитория с правами `0600`. По умолчанию создаётся **черновик в треке internal**. `validate_only:true` загружает файлы во временную транзакцию Google Play и проверяет её через API без сохранения релиза; нужны ключ @@ -135,8 +147,8 @@ bundle exec fastlane android play_release track:production release_status:comple `MEGAPROXY_RELEASE_DIR` меняет каталог артефактов по умолчанию. Относительные пути считаются от корня репозитория. Метаданные, changelog, изображения и скриншоты не загружаются; каталог F-Droid `fastlane/metadata/android` остаётся отдельным от управления карточкой Play. -Существующий workflow по тегу по-прежнему публикует только в GitHub. CI для PR не должен получать -JSON-ключ Play или вызывать `play_release`. +Workflow по тегу публикует GitHub Release и internal-черновик Google Play. CI для PR не должен +получать JSON-ключ Play или вызывать `play_release`. ## Обновление Fastlane From b8db1d45030e6aeacceb7bf9ad2989f7dea235f4 Mon Sep 17 00:00:00 2001 From: Andrey Prokopyuk Date: Sat, 19 Sep 2026 13:09:41 +0300 Subject: [PATCH 4/4] Document release env as the Google Play credentials source --- docs/en/fastlane.md | 20 ++++++-------------- docs/ru/fastlane.md | 19 +++++-------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/docs/en/fastlane.md b/docs/en/fastlane.md index 2062258..7eda3aa 100644 --- a/docs/en/fastlane.md +++ b/docs/en/fastlane.md @@ -80,18 +80,20 @@ for the intended test/production tracks. Keep the JSON key outside the repositor See [Google API setup](https://developers.google.com/android-publisher/getting_started) and [Fastlane supply setup](https://docs.fastlane.tools/actions/upload_to_play_store/#setup). -Run from the repository root: +Store `export SUPPLY_JSON_KEY_DATA=...` with the complete, shell-quoted JSON in the local +`~/.config/megaproxy/release.env` file. Keep this file outside the repository with permissions +`0600`. Run from the repository root: ```shell -export SUPPLY_JSON_KEY_DATA="$(cat "$HOME/.my-tokens/megaproxy-play.json")" +source "$HOME/.config/megaproxy/release.env" bundle exec fastlane android release_artifacts bundle exec fastlane android play_release validate_only:true bundle exec fastlane android play_release ``` `SUPPLY_JSON_KEY_DATA` is Fastlane's standard environment variable for the complete JSON key, -not a file path or Base64 string. If your local environment already supplies it, omit the `export` -above. The file in that example is only a local storage option; the lane does not read key files. +not a file path or Base64 string. Sourcing `release.env` exports it for Fastlane; if your +environment already supplies it, no additional key setup is needed. In GitHub, create an Actions secret named `SUPPLY_JSON_KEY_DATA` containing the same complete JSON. The existing tag-triggered release workflow passes it only to the upload step: @@ -108,16 +110,6 @@ the matching AAB and symbols from `dist/release` as an internal draft. A missing Play upload fails the workflow; the already published GitHub Release remains available. Do not pass the key as a lane argument or print it in logs. PR workflows must not receive it. -For an existing local shell env file, add `export SUPPLY_JSON_KEY_DATA=...` using a shell-quoted JSON -value and source that file before running Fastlane. For example, with the local release configuration: - -```shell -source "$HOME/.config/megaproxy/release.env" -bundle exec fastlane android play_release -``` - -Keep the env file outside the repository with permissions `0600`. - The default upload creates a **draft on the internal track**. `validate_only:true` uploads to a temporary Google Play edit and asks the API to validate it without committing a release; it needs credentials and network access and is not an offline dry run. Review/complete a draft in Play Console. diff --git a/docs/ru/fastlane.md b/docs/ru/fastlane.md index 4709289..429740a 100644 --- a/docs/ru/fastlane.md +++ b/docs/ru/fastlane.md @@ -83,18 +83,20 @@ Cloud, создайте сервисный аккаунт и пригласит См. [настройку Google API](https://developers.google.com/android-publisher/getting_started) и [настройку Fastlane supply](https://docs.fastlane.tools/actions/upload_to_play_store/#setup). +Сохраните `export SUPPLY_JSON_KEY_DATA=...` с полным JSON в корректных shell-кавычках в локальном +файле `~/.config/megaproxy/release.env`. Храните его вне репозитория с правами `0600`. Запускайте из корня репозитория: ```shell -export SUPPLY_JSON_KEY_DATA="$(cat "$HOME/.my-tokens/megaproxy-play.json")" +source "$HOME/.config/megaproxy/release.env" bundle exec fastlane android release_artifacts bundle exec fastlane android play_release validate_only:true bundle exec fastlane android play_release ``` `SUPPLY_JSON_KEY_DATA` — штатная переменная окружения Fastlane с полным содержимым JSON-ключа, -а не путём к файлу или строкой Base64. Если локальное окружение уже задаёт её, пропустите `export` -выше. Файл в примере — лишь вариант локального хранения; сам lane файлы ключей не читает. +а не путём к файлу или строкой Base64. Загрузка `release.env` экспортирует её для Fastlane; +если окружение уже задаёт переменную, дополнительная настройка ключа не нужна. В GitHub создайте Actions secret `SUPPLY_JSON_KEY_DATA` с тем же полным JSON. Существующий release-workflow по тегу передаёт его только шагу загрузки: @@ -111,17 +113,6 @@ AAB и symbols из `dist/release` как internal-черновик. Отсут завершает workflow с ошибкой; уже опубликованный GitHub Release остаётся доступным. Не передавайте ключ аргументом lane и не выводите его в логи. Workflow для PR не должны получать этот ключ. -В существующий локальный shell env-файл добавьте `export SUPPLY_JSON_KEY_DATA=...` с JSON в -корректных shell-кавычках и загрузите файл перед запуском Fastlane. Например, для локальной -релизной конфигурации: - -```shell -source "$HOME/.config/megaproxy/release.env" -bundle exec fastlane android play_release -``` - -Храните env-файл вне репозитория с правами `0600`. - По умолчанию создаётся **черновик в треке internal**. `validate_only:true` загружает файлы во временную транзакцию Google Play и проверяет её через API без сохранения релиза; нужны ключ и сеть, это не локальный dry run. Проверьте и завершите черновик в Play Console.