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
5 changes: 3 additions & 2 deletions .github/workflows/smoke-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ jobs:
if: ${{ github.event.inputs.record_snapshots != 'true' }}
steps:
- uses: actions/checkout@v4.1.1
with:
fetch-depth: 100
- uses: ./.github/actions/bootstrap
env:
INSTALL_INTERFACE_ANALYZER: true
- run: bundle exec fastlane validate_public_interface
- run: bundle exec fastlane lint_pr
- run: bundle exec fastlane rubocop
- run: bundle exec fastlane run_swift_format strict:true
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ StreamChat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
build/
DerivedData/

# Interface Analyser
stream-module-interface-analyser/
interface-analyser-report.md
public_interface_current.*
public_interface_previous.*

## Various settings
*.pbxuser
!default.pbxuser
Expand Down
1 change: 1 addition & 0 deletions Githubfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export GCLOUD_VERSION='464.0.0'
export MINT_VERSION='0.17.5'
export SONAR_VERSION='6.2.1.4610'
export IPSW_VERSION='3.1.592'
export INTERFACE_ANALYZER_VERSION='1.0.7'
8 changes: 8 additions & 0 deletions Scripts/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,11 @@ if [[ ${INSTALL_IPSW-default} == true ]]; then
chmod +x ipsw
sudo mv ipsw /usr/local/bin/
fi

if [[ ${INSTALL_INTERFACE_ANALYZER-default} == true ]]; then
puts "Install interface-analyser v${INTERFACE_ANALYZER_VERSION}"
FILE="interface-analyser"
wget "https://github.com/GetStream/stream-module-interface-analyser/releases/download/v${INTERFACE_ANALYZER_VERSION}/${FILE}"
chmod +x ${FILE}
sudo mv ${FILE} /usr/local/bin/
fi
40 changes: 40 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ lane :sources_matrix do
ruby: ['fastlane', 'Gemfile', 'Gemfile.lock'],
size: ['Sources', xcode_project],
xcmetrics: ['Sources'],
public_interface: ['Sources'],
swiftformat_include: ['Sources', 'DemoApp', 'Tests', 'Integration'],
swiftformat_exclude: ['**/Generated', 'Sources/StreamChatUI/StreamNuke', 'Sources/StreamChatUI/StreamSwiftyGif', 'Sources/StreamChatUI/StreamDifferenceKit']
}
Expand All @@ -845,6 +846,45 @@ lane :copyright do
)
end

lane :validate_public_interface do
next unless is_check_required(sources: sources_matrix[:public_interface], force_check: @force_check)

# Run the analysis on the current branch
original_branch = current_branch
sh('interface-analyser analysis ../Sources/ public_interface_current.json')

# Checkout the target branch
target_branch = original_branch.include?('release/') ? 'main' : 'develop'
sh("git fetch origin #{target_branch}")
sh("git checkout #{target_branch}")

# Run the analysis on the target branch
sh('interface-analyser analysis ../Sources/ public_interface_previous.json')

# Run diff
report_path = 'interface-analyser-report.md'
sh("interface-analyser diff public_interface_current.json public_interface_previous.json #{report_path}")

# Check if report exists and is non-zero in size
diff =
if File.exist?(report_path) && File.size(report_path) > 0
File.read(report_path).strip
else
'🚀 No changes affecting the public interface.'
end

# Generate markdown table for the PR comment
header = '## Public Interface'
content = "#{header}\n#{diff}"

# Post PR comment if running in CI
pr_comment(text: content, edit_last_comment_with_text: header) if is_ci

# Checkout the original branch
sh("git fetch origin #{original_branch}")
sh("git checkout #{original_branch}")
end
Comment on lines +849 to +886
Copy link

@coderabbitai coderabbitai bot Jul 23, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and tool verification to the interface validation lane.

The lane implementation is well-structured but needs improvements for robustness:

  1. Missing error handling: Git operations can fail if branches don't exist or network issues occur
  2. Tool availability: No verification that interface-analyser is installed
  3. Branch restoration: Should use ensure block to guarantee branch restoration even if errors occur

Consider these improvements:

lane :validate_public_interface do
  next unless is_check_required(sources: sources_matrix[:public_interface], force_check: @force_check)

+  # Verify tool is available
+  begin
+    sh('which interface-analyser')
+  rescue
+    UI.user_error!('interface-analyser tool is not installed. Please run bootstrap with INSTALL_INTERFACE_ANALYZER=true')
+  end

  # Run the analysis on the current branch
  original_branch = current_branch
-  sh('interface-analyser analysis ../Sources/ public_interface_current.json')
+  
+  begin
+    sh('interface-analyser analysis ../Sources/ public_interface_current.json')

    # Checkout the target branch
    target_branch = original_branch.include?('release/') ? 'main' : 'develop'
-    sh("git fetch origin #{target_branch}")
-    sh("git checkout #{target_branch}")
+    sh("git fetch origin #{target_branch}") rescue UI.user_error!("Failed to fetch #{target_branch}")
+    sh("git checkout #{target_branch}") rescue UI.user_error!("Failed to checkout #{target_branch}")

    # Run the analysis on the target branch
    sh('interface-analyser analysis ../Sources/ public_interface_previous.json')

    # Run diff
    report_path = 'interface-analyser-report.md'
    sh("interface-analyser diff public_interface_current.json public_interface_previous.json #{report_path}")

    # Check if report exists and is non-zero in size
    diff =
      if File.exist?(report_path) && File.size(report_path) > 0
        File.read(report_path).strip
      else
        '🚀 No changes affecting the public interface.'
      end

    # Generate markdown table for the PR comment
    header = '## Public Interface'
    content = "#{header}\n#{diff}"

    # Post PR comment if running in CI
    pr_comment(text: content, edit_last_comment_with_text: header) if is_ci

+  ensure
    # Checkout the original branch
-    sh("git fetch origin #{original_branch}")
-    sh("git checkout #{original_branch}")
+    begin
+      sh("git fetch origin #{original_branch}")
+      sh("git checkout #{original_branch}")
+    rescue => e
+      UI.error("Failed to restore original branch #{original_branch}: #{e}")
+    end
+  end
end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
lane :validate_public_interface do
next unless is_check_required(sources: sources_matrix[:public_interface], force_check: @force_check)
# Run the analysis on the current branch
original_branch = current_branch
sh('interface-analyser analysis ../Sources/ public_interface_current.json')
# Checkout the target branch
target_branch = original_branch.include?('release/') ? 'main' : 'develop'
sh("git fetch origin #{target_branch}")
sh("git checkout #{target_branch}")
# Run the analysis on the target branch
sh('interface-analyser analysis ../Sources/ public_interface_previous.json')
# Run diff
report_path = 'interface-analyser-report.md'
sh("interface-analyser diff public_interface_current.json public_interface_previous.json #{report_path}")
# Check if report exists and is non-zero in size
diff =
if File.exist?(report_path) && File.size(report_path) > 0
File.read(report_path).strip
else
'🚀 No changes affecting the public interface.'
end
# Generate markdown table for the PR comment
header = '## Public Interface'
content = "#{header}\n#{diff}"
# Post PR comment if running in CI
pr_comment(text: content, edit_last_comment_with_text: header) if is_ci
# Checkout the original branch
sh("git fetch origin #{original_branch}")
sh("git checkout #{original_branch}")
end
lane :validate_public_interface do
next unless is_check_required(sources: sources_matrix[:public_interface], force_check: @force_check)
# Verify tool is available
begin
sh('which interface-analyser')
rescue
UI.user_error!('interface-analyser tool is not installed. Please run bootstrap with INSTALL_INTERFACE_ANALYZER=true')
end
# Run the analysis on the current branch
original_branch = current_branch
begin
sh('interface-analyser analysis ../Sources/ public_interface_current.json')
# Checkout the target branch
target_branch = original_branch.include?('release/') ? 'main' : 'develop'
sh("git fetch origin #{target_branch}") rescue UI.user_error!("Failed to fetch #{target_branch}")
sh("git checkout #{target_branch}") rescue UI.user_error!("Failed to checkout #{target_branch}")
# Run the analysis on the target branch
sh('interface-analyser analysis ../Sources/ public_interface_previous.json')
# Run diff
report_path = 'interface-analyser-report.md'
sh("interface-analyser diff public_interface_current.json public_interface_previous.json #{report_path}")
# Check if report exists and is non-zero in size
diff =
if File.exist?(report_path) && File.size(report_path) > 0
File.read(report_path).strip
else
'🚀 No changes affecting the public interface.'
end
# Generate markdown table for the PR comment
header = '## Public Interface'
content = "#{header}\n#{diff}"
# Post PR comment if running in CI
pr_comment(text: content, edit_last_comment_with_text: header) if is_ci
ensure
# Checkout the original branch
begin
sh("git fetch origin #{original_branch}")
sh("git checkout #{original_branch}")
rescue => e
UI.error("Failed to restore original branch #{original_branch}: #{e}")
end
end
end
🤖 Prompt for AI Agents
In fastlane/Fastfile lines 849 to 886, add error handling around git commands to
catch failures like missing branches or network issues by wrapping them in
begin-rescue blocks. Before running interface-analyser commands, verify the tool
is installed by checking its availability and aborting with a clear message if
not found. Use an ensure block to guarantee that the original branch is checked
out again even if any errors occur during the lane execution, ensuring branch
restoration happens reliably.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These error handlings are not required because the script will fail anyways on those lines and print an error message.

Copy link

Choose a reason for hiding this comment

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

@testableapple You're absolutely right! Fastlane's default behavior will handle the failures and provide clear error messages when shell commands fail. Keeping the implementation simple and relying on fastlane's built-in error reporting makes sense for your use case. Thanks for the clarification!


✏️ Learnings added
Learnt from: testableapple
PR: GetStream/stream-chat-swift#3740
File: fastlane/Fastfile:849-886
Timestamp: 2025-07-23T16:14:40.239Z
Learning: The team prefers simpler error handling in fastlane scripts and relies on fastlane's default error reporting mechanisms rather than adding explicit begin-rescue blocks around shell commands.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


lane :show_frameworks_sizes do |options|
next unless is_check_required(sources: sources_matrix[:size], force_check: @force_check)

Expand Down
Loading