capistrano-ghostinspector 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30234e4b797a6a5cfe63c41350826bca1dec3cb0
4
- data.tar.gz: 87ac2f5807a64b752ccebce107fc100a73df3a49
3
+ metadata.gz: 6085690f5e95b6c2fdb500613ec3ac052c5b6a0e
4
+ data.tar.gz: 1bbe0b1c0f038645aadb593eec58ce40c88bfe43
5
5
  SHA512:
6
- metadata.gz: aa8a90aba72f06af78f400d427f42646eb254d01117c88bc83291b96dd3deccfc0b486ad787df984a901a1409cb19f0edb973ac94f3f05a9299d5c32c3f7f9f9
7
- data.tar.gz: 7cad68d9aafdf032ce81f43ea335eb3603cd186a1550a9148e888a43c9666f6083b75f770b71ed2f6f5f13556548cfb3a5cd6472594a9609bd6a74c60e97b7d7
6
+ metadata.gz: 8a7278cdcc4df990d901d7f62cba0a920ddacef40102aa893860f71f6f6935f28e3c8493fbed088b47dfed239dc802e3c6847a44d71b1db65eff3d882207c9f3
7
+ data.tar.gz: ee8ffb81da2316a113ad3467c1607ae5a7cf5437667a226fc8e693d3829b8b63832fb81f3c26a70b70d60bf267d6b5e295885a2dbc8295965fab0384bb7e3e9c
data/README.md CHANGED
@@ -13,6 +13,10 @@
13
13
  - Auto configure start URL to reuse tests across multiple stages
14
14
  - Send deployment information to Google Analytics
15
15
  - Send errors to Google Analytics on failed tests
16
+ - Send successful test runs to Google Analytics
17
+ - Use Custom Dimensions in Google Analytics
18
+ - Send test names as Custom Dimension
19
+ - Track Jira tickets as Custom Dimension
16
20
 
17
21
  ## Installation
18
22
 
@@ -44,7 +48,6 @@ First thing you need to do is create your `YAML` file (`gi_config.yaml`) in the
44
48
  APIKEY: XXXXXXXXXXXXXXXXXXX
45
49
  gi_enabled: true
46
50
  rollback: true
47
- ga_property: ""
48
51
  suites:
49
52
  aboutpage: "XXXXXXXXXXXXXXXXXXX"
50
53
  suite2: ""
@@ -52,6 +55,10 @@ tests:
52
55
  homepage: "XXXXXXXXXXXXXXXXXXX"
53
56
  test2: ""
54
57
  test3: ""
58
+ ga_property: "UA-XXXXXXXX-X"
59
+ ga_custom_1: 1
60
+ ga_custom_2: 2
61
+ jira_project_code: "GHOST"
55
62
  ```
56
63
 
57
64
  You can obtain your API key, suite ID and test ID from your Ghost Inspector console. At the bottom right of the suite page you will see API Access e.g.
@@ -70,7 +77,14 @@ By default the `rollback` feature is enabled, you can disabled this for all stag
70
77
  set :rollback, false
71
78
  ```
72
79
 
73
- The Google Analytics property must be inserted into the `ga_property` in order to log deployments and errors. Simply update your YAML to include this `ga_property: "UA-XXXXXXXX-1"`. To disable the Google Analytics tracking just leave the `ga_property` as empty string i.e. `ga_property: ""` in your YAML
80
+ The Google Analytics property must be inserted into the `ga_property` in order to log deployments and errors. Simply update your YAML to include this `ga_property: "UA-XXXXXXXX-1"`. To disable the Google Analytics tracking just leave the `ga_property` as empty string i.e. `ga_property: ""` in your YAML.
81
+
82
+ Since version `0.3.0`, Google Analytics now uses Custom Dimensions as outlined in the [Google Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters?hl=en#cd_ "Google Measurement Protocol") documentation. When you define a new custom dimension in Google Analytics you are given a new dimension index. Default accounts have 20 available indexes where as premium accounts have 200. The `ga_custom_1` property is used to define the custom dimension for the testname and `ga_custom_2` is used to define the Jira tickets*. If you do not set the `ga_custom_1` or `ga_custom_2` properties then the default index of `1` & `2` will be used.
83
+
84
+ \*_Jira tickets are extracted from the git log during the deployment. For this reason it can only track the tickets where you have correctly assigned the ticket number and identifier to the commit message. i.e._
85
+ ```
86
+ git commit -am "GHOST-123 Add new item to the gem"
87
+ ```
74
88
 
75
89
  ## Usage
76
90
 
@@ -1,66 +1,173 @@
1
+ require "capistrano"
1
2
  require "capistrano/ghostinspector/version"
2
3
  require "capistrano/ghostinspector/arrays"
3
4
  require "capistrano/ghostinspector/api"
4
- require "capistrano"
5
+ require "capistrano/ghostinspector/analytics"
5
6
 
6
7
  module Capistrano
7
8
  module Ghostinspector
8
9
  def self.load_into(config)
9
10
  config.load do
10
- after "deploy", "capistrano:ghostinspector:run"
11
+ after "deploy", "ghostinspector:setup"
12
+ after "ghostinspector:setup", "ghostinspector:run"
11
13
 
12
- namespace :capistrano do
13
- namespace :ghostinspector do
14
- task :run, :only => { :primary => true } do
14
+ gi_config = YAML::load(File.read("gi_config.yaml"))
15
15
 
16
- set :giconfig, YAML::load(File.read("gi_config.yaml"))
16
+ namespace :ghostinspector do
17
+ desc "Setup Ghost Inspector Config"
18
+ task :setup, :only => { :primary => true } do
17
19
 
18
- # Ghost Inspector API key
19
- set :gi_api_key, giconfig["APIKEY"]
20
+ # Ghost Inspector API key
21
+ set :gi_api_key, gi_config["APIKEY"]
20
22
 
21
- # Google Analytics Tracking Property
22
- set :ga_property, giconfig["ga_property"]
23
+ # Google Analytics Tracking Property
24
+ set :ga_property, gi_config['ga_property']
23
25
 
24
- # Get tests and suites from command line
25
- set :gitest, fetch(:gitest, nil)
26
- set :gisuite, fetch(:gisuite, nil)
26
+ if gi_config.has_key?("ga_custom_1")
27
+ set :ga_custom_1, gi_config["ga_custom_1"]
28
+ else
29
+ set :ga_custom_1, "1"
30
+ end
27
31
 
28
- # Check if GI is enabled for this deployment (Default: true)
29
- set :gi_enabled, fetch(:gi_enabled, giconfig["gi_enabled"])
32
+ if gi_config.has_key?("ga_custom_2")
33
+ set :ga_custom_2, gi_config["ga_custom_2"]
34
+ else
35
+ set :ga_custom_2, "2"
36
+ end
30
37
 
31
- # Should we rollback on failed GI tests (Default: true)
32
- set :rollback, fetch(:rollback, giconfig["rollback"])
38
+ if gi_config.has_key?("jira_project_code")
39
+ set :jira_project_code, gi_config["jira_project_code"]
40
+ else
41
+ set :jira_project_code, "GHOST"
42
+ end
33
43
 
34
- if (gi_enabled == true)
44
+ # Get tests and suites from command line
45
+ set :gitest, fetch(:gitest, nil)
46
+ set :gisuite, fetch(:gisuite, nil)
35
47
 
36
- # run each test
37
- Capistrano::Ghostinspector.getTests(gitest, giconfig["tests"]).each do |test|
38
- puts "* * * Running Ghost Inspector Test * * *"
39
- set :passing, Capistrano::Ghostinspector::Api.executeApi("tests", test, gi_api_key, domain, rollback, ga_property, current_revision[0,7])
40
- end
48
+ # Check if GI is enabled for this deployment (Default: true)
49
+ set :gi_enabled, fetch(:gi_enabled, gi_config['gi_enabled'])
41
50
 
42
- # run each suite
43
- Capistrano::Ghostinspector.getTests(gisuite, giconfig["suites"]).each do |suite|
44
- puts "* * * Running Ghost Inspector Suite * * *"
45
- set :passing, Capistrano::Ghostinspector::Api.executeApi("suites", suite, gi_api_key, domain, rollback, ga_property, current_revision[0,7])
46
- end
51
+ # Should we rollback on failed GI tests (Default: true)
52
+ set :rollback, fetch(:rollback, gi_config['rollback'])
53
+ end
54
+
55
+ desc "Run Ghost Inspector Tests"
56
+ task :run, :only => { :primary => true } do
57
+
58
+ if (fetch(:gi_enabled) == true)
59
+
60
+ giApi = Api.new(fetch(:gi_api_key), fetch(:domain), fetch(:rollback), fetch(:ga_property))
61
+
62
+ @collection = Array.new
63
+ # run each test
64
+ Capistrano::Ghostinspector.getTests(fetch(:gitest), gi_config["tests"]).each do |test|
65
+ puts "* * * Running Ghost Inspector Test * * *"
66
+ set :data, giApi.executeApi("tests", test)
67
+
68
+ items = { :passing => data[0], :results => data[1], :type => "tests"}
69
+ @collection << items
70
+ end
47
71
 
48
- # If any test fails and the stage allows rollbacks then
49
- # rollback to previous version.
50
- if (passing == false && rollback == true)
51
- puts "* * * Ghost Inspector Failed. Rolling back * * *"
52
- run_locally %{cap #{stage} deploy:rollback}
53
- else
54
- puts "* * * Ghost Inspector Complete. Deployment Complete * * *"
72
+ # run each suite
73
+ Capistrano::Ghostinspector.getTests(fetch(:gisuite), gi_config["suites"]).each do |suite|
74
+ puts "* * * Running Ghost Inspector Suite * * *"
75
+ set :data, giApi.executeApi("suites", suite)
76
+
77
+ data[1]["data"].each do |test|
78
+ items = { :passing => test["passing"], :results => test, :type => "suites"}
79
+ @collection << items
55
80
  end
56
81
 
57
82
  end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ desc "Send Results to Google Analytics"
89
+ task :sendGA, :only => { :primary => true } do
90
+
91
+ puts "* * * Sending Data to Google Analytics * * *"
92
+
93
+ jira_project_code = fetch(:jira_project_code)
94
+
95
+ log = capture(
96
+ "cd #{current_path} && git log #{previous_revision[0,7]}..#{current_revision[0,7]} --format=\"%s\" | grep -oh '#{jira_project_code}-[0-9]\\+' | sort | uniq"
97
+ )
98
+
99
+ options = {
100
+ :ga_property => fetch(:ga_property),
101
+ :ga_custom_1 => fetch(:ga_custom_1),
102
+ :ga_custom_2 => fetch(:ga_custom_2),
103
+ :domain => fetch(:domain),
104
+ :current_revision => fetch(:current_revision),
105
+ :previous_revision => fetch(:previous_revision),
106
+ :branch => fetch(:branch, "default"),
107
+ :stage => fetch(:stage),
108
+ :tickets => Capistrano::Ghostinspector.getTickets(log)
109
+ }
110
+
111
+ analytics = Analytics.new(options)
112
+
113
+ @collection.each do |item|
114
+ analytics.pushData(item[:type], item[:results])
115
+ end
116
+
117
+ end
118
+
119
+ desc "Finalise Ghost Inspector Run"
120
+ task :finalise_run, :only => { :primary => true } do
121
+
122
+ set :passing, true
123
+ @collection.each do |item|
124
+ if item[:passing] == false
125
+ set :passing, false
126
+ end
58
127
  end
128
+
129
+ # If any test fails and the stage allows rollbacks then
130
+ # rollback to previous version.
131
+ if (fetch(:passing) == false && fetch(:rollback) == true)
132
+ puts "* * * Ghost Inspector Failed. Rolling back * * *"
133
+ run_locally %{cap #{stage} deploy:rollback}
134
+ else
135
+ puts "* * * Ghost Inspector Complete. Deployment Complete * * *"
136
+ end
137
+
59
138
  end
139
+
60
140
  end
61
141
 
142
+
143
+ after "ghostinspector:run", "ghostinspector:sendGA"
144
+ after "ghostinspector:sendGA", "ghostinspector:finalise_run"
145
+
62
146
  end
63
147
  end
148
+
149
+
150
+ def self.getTickets(log)
151
+
152
+ tickets = ""
153
+ log.each_line do |line|
154
+ line.delete!('";')
155
+ line.strip!
156
+ line.gsub!("'", '\u0027')
157
+ tickets = "#{tickets}, #{line}"
158
+ end
159
+
160
+ if (tickets.to_s == "")
161
+ tickets = "None"
162
+ else
163
+ tickets[0] = ''
164
+ end
165
+
166
+ return tickets
167
+
168
+ end
169
+
170
+
64
171
  end
65
172
  end
66
173
 
@@ -1,33 +1,95 @@
1
- require "capistrano/ghostinspector/analytics"
2
1
  require "staccato"
3
2
 
4
3
  module Capistrano
5
4
  module Ghostinspector
6
- module Analytics
7
- def self.pushDeployment(ga_property, current_revision)
5
+ class Analytics
6
+ def initialize(options)
7
+ @options = options
8
+ @tracker = Staccato.tracker(options[:ga_property])
9
+ end
8
10
 
9
- tracker = Staccato.tracker(ga_property)
11
+ def pushData(type, results)
10
12
 
11
- # inform GA of a new deployment
12
- tracker.event(category: 'deployment', action: 'deploy', label: current_revision, non_interactive: true)
13
+ # Lets push the deployment in GA if the configuration allows it.
14
+ pushDeployment()
13
15
 
14
- end
16
+ if type == "tests"
17
+ testname = "GI TEST - " + results["data"]["test"]["name"]
15
18
 
16
- def self.pushErrors(ga_property, current_revision, data)
19
+ if results["data"]["passing"] == true
20
+ trackData(results["data"]["steps"], testname, "success")
21
+ else
22
+ trackData(results["data"]["steps"], testname, "error")
23
+ end
17
24
 
18
- tracker = Staccato.tracker(ga_property)
25
+ else
19
26
 
20
- data['steps'].each do |step|
27
+ testname = "GI TEST - " + results["testName"]
21
28
 
22
- if (step['passing'] == false)
23
- # send the errors to GA
24
- tracker.event(category: 'error', action: step['error'], label: "Command: #{step['command']} - Target: #{step['target']}", non_interactive: true)
25
- end
29
+ if results["passing"] == true
30
+ trackData(results["steps"], testname, "success")
31
+ else
32
+ trackData(results["steps"], testname, "error")
33
+ end
26
34
 
27
- end
35
+ end
28
36
 
29
- end
37
+ end
30
38
 
31
- end
39
+ private
40
+
41
+ def pushDeployment()
42
+
43
+ # inform GA of a new deployment
44
+ @action = "deploy to #{@options[:stage]}"
45
+ current_revision = @options[:current_revision][0,7]
46
+ previous_revision = @options[:previous_revision][0,7]
47
+ @deployed = "Deployed revision #{current_revision} from branch #{@options[:branch]} (replacing #{previous_revision})"
48
+ hit = Staccato::Event.new(@tracker, category: 'deployment', action: @action, label: @deployed, document_hostname: @options[:domain], document_path: @action)
49
+ hit.add_custom_dimension(@options[:ga_custom_1], "deployment")
50
+ hit.add_custom_dimension(@options[:ga_custom_2], "#{@options[:tickets]}")
51
+ hit.track!
52
+
53
+ end
54
+
55
+ def trackData(steps, testName, type)
56
+
57
+ if type == 'success'
58
+ steps.each do |step|
59
+
60
+ hit = Staccato::Event.new(@tracker, category: 'success', action: step['command'], label: step['target'], document_hostname: @options[:domain], document_path: testName)
61
+ hit.add_custom_dimension(@options[:ga_custom_1], testName)
62
+ hit.add_custom_dimension(@options[:ga_custom_2], "#{@options[:tickets]}")
63
+ hit.track!
64
+
65
+ end
66
+ # pageView(testName)
67
+ else
68
+ steps.each do |step|
69
+
70
+ if (step['passing'] == false)
71
+ # send the errors to GA
72
+
73
+ hit = Staccato::Event.new(@tracker, category: 'error', action: step['error'], label: "Command: #{step['command']} - Target: #{step['target']}", document_hostname: @options[:domain], document_path: testName)
74
+ hit.add_custom_dimension(@options[:ga_custom_1], testName)
75
+ hit.add_custom_dimension(@options[:ga_custom_2], "#{@options[:tickets]}")
76
+ hit.track!
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ def pageView(testName)
85
+
86
+ hit = Staccato::Pageview.new(@tracker, hostname: @options[:domain], path: testName, title: testName, document_hostname: @options[:domain])
87
+ hit.add_custom_dimension(@options[:ga_custom_1], testName)
88
+ hit.add_custom_dimension(@options[:ga_custom_2], "#{@options[:tickets]}")
89
+ hit.track!
90
+
91
+ end
92
+
93
+ end
32
94
  end
33
- end
95
+ end
@@ -1,76 +1,94 @@
1
- require "capistrano/ghostinspector/analytics"
2
1
  require 'net/https'
3
2
  require 'json'
4
3
 
5
4
  module Capistrano
6
5
  module Ghostinspector
7
- module Api
8
- def self.executeApi(type, test, gi_api_key, domain, rollback, ga_property, current_revision)
9
-
10
- # Determine if we should get results to
11
- # check for any failed tests
12
- immediate = self.includeResults(rollback, ga_property)
13
-
14
- # Default all tests pass
15
- passing = true
16
-
17
- # Lets push the deployment in GA if the configuration allows it.
18
- Capistrano::Ghostinspector::Analytics.pushDeployment(ga_property, current_revision)
19
-
20
- # # Perform the API request and get the results
21
- results = self.sendRequest(type, test, gi_api_key, domain, immediate)
22
-
23
- # Check the data returned for failed tests
24
- if (rollback == true)
25
- passing = self.getPassing(type, results, ga_property)
26
- end
27
-
28
- if (passing == false && ga_property != "")
29
- Capistrano::Ghostinspector::Analytics.pushErrors(ga_property, current_revision, results['data'])
30
- end
31
-
32
- return passing
33
-
34
- end
35
-
36
- def self.includeResults(rollback, ga_property)
37
- # Determine if we should get results to
38
- # check for any failed tests
39
- if (rollback == false && ga_property == "")
40
- immediate = "&immediate=1"
41
- else
42
- immediate = ""
43
- puts "* * * Gathering results. This could take a few minutes. * * *"
44
- end
45
-
46
- return immediate
47
- end
48
-
49
- def self.sendRequest(type, test, gi_api_key, domain, immediate)
50
-
51
- # execute the Ghost Inspector API call
52
- uri = URI("https://api.ghostinspector.com/v1/#{type}/#{test}/execute/?apiKey=#{gi_api_key}&startUrl=http://#{domain}/#{immediate}")
53
- data = Net::HTTP.get(uri)
54
-
55
- results = JSON.parse(data)
56
-
57
- return results
58
- end
59
-
60
- def self.getPassing(type, results, ga_property)
61
-
62
- if (type == "suite")
63
- results['data'].each do |testItem|
64
- passing = testItem['passing']
65
- end
66
- else
67
- passing = results['data']['passing']
68
- end
69
-
70
- return passing
71
-
72
- end
73
-
74
- end
6
+ class Api
7
+
8
+ def initialize(gi_api_key, domain, rollback, ga_property)
9
+ @apiKey = gi_api_key
10
+ @domain = domain
11
+ @rollback = rollback
12
+ @ga_property = ga_property
13
+
14
+ # Determine if we should get results to
15
+ # check for any failed tests
16
+ @immediate = includeResults()
17
+ end
18
+
19
+
20
+ def executeApi(type, test)
21
+
22
+ # Default all tests pass
23
+ passing = true
24
+
25
+ # ------ TESTING ONLY ------
26
+ # results = JSON.parse(File.read("gitestresults.json"))
27
+ # results = JSON.parse(File.read("suiteresults.json"))
28
+ # ------ TESTING ONLY ------
29
+
30
+ # # Perform the API request and get the results
31
+ results = sendRequest(type, test)
32
+
33
+ # Check the data returned for failed tests
34
+ if (@rollback == true)
35
+ passing = getPassing(type, results)
36
+ end
37
+
38
+ data = Array.new
39
+ data << passing
40
+ data << results
41
+
42
+ return data
43
+
44
+ end
45
+
46
+ private
47
+
48
+ def includeResults()
49
+
50
+ # Determine if we should get results to
51
+ # check for any failed tests
52
+ if (@rollback == false && @ga_property == "")
53
+ immediate = "&immediate=1"
54
+ else
55
+ immediate = ""
56
+ puts "* * * Gathering results. This could take a few minutes. * * *"
57
+ end
58
+
59
+ return immediate
60
+ end
61
+
62
+ def sendRequest(type, test)
63
+
64
+ uri = URI("https://api.ghostinspector.com/v1/#{type}/#{test}/execute/?apiKey=#{@apiKey}&startUrl=http://#{@domain}/#{@immediate}")
65
+
66
+ Net::HTTP.start(uri.host, uri.port,
67
+ :use_ssl => uri.scheme == 'https') do |http|
68
+ request = Net::HTTP::Get.new uri
69
+ http.read_timeout = 600
70
+ @response = http.request request
71
+ end
72
+
73
+ results = JSON.parse(@response.body)
74
+
75
+ return results
76
+ end
77
+
78
+ def getPassing(type, results)
79
+
80
+ if (type == "suites")
81
+ results["data"].each do |testItem|
82
+ passing = testItem["passing"]
83
+ end
84
+ else
85
+ passing = results["data"]["passing"]
86
+ end
87
+
88
+ return passing
89
+
90
+ end
91
+
92
+ end
75
93
  end
76
- end
94
+ end
@@ -2,19 +2,19 @@ module Capistrano
2
2
  module Ghostinspector
3
3
  def self.getTests(test, giconfig)
4
4
 
5
- # Return an array of tests/suites to
6
- # run in ghost inspector
7
- array = Array.new
8
- if (test != nil)
9
- test.split(',').each do |key|
10
- if (giconfig.has_key?(key))
11
- array << giconfig[key]
12
- end
13
- end
14
- end
5
+ # Return an array of tests/suites to
6
+ # run in ghost inspector
7
+ array = Array.new
8
+ if (test != nil)
9
+ test.split(',').each do |key|
10
+ if (giconfig.has_key?(key))
11
+ array << giconfig[key]
12
+ end
13
+ end
14
+ end
15
15
 
16
- return array
16
+ return array
17
17
 
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module Ghostinspector
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-ghostinspector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Richardson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-19 00:00:00.000000000 Z
11
+ date: 2015-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capistrano
@@ -111,7 +111,6 @@ files:
111
111
  - lib/capistrano/ghostinspector/analytics.rb
112
112
  - lib/capistrano/ghostinspector/api.rb
113
113
  - lib/capistrano/ghostinspector/arrays.rb
114
- - lib/capistrano/ghostinspector/config.rb
115
114
  - lib/capistrano/ghostinspector/version.rb
116
115
  - spec/capistrano-ghostinspector_spec.rb
117
116
  - spec/spec_helper.rb
@@ -1,13 +0,0 @@
1
- require "capistrano/ghostinspector/analytics"
2
-
3
- module Capistrano
4
- module Ghostinspector
5
- def self.configure(config)
6
-
7
-
8
-
9
-
10
- end
11
-
12
- end
13
- end