lib/dri/commands/fetch/failures.rb in dri-0.10.2 vs lib/dri/commands/fetch/failures.rb in dri-0.11.0
- old
+ new
@@ -1,40 +1,41 @@
# frozen_string_literal: true
+require "influxdb-client"
+
require_relative '../../command'
require_relative '../../utils/table'
require_relative '../../utils/constants'
+require_relative '../../support/influxdb_tools'
module Dri
module Commands
class Fetch
- class Failures < Dri::Command
+ class Failures < Dri::Command # rubocop:disable Metrics/ClassLength
include Dri::Utils::Table
include Dri::Utils::Constants::Triage::Labels
+ include Dri::Support::InfluxdbTools
using Refinements
def initialize(options)
@options = options
- @start_date = @options[:start_date] ? Date.parse(@options[:start_date]) : Date.today
+ @start_date = @options[:start_date] ? Date.parse(@options[:start_date]) : Date.today - 1
@end_date = @options[:end_date] ? Date.parse(@options[:end_date]) : Date.today
@cutoff_time = @options[:cutoff] ? Time.parse(options[:cutoff]).utc : nil
end
- def execute(input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
+ def execute(_input: $stdin, output: $stdout) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
verify_config_exists
- urgent_environments = %w[canary canary.staging]
-
title = add_color('Title', :bright_yellow)
triaged = add_color('Triaged?', :bright_yellow)
environment = add_color('Environment', :bright_yellow)
- author = add_color('Author', :bright_yellow)
url = add_color('URL', :bright_yellow)
updated_at = add_color('Updated at', :bright_yellow)
sorted_failures = []
- labels = { title: title, triaged: triaged, environment: environment, author: author, url: url,
+ labels = { title: title, triaged: triaged, environment: environment, url: url,
updated_at: updated_at }
triaged_counter = 0
if @cutoff_time
@start_date = Time.new(
@@ -55,60 +56,118 @@
if failures.empty?
logger.info "Life is great, there are no new failures between #{@start_date} and #{@end_date}!"
exit 0
end
+ blocker_set = Set.new
+
+ blocker_set = Set.new
+
+ if query_api
+ begin
+ blockers = query_api.query(query: query_reliables_smokes)
+
+ blockers.each do |table|
+ table.records.each do |record|
+ blocker_set.add(record.values['name'])
+ end
+ end
+ rescue StandardError => e
+ logger.error "An error occurred querying for reliable and smoke failures: #{e.message}"
+ end
+ end
+
failures.each do |failure|
project_id = failure.project_id
title = failure.title.truncate(60)
- author = failure.to_h.dig('author', 'username').truncate(25)
+
+ title = bold("*#{failure.title.truncate(60)}*") if blocker?(failure.title, blocker_set)
+
url = failure.web_url
updated_at = failure.updated_at
triaged = add_color('x', :red)
envs = failure.labels.select { |l| l.include?(FOUND) }.map do |l|
env = l.split(':').last.gsub('.gitlab.com', '')
env == 'gitlab.com' ? 'production' : env
end
- urgent = urgent_environments.all? { |env| envs.include?(env) }
- next if @options[:urgent] && !urgent
-
emoji_awards = api_client.fetch_awarded_emojis(failure.iid, project_id: project_id).find do |e|
e.name == emoji && e.to_h.dig('user', 'username') == username
end
if emoji_awards
triaged = add_color('✓', :green)
triaged_counter += 1
end
- sorted_failures << { title: title, triaged: triaged, environment: envs.first || 'none', author: author,
+ sorted_failures << { title: title, triaged: triaged, environment: envs.first || 'none',
url: url, updated_at: updated_at }
end
sorted_failures.sort_by! { |failure| failure[@options[:sort_by]&.to_sym || :environment] }
end
- msg = if @options[:urgent]
- <<~MSG
- Found: #{sorted_failures.size} urgent failures, occurring in both canary.gitlab.com and canary.staging.gitlab.com.
- MSG
- else
- <<~MSG
- Found: #{sorted_failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}.
- MSG
- end
+ msg = <<~MSG
+ Found: #{sorted_failures.size} failures, of these #{triaged_counter} have been triaged with a #{emoji}.
+ Smoke and Reliable failures are marked with *Failure..* in bold.
+ MSG
terminal_width = TTY::Screen.width
- if terminal_width <= 210 # adjust the desired minimum width
+ if terminal_width <= 210
labels.delete(:updated_at)
sorted_failures.map { |failure| failure.delete(:updated_at) }
end
- print_table(labels.values, sorted_failures.map(&:values), alignments: [:left, :center, :center, :left, :left])
+ print_table(
+ labels.values,
+ sorted_failures.map(&:values),
+ alignments: [:left, :center, :center, :left]
+ )
output.puts(msg)
+ end
+
+ private
+
+ def blocker?(title, set)
+ title_part = title.split('|').last
+ return true if title_part&.strip && set.include?(title_part.strip)
+
+ false
+ end
+
+ def query_reliables_smokes
+ <<~QUERY
+ from(bucket: "#{Support::InfluxdbTools::INFLUX_MAIN_TEST_METRICS_BUCKET}")
+ |> range(start: -1d)
+ |> filter(fn: (r) => r._measurement == "test-stats")
+ |> filter(fn: (r) => r.run_type == "staging-full" or
+ r.run_type == "staging-sanity" or
+ r.run_type == "production-full" or
+ r.run_type == "production-sanity" or
+ r.run_type == "package-and-qa" or
+ r.run_type == "nightly" or
+ r.run_type == "e2e-test-on-gdk"
+ )
+ |> filter(fn: (r) => r.job_name != "airgapped" and
+ r.job_name != "instance-image-slow-network" and
+ r.job_name != "nplus1-instance-image"
+ )
+ |> filter(fn: (r) => r.status != "pending" and
+ r.merge_request == "false" and
+ r.quarantined == "false" and
+ r.smoke == "true" or
+ r.reliable == "true"
+ )
+ |> filter(fn: (r) => r["_field"] == "job_url" or
+ r["_field"] == "failure_exception" or
+ r["_field"] == "id"
+ )
+ |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
+ |> group(columns: ["name"])
+ |> distinct(column: "name")
+ QUERY
end
end
end
end
end