lib/circle/cli/app.rb
require 'launchy'
require 'circle/cli/repo'
require 'circle/cli/project'
require 'circle/cli/watcher'
module Circle
module CLI
class App < Thor
CIRCLE_URL = 'https://circleci.com/account/api'
LOGIN_HELP = <<-EOMSG
1. Press [enter], and you'll be taken CircleCI.
2. Enter a name for your new token.
3. Click 'Create new token'.
4. Come back to your prompt and paste in your new token.
5. Press enter to complete the process.
EOMSG
NO_TOKEN_MESSAGE = <<-EOMSG
CircleCI token hasn't been configured. Run the following command to login:
$ circle login
EOMSG
default_task :status
class_option :repo, default: '.', desc: 'path to repo'
desc 'status', 'show CircleCI build result'
method_option :branch, desc: 'branch name'
method_option :watch, desc: 'watch the build', type: :boolean, default: false
method_option :poll, default: 5, desc: 'polling frequency', type: :numeric
def status
validate_repo!
validate_latest!
watcher = Watcher.new do
display_status
end
watcher.to_preload do
project.clear_cache!
project.latest.preload
end
if options[:watch]
watcher.poll(options[:poll])
else
watcher.display
end
end
desc 'watch', 'an alias for `circle --watch`', hide: true
def watch
invoke :status, [], watch: true
end
desc 'overview', 'list recent builds and their statuses for all branches'
method_option :watch, desc: 'watch the list of builds', type: :boolean, default: false
method_option :poll, default: 5, desc: 'polling frequency', type: :numeric
def overview
validate_repo!
abort! 'No recent builds.' if project.recent_builds.empty?
watcher = Watcher.new do
display_builds(project.recent_builds)
end
watcher.to_preload do
project.clear_cache!
project.recent_builds
end
if options[:watch]
watcher.poll(options[:poll])
else
watcher.display
end
end
desc 'open', 'open CircleCI build'
method_option :branch, desc: 'branch name'
def open
validate_repo!
validate_latest!
Launchy.open latest[:build_url]
end
desc 'build', 'trigger a build on circle ci'
method_option :branch, desc: 'branch name'
def build
validate_repo!
project.build!
say "A build has been triggered.\n\n", :green
invoke :status, [], watch: true
end
desc 'cancel', 'cancel most recent build'
method_option :branch, desc: 'branch name'
def cancel
validate_repo!
validate_latest!
latest.cancel! unless latest.finished?
invoke :status
say "\nThe build has been cancelled.", :red unless latest.finished?
end
desc 'token', 'view or edit CircleCI token'
def token(value = nil)
if value
repo.circle_token = value
elsif value = repo.circle_token
say value
else
say NO_TOKEN_MESSAGE, :yellow
end
end
desc 'login', 'login to Circle CI'
def login
say LOGIN_HELP, :yellow
ask set_color("\nPress [enter] to open CircleCI", :blue)
Launchy.open(CIRCLE_URL)
value = ask set_color('Enter your token:', :blue)
repo.circle_token = value
say "\nYour token has been set to '#{value}'.", :green
end
private
def repo
@repo ||= Repo.new(options)
end
def project
@project ||= Project.new(repo)
end
def latest
project.latest
end
def validate_repo!
abort! "Unsupported repo url format #{repo.uri}" unless repo.uri.github?
abort! NO_TOKEN_MESSAGE unless repo.circle_token
end
def validate_latest!
abort! 'No CircleCI builds found.' unless project.latest
end
def abort!(message)
abort set_color(message, :red)
end
def display(description, value, color)
status = set_color description.ljust(15), :bold
result = set_color value.to_s, color
say "#{status} #{result}"
end
def display_status
say "#{latest[:subject]}\n\n", :cyan if latest[:subject]
display 'Build status', latest.status, latest.color
display 'Started at', latest.formatted_start_time, latest.color
display 'Finished at', latest.formatted_stop_time, latest.color
display 'Compare', latest[:compare], latest.color if latest[:compare]
display_steps latest.steps unless latest.steps.empty?
display_failures latest.failing_tests unless latest.failing_tests.empty?
exit 1 if latest.failed?
exit 0 if latest.finished?
end
def display_steps(steps)
say "\nSteps:", :bold
print_table steps.map { |step|
[set_color(step[:name], step.color), step.duration]
}
end
def display_failures(failures)
say "\nFailing specs:", :bold
print_table failures.map { |spec|
[set_color(spec['file'], :red), spec['name']]
}
end
def display_builds(builds)
print_table builds.map { |build|
branch = set_color(build[:branch], :bold)
status = set_color(build.status, build.color)
started = build.formatted_start_time
[branch, status, build.subject, started]
}
end
end
end
end