1

I'm writing a post_install script in my Podfile in order to enable gathering of code coverage reports from my framework when I run the unit tests in the example project. Here's what I've got:

post_install do |installer|
  pods_project = installer.pods_project
  shared_data_dir = Xcodeproj::XCScheme.shared_data_dir(pods_project.path)
  scheme_filename = "BonMot.xcscheme"
  scheme = Xcodeproj::XCScheme.new File.join(shared_data_dir, scheme_filename)
  test_action = scheme.test_action
  test_action.code_coverage_enabled = true
  scheme.test_action = test_action
  puts "now scheme is #{scheme}"
  scheme.save!
end

When I print out the scheme, I can confirm that code coverage gathering is enabled, and when I check the modification date of the file, it is updated to the current time, although that is easily explained by the fact that I'm running pod install. The code coverage option is not being written back to the BonMot.xcscheme file. Why not?

Zev Eisenberg
  • 8,080
  • 5
  • 38
  • 82

2 Answers2

3

Looks like post_install is too early to work with schemes. CocoaPods installer calls write_pod_project method right after run_podfile_post_install_hooks during "Generating Pods project" step and there is recreate_user_schemes call inside. So your scheme is rewritten every time during installation process.

I do not like my solution very match but it works for me:

post_install do |installer|

  orig_share_development_pod_schemes = installer.method :share_development_pod_schemes
  installer.define_singleton_method :share_development_pod_schemes do
    orig_share_development_pod_schemes.call

    # do what you want with schemes
  end

end

UPDATE (CocoaPods 1.2.0 and newer)

Since solution is based on implementation details it became broken when CocoaPods 1.2.0 had been released. Keeping the same direction I may suggest new method to redefine:

post_install do |installer|

  orig_write_lockfiles = installer.method :write_lockfiles
  installer.define_singleton_method :write_lockfiles do
    # do what you want with schemes

    orig_write_lockfiles.call
  end

end

UPDATE (CocoaPods 1.10.0 and newer)

Finally, we've got a solution without need to rely on implementation with new post_integrate_hook API:

post_integrate do |installer|
  # do what you want with schemes
end
1

You are using the installer.pods_project which is the Pods.xcodeproj project I believe.

Your BonMot.xcscheme scheme is probably in your app project, not your pods project.

So if that's the case, what your code do is that it probably creates a brand new Pods.xcodeproj/xcshareddata/xcschemes/BonMot.xcscheme file, change its code coverage entry, and save it, instead of changing the existing BonMotApp.xcodeproj/xcshareddata/xcschemes/BonMot.xcscheme scheme.

You might want to puts scheme.path and puts pods_project.path to debug that and be sure you change what you expect.

To reference your app project instead, you might use something like that:

app_project = aggregate_targets.map(&:user_project_path).uniq.first

If you really wanted to modify a scheme included in the Pods project, that scheme is probably not named BonMot which I believe is the name of your App, except if that's the name of a framework brought as a Development Pod in your workspace via CocoaPods.


Full explanation:

That's because even if in practice I've never seen it used anywhere, CocoaPods allow you to integrate pods in multiple user projects at once. Usually you only have one xcodeproj, but you're indeed allowed to specify the xcodeproj directly in your target … do blocks to indicate a specific Xcode project the target belongs to, and thus integrate your pods in targets of different projects.

So this line will ask each Pod's aggregate_target (pod targets that aggregate pods for a specific app target(s)) which user project it belongs to, and then we remove duplicates on that list of user projects. Then as in practice we usually (99.9% of the time) have only one app project, we can get the first and only entry in that list.

AliSoftware
  • 32,623
  • 6
  • 82
  • 77