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