<commit_before>require 'cocaine'
require 'git_repo'

class GitBlame
  PEOPLE_JSON_URL = 'https://people.squareup.com/people.json'

  class << self
    def emails_since_last_green(build)
      lookup_git_names_and_emails(git_names_and_emails_since_last_green(build).split("\n"))
    end

    def emails_in_branch(build)
      lookup_git_names_and_emails(git_names_and_emails_in_branch(build).split("\n"))
    end

    def changes_since_last_green(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H|%an <%ae>|%ad|%B::!::' #{build.previous_successful_build.try(:ref)}...#{build.ref}").run
      end
      parse_git_changes(output)
    end

    def changes_in_branch(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H|%an <%ae>|%ad|%B::!::' origin/master..origin/#{build.branch}").run
      end
      parse_git_changes(output)
    end

    def files_changed_since_last_green(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H::!::' --name-only #{build.previous_successful_build.try(:ref)}...#{build.ref}").run
      end
      parse_git_files_changes(output)
    end

    def files_changed_in_branch(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H::!::' --name-only origin/master..origin/#{build.branch}").run
      end
      parse_git_files_changes(output)
    end

    private

    def email_from_git_email(email)
      if people_lookup[:by_email][email].present?
        email
      else
        usernames = email.split('@').first.split('+')
        usernames.map do |username|
          username.strip!
          people_lookup[:by_username][username].try(:[], :email)
        end
      end
    end

    def email_from_git_name(name)
      if people_lookup[:by_name][name].present?
        people_lookup[:by_name][name][:email]
      else
        names = (name.split(/ and /i) | name.split('+') | name.split(',') | name.split('&')) - [name]
        names.map do |_name|
          _name.strip!
          people_lookup[:by_name][_name].try(:[], :email)
        end
      end
    end

    def people_lookup
      return @people_lookup if @people_lookup

      @people_lookup = {:by_email => {}, :by_name => {}, :by_username => {}}
      people_from_ldap.each { |person|
        @people_lookup[:by_email][person['Email']] = {:name => "#{person['First']} #{person['Last']}"}
        @people_lookup[:by_name]["#{person['First']} #{person['Last']}"] = {:email => "#{person['Email']}"}
        @people_lookup[:by_username]["#{person['Username']}"] = {:email => "#{person['Email']}"}
      }
      @people_lookup
    end

    def people_from_ldap
      @people_from_ldap ||= JSON.parse(HTTParty.get(PEOPLE_JSON_URL).body)
    end

    def git_names_and_emails_since_last_green(build)
      GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --format=%an:%ae --no-merges #{build.previous_successful_build.try(:ref)}...#{build.ref}").run
      end
    end

    def git_names_and_emails_in_branch(build)
      GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --format=%an:%ae --no-merges origin/master..origin/#{build.branch}").run
      end
    end

    def lookup_git_names_and_emails(git_names_and_emails)
      git_names_and_emails.map do |git_name_and_email|
        name, email = git_name_and_email.split(":")
        Array(email_from_git_email(email)) | Array(email_from_git_name(name))
      end.flatten.compact.uniq<commit_msg>protect against > characters in branch names.  e.g. michaelzh/SignalService-Postgres->MySQL<commit_after>require 'cocaine'
require 'git_repo'

class GitBlame
  PEOPLE_JSON_URL = 'https://people.squareup.com/people.json'

  class << self
    def emails_since_last_green(build)
      lookup_git_names_and_emails(git_names_and_emails_since_last_green(build).split("\n"))
    end

    def emails_in_branch(build)
      lookup_git_names_and_emails(git_names_and_emails_in_branch(build).split("\n"))
    end

    def changes_since_last_green(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H|%an <%ae>|%ad|%B::!::' '#{build.previous_successful_build.try(:ref)}...#{build.ref}'").run
      end
      parse_git_changes(output)
    end

    def changes_in_branch(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H|%an <%ae>|%ad|%B::!::' 'origin/master..origin/#{build.branch}'").run
      end
      parse_git_changes(output)
    end

    def files_changed_since_last_green(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H::!::' --name-only '#{build.previous_successful_build.try(:ref)}...#{build.ref}'").run
      end
      parse_git_files_changes(output)
    end

    def files_changed_in_branch(build)
      output = GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --no-merges --format='::!::%H::!::' --name-only 'origin/master..origin/#{build.branch}'").run
      end
      parse_git_files_changes(output)
    end

    private

    def email_from_git_email(email)
      if people_lookup[:by_email][email].present?
        email
      else
        usernames = email.split('@').first.split('+')
        usernames.map do |username|
          username.strip!
          people_lookup[:by_username][username].try(:[], :email)
        end
      end
    end

    def email_from_git_name(name)
      if people_lookup[:by_name][name].present?
        people_lookup[:by_name][name][:email]
      else
        names = (name.split(/ and /i) | name.split('+') | name.split(',') | name.split('&')) - [name]
        names.map do |_name|
          _name.strip!
          people_lookup[:by_name][_name].try(:[], :email)
        end
      end
    end

    def people_lookup
      return @people_lookup if @people_lookup

      @people_lookup = {:by_email => {}, :by_name => {}, :by_username => {}}
      people_from_ldap.each { |person|
        @people_lookup[:by_email][person['Email']] = {:name => "#{person['First']} #{person['Last']}"}
        @people_lookup[:by_name]["#{person['First']} #{person['Last']}"] = {:email => "#{person['Email']}"}
        @people_lookup[:by_username]["#{person['Username']}"] = {:email => "#{person['Email']}"}
      }
      @people_lookup
    end

    def people_from_ldap
      @people_from_ldap ||= JSON.parse(HTTParty.get(PEOPLE_JSON_URL).body)
    end

    def git_names_and_emails_since_last_green(build)
      GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --format='%an:%ae' --no-merges '#{build.previous_successful_build.try(:ref)}...#{build.ref}'").run
      end
    end

    def git_names_and_emails_in_branch(build)
      GitRepo.inside_repo(build.repository) do
        Cocaine::CommandLine.new("git log --format='%an:%ae' --no-merges 'origin/master..origin/#{build.branch}'").run
      end
    end

    def lookup_git_names_and_emails(git_names_and_emails)
      git_names_and_emails.map do |git_name_and_email|
        name, email = git_name_and_email.split(":")
        Array(email_from_git_email(email)) | Array(email_from_git_name(name))
      end.flatten.compact.uniq
{'fraction_non_alphanumeric': 0.16163222045574988, 'fraction_numerical': 0.0, 'mean_word_length': 3.424970691676436, 'pattern_counts': {'":': 2, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3660543', 'n_tokens_mistral': 2608, 'n_tokens_neox': 2584, 'n_words': 362}