Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ String _debugSymbolsScript(
require 'xcodeproj'
xcodeFile='${getXcodeProjectPath(platform)}'
runScriptName='$debugSymbolScriptName'
bundleScriptName='$bundleServiceScriptName'
project = Xcodeproj::Project.open(xcodeFile)


Expand All @@ -412,19 +413,78 @@ ${isDevDependency ? 'dart run flutterfire_cli:flutterfire' : 'flutterfire'} uplo

for target in project.targets
if (target.name == '$target')
# Find existing debug symbols phase
phase = target.shell_script_build_phases().find do |item|
if defined? item && item.name
item.name == runScriptName
end
end

# Find bundle-service-file phase to determine insertion position
bundlePhase = target.shell_script_build_phases().find do |item|
if defined? item && item.name
item.name == bundleScriptName
end
end

if phase.nil?
# Create new phase
phase = target.new_shell_script_build_phase(runScriptName)
phase.shell_script = bashScript

# If bundle-service-file exists, ensure debug symbols is placed right after it
if (!bundlePhase.nil?)
# Get all build phases
allPhases = target.build_phases
bundleIndex = allPhases.index(bundlePhase)
currentDebugIndex = allPhases.index(phase)

# If debug symbols is not right after bundle-service-file, reorder
if (currentDebugIndex != bundleIndex + 1)
# Remove from current position
target.build_phases.delete(phase)
# Insert right after bundle-service-file
target.build_phases.insert(bundleIndex + 1, phase)
end
end

project.save()
elsif phase.shell_script != bashScript
# Update existing phase
phase.shell_script = bashScript

# Ensure correct ordering: debug symbols should be right after bundle-service-file
if (!bundlePhase.nil?)
allPhases = target.build_phases
bundleIndex = allPhases.index(bundlePhase)
debugIndex = allPhases.index(phase)

# If debug symbols is not right after bundle-service-file, reorder
if (debugIndex != bundleIndex + 1)
# Remove from current position
target.build_phases.delete(phase)
# Insert right after bundle-service-file
target.build_phases.insert(bundleIndex + 1, phase)
end
end

project.save()
else
# Script exists and content is correct, but check ordering
if (!bundlePhase.nil?)
allPhases = target.build_phases
bundleIndex = allPhases.index(bundlePhase)
debugIndex = allPhases.index(phase)

# If debug symbols is not right after bundle-service-file, reorder
if (debugIndex != bundleIndex + 1)
# Remove from current position
target.build_phases.delete(phase)
# Insert right after bundle-service-file
target.build_phases.insert(bundleIndex + 1, phase)
project.save()
end
end
end
end
end
Expand Down
102 changes: 102 additions & 0 deletions packages/flutterfire_cli/test/configure_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,108 @@ void main() {
),
);

test(
'flutterfire configure: build configuration - verify script ordering after second configure',
() async {
// Add crashlytics dependency so debug symbols script gets added
final addCrashlyticsResult = Process.runSync(
'flutter',
['pub', 'add', 'firebase_crashlytics'],
workingDirectory: projectPath,
);

if (addCrashlyticsResult.exitCode != 0) {
fail(addCrashlyticsResult.stderr as String);
}

// First configure run
final result = Process.runSync(
'flutterfire',
[
'configure',
'--yes',
'--project=$firebaseProjectId',
'--platforms=macos',
'--macos-out=macos/$buildType',
'--macos-build-config=$appleBuildConfiguration',
],
workingDirectory: projectPath,
runInShell: true,
);

if (result.exitCode != 0) {
fail(result.stderr as String);
}

if (Platform.isMacOS) {
// Second configure run - this should trigger reordering if needed
final result2 = Process.runSync(
'flutterfire',
[
'configure',
'--yes',
'--project=$firebaseProjectId',
'--platforms=macos',
'--macos-out=macos/$buildType',
'--macos-build-config=$appleBuildConfiguration',
],
workingDirectory: projectPath,
runInShell: true,
);

if (result2.exitCode != 0) {
fail(result2.stderr as String);
}

// Verify script ordering for iOS
final scriptOrderCheckIos = rubyScriptForCheckingScriptOrdering(
projectPath!,
kIos,
);

final iosOrderResult = Process.runSync(
'ruby',
[
'-e',
scriptOrderCheckIos,
],
runInShell: true,
);

if (iosOrderResult.exitCode != 0) {
fail(iosOrderResult.stderr as String);
}

expect(iosOrderResult.stdout, 'success');

// Verify script ordering for macOS
final scriptOrderCheckMacos = rubyScriptForCheckingScriptOrdering(
projectPath!,
kMacos,
);

final macosOrderResult = Process.runSync(
'ruby',
[
'-e',
scriptOrderCheckMacos,
],
runInShell: true,
);

if (macosOrderResult.exitCode != 0) {
fail(macosOrderResult.stderr as String);
}

expect(macosOrderResult.stdout, 'success');
}
},
skip: !Platform.isMacOS,
timeout: const Timeout(
Duration(minutes: 2),
),
);

test(
'flutterfire configure: android - "default" Apple - "target"',
() async {
Expand Down
59 changes: 59 additions & 0 deletions packages/flutterfire_cli/test/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,65 @@ String rubyScriptForTestingDebugSymbolScriptExists(
''';
}

String rubyScriptForCheckingScriptOrdering(
String projectPath,
String platform, {
String targetName = 'Runner',
String bundleScriptName = 'FlutterFire: "flutterfire bundle-service-file"',
String debugSymbolScriptName =
'FlutterFire: "flutterfire upload-crashlytics-symbols"',
}) {
final xcodeProjectPath = p.join(projectPath, platform, 'Runner.xcodeproj');
return '''
require 'xcodeproj'
xcodeFile='$xcodeProjectPath'
bundleScriptName='$bundleScriptName'
debugSymbolScriptName='$debugSymbolScriptName'
targetName='$targetName'
project = Xcodeproj::Project.open(xcodeFile)

target = project.targets.find { |target| target.name == targetName }

if (target)
# Find both scripts
bundlePhase = target.shell_script_build_phases().find do |item|
if defined? item && item.name
item.name == bundleScriptName
end
end

debugSymbolPhase = target.shell_script_build_phases().find do |item|
if defined? item && item.name
item.name == debugSymbolScriptName
end
end

# Both scripts must exist
if (bundlePhase.nil?)
abort("failed, bundle-service-file script not found")
end

if (debugSymbolPhase.nil?)
abort("failed, upload-crashlytics-symbols script not found")
end

# Get all build phases to check ordering
allPhases = target.build_phases
bundleIndex = allPhases.index(bundlePhase)
debugSymbolIndex = allPhases.index(debugSymbolPhase)

# bundle-service-file must come before upload-crashlytics-symbols
if (bundleIndex >= debugSymbolIndex)
abort("failed, bundle-service-file script (index: #{bundleIndex}) must come before upload-crashlytics-symbols script (index: #{debugSymbolIndex})")
end

\$stdout.write("success")
else
abort("failed, #{targetName} target not found.")
end
''';
}

Future<File> findFileInDirectory(
String directoryPath,
String fileName,
Expand Down
Loading