bugsnag-capistrano 1.1.0 → 2.1.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.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE/A.md +14 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +50 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
- data/.github/support.md +22 -0
- data/.github/workflows/tests.yml +34 -0
- data/CHANGELOG.md +25 -0
- data/CONTRIBUTING.md +2 -1
- data/Gemfile +6 -3
- data/README.md +1 -3
- data/Rakefile +1 -19
- data/UPGRADING.md +27 -0
- data/VERSION +1 -1
- data/lib/bugsnag-capistrano/capistrano.rb +1 -1
- data/lib/bugsnag-capistrano/capistrano2.rb +14 -11
- data/lib/bugsnag-capistrano/release.rb +85 -0
- data/lib/bugsnag-capistrano/tasks/bugsnag.cap +13 -17
- data/spec/capistrano_spec.rb +93 -42
- data/spec/helpers/capistrano.rb +71 -0
- data/spec/helpers/server.rb +63 -0
- data/spec/release_spec.rb +94 -0
- data/spec/spec_helper.rb +2 -0
- metadata +15 -10
- data/.travis.yml +0 -77
- data/lib/bugsnag-capistrano/deploy.rb +0 -98
- data/lib/bugsnag-capistrano/tasks.rb +0 -2
- data/lib/bugsnag-capistrano/tasks/bugsnag-capistrano.rake +0 -85
- data/spec/deploy_spec.rb +0 -66
- data/spec/rake_spec.rb +0 -64
@@ -1,46 +1,42 @@
|
|
1
1
|
namespace :load do
|
2
|
-
|
3
2
|
task :defaults do
|
4
|
-
|
5
3
|
set :bugsnag_default_hooks, ->{ true }
|
6
|
-
|
7
4
|
end
|
8
|
-
|
9
5
|
end
|
10
6
|
|
11
7
|
namespace :deploy do
|
12
|
-
|
13
8
|
before :starting, :bugsnag_hooks do
|
14
9
|
invoke 'bugsnag:add_default_hooks' if fetch(:bugsnag_default_hooks)
|
15
10
|
end
|
16
|
-
|
17
11
|
end
|
18
12
|
|
19
13
|
namespace :bugsnag do
|
20
|
-
|
21
14
|
task :add_default_hooks do
|
22
|
-
after 'deploy:published', 'bugsnag:
|
15
|
+
after 'deploy:published', 'bugsnag:release'
|
23
16
|
end
|
24
17
|
|
25
|
-
desc 'Notify Bugsnag that new production code has been
|
26
|
-
task :
|
18
|
+
desc 'Notify Bugsnag that new production code has been released'
|
19
|
+
task :release do
|
27
20
|
run_locally do
|
28
21
|
begin
|
29
|
-
|
22
|
+
auto_assign_release_bool = ENV["BUGSNAG_AUTO_ASSIGN_RELEASE"] == 'true'
|
23
|
+
Bugsnag::Capistrano::Release.notify({
|
30
24
|
:api_key => fetch(:bugsnag_api_key, ENV["BUGSNAG_API_KEY"]),
|
25
|
+
:app_version => fetch(:app_version, ENV["BUGSNAG_APP_VERSION"]),
|
26
|
+
:auto_assign_release => fetch(:bugsnag_auto_assign_release, auto_assign_release_bool),
|
27
|
+
:builder_name => fetch(:bugsnag_builder, ENV["BUGSNAG_BUILDER_NAME"] || ENV["USER"]),
|
28
|
+
:metadata => fetch(:bugsnag_metadata),
|
31
29
|
:release_stage => fetch(:bugsnag_env) || ENV["BUGSNAG_RELEASE_STAGE"] || fetch(:rails_env) || fetch(:stage) || "production",
|
32
30
|
:revision => fetch(:current_revision, ENV["BUGSNAG_REVISION"]),
|
33
|
-
:repository => fetch(:repo_url, ENV["BUGSNAG_REPOSITORY"]),
|
34
|
-
:
|
35
|
-
:app_version => fetch(:app_version, ENV["BUGSNAG_APP_VERSION"]),
|
31
|
+
:repository => fetch(:bugsnag_repo_url, fetch(:repo_url, ENV["BUGSNAG_REPOSITORY"])),
|
32
|
+
:source_control_provider => fetch(:bugsnag_source_control_provider, ENV["BUGSNAG_SOURCE_CONTROL_PROVIDER"]),
|
36
33
|
:endpoint => fetch(:bugsnag_endpoint)
|
37
34
|
})
|
38
|
-
info 'Bugsnag
|
35
|
+
info 'Bugsnag release notification complete.'
|
39
36
|
rescue
|
40
|
-
error "Bugsnag
|
37
|
+
error "Bugsnag release notification failed, #{$!.inspect}"
|
41
38
|
end
|
42
39
|
end
|
43
40
|
end
|
44
|
-
|
45
41
|
end
|
46
42
|
# vi:ft=ruby
|
data/spec/capistrano_spec.rb
CHANGED
@@ -1,65 +1,116 @@
|
|
1
|
-
|
2
|
-
require 'rspec/expectations'
|
3
|
-
require 'rspec/mocks'
|
4
|
-
|
5
|
-
require 'webrick'
|
6
|
-
|
7
|
-
describe "bugsnag capistrano", :always do
|
8
|
-
|
9
|
-
server = nil
|
10
|
-
queue = Queue.new
|
11
|
-
cap_2 = ENV['CAP_2_TEST'] == 'true'
|
12
|
-
fixture_path = cap_2 ? '../examples/capistrano2' : '../examples/capistrano3'
|
13
|
-
exec_string = cap_2 ? 'bundle exec cap deploy' : 'bundle exec cap test deploy'
|
14
|
-
example_path = File.join(File.dirname(__FILE__), fixture_path)
|
15
|
-
|
16
|
-
before do
|
17
|
-
server = WEBrick::HTTPServer.new :Port => 0, :Logger => WEBrick::Log.new(STDOUT), :AccessLog => []
|
18
|
-
server.mount_proc '/deploy' do |req, res|
|
19
|
-
queue.push req.body
|
20
|
-
res.status = 200
|
21
|
-
res.body = "OK\n"
|
22
|
-
end
|
23
|
-
Thread.new{ server.start }
|
24
|
-
end
|
1
|
+
require_relative './spec_helper'
|
25
2
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
3
|
+
describe "bugsnag capistrano" do
|
4
|
+
server = Helpers::Server.new
|
5
|
+
|
6
|
+
before { server.start }
|
7
|
+
after { server.stop }
|
30
8
|
|
31
|
-
let(:request) { JSON.parse(queue.pop) }
|
32
|
-
|
33
9
|
it "sends a deploy notification to the set endpoint" do
|
34
|
-
ENV['BUGSNAG_ENDPOINT'] =
|
35
|
-
|
36
|
-
|
37
|
-
|
10
|
+
ENV['BUGSNAG_ENDPOINT'] = server.url
|
11
|
+
ENV['BUGSNAG_APP_VERSION'] = "1"
|
12
|
+
|
13
|
+
Dir.chdir(Helpers::Capistrano.example_path) do
|
14
|
+
system(Helpers::Capistrano.deploy_command)
|
38
15
|
end
|
39
16
|
|
40
|
-
payload =
|
17
|
+
payload = server.last_request
|
41
18
|
expect(payload["apiKey"]).to eq('YOUR_API_KEY')
|
19
|
+
expect(payload["appVersion"]).to eq("1")
|
42
20
|
expect(payload["releaseStage"]).to eq('production')
|
43
21
|
end
|
44
22
|
|
45
23
|
it "allows modifications of deployment characteristics" do
|
46
|
-
ENV['BUGSNAG_ENDPOINT'] =
|
24
|
+
ENV['BUGSNAG_ENDPOINT'] = server.url
|
47
25
|
ENV['BUGSNAG_API_KEY'] = "this is a test key"
|
48
26
|
ENV['BUGSNAG_RELEASE_STAGE'] = "test"
|
49
27
|
ENV['BUGSNAG_REVISION'] = "test"
|
50
28
|
ENV['BUGSNAG_APP_VERSION'] = "1"
|
51
29
|
ENV['BUGSNAG_REPOSITORY'] = "test@repo.com:test/test_repo.git"
|
30
|
+
ENV['BUGSNAG_SOURCE_CONTROL_PROVIDER'] = "github"
|
31
|
+
ENV['BUGSNAG_AUTO_ASSIGN_RELEASE'] = 'true'
|
52
32
|
|
53
|
-
Dir.chdir(example_path) do
|
54
|
-
system(
|
33
|
+
Dir.chdir(Helpers::Capistrano.example_path) do
|
34
|
+
system(Helpers::Capistrano.deploy_command)
|
55
35
|
end
|
56
36
|
|
57
|
-
payload =
|
37
|
+
payload = server.last_request
|
58
38
|
expect(payload["apiKey"]).to eq('this is a test key')
|
59
39
|
expect(payload["releaseStage"]).to eq('test')
|
60
|
-
expect(payload["repository"]).to eq("test@repo.com:test/test_repo.git")
|
61
40
|
expect(payload["appVersion"]).to eq("1")
|
62
|
-
expect(payload["
|
41
|
+
expect(payload["sourceControl"]).to_not be_nil
|
42
|
+
expect(payload["sourceControl"]["revision"]).to eq("test")
|
43
|
+
expect(payload["sourceControl"]["repository"]).to eq("test@repo.com:test/test_repo.git")
|
44
|
+
expect(payload["sourceControl"]["provider"]).to eq("github")
|
45
|
+
expect(payload["autoAssignRelease"]).to eq(true)
|
63
46
|
end
|
64
|
-
end
|
65
47
|
|
48
|
+
it "uses 'repo_url' in preference to 'BUGSNAG_REPOSITORY'" do
|
49
|
+
ENV['BUGSNAG_REPOSITORY'] = "unused@repo.com:unused/unused_repo.git"
|
50
|
+
|
51
|
+
capfile = Helpers::Capistrano.generate_capfile({
|
52
|
+
bugsnag_api_key: "this is a test key",
|
53
|
+
app_version: "1",
|
54
|
+
bugsnag_auto_assign_release: true,
|
55
|
+
bugsnag_builder: "bob",
|
56
|
+
bugsnag_metadata: { a: 1, b: 2 },
|
57
|
+
bugsnag_env: "test",
|
58
|
+
current_revision: "test1234",
|
59
|
+
repo_url: "test@repo.com:test/test_repo.git",
|
60
|
+
bugsnag_source_control_provider: "github",
|
61
|
+
bugsnag_endpoint: server.url,
|
62
|
+
})
|
63
|
+
|
64
|
+
Helpers::Capistrano.run(capfile)
|
65
|
+
|
66
|
+
payload = server.last_request
|
67
|
+
|
68
|
+
expect(payload["apiKey"]).to eq('this is a test key')
|
69
|
+
expect(payload["appVersion"]).to eq("1")
|
70
|
+
expect(payload["autoAssignRelease"]).to eq(true)
|
71
|
+
expect(payload["builderName"]).to eq("bob")
|
72
|
+
expect(payload["buildTool"]).to eq("bugsnag-capistrano")
|
73
|
+
expect(payload["metadata"]).to eq({ "a" => 1, "b" => 2 })
|
74
|
+
expect(payload["releaseStage"]).to eq("test")
|
75
|
+
expect(payload["sourceControl"]).to eq({
|
76
|
+
"revision" => "test1234",
|
77
|
+
"repository" => "test@repo.com:test/test_repo.git",
|
78
|
+
"provider" => "github",
|
79
|
+
})
|
80
|
+
end
|
81
|
+
|
82
|
+
it "uses 'bugsnag_repo_url' in preference to 'repo_url'" do
|
83
|
+
ENV['BUGSNAG_REPOSITORY'] = "unused@repo.com:unused/unused_repo.git"
|
84
|
+
|
85
|
+
capfile = Helpers::Capistrano.generate_capfile({
|
86
|
+
bugsnag_api_key: "this is a test key",
|
87
|
+
app_version: "1",
|
88
|
+
bugsnag_auto_assign_release: true,
|
89
|
+
bugsnag_builder: "bob",
|
90
|
+
bugsnag_metadata: { a: 1, b: 2 },
|
91
|
+
bugsnag_env: "test",
|
92
|
+
current_revision: "test1234",
|
93
|
+
repo_url: "test@repo.com:test/test_repo.git",
|
94
|
+
bugsnag_repo_url: "https://repo.com/test/test_repo.git",
|
95
|
+
bugsnag_source_control_provider: "github",
|
96
|
+
bugsnag_endpoint: server.url,
|
97
|
+
})
|
98
|
+
|
99
|
+
Helpers::Capistrano.run(capfile)
|
100
|
+
|
101
|
+
payload = server.last_request
|
102
|
+
|
103
|
+
expect(payload["apiKey"]).to eq('this is a test key')
|
104
|
+
expect(payload["appVersion"]).to eq("1")
|
105
|
+
expect(payload["autoAssignRelease"]).to eq(true)
|
106
|
+
expect(payload["builderName"]).to eq("bob")
|
107
|
+
expect(payload["buildTool"]).to eq("bugsnag-capistrano")
|
108
|
+
expect(payload["metadata"]).to eq({ "a" => 1, "b" => 2 })
|
109
|
+
expect(payload["releaseStage"]).to eq("test")
|
110
|
+
expect(payload["sourceControl"]).to eq({
|
111
|
+
"revision" => "test1234",
|
112
|
+
"repository" => "https://repo.com/test/test_repo.git",
|
113
|
+
"provider" => "github",
|
114
|
+
})
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Helpers
|
5
|
+
class Capistrano
|
6
|
+
def self.version_2?
|
7
|
+
ENV['CAP_2_TEST'] == 'true'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.deploy_command
|
11
|
+
return 'bundle exec cap deploy' if version_2?
|
12
|
+
|
13
|
+
'bundle exec cap test deploy'
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.example_path
|
17
|
+
fixture_path = version_2? ? '../../examples/capistrano2' : '../../examples/capistrano3'
|
18
|
+
|
19
|
+
File.join(File.dirname(__FILE__), fixture_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.generate_capfile(variables)
|
23
|
+
return generate_v2_capfile(variables) if version_2?
|
24
|
+
|
25
|
+
capfile = <<-RUBY.gsub(/^\s+/, "")
|
26
|
+
require "capistrano/setup"
|
27
|
+
|
28
|
+
require "capistrano/deploy"
|
29
|
+
require "capistrano/scm/git"
|
30
|
+
install_plugin Capistrano::SCM::Git
|
31
|
+
|
32
|
+
require "bugsnag-capistrano"
|
33
|
+
RUBY
|
34
|
+
|
35
|
+
# add calls to set each variable - "set(:key, value)"
|
36
|
+
variables.each do |key, value|
|
37
|
+
capfile << "set(:#{key}, #{value.inspect})\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
capfile
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.generate_v2_capfile(variables)
|
44
|
+
capfile = "require 'bugsnag-capistrano'\n"
|
45
|
+
|
46
|
+
# add calls to set each variable - "set(:key, value)"
|
47
|
+
variables.each do |key, value|
|
48
|
+
capfile << "set(:#{key}, #{value.inspect})\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
# add an empty deploy task
|
52
|
+
capfile << "task :deploy do\nend"
|
53
|
+
|
54
|
+
capfile
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.run(capfile)
|
58
|
+
Dir.mktmpdir do |path|
|
59
|
+
FileUtils.cp_r("#{example_path}/.", path)
|
60
|
+
|
61
|
+
File.open("#{path}/Capfile", "w") do |file|
|
62
|
+
file.write(capfile)
|
63
|
+
end
|
64
|
+
|
65
|
+
Dir.chdir(path) do
|
66
|
+
system(deploy_command)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'webrick'
|
3
|
+
|
4
|
+
module Helpers
|
5
|
+
class Server
|
6
|
+
def initialize
|
7
|
+
@queue = Queue.new
|
8
|
+
@server = nil
|
9
|
+
@thread = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
@server = WEBrick::HTTPServer.new({
|
14
|
+
Port: 0,
|
15
|
+
Logger: WEBrick::Log.new(STDOUT),
|
16
|
+
AccessLog: []
|
17
|
+
})
|
18
|
+
|
19
|
+
@server.mount_proc('/deploy') do |req, res|
|
20
|
+
@queue.push(req.body)
|
21
|
+
|
22
|
+
res.status = 200
|
23
|
+
res.body = "OK\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
@thread = Thread.new { @server.start }
|
27
|
+
|
28
|
+
loop do
|
29
|
+
break if @server.status == :Running
|
30
|
+
|
31
|
+
sleep(0.1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def stop
|
36
|
+
@queue.clear
|
37
|
+
@server.stop
|
38
|
+
@thread.join(5)
|
39
|
+
@server = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def url
|
43
|
+
raise "Server is not running!" if @server.nil?
|
44
|
+
|
45
|
+
"http://localhost:" + @server.config[:Port].to_s + "/deploy"
|
46
|
+
end
|
47
|
+
|
48
|
+
def last_request
|
49
|
+
retries = 0
|
50
|
+
|
51
|
+
begin
|
52
|
+
JSON.parse(@queue.pop(true))
|
53
|
+
rescue ThreadError
|
54
|
+
raise if retries >= 10
|
55
|
+
|
56
|
+
retries += 1
|
57
|
+
sleep(0.1)
|
58
|
+
|
59
|
+
retry
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
require 'rspec/expectations'
|
4
|
+
require 'rspec/mocks'
|
5
|
+
require 'webmock/rspec'
|
6
|
+
|
7
|
+
require 'bugsnag-capistrano/release'
|
8
|
+
|
9
|
+
module Bugsnag::Capistrano
|
10
|
+
class Release
|
11
|
+
attr_accessor :logger
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Bugsnag::Capistrano::Release do
|
16
|
+
it "should call notify_without bugsnag" do
|
17
|
+
expect(Bugsnag::Capistrano::Release).to receive(:deliver)
|
18
|
+
Bugsnag::Capistrano::Release.notify({:api_key => "test", :app_version => "1"})
|
19
|
+
end
|
20
|
+
|
21
|
+
it "delivers a request to the given url" do
|
22
|
+
url = "http://localhost:56456"
|
23
|
+
stub_request(:post, url)
|
24
|
+
.to_return(status:200, body: "")
|
25
|
+
Bugsnag::Capistrano::Release.deliver(url, nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "delivers a body unmodified" do
|
29
|
+
body = ::JSON.dump({
|
30
|
+
"paramA" => 'a',
|
31
|
+
"paramB" => 'b',
|
32
|
+
"paramHash" => {
|
33
|
+
"one" => 1,
|
34
|
+
"two" => 2,
|
35
|
+
"three" => 3
|
36
|
+
}
|
37
|
+
})
|
38
|
+
url = "http://localhost:56456"
|
39
|
+
request = stub_request(:post, url)
|
40
|
+
.with(body: body, headers: { 'Content-Type' => 'application/json'})
|
41
|
+
.to_return(status:200, body: "")
|
42
|
+
Bugsnag::Capistrano::Release.deliver(url, body)
|
43
|
+
assert_requested request
|
44
|
+
end
|
45
|
+
|
46
|
+
it "cannot send without an apikey" do
|
47
|
+
expect(Bugsnag::Capistrano::Release).to_not receive(:deliver)
|
48
|
+
expect(Bugsnag::Capistrano::Release.logger).to receive(:warn).with("Cannot deliver notification. Missing required apiKey")
|
49
|
+
|
50
|
+
Bugsnag::Capistrano::Release.notify()
|
51
|
+
end
|
52
|
+
|
53
|
+
it "cannot send without an appVersion" do
|
54
|
+
expect(Bugsnag::Capistrano::Release).to_not receive(:deliver)
|
55
|
+
expect(Bugsnag::Capistrano::Release.logger).to receive(:warn).with("Cannot deliver notification. Missing required appVersion")
|
56
|
+
|
57
|
+
Bugsnag::Capistrano::Release.notify({:api_key => "test"})
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with bugsnag installed" do
|
61
|
+
before do
|
62
|
+
module Kernel
|
63
|
+
alias_method :old_require, :require
|
64
|
+
def require(path)
|
65
|
+
old_require(path) unless /^bugsnag/.match(path)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "gets information from bugsnag configuration if available" do
|
71
|
+
config = double
|
72
|
+
allow(config).to receive(:api_key).and_return("bugsnag_api_key")
|
73
|
+
allow(config).to receive(:app_version).and_return("bugsnag_app_version")
|
74
|
+
allow(config).to receive(:release_stage).and_return("bugsnag_release_stage")
|
75
|
+
|
76
|
+
allow(Bugsnag).to receive(:configuration).and_return(config)
|
77
|
+
expect(Bugsnag::Capistrano::Release).to receive(:deliver) do |uri, body_string|
|
78
|
+
expect(uri).to eq(Bugsnag::Capistrano::Release::DEFAULT_BUILD_ENDPOINT)
|
79
|
+
body = ::JSON.parse(body_string)
|
80
|
+
expect(body["apiKey"]).to eq("bugsnag_api_key")
|
81
|
+
expect(body["appVersion"]).to eq("bugsnag_app_version")
|
82
|
+
expect(body["releaseStage"]).to eq("bugsnag_release_stage")
|
83
|
+
end
|
84
|
+
|
85
|
+
Bugsnag::Capistrano::Release.notify()
|
86
|
+
end
|
87
|
+
|
88
|
+
after do
|
89
|
+
module Kernel
|
90
|
+
alias_method :require, :old_require
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|