allure-report-publisher 0.4.3 → 0.5.3

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: 8f757600df186b938fd2cc55ea286e756c085c8a9d05bc24ceb1f003e4b3f59b
4
- data.tar.gz: fb991d06db323e8e0908c23af93f740b548849538bcfccc402bb81e6a95895b3
3
+ metadata.gz: f65f9f3b2b9dafec360e713beab7a54a7c70aa3175b631879c48fd12ac585f20
4
+ data.tar.gz: 5b07128e2401f75e6471bde00f4eec36c93a4e3bf54c48db2c21c171efda03a4
5
5
  SHA512:
6
- metadata.gz: d3388a7c26dbc51a285c7bc9d1a767081d1feb661d83e6762ebba270cb73a4f2cee72b6429b2d75c1be83f767ca40617195f2151fd5c178a978b031c014e83bc
7
- data.tar.gz: 1f7f6bcceb4db8369c9a64674213e2e9b6f751bf7cf9bfa617b8f45377711e0809be2183a0cebb13be3c6f34f5e48b194ba7d27ac4656b0c961f765a8d218e18
6
+ metadata.gz: d0fcf8fc805e8955cce389d6bccee27253507fcc8926d43af4a7b0ebb2ffb6db8fe5a42834fae8d8e443f039388d6b3788f7fa63fcab68441f893dcd54582bc8
7
+ data.tar.gz: 3c0b298e4ba099532a2938b28f1b0920e4dffc4a5a57bcd38f583db5e8c0a289da450869c2f5ab46d62147ae7b819ebad71ee8a063b84fccf1c4c4bbde17f1d6
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,138 @@
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 { |table| table << short_summary } if summary_type == TOTAL
27
+
28
+ terminal_table do |table|
29
+ expanded_summary.each { |row| table << row }
30
+ table << :separator
31
+ table << short_summary
32
+ end
33
+ end
34
+
35
+ # Test run status emoji
36
+ #
37
+ # @return [String]
38
+ def status
39
+ short_summary.last
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :report_path, :summary_type
45
+
46
+ # Expanded summary table
47
+ #
48
+ # @return [Array<Array>]
49
+ def expanded_summary
50
+ @expanded_summary ||= summary_data.map do |name, summary|
51
+ [name, *summary.values, status_icon(summary[:passed], summary[:failed], summary[:flaky])]
52
+ end
53
+ end
54
+
55
+ # Short summary table
56
+ #
57
+ # @return [Array<String>]
58
+ def short_summary
59
+ return @short_summary if defined?(@short_summary)
60
+
61
+ sum = summary_data.values.each_with_object({ passed: 0, failed: 0, skipped: 0, flaky: 0 }) do |entry, hsh|
62
+ hsh[:passed] += entry[:passed]
63
+ hsh[:failed] += entry[:failed]
64
+ hsh[:skipped] += entry[:skipped]
65
+ hsh[:flaky] += entry[:flaky]
66
+ end
67
+
68
+ @short_summary = [
69
+ "Total",
70
+ sum[:passed],
71
+ sum[:failed],
72
+ sum[:skipped],
73
+ sum[:flaky],
74
+ status_icon(sum[:passed], sum[:failed], sum[:flaky])
75
+ ]
76
+ end
77
+
78
+ # Status icon based on run results
79
+ #
80
+ # @param [Integer] passed
81
+ # @param [Integer] failed
82
+ # @param [Integer] flaky
83
+ # @return [String]
84
+ def status_icon(passed, failed, flaky)
85
+ return "➖" if passed.zero? && failed.zero?
86
+ return flaky.zero? ? "✅" : "⚠️" if failed.zero?
87
+
88
+ "❌"
89
+ end
90
+
91
+ # Summary terminal table
92
+ #
93
+ # @return [Terminal::Table]
94
+ def terminal_table
95
+ Terminal::Table.new do |table|
96
+ table.title = "#{summary_type} summary"
97
+ table.headings = ["", "passed", "failed", "skipped", "flaky", "result"]
98
+ yield(table)
99
+ end
100
+ end
101
+
102
+ # Data json
103
+ #
104
+ # @return [Hash]
105
+ def data_json
106
+ @data_json ||= JSON.parse(
107
+ File.read(File.join(report_path, "data", "#{summary_type == TOTAL ? SUITES : summary_type}.json")),
108
+ symbolize_names: true
109
+ )
110
+ end
111
+
112
+ # Summary data
113
+ #
114
+ # @return [Hash<Hash>]
115
+ def summary_data
116
+ data_json[:children].each_with_object({}) do |entry, result|
117
+ result[entry[:name]] = fetch_results(entry)
118
+ end
119
+ end
120
+
121
+ # Fetch test results
122
+ #
123
+ # @param [Hash] entry
124
+ # @param [Hash] summary
125
+ # @return [Hash]
126
+ def fetch_results(entry, summary = { passed: 0, failed: 0, skipped: 0, flaky: 0 })
127
+ entry[:children].each { |item| fetch_results(item, summary) } if entry.key?(:children)
128
+
129
+ summary[:passed] += 1 if entry[:status] == "passed"
130
+ summary[:skipped] += 1 if entry[:status] == "skipped"
131
+ summary[:flaky] += 1 if entry[:flaky]
132
+ summary[:failed] += 1 if %w[failed broken].include?(entry[:status])
133
+
134
+ summary
135
+ end
136
+ end
137
+ end
138
+ 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,32 +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.write("#{results_path}/#{EXECUTOR_JSON}", ci_provider.executor_info.to_json)
160
+ pre.join("/")
161
+ end
152
162
  end
153
163
 
154
- # Run upload commands
164
+ # Report files
155
165
  #
156
- # @return [void]
157
- def run_uploads
158
- upload_history unless !run_id || copy_latest
159
- upload_report
160
- 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?)
161
171
  end
162
172
 
163
173
  # Get run id
@@ -173,48 +183,47 @@ module Publisher
173
183
  def ci_provider
174
184
  return @ci_provider if defined?(@ci_provider)
175
185
 
176
- @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
+ )
177
192
  end
178
193
 
179
- # Fetch allure report history
194
+ # Add allure history
180
195
  #
181
196
  # @return [void]
182
- def create_history_dir
183
- FileUtils.mkdir_p(path(results_path, "history"))
197
+ def add_history
198
+ create_history_dir
199
+ download_history
200
+ rescue HistoryNotFoundError
201
+ nil
184
202
  end
185
203
 
186
- # Report path prefix
204
+ # Add CI executor info
187
205
  #
188
- # @return [String]
189
- def full_prefix
190
- @full_prefix ||= [prefix, run_id].compact.yield_self do |pre|
191
- break if pre.empty?
192
-
193
- pre.join("/")
194
- end
195
- end
206
+ # @return [void]
207
+ def add_executor_info
208
+ return unless ci_provider
196
209
 
197
- # Aggregated results directory
198
- #
199
- # @return [String]
200
- def results_path
201
- @results_path ||= Dir.mktmpdir("allure-results")
210
+ File.write("#{results_path}/#{EXECUTOR_JSON}", ci_provider.executor_info.to_json)
202
211
  end
203
212
 
204
- # Allure report directory
213
+ # Run upload commands
205
214
  #
206
- # @return [String]
207
- def report_path
208
- @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
209
220
  end
210
221
 
211
- # Report files
222
+ # Fetch allure report history
212
223
  #
213
- # @return [Array<Pathname>]
214
- def report_files
215
- @report_files ||= Pathname
216
- .glob("#{report_path}/**/*")
217
- .reject(&:directory?)
224
+ # @return [void]
225
+ def create_history_dir
226
+ FileUtils.mkdir_p(path(results_path, "history"))
218
227
  end
219
228
  end
220
229
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Publisher
4
- VERSION = "0.4.3"
4
+ VERSION = "0.5.3"
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.3
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrejs Cunskis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-06 00:00:00.000000000 Z
11
+ date: 2022-04-18 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.113.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.113.0
32
+ version: 1.114.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: dry-cli
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -148,6 +148,20 @@ dependencies:
148
148
  - - "~>"
149
149
  - !ruby/object:Gem::Version
150
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'
151
165
  - !ruby/object:Gem::Dependency
152
166
  name: tty-spinner
153
167
  requirement: !ruby/object:Gem::Requirement
@@ -162,6 +176,174 @@ dependencies:
162
176
  - - "~>"
163
177
  - !ruby/object:Gem::Version
164
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
165
347
  description: Upload allure reports to different file storage providers
166
348
  email:
167
349
  - andrejs.cunskis@gmail.com
@@ -177,10 +359,11 @@ files:
177
359
  - lib/allure_report_publisher/commands/version.rb
178
360
  - lib/allure_report_publisher/lib/helpers/helpers.rb
179
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
180
364
  - lib/allure_report_publisher/lib/providers/_provider.rb
181
365
  - lib/allure_report_publisher/lib/providers/github.rb
182
366
  - lib/allure_report_publisher/lib/providers/gitlab.rb
183
- - lib/allure_report_publisher/lib/providers/url_section_builder.rb
184
367
  - lib/allure_report_publisher/lib/report_generator.rb
185
368
  - lib/allure_report_publisher/lib/uploaders/_uploader.rb
186
369
  - lib/allure_report_publisher/lib/uploaders/gcs.rb
@@ -211,7 +394,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
394
  - !ruby/object:Gem::Version
212
395
  version: '0'
213
396
  requirements: []
214
- rubygems_version: 3.3.3
397
+ rubygems_version: 3.3.7
215
398
  signing_key:
216
399
  specification_version: 4
217
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