#!/usr/bin/env ruby # frozen_string_literal: true require "bundler/setup" require "optparse" require_relative "../lib/gitlab_quality/test_tooling" params = {} summary_table_opts = {} messages = [] gitlab_api_token = nil options = OptionParser.new do |opts| opts.banner = "Usage: #{$PROGRAM_NAME} [options]" opts.on('-w', '--slack-webhook-url SLACK_WEBHOOK_URL', String, 'Slack webhook URL') do |slack_webhook_url| params[:slack_webhook_url] = slack_webhook_url end opts.on('-a', '--gitlab-api-token TOKEN', String, 'GitLab API token') do |token| gitlab_api_token = token unless token.empty? end opts.on('-c', '--channel CHANNEL', String, 'Slack channel to post the message to') do |channel| params[:channel] = channel end opts.on('-m', '--message MESSAGE', String, 'Post message to Slack') do |message| messages << message end opts.on('-s', '--sort-by SORT', String, 'Used with the `--include-summary-table` flag — An optional sort for the test summary table. This flag must be positioned before `--include-summary-table`') do |sort_by| valid_options = ["Dev Stage", "Total", "Failures", "Errors", "Skipped", "Result"].freeze raise ArgumentError, "Invalid sort option: #{sort_by}. Valid options are: #{valid_options.join(', ')}" unless valid_options.include?(sort_by) summary_table_opts[:sort_by] = sort_by end opts.on('-d', '--sort-direction [asc|desc]', String, 'Used with the `--sort-by` flag — Define the sort direction of the test summary table (default: `asc`)') do |sort_direction| raise ArgumentError, "Invalid sort direction: #{sort_direction}. Valid options are: asc, desc" unless %w[asc desc].include?(sort_direction.downcase) summary_table_opts[:sort_direction] = sort_direction.downcase.to_sym end opts.on('-t', '--include-summary-table FILES', String, 'Add a test summary table based on RSpec report files (JUnit XML)') do |files| params[:summary_table_files] = files end opts.on('-j', '--include-failed-jobs-table', 'Add a list of failed jobs in the pipeline') do next puts("Failed jobs table requires api token to be set via --gitlab-api-token option, skipping failed jobs table") unless gitlab_api_token project_id = ENV['CI_PROJECT_ID']&.to_i || (next puts("CI_PROJECT_ID not set, skipping failed jobs table")) pipeline_id = ENV['CI_PIPELINE_ID']&.to_i || (next puts("CI_PIPELINE_ID not set, skipping failed jobs table")) jobs = GitlabQuality::TestTooling::GitlabClient::JobsClient.new(token: gitlab_api_token, project: project_id).pipeline_jobs(pipeline_id: pipeline_id, scope: 'failed') next if jobs.empty? messages << GitlabQuality::TestTooling::FailedJobsTable.create(jobs: jobs) rescue StandardError => e puts "Failed to fetch failed jobs. #{e.class}: #{e.message}" end opts.on('-u', '--username USERNAME', String, 'Username to use for the Slack message') do |username| params[:username] = username end opts.on('-i', '--icon-emoji ICON_EMOJI', String, 'Icon emoji to use for the Slack message') do |icon_emoji| params[:icon_emoji] = icon_emoji end opts.on_tail('-v', '--version', 'Show the version') do require_relative "../lib/gitlab_quality/test_tooling/version" puts "#{$PROGRAM_NAME} : #{GitlabQuality::TestTooling::VERSION}" exit end opts.on_tail('-h', '--help', 'Show the usage') do puts "Purpose: Post a message to Slack, and optionally add a test summary table based on RSpec report files (JUnit XML)" puts opts exit end opts.parse(ARGV) end if params.any? messages << GitlabQuality::TestTooling::SummaryTable.create(input_files: params.delete(:summary_table_files), **summary_table_opts) if params.key?(:summary_table_files) params[:message] = messages.join("\n") GitlabQuality::TestTooling::Slack::PostToSlack.new(**params).invoke! else puts options exit 1 end