cupertino 0.0.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,9 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cupertino (0.0.2)
4
+ cupertino (0.2.0)
5
5
  commander (~> 4.1.2)
6
6
  mechanize (~> 2.5.1)
7
+ term-ansicolor (~> 1.0.7)
8
+ terminal-table (~> 1.4.5)
7
9
 
8
10
  GEM
9
11
  remote: http://rubygems.org/
@@ -12,7 +14,7 @@ GEM
12
14
  highline (~> 1.6.11)
13
15
  domain_name (0.5.3)
14
16
  unf (~> 0.0.3)
15
- highline (1.6.12)
17
+ highline (1.6.13)
16
18
  mechanize (2.5.1)
17
19
  domain_name (~> 0.5, >= 0.5.1)
18
20
  mime-types (~> 1.17, >= 1.17.2)
@@ -28,6 +30,8 @@ GEM
28
30
  ntlm-http (0.1.1)
29
31
  rake (0.9.2.2)
30
32
  rspec (0.6.4)
33
+ term-ansicolor (1.0.7)
34
+ terminal-table (1.4.5)
31
35
  unf (0.0.5)
32
36
  unf_ext
33
37
  unf_ext (0.0.5)
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Mattt Thompson (http://mattt.me/)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,43 +1,103 @@
1
1
  # Cupertino
2
- **Mechanize the Apple Dev Center**
2
+ **CLI for the Apple Dev Center**
3
3
 
4
4
  Automate administrative tasks that you would normally have to do through the Apple Dev Center websites. Life's too short to manage device identifiers by hand!
5
5
 
6
6
  This project is starting with the iOS Provisioning Portal, and may later expand to include iTunes Connect and/or Mac Developer Certificate Utility.
7
7
 
8
+ ## Installation
9
+
10
+ ```sh
11
+ $ gem install cupertino
12
+ ```
13
+
8
14
  ## Usage
9
15
 
16
+ ### Devices
17
+
10
18
  ```sh
11
19
  $ ios devices:list
12
20
 
13
- Mattt Thompson's iPad abcdef0123456789...
14
- Mattt Thompson's iPhone abcdef0123456789...
21
+ +---------------------------+------------------------------------------+
22
+ | Device Name | Device Identifier |
23
+ +---------------------------+------------------------------------------+
24
+ | Johnny Appleseed iPad | 0123456789012345678901234567890123abcdef |
25
+ | Johnny Appleseed iPhone | abcdef0123456789012345678901234567890123 |
26
+ +---------------------------+------------------------------------------+
15
27
 
16
28
  $ ios devices:add "iPad 1"=abc123
17
29
  $ ios devices:add "iPad 2"=def456 "iPad 3"=ghi789 ...
30
+ ```
31
+
32
+ ### Provisioning Profiles
33
+
34
+ ```sh
35
+ $ ios profiles:list
36
+
37
+ +----------------------------------+--------------+---------+
38
+ | Profile | App ID | Status |
39
+ +----------------------------------+--------------+---------+
40
+ | iOS Team Provisioning Profile: * | ABCDEFG123.* | Valid |
41
+ +----------------------------------+--------------+---------+
42
+ ```
43
+
44
+ ### App IDs
18
45
 
19
- $ ios devices:remove "iPad 1"
46
+ ```sh
47
+ $ ios app_ids:list
48
+
49
+ +-----------------------------+------------------------+-------------------+-------------------+
50
+ | Bundle Seed ID | Description | Development | Distribution |
51
+ +-----------------------------+------------------------+-------------------+-------------------+
52
+ | 123ABCDEFG.com.mattt.bundle | App Bundle Description | Passes | Passes |
53
+ | | | Data Protection | Data Protection |
54
+ | | | iCloud | iCloud |
55
+ | | | In-App Purchase | In-App Purchase |
56
+ | | | Game Center | Game Center |
57
+ | | | Push Notification | Push Notification |
58
+ +-----------------------------+------------------------+-------------------+-------------------+
59
+ ```
60
+
61
+ ### Certificates
62
+
63
+ ```
64
+ $ ios certificates:list
65
+
66
+ +------------------+----------------------------------+-----------------+--------+
67
+ | Name | Provisioning Profiles | Expiration Date | Status |
68
+ +------------------+----------------------------------+-----------------+--------+
69
+ | Johnny Appleseed | iOS Team Provisioning Profile: * | Dec 23, 2012 | Issued |
70
+ +------------------+----------------------------------+-----------------+--------+
20
71
  ```
21
72
 
22
73
  ## Commands
23
74
 
75
+ _Crossed out commands are not yet implemented_
76
+
77
+ - `devices:add`
24
78
  - `devices:list`
79
+ - ~~`devices:remove`~~
25
80
 
26
- ### To Be Implemented
81
+ - `profiles:list`
82
+ - ~~`profiles:add`~~
83
+ - ~~`profiles:edit`~~
27
84
 
28
- #### Devices
85
+ - `certificates:list [development|distribution]`
86
+ - ~~`certificates:add [development|distribution]`~~
87
+ - ~~`certificates:download CERTIFICATE_NAME`~~
88
+ - ~~`certificates:revoke CERTIFICATE_NAME`~~
29
89
 
30
- - `devices:add`
31
- - `devices:remove`
90
+ - `app_ids:list`
91
+ - ~~`app_ids:new`~~
32
92
 
33
- #### Certificates
93
+ ## Contact
34
94
 
35
- - `certificates:list [-e development|distribution]`
36
- - `certificates:add [-e development|distribution]`
37
- - `certificates:download CERTIFICATE_NAME`
38
- - `certificates:revoke CERTIFICATE_NAME`
95
+ Mattt Thompson
39
96
 
40
- #### Application IDs
97
+ - http://github.com/mattt
98
+ - http://twitter.com/mattt
99
+ - m@mattt.me
41
100
 
42
- - `app_ids:list`
43
- - `app_ids:new`
101
+ ## License
102
+
103
+ Cupertino is available under the MIT license. See the LICENSE file for more info.
data/bin/ios CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'commander/import'
4
+ require 'terminal-table'
5
+ require 'term/ansicolor'
4
6
 
5
7
  $:.push File.expand_path("../../lib", __FILE__)
6
8
 
data/cupertino.gemspec CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |s|
16
16
  s.add_development_dependency "rake", "~> 0.9.2"
17
17
 
18
18
  s.add_dependency "commander", "~> 4.1.2"
19
+ s.add_dependency "terminal-table", "~> 1.4.5"
20
+ s.add_dependency "term-ansicolor", "~> 1.0.7"
19
21
  s.add_dependency "mechanize", "~> 2.5.1"
20
22
 
21
23
  s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
@@ -25,14 +25,38 @@ module Cupertino
25
25
  end
26
26
  end
27
27
 
28
+ def list_certificates(type = :development)
29
+ url = case type
30
+ when :development
31
+ "https://developer.apple.com/ios/manage/certificates/team/index.action"
32
+ when :distribution
33
+ "https://developer.apple.com/ios/manage/certificates/team/distribute.action"
34
+ else
35
+ raise ArgumentError, "Certificate type must be :development or :distribution"
36
+ end
37
+
38
+ get(url)
39
+
40
+ certificates = []
41
+ page.parser.xpath('//div[@class="nt_multi"]/table/tbody/tr').each do |row|
42
+ certificate = Certificate.new
43
+ certificate.name = row.at_xpath('td[@class="name"]//p/text()').to_s.strip rescue nil
44
+ certificate.provisioning_profiles = row.at_xpath('td[@class="profiles"]/text()').to_s.strip.split(/\n+/) rescue []
45
+ certificate.expiration_date = row.at_xpath('td[@class="date"]/text()').to_s.strip rescue nil
46
+ certificate.status = row.at_xpath('td[@class="status"]/text()').to_s.strip rescue nil
47
+ certificates << certificate
48
+ end
49
+ certificates
50
+ end
51
+
28
52
  def list_devices
29
53
  get("https://developer.apple.com/ios/manage/devices/index.action")
30
54
 
31
55
  devices = []
32
56
  page.parser.xpath('//fieldset[@id="fs-0"]/table/tbody/tr').each do |row|
33
57
  device = Device.new
34
- device.name = row.at_xpath('td[@class="name"]/span/text()')
35
- device.udid = row.at_xpath('td[@class="id"]/text()')
58
+ device.name = row.at_xpath('td[@class="name"]/span/text()').to_s.strip rescue nil
59
+ device.udid = row.at_xpath('td[@class="id"]/text()').to_s.strip rescue nil
36
60
  devices << device
37
61
  end
38
62
  devices
@@ -61,6 +85,50 @@ module Cupertino
61
85
  end
62
86
  end
63
87
 
88
+ def list_profiles(type = :development)
89
+ url = case type
90
+ when :development
91
+ "https://developer.apple.com/ios/manage/provisioningprofiles/index.action"
92
+ when :distribution
93
+ "https://developer.apple.com/ios/manage/provisioningprofiles/viewDistributionProfiles.action"
94
+ else
95
+ raise ArgumentError, "Provisioning profile type must be :development or :distribution"
96
+ end
97
+
98
+ get(url)
99
+
100
+ profiles = []
101
+ page.parser.xpath('//fieldset[@id="fs-0"]/table/tbody/tr').each do |row|
102
+ profile = ProvisioningProfile.new
103
+ profile.name = row.at_xpath('td[@class="profile"]/text()').to_s.strip rescue nil
104
+ profile.app_id = row.at_xpath('td[@class="appid"]/text()').to_s.strip rescue nil
105
+ profile.status = row.at_xpath('td[@class="statusXcode"]/text()').to_s.strip rescue nil
106
+ profiles << profile
107
+ end
108
+ profiles
109
+ end
110
+
111
+ def list_app_ids
112
+ get ("https://developer.apple.com/ios/manage/bundles/index.action")
113
+
114
+ app_ids = []
115
+ page.parser.xpath('//div[@class="nt_multi"]/table/tbody/tr').each do |row|
116
+ app_id = AppID.new
117
+ app_id.bundle_seed_id = row.at_xpath('td[@class="name"]/strong/text()').to_s.strip rescue nil
118
+ app_id.description = row.at_xpath('td[@class="name"]/text()').to_s.strip rescue nil
119
+
120
+ keys = row.xpath('td[@class="name"]/p/text()').collect(&:to_s).collect(&:strip)
121
+ app_id.development_properties, app_id.distribution_properties = row.xpath('td')[1..2].collect do |td|
122
+ values = td.xpath('p//text()').collect(&:to_s).collect(&:strip).reject{|text| text.empty?}
123
+ keys.zip(values)
124
+ keys.zip(values)
125
+ end
126
+
127
+ app_ids << app_id
128
+ end
129
+ app_ids
130
+ end
131
+
64
132
  private
65
133
 
66
134
  def login!
@@ -0,0 +1,38 @@
1
+ COLORS_BY_PROPERTY_VALUES = {
2
+ "Enabled" => :green,
3
+ "Configurable" => :yellow,
4
+ "Unavailable" => :underline
5
+ }
6
+
7
+ command :'app_ids:list' do |c|
8
+ c.syntax = 'ios app_ids:list'
9
+ c.summary = 'Lists the App IDs'
10
+ c.description = ''
11
+
12
+ c.action do |args, options|
13
+ app_ids = agent.list_app_ids
14
+
15
+ title = "Legend: #{COLORS_BY_PROPERTY_VALUES.collect{|k, v| k.send(v)}.join(', ')}"
16
+ table = Terminal::Table.new :title => title do |t|
17
+ t << ["Bundle Seed ID", "Description", "Development", "Distribution"]
18
+ app_ids.each do |app_id|
19
+ t << :separator
20
+
21
+ row = [app_id.bundle_seed_id, app_id.description]
22
+ [app_id.development_properties, app_id.distribution_properties].each do |properties|
23
+ values = []
24
+ properties.each do |key, value|
25
+ color = COLORS_BY_PROPERTY_VALUES[value] || :reset
26
+ values << key.sub(/\:$/, "").send(color)
27
+ end
28
+ row << values.join("\n")
29
+ end
30
+ t << row
31
+ end
32
+ end
33
+
34
+ puts table
35
+ end
36
+ end
37
+
38
+ alias_command :app_ids, :'app_ids:list'
@@ -0,0 +1,31 @@
1
+ command :'certificates:list' do |c|
2
+ c.syntax = 'ios certificates:list [development|distribution]'
3
+ c.summary = 'Lists the Certificates'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ type = args.first.downcase.to_sym rescue nil
8
+ certificates = agent.list_certificates(type ||= :development)
9
+
10
+ say_warning "No #{type} certificates found." and abort if certificates.empty?
11
+
12
+ table = Terminal::Table.new do |t|
13
+ t << ["Name", "Provisioning Profiles", "Expiration Date", "Status"]
14
+ t.add_separator
15
+ certificates.each do |certificate|
16
+ status = case certificate.status
17
+ when "Issued"
18
+ certificate.status.green
19
+ else
20
+ certificate.status.red
21
+ end
22
+
23
+ t << [certificate.name, certificate.provisioning_profiles.join("\n"), certificate.expiration_date, status]
24
+ end
25
+ end
26
+
27
+ puts table
28
+ end
29
+ end
30
+
31
+ alias_command :certificates, :'certificates:list'
@@ -6,10 +6,15 @@ command :'devices:list' do |c|
6
6
  c.action do |args, options|
7
7
  devices = agent.list_devices
8
8
 
9
- say_ok "Devices:"
10
- devices.each do |device|
11
- log device.name, device.udid
9
+ table = Terminal::Table.new do |t|
10
+ t << ["Device Name", "Device Identifier"]
11
+ t.add_separator
12
+ devices.each do |device|
13
+ t << [device.name, device.udid]
14
+ end
12
15
  end
16
+
17
+ puts table
13
18
  end
14
19
  end
15
20
 
@@ -0,0 +1,31 @@
1
+ command :'profiles:list' do |c|
2
+ c.syntax = 'ios profiles:list [development|distribution]'
3
+ c.summary = 'Lists the Provisioning Profiles'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ type = args.first.downcase.to_sym rescue nil
8
+ profiles = agent.list_profiles(type ||= :development)
9
+
10
+ say_warning "No #{type} provisioning profiles found." and abort if profiles.empty?
11
+
12
+ table = Terminal::Table.new do |t|
13
+ t << ["Profile", "App ID", "Status"]
14
+ t.add_separator
15
+ profiles.each do |profile|
16
+ status = case profile.status
17
+ when "Invalid"
18
+ profile.status.red
19
+ else
20
+ profile.status.green
21
+ end
22
+
23
+ t << [profile.name, profile.app_id, status]
24
+ end
25
+ end
26
+
27
+ puts table
28
+ end
29
+ end
30
+
31
+ alias_command :profiles, :'profiles:list'
@@ -3,4 +3,7 @@ include Cupertino::ProvisioningPortal::Helpers
3
3
 
4
4
  $:.push File.expand_path('../', __FILE__)
5
5
 
6
+ require 'commands/certificates'
6
7
  require 'commands/devices'
8
+ require 'commands/profiles'
9
+ require 'commands/app_ids'
@@ -3,6 +3,10 @@ module Commander::UI
3
3
  alias :pw :password
4
4
  end
5
5
 
6
+ class String
7
+ include Term::ANSIColor
8
+ end
9
+
6
10
  module Cupertino
7
11
  module ProvisioningPortal
8
12
  module Helpers
data/lib/cupertino.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cupertino
2
- VERSION = '0.0.2'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cupertino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
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-07-05 00:00:00.000000000Z
12
+ date: 2012-07-07 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70106699402980 !ruby/object:Gem::Requirement
16
+ requirement: &70303149797320 !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: *70106699402980
24
+ version_requirements: *70303149797320
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70106699401440 !ruby/object:Gem::Requirement
27
+ requirement: &70303149796820 !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: *70106699401440
35
+ version_requirements: *70303149796820
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: commander
38
- requirement: &70106699399220 !ruby/object:Gem::Requirement
38
+ requirement: &70303149796360 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,32 @@ dependencies:
43
43
  version: 4.1.2
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70106699399220
46
+ version_requirements: *70303149796360
47
+ - !ruby/object:Gem::Dependency
48
+ name: terminal-table
49
+ requirement: &70303149795880 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.5
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70303149795880
58
+ - !ruby/object:Gem::Dependency
59
+ name: term-ansicolor
60
+ requirement: &70303149795360 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.0.7
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70303149795360
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: mechanize
49
- requirement: &70106699395800 !ruby/object:Gem::Requirement
71
+ requirement: &70303149794820 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ~>
@@ -54,7 +76,7 @@ dependencies:
54
76
  version: 2.5.1
55
77
  type: :runtime
56
78
  prerelease: false
57
- version_requirements: *70106699395800
79
+ version_requirements: *70303149794820
58
80
  description: Mechanize the Apple Developer Center
59
81
  email: m@mattt.me
60
82
  executables:
@@ -66,11 +88,15 @@ files:
66
88
  - ./Gemfile
67
89
  - ./Gemfile.lock
68
90
  - ./lib/cupertino/provisioning_portal/agent.rb
91
+ - ./lib/cupertino/provisioning_portal/commands/app_ids.rb
92
+ - ./lib/cupertino/provisioning_portal/commands/certificates.rb
69
93
  - ./lib/cupertino/provisioning_portal/commands/devices.rb
94
+ - ./lib/cupertino/provisioning_portal/commands/profiles.rb
70
95
  - ./lib/cupertino/provisioning_portal/commands.rb
71
96
  - ./lib/cupertino/provisioning_portal/helpers.rb
72
97
  - ./lib/cupertino/provisioning_portal.rb
73
98
  - ./lib/cupertino.rb
99
+ - ./LICENSE
74
100
  - ./Rakefile
75
101
  - ./README.md
76
102
  - bin/ios
@@ -88,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
114
  version: '0'
89
115
  segments:
90
116
  - 0
91
- hash: 2027864098063448986
117
+ hash: 2813805427560114884
92
118
  required_rubygems_version: !ruby/object:Gem::Requirement
93
119
  none: false
94
120
  requirements:
@@ -97,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
123
  version: '0'
98
124
  segments:
99
125
  - 0
100
- hash: 2027864098063448986
126
+ hash: 2813805427560114884
101
127
  requirements: []
102
128
  rubyforge_project:
103
129
  rubygems_version: 1.8.15