#!/usr/bin/env ruby # frozen_string_literal: true require 'date' require 'optparse' require 'pry' require_relative '../lib/git_ownership_insights/version' require_relative '../lib/git_ownership_insights/git_ownership_insight' options = {} OptionParser.new do |opts| opts.banner = 'Usage: git_ownership_insights [options]' opts.on('--debug', 'Enable debug mode') do options[:debug] = true end opts.on('--ci', 'Do not print the info messages for better CI text parsing [default: false]') do options[:ci] = true end opts.on('--codeowners', 'Print CODEOWNERS info [default: false]') do options[:codeowners] = true end opts.on('--hotspot-files', 'Print the found hotspot files (big files touched by many) [default: false]') do options[:hotspot_files] = true end opts.on('--excluded-contributors STRING', 'Comma-delimited list of excluded contributors [example: WEB,RAILS,MOBILE]') do |exclusions| options[:exclusions] = exclusions end opts.on('--excluded-files STRING', 'Comma-delimited list of excluded files [example: ViewController,AppDelegate.swift]') do |excluded_files| options[:excluded_files] = excluded_files end opts.on('--steps STRING', 'Number of steps the script will go into the past [default: 1]') do |steps| options[:steps] = steps end opts.on('--duration-in-days STRING', 'Number of days to aggregate the changes for [default: 30]') do |duration_in_days| options[:duration_in_days] = duration_in_days end opts.on('--path STRING', 'Path to the directory or file to calculate the ownership [default: "."]') do |path| options[:path] = path end opts.on('--team-regex STRING', 'Regex that will identify the team name [default: "[A-Za-z]+"]') do |team_regex| options[:team_regex] = team_regex end opts.on('--top-contributing-team STRING', 'Limit of top contributed to the directory teams in codeownership data [default: 5]') do |top_contributing_team| options[:top_contributing_team] = top_contributing_team end opts.on('--top-touched-files STRING', 'Limit of top touched files by individual contributors in codeownership data [default: 5]') do |top_touched_files| options[:top_touched_files] = top_touched_files end opts.on('--codeowners-path STRING', 'Path to CODEOWNERS file [default: .github/CODEOWNERS]') do |codeowners_path| options[:codeowners_path] = codeowners_path end opts.on('--big-file-size STRING', 'The amount of lines in the file to be considered big [default: 250]') do |big_file_size| options[:big_file_size] = big_file_size end opts.on('--default-branch STRING', 'The default branch to pull and run metrics for [default: master]') do |default_branch| options[:default_branch] = default_branch end opts.on('--code-extensions STRING', 'The file extensions that consider to be code [default: ".kt,.swift"]') do |code_extension| options[:code_extension] = code_extension end opts.on('-v', '--version', 'Display the version of the gem') do puts "git_ownership_insights version #{GitOwnershipInsights::VERSION}" exit end opts.on('-h', '--help', 'Display this help message') do puts opts puts <<~EXAMPLES Examples: git_ownership_insights --path src/test --exclusions WEB,RAILS --steps 2 --duration-in-days 90 --hotspot-files --debug EXAMPLES exit end end.parse! EXCLUSIONS = options[:exclusions]&.split(',') REPO_PATH = options[:path] || '.' TEAM_REGEX = options[:team_regex] || '[A-Za-z]+' TOP_TOUCHED_FILES = options[:top_touched_files] || 5 TOP_CONTRIBUTED_TEAMS = options[:top_contributing_team] || 5 CODEOWNERS_PATH = options[:codeowners_path] || '.github/CODEOWNERS' BIG_FILE_SIZE = options[:big_file_size] || 250 CI = options[:ci] || false DEFAULT_BRANCH = options[:default_branch] || 'master' CODEOWNERS = options[:codeowners] || false HOTSPOT = options[:hotspot_files] || false CODE_EXTENSIONS = options[:code_extension] ? options[:code_extension].split(',') : ['.swift', '.kt'] EXCLUDED_FILES = options[:excluded_files] unless CI puts "\nDirectory: #{REPO_PATH}\n" puts "Time period that data is aggregated by: #{options[:duration_in_days]} days" puts "Steps to jump in the past: #{options[:steps].to_i}" puts "Runs against: #{DEFAULT_BRANCH}" puts "Code extensions: #{CODE_EXTENSIONS}" puts "Regex to detect the teams identifiers: #{TEAM_REGEX}" puts "Excluded contributors: #{EXCLUSIONS}\n" if EXCLUSIONS puts "Excluded file patterns: #{EXCLUDED_FILES.split(',')}\n" if EXCLUDED_FILES puts "Lines of code limit (big files) for the hotspot calculation: #{BIG_FILE_SIZE}" puts "Hotspot detailed output is: #{options[:hotspot_files] ? 'on' : 'off'}\n" puts "CODEOWNERS output is: #{options[:codeowners] ? 'on' : 'off'}\n" puts "Limit of the teams shown in codeownership data: #{TOP_CONTRIBUTED_TEAMS}" puts "Limit of the files shown in codeownership data: #{TOP_TOUCHED_FILES}" puts "CI mode is: #{options[:ci] ? 'on' : 'off'}\n" puts "Debug mode is: #{options[:debug] ? 'on' : 'off'}\n\n" end system("git checkout #{DEFAULT_BRANCH}", [:out] => File::NULL) system('git pull', %i[out err] => File::NULL) GitOwnershipInsights.contribution_message(duration_in_days: options[:duration_in_days] || 30, directory_path: REPO_PATH, begin_time: DateTime.now, steps: options[:steps].to_i, debug: options[:debug])