atlantispro 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8c1c129d83eed952059a24255df8c32981f9ac0
4
- data.tar.gz: 120997573134d06c79c7cd7813956086374a472e
3
+ metadata.gz: deee38e26d7c80ed8bcf9aa7ff0625c34431f004
4
+ data.tar.gz: ce4b735ebb4927cf32732743a0666f8a2aa16cad
5
5
  SHA512:
6
- metadata.gz: bf28939c5e893edf9e9422f202265c4b14d2136b63f76391528b844d7d3367c350fb847c10747383bd36cf7b58f918f49625bbf533fed118e87430a02ad83806
7
- data.tar.gz: 6754d4899a3f5581e225b0765f0a31a1e37a2d72b106fe147ac62cba09e9e58fc22f53aa315d58cb7a9e5bb7f7e559a3cb3dd90000d3c95cd1dfb683b1600478
6
+ metadata.gz: a4d95d18bb76ef9cbc37576226cc5f168d56eabf022a093ad8735d766e2f27ee06ffa67f09d036b9881d3c6d538dee7655b281059da544e04ad32f197a600674
7
+ data.tar.gz: 6ef003a0b3a0ca393ee8d9eaab686b60ac405437bf97cc19510795d3f222af296d9b3eb43c3c00c7a95722a000c77a48d58bd9a2ac4fe759847a47ccf9ebc00c
data/Atlantis.gemspec CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Atlantis::VERSION
9
9
  spec.authors = ["Dal Rupnik"]
10
10
  spec.email = ["legoless@gmail.com"]
11
- spec.summary = "Some random description"
12
- spec.description = "Yeees"
13
- spec.homepage = ""
11
+ spec.summary = "A command line interface to connect to distribution services such as TestFlight or Crashlytics."
12
+ spec.description = "A simple command line interface to work with multiple application distribution services, such as TestFlight or Crashlytics. Allows for downloading of device identifiers, registered testers and more."
13
+ spec.homepage = "https://github.com/legoless/Atlantis"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.add_dependency "commander", "~> 4.1.2"
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ atlantispro (0.1.2)
5
+ certified (>= 0.1.0)
6
+ commander (~> 4.1.2)
7
+ mechanize (~> 2.5.1)
8
+ nokogiri (~> 1.5.9)
9
+ security (~> 0.1.2)
10
+ term-ansicolor (~> 1.0.7)
11
+ terminal-table (~> 1.4.5)
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
15
+ specs:
16
+ certified (0.1.2)
17
+ commander (4.1.6)
18
+ highline (~> 1.6.11)
19
+ domain_name (0.5.18)
20
+ unf (>= 0.0.5, < 1.0.0)
21
+ highline (1.6.21)
22
+ mechanize (2.5.1)
23
+ domain_name (~> 0.5, >= 0.5.1)
24
+ mime-types (~> 1.17, >= 1.17.2)
25
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
26
+ net-http-persistent (~> 2.5, >= 2.5.2)
27
+ nokogiri (~> 1.4)
28
+ ntlm-http (~> 0.1, >= 0.1.1)
29
+ webrobots (~> 0.0, >= 0.0.9)
30
+ mime-types (1.25.1)
31
+ net-http-digest_auth (1.4)
32
+ net-http-persistent (2.9.4)
33
+ nokogiri (1.5.11)
34
+ ntlm-http (0.1.1)
35
+ rake (10.3.2)
36
+ security (0.1.2)
37
+ term-ansicolor (1.0.7)
38
+ terminal-table (1.4.5)
39
+ unf (0.1.4)
40
+ unf_ext
41
+ unf_ext (0.0.6)
42
+ webrobots (0.1.1)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ atlantispro!
49
+ bundler (~> 1.6)
50
+ rake
@@ -16,8 +16,7 @@ Signal.trap("INT") {} # Suppress backtrace when exiting command
16
16
 
17
17
  program :name, 'atlantis'
18
18
  program :version, Atlantis::VERSION
19
- program :description, 'A command-line interface for the TestFlight Portal'
20
-
19
+ program :description, 'A command-line interface for Distribution Portals (Crashlytics, TestFlight)'
21
20
  program :help, 'Author', 'Dal Rupnik <legoless@gmail.com>'
22
21
  program :help, 'Website', 'https://github.com/legoless'
23
22
  program :help_formatter, :compact
@@ -3,26 +3,26 @@ require 'certified'
3
3
 
4
4
  module Atlantis
5
5
  module Portal
6
- HOST = "testflightapp.com"
7
-
8
6
  class UnsuccessfulAuthenticationError < RuntimeError; end
7
+ class NetworkConnectionError < RuntimeError; end
9
8
  class UnexpectedContentError < RuntimeError; end
9
+ class UnknownTeamError < RuntimeError; end
10
10
 
11
- class Person < Struct.new(:id, :name, :email, :devices)
11
+ class Person < Struct.new(:id, :name, :email, :devices, :groups)
12
12
  def to_s
13
- "#{self.id} #{self.name} #{self.email} #{self.devices}"
13
+ "#{self.id} #{self.name} #{self.email}"
14
14
  end
15
15
  end
16
16
 
17
- class Device < Struct.new(:udid, :name)
17
+ class Device < Struct.new(:manufacturer, :model, :os_version, :identifier, :name, :platform, :model_name)
18
18
  def to_s
19
- "#{self.udid} #{self.name}"
19
+ "#{self.identifier} #{self.name}"
20
20
  end
21
21
  end
22
22
 
23
- class DistributionList < Struct.new(:id, :name, :count)
23
+ class Group < Struct.new(:id, :alias, :name, :count)
24
24
  def to_s
25
- "#{self.id} #{self.name} #{self.count}"
25
+ "#{self.id} #{self.name}"
26
26
  end
27
27
  end
28
28
 
@@ -31,7 +31,16 @@ module Atlantis
31
31
  "#{self.id} #{self.name} #{self.token}"
32
32
  end
33
33
  end
34
+
35
+ class CommandArguments < Struct.new(:username, :password, :team, :format, :service, :group)
36
+ def to_s
37
+ "#{self.username} #{self.team} #{self.format} #{self.service}"
38
+ end
39
+ end
34
40
  end
35
41
  end
36
42
 
37
- require 'atlantis/portal/agent'
43
+ require 'atlantis/portal/agent'
44
+ require 'atlantis/portal/service'
45
+ require 'atlantis/portal/crashlytics/crashlyticsservice'
46
+ require 'atlantis/portal/testflight/testflightservice'
@@ -8,7 +8,7 @@ require 'nokogiri'
8
8
  module Atlantis
9
9
  module Portal
10
10
  class Agent < ::Mechanize
11
- attr_accessor :username, :password, :team, :format
11
+ attr_accessor :format, :service, :service_instance
12
12
 
13
13
  def initialize
14
14
  super
@@ -25,203 +25,7 @@ module Atlantis
25
25
 
26
26
  set_proxy(uri.host, uri.port, user || uri.user, password || uri.password)
27
27
  end
28
-
29
- pw = Security::InternetPassword.find(:server => Atlantis::Portal::HOST)
30
- @username, @password = pw.attributes['acct'], pw.password if pw
31
- end
32
-
33
- def username=(value)
34
- @username = value
35
-
36
- pw = Security::InternetPassword.find(:a => self.username, :server => Atlantis::Portal::HOST)
37
- @password = pw.password if pw
38
- end
39
-
40
- def get(uri, parameters = [], referer = nil, headers = {})
41
- uri = ::File.join("https://#{Atlantis::Portal::HOST}", uri) unless /^https?/ === uri
42
-
43
- 3.times do
44
- super(uri, parameters, referer, headers)
45
-
46
- #puts page.body
47
-
48
- return page unless page.respond_to?(:title)
49
-
50
- unless page.parser.at_css('#id_username').nil?
51
- #puts "Logging in"
52
- login! and next
53
- else
54
- if !@team.nil? && !@team.empty?
55
- select_team! and next
56
- else
57
- return page
58
- end
59
- end
60
- end
61
-
62
- raise UnsuccessfulAuthenticationError
63
- end
64
-
65
- def list_people(distribution_list)
66
-
67
- if (distribution_list == 'all')
68
- get('https://testflightapp.com/dashboard/team')
69
- else
70
- lists = list_lists
71
-
72
- list = lists.find{|p| p.name == distribution_list}
73
-
74
- say_warning "No #{distribution_list} distribution list found." and abort if list.nil?
75
-
76
- get('https://testflightapp.com/dashboard/team/list/' + list.id)
77
- end
78
-
79
- people = []
80
-
81
- page.parser.css("table#member-table tr").each do |row|
82
- cols = row.css('td')
83
-
84
- #puts cols.length
85
-
86
- if (cols.length > 0)
87
- person = Person.new
88
-
89
- person.id = cols[0].css("input")[0]['value'];
90
- person.name = cols[1].text.strip.split.map(&:capitalize).join(' ')
91
- person.email = cols[2].text.strip
92
- person.devices = cols[3].text.strip
93
-
94
- people << person
95
-
96
- end
97
- end
98
-
99
- people
100
- end
101
-
102
- def list_devices(distribution_list)
103
- people = list_people(distribution_list)
104
-
105
- people_list = []
106
-
107
- people.each do |person|
108
- people_list << person.id
109
- end
110
-
111
- post('https://testflightapp.com/dashboard/team/export/devices/', { "members" => people_list.join('|'), "csrfmiddlewaretoken" => page.parser.css("[name='csrfmiddlewaretoken']")[0]['value'] } )
112
-
113
- device_list = page.body.split( /\r?\n/ )
114
-
115
- # Remove first one
116
- device_list.shift
117
-
118
- devices = []
119
-
120
- device_list.each do |dev|
121
- #puts dev
122
-
123
- device = Device.new
124
- device.udid = dev.split(/\t/)[0]
125
- device.name = dev.split(/\t/)[1]
126
-
127
- devices << device
128
- end
129
-
130
- devices
131
28
  end
132
-
133
- def list_lists
134
- get('https://testflightapp.com/dashboard/team')
135
-
136
- lists = []
137
-
138
- page.parser.css("nav.vert-nav li a").each do |row|
139
-
140
- unless (row['href'].nil?)
141
- url = row['href'].split('/')
142
-
143
- #puts url.length
144
-
145
- if (url.length >= 5) && (url[4].is_i?)
146
- #puts url[3]
147
-
148
- list = DistributionList.new
149
- list.id = url[4]
150
- list.name = row.css('> text()').text.strip
151
- list.count = row.css('span').text.strip
152
-
153
- lists << list
154
- end
155
-
156
- end
157
- end
158
-
159
- lists
160
- end
161
-
162
- def list_teams
163
- teams = []
164
-
165
- # Selected team
166
-
167
- selected_team = page.parser.css('ul.dropdown-menu li div div.textcontain180 text()')
168
-
169
- team = Team.new
170
- team.name = selected_team
171
-
172
- teams << team
173
-
174
- all_teams = page.parser.css('ul.ddteamlist li a')
175
- all_teams.each do |row|
176
- team = Team.new
177
- team.id = row['data-team-id']
178
- team.name = row.text
179
-
180
- teams << team
181
- end
182
-
183
- teams
184
- end
185
-
186
- private
187
-
188
- def login!
189
- if form = page.forms.first
190
- #puts "LOGGING IN" + self.username
191
-
192
- form.fields_with(type: 'email').first.value = self.username
193
- form.fields_with(type: 'password').first.value = self.password
194
-
195
- form.submit
196
- end
197
- end
198
-
199
- def select_team!
200
- teams = list_teams
201
-
202
- #puts teams
203
-
204
- # Check if desired team is different to selected team
205
-
206
- if @team != teams[0].name
207
- #puts "Selecting team..."
208
-
209
- if form = page.form_with(:id => 'team-change')
210
-
211
- team = teams.find{|t| t.name == @team}
212
-
213
- #puts team
214
-
215
- unless (team.nil?)
216
- form.team = team.id
217
- form.submit
218
- end
219
- end
220
- end
221
-
222
- @team = ''
223
- end
224
-
225
29
  end
226
30
  end
227
31
  end
@@ -3,15 +3,17 @@ include Atlantis::Portal
3
3
  require 'atlantis/portal/helpers'
4
4
  include Atlantis::Portal::Helpers
5
5
 
6
- global_option('-u', '--username USER', 'Username') { |arg| agent.username = arg unless arg.nil? }
7
- global_option('-p', '--password PASSWORD', 'Password') { |arg| agent.password = arg unless arg.nil? }
8
- global_option('--team TEAM', 'Team') { |arg| agent.team = arg if arg }
6
+ global_option('-u', '--username USER', 'Username') { |arg| arguments.username = arg unless arg.nil? }
7
+ global_option('-p', '--password PASSWORD', 'Password') { |arg| arguments.password = arg unless arg.nil? }
8
+ global_option('--team TEAM', 'Team or Organisation') { |arg| arguments.team = arg if arg }
9
9
  global_option('--info', 'Set log level to INFO') { agent.log.level = Logger::INFO }
10
10
  global_option('--debug', 'Set log level to DEBUG') { agent.log.level = Logger::DEBUG }
11
- global_option('--format [table|csv]', 'Set output format (default: table)') { |arg| agent.format = arg if arg }
11
+ global_option('--format [table|csv|json]', 'Set output format (default: table)') { |arg| arguments.format = arg if arg }
12
+ global_option('--group GROUP', 'Set group or distribution list') { |arg| arguments.group = arg if arg }
13
+ global_option('--service [crashlytics/testflight]', 'Set service (default: testflight)') { |arg| arguments.service = arg if arg }
12
14
 
13
15
  require 'atlantis/portal/commands/login'
14
16
  require 'atlantis/portal/commands/logout'
15
17
  require 'atlantis/portal/commands/people'
16
18
  require 'atlantis/portal/commands/devices'
17
- require 'atlantis/portal/commands/lists'
19
+ require 'atlantis/portal/commands/groups'
@@ -1,43 +1,12 @@
1
1
  command :'devices' do |c|
2
- c.syntax = 'testflight devices'
3
- c.summary = 'Lists devices on TestFlight'
2
+ c.syntax = 'distribution devices'
3
+ c.summary = 'Lists devices registered on specified service'
4
4
  c.description = ''
5
5
 
6
6
  c.action do |args, options|
7
- distribution_list = args.join(" ").strip
8
7
 
9
- if (distribution_list.empty?)
10
- distribution_list = 'all'
11
- end
12
- devices = try{agent.list_devices(distribution_list)}
8
+ devices = try{service.list_devices(arguments.group)}
13
9
 
14
- #devices = []
15
-
16
- if (agent.format == "csv")
17
- csv_string = CSV.generate do |csv|
18
- csv << ["Name", "UDID"]
19
-
20
- devices.each do |device|
21
- csv << [device.name, device.udid]
22
- end
23
- end
24
-
25
- puts csv_string
26
- else
27
-
28
- title = "Listing devices"
29
-
30
- table = Terminal::Table.new :title => title do |t|
31
- t << ["Name", "UDID"]
32
- t.add_separator
33
- devices.each do |device|
34
- t << [device.name, device.udid]
35
- end
36
- end
37
-
38
- #table.align_column 2, :center
39
-
40
- puts table
41
- end
10
+ output('Devices', ["Name", "Identifier"], devices)
42
11
  end
43
12
  end
@@ -0,0 +1,11 @@
1
+ command :'groups' do |c|
2
+ c.syntax = 'distribution groups'
3
+ c.summary = 'Lists all groups on service'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ lists = try{service.list_groups}
8
+
9
+ output('Groups', ["ID", "Name"], lists)
10
+ end
11
+ end
@@ -1,15 +1,15 @@
1
1
  command :login do |c|
2
- c.syntax = 'testflight login'
3
- c.summary = 'Save account credentials'
2
+ c.syntax = 'distribution login'
3
+ c.summary = 'Save account credentials for specific service'
4
4
  c.description = ''
5
5
 
6
6
  c.action do |args, options|
7
- say_warning "You are already authenticated" if Security::InternetPassword.find(:server => Atlantis::Portal::HOST)
7
+ say_warning "You are already authenticated" if Security::InternetPassword.find(:server => service.host)
8
8
 
9
9
  user = ask "Username:"
10
10
  pass = password "Password:"
11
11
 
12
- Security::InternetPassword.add(Atlantis::Portal::HOST, user, pass)
12
+ Security::InternetPassword.add(service.host, user, pass)
13
13
 
14
14
  say_ok "Account credentials saved"
15
15
  end