circleci-cli 0.6.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +21 -19
  4. data/bin/circle +2 -2
  5. data/bin/console +1 -1
  6. data/{circler.gemspec → circleci-cli.gemspec} +3 -3
  7. data/exe/{circle → circleci-cli} +2 -2
  8. data/lib/circleci/cli.rb +77 -0
  9. data/lib/circleci/cli/command.rb +16 -0
  10. data/lib/circleci/cli/command/base_command.rb +45 -0
  11. data/lib/circleci/cli/command/browse_command.rb +24 -0
  12. data/lib/circleci/cli/command/build_command.rb +19 -0
  13. data/lib/circleci/cli/command/builds_command.rb +25 -0
  14. data/lib/circleci/cli/command/cancel_command.rb +23 -0
  15. data/lib/circleci/cli/command/projects_command.rb +16 -0
  16. data/lib/circleci/cli/command/retry_command.rb +23 -0
  17. data/lib/circleci/cli/command/watch_command.rb +77 -0
  18. data/lib/circleci/cli/networking.rb +9 -0
  19. data/lib/circleci/cli/networking/pusher_client.rb +62 -0
  20. data/lib/circleci/cli/printer.rb +11 -0
  21. data/lib/circleci/cli/printer/build_printer.rb +63 -0
  22. data/lib/circleci/cli/printer/project_printer.rb +37 -0
  23. data/lib/circleci/cli/printer/step_printer.rb +57 -0
  24. data/lib/circleci/cli/response.rb +13 -0
  25. data/lib/circleci/cli/response/account.rb +21 -0
  26. data/lib/circleci/cli/response/action.rb +39 -0
  27. data/lib/circleci/cli/response/build.rb +104 -0
  28. data/lib/circleci/cli/response/project.rb +21 -0
  29. data/lib/circleci/cli/response/step.rb +22 -0
  30. data/lib/circleci/cli/version.rb +7 -0
  31. data/lib/circleci_cli.rb +7 -0
  32. metadata +29 -25
  33. data/lib/circler.rb +0 -6
  34. data/lib/circler/cli.rb +0 -88
  35. data/lib/circler/command/base_command.rb +0 -41
  36. data/lib/circler/command/browse_command.rb +0 -20
  37. data/lib/circler/command/build_command.rb +0 -15
  38. data/lib/circler/command/builds_command.rb +0 -21
  39. data/lib/circler/command/cancel_command.rb +0 -19
  40. data/lib/circler/command/projects_command.rb +0 -12
  41. data/lib/circler/command/retry_command.rb +0 -19
  42. data/lib/circler/command/watch_command.rb +0 -73
  43. data/lib/circler/networking/pusher_client.rb +0 -56
  44. data/lib/circler/printer/build_printer.rb +0 -59
  45. data/lib/circler/printer/project_printer.rb +0 -33
  46. data/lib/circler/printer/step_printer.rb +0 -53
  47. data/lib/circler/response/account.rb +0 -17
  48. data/lib/circler/response/action.rb +0 -35
  49. data/lib/circler/response/build.rb +0 -100
  50. data/lib/circler/response/project.rb +0 -17
  51. data/lib/circler/response/step.rb +0 -18
  52. data/lib/circler/version.rb +0 -5
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'circleci/cli/networking/pusher_client'
4
+
5
+ module CircleCI
6
+ module CLI
7
+ module Networking; end
8
+ end
9
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pusher-client'
4
+
5
+ module CircleCI
6
+ module CLI
7
+ module Networking
8
+ class CircleCIPusherClient
9
+ def connect
10
+ PusherClient.logger.level = Logger::ERROR
11
+ @socket = PusherClient::Socket.new(app_key, pusher_options)
12
+ @socket.connect(true)
13
+ end
14
+
15
+ def bind(channel, event)
16
+ @socket.subscribe(channel)
17
+ @socket[channel].bind(event) do |data|
18
+ yield data
19
+ end
20
+ end
21
+
22
+ def bind_event_json(channel, event)
23
+ bind(channel, event) do |data|
24
+ JSON.parse(data).each { |json| yield(json) }
25
+ end
26
+ end
27
+
28
+ def unsubscribe(channel)
29
+ @socket.unsubscribe(channel)
30
+ end
31
+
32
+ private
33
+
34
+ def app_key
35
+ '1cf6e0e755e419d2ac9a'
36
+ end
37
+
38
+ def pusher_options
39
+ {
40
+ secure: true,
41
+ auth_method: proc { |a, b| auth(a, b) },
42
+ logger: Logger.new('/dev/null')
43
+ }
44
+ end
45
+
46
+ def auth(socket_id, channel)
47
+ data = { socket_id: socket_id, channel_name: channel.name }
48
+ token = ENV['CIRCLE_CI_TOKEN'] || ask('Circle CI token ? :')
49
+ res = connection.post("/auth/pusher?circle-token=#{token}", data)
50
+ JSON.parse(res.body)['auth']
51
+ end
52
+
53
+ def connection
54
+ Faraday.new(url: 'https://circleci.com') do |f|
55
+ f.request :url_encoded
56
+ f.adapter Faraday.default_adapter
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'circleci/cli/printer/project_printer'
4
+ require 'circleci/cli/printer/build_printer'
5
+ require 'circleci/cli/printer/step_printer'
6
+
7
+ module CircleCI
8
+ module CLI
9
+ module Printer; end
10
+ end
11
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Printer
6
+ class BuildPrinter
7
+ def initialize(builds, pretty: true)
8
+ @builds = builds
9
+ @pretty = pretty
10
+ end
11
+
12
+ def to_s
13
+ @pretty ? print_pretty : print_compact
14
+ end
15
+
16
+ private
17
+
18
+ def print_compact
19
+ rows.map { |row| pad_columns_by_space(row, max_row_widths) }.join("\n")
20
+ end
21
+
22
+ def print_pretty
23
+ Terminal::Table.new(title: title, headings: headings, rows: rows).to_s
24
+ end
25
+
26
+ def title
27
+ build = @builds.first
28
+ "Recent Builds / #{build.project_name}".green
29
+ end
30
+
31
+ def headings
32
+ %w[Number Status Branch Author Commit Duration StartTime]
33
+ end
34
+
35
+ def rows
36
+ @builds.map(&:information)
37
+ end
38
+
39
+ def max_row_widths
40
+ @builds
41
+ .map(&:information)
42
+ .map { |array| array.map(&:to_s).map(&:size) }
43
+ .transpose
44
+ .map(&:max)
45
+ end
46
+
47
+ def pad_columns_by_space(columns, max_widths)
48
+ columns
49
+ .map
50
+ .with_index { |column, i| pad_column_by_space(column, max_widths, i) }
51
+ .join(' ')
52
+ .to_s
53
+ end
54
+
55
+ def pad_column_by_space(column, max_widths, index)
56
+ column_string = column.to_s
57
+ spaces = ' ' * (max_widths[index] - column_string.size)
58
+ column_string + spaces
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Printer
6
+ class ProjectPrinter
7
+ attr_accessor :compact
8
+ def initialize(projects, pretty: true)
9
+ @projects = projects
10
+ @pretty = pretty
11
+ end
12
+
13
+ def to_s
14
+ @pretty ? print_pretty : print_compact
15
+ end
16
+
17
+ private
18
+
19
+ def print_compact
20
+ @projects
21
+ .map(&:information)
22
+ .map { |array| array.join('/').to_s }
23
+ .sort
24
+ .join("\n")
25
+ end
26
+
27
+ def print_pretty
28
+ Terminal::Table.new(
29
+ title: 'Projects'.green,
30
+ headings: ['User name', 'Repository name'],
31
+ rows: @projects.map(&:information)
32
+ ).to_s
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Printer
6
+ class StepPrinter
7
+ def initialize(steps, pretty: true)
8
+ @steps = steps
9
+ @pretty = pretty
10
+ end
11
+
12
+ def to_s
13
+ Terminal::Table.new do |t|
14
+ @steps
15
+ .group_by(&:type)
16
+ .each do |key, steps|
17
+ t << :separator
18
+ t << [{ value: key.green, alignment: :center, colspan: 2 }]
19
+ steps.each { |s| print_actions(t, s) }
20
+ end
21
+ end.to_s
22
+ end
23
+
24
+ private
25
+
26
+ def colorize_by_status(string, status)
27
+ case status
28
+ when 'success', 'fixed' then string.green
29
+ when 'canceled' then string.yellow
30
+ when 'failed', 'timedout' then string.red
31
+ when 'no_tests', 'not_run' then string.light_black
32
+ else string
33
+ end
34
+ end
35
+
36
+ def format_time(time)
37
+ return '' unless time
38
+
39
+ minute = format('%02d', time / 1000 / 60)
40
+ second = format('%02d', (time / 1000) % 60)
41
+ "#{minute}:#{second}"
42
+ end
43
+
44
+ def print_actions(table, step)
45
+ table << :separator
46
+ step.actions.each do |a|
47
+ table << [
48
+ colorize_by_status(a.name.slice(0..120), a.status),
49
+ format_time(a.run_time_millis)
50
+ ]
51
+ table << [{ value: a.log, alignment: :left, colspan: 2 }] if a.failed? && a.log
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'circleci/cli/response/account'
4
+ require 'circleci/cli/response/project'
5
+ require 'circleci/cli/response/build'
6
+ require 'circleci/cli/response/step'
7
+ require 'circleci/cli/response/action'
8
+
9
+ module CircleCI
10
+ module CLI
11
+ module Response; end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Response
6
+ class Account
7
+ def initialize(hash)
8
+ @hash = hash
9
+ end
10
+
11
+ def user_name
12
+ @hash['name']
13
+ end
14
+
15
+ def self.me
16
+ Account.new(CircleCi::User.me.body)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Response
6
+ class Action
7
+ attr_reader :name, :status, :run_time_millis
8
+ def initialize(hash)
9
+ @hash = hash
10
+ @name = hash['name']
11
+ @status = hash['status']
12
+ @run_time_millis = hash['run_time_millis']
13
+ end
14
+
15
+ def log
16
+ request(@hash['output_url'])
17
+ .map do |r|
18
+ r['message']
19
+ .gsub(/\r\n/, "\n")
20
+ .gsub(/\e\[A\r\e\[2K/, '')
21
+ .scan(/.{1,120}/)
22
+ .join("\n")
23
+ end
24
+ .join("\n")
25
+ end
26
+
27
+ def failed?
28
+ @status == 'timedout' || @status == 'failed'
29
+ end
30
+
31
+ private
32
+
33
+ def request(url)
34
+ JSON.parse(Faraday.new(url).get.body)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Response
6
+ class Build
7
+ class << self
8
+ def all(username, reponame)
9
+ CircleCi::Project.new(username, reponame, 'github').recent_builds
10
+ .body
11
+ .map { |b| Build.new(b) }
12
+ end
13
+
14
+ def branch(username, reponame, branch)
15
+ CircleCi::Project.new(username, reponame, 'github').recent_builds_branch(branch)
16
+ .body
17
+ .map { |b| Build.new(b) }
18
+ end
19
+
20
+ def get(username, reponame, number)
21
+ Build.new(CircleCi::Build.new(username, reponame, 'github', number).get.body)
22
+ end
23
+
24
+ def retry(username, reponame, number)
25
+ Build.new(CircleCi::Build.new(username, reponame, 'github', number).retry.body)
26
+ end
27
+
28
+ def cancel(username, reponame, number)
29
+ Build.new(CircleCi::Build.new(username, reponame, 'github', number).cancel.body)
30
+ end
31
+ end
32
+
33
+ def initialize(hash)
34
+ @hash = hash
35
+ end
36
+
37
+ def username
38
+ @hash['username']
39
+ end
40
+
41
+ def reponame
42
+ @hash['reponame']
43
+ end
44
+
45
+ def status
46
+ @hash['status']
47
+ end
48
+
49
+ def build_number
50
+ @hash['build_num']
51
+ end
52
+
53
+ def running?
54
+ status == 'running'
55
+ end
56
+
57
+ def channel_name
58
+ "private-#{username}@#{reponame}@#{build_number}@vcs-github@0"
59
+ end
60
+
61
+ def project_name
62
+ "#{username}/#{reponame}"
63
+ end
64
+
65
+ def information
66
+ [
67
+ @hash['build_num'],
68
+ colorize_by_status(@hash['status'], @hash['status']),
69
+ colorize_by_status(@hash['branch'], @hash['status']),
70
+ @hash['author_name'],
71
+ (@hash['subject'] || '').slice(0..60),
72
+ format_time(@hash['build_time_millis']),
73
+ @hash['start_time']
74
+ ]
75
+ end
76
+
77
+ def steps
78
+ hash = @hash['steps'].group_by { |s| s['actions'].first['type'] }
79
+ hash.flat_map { |type, value| value.map { |v| Step.new(type, v) } }
80
+ end
81
+
82
+ private
83
+
84
+ def colorize_by_status(string, status)
85
+ case status
86
+ when 'success', 'fixed' then string.green
87
+ when 'canceled' then string.yellow
88
+ when 'failed' then string.red
89
+ when 'no_tests', 'not_run' then string.light_black
90
+ else string
91
+ end
92
+ end
93
+
94
+ def format_time(time)
95
+ return '' unless time
96
+
97
+ minute = format('%02d', time / 1000 / 60)
98
+ second = format('%02d', (time / 1000) % 60)
99
+ "#{minute}:#{second}"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CircleCI
4
+ module CLI
5
+ module Response
6
+ class Project
7
+ def initialize(hash)
8
+ @hash = hash
9
+ end
10
+
11
+ def information
12
+ [@hash['username'], @hash['reponame']]
13
+ end
14
+
15
+ def self.all
16
+ CircleCi::Projects.new.get.body.map { |p| Project.new(p) }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end