infinite-loop 0.1.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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in infinite-loop.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Thomas Dohmke
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ # Infinite::Loop
2
+
3
+ ### CLI for HockeyApp
4
+
5
+ List apps and devices from HockeyApp. Highly inspired by the great [Cupertino](https://github.com/mattt/cupertino).
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ $ gem install infinite-loop
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Fetch or Create an API token
16
+
17
+ ```sh
18
+ $ hockey login
19
+ ```
20
+
21
+ This asks you for your email and password. It then checks if you have any existing read-only tokens and stores the first in ~/.netrc. If not, it creates one.
22
+
23
+ ### List of Apps
24
+
25
+ ```sh
26
+ $ hockey apps:list
27
+ ```
28
+
29
+ ### List of Devices
30
+
31
+ ```sh
32
+ $ hockey devices:list APP_ID
33
+ ```
34
+
35
+ If you only want devices which are not in your current provisioning profile, add "unprovisioned":
36
+
37
+ ```sh
38
+ $ hockey devices:list APP_ID unprovisioned
39
+ ```
40
+
41
+ ### Loop Over Devices and Add to Provisioning Portal
42
+
43
+ This works only if you have already set up cupertino:
44
+
45
+ ```sh
46
+ $ gem install cupertino
47
+ $ ios login
48
+ ```
49
+
50
+ Then you can show all device (or all unprovisioned devices, see above) and add them to the portal:
51
+
52
+ ```sh
53
+ $ hockey devices:loop APP_ID
54
+ ```
55
+
56
+ Finally edit your profile:
57
+
58
+ ```sh
59
+ $ ios profiles:manage:devices distribution
60
+ ```
61
+
62
+ ## TODO
63
+
64
+ - Download profiles from the Provisioning Portal
65
+ - Upload modified profiles to HockeyApp
66
+ - Token management
67
+ - Some error handling
68
+
69
+ ## Contact
70
+
71
+ Thomas Dohmke & HockeyApp
72
+
73
+ - http://twitter.com/ashtom
74
+ - http://twitter.com/hockeyapp
75
+ - support@hockeyapp.net
76
+
77
+ ## License
78
+
79
+ Infinite Loop is available under the MIT license. See the LICENSE file for more info.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander/import'
4
+ require 'terminal-table'
5
+ require 'term/ansicolor'
6
+ require 'netrc'
7
+
8
+ require 'infinite'
9
+
10
+ HighLine.track_eof = false # Fix for built-in Ruby
11
+
12
+ program :version, Infinite::VERSION
13
+ program :description, 'A command-line interface for HockeyApp'
14
+
15
+ program :help, 'Author', 'Thomas Dohmke <thomas@hockeyapp.net>'
16
+ program :help, 'Website', 'http://hockeyapp.net'
17
+ program :help_formatter, :compact
18
+
19
+ default_command :help
20
+
21
+ require 'infinite/loop'
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "infinite"
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Thomas Dohmke"]
7
+ gem.email = ["thomas@dohmke.de"]
8
+ gem.description = "A command-line interface for HockeyApp"
9
+ gem.summary = "Infinite Loop"
10
+ gem.homepage = ""
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = "infinite-loop"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Infinite::VERSION
18
+
19
+ gem.add_dependency "cupertino"
20
+ gem.add_dependency "rest-client"
21
+ gem.add_dependency "json"
22
+ end
@@ -0,0 +1,4 @@
1
+ module Infinite
2
+ VERSION = '0.1.0'
3
+ HOSTNAME = 'rink.hockeyapp.net'
4
+ end
@@ -0,0 +1,3 @@
1
+ require "infinite/loop/agent"
2
+ require "infinite/loop/helpers"
3
+ require "infinite/loop/commands"
@@ -0,0 +1,62 @@
1
+ require "json"
2
+ require "rest-client"
3
+
4
+ module Infinite
5
+ module Loop
6
+ class Agent
7
+ BASE_URL = "https://rink.hockeyapp.net/api/2/"
8
+
9
+ def initialize
10
+ netrc = Netrc.read
11
+ @token = netrc[Infinite::HOSTNAME].first unless netrc[Infinite::HOSTNAME].nil?
12
+ end
13
+
14
+ def list_apps(release_type_string = nil)
15
+ response = RestClient.get "#{BASE_URL}apps", { "X-HockeyAppToken" => @token }
16
+ apps = JSON.parse(response)["apps"]
17
+ apps.reject! { |app| app["release_type"] != release_type(release_type_string) } unless release_type_string.nil?
18
+ apps
19
+ end
20
+
21
+ def list_devices(app_id, unprovisioned = nil)
22
+ response = RestClient.get "#{BASE_URL}apps/#{app_id}/devices?unprovisioned=#{unprovisioned.to_s == "unprovisioned" ? 1 : 0}", {"X-HockeyAppToken" => @token }
23
+ devices = JSON.parse(response)["devices"]
24
+ devices
25
+ end
26
+
27
+ def list_tokens(user, pass)
28
+ response = RestClient::Request.new(:method => :get, :url => "#{BASE_URL}auth_tokens", :user => user, :password => pass).execute
29
+ tokens = JSON.parse(response.to_str)["tokens"]
30
+ tokens
31
+ end
32
+
33
+ def create_token(user, pass)
34
+ response = RestClient::Request.new(:method => :post, :url => "#{BASE_URL}auth_tokens", :user => user, :password => pass).execute
35
+ tokens = JSON.parse(response.to_str)["tokens"]
36
+ tokens
37
+ end
38
+
39
+ def release_type(string)
40
+ case string
41
+ when "beta"
42
+ 0
43
+ when "live"
44
+ 1
45
+ when "alpha"
46
+ 2
47
+ end
48
+ end
49
+
50
+ def release_type_string(value)
51
+ case value.to_i
52
+ when 0
53
+ "beta"
54
+ when 1
55
+ "live"
56
+ when 2
57
+ "alpha"
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,6 @@
1
+ include Infinite::Loop::Helpers
2
+
3
+ require 'Infinite/loop/commands/apps'
4
+ require 'Infinite/loop/commands/devices'
5
+ require 'Infinite/loop/commands/login'
6
+ require 'Infinite/loop/commands/logout'
@@ -0,0 +1,28 @@
1
+ command :'apps:list' do |c|
2
+ c.syntax = 'hockey apps:list'
3
+ c.summary = 'Lists the Name and ID of Apps on HockeyApp'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ if args.nil? or args.empty?
8
+ apps = try { agent.list_apps }
9
+ else
10
+ apps = try { agent.list_apps(args.first) }
11
+ end
12
+
13
+ title = "Listing Apps"
14
+ table = Terminal::Table.new :title => title do |t|
15
+ t << ["Title", "Platform", "Release Type", "App ID"]
16
+ t.add_separator
17
+ apps.compact.each do |app|
18
+ t << [
19
+ app["title"],
20
+ app["platform"],
21
+ agent.release_type_string(app["release_type"]),
22
+ app["public_identifier"]
23
+ ]
24
+ end
25
+ puts t
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,74 @@
1
+ command :'devices:list' do |c|
2
+ c.syntax = 'hockey devices:list'
3
+ c.summary = 'Lists the Devices of an App on HockeyApp'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ say_error "Missing arguments, expected App ID" and abort if args.nil? or args.empty?
8
+
9
+ devices = try { agent.list_devices(args[0], (args.length > 1 ? args[1] : nil)) }
10
+ title = "Listing Devices"
11
+ table = Terminal::Table.new :title => title do |t|
12
+ t << ["Device Name", "Device Identifier"]
13
+ t.add_separator
14
+ devices.compact.each do |device|
15
+ t << [
16
+ device["name"],
17
+ device["udid"]
18
+ ]
19
+ end
20
+ puts t
21
+ end
22
+ end
23
+ end
24
+
25
+ command :'devices:loop' do |c|
26
+ c.syntax = 'hockey devices:list'
27
+ c.summary = 'Add the Devices of an App on HockeyApp to the Provisioning Portal'
28
+ c.description = ''
29
+
30
+ c.action do |args, options|
31
+ say_error "Missing arguments, expected App ID" and abort if args.nil? or args.empty?
32
+
33
+ devices = try { agent.list_devices(args[0], (args.length > 1 ? args[1] : nil)) }
34
+ title = "Listing Devices"
35
+ table = Terminal::Table.new :title => title do |t|
36
+ t << ["#", "Device Name", "Device Identifier"]
37
+ t.add_separator
38
+ index = 0
39
+ devices.compact.each do |device|
40
+ t << [
41
+ "#{index + 1}",
42
+ device["name"],
43
+ device["udid"]
44
+ ]
45
+ index += 1
46
+ end
47
+
48
+ looping = true
49
+ while looping
50
+ puts t
51
+ selected = ask "Add device by #, or all devices (a), or quit (q):"
52
+ puts
53
+
54
+ case selected
55
+ when 'q'
56
+ add = nil
57
+ looping = false
58
+ when 'a'
59
+ add = devices
60
+ else
61
+ add = [devices[selected.to_i - 1]] if selected.to_i >= 1 and selected.to_i <= index
62
+ end
63
+
64
+ unless add.nil?
65
+ ext_args = []
66
+ add.each do |device|
67
+ ext_args << "\"#{device["name"]}=#{device["udid"]}\""
68
+ end
69
+ system "ios devices:add #{ext_args.join(" ")}"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,24 @@
1
+ command :login do |c|
2
+ c.syntax = 'hockey login'
3
+ c.summary = 'Sign in to HockeyApp and fetch or create token'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ say_warning "You are already authenticated" if Netrc.read[Infinite::HOSTNAME]
8
+
9
+ user = ask "Email:"
10
+ pass = password "Password:"
11
+
12
+ tokens = agent.list_tokens(user, pass)
13
+ tokens.reject! { |token| token["rights"].to_i != 2 }
14
+ if tokens.length == 0
15
+ tokens = agent.create_token(user, pass)
16
+ end
17
+
18
+ netrc = Netrc.read
19
+ netrc[Infinite::HOSTNAME] = tokens.first["token"], "X"
20
+ netrc.save
21
+
22
+ say_ok "API token saved"
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ command :logout do |c|
2
+ c.syntax = 'hockey logout'
3
+ c.summary = 'Remove API token'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ say_error "You are not authenticated" and abort unless Netrc.read[Infinite::HOSTNAME]
8
+
9
+ netrc = Netrc.read
10
+ netrc.delete(Infinite::HOSTNAME)
11
+ netrc.save
12
+
13
+ say_ok "API token removed"
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ class String
2
+ include Term::ANSIColor
3
+ end
4
+
5
+ module Infinite
6
+ module Loop
7
+ module Helpers
8
+ def agent
9
+ @agent = Infinite::Loop::Agent.new unless @agent
10
+ @agent
11
+ end
12
+
13
+ def pluralize(n, singular, plural = nil)
14
+ n.to_i == 1 ? "1 #{singular}" : "#{n} #{plural || singular + 's'}"
15
+ end
16
+
17
+ def try
18
+ return unless block_given?
19
+
20
+ begin
21
+ yield
22
+ #rescue UnsuccessfulAuthenticationError
23
+ # say_error "Could not authenticate with HockeyApp." and abort
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: infinite-loop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Thomas Dohmke
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cupertino
16
+ requirement: &70213216552340 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70213216552340
25
+ - !ruby/object:Gem::Dependency
26
+ name: rest-client
27
+ requirement: &70213216551520 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70213216551520
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ requirement: &70213216550540 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70213216550540
47
+ description: A command-line interface for HockeyApp
48
+ email:
49
+ - thomas@dohmke.de
50
+ executables:
51
+ - hockey
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - LICENSE
58
+ - README.md
59
+ - Rakefile
60
+ - bin/hockey
61
+ - infinite-loop.gemspec
62
+ - lib/infinite.rb
63
+ - lib/infinite/loop.rb
64
+ - lib/infinite/loop/agent.rb
65
+ - lib/infinite/loop/commands.rb
66
+ - lib/infinite/loop/commands/apps.rb
67
+ - lib/infinite/loop/commands/devices.rb
68
+ - lib/infinite/loop/commands/login.rb
69
+ - lib/infinite/loop/commands/logout.rb
70
+ - lib/infinite/loop/helpers.rb
71
+ homepage: ''
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.17
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Infinite Loop
95
+ test_files: []