Skip to content

Automate the App Store submission - #139

Merged
evandhoffman merged 5 commits into
mainfrom
ci/appstore-submit
Oct 12, 2026
Merged

evandhoffman merged 5 commits into
mainfrom
ci/appstore-submit

Conversation

@evandhoffman

@evandhoffman evandhoffman commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR automates the App Store submission. It does items 2 and 3 of #132.

  • release-appstore.yml: dispatch only, on the Linux runner.
    • Inputs: version, build (optional), mode, release_type and replace_whats_new.
    • mode is dry-run (the default, writes nothing), prepare (writes, does not submit) or submit.
    • Every input reaches the shell through env:, and the shell checks it. The API key is deleted even when the job fails.
  • scripts/submit_appstore_release.py: ported from StationCast, with 110 new tests. It uses scripts/asc_api.py, not its own JWT code.
    • It runs every read-only check first, and refuses with the full list of problems before any write. It checks:
      • the build;
      • the version state;
      • the description, keywords and support URL;
      • What's New;
      • the 6.9-inch screenshots;
      • the privacy policy URL;
      • the App Review contact;
      • the open review submissions.
    • What's New: the script keeps the text in App Store Connect. When that text is empty, it uses the version's section of docs/changelog.md.
    • One editable version: App Store Connect allows only one. When a lower version is in Prepare for Submission, the script renames it, so its metadata and screenshots stay.
    • App Review contact: it comes from four new secrets, ASC_REVIEW_CONTACT_*. A set secret wins over the value in App Store Connect. The script never logs a contact value: a test checks every log record, and API errors are redacted.
    • A failed submit run can leave the version in a draft submission ("Ready for Review"). The next run reuses that version and the draft.
  • scripts/changelog.py check now refuses < and >. App Store Connect refused them in What's New today ("must not contain markup language"). One old changelog line is reworded.
  • docs/app-store-release.md: the runbook. It covers the key and the secrets, a public release, external TestFlight, the checks after a submission, a failed run, a rejection and the key rotation.
  • ios-tests.yml treats release-appstore.yml as Linux-only. AGENTS.md is updated.

Verification

  • actionlint: no findings.
  • ruff, mypy --strict and pytest -rs: 319 passed, 0 skipped.
  • scripts/changelog.py check: passes.
  • pre-commit run --all-files: all hooks pass.
  • Not run: the workflow, and any App Store Connect call. After the merge, a dry run against 2.5.5 checks the API shapes. It only reads, and it must refuse, because 2.5.5 is in review.

Before the first prepare or submit run

The owner sets the four ASC_REVIEW_CONTACT_* secrets (see the runbook).

Release

skip-release. CI, tooling and docs only.

evan-agent Bot added 5 commits October 12, 2026 15:04
…rom secrets

A failed submit run can leave the version READY_FOR_REVIEW in a draft submission. The script now reuses that version and the draft, so the next run can finish. The review detail write sends only the contact values from the secrets, so an API error cannot repeat a kept value, and the write is skipped when nothing changes. A rejected submission (UNRESOLVED_ISSUES) now asks for an answer in App Store Connect. The runbook covers both cases.
@evandhoffman evandhoffman added the skip-release Docs, CI or tooling only: the merge cuts no release and no TestFlight upload label Oct 12, 2026
@evandhoffman
evandhoffman merged commit 8a28dfb into main Oct 12, 2026
7 checks passed
@evandhoffman
evandhoffman deleted the ci/appstore-submit branch October 12, 2026 19:19
@evandhoffman evandhoffman mentioned this pull request Oct 12, 2026
2 of 3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-release Docs, CI or tooling only: the merge cuts no release and no TestFlight upload

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant