golden_rose 0.1.0 → 1.0.0.pre

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.
@@ -0,0 +1,11 @@
1
+ module GoldenRose
2
+ class Info
3
+ def initialize(parsed_info)
4
+ @parsed_info = parsed_info
5
+ end
6
+
7
+ def build_log_path
8
+ @parsed_info['Actions'].first['BuildResult']['LogPath']
9
+ end
10
+ end
11
+ end
@@ -2,57 +2,55 @@
2
2
  # from zip file or folder
3
3
 
4
4
  require "plist"
5
- require "zip"
6
- require "securerandom"
7
5
 
8
6
  module GoldenRose
9
7
  class Parser
10
- FILE_NAME = "action_TestSummaries.plist"
11
-
12
- attr_accessor :parsed_plist, :folder_path
8
+ attr_accessor :folder_path
9
+ attr_reader :parsed_test_summaries_plist, :parsed_info_plist, :parsed_build_logs
13
10
 
14
11
  def initialize(folder_path)
15
12
  @folder_path = folder_path
16
13
  end
17
14
 
18
15
  def parse!
19
- archive? ? open_zip : open_directory
20
- raise GeneratingError, "File 'TestSummaries.plist' was not found in the folder." unless @plist_file_path
21
- @parsed_plist = Plist::parse_xml(@plist_file_path)
22
- File.delete(@plist_file_path) if archive?
23
- raise GeneratingError, "Could not parse plist correctly." unless parsed_plist
24
- parsed_plist
16
+ read_plists
17
+ parse_plists
18
+ parse_build_logs
19
+ delete_extracted_files
20
+ self
21
+ end
25
22
 
26
- rescue Zip::Error, Errno::ENOENT
27
- raise GeneratingError, "Could not open the folder."
23
+ def source_type
24
+ archive? ? :zip : :dir
28
25
  end
29
26
 
30
27
  private
31
28
 
32
- def open_directory
33
- @plist_file_path = Dir.glob("#{folder_path}/**/#{FILE_NAME}").first
29
+ def read_plists
30
+ @test_summaries_resource = FileResource.new(:test_summaries_plist, source_type, folder_path)
31
+ @info_resource = FileResource.new(:info_plist, source_type, folder_path)
32
+ end
33
+
34
+ def parse_plists
35
+ @parsed_test_summaries_plist = @test_summaries_resource.path ? Plist.parse_xml(@test_summaries_resource.path) : nil
36
+ puts("Could not parse test_summaries.plist correctly") unless @parsed_test_summaries_plist
37
+ @parsed_info_plist = Plist.parse_xml(@info_resource.path)
38
+ fail GeneratingError, 'Could not parse Info.plist correctly.' unless @parsed_info_plist
34
39
  end
35
40
 
36
- def open_zip
37
- Zip::File.open(folder_path) do |zip_file|
38
- entry = zip_file.find do |entry|
39
- file_name = File.basename(entry.name)
40
- test_summaries?(file_name)
41
- end
42
- if entry
43
- uuid = ::SecureRandom.uuid
44
- @plist_file_path = File.join(GoldenRose::root, "/source_#{uuid}.plist")
45
- entry.extract(@plist_file_path)
46
- end
47
- end
41
+ def parse_build_logs
42
+ build_log_path = Info.new(@parsed_info_plist).build_log_path
43
+ @build_log_resource = FileResource.new(:build_log, source_type, folder_path, build_log_path)
44
+ @parsed_build_logs = GoldenRose::BuildLog::Parser.new(@build_log_resource.path).parse!
48
45
  end
49
46
 
50
- def test_summaries?(file_name)
51
- file_name == FILE_NAME
47
+ def delete_extracted_files
48
+ [@test_summaries_resource, @info_resource, @build_log_resource]
49
+ .map(&:delete_extracted_file)
52
50
  end
53
51
 
54
52
  def archive?
55
53
  !(folder_path =~ /\.(?:rar|zip|tar.gz)$/).nil?
56
54
  end
57
55
  end
58
- end
56
+ end
@@ -3,65 +3,15 @@
3
3
 
4
4
  module GoldenRose
5
5
  class ResultsFilterer
6
- attr_accessor :parsed_plist, :results
6
+ attr_accessor :parsed_plist
7
7
 
8
8
  def initialize(parsed_plist)
9
9
  @parsed_plist = parsed_plist
10
10
  end
11
11
 
12
12
  def filter!
13
- raise GeneratingError, "Testable summaries not present." unless testable_summaries
14
- raise GeneratingError, "Tests not present." unless tests
15
- @results = Results.new(execution_details, items)
13
+ return nil if @parsed_plist.nil?
14
+ ExecutionDetails.new(@parsed_plist)
16
15
  end
17
-
18
- private
19
-
20
- def iterate_subtests(items)
21
- items.map do |subtest|
22
- child_subtests = subtest["Subtests"]
23
- next if child_subtests && child_subtests.empty?
24
-
25
- if child_subtests
26
- ParentItem.new(subtest).tap do |item|
27
- item.subtests = iterate_subtests(child_subtests)
28
- end.to_h
29
- else
30
- ChildItem.new(subtest).to_h
31
- end
32
- end.compact
33
- end
34
-
35
- def items
36
- @items ||= compact_results(iterate_subtests(tests))
37
- end
38
-
39
- # This method simplify results structure,
40
- # it sets only one level of nesting
41
- # by leaving parents only with collection as child
42
- def compact_results(items)
43
- items.map do |subtest|
44
- subtests = subtest[:subtests]
45
- if subtests.size > 1
46
- subtests
47
- elsif subtests.size == 1
48
- compact_results(subtests)
49
- end
50
- end.flatten.compact
51
- end
52
-
53
- def execution_details
54
- ExecutionDetails.new(parsed_plist, items)
55
- end
56
-
57
- def testable_summaries
58
- parsed_plist['TestableSummaries']
59
- end
60
-
61
- def tests
62
- testable_summaries.first['Tests']
63
- end
64
-
65
- class Results < Struct.new(:details, :items); end
66
16
  end
67
- end
17
+ end
@@ -0,0 +1,24 @@
1
+ %ol#collapsible
2
+ - @build_logs.each do |build_target|
3
+ %li
4
+ %label(for="#{build_target.target_name}")
5
+ = "Build target #{build_target.target_name}"
6
+ %input(type="checkbox" id="#{build_target.target_name}")
7
+ %ol
8
+ - build_target.sections.each do |build_section|
9
+ %li
10
+ %span{class: (build_section.success? ? 'build-log-success' : 'build-log-error')}
11
+ = build_section.name
12
+ - if build_section.file?
13
+ %span.file
14
+ = build_section.file
15
+ %span.path
16
+ = "...in #{build_section.directory}"
17
+ - elsif !build_section.file? && build_section.path?
18
+ %span.path
19
+ = "#{build_section.path}"
20
+ - if build_section.errors?
21
+ %ul
22
+ - build_section.errors.each do |build_error|
23
+ %li.build-log-error.error-text
24
+ = build_error
@@ -0,0 +1,5 @@
1
+ #footer
2
+ Made with
3
+ %span.heart ❤
4
+ by
5
+ %a(title="PGS Software" href="https://pgs-soft.com")PGS Software
@@ -0,0 +1,9 @@
1
+ - (activity_summaries || []).each do |activity_summary|
2
+ %tr
3
+ %td
4
+ = activity_summary.content.start_time
5
+ %td
6
+ = activity_summary.content.finish_time
7
+ %td
8
+ = activity_summary.content.title
9
+ = render_subactivities(activity_summary)
@@ -0,0 +1,52 @@
1
+ - if @details.testable_summaries.size > 1
2
+ %ul.tab-nd.tests-tabs
3
+ - @details.testable_summaries.each.with_index do |testable_summary, idx|
4
+ %li
5
+ %a.tablinks-nd{href: "javascript:void(0)", onclick: "openTabNd(event, 'testable-summary-#{idx}')"}
6
+ = testable_summary.name
7
+ - @details.testable_summaries.each.with_index do |testable_summary, idx|
8
+ %div{id: "testable-summary-#{idx}", class: 'tabcontent-nd'}
9
+ %h1
10
+ = testable_summary.name
11
+ #details
12
+ #{testable_summary.total_tests_count} tests run on
13
+ %strong
14
+ #{@details.model_name} iOS #{@details.os_version}
15
+ with
16
+ %strong
17
+ #{testable_summary.passing_count} passing
18
+ and
19
+ %strong
20
+ #{testable_summary.failures_count} failing
21
+ in #{testable_summary.formatted_time}
22
+ #results
23
+ %ol#collapsible
24
+ - testable_summary.items.each do |item|
25
+ %li
26
+ %label(for="#{item[:node_id]}")
27
+ = item[:name]
28
+ - if item[:failures_count]
29
+ %span.failures-count
30
+ = "Failures: "
31
+ = item[:failures_count]
32
+ %input(type="checkbox" id="#{item[:node_id]}")
33
+ %ol
34
+ - (item[:subtests] || []).each do |subtest|
35
+ %li
36
+ %span(class="#{subtest[:status]}")
37
+ - if subtest[:has_activity_summaries]
38
+ %a.link{:href => "test_logs/#{subtest[:uuid]}.html", :target => "_blank"}
39
+ = subtest[:name]
40
+ - else
41
+ = subtest[:name]
42
+ %span.time
43
+ = subtest[:time]
44
+ - if subtest[:failures]
45
+ - subtest[:failures].each do |failure|
46
+ .failure-message
47
+ = failure[:message]
48
+ .failure-details
49
+ #{failure[:file_name]}:#{failure[:line_number]}
50
+ - if subtest[:instance].screenshot
51
+ %a{:href => "#{subtest[:instance].screenshot}"}
52
+ %img.screenshot-thumb{alt: "#{subtest[:instance].screenshot}", src: "#{subtest[:instance].screenshot}"}/
@@ -0,0 +1,48 @@
1
+ :javascript
2
+ function openTab(evt, tabId) {
3
+ var i, tabcontent, tablinks;
4
+
5
+ // Get all elements with class="tabcontent" and hide them
6
+ tabcontent = document.getElementsByClassName("tabcontent");
7
+ for (i = 0; i < tabcontent.length; i++) {
8
+ tabcontent[i].style.display = "none";
9
+ }
10
+
11
+ // Get all elements with class="tablinks" and remove the class "active"
12
+ tablinks = document.getElementsByClassName("tablinks");
13
+ for (i = 0; i < tablinks.length; i++) {
14
+ tablinks[i].className = tablinks[i].className.replace(" active", "");
15
+ }
16
+
17
+ // Show the current tab, and add an "active" class to the link that opened the tab
18
+ document.getElementById(tabId).style.display = "block";
19
+ evt.currentTarget.className += " active";
20
+ }
21
+
22
+ function openTabNd(evt, tabId) {
23
+ var i, tabcontent, tablinks;
24
+
25
+ // Get all elements with class="tabcontent" and hide them
26
+ tabcontent = document.getElementsByClassName("tabcontent-nd");
27
+ for (i = 0; i < tabcontent.length; i++) {
28
+ tabcontent[i].style.display = "none";
29
+ }
30
+
31
+ // Get all elements with class="tablinks" and remove the class "active"
32
+ tablinks = document.getElementsByClassName("tablinks-nd");
33
+ for (i = 0; i < tablinks.length; i++) {
34
+ tablinks[i].className = tablinks[i].className.replace(" active", "");
35
+ }
36
+
37
+ // Show the current tab, and add an "active" class to the link that opened the tab
38
+ document.getElementById(tabId).style.display = "block";
39
+ evt.currentTarget.className += " active";
40
+ }
41
+
42
+
43
+ // Get the element with id="defaultOpen" and click on it
44
+ document.getElementById("default-open").click();
45
+ var firstTablinkNd = document.getElementsByClassName("tablinks-nd")[0];
46
+ if (firstTablinkNd) {
47
+ firstTablinkNd.click();
48
+ }
@@ -0,0 +1,203 @@
1
+ :css
2
+ body { font-family: 'Source Sans Pro', sans-serif; }
3
+ #container { max-width: 1170px; margin: auto;}
4
+ h1 {
5
+ color: #ff7726;
6
+ font-size: 48px;
7
+ font-weight: 600;
8
+ line-height: 18px;
9
+ text-align: left;
10
+ margin: 73px 0 24px 0;
11
+ }
12
+ #details {
13
+ color: #4e4e4e;
14
+ margin: 0 0 60px 0;
15
+ font-size: 18px;
16
+ line-height: 18px;
17
+ }
18
+ .no-results-info {
19
+ text-align: center;
20
+ font-size: 28pt;
21
+ color: grey;
22
+ margin-top: 80px;
23
+ }
24
+ #results { margin-right: 34px; }
25
+ input[type=checkbox], input[type=checkbox] + ol > li { display: none; }
26
+ input[type=checkbox]:checked + ol > li { display: block; }
27
+ ol, li { position: relative; }
28
+ ol { margin: 0; padding: 0 0 0 34px; }
29
+ ol#collapsible { padding: 0; }
30
+ ol::before {
31
+ content: "▶";
32
+ position: absolute;
33
+ top: -33px; left: 15px;
34
+ font-size: 10px;
35
+ color: #ff7726;
36
+ }
37
+ ol#collapsible::before { display: none; }
38
+ input[type=checkbox]:checked + ol::before { content: "▼"; }
39
+ li { list-style: none; }
40
+ label { cursor: pointer; }
41
+ label, .success, .failure {
42
+ padding: 13.5px 0 13.5px 34px;
43
+ width: auto;
44
+ display: block;
45
+ background: #f6f6f6;
46
+ border-bottom: 3px #fff solid;
47
+ color: #4e4e4e;
48
+ letter-spacing: -0.32px;
49
+ line-height: 18px;
50
+ }
51
+ .time, .failures-count {
52
+ float: right;
53
+ width: 90px;
54
+ }
55
+ .failures-count { color: #a80000; }
56
+ .success {
57
+ background: #ccffcc;
58
+ color: #005e37;
59
+ padding: 8.5px 0 8.5px 34px;
60
+ font-weight: 400;
61
+ }
62
+ .failure {
63
+ background: #ffcfcf;
64
+ color: #a80000;
65
+ }
66
+ .failure-message, .failure-details {
67
+ clear: both;
68
+ display: block;
69
+ font-size: 14px;
70
+ letter-spacing: -0.28px;
71
+ margin-right: 34px;
72
+ }
73
+ #build-logs-id {
74
+ margin-right: 34px;
75
+ padding-top: 80px;
76
+ }
77
+ #build-logs-id .build-log-success:before {
78
+ content:'✓';
79
+ font-weight: bold;
80
+ display:inline-block;
81
+ vertical-align: top;
82
+ line-height: 1em;
83
+ width: 1em;
84
+ height:1em;
85
+ margin-right: 0.3em;
86
+ text-align: center;
87
+ color: #FFF;
88
+ background-color: green;
89
+ -moz-border-radius: 0.5em;
90
+ -webkit-border-radius: 0.5em;
91
+ border-radius: 0.5em;
92
+ margin-top: 2px;
93
+ }
94
+ #build-logs-id .build-log-error:before {
95
+ content:'✗';
96
+ font-weight: bold;
97
+ display:inline-block;
98
+ line-height: 1em;
99
+ vertical-align: top;
100
+ width: 1em;
101
+ height:1em;
102
+ margin-right: 0.3em;
103
+ text-align: center;
104
+ color: #FFF;
105
+ background-color: red;
106
+ -moz-border-radius: 0.5em;
107
+ -webkit-border-radius: 0.5em;
108
+ border-radius: 0.5em;
109
+ margin-top: 2px;
110
+ }
111
+ .error-text {
112
+ color: red;
113
+ font-size: 14px;
114
+ }
115
+ #build-logs-id .path {
116
+ color: #737373;
117
+ font-family: Courier New;
118
+ font-size: 14px;
119
+ }
120
+ #build-logs-id .file {
121
+ font-size: 14px;
122
+ }
123
+ #footer {
124
+ color: #4e4e4e;
125
+ font-size: 14px;
126
+ margin-top: 40px;
127
+ }
128
+ .heart { color: #ff7726; }
129
+ #footer a { color: #ff7726; text-decoration: none; }
130
+ /* TABS styles - BEGIN ========================== */
131
+ ul.tab, ul.tab-nd {
132
+ list-style-type: none;
133
+ margin: 0;
134
+ padding: 0;
135
+ overflow: hidden;
136
+ }
137
+ /* Float the list items side by side */
138
+ ul.tab li, ul.tab-nd li {float: left;}
139
+ /* Style the links inside the list items */
140
+ ul.tab li a {
141
+ display: inline-block;
142
+ color: black;
143
+ text-align: center;
144
+ padding: 14px 35px;
145
+ text-decoration: none;
146
+ transition: 0.3s;
147
+ font-size: 17px;
148
+ font-weight: bold;
149
+ }
150
+ ul.tab-nd li a {
151
+ display: inline-block;
152
+ color: black;
153
+ text-align: center;
154
+ padding: 10px 30px;
155
+ text-decoration: none;
156
+ transition: 0.3s;
157
+ font-size: 17px;
158
+ font-weight: bold;
159
+ }
160
+ ul.tab-nd {
161
+ display: inline-block;
162
+ position: relative;
163
+ left: -13px;
164
+ }
165
+ /* Create an active/current tablink class */
166
+ ul.tab li a:focus, ul.tab li a.active, ul.tab li a:hover {
167
+ background-color: #FF7726;
168
+ color: #FFF;
169
+ }
170
+ ul.tab-nd li a:focus, ul.tab-nd li a.active, ul.tab-nd li a:hover {
171
+ border-width: 1px 1px 0 1px;
172
+ }
173
+ ul.tab-nd li a:hover {
174
+ background-color: #FF7726;
175
+ color: #FFF;
176
+ }
177
+ ul.tab-nd li a {
178
+ background-color: #FFF;
179
+ color: black;
180
+ border-color: #FF7726;
181
+ border-width: 0 0 1px 0;
182
+ border-style: solid;
183
+ }
184
+ /* Style the tab content */
185
+ .tabcontent {
186
+ display: none;
187
+ padding: 6px 12px;
188
+ border-top: none;
189
+ }
190
+ .tests-tabs {
191
+ top: 50px;
192
+ }
193
+ /* TABS styles - END ===================== */
194
+
195
+ .link {
196
+ text-decoration : none;
197
+ color:inherit;
198
+ }
199
+
200
+ .screenshot-thumb {
201
+ height:100px;
202
+ width:auto;
203
+ }
@@ -0,0 +1,101 @@
1
+ :css
2
+ /*** Table Styles **/
3
+ #test-logs .table-fill {
4
+ background: white;
5
+ border-radius:3px;
6
+ border-collapse: collapse;
7
+ margin: auto;
8
+ padding:0px;
9
+ width: 100%;
10
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
11
+ animation: float 5s infinite;
12
+ }
13
+ #test-logs th {
14
+ color: #FFFFFF;
15
+ background: #FF7726;
16
+ border-bottom:1px solid #ff7e33;
17
+ border-right: 1px solid #ff7e33;
18
+ font-size:16px;
19
+ font-weight: 900;
20
+ padding:6px;
21
+ text-align:left;
22
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
23
+ vertical-align:middle;
24
+ }
25
+
26
+ #test-logs th:first-child {
27
+ border-top-left-radius:3px;
28
+ }
29
+
30
+ #test-logs th:last-child {
31
+ border-top-right-radius:3px;
32
+ border-right:none;
33
+ }
34
+
35
+ #test-logs tr {
36
+ border-top: 1px solid #C1C3D1;
37
+ border-bottom-: 1px solid #C1C3D1;
38
+ color:#666B85;
39
+ font-size:16px;
40
+ font-weight:normal;
41
+ text-shadow: 0 1px 1px rgba(256, 256, 256, 0.1);
42
+ }
43
+
44
+ #test-logs tr:first-child {
45
+ border-top:none;
46
+ }
47
+
48
+ #test-logs tr:last-child {
49
+ border-bottom:none;
50
+ }
51
+
52
+ #test-logs tr:nth-child(odd) td {
53
+ background:#ffefe6;
54
+ }
55
+
56
+ #test-logs tr:last-child td:first-child {
57
+ border-bottom-left-radius:3px;
58
+ }
59
+
60
+ #test-logs tr:last-child td:last-child {
61
+ border-bottom-right-radius:3px;
62
+ }
63
+
64
+ #test-logs td {
65
+ background:#FFFFFF;
66
+ padding:4px 6px;
67
+ text-align:left;
68
+ vertical-align:middle;
69
+ font-weight:300;
70
+ font-size:16px;
71
+ text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
72
+ border-right: 1px solid #C1C3D1;
73
+ }
74
+
75
+ #test-logs td:last-child {
76
+ border-right: 0px;
77
+ }
78
+
79
+ #test-logs th.text-left {
80
+ text-align: left;
81
+ }
82
+
83
+ #test-logs th.text-center {
84
+ text-align: center;
85
+ }
86
+
87
+ #test-logs th.text-right {
88
+ text-align: right;
89
+ }
90
+
91
+ #test-logs td.text-left {
92
+ text-align: left;
93
+ }
94
+
95
+ #test-logs td.text-center {
96
+ text-align: center;
97
+ }
98
+
99
+ #test-logs td.text-right {
100
+ text-align: right;
101
+ }