allure-report-publisher 0.4.2 → 0.5.2

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
  SHA256:
3
- metadata.gz: 95d9fe3571d7c0a5854a67a41b12167670392acc96301c226588e518a82af6c3
4
- data.tar.gz: 681425836f0ae22eb2ddaf92d613fccd3072f33693b55fbbf2ce549c4ee19c8e
3
+ metadata.gz: 41262f49694d870733005c690d1384d2f95493efe3dd1f4af0f57bdf27871c51
4
+ data.tar.gz: c4c115289ce0ad2f21adc359b96e6c61d06534227086f9e18808568dfd8dae69
5
5
  SHA512:
6
- metadata.gz: 5a5461c76b830a1be53fe821519b8f40d355772ad001083f67827e6e62dd7363e593d383073cc98237081f23178fb69e4aa0ddd2d8d551bdb24cfd6473026735
7
- data.tar.gz: d02e41c8fdaa9f4e18e3a6e295d25801c8d5d39c57ede1f046e150056e82a7320094b5364a133cc77e37071a3491cce7940cf44ca20a5b7acafc6660664cf290
6
+ metadata.gz: 8da58fa175adce43b0e8a5a06d7ade6157b99ab8c31f566da1e9cfbc082ee89251da8ba54a3c9bcd37bef72e8554456fd17cb3eecedf839e7864270b6558f3ae
7
+ data.tar.gz: cdfeefbee4ebdf742614e664e0ab691977b0f5ce4445928ef219bc071a9d98c2410b2ac7b0f69a6a3dd634cf3f3f3731fbf8af7f2a5221279423900176bd84e5
data/README.md CHANGED
@@ -48,8 +48,9 @@ Options:
48
48
  --bucket=VALUE # Bucket name. Required: true
49
49
  --prefix=VALUE # Optional prefix for report path. Required: false
50
50
  --update-pr=VALUE # Add report url to PR via comment or description update. Required: false: (comment/description)
51
+ --summary=VALUE # Additionally add summary table to PR comment or description. Required: false: (behaviors/suites/packages/total)
51
52
  --[no-]copy-latest # Keep copy of latest report at base prefix path, default: false
52
- --[no-]color # Toggle color output, default: false
53
+ --[no-]color # Force color output
53
54
  --[no-]ignore-missing-results # Ignore missing allure results, default: false
54
55
  --help, -h # Print this help
55
56
 
@@ -104,9 +105,10 @@ Following CI providers are supported:
104
105
 
105
106
  ## Pull requests
106
107
 
107
- It is possible to update pull requests with urls to published reports.
108
+ It is possible to update pull requests with urls to published reports and execution summary.
108
109
 
109
110
  - `--update-pr=(comment|description)`: post report urls in pr description or as a comment
111
+ - `--summary=(behaviors/suites/packages/total)`: add execution summary table
110
112
 
111
113
  Example:
112
114
 
@@ -114,9 +116,19 @@ Example:
114
116
 
115
117
  `# Allure report`
116
118
 
117
- `allure-report-publisher` generated test report for [1b756f48](https://github.com/andrcuns/allure-report-publisher/commit/HEAD)!
119
+ `allure-report-publisher` generated test report!
118
120
 
119
- **rspec**: 📝 [test report](https://storage.googleapis.com/allure-test-reports/allure-report-publisher/refs/heads/main/index.html)
121
+ **rspec**: [test report](https://storage.googleapis.com/allure-test-reports/allure-report-publisher/refs/heads/main/index.html) for [1b756f48](https://github.com/andrcuns/allure-report-publisher/commit/HEAD)
122
+
123
+ ```markdown
124
+ +--------------------------------------------------------+
125
+ | total summary |
126
+ +-----------+--------+--------+---------+-------+--------+
127
+ | | passed | failed | skipped | flaky | result |
128
+ +-----------+--------+--------+---------+-------+--------+
129
+ | Total | 100 | 0 | 2 | 0 | ✅ |
130
+ +-----------+--------+--------+---------+-------+--------+
131
+ ```
120
132
 
121
133
  ---
122
134
 
@@ -21,16 +21,24 @@ module Publisher
21
21
  desc: "Optional prefix for report path. Required: false"
22
22
  option :update_pr,
23
23
  type: :string,
24
- values: %w[comment description],
25
- desc: "Add report url to PR via comment or description update. Required: false"
24
+ desc: "Add report url to PR via comment or description update. Required: false",
25
+ values: %w[comment description]
26
+ option :summary,
27
+ type: :string,
28
+ desc: "Additionally add summary table to PR comment or description. Required: false",
29
+ values: [
30
+ Publisher::Helpers::Summary::BEHAVIORS,
31
+ Publisher::Helpers::Summary::SUITES,
32
+ Publisher::Helpers::Summary::PACKAGES,
33
+ Publisher::Helpers::Summary::TOTAL
34
+ ]
26
35
  option :copy_latest,
27
36
  type: :boolean,
28
37
  default: false,
29
38
  desc: "Keep copy of latest report at base prefix path"
30
39
  option :color,
31
40
  type: :boolean,
32
- default: false,
33
- desc: "Toggle color output"
41
+ desc: "Force color output"
34
42
  option :ignore_missing_results,
35
43
  type: :boolean,
36
44
  default: false,
@@ -42,12 +50,11 @@ module Publisher
42
50
  ]
43
51
 
44
52
  def call(**args)
45
- Helpers.pastel(force_color: args[:color] || nil)
53
+ Helpers.pastel(force_color: args[:color])
54
+ @args = args
46
55
 
47
- validate_args(args)
48
- validate_result_files(args[:results_glob], args[:ignore_missing_results])
49
-
50
- uploader = uploaders(args[:type]).new(**args.slice(:results_glob, :bucket, :prefix, :copy_latest, :update_pr))
56
+ validate_args
57
+ validate_result_files
51
58
 
52
59
  log("Generating allure report")
53
60
  Spinner.spin("generating") { uploader.generate_report }
@@ -63,6 +70,24 @@ module Publisher
63
70
 
64
71
  private
65
72
 
73
+ attr_reader :args
74
+
75
+ # Uploader instance
76
+ #
77
+ # @return [Publisher::Uploaders::Uploader]
78
+ def uploader
79
+ @uploader ||= uploaders(args[:type]).new(
80
+ summary_type: args[:summary],
81
+ **args.slice(
82
+ :results_glob,
83
+ :bucket,
84
+ :prefix,
85
+ :copy_latest,
86
+ :update_pr
87
+ )
88
+ )
89
+ end
90
+
66
91
  # Uploader class
67
92
  #
68
93
  # @param [String] uploader
@@ -76,9 +101,8 @@ module Publisher
76
101
 
77
102
  # Validate required args
78
103
  #
79
- # @param [Hash] args
80
104
  # @return [void]
81
- def validate_args(args)
105
+ def validate_args
82
106
  error("Missing argument --results-glob!") unless args[:results_glob]
83
107
  error("Missing argument --bucket!") unless args[:bucket]
84
108
  end
@@ -87,7 +111,9 @@ module Publisher
87
111
  #
88
112
  # @param [String] results_glob
89
113
  # @return [void]
90
- def validate_result_files(results_glob, ignore)
114
+ def validate_result_files
115
+ results_glob = args[:results_glob]
116
+ ignore = args[:ignore_missing_results]
91
117
  return unless Dir.glob(results_glob).empty?
92
118
 
93
119
  log("Glob '#{results_glob}' did not match any files!", ignore ? :yellow : :red)
@@ -0,0 +1,133 @@
1
+ require "terminal-table"
2
+
3
+ module Publisher
4
+ module Helpers
5
+ # Test summary table generator
6
+ #
7
+ class Summary
8
+ BEHAVIORS = "behaviors".freeze
9
+ PACKAGES = "packages".freeze
10
+ SUITES = "suites".freeze
11
+ TOTAL = "total".freeze
12
+
13
+ # Summary table generator
14
+ #
15
+ # @param [String] report_path
16
+ # @param [String] summary_type
17
+ def initialize(report_path, summary_type)
18
+ @report_path = report_path
19
+ @summary_type = summary_type || TOTAL
20
+ end
21
+
22
+ # Summary table
23
+ #
24
+ # @return [Terminal::Table]
25
+ def table
26
+ return terminal_table([short_summary]) if summary_type == TOTAL
27
+
28
+ terminal_table(expanded_summary)
29
+ end
30
+
31
+ # Test run status emoji
32
+ #
33
+ # @return [String]
34
+ def status
35
+ short_summary.last
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :report_path, :summary_type
41
+
42
+ # Expanded summary table
43
+ #
44
+ # @return [Array<Array>]
45
+ def expanded_summary
46
+ @expanded_summary ||= summary_data.map do |name, summary|
47
+ [name, *summary.values, status_icon(summary[:failed], summary[:flaky])]
48
+ end
49
+ end
50
+
51
+ # Short summary table
52
+ #
53
+ # @return [Array<String>]
54
+ def short_summary
55
+ return @short_summary if defined?(@short_summary)
56
+
57
+ sum = summary_data.values.each_with_object({ passed: 0, failed: 0, skipped: 0, flaky: 0 }) do |entry, hsh|
58
+ hsh[:passed] += entry[:passed]
59
+ hsh[:failed] += entry[:failed]
60
+ hsh[:skipped] += entry[:skipped]
61
+ hsh[:flaky] += entry[:flaky]
62
+ end
63
+
64
+ @short_summary = [
65
+ "Total",
66
+ sum[:passed],
67
+ sum[:failed],
68
+ sum[:skipped],
69
+ sum[:flaky],
70
+ status_icon(sum[:failed], sum[:flaky])
71
+ ]
72
+ end
73
+
74
+ # Status icon based on run results
75
+ #
76
+ # @param [Integer] failed
77
+ # @param [Integer] flaky
78
+ # @return [String]
79
+ def status_icon(failed, flaky)
80
+ return flaky.zero? ? "✅" : "⚠️" if failed.zero?
81
+
82
+ "❌"
83
+ end
84
+
85
+ # Summary terminal table
86
+ #
87
+ # @param [Array] rows
88
+ # @return [Terminal::Table]
89
+ def terminal_table(rows)
90
+ Terminal::Table.new do |table|
91
+ table.title = "#{summary_type} summary"
92
+ table.headings = ["", "passed", "failed", "skipped", "flaky", "result"]
93
+ table.rows = rows
94
+ end
95
+ end
96
+
97
+ # Data json
98
+ #
99
+ # @return [Hash]
100
+ def data_json
101
+ @data_json ||= JSON.parse(
102
+ File.read(File.join(report_path, "data", "#{summary_type == TOTAL ? SUITES : summary_type}.json")),
103
+ symbolize_names: true
104
+ )
105
+ end
106
+
107
+ # Summary data
108
+ #
109
+ # @return [Hash<Hash>]
110
+ def summary_data
111
+ data_json[:children].each_with_object({}) do |entry, result|
112
+ result[entry[:name]] = fetch_results(entry)
113
+ end
114
+ end
115
+
116
+ # Fetch test results
117
+ #
118
+ # @param [Hash] entry
119
+ # @param [Hash] summary
120
+ # @return [Hash]
121
+ def fetch_results(entry, summary = { passed: 0, failed: 0, skipped: 0, flaky: 0 })
122
+ entry[:children].each { |item| fetch_results(item, summary) } if entry.key?(:children)
123
+
124
+ summary[:passed] += 1 if entry[:status] == "passed"
125
+ summary[:skipped] += 1 if entry[:status] == "skipped"
126
+ summary[:flaky] += 1 if entry[:flaky]
127
+ summary[:failed] += 1 if %w[failed broken].include?(entry[:status])
128
+
129
+ summary
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,131 @@
1
+ module Publisher
2
+ module Helpers
3
+ # Urls section builder
4
+ #
5
+ class UrlSectionBuilder
6
+ DESCRIPTION_PATTERN = /<!-- allure -->[\s\S]+<!-- allurestop -->/.freeze
7
+ JOBS_PATTERN = /<!-- jobs -->\n([\s\S]+)\n<!-- jobs -->/.freeze
8
+
9
+ # Url section builder
10
+ #
11
+ # @param [String] report_url
12
+ # @param [String] report_path
13
+ # @param [String] build_name
14
+ # @param [String] sha_url
15
+ # @param [String] summary_type
16
+ def initialize(report_url:, report_path:, build_name:, sha_url:, summary_type:)
17
+ @report_url = report_url
18
+ @report_path = report_path
19
+ @build_name = build_name
20
+ @sha_url = sha_url
21
+ @summary_type = summary_type
22
+ end
23
+
24
+ # Matches url section pattern
25
+ #
26
+ # @param [String] urls_block
27
+ # @return [Boolean]
28
+ def self.match?(urls_block)
29
+ urls_block.match?(DESCRIPTION_PATTERN)
30
+ end
31
+
32
+ # PR description with allure report urls
33
+ #
34
+ # @param [String] pr_description
35
+ # @return [String]
36
+ def updated_pr_description(pr_description)
37
+ stripped_description = (pr_description || "").strip
38
+
39
+ return url_section(separator: false) if stripped_description == ""
40
+ return "#{pr_description}\n\n#{url_section}" unless pr_description.match?(DESCRIPTION_PATTERN)
41
+
42
+ job_entries = jobs_section(pr_description)
43
+ non_empty = stripped_description != pr_description.match(DESCRIPTION_PATTERN)[0]
44
+ pr_description.gsub(DESCRIPTION_PATTERN, url_section(job_entries: job_entries, separator: non_empty))
45
+ end
46
+
47
+ # Comment body with allure report urls
48
+ #
49
+ # @param [String] pr_comment
50
+ # @return [String]
51
+ def comment_body(pr_comment = nil)
52
+ return url_section(separator: false) unless pr_comment
53
+
54
+ job_entries = jobs_section(pr_comment)
55
+ url_section(job_entries: job_entries, separator: false)
56
+ end
57
+
58
+ attr_reader :report_url,
59
+ :report_path,
60
+ :build_name,
61
+ :sha_url,
62
+ :summary_type
63
+
64
+ private
65
+
66
+ # Url section heading
67
+ #
68
+ # @return [String]
69
+ def heading
70
+ @heading ||= "# Allure report\n`allure-report-publisher` generated test report!"
71
+ end
72
+
73
+ # Test run summary
74
+ #
75
+ # @return [Helpers::Summary]
76
+ def summary
77
+ @summary ||= Helpers::Summary.new(report_path, summary_type)
78
+ end
79
+
80
+ # Single job report URL entry
81
+ #
82
+ # @return [String]
83
+ def job_entry
84
+ @job_entry ||= begin
85
+ entry = ["<!-- #{build_name} -->"]
86
+ entry << "**#{build_name}**: #{summary.status} [test report](#{report_url}) for #{sha_url}"
87
+ entry << "```markdown\n#{summary.table}\n```" if summary_type
88
+ entry << "<!-- #{build_name} -->"
89
+
90
+ entry.join("\n")
91
+ end
92
+ end
93
+
94
+ # Job entry pattern
95
+ #
96
+ # @return [RegExp]
97
+ def job_entry_pattern
98
+ @job_entry_pattern ||= /<!-- #{build_name} -->\n([\s\S]+)\n<!-- #{build_name} -->/
99
+ end
100
+
101
+ # Allure report url section
102
+ #
103
+ # @return [String]
104
+ def url_section(job_entries: job_entry, separator: true)
105
+ reports = <<~BODY.strip
106
+ <!-- allure -->
107
+ ---
108
+ #{heading}
109
+
110
+ <!-- jobs -->
111
+ #{job_entries}
112
+ <!-- jobs -->
113
+ <!-- allurestop -->
114
+ BODY
115
+
116
+ separator ? reports : reports.gsub("---\n", "")
117
+ end
118
+
119
+ # Return updated jobs section
120
+ #
121
+ # @param [String] urls
122
+ # @return [String]
123
+ def jobs_section(urls_block)
124
+ jobs = urls_block.match(JOBS_PATTERN)[1]
125
+ return jobs.gsub(job_entry_pattern, job_entry) if jobs.match?(job_entry_pattern)
126
+
127
+ "#{jobs}\n#{job_entry}"
128
+ end
129
+ end
130
+ end
131
+ end
@@ -15,9 +15,15 @@ module Publisher
15
15
  class Provider
16
16
  ALLURE_JOB_NAME = "ALLURE_JOB_NAME".freeze
17
17
 
18
- def initialize(report_url:, update_pr:)
18
+ # CI provider base
19
+ #
20
+ # @param [String] report_url
21
+ # @param [Boolean] update_pr
22
+ def initialize(report_url:, report_path:, update_pr:, summary_type:)
19
23
  @report_url = report_url
24
+ @report_path = report_path
20
25
  @update_pr = update_pr
26
+ @summary_type = summary_type
21
27
  end
22
28
 
23
29
  # :nocov:
@@ -58,7 +64,10 @@ module Publisher
58
64
 
59
65
  private
60
66
 
61
- attr_reader :report_url, :update_pr
67
+ attr_reader :report_url,
68
+ :report_path,
69
+ :update_pr,
70
+ :summary_type
62
71
 
63
72
  # Current pull request description
64
73
  #
@@ -113,8 +122,14 @@ module Publisher
113
122
  # Report urls section creator
114
123
  #
115
124
  # @return [ReportUrls]
116
- def report_urls
117
- @report_urls ||= UrlSectionBuilder.new(report_url: report_url, build_name: build_name, sha_url: sha_url)
125
+ def url_section_builder
126
+ @url_section_builder ||= Helpers::UrlSectionBuilder.new(
127
+ report_url: report_url,
128
+ report_path: report_path,
129
+ build_name: build_name,
130
+ sha_url: sha_url,
131
+ summary_type: summary_type
132
+ )
118
133
  end
119
134
  end
120
135
  end
@@ -58,16 +58,16 @@ module Publisher
58
58
  #
59
59
  # @return [void]
60
60
  def update_pr_description
61
- client.update_pull_request(repository, pr_id, body: report_urls.updated_pr_description(pr_description))
61
+ client.update_pull_request(repository, pr_id, body: url_section_builder.updated_pr_description(pr_description))
62
62
  end
63
63
 
64
64
  # Add comment with report url
65
65
  #
66
66
  # @return [void]
67
67
  def add_comment
68
- return client.add_comment(repository, pr_id, report_urls.comment_body) unless comment
68
+ return client.add_comment(repository, pr_id, url_section_builder.comment_body) unless comment
69
69
 
70
- client.update_comment(repository, comment[:id], report_urls.comment_body(comment[:body]))
70
+ client.update_comment(repository, comment[:id], url_section_builder.comment_body(comment[:body]))
71
71
  end
72
72
 
73
73
  # Existing comment with allure urls
@@ -75,7 +75,7 @@ module Publisher
75
75
  # @return [Sawyer::Resource]
76
76
  def comment
77
77
  @comment ||= client.issue_comments(repository, pr_id).detect do |comment|
78
- UrlSectionBuilder.match?(comment[:body])
78
+ Helpers::UrlSectionBuilder.match?(comment[:body])
79
79
  end
80
80
  end
81
81
 
@@ -48,16 +48,20 @@ module Publisher
48
48
  #
49
49
  # @return [void]
50
50
  def update_pr_description
51
- client.update_merge_request(project, mr_iid, description: report_urls.updated_pr_description(pr_description))
51
+ client.update_merge_request(
52
+ project,
53
+ mr_iid,
54
+ description: url_section_builder.updated_pr_description(pr_description)
55
+ )
52
56
  end
53
57
 
54
58
  # Add comment with report url
55
59
  #
56
60
  # @return [void]
57
61
  def add_comment
58
- return client.create_merge_request_comment(project, mr_iid, report_urls.comment_body) unless comment
62
+ return client.create_merge_request_comment(project, mr_iid, url_section_builder.comment_body) unless comment
59
63
 
60
- client.edit_merge_request_note(project, mr_iid, comment.id, report_urls.comment_body(comment.body))
64
+ client.edit_merge_request_note(project, mr_iid, comment.id, url_section_builder.comment_body(comment.body))
61
65
  end
62
66
 
63
67
  # Existing comment with allure urls
@@ -65,7 +69,7 @@ module Publisher
65
69
  # @return [Gitlab::ObjectifiedHash]
66
70
  def comment
67
71
  client.merge_request_comments(project, mr_iid).auto_paginate.detect do |comment|
68
- UrlSectionBuilder.match?(comment.body)
72
+ Helpers::UrlSectionBuilder.match?(comment.body)
69
73
  end
70
74
  end
71
75
 
@@ -10,10 +10,8 @@ module Publisher
10
10
  class ReportGenerator
11
11
  include Helpers
12
12
 
13
- def initialize(results_glob, results_path, report_path)
13
+ def initialize(results_glob)
14
14
  @results_glob = results_glob
15
- @results_path = results_path
16
- @report_path = report_path
17
15
  end
18
16
 
19
17
  # Generate allure report
@@ -24,9 +22,23 @@ module Publisher
24
22
  generate_report
25
23
  end
26
24
 
25
+ # Aggregated results directory
26
+ #
27
+ # @return [String]
28
+ def results_path
29
+ @results_path ||= Dir.mktmpdir("allure-results")
30
+ end
31
+
32
+ # Allure report directory
33
+ #
34
+ # @return [String]
35
+ def report_path
36
+ @report_path ||= Dir.mktmpdir("allure-report")
37
+ end
38
+
27
39
  private
28
40
 
29
- attr_reader :results_glob, :results_path, :report_path
41
+ attr_reader :results_glob
30
42
 
31
43
  # Copy all results files to results directory
32
44
  #
@@ -1,3 +1,5 @@
1
+ require "forwardable"
2
+
1
3
  module Publisher
2
4
  module Uploaders
3
5
  class HistoryNotFoundError < StandardError; end
@@ -6,6 +8,7 @@ module Publisher
6
8
  #
7
9
  class Uploader
8
10
  include Helpers
11
+ extend Forwardable
9
12
 
10
13
  EXECUTOR_JSON = "executor.json".freeze
11
14
  HISTORY = [
@@ -16,11 +19,12 @@ module Publisher
16
19
  "retry-trend.json"
17
20
  ].freeze
18
21
 
19
- def initialize(results_glob:, bucket:, update_pr: nil, prefix: nil, copy_latest: false)
22
+ def initialize(results_glob:, bucket:, update_pr: nil, prefix: nil, copy_latest: false, summary_type: nil) # rubocop:disable Metrics/ParameterLists
20
23
  @results_glob = results_glob
21
24
  @bucket_name = bucket
22
25
  @prefix = prefix
23
26
  @update_pr = update_pr
27
+ @summary_type = summary_type
24
28
  @copy_latest = !!(Providers.provider && copy_latest) # copy latest for ci only
25
29
  end
26
30
 
@@ -40,7 +44,7 @@ module Publisher
40
44
  add_history
41
45
  add_executor_info
42
46
 
43
- ReportGenerator.new(results_glob, results_path, report_path).generate
47
+ report_generator.generate
44
48
  end
45
49
 
46
50
  # Upload report to storage provider
@@ -78,7 +82,14 @@ module Publisher
78
82
 
79
83
  private
80
84
 
81
- attr_reader :results_glob, :bucket_name, :prefix, :update_pr, :copy_latest
85
+ attr_reader :results_glob,
86
+ :bucket_name,
87
+ :prefix,
88
+ :update_pr,
89
+ :copy_latest,
90
+ :summary_type
91
+
92
+ def_delegators :report_generator, :results_path, :report_path
82
93
 
83
94
  # :nocov:
84
95
 
@@ -132,34 +143,31 @@ module Publisher
132
143
  end
133
144
  # :nocov:
134
145
 
135
- # Add allure history
146
+ # Allure report generator
136
147
  #
137
- # @return [void]
138
- def add_history
139
- create_history_dir
140
- download_history
141
- rescue HistoryNotFoundError
142
- nil
148
+ # @return [Publisher::ReportGenerator]
149
+ def report_generator
150
+ @report_generator ||= ReportGenerator.new(results_glob)
143
151
  end
144
152
 
145
- # Add CI executor info
153
+ # Report path prefix
146
154
  #
147
- # @return [void]
148
- def add_executor_info
149
- return unless ci_provider
155
+ # @return [String]
156
+ def full_prefix
157
+ @full_prefix ||= [prefix, run_id].compact.yield_self do |pre|
158
+ break if pre.empty?
150
159
 
151
- File.open("#{results_path}/#{EXECUTOR_JSON}", "w") do |file|
152
- file.write(ci_provider.executor_info.to_json)
160
+ pre.join("/")
153
161
  end
154
162
  end
155
163
 
156
- # Run upload commands
164
+ # Report files
157
165
  #
158
- # @return [void]
159
- def run_uploads
160
- upload_history unless !run_id || copy_latest
161
- upload_report
162
- upload_latest_copy if copy_latest
166
+ # @return [Array<Pathname>]
167
+ def report_files
168
+ @report_files ||= Pathname
169
+ .glob("#{report_path}/**/*")
170
+ .reject(&:directory?)
163
171
  end
164
172
 
165
173
  # Get run id
@@ -175,48 +183,47 @@ module Publisher
175
183
  def ci_provider
176
184
  return @ci_provider if defined?(@ci_provider)
177
185
 
178
- @ci_provider = Providers.provider&.new(report_url: report_url, update_pr: update_pr)
186
+ @ci_provider = Providers.provider&.new(
187
+ report_url: report_url,
188
+ report_path: report_path,
189
+ update_pr: update_pr,
190
+ summary_type: summary_type
191
+ )
179
192
  end
180
193
 
181
- # Fetch allure report history
194
+ # Add allure history
182
195
  #
183
196
  # @return [void]
184
- def create_history_dir
185
- FileUtils.mkdir_p(path(results_path, "history"))
197
+ def add_history
198
+ create_history_dir
199
+ download_history
200
+ rescue HistoryNotFoundError
201
+ nil
186
202
  end
187
203
 
188
- # Report path prefix
204
+ # Add CI executor info
189
205
  #
190
- # @return [String]
191
- def full_prefix
192
- @full_prefix ||= [prefix, run_id].compact.yield_self do |pre|
193
- break if pre.empty?
194
-
195
- pre.join("/")
196
- end
197
- end
206
+ # @return [void]
207
+ def add_executor_info
208
+ return unless ci_provider
198
209
 
199
- # Aggregated results directory
200
- #
201
- # @return [String]
202
- def results_path
203
- @results_path ||= Dir.mktmpdir("allure-results")
210
+ File.write("#{results_path}/#{EXECUTOR_JSON}", ci_provider.executor_info.to_json)
204
211
  end
205
212
 
206
- # Allure report directory
213
+ # Run upload commands
207
214
  #
208
- # @return [String]
209
- def report_path
210
- @report_path ||= Dir.mktmpdir("allure-report")
215
+ # @return [void]
216
+ def run_uploads
217
+ upload_history unless !run_id || copy_latest
218
+ upload_report
219
+ upload_latest_copy if copy_latest
211
220
  end
212
221
 
213
- # Report files
222
+ # Fetch allure report history
214
223
  #
215
- # @return [Array<Pathname>]
216
- def report_files
217
- @report_files ||= Pathname
218
- .glob("#{report_path}/**/*")
219
- .reject(&:directory?)
224
+ # @return [void]
225
+ def create_history_dir
226
+ FileUtils.mkdir_p(path(results_path, "history"))
220
227
  end
221
228
  end
222
229
  end
@@ -1,4 +1,5 @@
1
1
  require "aws-sdk-s3"
2
+ require "mini_mime"
2
3
 
3
4
  module Publisher
4
5
  module Uploaders
@@ -88,7 +89,8 @@ module Publisher
88
89
  {
89
90
  body: File.new(file),
90
91
  bucket: bucket_name,
91
- key: key(key_prefix, file.relative_path_from(report_path))
92
+ key: key(key_prefix, file.relative_path_from(report_path)),
93
+ content_type: MiniMime.lookup_by_filename(file).content_type
92
94
  }
93
95
  end
94
96
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Publisher
4
- VERSION = "0.4.2"
4
+ VERSION = "0.5.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: allure-report-publisher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrejs Cunskis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-15 00:00:00.000000000 Z
11
+ date: 2022-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 1.93.1
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 1.110.0
22
+ version: 1.114.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 1.93.1
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 1.110.0
32
+ version: 1.114.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: dry-cli
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -78,6 +78,20 @@ dependencies:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
80
  version: '1.31'
81
+ - !ruby/object:Gem::Dependency
82
+ name: mini_mime
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.1'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.1'
81
95
  - !ruby/object:Gem::Dependency
82
96
  name: octokit
83
97
  requirement: !ruby/object:Gem::Requirement
@@ -134,6 +148,20 @@ dependencies:
134
148
  - - "~>"
135
149
  - !ruby/object:Gem::Version
136
150
  version: 3.0.0
151
+ - !ruby/object:Gem::Dependency
152
+ name: terminal-table
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '3.0'
158
+ type: :runtime
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '3.0'
137
165
  - !ruby/object:Gem::Dependency
138
166
  name: tty-spinner
139
167
  requirement: !ruby/object:Gem::Requirement
@@ -148,6 +176,174 @@ dependencies:
148
176
  - - "~>"
149
177
  - !ruby/object:Gem::Version
150
178
  version: 0.9.3
179
+ - !ruby/object:Gem::Dependency
180
+ name: allure-rspec
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: 2.17.0
186
+ type: :development
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: 2.17.0
193
+ - !ruby/object:Gem::Dependency
194
+ name: climate_control
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: 1.0.1
200
+ type: :development
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - "~>"
205
+ - !ruby/object:Gem::Version
206
+ version: 1.0.1
207
+ - !ruby/object:Gem::Dependency
208
+ name: pry-byebug
209
+ requirement: !ruby/object:Gem::Requirement
210
+ requirements:
211
+ - - "~>"
212
+ - !ruby/object:Gem::Version
213
+ version: '3.9'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - "~>"
219
+ - !ruby/object:Gem::Version
220
+ version: '3.9'
221
+ - !ruby/object:Gem::Dependency
222
+ name: rake
223
+ requirement: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - "~>"
226
+ - !ruby/object:Gem::Version
227
+ version: '13.0'
228
+ type: :development
229
+ prerelease: false
230
+ version_requirements: !ruby/object:Gem::Requirement
231
+ requirements:
232
+ - - "~>"
233
+ - !ruby/object:Gem::Version
234
+ version: '13.0'
235
+ - !ruby/object:Gem::Dependency
236
+ name: rspec
237
+ requirement: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - "~>"
240
+ - !ruby/object:Gem::Version
241
+ version: '3.11'
242
+ type: :development
243
+ prerelease: false
244
+ version_requirements: !ruby/object:Gem::Requirement
245
+ requirements:
246
+ - - "~>"
247
+ - !ruby/object:Gem::Version
248
+ version: '3.11'
249
+ - !ruby/object:Gem::Dependency
250
+ name: rubocop
251
+ requirement: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - "~>"
254
+ - !ruby/object:Gem::Version
255
+ version: '1.27'
256
+ type: :development
257
+ prerelease: false
258
+ version_requirements: !ruby/object:Gem::Requirement
259
+ requirements:
260
+ - - "~>"
261
+ - !ruby/object:Gem::Version
262
+ version: '1.27'
263
+ - !ruby/object:Gem::Dependency
264
+ name: rubocop-performance
265
+ requirement: !ruby/object:Gem::Requirement
266
+ requirements:
267
+ - - "~>"
268
+ - !ruby/object:Gem::Version
269
+ version: '1.13'
270
+ type: :development
271
+ prerelease: false
272
+ version_requirements: !ruby/object:Gem::Requirement
273
+ requirements:
274
+ - - "~>"
275
+ - !ruby/object:Gem::Version
276
+ version: '1.13'
277
+ - !ruby/object:Gem::Dependency
278
+ name: rubocop-rake
279
+ requirement: !ruby/object:Gem::Requirement
280
+ requirements:
281
+ - - "~>"
282
+ - !ruby/object:Gem::Version
283
+ version: 0.6.0
284
+ type: :development
285
+ prerelease: false
286
+ version_requirements: !ruby/object:Gem::Requirement
287
+ requirements:
288
+ - - "~>"
289
+ - !ruby/object:Gem::Version
290
+ version: 0.6.0
291
+ - !ruby/object:Gem::Dependency
292
+ name: rubocop-rspec
293
+ requirement: !ruby/object:Gem::Requirement
294
+ requirements:
295
+ - - "~>"
296
+ - !ruby/object:Gem::Version
297
+ version: '2.9'
298
+ type: :development
299
+ prerelease: false
300
+ version_requirements: !ruby/object:Gem::Requirement
301
+ requirements:
302
+ - - "~>"
303
+ - !ruby/object:Gem::Version
304
+ version: '2.9'
305
+ - !ruby/object:Gem::Dependency
306
+ name: simplecov
307
+ requirement: !ruby/object:Gem::Requirement
308
+ requirements:
309
+ - - "~>"
310
+ - !ruby/object:Gem::Version
311
+ version: 0.21.2
312
+ type: :development
313
+ prerelease: false
314
+ version_requirements: !ruby/object:Gem::Requirement
315
+ requirements:
316
+ - - "~>"
317
+ - !ruby/object:Gem::Version
318
+ version: 0.21.2
319
+ - !ruby/object:Gem::Dependency
320
+ name: simplecov-console
321
+ requirement: !ruby/object:Gem::Requirement
322
+ requirements:
323
+ - - "~>"
324
+ - !ruby/object:Gem::Version
325
+ version: 0.9.1
326
+ type: :development
327
+ prerelease: false
328
+ version_requirements: !ruby/object:Gem::Requirement
329
+ requirements:
330
+ - - "~>"
331
+ - !ruby/object:Gem::Version
332
+ version: 0.9.1
333
+ - !ruby/object:Gem::Dependency
334
+ name: solargraph
335
+ requirement: !ruby/object:Gem::Requirement
336
+ requirements:
337
+ - - "~>"
338
+ - !ruby/object:Gem::Version
339
+ version: 0.44.3
340
+ type: :development
341
+ prerelease: false
342
+ version_requirements: !ruby/object:Gem::Requirement
343
+ requirements:
344
+ - - "~>"
345
+ - !ruby/object:Gem::Version
346
+ version: 0.44.3
151
347
  description: Upload allure reports to different file storage providers
152
348
  email:
153
349
  - andrejs.cunskis@gmail.com
@@ -163,10 +359,11 @@ files:
163
359
  - lib/allure_report_publisher/commands/version.rb
164
360
  - lib/allure_report_publisher/lib/helpers/helpers.rb
165
361
  - lib/allure_report_publisher/lib/helpers/spinner.rb
362
+ - lib/allure_report_publisher/lib/helpers/summary.rb
363
+ - lib/allure_report_publisher/lib/helpers/url_section_builder.rb
166
364
  - lib/allure_report_publisher/lib/providers/_provider.rb
167
365
  - lib/allure_report_publisher/lib/providers/github.rb
168
366
  - lib/allure_report_publisher/lib/providers/gitlab.rb
169
- - lib/allure_report_publisher/lib/providers/url_section_builder.rb
170
367
  - lib/allure_report_publisher/lib/report_generator.rb
171
368
  - lib/allure_report_publisher/lib/uploaders/_uploader.rb
172
369
  - lib/allure_report_publisher/lib/uploaders/gcs.rb
@@ -197,7 +394,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
197
394
  - !ruby/object:Gem::Version
198
395
  version: '0'
199
396
  requirements: []
200
- rubygems_version: 3.2.32
397
+ rubygems_version: 3.3.7
201
398
  signing_key:
202
399
  specification_version: 4
203
400
  summary: Allure report uploader
@@ -1,97 +0,0 @@
1
- module Publisher
2
- module Providers
3
- # Urls section builder
4
- #
5
- class UrlSectionBuilder
6
- DESCRIPTION_PATTERN = /<!-- allure -->[\s\S]+<!-- allurestop -->/.freeze
7
- JOBS_PATTERN = /<!-- jobs -->\n([\s\S]+)\n<!-- jobs -->/.freeze
8
-
9
- def initialize(report_url:, build_name:, sha_url:)
10
- @report_url = report_url
11
- @build_name = build_name
12
- @sha_url = sha_url
13
- end
14
-
15
- # Matches url section pattern
16
- #
17
- # @param [String] urls_block
18
- # @return [Boolean]
19
- def self.match?(urls_block)
20
- urls_block.match?(DESCRIPTION_PATTERN)
21
- end
22
-
23
- # Get urls for PR update
24
- #
25
- # @param [String] pr
26
- # @return [String]
27
- def updated_pr_description(pr_description)
28
- return "#{pr_description}\n\n#{body}" unless pr_description.match?(DESCRIPTION_PATTERN)
29
-
30
- job_entries = jobs_section(pr_description)
31
- pr_description.gsub(DESCRIPTION_PATTERN, body(job_entries))
32
- end
33
-
34
- # Allure report url comment
35
- #
36
- # @return [String]
37
- def comment_body(pr_comment = nil)
38
- return body.gsub("---\n", "") unless pr_comment
39
-
40
- job_entries = jobs_section(pr_comment)
41
- body(job_entries).gsub("---\n", "")
42
- end
43
-
44
- attr_reader :report_url, :build_name, :sha_url
45
-
46
- private
47
-
48
- # Allure report url pr description
49
- #
50
- # @return [String]
51
- def body(job_entries = job_entry)
52
- @body ||= <<~BODY.strip
53
- <!-- allure -->
54
- ---
55
- #{heading}
56
-
57
- <!-- jobs -->
58
- #{job_entries}
59
- <!-- jobs -->
60
- <!-- allurestop -->
61
- BODY
62
- end
63
-
64
- # Url section heading
65
- #
66
- # @return [String]
67
- def heading
68
- @heading ||= "# Allure report\n`allure-report-publisher` generated test report for #{sha_url}!"
69
- end
70
-
71
- # Return updated jobs section
72
- #
73
- # @param [String] urls
74
- # @return [String]
75
- def jobs_section(urls_block)
76
- jobs = urls_block.match(JOBS_PATTERN)[1]
77
- return jobs.gsub(job_entry_pattern, job_entry) if jobs.match?(job_entry_pattern)
78
-
79
- "#{jobs}\n#{job_entry}"
80
- end
81
-
82
- # Single job report URL entry
83
- #
84
- # @return [String]
85
- def job_entry
86
- @job_entry ||= "**#{build_name}**: 📝 [test report](#{report_url})<br />"
87
- end
88
-
89
- # Job entry pattern
90
- #
91
- # @return [RegExp]
92
- def job_entry_pattern
93
- @job_entry_pattern ||= %r{^\*\*#{build_name}\*\*:.*\[test report\]\(.*\)<br />$}
94
- end
95
- end
96
- end
97
- end