fastlane 2.179.0 → 2.180.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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