bugsnag-capistrano 1.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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:deploy'
15
+ after 'deploy:published', 'bugsnag:release'
23
16
  end
24
17
 
25
- desc 'Notify Bugsnag that new production code has been deployed'
26
- task :deploy do
18
+ desc 'Notify Bugsnag that new production code has been released'
19
+ task :release do
27
20
  run_locally do
28
21
  begin
29
- Bugsnag::Capistrano::Deploy.notify({
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
- :branch => fetch(:branch, ENV["BUGSNAG_BRANCH"]),
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 deploy notification complete.'
35
+ info 'Bugsnag release notification complete.'
39
36
  rescue
40
- error "Bugsnag deploy notification failed, #{$!.inspect}"
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
@@ -1,65 +1,116 @@
1
- require 'webmock/rspec'
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
- after do
27
- server.stop
28
- queue.clear
29
- end
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'] = "http://localhost:" + server.config[:Port].to_s + "/deploy"
35
-
36
- Dir.chdir(example_path) do
37
- system(exec_string)
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 = request()
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'] = "http://localhost:" + server.config[:Port].to_s + "/deploy"
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(exec_string)
33
+ Dir.chdir(Helpers::Capistrano.example_path) do
34
+ system(Helpers::Capistrano.deploy_command)
55
35
  end
56
36
 
57
- payload = request()
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["revision"]).to eq("test")
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