fastlane 2.179.0 → 2.180.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +84 -84
  3. data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +1 -1
  4. data/fastlane/lib/fastlane/actions/jira.rb +61 -14
  5. data/fastlane/lib/fastlane/actions/notarize.rb +98 -51
  6. data/fastlane/lib/fastlane/actions/sourcedocs.rb +164 -0
  7. data/fastlane/lib/fastlane/setup/setup.rb +23 -10
  8. data/fastlane/lib/fastlane/swift_runner_upgrader.rb +2 -0
  9. data/fastlane/lib/fastlane/version.rb +1 -1
  10. data/fastlane/swift/Deliverfile.swift +1 -1
  11. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  12. data/fastlane/swift/Fastlane.swift +87 -21
  13. data/fastlane/swift/Gymfile.swift +1 -1
  14. data/fastlane/swift/GymfileProtocol.swift +1 -1
  15. data/fastlane/swift/LaneFileProtocol.swift +9 -3
  16. data/fastlane/swift/Matchfile.swift +1 -1
  17. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  18. data/fastlane/swift/Precheckfile.swift +1 -1
  19. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  20. data/fastlane/swift/RubyCommand.swift +1 -1
  21. data/fastlane/swift/Scanfile.swift +1 -1
  22. data/fastlane/swift/ScanfileProtocol.swift +5 -1
  23. data/fastlane/swift/Screengrabfile.swift +1 -1
  24. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  25. data/fastlane/swift/Snapshotfile.swift +1 -1
  26. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  27. data/fastlane/swift/SocketClient.swift +2 -1
  28. data/fastlane/swift/SocketResponse.swift +4 -2
  29. data/fastlane/swift/formatting/Brewfile.lock.json +3 -3
  30. data/fastlane_core/lib/fastlane_core/queue_worker.rb +2 -2
  31. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +12 -1
  32. data/match/lib/match/change_password.rb +1 -1
  33. data/scan/lib/scan/options.rb +10 -5
  34. data/scan/lib/scan/runner.rb +52 -1
  35. data/scan/lib/scan/test_command_generator.rb +8 -8
  36. data/snapshot/lib/assets/SnapshotHelper.swift +1 -1
  37. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +1 -1
  38. data/spaceship/lib/spaceship/connect_api/token.rb +7 -1
  39. metadata +18 -18
  40. data/gym/lib/gym/.runner.rb.swp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37bd22615ab9e8e6eaa0861b231896cfa234eb207772352f26d727f7735c34c5
4
- data.tar.gz: bc34b9e91a9b80abc345780db060f494a9012c15df9292336ff428234228aad7
3
+ metadata.gz: d47a944d1f222d53ea13b59b215a89b39bf0e2498f366860a4e5bbbfe73055ac
4
+ data.tar.gz: 0de45e4351069b144d5d98b74238db10e93b1d6d36c05d7346f7117f2e68f0e7
5
5
  SHA512:
6
- metadata.gz: 5dfdc64c102b6ae9d723ba7bc9cdbcf1bcb517c620475c8bf1f3eded3d1ccfc47705b85eea80f6112e946b339344550b51a4f3ed1d6c571e1974625931c53336
7
- data.tar.gz: d53a201dcc0da9a8f4eb0fb88b629be149ea3cebde1225c59072a236d9e6ec705b69aeccf4bd3d0c55abc5b457e1557ab7169779b20d8bbf86299cb7605d0abb
6
+ metadata.gz: f70ad0a907abfe6f29d9db3f6c8b7a2d62c154e5706421cbbe9b0f2c478c447046cb2f84e2dcd78f38d7a7cc31f2be4fcc89ab3d8096ed40f3b8cb02863cd351
7
+ data.tar.gz: a9ecd2ddac8fe476e6278187599302ce830c8cd61afa8c5e45b054693696fb6ecf0b0b953f5499e7ead0accb3d49d8cba5c3d6b43468aa109c62034ae98457fa
data/README.md CHANGED
@@ -35,11 +35,23 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
35
35
  <!-- This table is regenerated and resorted on each release -->
36
36
  <table id='team'>
37
37
  <tr>
38
- <td id='joshua-liebowitz'>
39
- <a href='https://github.com/taquitos'>
40
- <img src='https://github.com/taquitos.png?size=140'>
38
+ <td id='jimmy-dee'>
39
+ <a href='https://github.com/jdee'>
40
+ <img src='https://github.com/jdee.png?size=140'>
41
41
  </a>
42
- <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
42
+ <h4 align='center'>Jimmy Dee</h4>
43
+ </td>
44
+ <td id='danielle-tomlinson'>
45
+ <a href='https://github.com/endocrimes'>
46
+ <img src='https://github.com/endocrimes.png?size=140'>
47
+ </a>
48
+ <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
49
+ </td>
50
+ <td id='andrew-mcburney'>
51
+ <a href='https://github.com/armcburney'>
52
+ <img src='https://github.com/armcburney.png?size=140'>
53
+ </a>
54
+ <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
43
55
  </td>
44
56
  <td id='manu-wallner'>
45
57
  <a href='https://github.com/milch'>
@@ -47,69 +59,83 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
47
59
  </a>
48
60
  <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
49
61
  </td>
50
- <td id='josh-holtz'>
51
- <a href='https://github.com/joshdholtz'>
52
- <img src='https://github.com/joshdholtz.png?size=140'>
62
+ <td id='roger-oba'>
63
+ <a href='https://github.com/rogerluan'>
64
+ <img src='https://github.com/rogerluan.png?size=140'>
53
65
  </a>
54
- <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
66
+ <h4 align='center'><a href='https://twitter.com/rogerluan_'>Roger Oba</a></h4>
55
67
  </td>
56
- <td id='stefan-natchev'>
57
- <a href='https://github.com/snatchev'>
58
- <img src='https://github.com/snatchev.png?size=140'>
68
+ </tr>
69
+ <tr>
70
+ <td id='iulian-onofrei'>
71
+ <a href='https://github.com/revolter'>
72
+ <img src='https://github.com/revolter.png?size=140'>
59
73
  </a>
60
- <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
74
+ <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
61
75
  </td>
62
- <td id='satoshi-namai'>
63
- <a href='https://github.com/ainame'>
64
- <img src='https://github.com/ainame.png?size=140'>
76
+ <td id='luka-mirosevic'>
77
+ <a href='https://github.com/lmirosevic'>
78
+ <img src='https://github.com/lmirosevic.png?size=140'>
65
79
  </a>
66
- <h4 align='center'><a href='https://twitter.com/ainame'>Satoshi Namai</a></h4>
80
+ <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
81
+ </td>
82
+ <td id='aaron-brager'>
83
+ <a href='https://github.com/getaaron'>
84
+ <img src='https://github.com/getaaron.png?size=140'>
85
+ </a>
86
+ <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
87
+ </td>
88
+ <td id='jorge-revuelta-h'>
89
+ <a href='https://github.com/minuscorp'>
90
+ <img src='https://github.com/minuscorp.png?size=140'>
91
+ </a>
92
+ <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
67
93
  </td>
68
- </tr>
69
- <tr>
70
94
  <td id='jérôme-lacoste'>
71
95
  <a href='https://github.com/lacostej'>
72
96
  <img src='https://github.com/lacostej.png?size=140'>
73
97
  </a>
74
98
  <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
75
99
  </td>
100
+ </tr>
101
+ <tr>
76
102
  <td id='matthew-ellis'>
77
103
  <a href='https://github.com/matthewellis'>
78
104
  <img src='https://github.com/matthewellis.png?size=140'>
79
105
  </a>
80
106
  <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
81
107
  </td>
82
- <td id='aaron-brager'>
83
- <a href='https://github.com/getaaron'>
84
- <img src='https://github.com/getaaron.png?size=140'>
85
- </a>
86
- <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
87
- </td>
88
- <td id='iulian-onofrei'>
89
- <a href='https://github.com/revolter'>
90
- <img src='https://github.com/revolter.png?size=140'>
108
+ <td id='joshua-liebowitz'>
109
+ <a href='https://github.com/taquitos'>
110
+ <img src='https://github.com/taquitos.png?size=140'>
91
111
  </a>
92
- <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
112
+ <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
93
113
  </td>
94
- <td id='jimmy-dee'>
95
- <a href='https://github.com/jdee'>
96
- <img src='https://github.com/jdee.png?size=140'>
114
+ <td id='daniel-jankowski'>
115
+ <a href='https://github.com/mollyIV'>
116
+ <img src='https://github.com/mollyIV.png?size=140'>
97
117
  </a>
98
- <h4 align='center'>Jimmy Dee</h4>
118
+ <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
99
119
  </td>
100
- </tr>
101
- <tr>
102
120
  <td id='jan-piotrowski'>
103
121
  <a href='https://github.com/janpio'>
104
122
  <img src='https://github.com/janpio.png?size=140'>
105
123
  </a>
106
124
  <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
107
125
  </td>
108
- <td id='helmut-januschka'>
109
- <a href='https://github.com/hjanuschka'>
110
- <img src='https://github.com/hjanuschka.png?size=140'>
126
+ <td id='felix-krause'>
127
+ <a href='https://github.com/KrauseFx'>
128
+ <img src='https://github.com/KrauseFx.png?size=140'>
111
129
  </a>
112
- <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
130
+ <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
131
+ </td>
132
+ </tr>
133
+ <tr>
134
+ <td id='satoshi-namai'>
135
+ <a href='https://github.com/ainame'>
136
+ <img src='https://github.com/ainame.png?size=140'>
137
+ </a>
138
+ <h4 align='center'><a href='https://twitter.com/ainame'>Satoshi Namai</a></h4>
113
139
  </td>
114
140
  <td id='maksym-grebenets'>
115
141
  <a href='https://github.com/mgrebenets'>
@@ -117,11 +143,11 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
117
143
  </a>
118
144
  <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
119
145
  </td>
120
- <td id='danielle-tomlinson'>
121
- <a href='https://github.com/endocrimes'>
122
- <img src='https://github.com/endocrimes.png?size=140'>
146
+ <td id='max-ott'>
147
+ <a href='https://github.com/max-ott'>
148
+ <img src='https://github.com/max-ott.png?size=140'>
123
149
  </a>
124
- <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
150
+ <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
125
151
  </td>
126
152
  <td id='fumiya-nakamura'>
127
153
  <a href='https://github.com/nafu'>
@@ -129,32 +155,6 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
129
155
  </a>
130
156
  <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
131
157
  </td>
132
- </tr>
133
- <tr>
134
- <td id='jorge-revuelta-h'>
135
- <a href='https://github.com/minuscorp'>
136
- <img src='https://github.com/minuscorp.png?size=140'>
137
- </a>
138
- <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
139
- </td>
140
- <td id='felix-krause'>
141
- <a href='https://github.com/KrauseFx'>
142
- <img src='https://github.com/KrauseFx.png?size=140'>
143
- </a>
144
- <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
145
- </td>
146
- <td id='roger-oba'>
147
- <a href='https://github.com/rogerluan'>
148
- <img src='https://github.com/rogerluan.png?size=140'>
149
- </a>
150
- <h4 align='center'><a href='https://twitter.com/rogerluan_'>Roger Oba</a></h4>
151
- </td>
152
- <td id='daniel-jankowski'>
153
- <a href='https://github.com/mollyIV'>
154
- <img src='https://github.com/mollyIV.png?size=140'>
155
- </a>
156
- <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
157
- </td>
158
158
  <td id='olivier-halligon'>
159
159
  <a href='https://github.com/AliSoftware'>
160
160
  <img src='https://github.com/AliSoftware.png?size=140'>
@@ -163,29 +163,29 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
163
163
  </td>
164
164
  </tr>
165
165
  <tr>
166
- <td id='kohki-miki'>
167
- <a href='https://github.com/giginet'>
168
- <img src='https://github.com/giginet.png?size=140'>
166
+ <td id='helmut-januschka'>
167
+ <a href='https://github.com/hjanuschka'>
168
+ <img src='https://github.com/hjanuschka.png?size=140'>
169
169
  </a>
170
- <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
170
+ <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
171
171
  </td>
172
- <td id='max-ott'>
173
- <a href='https://github.com/max-ott'>
174
- <img src='https://github.com/max-ott.png?size=140'>
172
+ <td id='josh-holtz'>
173
+ <a href='https://github.com/joshdholtz'>
174
+ <img src='https://github.com/joshdholtz.png?size=140'>
175
175
  </a>
176
- <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
176
+ <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
177
177
  </td>
178
- <td id='luka-mirosevic'>
179
- <a href='https://github.com/lmirosevic'>
180
- <img src='https://github.com/lmirosevic.png?size=140'>
178
+ <td id='kohki-miki'>
179
+ <a href='https://github.com/giginet'>
180
+ <img src='https://github.com/giginet.png?size=140'>
181
181
  </a>
182
- <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
182
+ <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
183
183
  </td>
184
- <td id='andrew-mcburney'>
185
- <a href='https://github.com/armcburney'>
186
- <img src='https://github.com/armcburney.png?size=140'>
184
+ <td id='stefan-natchev'>
185
+ <a href='https://github.com/snatchev'>
186
+ <img src='https://github.com/snatchev.png?size=140'>
187
187
  </a>
188
- <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
188
+ <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
189
189
  </td>
190
190
  </table>
191
191
 
@@ -99,7 +99,7 @@ module Fastlane
99
99
  end
100
100
 
101
101
  def self.is_supported?(platform)
102
- true
102
+ [:ios, :mac, :tvos].include?(platform)
103
103
  end
104
104
 
105
105
  def self.details
@@ -1,5 +1,9 @@
1
1
  module Fastlane
2
2
  module Actions
3
+ module SharedValues
4
+ JIRA_JSON = :JIRA_JSON
5
+ end
6
+
3
7
  class JiraAction < Action
4
8
  def self.run(params)
5
9
  Actions.verify_gem!('jira-ruby')
@@ -21,10 +25,28 @@ module Fastlane
21
25
  password: password
22
26
  }
23
27
 
24
- client = JIRA::Client.new(options)
25
- issue = client.Issue.find(ticket_id)
26
- comment = issue.comments.build
27
- comment.save({ 'body' => comment_text })
28
+ begin
29
+ client = JIRA::Client.new(options)
30
+ issue = client.Issue.find(ticket_id)
31
+ comment = issue.comments.build
32
+ comment.save({ 'body' => comment_text })
33
+
34
+ # An exact representation of the JSON returned from the JIRA API
35
+ # https://github.com/sumoheavy/jira-ruby/blob/master/lib/jira/base.rb#L67
36
+ json_response = comment.attrs
37
+ raise 'Failed to add a comment on Jira ticket' if json_response.nil?
38
+
39
+ Actions.lane_context[SharedValues::JIRA_JSON] = json_response
40
+ UI.success('Successfully added a comment on Jira ticket')
41
+ return json_response
42
+ rescue => exception
43
+ message = "Received exception when adding a Jira comment: #{exception}"
44
+ if params[:fail_on_error]
45
+ UI.user_error!(message)
46
+ else
47
+ UI.error(message)
48
+ end
49
+ end
28
50
  end
29
51
 
30
52
  #####################################################
@@ -32,7 +54,7 @@ module Fastlane
32
54
  #####################################################
33
55
 
34
56
  def self.description
35
- "Leave a comment on JIRA tickets"
57
+ "Leave a comment on a Jira ticket"
36
58
  end
37
59
 
38
60
  def self.available_options
@@ -50,13 +72,13 @@ module Fastlane
50
72
  default_value: ""),
51
73
  FastlaneCore::ConfigItem.new(key: :username,
52
74
  env_name: "FL_JIRA_USERNAME",
53
- description: "Username for JIRA instance",
75
+ description: "Username for Jira instance",
54
76
  verify_block: proc do |value|
55
77
  UI.user_error!("No username") if value.to_s.length == 0
56
78
  end),
57
79
  FastlaneCore::ConfigItem.new(key: :password,
58
80
  env_name: "FL_JIRA_PASSWORD",
59
- description: "Password for Jira",
81
+ description: "Password or API token for Jira",
60
82
  sensitive: true,
61
83
  verify_block: proc do |value|
62
84
  UI.user_error!("No password") if value.to_s.length == 0
@@ -72,15 +94,35 @@ module Fastlane
72
94
  description: "Text to add to the ticket as a comment",
73
95
  verify_block: proc do |value|
74
96
  UI.user_error!("No comment specified") if value.to_s.length == 0
75
- end)
97
+ end),
98
+ FastlaneCore::ConfigItem.new(key: :fail_on_error,
99
+ env_name: "FL_JIRA_FAIL_ON_ERROR",
100
+ description: "Should an error adding the Jira comment cause a failure?",
101
+ type: Boolean,
102
+ optional: true,
103
+ default_value: true) # Default value is true for 'Backward compatibility'
104
+ ]
105
+ end
106
+
107
+ def self.output
108
+ [
109
+ ['JIRA_JSON', 'The whole Jira API JSON object']
76
110
  ]
77
111
  end
78
112
 
79
113
  def self.return_value
114
+ [
115
+ "A hash containing all relevant information of the Jira comment",
116
+ "Access Jira comment 'id', 'author', 'body', and more"
117
+ ].join("\n")
118
+ end
119
+
120
+ def self.return_type
121
+ :hash
80
122
  end
81
123
 
82
124
  def self.authors
83
- ["iAmChrisTruman"]
125
+ ["iAmChrisTruman", "crazymanish"]
84
126
  end
85
127
 
86
128
  def self.is_supported?(platform)
@@ -92,17 +134,22 @@ module Fastlane
92
134
  'jira(
93
135
  url: "https://bugs.yourdomain.com",
94
136
  username: "Your username",
95
- password: "Your password",
96
- ticket_id: "Ticket ID, i.e. IOS-123",
137
+ password: "Your password or API token",
138
+ ticket_id: "IOS-123",
97
139
  comment_text: "Text to post as a comment"
98
- )',
140
+ )', # How to get API token: https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/#get-an-api-token
99
141
  'jira(
100
142
  url: "https://yourserverdomain.com",
101
143
  context_path: "/jira",
102
144
  username: "Your username",
103
- password: "Your password",
104
- ticket_id: "Ticket ID, i.e. IOS-123",
145
+ password: "Your password or API token",
146
+ ticket_id: "IOS-123",
105
147
  comment_text: "Text to post as a comment"
148
+ )',
149
+ 'jira(
150
+ ticket_id: "IOS-123",
151
+ comment_text: "Text to post as a comment",
152
+ fail_on_error: false
106
153
  )'
107
154
  ]
108
155
  end
@@ -1,12 +1,14 @@
1
1
  module Fastlane
2
2
  module Actions
3
3
  class NotarizeAction < Action
4
+ # rubocop:disable Metrics/PerceivedComplexity
4
5
  def self.run(params)
5
6
  package_path = params[:package]
6
7
  bundle_id = params[:bundle_id]
7
8
  try_early_stapling = params[:try_early_stapling]
8
9
  print_log = params[:print_log]
9
10
  verbose = params[:verbose]
11
+ api_key_path = params[:api_key_path]
10
12
 
11
13
  # Compress and read bundle identifier only for .app bundle.
12
14
  compressed_package_path = nil
@@ -28,68 +30,73 @@ module Fastlane
28
30
 
29
31
  UI.user_error!('Could not read bundle identifier, provide as a parameter') unless bundle_id
30
32
 
31
- apple_id_account = CredentialsManager::AccountManager.new(user: params[:username])
32
-
33
- # Add password as a temporary environment variable for altool.
34
- # Use app specific password if specified.
35
- ENV['FL_NOTARIZE_PASSWORD'] = ENV['FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD'] || apple_id_account.password
36
-
37
33
  UI.message('Uploading package to notarization service, might take a while')
38
34
 
39
- notarization_upload_command = "xcrun altool --notarize-app -t osx -f \"#{compressed_package_path || package_path}\" --primary-bundle-id #{bundle_id} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD --output-format xml"
40
- notarization_upload_command << " --asc-provider \"#{params[:asc_provider]}\"" if params[:asc_provider]
35
+ notarization_upload_command = "xcrun altool --notarize-app -t osx -f \"#{compressed_package_path || package_path}\" --primary-bundle-id #{bundle_id} --output-format xml"
41
36
 
42
- notarization_upload_response = Actions.sh(
43
- notarization_upload_command,
44
- log: verbose
45
- )
37
+ notarization_info = {}
38
+ with_notarize_authenticator(params, api_key_path) do |notarize_authenticator|
39
+ notarization_upload_command << " --asc-provider \"#{params[:asc_provider]}\"" if params[:asc_provider] && api_key_path.nil?
46
40
 
47
- FileUtils.rm_rf(compressed_package_path) if compressed_package_path
41
+ notarization_upload_response = Actions.sh(
42
+ notarize_authenticator.call(notarization_upload_command),
43
+ log: verbose
44
+ )
48
45
 
49
- notarization_upload_plist = Plist.parse_xml(notarization_upload_response)
50
- notarization_request_id = notarization_upload_plist['notarization-upload']['RequestUUID']
46
+ FileUtils.rm_rf(compressed_package_path) if compressed_package_path
51
47
 
52
- UI.success("Successfully uploaded package to notarization service with request identifier #{notarization_request_id}")
48
+ notarization_upload_plist = Plist.parse_xml(notarization_upload_response)
53
49
 
54
- notarization_info = {}
55
- while notarization_info.empty? || (notarization_info['Status'] == 'in progress')
56
- if notarization_info.empty?
57
- UI.message('Waiting to query request status')
58
- elsif try_early_stapling
59
- UI.message('Request in progress, trying early staple')
60
-
61
- begin
62
- self.staple(package_path, verbose)
63
- UI.message('Successfully notarized and early stapled package.')
64
-
65
- return
66
- rescue
67
- UI.message('Early staple failed, waiting to query again')
68
- end
50
+ if notarization_upload_plist.key?('product-errors') && notarization_upload_plist['product-errors'].any?
51
+ UI.important("🚫 Could not upload package to notarization service! Here are the reasons:")
52
+ notarization_upload_plist['product-errors'].each { |product_error| UI.error("#{product_error['message']} (#{product_error['code']})") }
53
+ UI.user_error!("Package upload to notarization service cancelled. Please check the error messages above.")
69
54
  end
70
55
 
71
- sleep(30)
72
-
73
- UI.message('Querying request status')
74
-
75
- # As of July 2020, the request UUID might not be available for polling yet which returns an error code
76
- # This is now handled with the error_callback (which prevents an error from being raised)
77
- # Catching this error allows for polling to continue until the notarization is complete
78
- error = false
79
- notarization_info_response = Actions.sh(
80
- "xcrun altool --notarization-info #{notarization_request_id} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD --output-format xml",
81
- log: verbose,
82
- error_callback: lambda { |msg|
83
- error = true
84
- UI.error("Error polling for notarization info: #{msg}")
85
- }
86
- )
56
+ notarization_request_id = notarization_upload_plist['notarization-upload']['RequestUUID']
57
+
58
+ UI.success("Successfully uploaded package to notarization service with request identifier #{notarization_request_id}")
59
+
60
+ while notarization_info.empty? || (notarization_info['Status'] == 'in progress')
61
+ if notarization_info.empty?
62
+ UI.message('Waiting to query request status')
63
+ elsif try_early_stapling
64
+ UI.message('Request in progress, trying early staple')
65
+
66
+ begin
67
+ self.staple(package_path, verbose)
68
+ UI.message('Successfully notarized and early stapled package.')
69
+
70
+ return
71
+ rescue
72
+ UI.message('Early staple failed, waiting to query again')
73
+ end
74
+ end
87
75
 
88
- unless error
89
- notarization_info_plist = Plist.parse_xml(notarization_info_response)
90
- notarization_info = notarization_info_plist['notarization-info']
76
+ sleep(30)
77
+
78
+ UI.message('Querying request status')
79
+
80
+ # As of July 2020, the request UUID might not be available for polling yet which returns an error code
81
+ # This is now handled with the error_callback (which prevents an error from being raised)
82
+ # Catching this error allows for polling to continue until the notarization is complete
83
+ error = false
84
+ notarization_info_response = Actions.sh(
85
+ notarize_authenticator.call("xcrun altool --notarization-info #{notarization_request_id} --output-format xml"),
86
+ log: verbose,
87
+ error_callback: lambda { |msg|
88
+ error = true
89
+ UI.error("Error polling for notarization info: #{msg}")
90
+ }
91
+ )
92
+
93
+ unless error
94
+ notarization_info_plist = Plist.parse_xml(notarization_info_response)
95
+ notarization_info = notarization_info_plist['notarization-info']
96
+ end
91
97
  end
92
98
  end
99
+ # rubocop:enable Metrics/PerceivedComplexity
93
100
 
94
101
  log_url = notarization_info['LogFileURL']
95
102
  ENV['FL_NOTARIZE_LOG_FILE_URL'] = log_url
@@ -123,6 +130,35 @@ module Fastlane
123
130
  )
124
131
  end
125
132
 
133
+ def self.with_notarize_authenticator(params, api_key_path)
134
+ if api_key_path
135
+ # From xcrun altool for --apiKey:
136
+ # This option will search the following directories in sequence for a private key file with the name of 'AuthKey_<api_key>.p8': './private_keys', '~/private_keys', '~/.private_keys', and '~/.appstoreconnect/private_keys'.
137
+ api_key = Spaceship::ConnectAPI::Token.from_json_file(api_key_path)
138
+ api_key_folder_path = File.expand_path('~/.appstoreconnect/private_keys')
139
+ api_key_file_path = File.join(api_key_folder_path, "AuthKey_#{api_key.key_id}.p8")
140
+ directory_exists = File.directory?(api_key_folder_path)
141
+ file_exists = File.exist?(api_key_file_path)
142
+ begin
143
+ FileUtils.mkdir_p(api_key_folder_path) unless directory_exists
144
+ api_key.write_key_to_file(api_key_file_path) unless file_exists
145
+
146
+ yield(proc { |command| "#{command} --apiKey #{api_key.key_id} --apiIssuer #{api_key.issuer_id}" })
147
+ ensure
148
+ FileUtils.rm(api_key_file_path) unless file_exists
149
+ FileUtils.rm_r(api_key_folder_path) unless directory_exists
150
+ end
151
+ else
152
+ apple_id_account = CredentialsManager::AccountManager.new(user: params[:username])
153
+
154
+ # Add password as a temporary environment variable for altool.
155
+ # Use app specific password if specified.
156
+ ENV['FL_NOTARIZE_PASSWORD'] = ENV['FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD'] || apple_id_account.password
157
+
158
+ yield(proc { |command| "#{command} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD" })
159
+ end
160
+ end
161
+
126
162
  def self.description
127
163
  'Notarizes a macOS app'
128
164
  end
@@ -160,6 +196,8 @@ module Fastlane
160
196
  env_name: 'FL_NOTARIZE_USERNAME',
161
197
  description: 'Apple ID username',
162
198
  default_value: username,
199
+ optional: true,
200
+ conflicting_options: [:api_key_path],
163
201
  default_value_dynamic: true),
164
202
  FastlaneCore::ConfigItem.new(key: :asc_provider,
165
203
  env_name: 'FL_NOTARIZE_ASC_PROVIDER',
@@ -177,7 +215,16 @@ module Fastlane
177
215
  description: 'Whether to log requests',
178
216
  optional: true,
179
217
  default_value: false,
180
- type: Boolean)
218
+ type: Boolean),
219
+ FastlaneCore::ConfigItem.new(key: :api_key_path,
220
+ env_name: 'FL_NOTARIZE_API_KEY_PATH',
221
+ description: 'Path to AppStore Connect API key',
222
+ optional: true,
223
+ conflicting_options: [:username],
224
+ is_string: true,
225
+ verify_block: proc do |value|
226
+ UI.user_error!("API Key not found at '#{value}'") unless File.exist?(value)
227
+ end)
181
228
  ]
182
229
  end
183
230