Skip to content

chore: 0.9.21+52, and stop the iOS embedded bundles shipping a stale version - #165

Merged
abdulsaheel merged 3 commits into
mainfrom
chore/version-0.9.21
Jul 29, 2026
Merged

chore: 0.9.21+52, and stop the iOS embedded bundles shipping a stale version#165
abdulsaheel merged 3 commits into
mainfrom
chore/version-0.9.21

Conversation

@abdulsaheel

@abdulsaheel abdulsaheel commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

User description

Aligns one version across every artefact — Android, the GitHub release, the iOS app, and the part that was actually broken: the iOS widget extension and Watch app.

The bug

The iOS embedded bundles don't follow pubspec. The widget extension and Watch app build their Info.plist from Xcode build settings (GENERATE_INFOPLIST_FILE = YES), so their version comes from MARKETING_VERSION / CURRENT_PROJECT_VERSION in project.pbxproj. Only the Runner target reads $(FLUTTER_BUILD_NAME) — Flutter's Generated.xcconfig is in scope for that target alone.

So bumping pubspec moves the host app and leaves the embedded bundles behind. Built at pubspec 0.9.21+52 with the pbxproj untouched:

main app                         0.9.21 / 52
OpenStrapWidgetExtension.appex   0.9.20 / 51   ← stale
OpenStrapWatch Watch App.app     0.9.20 / 51   ← stale

Apple rejects this. An extension or WatchKit app whose CFBundleShortVersionString differs from its host fails App Store validation, so the upload bounces after the archive. That's why six pbxproj entries were all sitting at exactly 0.9.20/51 — they've been hand-edited every release, and forgetting once costs a failed submission. Since store uploads are manual (no fastlane), nothing was catching it.

What didn't work

Pointing them at $(FLUTTER_BUILD_NAME)/$(FLUTTER_BUILD_NUMBER) — the obvious fix, and already the pattern on three Runner configs. The variables are undefined for those targets and the versions came out empty. Caught by rebuilding and reading the compiled bundles rather than assuming; reverted. Worth recording so nobody re-tries it.

What's here

  • pubspec.yaml 0.9.20+51 → 0.9.21+52
  • Every MARKETING_VERSION0.9.21, every CURRENT_PROJECT_VERSION52. That includes three Runner configs still on a template-default 1.0/1 — inert (the build proves Runner follows pubspec), but making them uniform lets the guard stay dumb and strict rather than special-casing targets.
  • A release guard, beside the existing versionCode one: the tag build now fails if any pbxproj version disagrees with pubspec. Same spirit as the guard that already catches a missing +BUILD suffix — this failure mode is silent and only surfaces at upload time, so CI should own it.

Verification

On compiled bytes, not intent — flutter build ios --debug --no-codesign, then PlistBuddy on each bundle:

main app                         0.9.21 / 52
OpenStrapWidgetExtension.appex   0.9.21 / 52
OpenStrapWatch Watch App.app     0.9.21 / 52

Guard logic dry-run locally against the updated pbxproj: passes. flutter analyze clean. No Dart changed, so kAlgoVersion stays at 50.

Release convention from here

pubspec.yaml is the single source of truth. Bump it, and the tag vX.Y.Z must match its versionName — both already enforced. The new guard extends that to the iOS bundles, so App Store, Play Store and GitHub release all carry the same number by construction.

🤖 Generated with Claude Code


PR Type

Bug fix, Other


Description

  • Bump app version from 0.9.20+51 to 0.9.21+52 across all targets

  • Fix iOS widget extension and Watch app shipping stale version numbers

    • MARKETING_VERSION and CURRENT_PROJECT_VERSION updated for all embedded bundle configs (Debug/Release/Profile)
    • RunnerTests configs also corrected from placeholder 1.0/1 to 0.9.21/52
  • Add CI guard to catch future pubspec/pbxproj version drift before App Store rejection


Diagram Walkthrough

flowchart LR
  pubspec["pubspec.yaml\n0.9.21+52"]
  pbxproj["project.pbxproj\nMARKETING_VERSION=0.9.21\nCURRENT_PROJECT_VERSION=52"]
  ci["build.yml CI guard\nchecks pbxproj vs pubspec"]
  runner["Runner target\n(reads FLUTTER_BUILD_NAME)"]
  widget["OpenStrapWidgetExtension\n(literal version only)"]
  watch["OpenStrapWatch Watch App\n(literal version only)"]
  tests["RunnerTests\n(was 1.0/1, now 0.9.21/52)"]

  pubspec -- "version source" --> runner
  pubspec -- "CI validates match" --> ci
  ci -- "grep MARKETING_VERSION\nCURRENT_PROJECT_VERSION" --> pbxproj
  pbxproj --> widget
  pbxproj --> watch
  pbxproj --> tests
Loading

File Walkthrough

Relevant files
Configuration changes
pubspec.yaml
Bump app version to 0.9.21+52                                                       

pubspec.yaml

  • Version bumped from 0.9.20+51 to 0.9.21+52
  • Comment retained warning that
    MARKETING_VERSION/CURRENT_PROJECT_VERSION in project.pbxproj must be
    manually kept in sync
+1/-1     
project.pbxproj
Align all iOS embedded bundle versions to 0.9.21/52           

ios/Runner.xcodeproj/project.pbxproj

  • MARKETING_VERSION updated to 0.9.21 for widget extension
    (Debug/Release/Profile) and Watch app (Debug/Release/Profile)
  • CURRENT_PROJECT_VERSION updated to 52 for widget extension and Watch
    app configs
  • RunnerTests Debug/Release/Profile configs corrected from stale
    placeholder 1.0/1 to 0.9.21/52
+18/-18 
build.yml
Add CI guard preventing iOS embedded bundle version drift

.github/workflows/build.yml

  • New CI step greps all MARKETING_VERSION and CURRENT_PROJECT_VERSION
    values from project.pbxproj
  • Fails the build with a descriptive error if any value does not match
    the pubspec versionName/versionCode
  • Includes inline comment explaining why embedded bundles cannot use
    $(FLUTTER_BUILD_NAME) and why the guard is necessary
+32/-0   

Summary by CodeRabbit

  • Release
    • Updated the app version to 0.9.21 (build 52).
    • Strengthened release validation with an added preflight step to verify Android/iOS platform version settings match the app’s declared version.
    • Release APK/IPA packaging and attachment are now prevented if version/build-number values are missing or inconsistent, including iOS Info.plist mappings and build configuration settings.

…version

Sets one version across every artefact — Android, the GitHub release, the
iOS app, and (the part that was broken) the iOS widget extension and
Watch app.

THE BUG

The iOS embedded bundles do NOT follow pubspec. The widget extension and
the Watch app build their Info.plist from Xcode build settings
(GENERATE_INFOPLIST_FILE = YES), so their version comes from
MARKETING_VERSION / CURRENT_PROJECT_VERSION in project.pbxproj. Only the
Runner target reads $(FLUTTER_BUILD_NAME), because Flutter's
Generated.xcconfig is in scope for that target alone.

So a pubspec bump moved the host app and left the embedded bundles
behind. Built at pubspec 0.9.21+52 with the pbxproj untouched:

  main app                        0.9.21 / 52
  OpenStrapWidgetExtension.appex  0.9.20 / 51
  OpenStrapWatch Watch App.app    0.9.20 / 51

Apple rejects that. An extension or WatchKit app whose
CFBundleShortVersionString differs from its host fails App Store
validation, so the upload bounces after the archive — which is why six
pbxproj entries were all sitting at exactly 0.9.20/51: someone has been
hand-editing them every release, and forgetting once is a failed
submission.

WHAT DIDN'T WORK

Pointing them at $(FLUTTER_BUILD_NAME)/$(FLUTTER_BUILD_NUMBER) — the
obvious fix, and already the pattern on three Runner configs. The
variables are undefined for those targets, so the versions came out
EMPTY. Caught by rebuilding and reading the compiled bundles rather than
by assuming it worked; reverted.

WHAT'S HERE

- pubspec 0.9.20+51 → 0.9.21+52.
- Every MARKETING_VERSION → 0.9.21 and CURRENT_PROJECT_VERSION → 52,
  including the three Runner configs that were still on a template-default
  1.0/1. Those are inert (the build proves Runner follows pubspec), but
  uniform values let the guard below stay dumb and strict instead of
  special-casing targets.
- A release guard beside the existing versionCode one: the tag build now
  fails if any pbxproj version disagrees with pubspec. Same spirit as the
  guard that already catches a missing +BUILD suffix — the failure mode is
  silent and only shows up at upload time, so CI should catch it.

Verified on compiled bytes, not on intent:

  main app / widget / Watch  →  0.9.21 / 52

Analyze clean.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 02872069-f652-4a0f-b204-3d8e4a9e2a75

📥 Commits

Reviewing files that changed from the base of the PR and between 6534fd0 and d110d9c.

📒 Files selected for processing (1)
  • .github/workflows/build.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build.yml

📝 Walkthrough

Walkthrough

The release version advances to 0.9.21+52. A new preflight job validates Android and iOS version consistency, including embedded-bundle and Info.plist settings, before release packaging jobs run.

Changes

Release version validation

Layer / File(s) Summary
Update release version sources
pubspec.yaml, ios/Runner.xcodeproj/project.pbxproj
The pubspec and iOS target configurations now use marketing version 0.9.21 and build 52.
Gate release jobs with preflight guards
.github/workflows/build.yml
A preflight job validates Android and iOS version settings, rejects missing or unresolved values, checks Info.plist mappings, and gates both release jobs on successful guards.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Preflight
  participant Pubspec as pubspec.yaml
  participant Xcode as project.pbxproj
  participant ReleaseJobs as Android and iOS jobs
  Preflight->>Pubspec: Read versionName and BUILD
  Preflight->>Xcode: Validate iOS version settings and Info.plist mappings
  Xcode-->>Preflight: Return version values
  Preflight->>ReleaseJobs: Permit packaging when guards pass
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the version bump and the iOS stale embedded-bundle fix, which are the main changes in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/version-0.9.21

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit d110d9c)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

RunnerTests guard scope

The CI Python script checks every build configuration that has GENERATE_INFOPLIST_FILE = YES against pubspec's version. The RunnerTests target (configurations Debug/Release/Profile) now also has GENERATE_INFOPLIST_FILE = YES added in this PR, so the guard will verify its MARKETING_VERSION/CURRENT_PROJECT_VERSION too. That is fine for this release, but it means the RunnerTests target — a test host bundle that Apple never validates for version parity — will cause the preflight to fail on any future release if someone forgets to bump it alongside the widget/watch targets. The guard comment says it only applies to embedded bundles that Apple validates, but the regex makes no distinction between those and RunnerTests. This could produce a spurious preflight failure or, conversely, create pressure to keep bumping a bundle that has no store-submission requirement.

for m in re.finditer(r'/\* (\w+) \*/ = \{\s*isa = XCBuildConfiguration;(.*?)\n\t\t\};',
                     open(pbx).read(), re.S):
    cfg, body = m.groups()
    if not re.search(r'\bGENERATE_INFOPLIST_FILE = YES;', body):
        continue          # Runner: versions come from Runner/Info.plist
    checked += 1
    for key, want in (('MARKETING_VERSION', name), ('CURRENT_PROJECT_VERSION', build)):
        found = re.search(r'\b%s = ([^;]+);' % key, body)
        if not found:
            bad.append('%s: %s config has no %s, so its generated Info.plist '
                       'would omit the version. %s' % (pbx, cfg, key, why))
            continue
        val = found.group(1).strip().strip('"')
        if '$(' in val:
            bad.append('%s: %s config has %s = %s -- that build variable is '
                       'undefined for this target and produces an EMPTY version. %s'
                       % (pbx, cfg, key, val, why))
        elif val != want:
            bad.append('%s: %s config has %s = %s but pubspec says %s. %s'
                       % (pbx, cfg, key, val, want, why))

if checked == 0:
    print('::error::%s: found no GENERATE_INFOPLIST_FILE build configurations -- '
          'the iOS version guard is no longer checking anything.' % pbx)
    sys.exit(1)
Error on absent plist key

In the Runner Info.plist check, if the <key>CFBundleShortVersionString</key> or <key>CFBundleVersion</key> entry is absent, got is None and the code calls got.group(1).strip() inside the f-string passed to bad.append, raising AttributeError and crashing the script with a non-zero exit but no ::error:: annotation — the failure message would be a raw Python traceback rather than the intended human-readable CI error. The if not got or ... guard on the condition is correct, but the string formatting on the same line dereferences got unconditionally.

if not got or got.group(1).strip() != var:
    bad.append('ios/Runner/Info.plist: %s is %s, expected %s -- the main app '
               'would stop tracking pubspec and this guard would stop meaning '
               'anything.' % (key, got.group(1).strip() if got else 'absent', var))

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix crash when Info.plist key is absent

When got is None (key absent), got.group(1).strip() in the bad.append format string
raises AttributeError, crashing the script with an unhandled exception rather than
reporting the clean error message. The if not got branch is taken, but the format
string still evaluates got.group(1).strip() unconditionally. Use the
already-computed conditional string instead.

.github/workflows/build.yml [134-141]

 plist = open('ios/Runner/Info.plist').read()
 for key, var in (('CFBundleShortVersionString', '$(FLUTTER_BUILD_NAME)'),
                  ('CFBundleVersion', '$(FLUTTER_BUILD_NUMBER)')):
     got = re.search(r'<key>%s</key>\s*<string>([^<]*)</string>' % key, plist)
-    if not got or got.group(1).strip() != var:
+    got_val = got.group(1).strip() if got else 'absent'
+    if not got or got_val != var:
         bad.append('ios/Runner/Info.plist: %s is %s, expected %s -- the main app '
                    'would stop tracking pubspec and this guard would stop meaning '
-                   'anything.' % (key, got.group(1).strip() if got else 'absent', var))
+                   'anything.' % (key, got_val, var))
Suggestion importance[1-10]: 8

__

Why: When got is None, the bad.append format string still evaluates got.group(1).strip() unconditionally, causing an AttributeError. The fix correctly pre-computes got_val and uses it in both the condition and the format string, preventing the crash.

Medium

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 83-97: Update the validation block using the pbx and bad symbols
to inspect every embedded widget and Watch target/configuration, not just the
unique values returned by grep. Require each embedded configuration to define a
literal numeric MARKETING_VERSION matching name and CURRENT_PROJECT_VERSION
matching build, and set bad=1 for missing, inherited, unresolved, or otherwise
non-numeric settings before exiting.
- Around line 68-99: Move the MARKETING_VERSION/CURRENT_PROJECT_VERSION
validation block into a dedicated preflight job that runs before releases. Add a
needs dependency from both the android and ios jobs to this preflight job,
ensuring either release is blocked when the guard fails while preserving the
existing version checks and error behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b95b76e7-b9ff-485c-8871-3dda465754d9

📥 Commits

Reviewing files that changed from the base of the PR and between d9ddbaa and 7102cdf.

📒 Files selected for processing (3)
  • .github/workflows/build.yml
  • ios/Runner.xcodeproj/project.pbxproj
  • pubspec.yaml

Comment thread .github/workflows/build.yml
Comment thread .github/workflows/build.yml Outdated
…ery config

Two review findings on the guard added in the previous commit, both real.

The guard ran inside the `android` job while `ios` had no `needs:`, so the
check protecting the iOS embedded bundles did not gate the iOS build — a
mismatch would fail Android while iOS carried on and published the IPA.
It now lives in a `preflight` job that both release jobs depend on.

The pbxproj check also matched only values starting with a digit, so
`MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)"` matched nothing and passed —
and that is precisely the configuration proven to build EMPTY versions into
the widget and Watch bundles. Verified against the old check: it reports
clean on that input.

Replaced with a per-build-configuration check. Configurations with
GENERATE_INFOPLIST_FILE=YES generate their Info.plist from these settings and
must carry literal versions matching pubspec; the Runner configurations have
no such flag and correctly use $(FLUTTER_BUILD_*), because Runner's
checked-in Info.plist substitutes them. It also fails when no such
configuration is found, so the guard cannot quietly stop checking anything,
and asserts Runner/Info.plist still tracks pubspec.

Verified by extracting the step from the parsed YAML and running it: passes
on the current tree (9 configurations), and exits 1 for a build variable on
an embedded target, a stale literal, a deleted setting, and a Runner
Info.plist that stops tracking pubspec.
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 6534fd0

@github-actions

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix crash when Info.plist key is absent

When got is None (key absent), got.group(1).strip() in the bad.append format string
raises AttributeError, crashing the script with an unhandled exception rather than
reporting the clean error message. The if not got branch is taken, but the format
string still evaluates got.group(1).strip() unconditionally. Use the
already-computed conditional string instead.

.github/workflows/build.yml [134-141]

 plist = open('ios/Runner/Info.plist').read()
 for key, var in (('CFBundleShortVersionString', '$(FLUTTER_BUILD_NAME)'),
                  ('CFBundleVersion', '$(FLUTTER_BUILD_NUMBER)')):
     got = re.search(r'<key>%s</key>\s*<string>([^<]*)</string>' % key, plist)
-    if not got or got.group(1).strip() != var:
+    got_val = got.group(1).strip() if got else 'absent'
+    if not got or got_val != var:
         bad.append('ios/Runner/Info.plist: %s is %s, expected %s -- the main app '
                    'would stop tracking pubspec and this guard would stop meaning '
-                   'anything.' % (key, got.group(1).strip() if got else 'absent', var))
+                   'anything.' % (key, got_val, var))
Suggestion importance[1-10]: 8

__

Why: When got is None, the bad.append format string still evaluates got.group(1).strip() unconditionally, causing an AttributeError. The fix correctly pre-computes got_val and uses it in both the condition and the format string, preventing the crash.

Medium

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
.github/workflows/build.yml (2)

19-21: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Set persist-credentials: false on this checkout.

This step doesn't push or tag anything — it only reads tags for the versionCode guard — so there's no need to persist the checkout credential on disk.

🔒 Suggested fix
       - uses: actions/checkout@v4
         with:
           fetch-depth: 0   # all tags, so the versionCode guard can read prior releases' pubspec
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 19 - 21, Update the
actions/checkout@v4 step to set persist-credentials to false while retaining
fetch-depth: 0 for reading prior release tags.

Source: Linters/SAST tools


155-158: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Comment and fetch-depth: 0 here are now stale — the guard they refer to lives in preflight.

The versionCode guard that needed full tag history has moved entirely to the new preflight job. Nothing else in android reads git tags, so keeping fetch-depth: 0 here just makes this job's checkout slower/heavier for no benefit, and the comment now misdescribes what happens in this job. Also flagged by static analysis: this checkout doesn't set persist-credentials: false either.

🧹 Suggested fix
       - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0   # need all tags so the versionCode guard can read prior releases' pubspec
+        with:
+          persist-credentials: false

If anything else downstream in this job does rely on tag history, keep fetch-depth: 0 but drop the stale comment and still add persist-credentials: false.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 155 - 158, Update the checkout step
in the android job to remove the stale fetch-depth comment and use a shallow
checkout instead of fetching all history, since tag history is now handled by
preflight. Add persist-credentials: false to the actions/checkout@v4
configuration; retain full history only if another downstream android step
demonstrably requires tags.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/build.yml:
- Around line 19-21: Update the actions/checkout@v4 step to set
persist-credentials to false while retaining fetch-depth: 0 for reading prior
release tags.
- Around line 155-158: Update the checkout step in the android job to remove the
stale fetch-depth comment and use a shallow checkout instead of fetching all
history, since tag history is now handled by preflight. Add persist-credentials:
false to the actions/checkout@v4 configuration; retain full history only if
another downstream android step demonstrably requires tags.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f23d0abd-d2dc-4d78-beb2-b2eb6e58271d

📥 Commits

Reviewing files that changed from the base of the PR and between 7102cdf and 6534fd0.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

… credentials

The `android` checkout still pulled full history with a comment about the
versionCode guard, but that guard moved to `preflight` in the previous commit
and nothing left in the job reads git. `generate_release_notes` builds its
diff on GitHub's side from the tag rather than from local history — the ios
job has always checked out shallow and attaches to the same release without
trouble, which is the evidence that the deep fetch was doing nothing here.
`preflight` keeps `fetch-depth: 0`, since it is the one that walks the tags.

Also sets `persist-credentials: false` on all three checkouts. No step pushes
or otherwise writes to the repo, so leaving the token in `.git/config` only
widens what a compromised build dependency could read — and these jobs run
third-party pub and pod code.
@abdulsaheel

Copy link
Copy Markdown
Collaborator Author

Both latest items looked at — one was right, one I have to push back on.

CodeRabbit, stale fetch-depth: 0 in android — correct, fixed in d110d9c. The guard moved to preflight, and nothing left in the android job reads git. The evidence it was dead weight: the ios job has always checked out shallow and attaches to the same release via softprops/action-gh-release, so generate_release_notes is clearly building its diff on GitHub's side from the tag rather than from local history. preflight keeps fetch-depth: 0 since it is the one that walks the tags. Also took the persist-credentials: false point and applied it to all three checkouts — no step pushes, and these jobs run third-party pub and pod code.

PR Agent, "Fix crash when Info.plist key is absent" (importance 8) — this one is a false positive, and I checked before dismissing it. The claim is that got.group(1).strip() if got else 'absent' "still evaluates got.group(1).strip() unconditionally". It does not: that is a conditional expression, so when got is None Python returns 'absent' and never calls .group().

Verified rather than argued — I deleted the CFBundleShortVersionString key outright so re.search returns None, and ran the guard code extracted from the parsed workflow:

::error::ios/Runner/Info.plist: CFBundleShortVersionString is absent, expected $(FLUTTER_BUILD_NAME) -- the main app would stop tracking pubspec and this guard would stop meaning anything.
exit=1

Clean error, exit 1, no AttributeError. The suggested change is behaviour-preserving, so I have left the code as is.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit d110d9c

@github-actions

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

No code suggestions found for the PR.

@abdulsaheel
abdulsaheel merged commit d9474d8 into main Jul 29, 2026
3 checks passed
@abdulsaheel
abdulsaheel deleted the chore/version-0.9.21 branch July 29, 2026 04:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant