Skip to content

Latest commit

 

History

History
161 lines (135 loc) · 10.2 KB

release-automation.md

File metadata and controls

161 lines (135 loc) · 10.2 KB

Release automation

Run Actions → Prepare and merge release → Run workflow, select main, and enter an explicit new version such as 0.1.2 (without v). Starting this workflow authorizes creation of a release PR, automatic merge with a merge commit after full CI, and a release tag. The existing Release Android artifacts workflow then builds/signs/publishes APKs. This does not replace the device release review.

The workflow is already present in main. Adding secrets does not create a release; start the workflow explicitly with a new version.

One-time setup

In repository Settings → Secrets and variables → Actions, configure:

Kind Name Value
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.

The tag workflow also requires VIRUSTOTAL_API_KEY. After signing, it submits all five public release APKs to VirusTotal, including the universal APK via the large-file upload endpoint. It waits up to 30 minutes total, spacing API calls at least 16 seconds apart for the public API quota. Missing credentials, API errors, incomplete analyses, or malicious/suspicious engine verdicts block publication; investigate before rerunning. There is no automatic detection override. Zero detections are not a safety guarantee.

VIRUSTOTAL.md and VIRUSTOTAL.json are attached as release assets; hash-addressed links are added to the release notes and Actions summary. Reruns replace only the marked VirusTotal notes block and preserve other release text. Partial completed results remain in an Actions artifact on failure. PR CI does not receive the API key or upload APKs. Only APKs are uploaded, never signing keys, profiles or diagnostic logs. Upload API and size limits, analysis status/verdicts.

Keep the existing Android signing secrets for the tag workflow: ANDROID_SIGNING_KEY_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD. The preparation and PR checks do not receive them.

Enable merge commits. Protect main, require Change scope, Python tests and style, Native Go tests, Android tests and checks, Android emulator API 26 / Device tests, and Android emulator API 35 / Device tests, and disable bypass for the bot. If policy requires human review, approve the generated PR yourself; automation does not approve its own PR or bypass that policy. A denied merge stops finalization; rerun the failed finalization job after approval. Merge queues are not supported by this direct merge workflow. Tag rules must permit the bot to create v* tags.

Use a separate bot account if you want its permissions distinct from your own. This initial implementation uses a PAT; GitHub App token minting/renewal is not implemented. Do not put a short-lived installation token into a persistent secret and assume it will still work later.

The separate token is intentional: GitHub documents that GITHUB_TOKEN-created PR runs require approval and its pushes do not trigger downstream workflows. A PAT allows PR CI and the tag-triggered release build to run normally. GitHub token behaviour.

What happens

  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 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. Up to 600,000 input characters use one request. Larger evidence is partitioned, preferably at file boundaries, into bounded requests for factual summaries; every source character is included. Oversized summaries are reduced in further rounds before generating final notes. Summaries target 20,000 characters; longer nonempty output is preserved. Each reduction round must shrink the context. No model fallback or automatic input truncation is used. Large releases use more API calls; preparation allows 30 minutes. 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, token usage and summary lengths are logged without credentials or generated text, including before output validation failures. JSON validation and intermediate summaries do not establish factual completeness or 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 jobs listed above must finish with success; skipped, neutral, failed and cancelled jobs are insufficient. The recorded comparison base must match the release parent. The PR number is also recorded as a successful CI step because GitHub may remove run-to-PR links after merge; this allows a verified retry of tag creation.
  7. Recheck PR identity and unchanged main, then request a merge commit with the expected head SHA. GitHub protections still apply. Verify that the resulting commit belongs to main, has the verified base and head as its two parents, and has exactly the tested head's tree.
  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 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 and finalization execute trusted workflow source, not code fetched from the release PR. The release commit may change only Gradle's two version fields, the ten changelog files (five APK codes per locale) and release-notes/X.Y.Z.md. Concurrent release preparations are serialized.

Failure and recovery

No retry force-pushes branches, moves tags or rewrites historical notes. A failed check leaves a reviewable PR without a tag. After fixing/re-running its CI, use Re-run failed jobs on the preparation workflow if the PR head and base are unchanged. This reuses preparation outputs without paying for another API response. If the PR was already merged but tag creation failed, the same finalization rerun rechecks CI/tree and creates or verifies the tag without merging again.

If main or the PR head changed, the old finalization cannot approve that new code. Update the branch deliberately so its single release commit is based on current main, rerun full CI, and finalize the explicitly selected new head using a trusted main checkout, authenticated gh, and Fastlane:

export GITHUB_REPOSITORY=andre487/AndroidMegaProxy
bundle exec fastlane android release_finish version:0.1.2 pr:123 head:FULL_40_CHARACTER_SHA

The helper fetches the PR for validation but never checks it out or executes it. This command merges and tags; it is not a dry run. If preparation pushed the branch but PR creation failed, inspect that branch, create its PR manually, then use this same recovery procedure. Starting preparation again never silently adopts or replaces an existing branch. After a tag-build failure, rerun that build instead of moving the tag. Automated external F-Droid submissions are not part of this flow.

Manual preparation uses bundle exec fastlane android release_prepare version:0.1.2 from a clean current-main checkout, with the same API/token/model configuration.

API format: OpenAI Structured Outputs. Merge contract: GitHub merge API.

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

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.

Русская версия