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.
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