lita-jls 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +24 -0
- data/Rakefile +6 -0
- data/lib/lita-jls.rb +8 -0
- data/lib/lita-jls/bot_builder.rb +240 -0
- data/lib/lita-jls/github_url_parser.rb +43 -0
- data/lib/lita-jls/repository.rb +57 -0
- data/lib/lita-jls/util.rb +259 -0
- data/lib/lita/handlers/jls.rb +321 -0
- data/lita-jls.gemspec +41 -0
- data/locales/en.yml +4 -0
- data/spec/fixtures/bad_project/Gemfile +2 -0
- data/spec/fixtures/logstash-codec-edn/logstash-codec-edn.gemspec +29 -0
- data/spec/fixtures/logstash.gemspec +3 -0
- data/spec/fixtures/project_with_version_file/lib/testmore/version.rb +3 -0
- data/spec/fixtures/project_with_version_file/project_with_version_file.gemspec +9 -0
- data/spec/fixtures/vcr_cassettes/fetch_version_of_logstash-output-s3.yml +96 -0
- data/spec/fixtures/vcr_cassettes/gem_doesnt_exist.yml +57 -0
- data/spec/fixtures/vcr_cassettes/successful_clacheck.yml +127 -0
- data/spec/fixtures/vcr_cassettes/successful_clacheck_long_commit.yml +133 -0
- data/spec/fixtures/vcr_cassettes/successful_migrate_pr.yml +81 -0
- data/spec/lita-jls/bot_builder_spec.rb +158 -0
- data/spec/lita-jls/github_url_parser_spec.rb +80 -0
- data/spec/lita/handlers/jls_spec.rb +211 -0
- data/spec/spec_helper.rb +31 -0
- metadata +338 -0
@@ -0,0 +1,321 @@
|
|
1
|
+
require "cabin"
|
2
|
+
require "tmpdir"
|
3
|
+
require "tempfile"
|
4
|
+
require "fileutils"
|
5
|
+
require "insist"
|
6
|
+
require "uri"
|
7
|
+
require "lita-jls/bot_builder"
|
8
|
+
require "lita-jls/repository"
|
9
|
+
require "lita-jls/github_url_parser"
|
10
|
+
require "lita-jls/util"
|
11
|
+
|
12
|
+
# TODO(sissel): This code needs some suuuper serious refactoring and testing improvements.
|
13
|
+
# TODO(sissel): Remove any usage of Rugged. This library requires compile-time
|
14
|
+
# settings of libgit2 and that's an annoying battle.
|
15
|
+
|
16
|
+
module Lita
|
17
|
+
module Handlers
|
18
|
+
class Jls < Handler
|
19
|
+
include LitaJLS::Util
|
20
|
+
|
21
|
+
route /^merge(?<dry>\?)? (?<pr_url>[^ ]+) (?<branchspec>.*)$/, :merge,
|
22
|
+
:command => true,
|
23
|
+
:help => { "merge https://github.com/ORG/PROJECT/pull/NUMBER branch1 [branch2 ...]" => "merges a PR into one or more branches. To see if a merge is successful, use 'merge? project#pr branch1 [branch2 ...]" }
|
24
|
+
|
25
|
+
route /^cla(?<dry>\?)? (?<pr_url>[^ ]+)$/, :cla,
|
26
|
+
:command => true,
|
27
|
+
:help => { "cla https://github.com/ORG/PROJECT/pull/NUMBER" => "CLA check for a giaven PR" }
|
28
|
+
|
29
|
+
route /^\(tableflip\)$/, :tableflip,
|
30
|
+
:command => true,
|
31
|
+
:help => { "(tableflip)" => "Fix whatever just broke. Probably git is going funky, so I will purge my local git junk" }
|
32
|
+
|
33
|
+
route /^ping/, :ping, :command => true
|
34
|
+
|
35
|
+
route /^publish\s(?<git_url>[^ ]+)$/, :publish,
|
36
|
+
:command => true,
|
37
|
+
:restrict_to => :logstash,
|
38
|
+
:help => { 'publish https://github.com/ORG/project' => 'Install dependencies, Run test, build gem, publish and compare version on rubygems' }
|
39
|
+
|
40
|
+
route /^(why computer(s?) so bad\?|explain)/i, :pop_exception,
|
41
|
+
:command => true,
|
42
|
+
:help => { 'explain or why computers so bad?' => 'return the last exception from redis' }
|
43
|
+
|
44
|
+
route /^migrate_pr (?<source_url>[^ ]+) (?<destination_url>[^ ]+)$/, :migrate_pr,
|
45
|
+
:command => true,
|
46
|
+
:help => { 'migrate_pr https://github.com/elasticsearch/logstash/pull/1452 "\
|
47
|
+
+ "https://github.com/logstash-plugins/logstash-codec-line' => 'migrate pr from one repo to another' }
|
48
|
+
|
49
|
+
REMOTE = "origin"
|
50
|
+
URLBASE = "https://github.com/"
|
51
|
+
LIMIT_EXCEPTIONS_HISTORY = 20
|
52
|
+
|
53
|
+
RUBY_VERSION = "jruby-1.7.16"
|
54
|
+
|
55
|
+
on :loaded, :setup
|
56
|
+
|
57
|
+
def self.default_config(config)
|
58
|
+
config.default_organization = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def pop_exception(msg)
|
62
|
+
public_response = ['Commencing automated assembly. Estimated completion time is five hours.',
|
63
|
+
'That is the only way, sir.',
|
64
|
+
'Sir, please may I request just a few hours to calibrate.' ]
|
65
|
+
|
66
|
+
e = @redis.lpop(:exception)
|
67
|
+
|
68
|
+
msg.reply(public_response.sample)
|
69
|
+
|
70
|
+
logger.debug("pop exception", :exception => e)
|
71
|
+
|
72
|
+
if e
|
73
|
+
e = JSON.parse(e)
|
74
|
+
|
75
|
+
msg.reply_privately("exception: #{e.delete('exception')}")
|
76
|
+
msg.reply_privately("message: #{e.delete('message')}")
|
77
|
+
msg.reply_privately("backtrace: #{e.delete('backtrace')}")
|
78
|
+
|
79
|
+
# Print the remaining context
|
80
|
+
e.each do |key, value|
|
81
|
+
msg.reply_privately("#{key}: #{value}")
|
82
|
+
end
|
83
|
+
else
|
84
|
+
msg.reply_privately("No exception saved.")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def push_exception(e, context = {})
|
89
|
+
error = {
|
90
|
+
"exception" => e.exception,
|
91
|
+
"message" => e.message,
|
92
|
+
"backtrace" => e.backtrace,
|
93
|
+
}.merge(context)
|
94
|
+
|
95
|
+
@redis.lpush(:exception, error.to_json)
|
96
|
+
@redis.ltrim(:exception, 0, LIMIT_EXCEPTIONS_HISTORY)
|
97
|
+
end
|
98
|
+
|
99
|
+
def publish(msg)
|
100
|
+
git_url = msg.match_data["git_url"]
|
101
|
+
|
102
|
+
logger.info('publish', :url => git_url)
|
103
|
+
|
104
|
+
github_parser = LitaJLS::GithubUrlParser.parse(git_url, :link => :repository)
|
105
|
+
github_parser.validate!
|
106
|
+
|
107
|
+
repository = LitaJLS::Repository.new(github_parser)
|
108
|
+
repository.clone
|
109
|
+
repository.switch_branch('master')
|
110
|
+
|
111
|
+
builder = LitaJLS::BotBuilder.new(repository.git_path, { :ruby_version => RUBY_VERSION })
|
112
|
+
|
113
|
+
msg.reply("publishing (allthethings) for project: #{builder.project_name} branch: master")
|
114
|
+
|
115
|
+
reporter = LitaJLS::Reporter::HipChat.new(builder.build)
|
116
|
+
reporter.format(msg)
|
117
|
+
rescue => e
|
118
|
+
push_exception(e, :project => "#{github_parser.user}/#{github_parser.project}")
|
119
|
+
msg.reply("(stare) Error: #{e.inspect}")
|
120
|
+
raise
|
121
|
+
end # def publish
|
122
|
+
|
123
|
+
def ping(msg)
|
124
|
+
msg.reply("(chompy)")
|
125
|
+
end
|
126
|
+
|
127
|
+
def setup(*args)
|
128
|
+
ENV["PAGER"] = "cat"
|
129
|
+
@@logger_subscription ||= logger.subscribe(STDOUT)
|
130
|
+
|
131
|
+
@redis ||= Redis::Namespace.new("opsbot", redis: Lita.redis)
|
132
|
+
end
|
133
|
+
|
134
|
+
def cla(msg)
|
135
|
+
@cla_uri = config.cla_uri
|
136
|
+
pull = msg.match_data["pr_url"]
|
137
|
+
pull_path = URI.parse(pull).path
|
138
|
+
_, user, project, _, pr = pull_path.split("/")
|
139
|
+
cla?("#{user}/#{project}", pr)
|
140
|
+
msg.reply("#{user}/#{project}##{pr} CLA OK (freddie)")
|
141
|
+
rescue => e
|
142
|
+
msg.reply("cla check error: #{e}")
|
143
|
+
push_exception(e, :project => "#{user}/#{project}", :pr => pr)
|
144
|
+
end
|
145
|
+
|
146
|
+
def migrate_pr(msg)
|
147
|
+
source_url = msg.match_data["source_url"]
|
148
|
+
destination_url = msg.match_data["destination_url"]
|
149
|
+
if source_url.nil? || destination_url.nil?
|
150
|
+
raise "Invalid paramaters provided #{msg}"
|
151
|
+
end
|
152
|
+
|
153
|
+
destination_github_parser = parse_github_url(destination_url)
|
154
|
+
source_github_parser = parse_github_url(source_url)
|
155
|
+
|
156
|
+
pr_num = source_github_parser.pr
|
157
|
+
source_github_pr = github_get_pr("#{source_github_parser.user}/#{source_github_parser.project}", pr_num)
|
158
|
+
|
159
|
+
# Clone destination dir, patch and then push branch
|
160
|
+
repository = LitaJLS::Repository.new(destination_github_parser)
|
161
|
+
repository.clone if Dir["#{repository.git_path}/*"].empty?
|
162
|
+
repository.switch_branch("master")
|
163
|
+
|
164
|
+
# create a branch like pr/1234
|
165
|
+
pr_branch = "bot-migrated-pr/#{pr_num}"
|
166
|
+
repository.delete_local_branch(pr_branch, true)
|
167
|
+
repository.switch_branch(pr_branch, true)
|
168
|
+
|
169
|
+
patch_file = download_patch(source_github_pr[:patch_url], pr_num)
|
170
|
+
|
171
|
+
# Apply patch on repo
|
172
|
+
begin
|
173
|
+
repository.git_patch(patch_file.path)
|
174
|
+
repository.git_push_branch(pr_branch)
|
175
|
+
rescue => e
|
176
|
+
msg.reply("Error while migrating pr: #{e}")
|
177
|
+
push_exception(e, :source_url => source_url,
|
178
|
+
:destination_url => destination_url)
|
179
|
+
ensure
|
180
|
+
patch_file.unlink
|
181
|
+
end
|
182
|
+
|
183
|
+
# create the migrated PR in the destination repo
|
184
|
+
github_create_pr("#{destination_github_parser.user}/#{destination_github_parser.project}",
|
185
|
+
pr_branch, source_github_pr[:title],
|
186
|
+
source_github_pr[:body] + "\nMoved from #{source_url}")
|
187
|
+
end
|
188
|
+
|
189
|
+
@private
|
190
|
+
# downloads the patch file in mail format and saves it to a file
|
191
|
+
def download_patch(pr_url, pr_num)
|
192
|
+
http = Faraday.new("https://github.com")
|
193
|
+
response = http.get(URI.parse(pr_url).path)
|
194
|
+
if response.status != 200
|
195
|
+
raise "Unable to fetch pull request #{pr_url}"
|
196
|
+
end
|
197
|
+
|
198
|
+
patch_file = Tempfile.new("#{pr_num}.patch")
|
199
|
+
|
200
|
+
begin
|
201
|
+
#TODO: Use chunked writes
|
202
|
+
patch_file.write(response.body)
|
203
|
+
patch_file.close
|
204
|
+
rescue => e
|
205
|
+
raise "Error while downloading pr: #{pr_url}, exception #{e}"
|
206
|
+
end
|
207
|
+
|
208
|
+
return patch_file
|
209
|
+
end
|
210
|
+
|
211
|
+
@private
|
212
|
+
def parse_github_url(url)
|
213
|
+
github_parser = LitaJLS::GithubUrlParser.parse(url, :link => :repository)
|
214
|
+
github_parser.validate!
|
215
|
+
return github_parser
|
216
|
+
end
|
217
|
+
|
218
|
+
def merge(msg)
|
219
|
+
@cla_uri = config.cla_uri
|
220
|
+
FileUtils.mkdir_p(workdir) unless File.directory?(workdir)
|
221
|
+
pull = msg.match_data["pr_url"]
|
222
|
+
pull_path = URI.parse(pull).path
|
223
|
+
_, user, project, _, pr = pull_path.split("/")
|
224
|
+
|
225
|
+
if user.nil? || project.nil? || pr.nil? || pull !~ /^https:\/\/github.com\//
|
226
|
+
raise "Invalid URL. Expected something like: https://github.com/elasticsearch/snacktime/pull/12345"
|
227
|
+
end
|
228
|
+
|
229
|
+
branchspec = msg.match_data["branchspec"]
|
230
|
+
dry_run = msg.match_data["dry"]
|
231
|
+
|
232
|
+
begin
|
233
|
+
cla?("#{user}/#{project}", pr)
|
234
|
+
rescue => e
|
235
|
+
msg.reply("(firstworldproblems) cla check failed for #{user}/#{project}##{pr}.\n #{e}")
|
236
|
+
push_exception(e, :project => "#{user}/#{project}", :pr => pr)
|
237
|
+
return
|
238
|
+
end
|
239
|
+
|
240
|
+
url = File.join(URLBASE, user, project)
|
241
|
+
#git_url = "git@github.com:/#{user}/#{project}.git"
|
242
|
+
git_url = url
|
243
|
+
pr_url = File.join(url, "pull", "#{pr}.patch")
|
244
|
+
gitpath = gitdir(project)
|
245
|
+
branches = branchspec.split(/\s+/)
|
246
|
+
|
247
|
+
logger.info("Cloning git repo", :url => git_url, :gitpath => gitpath)
|
248
|
+
repo = clone_at(git_url, gitpath)
|
249
|
+
|
250
|
+
git(gitpath, "am", "--abort") if File.directory?(".git/rebase-apply")
|
251
|
+
|
252
|
+
# TODO(sissel): Fetch the PR patch
|
253
|
+
logger.info("Fetching PR patch", :url => pr_url)
|
254
|
+
http = Faraday.new("https://github.com")
|
255
|
+
response = http.get(URI.parse(pr_url).path)
|
256
|
+
if !response.success?
|
257
|
+
logger.warn("Failed fetching patch", :url => pr_url, :status => response.status, :headers => response.headers)
|
258
|
+
msg.reply("(grumpycat) Failed fetching patch. Cannot continue!")
|
259
|
+
return
|
260
|
+
end
|
261
|
+
|
262
|
+
patch = response.body
|
263
|
+
|
264
|
+
# For each branch, try to merge
|
265
|
+
repo = gitpath
|
266
|
+
branches.each do |branch|
|
267
|
+
begin
|
268
|
+
logger.info("Switching branches", :branch => branch, :repo => gitpath)
|
269
|
+
git(gitpath, "checkout", branch)
|
270
|
+
git(gitpath, "reset", "--hard", "#{REMOTE}/#{branch}")
|
271
|
+
git(gitpath, "pull", "--ff-only")
|
272
|
+
apply_patch(repo, patch) do |commit|
|
273
|
+
# Append the PR number to commit message
|
274
|
+
|
275
|
+
# Use "Fixes #XYZ" to make the PR get closed upon commit.
|
276
|
+
# https://help.github.com/articles/closing-issues-via-commit-messages
|
277
|
+
commit[:message] += "\nFixes ##{pr}"
|
278
|
+
end
|
279
|
+
rescue => e
|
280
|
+
push_exception(e, :project => "#{user}/#{project}", :pr => pr, :branch => branch)
|
281
|
+
msg.reply("(jackie) Failed attempting to merge #{user}/#{project}##{pr} into #{branch}: #{e}")
|
282
|
+
raise
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# At this point, all branches merged successfully. Time to push!
|
287
|
+
if dry_run
|
288
|
+
msg.reply("(success) Merging was successful #{user}/#{project}##{pr} into: #{branchspec}.\n(but I did not push it)")
|
289
|
+
else
|
290
|
+
msg.reply("(success) #{user}/#{project}##{pr} merged into: #{branchspec}")
|
291
|
+
git(gitpath, "push", REMOTE, *branches)
|
292
|
+
|
293
|
+
labels = branches.reject { |b| b == "master" }
|
294
|
+
github_issue_label("#{user}/#{project}", pr.to_i, labels)
|
295
|
+
end
|
296
|
+
github_issue_comment("#{user}/#{project}", pr.to_i, "Merged sucessfully into #{branchspec}!")
|
297
|
+
rescue => e
|
298
|
+
push_exception(e, :project => "#{user}/#{project}", :pr => pr, :branch => branches)
|
299
|
+
msg.reply("(stare) Error: #{e.inspect}")
|
300
|
+
raise
|
301
|
+
end # def merge
|
302
|
+
|
303
|
+
def tableflip(msg)
|
304
|
+
logger.debug("(fliptable), remove the git directory")
|
305
|
+
|
306
|
+
begin
|
307
|
+
dir = workdir("gitbase")
|
308
|
+
insist { dir } =~ /\/lita-jls/ # Just in case, before we go purging things...
|
309
|
+
FileUtils.rm_r(dir) if File.directory?(dir)
|
310
|
+
msg.reply("Git: (tableflip) (success)")
|
311
|
+
rescue => e
|
312
|
+
push_exception(e)
|
313
|
+
msg.reply("Git: (tableflip) (huh): #{e}")
|
314
|
+
raise e
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end # class Jls
|
318
|
+
|
319
|
+
Lita.register_handler(Jls)
|
320
|
+
end
|
321
|
+
end
|
data/lita-jls.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "lita-jls"
|
3
|
+
spec.version = "0.0.11"
|
4
|
+
spec.authors = ["Jordan Sissel"]
|
5
|
+
spec.email = ["jls@semicomplete.com"]
|
6
|
+
spec.description = %q{Some stuff for the lita.io bot}
|
7
|
+
spec.summary = spec.description
|
8
|
+
spec.homepage = "http://example.com/"
|
9
|
+
spec.license = "MIT"
|
10
|
+
spec.metadata = { "lita_plugin_type" => "handler" }
|
11
|
+
|
12
|
+
spec.files = `git ls-files`.split($/)
|
13
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
14
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
15
|
+
spec.require_paths = ["lib"]
|
16
|
+
|
17
|
+
spec.add_runtime_dependency "lita", ">= 3.3"
|
18
|
+
spec.add_runtime_dependency "cabin", ">= 0"
|
19
|
+
spec.add_runtime_dependency "faraday", ">= 0"
|
20
|
+
|
21
|
+
# For access to Github's api
|
22
|
+
spec.add_runtime_dependency "octokit", ">= 0"
|
23
|
+
# For netrc support in octokit
|
24
|
+
spec.add_runtime_dependency "netrc"
|
25
|
+
|
26
|
+
# For parsing github's .patch files (mbox format)
|
27
|
+
spec.add_runtime_dependency "mbox", ">= 0"
|
28
|
+
spec.add_runtime_dependency "insist"
|
29
|
+
spec.add_runtime_dependency 'gems', '~> 0.8.3'
|
30
|
+
spec.add_runtime_dependency 'semverly', '~> 1.0.0'
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
33
|
+
spec.add_development_dependency "rake"
|
34
|
+
spec.add_development_dependency "stud"
|
35
|
+
spec.add_development_dependency "rspec", ">= 3.0.0"
|
36
|
+
spec.add_development_dependency "simplecov"
|
37
|
+
spec.add_development_dependency "pry"
|
38
|
+
spec.add_development_dependency "coveralls"
|
39
|
+
spec.add_development_dependency "vcr"
|
40
|
+
spec.add_development_dependency "webmock"
|
41
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
|
3
|
+
s.name = 'logstash-codec-edn'
|
4
|
+
s.version = '0.1.3'
|
5
|
+
s.licenses = ['Apache License (2.0)']
|
6
|
+
s.summary = "Codec to process EDN data"
|
7
|
+
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
8
|
+
s.authors = ["Elasticsearch"]
|
9
|
+
s.email = 'info@elasticsearch.com'
|
10
|
+
s.homepage = "http://www.elasticsearch.org/guide/en/logstash/current/index.html"
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
|
13
|
+
# Files
|
14
|
+
s.files = `git ls-files`.split($\)
|
15
|
+
|
16
|
+
# Tests
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
|
19
|
+
# Special flag to let us know this is actually a logstash plugin
|
20
|
+
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "codec" }
|
21
|
+
|
22
|
+
# Gem dependencies
|
23
|
+
s.add_runtime_dependency 'logstash', '>= 1.4.0', '< 2.0.0'
|
24
|
+
|
25
|
+
s.add_runtime_dependency 'edn'
|
26
|
+
|
27
|
+
s.add_development_dependency 'logstash-devutils'
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'testmore/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dummy-gem-dont-publish"
|
8
|
+
spec.version = Testmore::VERSION
|
9
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://rubygems.org/api/v1/versions/logstash-output-s3.yaml
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Gems 0.8.3
|
16
|
+
- Ruby
|
17
|
+
Connection:
|
18
|
+
- keep-alive
|
19
|
+
Keep-Alive:
|
20
|
+
- '30'
|
21
|
+
Content-Type:
|
22
|
+
- application/x-www-form-urlencoded
|
23
|
+
response:
|
24
|
+
status:
|
25
|
+
code: 200
|
26
|
+
message: OK
|
27
|
+
headers:
|
28
|
+
Server:
|
29
|
+
- nginx
|
30
|
+
Date:
|
31
|
+
- Tue, 16 Dec 2014 16:12:50 GMT
|
32
|
+
Content-Type:
|
33
|
+
- text/yaml
|
34
|
+
Transfer-Encoding:
|
35
|
+
- chunked
|
36
|
+
Connection:
|
37
|
+
- keep-alive
|
38
|
+
Status:
|
39
|
+
- 200 OK
|
40
|
+
Etag:
|
41
|
+
- '"7341898c9b8c18bb4a2f72cafa13f98e"'
|
42
|
+
Last-Modified:
|
43
|
+
- Thu, 06 Nov 2014 09:33:38 GMT
|
44
|
+
Content-Disposition:
|
45
|
+
- attachment
|
46
|
+
Content-Transfer-Encoding:
|
47
|
+
- binary
|
48
|
+
Cache-Control:
|
49
|
+
- private
|
50
|
+
X-Content-Type-Options:
|
51
|
+
- nosniff
|
52
|
+
X-Ua-Compatible:
|
53
|
+
- IE=Edge,chrome=1
|
54
|
+
- IE=Edge,chrome=1
|
55
|
+
X-Request-Id:
|
56
|
+
- e726d0892877a0b310402be784f88add
|
57
|
+
X-Runtime:
|
58
|
+
- '0.012082'
|
59
|
+
X-Rack-Cache:
|
60
|
+
- miss
|
61
|
+
body:
|
62
|
+
encoding: UTF-8
|
63
|
+
string: |
|
64
|
+
---
|
65
|
+
- authors: Elasticsearch
|
66
|
+
built_at: '2014-11-19T00:00:00Z'
|
67
|
+
description: This gem is a logstash plugin required to be installed on top of the
|
68
|
+
Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is
|
69
|
+
not a stand-alone program
|
70
|
+
downloads_count: 479
|
71
|
+
number: 0.1.1
|
72
|
+
summary: This plugin was created for store the logstash's events into Amazon Simple
|
73
|
+
Storage Service (Amazon S3)
|
74
|
+
platform: ruby
|
75
|
+
ruby_version: '>= 0'
|
76
|
+
prerelease: false
|
77
|
+
licenses:
|
78
|
+
- Apache License (2.0)
|
79
|
+
requirements: []
|
80
|
+
- authors: Elasticsearch
|
81
|
+
built_at: '2014-11-06T00:00:00Z'
|
82
|
+
description: This plugin was created for store the logstash's events into Amazon
|
83
|
+
Simple Storage Service (Amazon S3)
|
84
|
+
downloads_count: 195
|
85
|
+
number: 0.1.0
|
86
|
+
summary: This plugin was created for store the logstash's events into Amazon Simple
|
87
|
+
Storage Service (Amazon S3)
|
88
|
+
platform: ruby
|
89
|
+
ruby_version: '>= 0'
|
90
|
+
prerelease: false
|
91
|
+
licenses:
|
92
|
+
- Apache License (2.0)
|
93
|
+
requirements: []
|
94
|
+
http_version:
|
95
|
+
recorded_at: Tue, 16 Dec 2014 16:12:51 GMT
|
96
|
+
recorded_with: VCR 2.9.3
|