cocoapods-bugsnag 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e5d8c650540e96f7ad51cbae072b074762bdfb8d1bb2552dad68763fec1d0e3
4
- data.tar.gz: 4c8c98a9e980e8c1b7fdf86a9119134ea84052ce7375d0ab25c276c32e84734c
3
+ metadata.gz: 9bd7a73528694640aa6a5d4029fcf1cdbef07d71a0da73ab2b859272e491a8ca
4
+ data.tar.gz: 2c00d5eea8c273f5d30b2683cb04fb0bc446f17bdf2b2f6f3e6a0233bda6bb9d
5
5
  SHA512:
6
- metadata.gz: 5ee6032be77a768e5fc2230005a2a84c26fbb26e61d025f805b1491b63dca26a6b47e41bb560e1e0305ae407b6d215043aa7e2af2cd3ddece1cbf63086696270
7
- data.tar.gz: 0040e50681ec86f21aad3fac88bb661701de9696afe426ca491e0807a646bbea306381eadfac377443f7a742145233cbed3dc043e589b31c77062853f7dc710b
6
+ metadata.gz: '042861a83266e07106633d6b236fe5e3ac5271d2bacfd73bf2eb43e50388e81b7e371a7df0ee2bce2a3762f139629ef7a37a2beaa77b8cf73af2120dea75466e'
7
+ data.tar.gz: 9708b8a7b945b3e99c18df3d5768d1369f0353e83d1266fcf92b90dc2626b258140b55c58bde738fb040f1d1f4121d8fbcdbc9b906ca45c97e96d8ad5d4ecf4b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.0 (13 Sept 2022)
4
+
5
+ ### Enhancements
6
+
7
+ * The Xcode build phase is now compatible with Xcode 14's `ENABLE_USER_SCRIPT_SANDBOXING` build setting.
8
+ This requires all dSYM files to be specified in the build phase's "Input Files" list.
9
+ | [#28](https://github.com/bugsnag/cocoapods-bugsnag/pull/28)
10
+
3
11
  ## 2.2.2 (17 May 2022)
4
12
 
5
13
  ### Enhancements
data/README.md CHANGED
@@ -40,9 +40,8 @@ pod install
40
40
  Once added, uploading your dSYM files to Bugsnag will occur automatically.
41
41
 
42
42
  By default, your Bugsnag API key will either be read from the `BUGSNAG_API_KEY`
43
- environment variable or from the `:bugsnag:apiKey` (or `BugsnagAPIKey`) value in your
44
- `Info.plist`. Alternatively edit the script in the new "Upload Bugsnag dSYM" build
45
- phase in Xcode.
43
+ environment variable (add an Xcode build setting with this name to set it) or
44
+ from the `:bugsnag:apiKey` (or `BugsnagAPIKey`) value in your `Info.plist`.
46
45
 
47
46
  Uploading can be disabled by setting `DISABLE_COCOAPODS_BUGSNAG=YES` in Xcode's
48
47
  Build Settings or an `xcconfig` file, or as an argument to `xcodebuild`.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "cocoapods-bugsnag"
3
- spec.version = "2.2.2"
3
+ spec.version = "2.3.0"
4
4
  spec.homepage = "https://bugsnag.com"
5
5
  spec.description = "Configures the dSYM upload phase of your project when integrated with bugsnag."
6
6
  spec.summary = "To get meaningful stacktraces from your crashes, the Bugsnag service needs your dSYM file for your build. This plugin adds an upload phase to your project where needed."
@@ -12,11 +12,13 @@ Gem::Specification.new do |spec|
12
12
  "cocoapods-bugsnag.gemspec"
13
13
  ]
14
14
  spec.extra_rdoc_files = [ "README.md", "CHANGELOG.md" ]
15
- spec.test_files = [ "spec/cocoapods_bugsnag_spec.rb" ]
15
+ spec.test_files = [
16
+ "spec/cocoapods_bugsnag_spec.rb",
17
+ "spec/spec_helper.rb"
18
+ ]
16
19
  spec.require_paths = [ "lib" ]
17
20
  spec.license = "MIT"
18
21
 
19
22
  spec.add_dependency "cocoapods", "~> 1.0"
20
23
  spec.add_development_dependency "rake", ">= 12.3.3"
21
- spec.add_development_dependency "bacon", "~> 1.0"
22
24
  end
@@ -9,41 +9,48 @@ module Pod
9
9
  BUGSNAG_PHASE_SCRIPT = <<'RUBY'
10
10
  # Set DISABLE_COCOAPODS_BUGSNAG=YES via Xcode's Build Settings, xcconfig or xcodebuild to skip upload
11
11
  if ENV['DISABLE_COCOAPODS_BUGSNAG'] == 'YES'
12
- p 'Skipping dSYM upload'
12
+ puts 'Skipping dSYM upload'
13
13
  return
14
14
  end
15
15
 
16
- api_key = nil # Insert your key here to use it directly from this script
16
+ # Attempt to get the API key from an environment variable (or Xcode build setting)
17
+ api_key = ENV["BUGSNAG_API_KEY"]
17
18
 
18
- # Attempt to get the API key from an environment variable
19
+ # If not present, attempt to lookup the value from the Info.plist
19
20
  unless api_key
20
- api_key = ENV["BUGSNAG_API_KEY"]
21
-
22
- # If not present, attempt to lookup the value from the Info.plist
23
- unless api_key
24
- info_plist_path = "#{ENV["BUILT_PRODUCTS_DIR"]}/#{ENV["INFOPLIST_PATH"]}"
25
- plist_buddy_response = `/usr/libexec/PlistBuddy -c "print :bugsnag:apiKey" "#{info_plist_path}"`
26
- plist_buddy_response = `/usr/libexec/PlistBuddy -c "print :BugsnagAPIKey" "#{info_plist_path}"` if !$?.success?
27
- api_key = plist_buddy_response if $?.success?
28
- end
21
+ info_plist_path = "#{ENV["BUILT_PRODUCTS_DIR"]}/#{ENV["INFOPLIST_PATH"]}"
22
+ plist_buddy_response = `/usr/libexec/PlistBuddy -c "print :bugsnag:apiKey" "#{info_plist_path}"`
23
+ plist_buddy_response = `/usr/libexec/PlistBuddy -c "print :BugsnagAPIKey" "#{info_plist_path}"` if !$?.success?
24
+ api_key = plist_buddy_response if $?.success?
29
25
  end
30
26
 
31
- fail("No Bugsnag API key detected - add your key to your Info.plist, BUGSNAG_API_KEY environment variable or this Run Script phase") unless api_key
32
-
33
- fork do
34
- Process.setsid
35
- STDIN.reopen("/dev/null")
36
- STDOUT.reopen("/dev/null", "a")
37
- STDERR.reopen("/dev/null", "a")
27
+ fail("No Bugsnag API key detected - add your key to your Info.plist or BUGSNAG_API_KEY environment variable") unless api_key
38
28
 
39
- require 'shellwords'
40
-
41
- Dir["#{ENV["DWARF_DSYM_FOLDER_PATH"]}/*/Contents/Resources/DWARF/*"].each do |dsym|
42
- curl_command = "curl --http1.1 -F dsym=@#{Shellwords.escape(dsym)} -F projectRoot=#{Shellwords.escape(ENV["PROJECT_DIR"])} "
43
- curl_command += "-F apiKey=#{Shellwords.escape(api_key)} "
44
- curl_command += "https://upload.bugsnag.com/"
45
- system(curl_command)
29
+ if ENV['ENABLE_USER_SCRIPT_SANDBOXING'] == 'YES'
30
+ count = ENV['SCRIPT_INPUT_FILE_COUNT'].to_i
31
+ abort 'error: dSYMs must be specified as build phase "Input Files" because ENABLE_USER_SCRIPT_SANDBOXING is enabled' unless count > 0
32
+ dsyms = []
33
+ for i in 0 .. count - 1
34
+ file = ENV["SCRIPT_INPUT_FILE_#{i}"]
35
+ next if file.end_with? '.plist'
36
+ if File.exist? file
37
+ dsyms.append file
38
+ else
39
+ abort "error: cannot read #{file}" unless ENV['DEBUG_INFORMATION_FORMAT'] != 'dwarf-with-dsym'
40
+ end
46
41
  end
42
+ else
43
+ dsyms = Dir["#{ENV['DWARF_DSYM_FOLDER_PATH']}/*/Contents/Resources/DWARF/*"]
44
+ end
45
+
46
+ dsyms.each do |dsym|
47
+ Process.detach Process.spawn('/usr/bin/curl', '--http1.1',
48
+ '-F', "apiKey=#{api_key}",
49
+ '-F', "dsym=@#{dsym}",
50
+ '-F', "projectRoot=#{ENV['PROJECT_DIR']}",
51
+ 'https://upload.bugsnag.com/',
52
+ %i[err out] => :close
53
+ )
47
54
  end
48
55
  RUBY
49
56
 
@@ -51,44 +58,54 @@ RUBY
51
58
  def integrate!
52
59
  integrate_without_bugsnag!
53
60
  return unless should_add_build_phase?
54
- return if bugsnag_native_targets.empty?
61
+
55
62
  UI.section("Integrating with Bugsnag") do
56
63
  add_bugsnag_upload_script_phase
57
64
  user_project.save
58
65
  end
59
- UI.puts "Added 'Upload Bugsnag dSYM' build phase"
60
66
  end
61
67
 
62
-
63
68
  def add_bugsnag_upload_script_phase
64
- bugsnag_native_targets.each do |native_target|
69
+ native_targets.each do |native_target|
65
70
  phase = native_target.shell_script_build_phases.select do |bp|
66
71
  bp.name == BUGSNAG_PHASE_NAME
67
- end.first || native_target.new_shell_script_build_phase(BUGSNAG_PHASE_NAME)
72
+ end.first || add_shell_script_build_phase(native_target, BUGSNAG_PHASE_NAME)
68
73
 
69
- phase.input_paths = BUGSNAG_PHASE_INPUT_PATHS
74
+ phase.input_paths = dsym_phase_input_paths(phase)
70
75
  phase.shell_path = BUGSNAG_PHASE_SHELL_PATH
71
76
  phase.shell_script = BUGSNAG_PHASE_SCRIPT
72
77
  phase.show_env_vars_in_log = '0'
73
78
  end
74
79
  end
75
80
 
81
+ def add_shell_script_build_phase(native_target, name)
82
+ UI.puts "Adding '#{name}' build phase to '#{native_target.name}'"
83
+ native_target.new_shell_script_build_phase(name)
84
+ end
85
+
86
+ def dsym_phase_input_paths(phase)
87
+ (phase.input_paths + BUGSNAG_PHASE_INPUT_PATHS + target.framework_dsym_paths).uniq
88
+ end
89
+
76
90
  def should_add_build_phase?
77
91
  has_bugsnag_dep = target.target_definition.dependencies.any? do |dep|
78
- dep.name.include?('Bugsnag')
92
+ dep.name.match?(/bugsnag/i)
79
93
  end
80
94
  uses_bugsnag_plugin = target.target_definition.podfile.plugins.key?('cocoapods-bugsnag')
81
95
  return has_bugsnag_dep && uses_bugsnag_plugin
82
96
  end
97
+ end
98
+ end
99
+
100
+ module Pod
101
+ class AggregateTarget
102
+ def framework_dsym_paths
103
+ return [] unless includes_frameworks?
83
104
 
84
- def bugsnag_native_targets
85
- @bugsnag_native_targets ||=(
86
- native_targets.reject do |native_target|
87
- native_target.shell_script_build_phases.any? do |bp|
88
- bp.name == BUGSNAG_PHASE_NAME && bp.input_paths == BUGSNAG_PHASE_INPUT_PATHS && bp.shell_path == BUGSNAG_PHASE_SHELL_PATH && bp.shell_script == BUGSNAG_PHASE_SCRIPT
89
- end
90
- end
91
- )
105
+ framework_paths_by_config['Release'].map do |framework|
106
+ name = File.basename(framework.source_path, '.framework')
107
+ "#{framework.source_path}.dSYM/Contents/Resources/DWARF/#{name}"
108
+ end
92
109
  end
93
110
  end
94
111
  end
@@ -1,3 +1,128 @@
1
- require 'bacon'
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'cocoapods'
4
+ require 'cocoapods_bugsnag'
5
+ require 'tmpdir'
3
6
 
7
+ # rubocop:disable Lint/MissingCopEnableDirective, Metrics/BlockLength
8
+
9
+ RSpec.describe 'cocoapods-bugsnag' do
10
+ context 'with a user project' do
11
+ around(:each) do |t|
12
+ Dir.chdir(Dir.mktmpdir) { t.run }
13
+ end
14
+
15
+ let(:config) { Pod::Config.instance }
16
+
17
+ before do
18
+ user_project = Xcodeproj::Project.new('App.xcodeproj')
19
+ Pod::Generator::AppTargetHelper.add_app_target(user_project, :osx, '10.11')
20
+ user_project.save
21
+
22
+ CLAide::Command::PluginManager.load_plugins('cocoapods')
23
+ end
24
+
25
+ it 'adds a build phase if included in Podfile' do
26
+ File.write 'Podfile', <<~RUBY
27
+ use_frameworks!
28
+ plugin 'cocoapods-bugsnag'
29
+ target 'App' do
30
+ pod 'AFNetworking'
31
+ pod 'Bugsnag'
32
+ end
33
+ RUBY
34
+
35
+ installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
36
+ installer.install!
37
+
38
+ expect(Pod::UI.output).to include "Adding 'Upload Bugsnag dSYM' build phase to 'App'"
39
+
40
+ expect(installer.aggregate_targets.flat_map(&:user_targets)).to all(satisfy do |target|
41
+ upload_phase = target.shell_script_build_phases.find { |bp| bp.name == 'Upload Bugsnag dSYM' }
42
+ expect(upload_phase.shell_path).to eq '/usr/bin/env ruby'
43
+ expect(upload_phase.shell_script).to include 'BUGSNAG_API_KEY'
44
+ expect(upload_phase.shell_script).to include 'SCRIPT_INPUT_FILE_COUNT'
45
+ expect(upload_phase.show_env_vars_in_log).to eq '0'
46
+ expect(upload_phase.input_paths).to eq %w[
47
+ ${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}
48
+ ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
49
+ ${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework.dSYM/Contents/Resources/DWARF/AFNetworking
50
+ ${BUILT_PRODUCTS_DIR}/Bugsnag/Bugsnag.framework.dSYM/Contents/Resources/DWARF/Bugsnag
51
+ ]
52
+ end)
53
+ end
54
+
55
+ it 'does not remove existing input phases' do
56
+ File.write 'Podfile', <<~RUBY
57
+ use_frameworks!
58
+ plugin 'cocoapods-bugsnag'
59
+ target 'App' do
60
+ pod 'AFNetworking'
61
+ pod 'Bugsnag'
62
+ end
63
+ RUBY
64
+
65
+ installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
66
+ installer.install!
67
+
68
+ expect(Pod::UI.output).to include "Adding 'Upload Bugsnag dSYM' build phase to 'App'"
69
+ Pod::UI.output = ''.dup
70
+
71
+ File.write 'Podfile', <<~RUBY
72
+ use_frameworks!
73
+ plugin 'cocoapods-bugsnag'
74
+ target 'App' do
75
+ # AFNetworking now omitted
76
+ pod 'Bugsnag'
77
+ end
78
+ RUBY
79
+
80
+ installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
81
+ installer.install!
82
+
83
+ expect(Pod::UI.output).not_to include "Adding 'Upload Bugsnag dSYM' build phase to 'App'"
84
+
85
+ expect(installer.aggregate_targets.flat_map(&:user_targets)).to all(satisfy do |target|
86
+ upload_phase = target.shell_script_build_phases.find { |bp| bp.name == 'Upload Bugsnag dSYM' }
87
+ expect(upload_phase.input_paths).to include(
88
+ '${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework.dSYM/Contents/Resources/DWARF/AFNetworking'
89
+ )
90
+ end)
91
+ end
92
+
93
+ it 'does nothing if Bugsnag is not a dependency' do
94
+ File.write 'Podfile', <<~RUBY
95
+ plugin 'cocoapods-bugsnag'
96
+ target 'App'
97
+ RUBY
98
+
99
+ installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
100
+ installer.install!
101
+
102
+ expect(Pod::UI.output).not_to include "Adding 'Upload Bugsnag dSYM' build phase to 'App'"
103
+
104
+ expect(installer.aggregate_targets.flat_map(&:user_targets)).to all(satisfy do |target|
105
+ upload_phase = target.shell_script_build_phases.find { |bp| bp.name == 'Upload Bugsnag dSYM' }
106
+ expect(upload_phase).to be_nil
107
+ end)
108
+ end
109
+
110
+ it 'does nothing if not added as a plugin' do
111
+ File.write 'Podfile', <<~RUBY
112
+ target 'App' do
113
+ pod 'Bugsnag'
114
+ end
115
+ RUBY
116
+
117
+ installer = Pod::Installer.new(config.sandbox, config.podfile, config.lockfile)
118
+ installer.install!
119
+
120
+ expect(Pod::UI.output).not_to include "Adding 'Upload Bugsnag dSYM' build phase to 'App'"
121
+
122
+ expect(installer.aggregate_targets.flat_map(&:user_targets)).to all(satisfy do |target|
123
+ upload_phase = target.shell_script_build_phases.find { |bp| bp.name == 'Upload Bugsnag dSYM' }
124
+ expect(upload_phase).to be_nil
125
+ end)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods'
4
+
5
+ module Pod
6
+ # Disable the wrapping so the output is deterministic in the tests.
7
+ #
8
+ UI.disable_wrap = true
9
+
10
+ # Redirects the messages to an internal store.
11
+ #
12
+ module UI
13
+ class << self
14
+ attr_accessor :output, :warnings, :next_input
15
+
16
+ def puts(message = '')
17
+ @output << "#{message}\n"
18
+ end
19
+
20
+ def warn(message = '', _actions = [])
21
+ @warnings << "#{message}\n"
22
+ end
23
+
24
+ def print(message)
25
+ @output << message
26
+ end
27
+
28
+ alias gets next_input
29
+
30
+ def print_warnings; end
31
+ end
32
+ end
33
+ end
34
+
35
+ RSpec.configure do |config|
36
+ config.before(:each) do
37
+ Pod::UI.output = ''.dup
38
+ Pod::UI.warnings = ''.dup
39
+ Pod::UI.next_input = ''.dup
40
+ Pod::Config.instance = nil
41
+ end
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-bugsnag
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delisa Mason
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-17 00:00:00.000000000 Z
11
+ date: 2022-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocoapods
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 12.3.3
41
- - !ruby/object:Gem::Dependency
42
- name: bacon
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.0'
55
41
  description: Configures the dSYM upload phase of your project when integrated with
56
42
  bugsnag.
57
43
  email:
@@ -68,6 +54,7 @@ files:
68
54
  - lib/cocoapods_bugsnag.rb
69
55
  - lib/cocoapods_plugin.rb
70
56
  - spec/cocoapods_bugsnag_spec.rb
57
+ - spec/spec_helper.rb
71
58
  homepage: https://bugsnag.com
72
59
  licenses:
73
60
  - MIT
@@ -95,3 +82,4 @@ summary: To get meaningful stacktraces from your crashes, the Bugsnag service ne
95
82
  where needed.
96
83
  test_files:
97
84
  - spec/cocoapods_bugsnag_spec.rb
85
+ - spec/spec_helper.rb