shenzhen 0.9.0 → 0.10.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
  SHA1:
3
- metadata.gz: 2745f53de64c6a957f3a244a80ed2bba9158bef2
4
- data.tar.gz: 07d9564be28ee258ca0a34fd455d6cde603d6458
3
+ metadata.gz: cd6f780fc6f948207a05137f7601aa343f853748
4
+ data.tar.gz: 5d2c3f534324b6e693ab7e506d5f1d1fb2aef0b6
5
5
  SHA512:
6
- metadata.gz: 9c66500a86a7a9ffa9120f565a0d151b4fa9dc87bad995730d1d186d8f06b4b03602e9ac0f5f577f4c86d818b95f4639968e7ddec82053c511079d2a8ff9ad8a
7
- data.tar.gz: 3fab0ee6067d5f030bbed3de04d6ee3dd7e12aec3887b59da1e4a5a0266846a2b1b842e2923141015d6a4d52754d42e59736bfd13105a25c03dfc085c91d6b95
6
+ metadata.gz: c15377a72c05879235ee17772e26d06fa20d49e6dbed6131e740704834bd586a664a425f446750eb9daa8db209595f2445df815d31b93b889b6c89bda9a3e31f
7
+ data.tar.gz: 8a38072bf6fc2311e48acce05d99439daac70335bb4edac49c9acd1d956c358a06b20565c34e14ff60584b6cad856807ca730104ee007ba2dc5747ffe5258648
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shenzhen (0.9.0)
4
+ shenzhen (0.10.0)
5
5
  aws-sdk (~> 1.0)
6
6
  commander (~> 4.1)
7
7
  dotenv (~> 0.7)
data/README.md CHANGED
@@ -1,8 +1,18 @@
1
1
  ![Shenzhen](https://raw.github.com/nomad/nomad.github.io/assets/shenzhen-banner.png)
2
2
 
3
- Create `.ipa` files and then distribute them with [TestFlight](https://testflightapp.com/), [HockeyApp](http://www.hockeyapp.net), [Crashlytics Beta](http://try.crashlytics.com/beta/), [DeployGate](https://deploygate.com), or even through [iTunes Connect](https://itunesconnect.apple.com)—all from the command line!
3
+ Create `.ipa` files and distribute them from the command line, using any of the following methods:
4
4
 
5
- Less cumbersome than clicking around in Xcode, and less hassle than rolling your own build script--Shenzhen radically improves the process of getting new builds out to testers and enterprises.
5
+ - [iTunes Connect](https://itunesconnect.apple.com)
6
+ - [TestFlight](https://testflightapp.com/)
7
+ - [HockeyApp](http://www.hockeyapp.net)
8
+ - [Crashlytics Beta](http://try.crashlytics.com/beta/)
9
+ - [DeployGate](https://deploygate.com)
10
+ - [Fly It Remotely (FIR.im)](http://fir.im)
11
+ - [蒲公英 (PGYER)](http://www.pgyer.com)
12
+ - [Amazon S3](http://aws.amazon.com/s3/)
13
+ - FTP / SFTP
14
+
15
+ Less cumbersome than clicking around in Xcode, and less hassle than rolling your own build script, Shenzhen radically improves the process of getting new builds out to testers and enterprises.
6
16
 
7
17
  > `shenzhen` is named for [深圳](http://en.wikipedia.org/wiki/Shenzhen), the Chinese city famous for being the center of manufacturing for a majority of consumer electronics, including iPhones and iPads.
8
18
  > It's part of a series of world-class command-line utilities for iOS development, which includes [Cupertino](https://github.com/mattt/cupertino) (Apple Dev Center management), [Houston](https://github.com/mattt/houston) (Push Notifications), [Venice](https://github.com/mattt/venice) (In-App Purchase Receipt Verification), [Dubai](https://github.com/mattt/dubai) (Passbook pass generation), and [Nashville](https://github.com/nomad/nashville) (iTunes Store API).
@@ -34,7 +44,7 @@ Shenzhen adds the `ipa` command to your PATH:
34
44
  ```
35
45
  $ ipa
36
46
 
37
- Build and distribute iOS apps (.ipa files)
47
+ Build and distribute iOS apps (.ipa files)
38
48
 
39
49
  Commands:
40
50
  build Create a new .ipa file for your app
@@ -42,7 +52,9 @@ $ ipa
42
52
  distribute:hockeyapp Distribute an .ipa file over HockeyApp
43
53
  distribute:crashlytics Distribute an .ipa file over Crashlytics
44
54
  distribute:deploygate Distribute an .ipa file over deploygate
55
+ distribute:firim Distribute an .ipa file over fir.im
45
56
  distribute:itunesconnect Upload an .ipa file to iTunes Connect for review
57
+ distribute:pgyer Distribute an .ipa file over Pgyer
46
58
  distribute:ftp Distribute an .ipa file over FTP
47
59
  distribute:s3 Distribute an .ipa file over Amazon S3
48
60
  info Show mobile provisioning information about an .ipa file
@@ -118,6 +130,23 @@ $ ipa distribute:s3 -a ACCESS_KEY_ID -s SECRET_ACCESS_KEY -b BUCKET
118
130
 
119
131
  > Shenzhen will load credentials from the environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION` unless otherwise specified.
120
132
 
133
+ #### FIR (Fly it Remotely)
134
+
135
+ ```
136
+ $ ipa distribute:fir -u USER_TOKEN -a APP_ID
137
+ ```
138
+
139
+ > Shenzhen will load credentials from the environment variables `FIR_USER_TOKEN`, `FIR_APP_ID` unless otherwise specified.
140
+
141
+ #### 蒲公英 (PGYER)
142
+
143
+ ```
144
+ $ ipa distribute:pgyer -u USER_KEY -a APP_KEY
145
+ ```
146
+
147
+ > Shenzhen will load credentials from the environment variables `PGYER_USER_KEY`, `PGYER_APP_KEY` unless otherwise specified.
148
+
149
+
121
150
  #### iTunes Connect Distribution
122
151
 
123
152
  ```
@@ -7,6 +7,8 @@ require 'plugins/itunesconnect'
7
7
  require 'plugins/ftp'
8
8
  require 'plugins/s3'
9
9
  require 'plugins/crashlytics'
10
+ require 'plugins/fir'
11
+ require 'plugins/pgyer'
10
12
 
11
13
  require 'commands/build'
12
14
  require 'commands/distribute'
@@ -0,0 +1,129 @@
1
+ require 'json'
2
+ require 'openssl'
3
+ require 'faraday'
4
+ require 'faraday_middleware'
5
+
6
+ module Shenzhen::Plugins
7
+ module Fir
8
+ class Client
9
+ HOSTNAME = 'fir.im'
10
+ VERSION = 'v2'
11
+
12
+ def initialize(user_token)
13
+ @user_token = user_token
14
+
15
+ @connection = Faraday.new(:url => "http://#{HOSTNAME}") do |builder|
16
+ builder.request :url_encoded
17
+ builder.response :json
18
+ builder.use FaradayMiddleware::FollowRedirects
19
+ builder.adapter :net_http
20
+ end
21
+ end
22
+
23
+ def get_app_info(app_id)
24
+ options = {
25
+ :type => 'ios',
26
+ :token => @user_token,
27
+ }
28
+
29
+ @connection.get("/api/#{VERSION}/app/info/#{app_id}", options) do |env|
30
+ yield env[:status], env[:body] if block_given?
31
+ end
32
+ rescue Faraday::Error::TimeoutError
33
+ say_error "Timed out while geting app info." and abort
34
+ end
35
+
36
+ def update_app_info(app_id, options)
37
+ @connection.put("/api/#{VERSION}/app/#{app_id}?token=#{@user_token}", options) do |env|
38
+ yield env[:status], env[:body] if block_given?
39
+ end
40
+ rescue Faraday::Error::TimeoutError
41
+ say_error "Timed out while geting app info." and abort
42
+ end
43
+
44
+ def upload_build(ipa, options)
45
+ connection = Faraday.new(:url => options['url'], :request => { :timeout => 360 }) do |builder|
46
+ builder.request :multipart
47
+ builder.response :json
48
+ builder.use FaradayMiddleware::FollowRedirects
49
+ builder.adapter :net_http
50
+ end
51
+
52
+ options = {
53
+ :key => options['type'],
54
+ :token => options['token'],
55
+ :file => Faraday::UploadIO.new(ipa, 'application/octet-stream')
56
+ }
57
+
58
+ connection.post('/', options).on_complete do |env|
59
+ yield env[:status], env[:body] if block_given?
60
+ end
61
+ rescue Errno::EPIPE
62
+ say_error "Upload failed. Check internet connection is ok." and abort
63
+ rescue Faraday::Error::TimeoutError
64
+ say_error "Timed out while uploading build. Check https://fir.im// to see if the upload was completed." and abort
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ command :'distribute:fir' do |c|
71
+ c.syntax = "ipa distribute:fir [options]"
72
+ c.summary = "Distribute an .ipa file over fir.im"
73
+ c.description = ""
74
+ c.option '-f', '--file FILE', ".ipa file for the build"
75
+ c.option '-u', '--user_token TOKEN', "User Token. Available at http://fir.im/user/info"
76
+ c.option '-a', '--app_id APPID', "App Id (iOS Bundle identifier)"
77
+ c.option '-n', '--notes NOTES', "Release notes for the build"
78
+
79
+ c.action do |args, options|
80
+ determine_file! unless @file = options.file
81
+ say_error "Missing or unspecified .ipa file" and abort unless @file and File.exist?(@file)
82
+
83
+ determine_fir_user_token! unless @user_token = options.user_token || ENV['FIR_USER_TOKEN']
84
+ say_error "Missing User Token" and abort unless @user_token
85
+
86
+ determine_fir_app_id! unless @app_id = options.app_id || ENV['FIR_APP_ID']
87
+ say_error "Missing App Id" and abort unless @app_id
88
+
89
+ determine_notes! unless @notes = options.notes
90
+ say_error "Missing release notes" and abort unless @notes
91
+
92
+ client = Shenzhen::Plugins::Fir::Client.new(@user_token)
93
+ app_response = client.get_app_info(@app_id)
94
+ if app_response.status == 200
95
+ upload_response = client.upload_build(@file, app_response.body['bundle']['pkg'])
96
+
97
+ if upload_response.status == 200
98
+ oid = upload_response.body['appOid']
99
+ today = Time.now.strftime('%Y-%m-%d %H:%M:%S')
100
+ @notes ||= "Upload on #{today}"
101
+
102
+ app_response = client.update_app_info(oid, {
103
+ :changelog => @notes,
104
+ })
105
+
106
+ if app_response.status == 200
107
+ app_short_uri = app_response.body['short']
108
+ say_ok "Build successfully uploaded to Fir, visit url: http://fir.im/#{app_short_uri}"
109
+ else
110
+ say_error "Error updating build information: #{app_response.body[:error]}" and abort
111
+ end
112
+ else
113
+ say_error "Error uploading to Fir: #{upload_response.body[:error]}" and abort
114
+ end
115
+ else
116
+ say_error "Error getting app information: #{response.body[:error]}"
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def determine_fir_user_token!
123
+ @user_token ||= ask "User Token:"
124
+ end
125
+
126
+ def determine_fir_app_id!
127
+ @app_id ||= ask "App Id:"
128
+ end
129
+ end
@@ -0,0 +1,135 @@
1
+ require 'json'
2
+ require 'openssl'
3
+ require 'faraday'
4
+ require 'faraday_middleware'
5
+
6
+ module Shenzhen::Plugins
7
+ module Pgyer
8
+ class Client
9
+ HOSTNAME = 'www.pgyer.com'
10
+
11
+ def initialize(user_key, api_key)
12
+ @user_key, @api_key = user_key, api_key
13
+ @connection = Faraday.new(:url => "http://#{HOSTNAME}", :request => { :timeout => 120 }) do |builder|
14
+ builder.request :multipart
15
+ builder.request :json
16
+ builder.response :json, :content_type => /\bjson$/
17
+ builder.use FaradayMiddleware::FollowRedirects
18
+ builder.adapter :net_http
19
+ end
20
+ end
21
+
22
+ def upload_build(ipa, options)
23
+ options.update({
24
+ :uKey => @user_key,
25
+ :_api_key => @api_key,
26
+ :file => Faraday::UploadIO.new(ipa, 'application/octet-stream')
27
+ })
28
+
29
+ @connection.post("/apiv1/app/upload", options).on_complete do |env|
30
+ yield env[:status], env[:body] if block_given?
31
+ end
32
+
33
+ rescue Faraday::Error::TimeoutError
34
+ say_error "Timed out while uploading build. Check http://www.pgyer.com/my to see if the upload was completed." and abort
35
+ end
36
+
37
+ def update_app_info(options)
38
+ connection = Faraday.new(:url => "http://#{HOSTNAME}", :request => { :timeout => 120 }) do |builder|
39
+ builder.request :url_encoded
40
+ builder.request :json
41
+ builder.response :logger
42
+ builder.response :json, :content_type => /\bjson$/
43
+ builder.use FaradayMiddleware::FollowRedirects
44
+ builder.adapter :net_http
45
+ end
46
+
47
+ options.update({
48
+ :uKey => @user_key,
49
+ :_api_key => @api_key,
50
+ })
51
+
52
+ connection.post("/apiv1/app/update", options) do |env|
53
+ yield env[:status], env[:body] if block_given?
54
+ end
55
+
56
+ rescue Faraday::Error::TimeoutError
57
+ say_error "Timed out while uploading build. Check http://www.pgyer.com/my to see if the upload was completed." and abort
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ command :'distribute:pgyer' do |c|
64
+ c.syntax = "ipa distribute:pgyer [options]"
65
+ c.summary = "Distribute an .ipa file over Pgyer"
66
+ c.description = ""
67
+ c.option '-f', '--file FILE', ".ipa file for the build"
68
+ c.option '-a', '--api_key KEY', "API KEY. Available at http://www.pgyer.com/doc/api#uploadApp"
69
+ c.option '-u', '--user_key KEY', "USER KEY. Available at http://www.pgyer.com/doc/api#uploadApp/"
70
+ c.option '--range RANGE', "Publish range. e.g. 1 (default), 2, 3"
71
+ c.option '--[no-]public', "Allow build app on public to download. it is not public default."
72
+ c.option '--password PASSWORD', "Set password to allow visit app web page."
73
+
74
+ c.action do |args, options|
75
+ determine_file! unless @file = options.file
76
+ say_error "Missing or unspecified .ipa file" and abort unless @file and File.exist?(@file)
77
+
78
+ determine_testflight_user_key! unless @user_key = options.user_key || ENV['PGYER_USER_KEY']
79
+ say_error "Missing User Key" and abort unless @user_key
80
+
81
+ determine_testflight_api_key! unless @api_key = options.api_key || ENV['PGYER_API_KEY']
82
+ say_error "Missing API Key" and abort unless @api_key
83
+
84
+ determine_publish_range! unless @publish_range = options.range
85
+ say_error "Missing Publish Range" and abort unless @publish_range
86
+
87
+ determine_is_public! unless @is_public = !!options.public
88
+ @is_public = @is_public ? 1 : 2
89
+
90
+ parameters = {}
91
+ parameters[:publishRange] = @publish_range
92
+ parameters[:isPublishToPublic] = @is_public
93
+ parameters[:password] = options.password.chomp if options.password
94
+
95
+ client = Shenzhen::Plugins::Pgyer::Client.new(@user_key, @api_key)
96
+ response = client.upload_build(@file, parameters)
97
+ case response.status
98
+ when 200...300
99
+ app_id = response.body['data']['appKey']
100
+ app_short_uri = response.body['data']['appShortcutUrl']
101
+
102
+ app_response = client.update_app_info({
103
+ :aKey => app_id,
104
+ :appUpdateDescription => @notes
105
+ })
106
+
107
+ if app_response.status == 200
108
+ say_ok "Build successfully uploaded to Pgyer, visit url: http://www.pgyer.com/#{app_short_uri}"
109
+ else
110
+ say_error "Error update build information: #{response.body}" and abort
111
+ end
112
+ else
113
+ say_error "Error uploading to Pgyer: #{response.body}" and abort
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ def determine_pgyer_api_key!
120
+ @api_key ||= ask "API Key:"
121
+ end
122
+
123
+ def determine_pgyer_user_key!
124
+ @user_key ||= ask "User Key:"
125
+ end
126
+
127
+ def determine_publish_range!
128
+ @publish_range ||= "1"
129
+ end
130
+
131
+ def determine_is_public!
132
+ @is_public ||= false
133
+ end
134
+
135
+ end
@@ -1,3 +1,3 @@
1
1
  module Shenzhen
2
- VERSION = '0.9.0'
2
+ VERSION = '0.10.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shenzhen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattt Thompson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-17 00:00:00.000000000 Z
11
+ date: 2014-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commander
@@ -209,9 +209,11 @@ files:
209
209
  - ./lib/shenzhen/plistbuddy.rb
210
210
  - ./lib/shenzhen/plugins/crashlytics.rb
211
211
  - ./lib/shenzhen/plugins/deploygate.rb
212
+ - ./lib/shenzhen/plugins/fir.rb
212
213
  - ./lib/shenzhen/plugins/ftp.rb
213
214
  - ./lib/shenzhen/plugins/hockeyapp.rb
214
215
  - ./lib/shenzhen/plugins/itunesconnect.rb
216
+ - ./lib/shenzhen/plugins/pgyer.rb
215
217
  - ./lib/shenzhen/plugins/s3.rb
216
218
  - ./lib/shenzhen/plugins/testflight.rb
217
219
  - ./lib/shenzhen/version.rb
@@ -220,9 +222,6 @@ files:
220
222
  - ./LICENSE
221
223
  - ./Rakefile
222
224
  - ./README.md
223
- - ./shenzhen-0.8.0.gem
224
- - ./shenzhen-0.8.1.gem
225
- - ./shenzhen-0.8.2.gem
226
225
  - ./shenzhen.gemspec
227
226
  - bin/ipa
228
227
  homepage: http://nomad-cli.com
data/shenzhen-0.8.0.gem DELETED
Binary file
data/shenzhen-0.8.1.gem DELETED
Binary file
data/shenzhen-0.8.2.gem DELETED
Binary file