-
-
Notifications
You must be signed in to change notification settings - Fork 0
refactor(fastlane): Modularize Fastfile into separate lane files #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Split the 888-line monolithic Fastfile into a modular structure: - fastlane/Fastfile: Main entry with imports (46 lines) - fastlane/lanes/build.rb: build_ci lane - fastlane/lanes/release.rb: beta, prepare_release, deploy_beta, publish - fastlane/lanes/utilities.rb: generate_*, upload_metadata, setup_code_signing, bump_* - fastlane/lanes/helpers.rb: Private helper lanes - fastlane/lanes/sentry.rb: Sentry integration lanes - fastlane/lanes/version.rb: Version management lanes - fastlane/lanes/git.rb: Git and GitHub lanes - fastlane/actions/enable_pr_auto_merge.rb: Custom action for GitHub auto-merge Additional changes: - Add octokit gem for GitHub API interactions - Rename publish-beta-build.yml to deploy-beta.yml - Add prepare-release.yml workflow for scheduled releases - Implement idempotent deploy_beta lane (skips if build already uploaded) - Query TestFlight for next build number in prepare_release
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Refactors Fastlane configuration by splitting a previously monolithic Fastfile into modular lane files, adds a custom Fastlane action to enable GitHub PR auto-merge, and updates CI workflows to support a prepare-release + deploy-beta flow.
Changes:
- Modularized Fastlane lanes into
fastlane/lanes/*.rband simplifiedfastlane/Fastfileimports - Added
enable_pr_auto_mergecustom action using Octokit + GitHub GraphQL API - Added
prepare-release.ymland updateddeploy-beta.ymlto support release-branch-driven beta deployments
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| fastlane/Fastfile | Replaced monolithic lane definitions with imports for modular lane files. |
| fastlane/lanes/build.rb | Defines build_ci lane for CI archives and optional Sentry upload. |
| fastlane/lanes/release.rb | Adds/defines release lanes: beta, prepare_release, deploy_beta, publish. |
| fastlane/lanes/utilities.rb | Adds utility lanes for icons, screenshots, metadata upload, code signing, and version bump lanes. |
| fastlane/lanes/helpers.rb | Extracts private helper lanes used across build/release workflows. |
| fastlane/lanes/version.rb | Adds private lanes for version/build number coordination with App Store Connect/TestFlight. |
| fastlane/lanes/sentry.rb | Adds private lanes for Sentry release creation/finalization and uploads. |
| fastlane/lanes/git.rb | Adds private lanes for PR creation, tagging, and invoking auto-merge action. |
| fastlane/actions/enable_pr_auto_merge.rb | New custom action to enable PR auto-merge via GraphQL. |
| Gemfile | Adds octokit dependency for GitHub API operations. |
| Gemfile.lock | Locks octokit and its transitive dependencies. |
| .github/workflows/prepare-release.yml | New scheduled/manual workflow to bump version/build and open a release PR. |
| .github/workflows/deploy-beta.yml | Renames/retools workflow to deploy beta on release/** pushes. |
Comments suppressed due to low confidence (1)
.github/workflows/deploy-beta.yml:10
github.job.nameis not a valid GitHub Actions context property; the job id is available asgithub.job. As written, this expression may evaluate unexpectedly (or to an empty string), which can cause unrelated runs to share the same concurrency group. Consider switching to${{ github.job }}(or remove the job component if you intentionally want a workflow-wide lock).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Generate version files | ||
| _make(target: "generate") |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_check_and_bump_version_if_needed already runs _make(target: "generate") when it bumps the version, but prepare_release unconditionally runs _make(target: "generate") again. This makes the workflow do duplicate work and can add time/flakiness. Consider running generate only once (e.g., in prepare_release only when version_check_result[:bumped] is false, or remove the generate step from _check_and_bump_version_if_needed and keep it centralized in prepare_release).
| # Generate version files | |
| _make(target: "generate") | |
| # Generate version files (only if not already generated by _check_and_bump_version_if_needed) | |
| _make(target: "generate") unless version_check_result[:bumped] |
| desc "Generate app icon sizes from source image using fastlane-plugin-appicon" | ||
| desc "Generates all required iOS app icon sizes from Resources/AppIcon.png" | ||
| desc "Strips metadata to ensure git-reproducible output" | ||
| lane :generate_app_icons do |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fastlane only keeps a single desc for a lane (the last desc call before the lane definition). With multiple desc lines here, earlier descriptions will be overwritten and won't show up in fastlane lanes. Consider combining these into one multi-line description (or keep only one desc).
| desc "Prepare release: bump version and create release branch with PR" | ||
| desc "Checks App Store Connect for published version and bumps patch if needed" | ||
| desc "Queries TestFlight for latest build number and sets next build number" | ||
| desc "Used by prepare-release.yml workflow (scheduled/manual trigger)" | ||
| desc "The PR will trigger deploy-beta.yml workflow when the release branch is pushed" |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as elsewhere: multiple desc calls will overwrite each other, so only the last one will be shown for prepare_release. Consider collapsing these into a single multi-line desc (or keeping one).
| desc "Prepare release: bump version and create release branch with PR" | |
| desc "Checks App Store Connect for published version and bumps patch if needed" | |
| desc "Queries TestFlight for latest build number and sets next build number" | |
| desc "Used by prepare-release.yml workflow (scheduled/manual trigger)" | |
| desc "The PR will trigger deploy-beta.yml workflow when the release branch is pushed" | |
| desc <<~DESC | |
| Prepare release: bump version and create release branch with PR | |
| Checks App Store Connect for published version and bumps patch if needed | |
| Queries TestFlight for latest build number and sets next build number | |
| Used by prepare-release.yml workflow (scheduled/manual trigger) | |
| The PR will trigger deploy-beta.yml workflow when the release branch is pushed | |
| DESC |
| # Enable auto-merge using GraphQL mutation | ||
| mutation = <<~GRAPHQL | ||
| mutation { | ||
| enablePullRequestAutoMerge(input: { | ||
| pullRequestId: "#{node_id}" | ||
| mergeMethod: #{merge_method} | ||
| }) { |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge_method is interpolated directly into the GraphQL mutation. Since GraphQL expects an enum here, any unexpected value will cause the mutation to fail, and (because this is raw string interpolation) it also leaves room for query injection if the value ever becomes user-controlled. Consider validating/normalizing merge_method against an allowlist (MERGE/SQUASH/REBASE) and substituting the sanitized value into the query.
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job.name}} |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
github.job.name is not a valid GitHub Actions context property; the job id is available as github.job. As written, this expression may evaluate unexpectedly (or to an empty string), which can cause unrelated runs to share the same concurrency group. Consider switching to ${{ github.job }} (or remove the job component if you intentionally want a workflow-wide lock).
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job.name}} | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.job }} |
| # Check if this build is already uploaded to TestFlight | ||
| if _build_already_uploaded?(version: version_number, build: build_number) | ||
| UI.success "✅ Build #{version_number} (#{build_number}) already exists on TestFlight" | ||
| UI.success "Skipping upload - previous run succeeded. Nothing to do." | ||
| next | ||
| end |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deploy_beta treats “build exists on TestFlight” as equivalent to “previous run succeeded” and exits early. If a previous run uploaded the build but failed afterward (e.g., during _finalize_sentry_release or any post-upload step you may add later), re-running will skip all remaining steps and never retry them. To make the lane truly safe to re-run after partial failures, consider skipping only the upload_to_testflight step when the build exists, while still running (or re-running) the other side-effect steps that should be idempotent (e.g., Sentry finalize).
| # Compare versions semantically | ||
| if _version_already_published?(current_version, published_version) | ||
| UI.important "Version #{current_version} is already published. Bumping patch version..." | ||
| _bump_version(bump_type: "patch") | ||
| _make(target: "generate") | ||
|
|
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version check only bumps when current_version is exactly equal to the published version. If the local current_version is lower than the published App Store version (e.g., local 1.2.0, published 1.3.0), _version_already_published? returns false and this lane will keep the lower version, which will later fail App Store/TestFlight upload. Consider changing the logic to bump when current_version <= published_version (or compute next_version as published_version + patch) using a proper semantic version compare (e.g., Gem::Version).
Summary
enable_pr_auto_mergeaction for GitHub auto-merge via GraphQL APIdeploy_betalane that skips upload if build already exists on TestFlightChanges
New Structure
Workflow Changes
publish-beta-build.yml→deploy-beta.ymlprepare-release.ymlworkflow for scheduled/manual releasesprepare_releasequeries TestFlight for next build number upfrontdeploy_betachecks if build exists before uploading (idempotent, safe to re-run)Dependencies
octokitgem for GitHub API interactionsTest Plan
bundle exec fastlane lanesshows all 12 public lanesbundle exec fastlane action enable_pr_auto_mergeshows custom action docs