shenzhen 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +3 -4
- data/lib/shenzhen.rb +1 -1
- data/lib/shenzhen/commands.rb +1 -0
- data/lib/shenzhen/commands/build.rb +2 -2
- data/lib/shenzhen/plugins/hockeyapp.rb +126 -0
- data/shenzhen-0.1.0.gem +0 -0
- metadata +18 -16
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# Shenzhen
|
2
2
|
**CLI for Building & Distributing iOS Apps (.ipa Files)**
|
3
3
|
|
4
|
-
Create `.ipa` files and then distribute them with [TestFlight](https://testflightapp.com/), all from the command line!
|
4
|
+
Create `.ipa` files and then distribute them with [TestFlight](https://testflightapp.com/) or [HockeyApp](http://www.hockeyapp.net), all from the command line!
|
5
5
|
|
6
6
|
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.
|
7
7
|
|
8
|
-
This project is starting with TestFlight, but will move to support other popular distribution methods, such as S3, CloudApp, and / or Dropbox. Suggestions (and pull requests) are very welcome.
|
9
|
-
|
10
8
|
> `shenzhen` is named for [深圳](http://en.wikipedia.org/wiki/Shenzhen), the Chinese city famous for its role as the center of manufacturing for a majority of consumer electronics, including iPhones and iPads. Its [sister project](https://github.com/mattt/cupertino)'s namesake, [Cupertino, CA](http://en.wikipedia.org/wiki/Cupertino,_California), is home to Apple, Inc.'s world headquarters.
|
11
9
|
|
12
10
|
## Installation
|
@@ -26,7 +24,8 @@ $ ipa
|
|
26
24
|
|
27
25
|
Commands:
|
28
26
|
build Create a new .ipa file for your app
|
29
|
-
distribute:testflight Distribute an .ipa file over
|
27
|
+
distribute:testflight Distribute an .ipa file over TestFlight
|
28
|
+
distribute:hockeyapp Distribute an .ipa file over HockeyApp
|
30
29
|
help Display global or [command] help documentation.
|
31
30
|
|
32
31
|
Aliases:
|
data/lib/shenzhen.rb
CHANGED
data/lib/shenzhen/commands.rb
CHANGED
@@ -48,13 +48,13 @@ command :build do |c|
|
|
48
48
|
ENV['CC'] = nil # Fix for RVM
|
49
49
|
abort unless system %{xcodebuild #{flags.join(' ')} clean build 1> /dev/null}
|
50
50
|
|
51
|
-
log "xcrun", "PackageApplication"
|
52
|
-
|
53
51
|
@xcodebuild_settings = Shenzhen::XcodeBuild.settings(flags)
|
54
52
|
@app_path = File.join(@xcodebuild_settings['BUILT_PRODUCTS_DIR'], @xcodebuild_settings['PRODUCT_NAME']) + ".app"
|
55
53
|
@dsym_path = @app_path + ".dSYM"
|
56
54
|
@dsym_filename = "#{@xcodebuild_settings['PRODUCT_NAME']}.app.dSYM"
|
57
55
|
@ipa_path = File.join(Dir.pwd, @xcodebuild_settings['PRODUCT_NAME']) + ".ipa"
|
56
|
+
|
57
|
+
log "xcrun", "PackageApplication"
|
58
58
|
abort unless system %{xcrun -sdk iphoneos PackageApplication -v "#{@app_path}" -o "#{@ipa_path}" --embed "#{@dsym_path}" 1> /dev/null}
|
59
59
|
|
60
60
|
log "zip", @dsym_filename
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
|
5
|
+
module Shenzhen::Plugins
|
6
|
+
module HockeyApp
|
7
|
+
class Client
|
8
|
+
HOSTNAME = 'rink.hockeyapp.net'
|
9
|
+
|
10
|
+
def initialize(api_token)
|
11
|
+
@api_token = api_token
|
12
|
+
@connection = Faraday.new(:url => "https://#{HOSTNAME}") do |builder|
|
13
|
+
builder.request :multipart
|
14
|
+
builder.request :url_encoded
|
15
|
+
builder.response :json, :content_type => /\bjson$/
|
16
|
+
builder.use FaradayMiddleware::FollowRedirects
|
17
|
+
builder.adapter :net_http
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def upload_build(ipa, options)
|
22
|
+
options[:ipa] = Faraday::UploadIO.new(ipa, 'application/octet-stream')
|
23
|
+
|
24
|
+
if dsym_filename = options.delete(:dsym_filename)
|
25
|
+
options[:dsym] = Faraday::UploadIO.new(dsym_filename, 'application/octet-stream')
|
26
|
+
end
|
27
|
+
|
28
|
+
@connection.post do |req|
|
29
|
+
if options[:public_identifer].nil?
|
30
|
+
req.url("/api/2/apps/upload")
|
31
|
+
else
|
32
|
+
req.url("/api/2/apps/#{options.delete(:public_identifer)}/app_versions")
|
33
|
+
end
|
34
|
+
req.headers['X-HockeyAppToken'] = @api_token
|
35
|
+
req.body = options
|
36
|
+
end.on_complete do |env|
|
37
|
+
yield env[:status], env[:body] if block_given?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
command :'distribute:hockeyapp' do |c|
|
45
|
+
c.syntax = "ipa distribute:hockeyapp [options]"
|
46
|
+
c.summary = "Distribute an .ipa file over HockeyApp"
|
47
|
+
c.description = ""
|
48
|
+
c.option '-f', '--file FILE', ".ipa file for the build"
|
49
|
+
c.option '-d', '--dsym FILE', "zipped .dsym package for the build"
|
50
|
+
c.option '-t', '--token TOKEN', "API Token. Available at https://rink.hockeyapp.net/manage/auth_tokens"
|
51
|
+
c.option '-i', '--identifier PUBLIC_IDENTIFIER', "Public identifier of the app you are targeting, if not specified HockeyApp will use the bundle identifier to choose the right"
|
52
|
+
c.option '-m', '--notes NOTES', "Release notes for the build (Default: Textile)"
|
53
|
+
c.option '--markdown', 'Notes are written with Markdown'
|
54
|
+
c.option '--tags TAGS', "Comma separated list of tags which will receive access to the build"
|
55
|
+
c.option '--notify', "Notify permitted teammates to install the build"
|
56
|
+
c.option '--downloadOff', "Upload but don't allow download of this version just yet"
|
57
|
+
|
58
|
+
c.option '-q', '--quiet', "Silence warning and success messages"
|
59
|
+
|
60
|
+
|
61
|
+
c.action do |args, options|
|
62
|
+
determine_file! unless @file = options.file
|
63
|
+
say_error "Missing or unspecified .ipa file" and abort unless @file and File.exist?(@file)
|
64
|
+
|
65
|
+
determine_dsym! unless @dsym = options.dsym
|
66
|
+
say_error "Specified dSYM.zip file doesn't exist" if @dsym and !File.exist?(@dsym)
|
67
|
+
|
68
|
+
determine_api_token! unless @api_token = options.token
|
69
|
+
say_error "Missing API Token" and abort unless @api_token
|
70
|
+
|
71
|
+
determine_notes! unless @notes = options.notes
|
72
|
+
say_error "Missing release notes" and abort unless @notes
|
73
|
+
|
74
|
+
parameters = {}
|
75
|
+
parameters[:public_identifer] = options.identifier if options.identifier
|
76
|
+
parameters[:notes] = @notes
|
77
|
+
parameters[:notes_type] = options.markdown ? "1" : "0"
|
78
|
+
parameters[:notify] = "1" if options.notify && !options.downloadOff
|
79
|
+
parameters[:status] = options.downloadOff ? "1" : "2"
|
80
|
+
parameters[:tags] = options.tags if options.tags
|
81
|
+
parameters[:dsym_filename] = @dsym if @dsym
|
82
|
+
|
83
|
+
|
84
|
+
client = Shenzhen::Plugins::HockeyApp::Client.new(@api_token)
|
85
|
+
response = client.upload_build(@file, parameters)
|
86
|
+
case response.status
|
87
|
+
when 200...300
|
88
|
+
say_ok "Build successfully uploaded to HockeyApp"
|
89
|
+
else
|
90
|
+
say_error "Error uploading to HockeyApp: #{response.body}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def determine_api_token!
|
97
|
+
@api_token ||= ask "API Token:"
|
98
|
+
end
|
99
|
+
|
100
|
+
def determine_file!
|
101
|
+
files = Dir['*.ipa']
|
102
|
+
@file ||= case files.length
|
103
|
+
when 0 then nil
|
104
|
+
when 1 then files.first
|
105
|
+
else
|
106
|
+
@file = choose "Select an .ipa File:", *files
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def determine_dsym!
|
111
|
+
dsym_files = Dir['*.dSYM.zip']
|
112
|
+
@dsym ||= case dsym_files.length
|
113
|
+
when 0 then nil
|
114
|
+
when 1 then dsym_files.first
|
115
|
+
else
|
116
|
+
@dsym = choose "Select a .dSYM.zip file:", *dsym_files
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def determine_notes!
|
121
|
+
placeholder = %{What's new in this release: }
|
122
|
+
|
123
|
+
@notes = ask_editor placeholder
|
124
|
+
@notes = nil if @notes == placeholder
|
125
|
+
end
|
126
|
+
end
|
data/shenzhen-0.1.0.gem
ADDED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shenzhen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-12 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70170608319000 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.6.1
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70170608319000
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &70170608318420 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.9.2
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70170608318420
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: commander
|
38
|
-
requirement: &
|
38
|
+
requirement: &70170608317720 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 4.1.2
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70170608317720
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: json
|
49
|
-
requirement: &
|
49
|
+
requirement: &70170608317140 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.7.3
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70170608317140
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: faraday
|
60
|
-
requirement: &
|
60
|
+
requirement: &70170608316680 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 0.8.0
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70170608316680
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: faraday_middleware
|
71
|
-
requirement: &
|
71
|
+
requirement: &70170608316200 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: 0.8.7
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70170608316200
|
80
80
|
description: CLI for Building & Distributing iOS Apps (.ipa Files)
|
81
81
|
email: m@mattt.me
|
82
82
|
executables:
|
@@ -90,12 +90,14 @@ files:
|
|
90
90
|
- ./lib/shenzhen/commands/build.rb
|
91
91
|
- ./lib/shenzhen/commands/distribute.rb
|
92
92
|
- ./lib/shenzhen/commands.rb
|
93
|
+
- ./lib/shenzhen/plugins/hockeyapp.rb
|
93
94
|
- ./lib/shenzhen/plugins/testflight.rb
|
94
95
|
- ./lib/shenzhen/xcodebuild.rb
|
95
96
|
- ./lib/shenzhen.rb
|
96
97
|
- ./LICENSE
|
97
98
|
- ./Rakefile
|
98
99
|
- ./README.md
|
100
|
+
- ./shenzhen-0.1.0.gem
|
99
101
|
- ./shenzhen.gemspec
|
100
102
|
- bin/ipa
|
101
103
|
homepage: http://github.com/mattt/shenzhen
|
@@ -112,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
112
114
|
version: '0'
|
113
115
|
segments:
|
114
116
|
- 0
|
115
|
-
hash:
|
117
|
+
hash: 4537962558176197982
|
116
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
119
|
none: false
|
118
120
|
requirements:
|
@@ -121,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
123
|
version: '0'
|
122
124
|
segments:
|
123
125
|
- 0
|
124
|
-
hash:
|
126
|
+
hash: 4537962558176197982
|
125
127
|
requirements: []
|
126
128
|
rubyforge_project:
|
127
129
|
rubygems_version: 1.8.15
|