deliver 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +20 -16
- data/lib/assets/DeliverfileDefault +2 -1
- data/lib/assets/DeliverfileExample +1 -1
- data/lib/deliver/app.rb +9 -2
- data/lib/deliver/deliverfile/deliverfile_creator.rb +3 -1
- data/lib/deliver/deliverfile/dsl.rb +6 -0
- data/lib/deliver/itunes_connect.rb +3 -3
- data/lib/deliver/itunes_transporter.rb +3 -3
- data/lib/deliver/password_manager.rb +38 -14
- data/lib/deliver/version.rb +1 -1
- data/spec/deliverfile_creator_spec.rb +2 -1
- data/spec/spec_helper.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be16fd06999f4fd2f5621ea5b1c4997f461776f6
|
4
|
+
data.tar.gz: d694a822e357510159c6c54cb9fe85259294df81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b1cbc989b40241a3f86ee2d1a85e670725b573f4cd3834be0efe92f799458e879b5521258aae7656c35074d5a18a760496b0a75134534f31ced29fd4f171e9a
|
7
|
+
data.tar.gz: 65a221d7ce61b6e083b0a3f07caef042e62a17def9d02b37f862c189f5d4b0020d6a8fdb81cf136e220b50230ccae355983779c5e3013d52782ca7c55bcdda39
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ Deliver - Continuous Deployment for iOS
|
|
14
14
|
Updating your iOS app should not be painful and time consuming. Automate the
|
15
15
|
whole process to start with Continuous Deployment.
|
16
16
|
|
17
|
-
```Deliver``` **can upload ipa files, app screenshots and more to the
|
17
|
+
```Deliver``` **can upload ipa files, app screenshots and more to the iTunes Connect backend**, which means, you can deploy new iPhone app updates just by using one command.
|
18
18
|
|
19
19
|
Follow the developer on Twitter: [@KrauseFx](https://twitter.com/KrauseFx)
|
20
20
|
|
@@ -34,11 +34,11 @@ Follow the developer on Twitter: [@KrauseFx](https://twitter.com/KrauseFx)
|
|
34
34
|
|
35
35
|
# Features
|
36
36
|
- Upload hundreds of screenshots with different languages from different devices
|
37
|
-
- Upload a new ipa file to
|
37
|
+
- Upload a new ipa file to iTunes Connect without Xcode from any computer
|
38
38
|
- Update app metadata
|
39
39
|
- Easily implement a real Continuous Deployment process
|
40
40
|
- Store the configuration in git to easily deploy from **any** computer, including your Continuous Integration server (e.g. Jenkins)
|
41
|
-
- Get a PDF preview of the fetched metadata before uploading the app metadata and screenshots to Apple: [Example Preview](https://github.com/krausefx/deliver/blob/master/assets/PDFExample.png?raw=1) (Yes, those are screenshots
|
41
|
+
- Get a PDF preview of the fetched metadata before uploading the app metadata and screenshots to Apple: [Example Preview](https://github.com/krausefx/deliver/blob/master/assets/PDFExample.png?raw=1) (Yes, those are screenshots taken for all screen sizes)
|
42
42
|
|
43
43
|
# Installation
|
44
44
|
|
@@ -50,7 +50,7 @@ Make sure, you have the latest version of the Xcode command line tools installed
|
|
50
50
|
|
51
51
|
xcode-select --install
|
52
52
|
|
53
|
-
Install phantomjs (this is needed to control the
|
53
|
+
Install phantomjs (this is needed to control the iTunes Connect frontend)
|
54
54
|
|
55
55
|
brew update && brew install phantomjs
|
56
56
|
|
@@ -59,12 +59,12 @@ If you don't have homebrew installed already, [install it here](http://brew.sh/)
|
|
59
59
|
# Quick Start
|
60
60
|
|
61
61
|
|
62
|
-
The guide will create all the necessary files for you, using the existing app metadata from
|
62
|
+
The guide will create all the necessary files for you, using the existing app metadata from iTunes Connect.
|
63
63
|
|
64
64
|
- ```cd [your_project_folder]```
|
65
65
|
- ```deliver init```
|
66
|
-
- When your app is already in the
|
67
|
-
- Enter your
|
66
|
+
- When your app is already in the App Store: ```y```
|
67
|
+
- Enter your iTunes Connect credentials
|
68
68
|
- Enter your app identifier
|
69
69
|
- Enjoy a good drink, while the computer does all the work for you
|
70
70
|
- When it's a new app: ```n```
|
@@ -85,12 +85,12 @@ Why should you have to remember complicated commands and parameters?
|
|
85
85
|
|
86
86
|
Store your configuration in a text file to easily deploy from any computer.
|
87
87
|
|
88
|
-
Run ```deliver init``` to create a new ```Deliverfile```. You can either let the wizard generate a file based on the metadata from
|
88
|
+
Run ```deliver init``` to create a new ```Deliverfile```. You can either let the wizard generate a file based on the metadata from iTunes Connect or create one from a template.
|
89
89
|
|
90
90
|
Once you created your configuration, just run ```deliver```.
|
91
91
|
|
92
92
|
Here are a few example files:
|
93
|
-
#### Upload screenshots to
|
93
|
+
#### Upload screenshots to iTunes Connect
|
94
94
|
```ruby
|
95
95
|
app_identifier "net.sunapps.1"
|
96
96
|
version "1.1"
|
@@ -99,7 +99,7 @@ screenshots_path "./screenshots"
|
|
99
99
|
```
|
100
100
|
The screenshots folder must include one subfolder per language (see [Available language codes](#available-language-codes))
|
101
101
|
|
102
|
-
#### Upload a new ipa file with a changelog to the
|
102
|
+
#### Upload a new ipa file with a changelog to the App Store
|
103
103
|
This will submit a new update to Apple
|
104
104
|
```ruby
|
105
105
|
ipa "./latest.ipa"
|
@@ -202,17 +202,21 @@ This project is well documented, check it out on [Rubydoc](http://www.rubydoc.in
|
|
202
202
|
|
203
203
|
|
204
204
|
# Credentials
|
205
|
+
The used username (Apple ID) will be stored in the ```Deliverfile``` by default. When you run ```deliver``` for the first time on another computer, you will only be asked for the password.
|
206
|
+
|
207
|
+
Therefore it is easy to switch between projects, without needing to logout and login again.
|
205
208
|
|
206
209
|
## Use the Keychain
|
207
|
-
The first time you use *Deliver* you have to enter your
|
210
|
+
The first time you use *Deliver* you have to enter your iTunes Connect
|
208
211
|
credentials. They will be stored in the Keychain.
|
209
212
|
|
210
213
|
If you decide to remove your
|
211
214
|
credentials from the Keychain, just open the *Keychain Access*, select
|
212
|
-
*All Items* and search for '
|
215
|
+
*All Items* and search for 'deliver'.
|
213
216
|
|
214
217
|
## Use environment variables
|
215
|
-
You can use the following environment variables to use a specific account instead of the one stored in the keychain
|
218
|
+
You can use the following environment variables to use a specific account instead of the one stored in the keychain.
|
219
|
+
This is especially important if you have more than one iTunes Connect account in your keychain:
|
216
220
|
|
217
221
|
DELIVER_USER
|
218
222
|
DELIVER_PASSWORD
|
@@ -229,8 +233,8 @@ Before actually uploading anything to iTunes, ```Deliver``` will generate a [PDF
|
|
229
233
|
|
230
234
|
```Deliver``` uses the following techniques under the hood:
|
231
235
|
|
232
|
-
- The iTMSTransporter tool is used to fetch the latest app metadata from
|
233
|
-
- With the iTMSTransporter you cannot create new version on
|
236
|
+
- The iTMSTransporter tool is used to fetch the latest app metadata from iTunes Connect and upload the updated app metadata back to Apple. It is also used to upload the ipa file. iTMSTransporter is a command line tool provided by Apple.
|
237
|
+
- With the iTMSTransporter you cannot create new version on iTunes Connect or actually publish the newly uploaded ipa file. This is why there is some browser scripting involved, using [Capybara](https://github.com/jnicklas/capybara) and [Poltergeist](https://github.com/teampoltergeist/poltergeist).
|
234
238
|
- The iTunes search API to find missing information about a certain app, like the *apple_id* when you only pass the *bundle_identifier*.
|
235
239
|
|
236
240
|
# Tips
|
@@ -263,7 +267,7 @@ These are features, which are implemented, but not yet fully tested and producti
|
|
263
267
|
```ruby
|
264
268
|
beta_ipa "./latest.ipa"
|
265
269
|
```
|
266
|
-
This will upload the ipa file to
|
270
|
+
This will upload the ipa file to iTunes Connect and mark the uploaded build as Beta build.
|
267
271
|
|
268
272
|
# Need help?
|
269
273
|
- If there is a technical problem with ```Deliver```, submit an issue. Run ```deliver --trace``` to get the stacktrace.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# For more information about each property, visit the GitHub documentation: https://github.com/krausefx/deliver
|
2
2
|
# Everything next to a # is a comment and will be ignored
|
3
3
|
|
4
|
-
|
4
|
+
email '[[EMAIL]]'
|
5
5
|
|
6
6
|
########################################
|
7
7
|
# App Metadata
|
@@ -9,6 +9,7 @@
|
|
9
9
|
|
10
10
|
# The app identifier is required
|
11
11
|
app_identifier "[[APP_IDENTIFIER]]"
|
12
|
+
apple_id "[[APPLE_ID]]"
|
12
13
|
|
13
14
|
|
14
15
|
# This folder has to include one folder for each language
|
data/lib/deliver/app.rb
CHANGED
@@ -43,8 +43,15 @@ module Deliver
|
|
43
43
|
begin
|
44
44
|
self.apple_id = Deliver::ItunesSearchApi.fetch_by_identifier(app_identifier)['trackId']
|
45
45
|
rescue
|
46
|
-
Helper.
|
47
|
-
|
46
|
+
unless Helper.is_test?
|
47
|
+
Helper.log.info "Could not find Apple ID based on the app identifier in the US App Store. Maybe the app is not yet in the store?".yellow
|
48
|
+
|
49
|
+
while ((self.apple_id || '').to_s.length == 0) || ((self.apple_id || 0).to_i == 0)
|
50
|
+
self.apple_id = ask("\nApple ID of your app (e.g. 284882215): ")
|
51
|
+
end
|
52
|
+
else
|
53
|
+
raise "Please pass a valid Apple ID using 'apple_id'".red
|
54
|
+
end
|
48
55
|
end
|
49
56
|
end
|
50
57
|
end
|
@@ -18,7 +18,7 @@ module Deliver
|
|
18
18
|
"\nThis is necessary to fetch the latest metadata from your app and use it to create a Deliverfile for you." +
|
19
19
|
"\nIf you have previously entered your credentials already, you will not be asked again."
|
20
20
|
|
21
|
-
if Deliver::PasswordManager.
|
21
|
+
if Deliver::PasswordManager.shared_manager.username and Deliver::PasswordManager.shared_manager.password
|
22
22
|
identifier = ''
|
23
23
|
while identifier.length < 3
|
24
24
|
identifier = ask("\nApp Identifier of your app (e.g. at.felixkrause.app_name): ")
|
@@ -86,6 +86,8 @@ module Deliver
|
|
86
86
|
deliver = File.read("#{gem_path}/lib/assets/DeliverfileDefault")
|
87
87
|
deliver.gsub!("[[APP_IDENTIFIER]]", app.app_identifier)
|
88
88
|
deliver.gsub!("[[APP_NAME]]", project_name)
|
89
|
+
deliver.gsub!("[[APPLE_ID]]", app.apple_id.to_s)
|
90
|
+
deliver.gsub!("[[EMAIL]]", PasswordManager.shared_manager.username)
|
89
91
|
|
90
92
|
return deliver
|
91
93
|
end
|
@@ -101,6 +101,12 @@ module Deliver
|
|
101
101
|
@deliver_data.set_new_value(Deliverer::ValKey::BETA_IPA, value)
|
102
102
|
end
|
103
103
|
|
104
|
+
# This will set the email address of the Apple ID to be used
|
105
|
+
def email(value)
|
106
|
+
value ||= yield if block_given?
|
107
|
+
PasswordManager.shared_manager(value)
|
108
|
+
end
|
109
|
+
|
104
110
|
# Set the apps new version number.
|
105
111
|
#
|
106
112
|
# If you do not set this, it will automatically being fetched from the
|
@@ -72,8 +72,8 @@ module Deliver
|
|
72
72
|
begin
|
73
73
|
Helper.log.info "Logging into iTunesConnect"
|
74
74
|
|
75
|
-
user ||= PasswordManager.
|
76
|
-
password ||= PasswordManager.
|
75
|
+
user ||= PasswordManager.shared_manager.username
|
76
|
+
password ||= PasswordManager.shared_manager.password
|
77
77
|
|
78
78
|
result = visit ITUNESCONNECT_URL
|
79
79
|
raise "Could not open iTunesConnect" unless result['status'] == 'success'
|
@@ -119,7 +119,7 @@ module Deliver
|
|
119
119
|
sleep 3
|
120
120
|
|
121
121
|
if current_url.include?"wa/defaultError" # app could not be found
|
122
|
-
raise "Could not open app details for app '#{app}'. Make sure you're using the correct Apple ID and the correct Apple developer account (#{PasswordManager.
|
122
|
+
raise "Could not open app details for app '#{app}'. Make sure you're using the correct Apple ID and the correct Apple developer account (#{PasswordManager.shared_manager.username}).".red
|
123
123
|
end
|
124
124
|
|
125
125
|
true
|
@@ -23,8 +23,8 @@ module Deliver
|
|
23
23
|
# If no username or password given, it will be taken from
|
24
24
|
# the #{Deliver::PasswordManager}
|
25
25
|
def initialize(user = nil, password = nil)
|
26
|
-
@user = (user || PasswordManager.
|
27
|
-
@password = (password || PasswordManager.
|
26
|
+
@user = (user || PasswordManager.shared_manager.username)
|
27
|
+
@password = (password || PasswordManager.shared_manager.password)
|
28
28
|
end
|
29
29
|
|
30
30
|
# Downloads the latest version of the app metadata package from iTC.
|
@@ -112,7 +112,7 @@ module Deliver
|
|
112
112
|
if $1.include?"Your Apple ID or password was entered incorrectly" or
|
113
113
|
$1.include?"This Apple ID has been locked for security reasons"
|
114
114
|
|
115
|
-
Deliver::PasswordManager.
|
115
|
+
Deliver::PasswordManager.shared_manager.password_seems_wrong
|
116
116
|
end
|
117
117
|
|
118
118
|
elsif line =~ WARNING_REGEX
|
@@ -9,15 +9,23 @@ module Deliver
|
|
9
9
|
# @return [String] The password of the currently logged in user
|
10
10
|
attr_accessor :password
|
11
11
|
|
12
|
-
HOST = "
|
12
|
+
HOST = "deliver" # there might be a string appended, if user has multiple accounts
|
13
13
|
private_constant :HOST
|
14
14
|
|
15
|
+
# A singleton object, which also makes sure, to use the correct Apple ID
|
16
|
+
# @param id_to_use (String) The Apple ID email address which should be used
|
17
|
+
def self.shared_manager(id_to_use = nil)
|
18
|
+
@@instance ||= PasswordManager.new(id_to_use)
|
19
|
+
end
|
20
|
+
|
15
21
|
# A new instance of PasswordManager.
|
16
22
|
#
|
17
23
|
# This already check the Keychain if there is a username and password stored.
|
18
24
|
# If that's not the case, it will ask for login data via stdin
|
19
|
-
|
20
|
-
|
25
|
+
# @param id_to_use (String) Apple ID (e.g. steve@apple.com) which should be used for this upload.
|
26
|
+
# if given, only the password will be asked/loaded.
|
27
|
+
def initialize(id_to_use = nil)
|
28
|
+
self.username ||= ENV["DELIVER_USER"] || id_to_use || load_from_keychain[0]
|
21
29
|
self.password ||= ENV["DELIVER_PASSWORD"] || load_from_keychain[1]
|
22
30
|
|
23
31
|
if (self.username || '').length == 0 or (self.password || '').length == 0
|
@@ -36,9 +44,10 @@ module Deliver
|
|
36
44
|
puts "It seems like the username or password for the account '#{self.username}' is wrong."
|
37
45
|
reenter = agree("Do you want to re-enter your username and password? (y/n)", true)
|
38
46
|
if reenter
|
47
|
+
remove_from_keychain
|
48
|
+
|
39
49
|
@username = nil
|
40
50
|
@password = nil
|
41
|
-
remove_from_keychain
|
42
51
|
|
43
52
|
puts "You will have to re-run the recent command to use the new username/password."
|
44
53
|
return true
|
@@ -54,33 +63,48 @@ module Deliver
|
|
54
63
|
puts "More information about that on GitHub: https://github.com/krausefx/deliver".green
|
55
64
|
puts "--------------------------------------------------------------------------".green
|
56
65
|
|
66
|
+
username_was_there = self.username
|
67
|
+
|
57
68
|
while (self.username || '').length == 0
|
58
69
|
self.username = ask("Username: ")
|
59
70
|
end
|
60
71
|
|
61
|
-
|
62
|
-
self.password = ask("Password: ") { |q| q.echo = "*" }
|
63
|
-
end
|
72
|
+
self.password ||= load_from_keychain[1] # maybe there was already something stored in the keychain
|
64
73
|
|
65
|
-
|
66
|
-
# Example usage taken from https://github.com/nomad/cupertino/blob/master/lib/cupertino/provisioning_portal/commands/login.rb
|
67
|
-
if Security::InternetPassword.add(HOST, self.username, self.password)
|
74
|
+
if (self.password || '').length > 0
|
68
75
|
return true
|
69
76
|
else
|
70
|
-
|
71
|
-
|
77
|
+
while (self.password || '').length == 0
|
78
|
+
text = "Password: "
|
79
|
+
text = "Password (for #{self.username}): " if username_was_there
|
80
|
+
self.password = ask(text) { |q| q.echo = "*" }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Now we store this information in the keychain
|
84
|
+
# Example usage taken from https://github.com/nomad/cupertino/blob/master/lib/cupertino/provisioning_portal/commands/login.rb
|
85
|
+
if Security::InternetPassword.add(hostname, self.username, self.password)
|
86
|
+
return true
|
87
|
+
else
|
88
|
+
Helper.log.error "Could not store password in keychain"
|
89
|
+
return false
|
90
|
+
end
|
72
91
|
end
|
73
92
|
end
|
74
93
|
|
75
94
|
def remove_from_keychain
|
76
|
-
|
95
|
+
puts "removing keychain item: #{hostname}"
|
96
|
+
Security::InternetPassword.delete(:server => hostname)
|
77
97
|
end
|
78
98
|
|
79
99
|
def load_from_keychain
|
80
|
-
pass = Security::InternetPassword.find(:server =>
|
100
|
+
pass = Security::InternetPassword.find(:server => hostname)
|
81
101
|
|
82
102
|
return [pass.attributes['acct'], pass.password] if pass
|
83
103
|
return [nil, nil]
|
84
104
|
end
|
105
|
+
|
106
|
+
def hostname
|
107
|
+
[HOST, self.username].join('.')
|
108
|
+
end
|
85
109
|
end
|
86
110
|
end
|
data/lib/deliver/version.rb
CHANGED
@@ -32,7 +32,6 @@ describe Deliver do
|
|
32
32
|
FileUtils.rm_rf("/tmp/#{apple_id}.itmsp") rescue nil
|
33
33
|
|
34
34
|
|
35
|
-
|
36
35
|
|
37
36
|
Deliver::ItunesTransporter.set_mock_file("spec/responses/transporter/download_valid_apple_id.txt")
|
38
37
|
|
@@ -60,6 +59,8 @@ describe Deliver do
|
|
60
59
|
correct = File.read("./lib/assets/DeliverfileDefault")
|
61
60
|
correct.gsub!("[[APP_IDENTIFIER]]", 'net.sunapps.54')
|
62
61
|
correct.gsub!("[[APP_NAME]]", project_name)
|
62
|
+
correct.gsub!("[[EMAIL]]", ENV["DELIVER_USER"])
|
63
|
+
correct.gsub!("[[APPLE_ID]]", apple_id.to_s)
|
63
64
|
expect(File.read("/tmp/Deliverfile")).to eq(correct)
|
64
65
|
|
65
66
|
expect(File.directory?([deliver_path, "screenshots"].join("/"))).to eq(true)
|
data/spec/spec_helper.rb
CHANGED
@@ -10,6 +10,9 @@ require 'mocking/webmocking'
|
|
10
10
|
require 'mocking/transporter_mocking'
|
11
11
|
|
12
12
|
|
13
|
+
ENV["DELIVER_USER"] = "DELIVERUSER"
|
14
|
+
ENV["DELIVER_PASSWORD"] = "DELIVERPASS"
|
15
|
+
|
13
16
|
# This module is only used to check the environment is currently a testing env
|
14
17
|
module SpecHelper
|
15
18
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deliver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: security
|