Commit 9f7de974 authored by Andrejs Cunskis's avatar Andrejs Cunskis

Automatically close previous reliable test reports

parent cb0c29e4
...@@ -20,9 +20,7 @@ module QA ...@@ -20,9 +20,7 @@ module QA
verify_ssl: false verify_ssl: false
} }
RestClient::Request.execute( RestClient::Request.execute(default_args.merge(args))
default_args.merge(args)
)
rescue RestClient::ExceptionWithResponse => e rescue RestClient::ExceptionWithResponse => e
return_response_or_raise(e) return_response_or_raise(e)
end end
...@@ -56,13 +54,16 @@ module QA ...@@ -56,13 +54,16 @@ module QA
end end
end end
def put(url, payload = nil) def put(url, payload = nil, args = {})
with_retry_on_too_many_requests do with_retry_on_too_many_requests do
RestClient::Request.execute( default_args = {
method: :put, method: :put,
url: url, url: url,
payload: payload, payload: payload,
verify_ssl: false) verify_ssl: false
}
RestClient::Request.execute(default_args.merge(args))
rescue RestClient::ExceptionWithResponse => e rescue RestClient::ExceptionWithResponse => e
return_response_or_raise(e) return_response_or_raise(e)
end end
......
...@@ -11,6 +11,8 @@ module QA ...@@ -11,6 +11,8 @@ module QA
include Support::InfluxdbTools include Support::InfluxdbTools
include Support::API include Support::API
RELIABLE_REPORT_LABEL = "reliable test report"
# Project for report creation: https://gitlab.com/gitlab-org/gitlab # Project for report creation: https://gitlab.com/gitlab-org/gitlab
PROJECT_ID = 278964 PROJECT_ID = 278964
...@@ -28,7 +30,11 @@ module QA ...@@ -28,7 +30,11 @@ module QA
reporter = new(range) reporter = new(range)
reporter.print_report reporter.print_report
reporter.report_in_issue_and_slack if report_in_issue_and_slack == "true"
if report_in_issue_and_slack == "true"
reporter.report_in_issue_and_slack
reporter.close_previous_reports
end
rescue StandardError => e rescue StandardError => e
reporter&.notify_failure(e) reporter&.notify_failure(e)
raise(e) raise(e)
...@@ -51,16 +57,15 @@ module QA ...@@ -51,16 +57,15 @@ module QA
# @return [void] # @return [void]
def report_in_issue_and_slack def report_in_issue_and_slack
puts "Creating report".colorize(:green) puts "Creating report".colorize(:green)
response = post( issue = api_update(
"#{gitlab_api_url}/projects/#{PROJECT_ID}/issues", :post,
{ "projects/#{PROJECT_ID}/issues",
title: "Reliable e2e test report", title: "Reliable e2e test report",
description: report_issue_body, description: report_issue_body,
labels: "Quality,test,type::maintenance,reliable test report,automation:ml" labels: "#{RELIABLE_REPORT_LABEL},Quality,test,type::maintenance,automation:ml"
},
headers: { "PRIVATE-TOKEN" => gitlab_access_token }
) )
web_url = parse_body(response)[:web_url] @report_iid = issue[:iid]
web_url = issue[:web_url]
puts "Created report issue: #{web_url}" puts "Created report issue: #{web_url}"
puts "Sending slack notification".colorize(:green) puts "Sending slack notification".colorize(:green)
...@@ -76,6 +81,25 @@ module QA ...@@ -76,6 +81,25 @@ module QA
puts "Done!" puts "Done!"
end end
# Close previous reliable test reports
#
# @return [void]
def close_previous_reports
puts "Closing previous reports".colorize(:green)
issues = api_get("projects/#{PROJECT_ID}/issues?labels=#{RELIABLE_REPORT_LABEL}&state=opened")
issues
.reject { |issue| issue[:iid] == report_iid }
.each do |issue|
issue_iid = issue[:iid]
issue_endpoint = "projects/#{PROJECT_ID}/issues/#{issue_iid}"
puts "Closing previous report '#{issue[:web_url]}'"
api_update(:put, issue_endpoint, state_event: "close")
api_update(:post, "#{issue_endpoint}/notes", body: "Closed issue in favor of ##{report_iid}")
end
end
# Notify failure # Notify failure
# #
# @param [StandardError] error # @param [StandardError] error
...@@ -89,7 +113,39 @@ module QA ...@@ -89,7 +113,39 @@ module QA
private private
attr_reader :range, :slack_channel attr_reader :range, :slack_channel, :report_iid
# Slack notifier
#
# @return [Slack::Notifier]
def notifier
@notifier ||= Slack::Notifier.new(
slack_webhook_url,
channel: slack_channel,
username: "Reliable Spec Report"
)
end
# Gitlab access token
#
# @return [String]
def gitlab_access_token
@gitlab_access_token ||= ENV["GITLAB_ACCESS_TOKEN"] || raise("Missing GITLAB_ACCESS_TOKEN env variable")
end
# Gitlab api url
#
# @return [String]
def gitlab_api_url
@gitlab_api_url ||= ENV["CI_API_V4_URL"] || raise("Missing CI_API_V4_URL env variable")
end
# Slack webhook url
#
# @return [String]
def slack_webhook_url
@slack_webhook_url ||= ENV["SLACK_WEBHOOK"] || raise("Missing SLACK_WEBHOOK env variable")
end
# Markdown formatted report issue body # Markdown formatted report issue body
# #
...@@ -323,36 +379,30 @@ module QA ...@@ -323,36 +379,30 @@ module QA
QUERY QUERY
end end
# Slack notifier # Api get request
#
# @return [Slack::Notifier]
def notifier
@notifier ||= Slack::Notifier.new(
slack_webhook_url,
channel: slack_channel,
username: "Reliable Spec Report"
)
end
# Gitlab access token
# #
# @return [String] # @param [String] path
def gitlab_access_token # @param [Hash] payload
@gitlab_access_token ||= ENV["GITLAB_ACCESS_TOKEN"] || raise("Missing GITLAB_ACCESS_TOKEN env variable") # @return [Hash, Array]
def api_get(path)
response = get("#{gitlab_api_url}/#{path}", { headers: { "PRIVATE-TOKEN" => gitlab_access_token } })
parse_body(response)
end end
# Gitlab api url # Api update request
# #
# @return [String] # @param [Symbol] verb :post or :put
def gitlab_api_url # @param [String] path
@gitlab_api_url ||= ENV["CI_API_V4_URL"] || raise("Missing CI_API_V4_URL env variable") # @param [Hash] payload
end # @return [Hash, Array]
def api_update(verb, path, **payload)
# Slack webhook url response = send(
# verb,
# @return [String] "#{gitlab_api_url}/#{path}",
def slack_webhook_url payload,
@slack_webhook_url ||= ENV["SLACK_WEBHOOK"] || raise("Missing SLACK_WEBHOOK env variable") { headers: { "PRIVATE-TOKEN" => gitlab_access_token } }
)
parse_body(response)
end end
end end
end end
......
...@@ -5,7 +5,6 @@ describe QA::Tools::ReliableReport do ...@@ -5,7 +5,6 @@ describe QA::Tools::ReliableReport do
subject(:run) { described_class.run(range: range, report_in_issue_and_slack: create_issue) } subject(:run) { described_class.run(range: range, report_in_issue_and_slack: create_issue) }
let(:gitlab_response) { instance_double("RestClient::Response", code: 200, body: { web_url: issue_url }.to_json) }
let(:slack_notifier) { instance_double("Slack::Notifier", post: nil) } let(:slack_notifier) { instance_double("Slack::Notifier", post: nil) }
let(:influx_client) { instance_double("InfluxDB2::Client", create_query_api: query_api) } let(:influx_client) { instance_double("InfluxDB2::Client", create_query_api: query_api) }
let(:query_api) { instance_double("InfluxDB2::QueryApi") } let(:query_api) { instance_double("InfluxDB2::QueryApi") }
...@@ -117,7 +116,7 @@ describe QA::Tools::ReliableReport do ...@@ -117,7 +116,7 @@ describe QA::Tools::ReliableReport do
stub_env("CI_API_V4_URL", "gitlab_api_url") stub_env("CI_API_V4_URL", "gitlab_api_url")
stub_env("GITLAB_ACCESS_TOKEN", "gitlab_token") stub_env("GITLAB_ACCESS_TOKEN", "gitlab_token")
allow(RestClient::Request).to receive(:execute).and_return(gitlab_response) allow(RestClient::Request).to receive(:execute)
allow(Slack::Notifier).to receive(:new).and_return(slack_notifier) allow(Slack::Notifier).to receive(:new).and_return(slack_notifier)
allow(InfluxDB2::Client).to receive(:new).and_return(influx_client) allow(InfluxDB2::Client).to receive(:new).and_return(influx_client)
...@@ -138,6 +137,37 @@ describe QA::Tools::ReliableReport do ...@@ -138,6 +137,37 @@ describe QA::Tools::ReliableReport do
context "with report creation" do context "with report creation" do
let(:create_issue) { "true" } let(:create_issue) { "true" }
let(:iid) { 2 }
let(:old_iid) { 1 }
let(:issue_endpoint) { "gitlab_api_url/projects/278964/issues" }
let(:common_api_args) do
{
verify_ssl: false,
headers: { "PRIVATE-TOKEN" => "gitlab_token" }
}
end
let(:create_issue_response) do
instance_double(
"RestClient::Response",
code: 200,
body: { web_url: issue_url, iid: iid }.to_json
)
end
let(:open_issues_response) do
instance_double(
"RestClient::Response",
code: 200,
body: [{ web_url: issue_url, iid: iid }, { web_url: issue_url, iid: old_iid }].to_json
)
end
let(:success_response) do
instance_double("RestClient::Response", code: 200, body: {}.to_json)
end
let(:issue_body) do let(:issue_body) do
<<~TXT.strip <<~TXT.strip
[[_TOC_]] [[_TOC_]]
...@@ -156,19 +186,48 @@ describe QA::Tools::ReliableReport do ...@@ -156,19 +186,48 @@ describe QA::Tools::ReliableReport do
TXT TXT
end end
it "creates report issue", :aggregate_failures do before do
allow(RestClient::Request).to receive(:execute).exactly(4).times.and_return(
create_issue_response,
open_issues_response,
success_response,
success_response
)
end
it "creates report issue" do
expect { run }.to output.to_stdout expect { run }.to output.to_stdout
expect(RestClient::Request).to have_received(:execute).with( expect(RestClient::Request).to have_received(:execute).with(
method: :post, method: :post,
url: "gitlab_api_url/projects/278964/issues", url: issue_endpoint,
verify_ssl: false,
headers: { "PRIVATE-TOKEN" => "gitlab_token" },
payload: { payload: {
title: "Reliable e2e test report", title: "Reliable e2e test report",
description: issue_body, description: issue_body,
labels: "Quality,test,type::maintenance,reliable test report,automation:ml" labels: "reliable test report,Quality,test,type::maintenance,automation:ml"
} },
**common_api_args
)
expect(RestClient::Request).to have_received(:execute).with(
method: :get,
url: "#{issue_endpoint}?labels=reliable test report&state=opened",
**common_api_args
)
expect(RestClient::Request).to have_received(:execute).with(
method: :put,
url: "#{issue_endpoint}/#{old_iid}",
payload: {
state_event: "close"
},
**common_api_args
)
expect(RestClient::Request).to have_received(:execute).with(
method: :post,
url: "#{issue_endpoint}/#{old_iid}/notes",
payload: {
body: "Closed issue in favor of ##{iid}"
},
**common_api_args
) )
expect(slack_notifier).to have_received(:post).with( expect(slack_notifier).to have_received(:post).with(
icon_emoji: ":tanuki-protect:", icon_emoji: ":tanuki-protect:",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment