travis 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +154 -0
  3. data/Rakefile +38 -0
  4. data/bin/travis +4 -0
  5. data/lib/travis.rb +8 -0
  6. data/lib/travis/cacert.pem +3895 -0
  7. data/lib/travis/cli.rb +83 -0
  8. data/lib/travis/cli/api_command.rb +65 -0
  9. data/lib/travis/cli/command.rb +212 -0
  10. data/lib/travis/cli/encrypt.rb +57 -0
  11. data/lib/travis/cli/endpoint.rb +13 -0
  12. data/lib/travis/cli/help.rb +21 -0
  13. data/lib/travis/cli/login.rb +57 -0
  14. data/lib/travis/cli/parser.rb +43 -0
  15. data/lib/travis/cli/raw.rb +16 -0
  16. data/lib/travis/cli/repo_command.rb +54 -0
  17. data/lib/travis/cli/version.rb +12 -0
  18. data/lib/travis/cli/whoami.rb +12 -0
  19. data/lib/travis/client.rb +20 -0
  20. data/lib/travis/client/entity.rb +139 -0
  21. data/lib/travis/client/error.rb +11 -0
  22. data/lib/travis/client/methods.rb +45 -0
  23. data/lib/travis/client/namespace.rb +78 -0
  24. data/lib/travis/client/repository.rb +66 -0
  25. data/lib/travis/client/session.rb +191 -0
  26. data/lib/travis/client/user.rb +20 -0
  27. data/lib/travis/pro.rb +5 -0
  28. data/lib/travis/tools/token_finder.rb +51 -0
  29. data/lib/travis/version.rb +3 -0
  30. data/spec/cli/encrypt_spec.rb +18 -0
  31. data/spec/cli/endpoint_spec.rb +23 -0
  32. data/spec/cli/help_spec.rb +33 -0
  33. data/spec/cli/login_spec.rb +13 -0
  34. data/spec/cli/version_spec.rb +18 -0
  35. data/spec/cli/whoami_spec.rb +27 -0
  36. data/spec/client/methods_spec.rb +15 -0
  37. data/spec/client/namespace_spec.rb +19 -0
  38. data/spec/client/repository_spec.rb +15 -0
  39. data/spec/client/session_spec.rb +145 -0
  40. data/spec/client/user_spec.rb +16 -0
  41. data/spec/client_spec.rb +5 -0
  42. data/spec/pro_spec.rb +10 -0
  43. data/spec/spec_helper.rb +16 -0
  44. data/spec/support/fake_api.rb +89 -0
  45. data/spec/support/fake_github.rb +20 -0
  46. data/spec/support/helpers.rb +43 -0
  47. data/spec/travis_spec.rb +9 -0
  48. data/travis.gemspec +84 -0
  49. metadata +240 -0
@@ -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,13 @@
1
+ require 'travis/cli'
2
+
3
+ module Travis
4
+ module CLI
5
+ class Endpoint < ApiCommand
6
+ skip :authenticate
7
+
8
+ def run
9
+ say api_endpoint, "API endpoint: %s"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -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