Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,37 @@ upload-metadata:
bundle install
bundle exec fastlane upload_metadata

# ============================================================================
# VERSION MANAGEMENT
# ============================================================================

## Bump the major version number (e.g., 1.1.2 -> 2.0.0)
#
# Increments the major version number and resets minor and patch to 0.
# This should be used for breaking changes or major feature releases.
.PHONY: bump-version-major
bump-version-major:
bundle install
bundle exec fastlane bump_version_major

## Bump the minor version number (e.g., 1.1.2 -> 1.2.0)
#
# Increments the minor version number and resets patch to 0.
# This should be used for new features or significant improvements.
.PHONY: bump-version-minor
bump-version-minor:
bundle install
bundle exec fastlane bump_version_minor

## Bump the patch version number (e.g., 1.1.2 -> 1.1.3)
#
# Increments the patch version number.
# This should be used for bug fixes and minor updates.
.PHONY: bump-version-patch
bump-version-patch:
bundle install
bundle exec fastlane bump_version_patch

# ============================================================================
# HELP & DOCUMENTATION
# ============================================================================
Expand Down
64 changes: 64 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,76 @@ Your feedback helps us improve Flinky for everyone. Thank you!"
UI.success "✅ Code signing synced successfully!"
end

desc "Bump the major version number (e.g., 1.1.2 -> 2.0.0)"
lane :bump_version_major do
_bump_version(bump_type: "major")
end

desc "Bump the minor version number (e.g., 1.1.2 -> 1.2.0)"
lane :bump_version_minor do
_bump_version(bump_type: "minor")
end

desc "Bump the patch version number (e.g., 1.1.2 -> 1.1.3)"
lane :bump_version_patch do
_bump_version(bump_type: "patch")
end

# ============================================================================
# PRIVATE LANES
# ============================================================================
# These lanes are internal helpers and are not exposed in `fastlane lanes`
# ============================================================================

# Private lane: Bump version number in project.pbxproj
private_lane :_bump_version do |options|
bump_type = options[:bump_type] # "major", "minor", or "patch"

# Get current version
old_version = get_version_number(
xcodeproj: "Flinky.xcodeproj",
target: "Flinky"
)

# Parse version into components
version_parts = old_version.split(".").map(&:to_i)
major = version_parts[0] || 0
minor = version_parts[1] || 0
patch = version_parts[2] || 0
Comment on lines +305 to +309
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

The version parsing logic uses || 0 fallback for missing version components, but this could mask issues with malformed version numbers. For example, if the version is "1.2.3.4", the extra ".4" would be silently ignored.

Consider adding validation to ensure the version follows the expected format before parsing:

unless old_version.match?(/^\d+\.\d+\.\d+$/)
  UI.user_error!("Invalid version format: #{old_version}. Expected format: major.minor.patch")
end

Copilot uses AI. Check for mistakes.

# Increment the appropriate part
case bump_type
when "major"
major += 1
minor = 0
patch = 0
when "minor"
minor += 1
patch = 0
when "patch"
patch += 1
else
UI.user_error!("Invalid bump_type: #{bump_type}. Must be 'major', 'minor', or 'patch'")
end

new_version = "#{major}.#{minor}.#{patch}"

# Update all MARKETING_VERSION entries in project.pbxproj
project_file = File.expand_path("../Flinky.xcodeproj/project.pbxproj")
project_content = File.read(project_file)

# Replace all MARKETING_VERSION entries
updated_content = project_content.gsub(
/MARKETING_VERSION = #{Regexp.escape(old_version)};/,
"MARKETING_VERSION = #{new_version};"
)

Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

The implementation doesn't verify whether the regex replacement actually modified any content. If the old_version doesn't match any MARKETING_VERSION entries (e.g., if the version format is different), the function will silently succeed without making any changes.

Add validation to ensure the replacement was successful:

if updated_content == project_content
  UI.user_error!("Failed to update version in project file. No MARKETING_VERSION entries matched '#{old_version}'")
end
Suggested change
# Ensure the replacement was successful
if updated_content == project_content
UI.user_error!("Failed to update version in project file. No MARKETING_VERSION entries matched '#{old_version}'")
end

Copilot uses AI. Check for mistakes.
# Write the updated content back
File.write(project_file, updated_content)

Comment on lines +295 to +340
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

Consider using fastlane's built-in increment_version_number action instead of manually manipulating the project.pbxproj file. The built-in action is more robust, handles edge cases better, and is maintained by the fastlane team.

Example usage:

increment_version_number(
  xcodeproj: "Flinky.xcodeproj",
  bump_type: bump_type  # "major", "minor", or "patch"
)

This approach would:

  • Be more maintainable and less prone to breaking with Xcode updates
  • Handle all build configurations automatically
  • Properly parse and validate version numbers
  • Reduce the risk of file corruption from manual regex replacements
Suggested change
# Private lane: Bump version number in project.pbxproj
private_lane :_bump_version do |options|
bump_type = options[:bump_type] # "major", "minor", or "patch"
# Get current version
old_version = get_version_number(
xcodeproj: "Flinky.xcodeproj",
target: "Flinky"
)
# Parse version into components
version_parts = old_version.split(".").map(&:to_i)
major = version_parts[0] || 0
minor = version_parts[1] || 0
patch = version_parts[2] || 0
# Increment the appropriate part
case bump_type
when "major"
major += 1
minor = 0
patch = 0
when "minor"
minor += 1
patch = 0
when "patch"
patch += 1
else
UI.user_error!("Invalid bump_type: #{bump_type}. Must be 'major', 'minor', or 'patch'")
end
new_version = "#{major}.#{minor}.#{patch}"
# Update all MARKETING_VERSION entries in project.pbxproj
project_file = File.expand_path("../Flinky.xcodeproj/project.pbxproj")
project_content = File.read(project_file)
# Replace all MARKETING_VERSION entries
updated_content = project_content.gsub(
/MARKETING_VERSION = #{Regexp.escape(old_version)};/,
"MARKETING_VERSION = #{new_version};"
)
# Write the updated content back
File.write(project_file, updated_content)
# Private lane: Bump version number using Fastlane's built-in action
private_lane :_bump_version do |options|
bump_type = options[:bump_type] # "major", "minor", or "patch"
# Validate bump_type
unless ["major", "minor", "patch"].include?(bump_type)
UI.user_error!("Invalid bump_type: #{bump_type}. Must be 'major', 'minor', or 'patch'")
end
# Get current version before bump
old_version = get_version_number(
xcodeproj: "Flinky.xcodeproj",
target: "Flinky"
)
# Use Fastlane's built-in increment_version_number to handle the bump
increment_version_number(
xcodeproj: "Flinky.xcodeproj",
bump_type: bump_type
)
# Read the new version after bump
new_version = get_version_number(
xcodeproj: "Flinky.xcodeproj",
target: "Flinky"
)

Copilot uses AI. Check for mistakes.
UI.success "✅ Version bumped from #{old_version} to #{new_version}"
end

# Private lane: Setup code signing for App Store Connect
private_lane :_setup_code_signing do
sync_code_signing(
Expand Down
Loading