chore(release): add scripted version bump and store builds - #107
Open
i-kumar wants to merge 1 commit into
Open
Conversation
iswheeler
approved these changes
Aug 13, 2026
iswheeler
left a comment
Contributor
There was a problem hiding this comment.
Looks good to me! Thanks for working on this
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cutting a MaizeBus release is currently a manual checklist. This PR replaces it with one command:
./scripts/release.sh patch.Description
Releasing today means hand-editing four files in four different formats (
pubspec.yaml,lib/constants.dart,ios/Runner.xcodeproj/project.pbxproj,android/local.properties) and remembering to point the backend URL back at production. Miss any one of those and nothing complains locally — you find out several minutes later when App Store Connect or Play Console rejects the artifact, or worse, when a build ships pointed at the dev backend.scripts/release.shdoes the version bump, runs pre-flight checks for the mistakes that fail silently, and builds both store artifacts. No app code changes; the script only touches those four files, and only when you run it.Type of Change
feat)fix)Related Issues
None
Changes Made
Two new files. No existing files modified.
scripts/release.shTakes an explicit version (
2.0.4) or a bump keyword (patch/minor/major). Build number defaults to current + 1.Pre-flight checks, chosen because each one catches a failure that is otherwise invisible until upload time:
--allow-dirtyoverrides.android/key.propertiesexistsbuild.gradle.ktssilently falls back to debug signing. The build succeeds and Play Console rejects the bundle minutes later.Info.pliststill uses$(FLUTTER_BUILD_NAME)/$(FLUTTER_BUILD_NUMBER)defaultValue:inconstants.dart, pointing at productionconstants.dartkeeps four commented-out backend URLs next to the live one. If the live one isn't production, the script fixes it. If it can't tell which is live, it refuses rather than guessing.All checks run to completion and report together, so one run tells you everything to fix.
A lower version name warns and prompts instead of hard-failing — re-uploading a build of an already-released version is legitimate. A non-increasing build number is always refused.
Flags:
--dry-run,-y,--build N,--skip-ios,--skip-android,--no-build,--allow-dirty,--allow-debug-signing..claude/commands/release.md— exposes the script as a/releaseslash command, so the process is identical whether run by hand or by Claude.Backend (TypeScript) and Firebase/Shared: no changes.
Note on which version files actually matter.
pubspec.yamlis the only load-bearing one. iOS reads it via the generated xcconfig throughInfo.plist; Android reads it viaupdateLocalProperties(), which rewriteslocal.propertieson every build anyway. Theproject.pbxprojandlocal.propertiesedits are cosmetic — synced only so the Xcode GUI and a bare Gradle invocation don't display a stale version. This is documented at the top of the script so nobody has to re-derive it.Testing Done
Flutter:
All testing was manual, run against scratch copies of the repo. This branch's own version files were never modified.
What was tested and why
The risky half of this script is the file rewriting. It edits YAML, Dart source, an Xcode
pbxproj, and a Java properties file using targeted text substitution rather than a real parser for each format. The failure mode isn't a crash — it's an edit that looks right and produces an artifact that gets rejected at upload, or ships under the wrong version. So every case below diffs the file before and after to confirm the script changed exactly what it meant to and nothing else.project.pbxproj(the riskiest edit) — the same setting names appear in both theRunnerandRunnerTeststargets, so a naive find-replace would clobber the test target. Verified the patcher touches exactly the same 12 lines the Xcode GUI touches, thatRunnerTestskeeps its ownMARKETING_VERSION = 1.0/CURRENT_PROJECT_VERSION = 1, thatplutil -lintstill parses the result, and that two consecutive bumps stay correct.pubspec.yaml,constants.dart,local.properties— exactly one line changed in each, no collateral damage to neighboring keys.//comments correctly skipped. The auto-fix rewrites only the live line and leaves all four commented alternates untouched.2.0,--build 10(non-increasing),--build abc, unknown flag, version passed twice. Each gets a specific error message, not a stack trace or a silent default.n, proceeds with a warning under-y./bin/bash, which is what/usr/bin/env bashresolves to here. Expanding an empty array underset -uerrors on that version, and pre-flight results live in an array, so this was verified rather than assumed.flutteronPATH. Artifact paths were checked againstflutter_toolssource rather than against the stub (the stub's paths were hand-written and would otherwise just confirm themselves):build/ios/ipa/*.ipaandbuild/app/outputs/bundle/release/app-release.aab. This project declares no product flavors, so both hold.Three bugs found and fixed along the way: the production URL's
//terminated perl'ss///early and crashed the backend auto-fix; pre-flight exited on the first failure instead of collecting all of them;--helpprinted the wrong line range.Known gaps before the first real run
flutter build ipaandflutter build appbundleare invoked verbatim, so the untested surface is the wrapper, not the builds.git checkout --.set -eexits with the version already bumped. Retrying needs--allow-dirty --build <same number>so the build number isn't consumed twice.--skip-ios/--skip-androidindividually (only--no-build, which sets both) and the/releasecommand itself are unexercised.Suggest the first real run be the next actual release rather than a synthetic one. Heads up that it will trip the clean-tree check if a version bump is already sitting uncommitted.
Screenshots / Demo (if UI or notification change)
N/A — no UI change.
Checklist
[type](scope): short descriptionmainand is our current working update branchprint()/debugPrint()/console.log()left in production codeandroid/key.propertiesis only checked for existence, never read, written, or logged.