travis 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.
- data/LICENSE +22 -0
- data/README.md +154 -0
- data/Rakefile +38 -0
- data/bin/travis +4 -0
- data/lib/travis.rb +8 -0
- data/lib/travis/cacert.pem +3895 -0
- data/lib/travis/cli.rb +83 -0
- data/lib/travis/cli/api_command.rb +65 -0
- data/lib/travis/cli/command.rb +212 -0
- data/lib/travis/cli/encrypt.rb +57 -0
- data/lib/travis/cli/endpoint.rb +13 -0
- data/lib/travis/cli/help.rb +21 -0
- data/lib/travis/cli/login.rb +57 -0
- data/lib/travis/cli/parser.rb +43 -0
- data/lib/travis/cli/raw.rb +16 -0
- data/lib/travis/cli/repo_command.rb +54 -0
- data/lib/travis/cli/version.rb +12 -0
- data/lib/travis/cli/whoami.rb +12 -0
- data/lib/travis/client.rb +20 -0
- data/lib/travis/client/entity.rb +139 -0
- data/lib/travis/client/error.rb +11 -0
- data/lib/travis/client/methods.rb +45 -0
- data/lib/travis/client/namespace.rb +78 -0
- data/lib/travis/client/repository.rb +66 -0
- data/lib/travis/client/session.rb +191 -0
- data/lib/travis/client/user.rb +20 -0
- data/lib/travis/pro.rb +5 -0
- data/lib/travis/tools/token_finder.rb +51 -0
- data/lib/travis/version.rb +3 -0
- data/spec/cli/encrypt_spec.rb +18 -0
- data/spec/cli/endpoint_spec.rb +23 -0
- data/spec/cli/help_spec.rb +33 -0
- data/spec/cli/login_spec.rb +13 -0
- data/spec/cli/version_spec.rb +18 -0
- data/spec/cli/whoami_spec.rb +27 -0
- data/spec/client/methods_spec.rb +15 -0
- data/spec/client/namespace_spec.rb +19 -0
- data/spec/client/repository_spec.rb +15 -0
- data/spec/client/session_spec.rb +145 -0
- data/spec/client/user_spec.rb +16 -0
- data/spec/client_spec.rb +5 -0
- data/spec/pro_spec.rb +10 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/fake_api.rb +89 -0
- data/spec/support/fake_github.rb +20 -0
- data/spec/support/helpers.rb +43 -0
- data/spec/travis_spec.rb +9 -0
- data/travis.gemspec +84 -0
- metadata +240 -0
data/lib/travis/cli.rb
ADDED
@@ -0,0 +1,83 @@
|
|
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 'gh'
|
13
|
+
GH.set(:ssl => Travis::Client::Session::SSL_OPTIONS)
|
14
|
+
|
15
|
+
module Travis
|
16
|
+
module CLI
|
17
|
+
autoload :ApiCommand, 'travis/cli/api_command'
|
18
|
+
autoload :Command, 'travis/cli/command'
|
19
|
+
autoload :Encrypt, 'travis/cli/encrypt'
|
20
|
+
autoload :Endpoint, 'travis/cli/endpoint'
|
21
|
+
autoload :Help, 'travis/cli/help'
|
22
|
+
autoload :Login, 'travis/cli/login'
|
23
|
+
autoload :Parser, 'travis/cli/parser'
|
24
|
+
autoload :Raw, 'travis/cli/raw'
|
25
|
+
autoload :RepoCommand, 'travis/cli/repo_command'
|
26
|
+
autoload :Version, 'travis/cli/version'
|
27
|
+
autoload :Whoami, 'travis/cli/whoami'
|
28
|
+
|
29
|
+
extend self
|
30
|
+
|
31
|
+
def windows?
|
32
|
+
RUBY_PLATFORM =~ /mswin|mingw/
|
33
|
+
end
|
34
|
+
|
35
|
+
def run(*args)
|
36
|
+
args, opts = preparse(args)
|
37
|
+
name = args.shift unless args.empty?
|
38
|
+
command = command(name).new(opts)
|
39
|
+
command.parse(args)
|
40
|
+
command.execute
|
41
|
+
end
|
42
|
+
|
43
|
+
def command(name)
|
44
|
+
const_name = command_name(name)
|
45
|
+
constant = CLI.const_get(const_name) if const_name =~ /^[A-Z][a-z]+$/ and const_defined? const_name
|
46
|
+
if command? constant
|
47
|
+
constant
|
48
|
+
else
|
49
|
+
$stderr.puts "unknown command #{name}"
|
50
|
+
exit 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def commands
|
55
|
+
CLI.constants.map { |n| CLI.const_get(n) }.select { |c| command? c }
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def command?(constant)
|
61
|
+
constant and constant < Command and not constant.abstract?
|
62
|
+
end
|
63
|
+
|
64
|
+
def command_name(name)
|
65
|
+
case name
|
66
|
+
when nil, '-h', '-?' then 'Help'
|
67
|
+
when '-v' then 'Version'
|
68
|
+
when /^--/ then command_name(name[2..-1])
|
69
|
+
else name.to_s.capitalize
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# can't use flatten as it will flatten hashes
|
74
|
+
def preparse(unparsed, args = [], opts = {})
|
75
|
+
case unparsed
|
76
|
+
when Hash then opts.merge! unparsed
|
77
|
+
when Array then unparsed.each { |e| preparse(e, args, opts) }
|
78
|
+
else args << unparsed.to_s
|
79
|
+
end
|
80
|
+
[args, opts]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class ApiCommand < Command
|
6
|
+
include Travis::Client::Methods
|
7
|
+
attr_reader :session
|
8
|
+
abstract
|
9
|
+
|
10
|
+
on('-e', '--api-endpoint URL', 'Travis API server to talk to')
|
11
|
+
on('--pro', "short-cut for --api-endpoint '#{Travis::Client::PRO_URI}'") { |c,_| c.api_endpoint = Travis::Client::PRO_URI }
|
12
|
+
on('--org', "short-cut for --api-endpoint '#{Travis::Client::ORG_URI}'") { |c,_| c.api_endpoint = Travis::Client::ORG_URI }
|
13
|
+
on('-t', '--token [ACCESS_TOKEN]', 'access token to use') { |c, t| c.access_token = t }
|
14
|
+
|
15
|
+
def initialize(*)
|
16
|
+
@session = Travis::Client.new
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def endpoint_config
|
21
|
+
config['endpoints'] ||= {}
|
22
|
+
config['endpoints'][api_endpoint] ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
self.access_token ||= fetch_token
|
27
|
+
endpoint_config['access_token'] ||= access_token
|
28
|
+
authenticate if pro?
|
29
|
+
end
|
30
|
+
|
31
|
+
def pro?
|
32
|
+
api_endpoint == Travis::Client::PRO_URI
|
33
|
+
end
|
34
|
+
|
35
|
+
def org?
|
36
|
+
api_endpoint == Travis::Client::ORG_URI
|
37
|
+
end
|
38
|
+
|
39
|
+
def detected_endpoint?
|
40
|
+
api_endpoint == detected_endpoint
|
41
|
+
end
|
42
|
+
|
43
|
+
def authenticate
|
44
|
+
error "not logged in, please run #{command("login#{endpoint_option}")}" if access_token.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def detected_endpoint
|
50
|
+
Travis::Client::ORG_URI
|
51
|
+
end
|
52
|
+
|
53
|
+
def endpoint_option
|
54
|
+
return "" if org? and detected_endpoint?
|
55
|
+
return " --org" if org?
|
56
|
+
return " --pro" if pro?
|
57
|
+
" -e %p" % api_endpoint
|
58
|
+
end
|
59
|
+
|
60
|
+
def fetch_token
|
61
|
+
return endpoint_config['access_token'] if endpoint_config['access_token']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
require 'highline'
|
3
|
+
require 'forwardable'
|
4
|
+
require 'delegate'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module Travis
|
8
|
+
module CLI
|
9
|
+
class Command
|
10
|
+
extend Parser
|
11
|
+
extend Forwardable
|
12
|
+
def_delegators :terminal, :agree, :ask, :choose
|
13
|
+
|
14
|
+
HighLine.use_color = !CLI.windows?
|
15
|
+
HighLine.color_scheme = HighLine::ColorScheme.new do |cs|
|
16
|
+
cs[:command] = [ :bold ]
|
17
|
+
cs[:error] = [ :red ]
|
18
|
+
cs[:important] = [ :bold, :underline ]
|
19
|
+
cs[:success] = [ :green ]
|
20
|
+
cs[:info] = [ :yellow ]
|
21
|
+
end
|
22
|
+
|
23
|
+
on('-h', '--help', 'Display help') do |c, _|
|
24
|
+
c.say c.help
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
on('-i', '--[no-]interactive', "be interactive and colorful") do |c, v|
|
29
|
+
c.force_interactive = v
|
30
|
+
end
|
31
|
+
|
32
|
+
on('-E', '--[no-]explode', "don't rescue exceptions")
|
33
|
+
|
34
|
+
def self.command_name
|
35
|
+
name[/[^:]*$/].downcase
|
36
|
+
end
|
37
|
+
|
38
|
+
@@abstract ||= [Command] # ignore the man behind the courtains!
|
39
|
+
def self.abstract?
|
40
|
+
@@abstract.include? self
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.abstract
|
44
|
+
@@abstract << self
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.skip(name)
|
48
|
+
define_method(name) {}
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_accessor :arguments, :config, :terminal, :force_interactive
|
52
|
+
|
53
|
+
def initialize(options = {})
|
54
|
+
@output = SimpleDelegator.new($stdout)
|
55
|
+
@input = SimpleDelegator.new($stdin)
|
56
|
+
@terminal = HighLine.new(@input, @output)
|
57
|
+
options.each do |key, value|
|
58
|
+
public_send("#{key}=", value) if respond_to? "#{key}="
|
59
|
+
end
|
60
|
+
@arguments ||= []
|
61
|
+
end
|
62
|
+
|
63
|
+
def input
|
64
|
+
@input.__getobj__
|
65
|
+
end
|
66
|
+
|
67
|
+
def input=(io)
|
68
|
+
@input.__setobj__(io)
|
69
|
+
end
|
70
|
+
|
71
|
+
def output
|
72
|
+
@output.__getobj__
|
73
|
+
end
|
74
|
+
|
75
|
+
def output=(io)
|
76
|
+
@output.__setobj__(io)
|
77
|
+
end
|
78
|
+
|
79
|
+
def write_to(io)
|
80
|
+
io_was, self.output = output, io
|
81
|
+
yield
|
82
|
+
ensure
|
83
|
+
self.output = io_was if io_was
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse(args)
|
87
|
+
rest = parser.parse(args)
|
88
|
+
arguments.concat(rest)
|
89
|
+
rescue OptionParser::ParseError => e
|
90
|
+
error e.message
|
91
|
+
end
|
92
|
+
|
93
|
+
def setup
|
94
|
+
end
|
95
|
+
|
96
|
+
def execute
|
97
|
+
check_arity(method(:run), *arguments)
|
98
|
+
load_config
|
99
|
+
setup
|
100
|
+
run(*arguments)
|
101
|
+
store_config
|
102
|
+
rescue StandardError => e
|
103
|
+
raise(e) if explode?
|
104
|
+
error e.message
|
105
|
+
end
|
106
|
+
|
107
|
+
def command_name
|
108
|
+
self.class.command_name
|
109
|
+
end
|
110
|
+
|
111
|
+
def usage
|
112
|
+
usage = "#$0 #{command_name} [options]"
|
113
|
+
method = method(:run)
|
114
|
+
if method.respond_to? :parameters
|
115
|
+
method.parameters.each do |type, name|
|
116
|
+
name = "[#{name}]" if type == :opt
|
117
|
+
name = "[#{name}..]" if type == :rest
|
118
|
+
usage << " #{name}"
|
119
|
+
end
|
120
|
+
else
|
121
|
+
usage << " ..."
|
122
|
+
end
|
123
|
+
"Usage: " << color(usage, :command)
|
124
|
+
end
|
125
|
+
|
126
|
+
def help
|
127
|
+
parser.banner = usage
|
128
|
+
parser.to_s
|
129
|
+
end
|
130
|
+
|
131
|
+
def say(data, format = nil)
|
132
|
+
data = format % color(data, :important) if format and interactive?
|
133
|
+
terminal.say data.gsub(/<\[\[/, '<%=').gsub(/\]\]>/, '%>')
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def template(file)
|
139
|
+
File.read(file).split('__END__', 2)[1].strip
|
140
|
+
end
|
141
|
+
|
142
|
+
def color(line, *args)
|
143
|
+
return line unless interactive?
|
144
|
+
terminal.color(line, *args)
|
145
|
+
end
|
146
|
+
|
147
|
+
def interactive?(io = output)
|
148
|
+
return io.tty? if force_interactive.nil?
|
149
|
+
force_interactive
|
150
|
+
end
|
151
|
+
|
152
|
+
def empty_line
|
153
|
+
say "\n"
|
154
|
+
end
|
155
|
+
|
156
|
+
def error(message)
|
157
|
+
write_to($stderr) do
|
158
|
+
say color(message, :error)
|
159
|
+
yield if block_given?
|
160
|
+
exit 1
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def command(name)
|
165
|
+
color("#$0 #{name}", :command)
|
166
|
+
end
|
167
|
+
|
168
|
+
def success(line)
|
169
|
+
say color(line, :success) if interactive?
|
170
|
+
end
|
171
|
+
|
172
|
+
def asset_path(name)
|
173
|
+
path = ENV.fetch('TRAVIS_CONFIG_PATH') { File.expand_path('.travis', Dir.home) }
|
174
|
+
Dir.mkdir(path, 0700) unless File.directory? path
|
175
|
+
File.join(path, name)
|
176
|
+
end
|
177
|
+
|
178
|
+
def load_asset(name, default = nil)
|
179
|
+
path = asset_path(name)
|
180
|
+
File.exist?(path) ? File.read(path) : default
|
181
|
+
end
|
182
|
+
|
183
|
+
def save_asset(name, content)
|
184
|
+
File.write(asset_path(name), content.to_s)
|
185
|
+
end
|
186
|
+
|
187
|
+
def load_config
|
188
|
+
@config = YAML.load load_asset('config.yml', '{}')
|
189
|
+
@original_config = @config.dup
|
190
|
+
end
|
191
|
+
|
192
|
+
def store_config
|
193
|
+
save_asset('config.yml', @config.to_yaml)
|
194
|
+
end
|
195
|
+
|
196
|
+
def check_arity(method, *args)
|
197
|
+
return unless method.respond_to? :parameters
|
198
|
+
method.parameters.each do |type, name|
|
199
|
+
return if type == :rest
|
200
|
+
wrong_args("few") unless args.shift or type == :opt
|
201
|
+
end
|
202
|
+
wrong_args("many") if args.any?
|
203
|
+
end
|
204
|
+
|
205
|
+
def wrong_args(quantity)
|
206
|
+
error "too #{quantity} arguments" do
|
207
|
+
say help
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'travis/cli'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Travis
|
6
|
+
module CLI
|
7
|
+
class Encrypt < RepoCommand
|
8
|
+
attr_accessor :config_key
|
9
|
+
|
10
|
+
on('--add [KEY]', 'adds it to .travis.yml under KEY (default: env.global)') do |c, value|
|
11
|
+
c.config_key = value || 'env.global'
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(*args)
|
15
|
+
data = args.join(" ")
|
16
|
+
|
17
|
+
if data.empty?
|
18
|
+
say color("Reading from stdin, press Ctrl+D when done", :info) if $stdin.tty?
|
19
|
+
data = $stdin.read
|
20
|
+
end
|
21
|
+
|
22
|
+
encrypted = repository.encrypt(data)
|
23
|
+
|
24
|
+
if config_key
|
25
|
+
travis_config = YAML.load_file(travis_yaml)
|
26
|
+
keys = config_key.split('.')
|
27
|
+
last_key = keys.pop
|
28
|
+
nested_config = keys.inject(travis_config) { |c,k| c[k] ||= {}}
|
29
|
+
nested_config[last_key] ||= [] << encrypted
|
30
|
+
File.write(travis_yaml, travis_config.to_yaml)
|
31
|
+
else
|
32
|
+
say encrypted.inspect, template(__FILE__)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def travis_yaml(dir = Dir.pwd)
|
39
|
+
path = File.expand_path('.travis.yml', dir)
|
40
|
+
if File.exist? path
|
41
|
+
path
|
42
|
+
else
|
43
|
+
parent = File.expand_path('..', dir)
|
44
|
+
travis_yaml(parent) if parent != dir
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
__END__
|
52
|
+
Please add the following to your <[[ color('.travis.yml', :info) ]]> file:
|
53
|
+
|
54
|
+
secure: %s
|
55
|
+
|
56
|
+
Pro Tip<[[ "™" unless Travis::CLI.windows? ]]>: You can add it automatically by running with <[[ color('--add', :info) ]]>.
|
57
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'travis/cli'
|
2
|
+
|
3
|
+
module Travis
|
4
|
+
module CLI
|
5
|
+
class Help < Command
|
6
|
+
def run(command = nil)
|
7
|
+
if command
|
8
|
+
say CLI.command(command).new.help
|
9
|
+
else
|
10
|
+
say "Usage: #$0 COMMAND ...\n\nAvailable commands:\n\n"
|
11
|
+
commands.each { |c| say "\t#{c.command_name}" }
|
12
|
+
say "\nrun `#$0 help COMMAND` for more infos"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def commands
|
17
|
+
CLI.commands.sort_by { |c| c.command_name }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|