Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,13 @@ jobs:
--repo "$GITHUB_REPOSITORY" \
--clobber
else
version_code_base="$(sed -nE 's/^val versionCodeBase = ([0-9]+)/\1/p' app/build.gradle.kts)"
code="$((version_code_base * 1000))"
notes="$RUNNER_TEMP/release-notes.md"
en="fastlane/metadata/android/en-US/changelogs/$code.txt"
ru="fastlane/metadata/android/ru-RU/changelogs/$code.txt"
if [[ ! -s "$en" || ! -s "$ru" ]]; then
echo 'Both EN/RU release changelogs are required' >&2
committed_notes="release-notes/${GITHUB_REF_NAME#v}.md"
if [[ ! -s "$committed_notes" ]]; then
echo 'Committed EN/RU release notes are required' >&2
exit 1
fi
{ printf '## English\n\n'; cat "$en"; printf '\n## Русский\n\n'; cat "$ru"; } > "$notes"
cp "$committed_notes" "$notes"
{
printf '\n<!-- megaproxy-virustotal -->\n'
cat dist/release/VIRUSTOTAL.md
Expand Down
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ 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.
- Release notes compare against the last reachable published stable release with all APKs and
checksums; skip failed releases and bare tags. Use the actual Git diff and concise EN/RU bullets
with one sentence per change.
Keep GitHub notes in `release-notes/X.Y.Z.md` separate from F-Droid's 500-character summaries;
preview existing releases through `release_notes_preview` without rewriting published history.
- Automated release PRs use a merge commit preserving the release branch history; verify both
parents and the tested tree before tagging the actual merge commit.
- Tagged releases publish signed APKs and `SHA256SUMS` to GitHub Releases. Google Play integration
Expand Down
1 change: 1 addition & 0 deletions docs/en/fastlane.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,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; excludes Python, Docker integration and emulator tests. |
| `bundle exec fastlane android debug_artifact` | Builds `app/build/outputs/apk/debug/app-debug.apk`. |
| `bundle exec fastlane android release_prepare version:0.1.2` | Generates EN/RU notes, increments the version and creates a release PR (requires API/token setup). |
| `bundle exec fastlane android release_notes_preview version:1.1.3 ref:v1.1.3` | Previews concise EN/RU GitHub and F-Droid notes for an explicit Git range without publishing. |
| `bundle exec fastlane android release_finish version:0.1.2 pr:123 head:FULL_SHA` | Requires full CI, merges the specified PR head with a merge commit and tags the merged commit. |
| `bundle exec fastlane android virus_total` | Scan signed APKs in `dist/release` (or `artifacts:PATH`); requires `VIRUSTOTAL_API_KEY`, blocks on detections/API failures. |
| `bundle exec fastlane android release_artifacts` | Builds and verifies the signed release APKs and `SHA256SUMS` in `dist/release`. |
Expand Down
43 changes: 30 additions & 13 deletions docs/en/release-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ In repository **Settings → Secrets and variables → Actions**, configure:

| Kind | Name | Value |
| --- | --- | --- |
| Secret | `OPENAI_API_KEY` | OpenAI API key, used only for generating the two changelog texts. |
| Secret | `OPENAI_API_KEY` | OpenAI API key, used only for generating EN/RU GitHub and F-Droid notes. |
| Variable / Secret | `OPENAI_RELEASE_MODEL` | A model available to your API project that supports Responses API Structured Outputs, for example `gpt-6.1-sol`. Variables take priority over Secrets if both are set. No implicit model fallback. |
| Secret | `RELEASE_BOT_TOKEN` | Fine-grained PAT limited to this repository: Contents read/write, Pull requests read/write, Actions read. |

Expand Down Expand Up @@ -61,23 +61,28 @@ allows PR CI and the tag-triggered release build to run normally.

1. Check out the selected `main` commit. Fail if `main` has already advanced,
the checkout is dirty, or the version, branch or tag is invalid/existing.
2. Find the highest stable `vX.Y.Z` tag reachable from that commit. Send commit
subjects/bodies and diff statistics since that tag to OpenAI. Code, repository
secrets and signing material are not included. History over 100,000 characters
fails rather than being silently truncated. API calls incur charges on the API
project; no live API call is part of unit tests.
3. Validate the complete structured response: English and Russian text only,
each 1–500 characters. Refusal, incomplete/malformed output or API errors stop
before release files are written. The model only writes text; it does not execute
commands, choose versions, merge or tag. Structured output does not guarantee
factual correctness: notes are visible in the PR and Actions summary.
2. Find the highest stable published `vX.Y.Z` release reachable from that commit,
with all five nonempty uploaded APK assets and `SHA256SUMS`; skip drafts, prereleases,
bare tags and incomplete releases. Send non-merge
commit subjects/bodies and the actual diff to OpenAI, excluding historical changelogs,
generated release notes and lock/sum files. Repository secrets and signing material
are not read. Context over 600,000 characters fails without truncation.
API calls incur charges; unit tests mock the API.
3. Generate equivalent EN/RU bullet lists with one sentence per change: up to 10 bullets
and 3,000 characters per locale for GitHub, plus a separate F-Droid summary of at most
500 characters per locale. Describe concrete behavior, combine related fixes and avoid
vague improvements; maintenance-only releases briefly name the maintenance work and
say app behavior is unchanged. Refusals, invalid output and API errors stop before writes.
The actual returned model, Git range and token usage are logged without credentials.
JSON validation does not establish factual correctness; review the notes in the PR.
4. Create `release/vX.Y.Z`. Set `versionName` and increment `versionCodeBase` by one
in `app/build.gradle.kts`. Keep `base * 1000 + ABI offset` unchanged for F-Droid
and variant-preserving updates. For example base 14 → 15 produces universal
`15000`, arm `15001`, arm64 `15002`, x86 `15003`, x86_64 `15004`.
5. Add `fastlane/metadata/android/{en-US,ru-RU}/changelogs/15000.txt` through `15004.txt`
for that example. Each locale uses the same text for universal and all ABI APKs,
so F-Droid can find the notes by the APK version code.
Commit the separate bilingual GitHub notes in `release-notes/X.Y.Z.md`.
Old changelogs and store descriptions are not rewritten. Open a PR to `main`.
6. Wait up to 60 minutes for **CI / pull_request** for the exact PR and head commit.
Release branches run every suite even on their first CI attempt. All six required
Expand All @@ -92,8 +97,8 @@ allows PR CI and the tag-triggered release build to run normally.
8. Create lightweight tag `vX.Y.Z` on **the actual merged commit**, never on the
release branch head or whatever `main` happens to point to later. The PAT causes
the existing tag build to run. Its new GitHub Release uses the same committed
EN/RU notes. A finalization rerun accepts an existing matching tag and never
moves a conflicting tag.
GitHub notes from `release-notes/X.Y.Z.md`. A finalization rerun accepts an existing
matching tag and never moves a conflicting tag.

The version must exceed both the version in code and the previous stable tag.
Prereleases and automatic version selection are deliberately unsupported. Preparation
Expand Down Expand Up @@ -133,4 +138,16 @@ from a clean current-main checkout, with the same API/token/model configuration.
API format: [OpenAI Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs).
Merge contract: [GitHub merge API](https://docs.github.com/en/rest/pulls/pulls#merge-a-pull-request).


Preview an existing release without writing release files or publishing anything:

```shell
bundle exec fastlane android release_notes_preview version:1.1.3 ref:v1.1.3
```

Set `OPENAI_API_KEY` and `OPENAI_RELEASE_MODEL` in the environment first. The explicit
`ref` keeps later commits out of the preview; both GitHub and F-Droid notes print to stdout.
Automatic baseline selection requires `GITHUB_REPOSITORY=owner/repo` and authenticated `gh`.
Use `previous:v1.1.1` only to override that selection explicitly.

[Русская версия](../ru/release-automation.md)
1 change: 1 addition & 0 deletions docs/ru/fastlane.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ bundle exec fastlane lanes
| `bundle exec fastlane android test` | Выполняет `native_tests` и `android_checks`; основная команда перед коммитом; без Python, Docker-интеграции и тестов на эмуляторах. |
| `bundle exec fastlane android debug_artifact` | Собирает `app/build/outputs/apk/debug/app-debug.apk`. |
| `bundle exec fastlane android release_prepare version:0.1.2` | Генерирует EN/RU changelog, повышает версию и создаёт release PR (нужна настройка API/токенов). |
| `bundle exec fastlane android release_notes_preview version:1.1.3 ref:v1.1.3` | Выводит тезисные EN/RU тексты GitHub и F-Droid для указанного диапазона Git без публикации. |
| `bundle exec fastlane android release_finish version:0.1.2 pr:123 head:FULL_SHA` | Ждёт полного CI, выполняет слияние указанного head PR с отдельным merge-коммитом и тегирует итоговый commit. |
| `bundle exec fastlane android virus_total` | Проверяет подписанные APK в `dist/release` (или `artifacts:PATH`); нужен `VIRUSTOTAL_API_KEY`, обнаружения/ошибки API блокируют публикацию. |
| `bundle exec fastlane android release_artifacts` | Собирает и проверяет подписанные APK и `SHA256SUMS` в `dist/release`. |
Expand Down
41 changes: 29 additions & 12 deletions docs/ru/release-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ workflow нужно явно запустить с новой версией.

| Тип | Имя | Значение |
| --- | --- | --- |
| Secret | `OPENAI_API_KEY` | Ключ OpenAI API, только для генерации двух текстов changelog. |
| Secret | `OPENAI_API_KEY` | Ключ OpenAI API, только для генерации EN/RU текстов GitHub и F-Droid. |
| Variable / Secret | `OPENAI_RELEASE_MODEL` | Доступная вашему API-проекту модель с Responses API Structured Outputs, например `gpt-6.1-sol`. Если заданы оба варианта, Variables имеют приоритет над Secrets. Неявного выбора другой модели нет. |
| Secret | `RELEASE_BOT_TOKEN` | Fine-grained PAT только для этого репозитория: Contents read/write, Pull requests read/write, Actions read. |

Expand Down Expand Up @@ -60,16 +60,20 @@ workflow с прямым merge не поддерживается. Правила

1. Checkout выбранного commit `main`. Остановка, если `main` уже изменился,
checkout грязный, версия некорректна либо ветка/тег уже существуют.
2. Выбор максимального стабильного `vX.Y.Z`, достижимого из этого commit.
В OpenAI передаются заголовки/тела commit и diff statistics после тега.
Код, repository secrets и материалы подписи в запрос не входят. История
длиннее 100 000 символов приводит к остановке, а не молчаливому усечению.
Запросы оплачиваются API-проектом; unit-тесты не вызывают живой API.
3. Проверка полного структурированного ответа: только EN/RU, по 1–500 символов.
Отказ, незавершённый/некорректный ответ и ошибки API останавливают процесс
до записи релизных файлов. Модель пишет только текст: команды, номера версий,
merge и тег обрабатывает обычный код. Формат JSON не гарантирует достоверность;
тексты доступны в PR и Actions summary.
2. Выбор максимального стабильного опубликованного `vX.Y.Z`, достижимого из этого commit,
со всеми пятью загруженными непустыми APK и `SHA256SUMS`; черновики, prerelease,
голые теги и неполные релизы пропускаются.
В OpenAI передаются сообщения коммитов без merge и сам diff, кроме исторических
changelog, сгенерированных release notes и lock/sum-файлов.
Repository secrets и материалы подписи не читаются. Контекст больше 600 000 символов
приводит к остановке без усечения. Запросы платные; unit-тесты подменяют API.
3. Генерация одинаковых по смыслу EN/RU списков: один пункт — одно предложение,
до 10 пунктов и 3000 символов на язык для GitHub и отдельная выжимка до 500 символов
на язык для F-Droid. Текст описывает конкретное поведение, объединяет связанные исправления
и избегает общих обещаний; при изменениях только инфраструктуры кратко называет их
и сообщает, что поведение приложения не изменилось. Отказ, некорректный ответ и ошибки API
останавливают процесс до записи файлов. Фактическая модель, диапазон Git и расход токенов
выводятся без ключей. Проверка JSON не подтверждает достоверность — проверьте текст в PR.
4. Создание `release/vX.Y.Z`, обновление `versionName` и увеличение
`versionCodeBase` на единицу в `app/build.gradle.kts`. Формула
`base * 1000 + ABI offset` сохраняется для F-Droid и обновлений того же варианта.
Expand All @@ -79,6 +83,7 @@ workflow с прямым merge не поддерживается. Правила
`fastlane/metadata/android/{en-US,ru-RU}/changelogs/15000.txt`–`15004.txt`
и PR в `main`. В каждом языке один текст сохраняется для universal и всех ABI APK,
чтобы F-Droid находил его по коду версии APK.
Отдельный двуязычный текст GitHub сохраняется в `release-notes/X.Y.Z.md`.
Исторические changelog и описания карточки не переписываются.
6. Ожидание до 60 минут **CI / pull_request** именно для этого PR и head SHA.
Release-ветки запускают все наборы тестов уже с первой попытки. Все шесть
Expand All @@ -93,7 +98,7 @@ workflow с прямым merge не поддерживается. Правила
совпадения его дерева с проверенным head.
8. Lightweight-тег `vX.Y.Z` ставится **на фактический commit после merge**,
не на head ветки и не на более поздний случайный `main`. PAT запускает обычную
сборку по тегу. Новый GitHub Release использует те же EN/RU тексты из Git.
сборку по тегу. Новый GitHub Release использует EN/RU текст из `release-notes/X.Y.Z.md`.
Повтор finalize принимает уже существующий правильный тег, но никогда
не переставляет тег, указывающий на другой commit.

Expand Down Expand Up @@ -135,4 +140,16 @@ bundle exec fastlane android release_finish version:0.1.2 pr:123 head:FULL_40_CH
Формат API: [OpenAI Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs).
Условия merge: [GitHub merge API](https://docs.github.com/en/rest/pulls/pulls#merge-a-pull-request).


Предпросмотр существующего релиза без записи релизных файлов и публикации:

```shell
bundle exec fastlane android release_notes_preview version:1.1.3 ref:v1.1.3
```

Заранее задайте `OPENAI_API_KEY` и `OPENAI_RELEASE_MODEL` в окружении. Явный `ref`
исключает более поздние коммиты; тексты GitHub и F-Droid выводятся в терминал.
Для автоматического выбора базы нужны `GITHUB_REPOSITORY=owner/repo` и авторизованный `gh`.
Параметр `previous:v1.1.1` позволяет явно переопределить базу.

[English version](../en/release-automation.md)
12 changes: 12 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ platform :android do
end
end

desc "Preview EN/RU changelogs for an explicit Git range without changing release files"
lane :release_notes_preview do |options|
version = options.fetch(:version)
previous = options[:previous]
ref = options[:ref] || "HEAD"
Dir.chdir(project_root) do
args = ["--version", version.to_s, "--ref", ref.to_s]
args += ["--previous", previous.to_s] if previous
sh(ENV.fetch("PYTHON", "python3"), "scripts/release_automation.py", "preview", *args)
end
end

desc "Wait for full release PR CI, create a merge commit, and tag its verified merged commit"
lane :release_finish do |options|
version = options[:version] || ENV.fetch("RELEASE_VERSION")
Expand Down
1 change: 1 addition & 0 deletions fastlane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Fastlane is the supported entry point for tests and build artifacts. Install Rub
| `bundle exec fastlane android test` | Run native unit tests and Android JVM/lint/build checks; excludes Python, Docker integration and device tests |
| `bundle exec fastlane android debug_artifact` | Produce `app/build/outputs/apk/debug/app-debug.apk` |
| `bundle exec fastlane android release_prepare version:0.1.2` | Generate EN/RU changelogs, bump the version and create a release PR |
| `bundle exec fastlane android release_notes_preview version:1.1.3 ref:v1.1.3` | Preview EN/RU GitHub and F-Droid notes without publishing |
| `bundle exec fastlane android release_finish version:0.1.2 pr:123 head:FULL_SHA` | Require full CI, squash merge the specified PR head and tag the merged commit |
| `bundle exec fastlane android virus_total` | Scan signed APKs in `dist/release` (or `artifacts:PATH`); requires `VIRUSTOTAL_API_KEY`, blocks on detections/API failures |
| `bundle exec fastlane android release_artifacts` | Produce signed APKs and checksums in `dist/release` |
Expand Down
Loading
Loading