cupertino 0.0.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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