circleci-cli 0.6.3 → 1.0.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +21 -19
- data/bin/circle +2 -2
- data/bin/console +1 -1
- data/{circler.gemspec → circleci-cli.gemspec} +3 -3
- data/exe/{circle → circleci-cli} +2 -2
- data/lib/circleci/cli.rb +77 -0
- data/lib/circleci/cli/command.rb +16 -0
- data/lib/circleci/cli/command/base_command.rb +45 -0
- data/lib/circleci/cli/command/browse_command.rb +24 -0
- data/lib/circleci/cli/command/build_command.rb +19 -0
- data/lib/circleci/cli/command/builds_command.rb +25 -0
- data/lib/circleci/cli/command/cancel_command.rb +23 -0
- data/lib/circleci/cli/command/projects_command.rb +16 -0
- data/lib/circleci/cli/command/retry_command.rb +23 -0
- data/lib/circleci/cli/command/watch_command.rb +77 -0
- data/lib/circleci/cli/networking.rb +9 -0
- data/lib/circleci/cli/networking/pusher_client.rb +62 -0
- data/lib/circleci/cli/printer.rb +11 -0
- data/lib/circleci/cli/printer/build_printer.rb +63 -0
- data/lib/circleci/cli/printer/project_printer.rb +37 -0
- data/lib/circleci/cli/printer/step_printer.rb +57 -0
- data/lib/circleci/cli/response.rb +13 -0
- data/lib/circleci/cli/response/account.rb +21 -0
- data/lib/circleci/cli/response/action.rb +39 -0
- data/lib/circleci/cli/response/build.rb +104 -0
- data/lib/circleci/cli/response/project.rb +21 -0
- data/lib/circleci/cli/response/step.rb +22 -0
- data/lib/circleci/cli/version.rb +7 -0
- data/lib/circleci_cli.rb +7 -0
- metadata +29 -25
- data/lib/circler.rb +0 -6
- data/lib/circler/cli.rb +0 -88
- data/lib/circler/command/base_command.rb +0 -41
- data/lib/circler/command/browse_command.rb +0 -20
- data/lib/circler/command/build_command.rb +0 -15
- data/lib/circler/command/builds_command.rb +0 -21
- data/lib/circler/command/cancel_command.rb +0 -19
- data/lib/circler/command/projects_command.rb +0 -12
- data/lib/circler/command/retry_command.rb +0 -19
- data/lib/circler/command/watch_command.rb +0 -73
- data/lib/circler/networking/pusher_client.rb +0 -56
- data/lib/circler/printer/build_printer.rb +0 -59
- data/lib/circler/printer/project_printer.rb +0 -33
- data/lib/circler/printer/step_printer.rb +0 -53
- data/lib/circler/response/account.rb +0 -17
- data/lib/circler/response/action.rb +0 -35
- data/lib/circler/response/build.rb +0 -100
- data/lib/circler/response/project.rb +0 -17
- data/lib/circler/response/step.rb +0 -18
- data/lib/circler/version.rb +0 -5
@@ -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,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
|