shenzhen 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shenzhen (0.1.0)
4
+ shenzhen (0.2.0)
5
5
  commander (~> 4.1.2)
6
6
  faraday (~> 0.8.0)
7
7
  faraday_middleware (~> 0.8.7)
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 testflight
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:
@@ -1,5 +1,5 @@
1
1
  module Shenzhen
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
4
4
 
5
5
  require 'shenzhen/agvtool'
@@ -1,6 +1,7 @@
1
1
  $:.push File.expand_path('../', __FILE__)
2
2
 
3
3
  require 'plugins/testflight'
4
+ require 'plugins/hockeyapp'
4
5
 
5
6
  require 'commands/build'
6
7
  require 'commands/distribute'
@@ -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
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.1.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-09 00:00:00.000000000Z
12
+ date: 2012-10-12 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70357169989920 !ruby/object:Gem::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: *70357169989920
24
+ version_requirements: *70170608319000
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70357169987940 !ruby/object:Gem::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: *70357169987940
35
+ version_requirements: *70170608318420
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: commander
38
- requirement: &70357169985980 !ruby/object:Gem::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: *70357169985980
46
+ version_requirements: *70170608317720
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: json
49
- requirement: &70357169976100 !ruby/object:Gem::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: *70357169976100
57
+ version_requirements: *70170608317140
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: faraday
60
- requirement: &70357169973340 !ruby/object:Gem::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: *70357169973340
68
+ version_requirements: *70170608316680
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: faraday_middleware
71
- requirement: &70357169971200 !ruby/object:Gem::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: *70357169971200
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: -2320972868632584491
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: -2320972868632584491
126
+ hash: 4537962558176197982
125
127
  requirements: []
126
128
  rubyforge_project:
127
129
  rubygems_version: 1.8.15