Files
orca/mobile/fastlane/ios_release_version_test.rb
Neil 3830851a83 fix(mobile): unblock iOS releases and prepare 0.0.36 (#10888)
* fix(mobile): block iOS uploads below the last shipped App Store version

The closed-train guard looked up each candidate version's own App Store
record, but a version only gets one once it is submitted for review.
0.0.34 reached TestFlight and was never submitted, so it had no record,
nothing looked closed, and the patch-bump walk stopped there — while
0.0.35 had already shipped. Apple rejected the upload after a 24-minute
build (90186 closed train, 90062 needs a higher CFBundleShortVersionString).

Fetch the highest closed version once and treat everything at or below it
as closed, comparing semver numerically so 0.0.10 outranks 0.0.9.

Also read appVersionState alongside appStoreState: the latter is
deprecated in App Store Connect API 3.3 and renames the shipped state to
READY_FOR_DISTRIBUTION, so reading only the old field would silently find
zero closed versions once Apple stops populating it.

* chore(mobile): prepare 0.0.36

app.json sat at 0.0.32 while 0.0.35 shipped on the App Store, because
release versions are resolved on the runner and never committed back.
Close the four-version drift so the checked-in version matches reality
and the iOS release no longer depends on the closed-train walk to find
an open version.

Bump Android versionCode 8 -> 9 in the same commit: the version is shared
between platforms, and shipping 0.0.36 with the code that already shipped
for 0.0.32 produces an APK that cannot install over the released build.
2026-07-27 01:53:11 -07:00

96 lines
3.1 KiB
Ruby

require "minitest/autorun"
require_relative "ios_release_version"
class IosReleaseVersionTest < Minitest::Test
def test_exact_version_wins_without_checking_trains
checked_versions = []
version = IosReleaseVersion.resolve(
requested: " 0.0.40 ",
bump_patch: true,
current_version: "0.0.32",
train_closed: ->(candidate) { checked_versions << candidate },
)
assert_equal("0.0.40", version)
assert_empty(checked_versions)
end
def test_uses_current_version_without_a_patch_bump
version = IosReleaseVersion.resolve(
requested: "",
bump_patch: false,
current_version: "0.0.32",
train_closed: ->(_) { flunk("should not check trains") },
)
assert_equal("0.0.32", version)
end
def test_skips_closed_patch_versions_from_a_stale_repo_version
closed_versions = %w[0.0.33 0.0.34]
version = IosReleaseVersion.resolve(
requested: "",
bump_patch: true,
current_version: "0.0.32",
train_closed: ->(candidate) { closed_versions.include?(candidate) },
)
assert_equal("0.0.35", version)
end
def test_rejects_non_semver_versions
error = assert_raises(ArgumentError) { IosReleaseVersion.bump_patch("0.0") }
assert_equal("Cannot bump non-semver mobile version '0.0'", error.message)
end
# The 0.0.34 regression: 0.0.35 shipped, so every version at or below it is
# closed even though 0.0.34 itself never got an App Store record.
def test_versions_at_or_below_the_highest_closed_version_are_closed
assert(IosReleaseVersion.closed_train?("0.0.34", "0.0.35"))
assert(IosReleaseVersion.closed_train?("0.0.35", "0.0.35"))
refute(IosReleaseVersion.closed_train?("0.0.36", "0.0.35"))
end
def test_nothing_is_closed_without_a_known_closed_version
refute(IosReleaseVersion.closed_train?("0.0.1", nil))
refute(IosReleaseVersion.closed_train?("0.0.1", ""))
end
def test_non_semver_candidates_are_treated_as_open
refute(IosReleaseVersion.closed_train?("0.0", "0.0.35"))
end
def test_resolve_skips_past_the_highest_closed_version
version = IosReleaseVersion.resolve(
requested: "",
bump_patch: true,
current_version: "0.0.32",
train_closed: ->(candidate) { IosReleaseVersion.closed_train?(candidate, "0.0.35") },
)
assert_equal("0.0.36", version)
end
def test_max_version_compares_numerically_not_lexically
assert_equal("0.0.10", IosReleaseVersion.max_version(%w[0.0.9 0.0.10 0.0.2]))
assert_equal("0.2.0", IosReleaseVersion.max_version(%w[0.1.99 0.2.0]))
assert_equal("1.0.0", IosReleaseVersion.max_version(%w[0.9.9 1.0.0]))
end
def test_max_version_ignores_non_semver_entries
assert_equal("0.0.35", IosReleaseVersion.max_version(["0.0.35", "1.0", "", nil]))
assert_nil(IosReleaseVersion.max_version([]))
assert_nil(IosReleaseVersion.max_version(nil))
end
# Minor/major releases must close stale patch trains beneath them.
def test_closed_train_compares_across_minor_and_major
assert(IosReleaseVersion.closed_train?("0.0.99", "0.1.0"))
assert(IosReleaseVersion.closed_train?("0.9.9", "1.0.0"))
refute(IosReleaseVersion.closed_train?("1.0.1", "1.0.0"))
end
end