Class: Cody::Tailer
Instance Method Summary
collapse
#cfn, #codebuild
#are_you_sure?, #find_stack, #inferred_project_name, #inferred_stack_name, #normalize_stack_name, #project_name_convention, #stack_exists?
Constructor Details
#initialize(options, build_id) ⇒ Tailer
Returns a new instance of Tailer.
7
8
9
10
11
12
13
14
|
# File 'lib/cody/tailer.rb', line 7
def initialize(options, build_id)
@options, @build_id = options, build_id
@output = [] @shown_phases = []
@thread = nil
set_trap
end
|
Instance Method Details
#build_time(build) ⇒ Object
183
184
185
186
|
# File 'lib/cody/tailer.rb', line 183
def build_time(build)
duration = build.phases.inject(0) { |sum,p| sum + p.duration_in_seconds.to_i }
pretty_time(duration)
end
|
#cloudwatch_tail ⇒ Object
83
84
85
86
87
88
89
90
91
92
93
|
# File 'lib/cody/tailer.rb', line 83
def cloudwatch_tail
since = @options[:since] || "7d" cw_tail = AwsLogs::Tail.new(
log_group_name: @log_group_name,
log_stream_names: [@log_stream_name],
since: since,
follow: true,
format: "simple",
)
cw_tail.run
end
|
#complete_failed?(build) ⇒ Boolean
build.build_status : The current status of the build. Valid values include:
FAILED : The build failed.
FAULT : The build faulted.
IN_PROGRESS : The build is still in progress.
STOPPED : The build stopped.
SUCCEEDED : The build succeeded.
TIMED_OUT : The build timed out.
124
125
126
127
|
# File 'lib/cody/tailer.rb', line 124
def complete_failed?(build)
return if ENV["CODY_TEST"]
build.build_complete && build.build_status != "SUCCEEDED"
end
|
#display_failed_phases(build) ⇒ Object
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
# File 'lib/cody/tailer.rb', line 48
def display_failed_phases(build)
failed_phases = build.phases.select do |phase|
phase.phase_status != "SUCCEEDED" && phase.phase_status.to_s != ""
end
return if failed_phases.empty?
puts "Failed Phases:"
failed_phases.each do |phase|
puts "#{phase.phase_type}: #{phase.phase_status.color(:red)}"
context = phase.contexts.last
if context message = context.message
puts message
if message.include?("CannotPullContainerError") && message.include?("access denied")
puts "See: https://docs.aws.amazon.com/codebuild/latest/userguide/sample-ecr.html"
end
end
end
end
|
#display_phase(details) ⇒ Object
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# File 'lib/cody/tailer.rb', line 149
def display_phase(details)
already_shown = @shown_phases.detect do |p|
p[:phase_type] == details[:phase_type] &&
p[:phase_status] == details[:phase_status] &&
p[:start_time] == details[:start_time] &&
p[:duration_in_seconds] == details[:duration_in_seconds]
end
return if already_shown
status = details[:phase_status].to_s status = status == "SUCCEEDED" ? status.color(:green) : status.color(:red)
say [
"Phase:".color(:green), details[:phase_type],
"Status:".color(:purple), status,
"Duration:".color(:purple), details[:duration_in_seconds],
].join(" ")
end
|
#final_message(build) ⇒ Object
40
41
42
43
44
45
46
|
# File 'lib/cody/tailer.rb', line 40
def final_message(build)
status = build.build_status.to_s status = status != "SUCCEEDED" ? status.color(:red) : status.color(:green)
puts "Final build status: #{status}"
display_failed_phases(build) if status != "SUCCEEDED"
puts "The build took #{build_time(build)} to complete."
end
|
#find_build ⇒ Object
68
69
70
71
|
# File 'lib/cody/tailer.rb', line 68
def find_build
resp = codebuild.batch_get_builds(ids: [@build_id])
resp.builds.first
end
|
#logs_command? ⇒ Boolean
111
112
113
|
# File 'lib/cody/tailer.rb', line 111
def logs_command?
ARGV.join(" ").include?("logs")
end
|
#output ⇒ Object
172
173
174
|
# File 'lib/cody/tailer.rb', line 172
def output
@output.join("\n") + "\n"
end
|
#pretty_time(total_seconds) ⇒ Object
189
190
191
192
193
194
195
196
197
|
# File 'lib/cody/tailer.rb', line 189
def pretty_time(total_seconds)
minutes = (total_seconds / 60) % 60
seconds = total_seconds % 60
if total_seconds < 60
"#{seconds.to_i}s"
else
"#{minutes.to_i}m #{seconds.to_i}s"
end
end
|
#print_phases(build) ⇒ Object
136
137
138
139
140
141
142
143
144
145
146
147
|
# File 'lib/cody/tailer.rb', line 136
def print_phases(build)
build.phases.each do |phase|
details = {
phase_type: phase.phase_type,
phase_status: phase.phase_status,
start_time: phase.start_time,
duration_in_seconds: phase.duration_in_seconds,
}
display_phase(details)
@shown_phases << details
end
end
|
#run ⇒ Object
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
# File 'lib/cody/tailer.rb', line 16
def run
puts "Showing logs for build #{@build_id}"
complete = false
until complete do
build = find_build
unless build
puts "ERROR: Build id not found: #{@build_id}".color(:red)
return
end
print_phases(build)
set_log_group_name(build)
complete = build.build_complete
next if ENV["CODY_TEST"]
start_cloudwatch_tail
sleep 5
end
stop_cloudwatch_tail(build)
final_message(build)
end
|
#say(text) ⇒ Object
168
169
170
|
# File 'lib/cody/tailer.rb', line 168
def say(text)
ENV["CODY_TEST"] ? @output << text : puts(text)
end
|
#set_log_group_name(build) ⇒ Object
Setting enables start_cloudwatch_tail
130
131
132
133
134
|
# File 'lib/cody/tailer.rb', line 130
def set_log_group_name(build)
logs = build.logs
@log_group_name = logs.group_name if logs.group_name
@log_stream_name = logs.stream_name if logs.stream_name
end
|
#set_trap ⇒ Object
176
177
178
179
180
181
|
# File 'lib/cody/tailer.rb', line 176
def set_trap
Signal.trap("INT") {
puts "\nCtrl-C detected. Exiting..."
exit }
end
|
#start_cloudwatch_tail ⇒ Object
73
74
75
76
77
78
79
80
81
|
# File 'lib/cody/tailer.rb', line 73
def start_cloudwatch_tail
return if @cloudwatch_tail_started
return unless @log_group_name && @log_stream_name
@thread = Thread.new do
cloudwatch_tail
end
@cloudwatch_tail_started = true
end
|
#stop_cloudwatch_tail(build) ⇒ Object
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/cody/tailer.rb', line 95
def stop_cloudwatch_tail(build)
return if ENV["CODY_TEST"]
sleep 10 if complete_failed?(build) and !logs_command?
AwsLogs::Tail.stop_follow!
@thread.join if @thread
end
|