travis-akerl 1.8.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +2512 -0
- data/Rakefile +64 -0
- data/assets/cacert.pem +69 -0
- data/assets/init/c.yml +4 -0
- data/assets/init/clojure.yml +1 -0
- data/assets/init/cpp.yml +4 -0
- data/assets/init/erlang.yml +3 -0
- data/assets/init/go.yml +4 -0
- data/assets/init/groovy.yml +1 -0
- data/assets/init/haskell.yml +1 -0
- data/assets/init/java.yml +4 -0
- data/assets/init/node_js.yml +5 -0
- data/assets/init/objective-c.yml +1 -0
- data/assets/init/perl.yml +4 -0
- data/assets/init/php.yml +4 -0
- data/assets/init/python.yml +5 -0
- data/assets/init/ruby.yml +6 -0
- data/assets/init/scala.yml +4 -0
- data/assets/notifications/Travis CI.app/Contents/Info.plist +52 -0
- data/assets/notifications/Travis CI.app/Contents/MacOS/Travis CI +0 -0
- data/assets/notifications/Travis CI.app/Contents/PkgInfo +1 -0
- data/assets/notifications/Travis CI.app/Contents/Resources/Travis CI.icns +0 -0
- data/assets/notifications/Travis CI.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
- data/assets/notifications/Travis CI.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- data/assets/notifications/Travis CI.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
- data/assets/notifications/Travis CI.app/Contents/_CodeSignature/CodeResources +173 -0
- data/assets/notifications/Travis CI.app/Contents/embedded.provisionprofile +0 -0
- data/assets/notifications/icon.png +0 -0
- data/assets/travis.sh +163 -0
- data/assets/travis.sh.erb +64 -0
- data/bin/travis +18 -0
- data/examples/org_overview.rb +3 -0
- data/examples/pro_auth.rb +23 -0
- data/examples/stream.rb +6 -0
- data/lib/travis/auto_login.rb +3 -0
- data/lib/travis/cli/accounts.rb +31 -0
- data/lib/travis/cli/api_command.rb +182 -0
- data/lib/travis/cli/branches.rb +25 -0
- data/lib/travis/cli/cache.rb +76 -0
- data/lib/travis/cli/cancel.rb +18 -0
- data/lib/travis/cli/command.rb +422 -0
- data/lib/travis/cli/console.rb +33 -0
- data/lib/travis/cli/disable.rb +15 -0
- data/lib/travis/cli/enable.rb +31 -0
- data/lib/travis/cli/encrypt.rb +115 -0
- data/lib/travis/cli/encrypt_file.rb +140 -0
- data/lib/travis/cli/endpoint.rb +35 -0
- data/lib/travis/cli/env.rb +66 -0
- data/lib/travis/cli/help.rb +23 -0
- data/lib/travis/cli/history.rb +49 -0
- data/lib/travis/cli/init.rb +82 -0
- data/lib/travis/cli/lint.rb +49 -0
- data/lib/travis/cli/login.rb +76 -0
- data/lib/travis/cli/logout.rb +14 -0
- data/lib/travis/cli/logs.rb +65 -0
- data/lib/travis/cli/monitor.rb +111 -0
- data/lib/travis/cli/open.rb +39 -0
- data/lib/travis/cli/parser.rb +43 -0
- data/lib/travis/cli/pubkey.rb +30 -0
- data/lib/travis/cli/raw.rb +20 -0
- data/lib/travis/cli/repo_command.rb +154 -0
- data/lib/travis/cli/report.rb +101 -0
- data/lib/travis/cli/repos.rb +53 -0
- data/lib/travis/cli/requests.rb +47 -0
- data/lib/travis/cli/restart.rb +18 -0
- data/lib/travis/cli/settings.rb +79 -0
- data/lib/travis/cli/setup/anynines.rb +21 -0
- data/lib/travis/cli/setup/appfog.rb +19 -0
- data/lib/travis/cli/setup/artifacts.rb +23 -0
- data/lib/travis/cli/setup/biicode.rb +19 -0
- data/lib/travis/cli/setup/cloud_66.rb +20 -0
- data/lib/travis/cli/setup/cloud_control.rb +21 -0
- data/lib/travis/cli/setup/cloud_files.rb +20 -0
- data/lib/travis/cli/setup/cloud_foundry.rb +23 -0
- data/lib/travis/cli/setup/code_deploy.rb +55 -0
- data/lib/travis/cli/setup/deis.rb +20 -0
- data/lib/travis/cli/setup/divshot.rb +18 -0
- data/lib/travis/cli/setup/elastic_beanstalk.rb +23 -0
- data/lib/travis/cli/setup/engine_yard.rb +24 -0
- data/lib/travis/cli/setup/gcs.rb +22 -0
- data/lib/travis/cli/setup/hackage.rb +18 -0
- data/lib/travis/cli/setup/heroku.rb +20 -0
- data/lib/travis/cli/setup/modulus.rb +18 -0
- data/lib/travis/cli/setup/ninefold.rb +20 -0
- data/lib/travis/cli/setup/nodejitsu.rb +27 -0
- data/lib/travis/cli/setup/npm.rb +20 -0
- data/lib/travis/cli/setup/open_shift.rb +20 -0
- data/lib/travis/cli/setup/opsworks.rb +22 -0
- data/lib/travis/cli/setup/pypi.rb +22 -0
- data/lib/travis/cli/setup/releases.rb +35 -0
- data/lib/travis/cli/setup/ruby_gems.rb +25 -0
- data/lib/travis/cli/setup/s3.rb +25 -0
- data/lib/travis/cli/setup/sauce_connect.rb +21 -0
- data/lib/travis/cli/setup/service.rb +73 -0
- data/lib/travis/cli/setup.rb +66 -0
- data/lib/travis/cli/show.rb +57 -0
- data/lib/travis/cli/sshkey.rb +118 -0
- data/lib/travis/cli/status.rb +19 -0
- data/lib/travis/cli/sync.rb +30 -0
- data/lib/travis/cli/token.rb +14 -0
- data/lib/travis/cli/version.rb +17 -0
- data/lib/travis/cli/whatsup.rb +30 -0
- data/lib/travis/cli/whoami.rb +15 -0
- data/lib/travis/cli.rb +126 -0
- data/lib/travis/client/account.rb +56 -0
- data/lib/travis/client/artifact.rb +88 -0
- data/lib/travis/client/auto_login.rb +45 -0
- data/lib/travis/client/broadcast.rb +14 -0
- data/lib/travis/client/build.rb +47 -0
- data/lib/travis/client/cache.rb +25 -0
- data/lib/travis/client/commit.rb +28 -0
- data/lib/travis/client/entity.rb +238 -0
- data/lib/travis/client/env_var.rb +102 -0
- data/lib/travis/client/error.rb +38 -0
- data/lib/travis/client/has_uuid.rb +13 -0
- data/lib/travis/client/job.rb +61 -0
- data/lib/travis/client/lint_result.rb +25 -0
- data/lib/travis/client/listener.rb +183 -0
- data/lib/travis/client/methods.rb +104 -0
- data/lib/travis/client/namespace.rb +85 -0
- data/lib/travis/client/not_loadable.rb +13 -0
- data/lib/travis/client/repository.rb +224 -0
- data/lib/travis/client/request.rb +36 -0
- data/lib/travis/client/restartable.rb +23 -0
- data/lib/travis/client/session.rb +339 -0
- data/lib/travis/client/settings.rb +25 -0
- data/lib/travis/client/singleton_setting.rb +36 -0
- data/lib/travis/client/ssh_key.rb +11 -0
- data/lib/travis/client/states.rb +98 -0
- data/lib/travis/client/user.rb +67 -0
- data/lib/travis/client/weak_entity.rb +26 -0
- data/lib/travis/client.rb +38 -0
- data/lib/travis/pro/auto_login.rb +3 -0
- data/lib/travis/pro.rb +5 -0
- data/lib/travis/tools/assets.rb +21 -0
- data/lib/travis/tools/completion.rb +54 -0
- data/lib/travis/tools/formatter.rb +50 -0
- data/lib/travis/tools/github.rb +293 -0
- data/lib/travis/tools/notification.rb +69 -0
- data/lib/travis/tools/safe_string.rb +22 -0
- data/lib/travis/tools/ssl_key.rb +48 -0
- data/lib/travis/tools/system.rb +88 -0
- data/lib/travis/version.rb +3 -0
- data/lib/travis.rb +8 -0
- data/spec/cli/api_command_spec.rb +38 -0
- data/spec/cli/cancel_spec.rb +15 -0
- data/spec/cli/encrypt_spec.rb +49 -0
- data/spec/cli/endpoint_spec.rb +39 -0
- data/spec/cli/help_spec.rb +33 -0
- data/spec/cli/history_spec.rb +38 -0
- data/spec/cli/init_spec.rb +227 -0
- data/spec/cli/login_spec.rb +13 -0
- data/spec/cli/logs_spec.rb +8 -0
- data/spec/cli/open_spec.rb +33 -0
- data/spec/cli/repo_command_spec.rb +25 -0
- data/spec/cli/restart_spec.rb +15 -0
- data/spec/cli/setup_spec.rb +5 -0
- data/spec/cli/show_spec.rb +9 -0
- data/spec/cli/status_spec.rb +28 -0
- data/spec/cli/token_spec.rb +22 -0
- data/spec/cli/version_spec.rb +18 -0
- data/spec/cli/whoami_spec.rb +34 -0
- data/spec/client/account_spec.rb +32 -0
- data/spec/client/auto_login_spec.rb +25 -0
- data/spec/client/broadcast_spec.rb +10 -0
- data/spec/client/build_spec.rb +31 -0
- data/spec/client/commit_spec.rb +22 -0
- data/spec/client/job_spec.rb +30 -0
- data/spec/client/methods_spec.rb +15 -0
- data/spec/client/namespace_spec.rb +19 -0
- data/spec/client/repository_spec.rb +39 -0
- data/spec/client/session_spec.rb +165 -0
- data/spec/client/user_spec.rb +16 -0
- data/spec/client_spec.rb +17 -0
- data/spec/pro_spec.rb +10 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/fake_api.rb +731 -0
- data/spec/support/fake_github.rb +24 -0
- data/spec/support/fake_travis_config.yml +14 -0
- data/spec/support/helpers.rb +45 -0
- data/spec/travis_spec.rb +10 -0
- data/travis.gemspec +371 -0
- metadata +534 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'travis/cli/setup'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Setup
|
6
|
+
class RubyGems < Service
|
7
|
+
description "automatic release to RubyGems"
|
8
|
+
|
9
|
+
def run
|
10
|
+
deploy 'rubygems', 'release' do |config|
|
11
|
+
authorization_file = File.expand_path('.rubygems/authorization', ENV['HOME'])
|
12
|
+
credentials_file = File.expand_path('.gem/credentials', ENV['HOME'])
|
13
|
+
|
14
|
+
config['api_key'] ||= File.read(authorization_file) if File.exist? authorization_file
|
15
|
+
config['api_key'] ||= YAML.load_file(credentials_file)[:rubygems_api_key] if File.exist? credentials_file
|
16
|
+
config['api_key'] ||= ask("RubyGems API token: ") { |q| q.echo = "*" }.to_s
|
17
|
+
config['gem'] ||= ask("Gem name: ") { |q| q.default = repository.name }.to_s
|
18
|
+
|
19
|
+
on("Release only tagged commits? ", config, 'tags' => true)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'travis/cli/setup'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Setup
|
6
|
+
class S3 < Service
|
7
|
+
description "automatic pushing to S3"
|
8
|
+
|
9
|
+
def run
|
10
|
+
deploy 's3', 'push' do |config|
|
11
|
+
config['access_key_id'] = ask("Access key ID: ").to_s
|
12
|
+
config['secret_access_key'] = ask("Secret access key: ") { |q| q.echo = "*" }.to_s
|
13
|
+
config['bucket'] = ask("Bucket: ").to_s
|
14
|
+
local_dir = ask("Local project directory to upload (Optional): ").to_s
|
15
|
+
config['local-dir'] = local_dir unless local_dir.empty?
|
16
|
+
upload_dir = ask("S3 upload directory (Optional): ").to_s
|
17
|
+
config['upload-dir'] = upload_dir unless upload_dir.empty?
|
18
|
+
config['acl'] = ask("S3 ACL Settings (private, public_read, public_read_write, authenticated_read, bucket_owner_read, bucket_owner_full_control): ").to_s { |q| q.default = 'private'}
|
19
|
+
encrypt(config, 'secret_access_key') if agree("Encrypt secret access key? ") { |q| q.default = 'yes' }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'travis/cli/setup'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Setup
|
6
|
+
class SauceConnect < Service
|
7
|
+
description "Sauce Connet addon for Sauce Labs integration"
|
8
|
+
service_name "sauce_connect"
|
9
|
+
|
10
|
+
def run
|
11
|
+
travis_config['addons'] ||= {}
|
12
|
+
configure 'sauce_connect', {}, travis_config['addons'] do |config|
|
13
|
+
config['username'] = ask("Sauce Labs user: ").to_s
|
14
|
+
config['access_key'] = ask("Sauce Labs access key: ") { |q| q.echo = "*" }.to_s
|
15
|
+
encrypt(config, 'access_key') if agree("Encrypt access key? ") { |q| q.default = 'yes' }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'travis/cli/setup'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Setup
|
6
|
+
class Service
|
7
|
+
def self.normalized_name(string)
|
8
|
+
string.to_s.downcase.gsub(/[^a-z\d]/, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.description(description = nil)
|
12
|
+
@description ||= ""
|
13
|
+
@description = description if description
|
14
|
+
@description
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.service_name(service_name = nil)
|
18
|
+
@service_name ||= normalized_name(name[/[^:]+$/])
|
19
|
+
@service_name = service_name if service_name
|
20
|
+
@service_name
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.known_as?(name)
|
24
|
+
normalized_name(service_name) == normalized_name(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :command
|
28
|
+
|
29
|
+
def initialize(command)
|
30
|
+
@command = command
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(*args, &block)
|
34
|
+
@command.send(*args, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def on(question, config, condition)
|
40
|
+
return unless agree(question) { |q| q.default = 'yes' }
|
41
|
+
config['on'] ||= {}
|
42
|
+
config['on'].merge! condition
|
43
|
+
end
|
44
|
+
|
45
|
+
def encrypt(config, key)
|
46
|
+
encrypted = repository.encrypt(config.fetch(key))
|
47
|
+
config[key] = { 'secure' => encrypted }
|
48
|
+
end
|
49
|
+
|
50
|
+
def configure(key, value = {}, config = travis_config)
|
51
|
+
error "#{key} section already exists in .travis.yml, run with --force to override" if config.include? key and not force?
|
52
|
+
yield(config[key] = value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def branch
|
56
|
+
@branch ||= `git rev-parse --symbolic-full-name --abbrev-ref HEAD`.chomp
|
57
|
+
end
|
58
|
+
|
59
|
+
def deploy(provider, verb = "deploy")
|
60
|
+
configure('deploy', 'provider' => provider) do |config|
|
61
|
+
yield config
|
62
|
+
|
63
|
+
on("#{verb.capitalize} only from #{repository.slug}? ", config, 'repo' => repository.slug)
|
64
|
+
on("#{verb.capitalize} from #{branch} branch? ", config, 'branch' => branch) if branch != 'master' and branch != 'HEAD'
|
65
|
+
|
66
|
+
encrypt(config, 'password') if config['password'] and agree("Encrypt Password? ") { |q| q.default = 'yes' }
|
67
|
+
encrypt(config, 'api_key') if config['api_key'] and agree("Encrypt API key? ") { |q| q.default = 'yes' }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Setup < RepoCommand
|
6
|
+
autoload :Anynines, 'travis/cli/setup/anynines'
|
7
|
+
autoload :Appfog, 'travis/cli/setup/appfog'
|
8
|
+
autoload :Artifacts, 'travis/cli/setup/artifacts'
|
9
|
+
autoload :Biicode, 'travis/cli/setup/biicode'
|
10
|
+
autoload :CloudControl, 'travis/cli/setup/cloud_control'
|
11
|
+
autoload :CloudFoundry, 'travis/cli/setup/cloud_foundry'
|
12
|
+
autoload :CodeDeploy, 'travis/cli/setup/code_deploy'
|
13
|
+
autoload :EngineYard, 'travis/cli/setup/engine_yard'
|
14
|
+
autoload :Heroku, 'travis/cli/setup/heroku'
|
15
|
+
autoload :Nodejitsu, 'travis/cli/setup/nodejitsu'
|
16
|
+
autoload :NPM, 'travis/cli/setup/npm'
|
17
|
+
autoload :OpenShift, 'travis/cli/setup/open_shift'
|
18
|
+
autoload :PyPI, 'travis/cli/setup/pypi'
|
19
|
+
autoload :RubyGems, 'travis/cli/setup/ruby_gems'
|
20
|
+
autoload :Ninefold, 'travis/cli/setup/ninefold'
|
21
|
+
autoload :S3, 'travis/cli/setup/s3'
|
22
|
+
autoload :CloudFiles, 'travis/cli/setup/cloud_files'
|
23
|
+
autoload :Divshot, 'travis/cli/setup/divshot'
|
24
|
+
autoload :Hackage, 'travis/cli/setup/hackage'
|
25
|
+
autoload :OpsWorks, 'travis/cli/setup/opsworks'
|
26
|
+
autoload :SauceConnect, 'travis/cli/setup/sauce_connect'
|
27
|
+
autoload :Modulus, 'travis/cli/setup/modulus'
|
28
|
+
autoload :Releases, 'travis/cli/setup/releases'
|
29
|
+
autoload :GCS, 'travis/cli/setup/gcs'
|
30
|
+
autoload :Cloud_66, 'travis/cli/setup/cloud_66'
|
31
|
+
autoload :ElasticBeanstalk, 'travis/cli/setup/elastic_beanstalk'
|
32
|
+
autoload :Deis, 'travis/cli/setup/deis'
|
33
|
+
autoload :Service, 'travis/cli/setup/service'
|
34
|
+
|
35
|
+
description "sets up an addon or deploy target"
|
36
|
+
on('-f', '--force', 'override config section if it already exists')
|
37
|
+
|
38
|
+
def self.service(name)
|
39
|
+
normal_name = Service.normalized_name(name)
|
40
|
+
const_name = constants(false).detect { |c| Service.normalized_name(c) == normal_name }
|
41
|
+
constant = const_get(const_name) if const_name
|
42
|
+
constant if constant and constant < Service and constant.known_as? name
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.services
|
46
|
+
constants(false).sort.map { |c| const_get(c) }.select { |c| c < Service }
|
47
|
+
end
|
48
|
+
|
49
|
+
def help
|
50
|
+
services = self.class.services.map { |s| "\t" << color(s.service_name.ljust(20), :command) << color(s.description, :info) }.join("\n")
|
51
|
+
super("\nAvailable services:\n\n#{services}\n\n")
|
52
|
+
end
|
53
|
+
|
54
|
+
def run(service, file = travis_yaml)
|
55
|
+
service(service).run
|
56
|
+
save_travis_config(file)
|
57
|
+
end
|
58
|
+
|
59
|
+
def service(name)
|
60
|
+
factory = self.class.service(name)
|
61
|
+
error("unknown service #{name}") unless factory
|
62
|
+
factory.new(self)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Show < RepoCommand
|
6
|
+
description "displays a build or job"
|
7
|
+
|
8
|
+
def run(number = last_build.number)
|
9
|
+
number = repository.branch(number).number if number !~ /^\d+(\.\d+)?$/ and repository.branch(number)
|
10
|
+
entity = job(number) || build(number)
|
11
|
+
|
12
|
+
error "could not find job or build #{repository.slug}##{number}" unless entity
|
13
|
+
|
14
|
+
say template(__FILE__) % [
|
15
|
+
entity.class.one.capitalize,
|
16
|
+
entity.number,
|
17
|
+
entity.commit.subject,
|
18
|
+
entity.state,
|
19
|
+
entity.color,
|
20
|
+
entity.pull_request? ? "pull request" : "push",
|
21
|
+
entity.branch_info,
|
22
|
+
entity.commit.compare_url,
|
23
|
+
formatter.duration(entity.duration),
|
24
|
+
formatter.time(entity.started_at),
|
25
|
+
formatter.time(entity.finished_at)
|
26
|
+
]
|
27
|
+
|
28
|
+
if entity.respond_to? :jobs
|
29
|
+
empty_line
|
30
|
+
entity.jobs.each do |job|
|
31
|
+
say [
|
32
|
+
color("##{job.number} #{job.state}:".ljust(16), [job.color, :bold]),
|
33
|
+
formatter.duration(job.duration).ljust(14),
|
34
|
+
formatter.job_config(job.config),
|
35
|
+
(color("(failure allowed)", :info) if job.allow_failures?)
|
36
|
+
].compact.join(" ").rstrip
|
37
|
+
end
|
38
|
+
else
|
39
|
+
config = formatter.job_config(entity.config)
|
40
|
+
say color("Allow Failure: ", :info) + entity.allow_failures?.inspect
|
41
|
+
say color("Config: ", :info) + config unless config.empty?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
__END__
|
49
|
+
|
50
|
+
<[[ color("%s #%s: ", :bold) ]]> <[[ color(%p, :bold) ]]>
|
51
|
+
<[[ color("State: ", :info) ]]><[[ color(%p, :%s) ]]>
|
52
|
+
<[[ color("Type: ", :info) ]]>%s
|
53
|
+
<[[ color("Branch: ", :info) ]]>%s
|
54
|
+
<[[ color("Compare URL: ", :info) ]]>%s
|
55
|
+
<[[ color("Duration: ", :info) ]]>%s
|
56
|
+
<[[ color("Started: ", :info) ]]>%s
|
57
|
+
<[[ color("Finished: ", :info) ]]>%s
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
require 'travis/tools/ssl_key'
|
3
|
+
require 'travis/tools/github'
|
4
|
+
|
5
|
+
module Travis
|
6
|
+
module CLI
|
7
|
+
class Sshkey < RepoCommand
|
8
|
+
description "checks, updates or deletes an SSH key"
|
9
|
+
on '-D', '--delete', 'remove SSH key'
|
10
|
+
on '-d', '--description DESCRIPTION', 'set description'
|
11
|
+
on '-u', '--upload FILE', 'upload key from given file'
|
12
|
+
on '-s', '--stdin', 'upload key read from stdin'
|
13
|
+
on '-c', '--check', 'set exit code depending on key existing'
|
14
|
+
on '-g', '--generate', 'generate SSH key and set up for given GitHub user'
|
15
|
+
on '-p', '--passphrase PASSPHRASE', 'pass phrase to decrypt with when using --upload'
|
16
|
+
|
17
|
+
def_delegators :repository, :ssh_key
|
18
|
+
|
19
|
+
def run
|
20
|
+
error "SSH keys are not available on #{color(session.config['host'], :bold)}" if org?
|
21
|
+
delete_key if delete?
|
22
|
+
update_key File.read(upload), upload if upload?
|
23
|
+
update_key $stdin.read, 'stdin' if stdin?
|
24
|
+
generate_key if generate?
|
25
|
+
display_key
|
26
|
+
end
|
27
|
+
|
28
|
+
def display_key
|
29
|
+
say "Current SSH key: #{color(ssh_key.description, :info)}"
|
30
|
+
say "Finger print: #{color(ssh_key.fingerprint, :info)}"
|
31
|
+
rescue Travis::Client::NotFound
|
32
|
+
say "No custom SSH key installed."
|
33
|
+
exit 1 if check?
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_key(value, file)
|
37
|
+
error "#{file} does not look like a private key" unless value.lines.first =~ /PRIVATE KEY/
|
38
|
+
value = remove_passphrase(value)
|
39
|
+
self.description ||= ask("Key description: ") { |q| q.default = "Custom Key" } if interactive?
|
40
|
+
say "Updating ssh key for #{color slug, :info} with key from #{color file, :info}"
|
41
|
+
empty_line
|
42
|
+
ssh_key.update(:value => value, :description => description || file)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete_key
|
46
|
+
return if interactive? and not danger_zone? "Remove SSH key for #{color slug, :info}?"
|
47
|
+
say "Removing ssh key for #{color slug, :info}"
|
48
|
+
ssh_key.delete
|
49
|
+
rescue Travis::Client::NotFound
|
50
|
+
warn "no key found to remove"
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate_key
|
54
|
+
github.with_basic_auth do |gh|
|
55
|
+
login = gh['user']['login']
|
56
|
+
check_access(gh)
|
57
|
+
empty_line
|
58
|
+
|
59
|
+
say "Generating RSA key."
|
60
|
+
private_key = Tools::SSLKey.generate_rsa
|
61
|
+
self.description ||= "key for fetching dependencies for #{slug} via #{login}"
|
62
|
+
|
63
|
+
say "Uploading public key to GitHub."
|
64
|
+
gh.post("/user/keys", :title => "#{description} (Travis CI)", :key => Tools::SSLKey.rsa_ssh(private_key.public_key))
|
65
|
+
|
66
|
+
say "Uploading private key to Travis CI."
|
67
|
+
ssh_key.update(:value => private_key.to_s, :description => description)
|
68
|
+
|
69
|
+
empty_line
|
70
|
+
say "You can store the private key to reuse it for other repositories (travis sshkey --upload FILE)."
|
71
|
+
if agree("Store private key? ") { |q| q.default = "no" }
|
72
|
+
path = ask("Path: ") { |q| q.default = "id_travis_rsa" }
|
73
|
+
File.write(path, private_key.to_s)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_passphrase(value)
|
79
|
+
return value unless Tools::SSLKey.has_passphrase? value
|
80
|
+
return Tools::SSLKey.remove_passphrase(value, passphrase) || error("wrong pass phrase") if passphrase
|
81
|
+
error "Key is encrypted, but missing --passphrase option" unless interactive?
|
82
|
+
say "The private key is protected by a pass phrase."
|
83
|
+
result = Tools::SSLKey.remove_passphrase(value, ask("Enter pass phrase: ") { |q| q.echo = "*" }) until result
|
84
|
+
empty_line
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
def check_access(gh)
|
89
|
+
gh["repos/#{slug}"]
|
90
|
+
rescue GH::Error
|
91
|
+
error "GitHub account has no read access to #{color slug, :bold}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def github
|
95
|
+
@github ||= begin
|
96
|
+
load_gh
|
97
|
+
Tools::Github.new(session.config['github']) do |g|
|
98
|
+
g.note = "token for fetching dependencies for #{slug} (Travis CI)"
|
99
|
+
g.explode = explode?
|
100
|
+
g.ask_login = proc { ask("Username: ") }
|
101
|
+
g.ask_password = proc { |user| ask("Password for #{user}: ") { |q| q.echo = "*" } }
|
102
|
+
g.ask_otp = proc { |user| ask("Two-factor authentication code for #{user}: ") }
|
103
|
+
g.login_header = proc { login_header }
|
104
|
+
g.debug = proc { |log| debug(log) }
|
105
|
+
g.after_tokens = proc { g.explode = true and error("no suitable github token found") }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def login_header
|
111
|
+
say "We need the #{color("GitHub login", :important)} for the account you want to add the key to."
|
112
|
+
say "This information will #{color("not be sent to Travis CI", :important)}, only to #{color(github_endpoint.host, :info)}."
|
113
|
+
say "The password will not be displayed."
|
114
|
+
empty_line
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Status < RepoCommand
|
6
|
+
description "checks status of the latest build"
|
7
|
+
|
8
|
+
on '-x', '--[no-]exit-code', 'sets the exit code to 1 if the build failed'
|
9
|
+
on '-q', '--[no-]quiet', 'does not print anything'
|
10
|
+
on '-p', '--[no-]fail-pending', 'sets the status code to 1 if the build is pending'
|
11
|
+
|
12
|
+
def run
|
13
|
+
say color(last_build.state, last_build.color), "build ##{last_build.number} %s" unless quiet?
|
14
|
+
exit 1 if exit_code? and last_build.unsuccessful?
|
15
|
+
exit 1 if fail_pending? and last_build.pending?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Sync < ApiCommand
|
6
|
+
description "triggers a new sync with GitHub"
|
7
|
+
|
8
|
+
on '-c', '--check', 'only check the sync status'
|
9
|
+
on '-b', '--background', 'will trigger sync but not block until sync is done'
|
10
|
+
on '-f', '--force', 'will force sync, even if one is already running'
|
11
|
+
|
12
|
+
def run
|
13
|
+
authenticate
|
14
|
+
|
15
|
+
if check?
|
16
|
+
say "#{"not " unless user.syncing?}syncing", "#{user.login} is currently %s"
|
17
|
+
elsif user.syncing? and not force?
|
18
|
+
error "user is already syncing"
|
19
|
+
elsif background?
|
20
|
+
say "starting synchronization"
|
21
|
+
sync(false)
|
22
|
+
else
|
23
|
+
say "synchronizing: "
|
24
|
+
sync
|
25
|
+
say color(" done", :success)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Whatsup < ApiCommand
|
6
|
+
description "lists most recent builds"
|
7
|
+
on('-m', '--my-repos', 'Only display my own repositories')
|
8
|
+
|
9
|
+
def run
|
10
|
+
say "nothing to show" if recent.empty?
|
11
|
+
|
12
|
+
recent.each do |repo|
|
13
|
+
say [
|
14
|
+
color(repo.slug, [:bold, repo.color]),
|
15
|
+
color("#{repo.last_build.state}: ##{repo.last_build.number}", repo.color)
|
16
|
+
].join(" ")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def recent
|
23
|
+
@recent ||= begin
|
24
|
+
recent = my_repos ? repos : repos(:member => user.login)
|
25
|
+
recent.select { |repo| repo.last_build }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Whoami < ApiCommand
|
6
|
+
description "outputs the current user"
|
7
|
+
|
8
|
+
def run
|
9
|
+
authenticate
|
10
|
+
name = " (#{user.name})" unless user.name.to_s.empty?
|
11
|
+
say user.login, "You are %s" << name.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/travis/cli.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
begin
|
2
|
+
require 'travis/client'
|
3
|
+
rescue LoadError => e
|
4
|
+
if e.message == 'no such file to load -- json'
|
5
|
+
$stderr.puts "You should either run `gem install json` or upgrade your Ruby version!"
|
6
|
+
exit 1
|
7
|
+
else
|
8
|
+
raise e
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'stringio'
|
13
|
+
|
14
|
+
module Travis
|
15
|
+
module CLI
|
16
|
+
autoload :Token, 'travis/cli/token'
|
17
|
+
autoload :ApiCommand, 'travis/cli/api_command'
|
18
|
+
autoload :Accounts, 'travis/cli/accounts'
|
19
|
+
autoload :Branches, 'travis/cli/branches'
|
20
|
+
autoload :Cache, 'travis/cli/cache'
|
21
|
+
autoload :Cancel, 'travis/cli/cancel'
|
22
|
+
autoload :Command, 'travis/cli/command'
|
23
|
+
autoload :Console, 'travis/cli/console'
|
24
|
+
autoload :Disable, 'travis/cli/disable'
|
25
|
+
autoload :Enable, 'travis/cli/enable'
|
26
|
+
autoload :Encrypt, 'travis/cli/encrypt'
|
27
|
+
autoload :EncryptFile, 'travis/cli/encrypt_file'
|
28
|
+
autoload :Endpoint, 'travis/cli/endpoint'
|
29
|
+
autoload :Env, 'travis/cli/env'
|
30
|
+
autoload :Help, 'travis/cli/help'
|
31
|
+
autoload :History, 'travis/cli/history'
|
32
|
+
autoload :Init, 'travis/cli/init'
|
33
|
+
autoload :Lint, 'travis/cli/lint'
|
34
|
+
autoload :Login, 'travis/cli/login'
|
35
|
+
autoload :Logout, 'travis/cli/logout'
|
36
|
+
autoload :Logs, 'travis/cli/logs'
|
37
|
+
autoload :Monitor, 'travis/cli/monitor'
|
38
|
+
autoload :Open, 'travis/cli/open'
|
39
|
+
autoload :Parser, 'travis/cli/parser'
|
40
|
+
autoload :Pubkey, 'travis/cli/pubkey'
|
41
|
+
autoload :Raw, 'travis/cli/raw'
|
42
|
+
autoload :RepoCommand, 'travis/cli/repo_command'
|
43
|
+
autoload :Report, 'travis/cli/report'
|
44
|
+
autoload :Repos, 'travis/cli/repos'
|
45
|
+
autoload :Restart, 'travis/cli/restart'
|
46
|
+
autoload :Requests, 'travis/cli/requests'
|
47
|
+
autoload :Settings, 'travis/cli/settings'
|
48
|
+
autoload :Setup, 'travis/cli/setup'
|
49
|
+
autoload :Show, 'travis/cli/show'
|
50
|
+
autoload :Sshkey, 'travis/cli/sshkey'
|
51
|
+
autoload :Status, 'travis/cli/status'
|
52
|
+
autoload :Sync, 'travis/cli/sync'
|
53
|
+
autoload :Version, 'travis/cli/version'
|
54
|
+
autoload :Whatsup, 'travis/cli/whatsup'
|
55
|
+
autoload :Whoami, 'travis/cli/whoami'
|
56
|
+
|
57
|
+
extend self
|
58
|
+
|
59
|
+
def run(*args)
|
60
|
+
args, opts = preparse(args)
|
61
|
+
name = args.shift unless args.empty?
|
62
|
+
command = command(name).new(opts)
|
63
|
+
command.parse(args)
|
64
|
+
command.execute
|
65
|
+
end
|
66
|
+
|
67
|
+
def command(name)
|
68
|
+
const_name = command_name(name)
|
69
|
+
constant = CLI.const_get(const_name) if const_name =~ /^[A-Z][A-Za-z]+$/ and const_defined? const_name
|
70
|
+
if command? constant
|
71
|
+
constant
|
72
|
+
else
|
73
|
+
$stderr.puts "unknown command #{name}"
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def commands
|
79
|
+
CLI.constants.map { |n| try_const_get(n) }.select { |c| command? c }
|
80
|
+
end
|
81
|
+
|
82
|
+
def silent
|
83
|
+
stderr, $stderr = $stderr, dummy_io
|
84
|
+
stdout, $stdout = $stdout, dummy_io
|
85
|
+
yield
|
86
|
+
ensure
|
87
|
+
$stderr = stderr if stderr
|
88
|
+
$stdout = stdout if stdout
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def try_const_get(name)
|
94
|
+
CLI.const_get(name)
|
95
|
+
rescue Exception
|
96
|
+
end
|
97
|
+
|
98
|
+
def dummy_io
|
99
|
+
return StringIO.new unless defined? IO::NULL and IO::NULL
|
100
|
+
File.open(IO::NULL, 'w')
|
101
|
+
end
|
102
|
+
|
103
|
+
def command?(constant)
|
104
|
+
constant.is_a? Class and constant < Command and not constant.abstract?
|
105
|
+
end
|
106
|
+
|
107
|
+
def command_name(name)
|
108
|
+
case name
|
109
|
+
when nil, '-h', '-?' then 'Help'
|
110
|
+
when '-v' then 'Version'
|
111
|
+
when /^--/ then command_name(name[2..-1])
|
112
|
+
else name.split('-').map(&:capitalize).join
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# can't use flatten as it will flatten hashes
|
117
|
+
def preparse(unparsed, args = [], opts = {})
|
118
|
+
case unparsed
|
119
|
+
when Hash then opts.merge! unparsed
|
120
|
+
when Array then unparsed.each { |e| preparse(e, args, opts) }
|
121
|
+
else args << unparsed.to_s
|
122
|
+
end
|
123
|
+
[args, opts]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|