Class: ChurnVsComplexity::GitStrategy

Inherits:
Object
  • Object
show all
Defined in:
lib/churn_vs_complexity/git_strategy.rb

Constant Summary collapse

EMPTY_TREE_SHA =
'4b825dc642cb6eb9a060e54bf8d69288fbee4904'

Instance Method Summary collapse

Constructor Details

#initialize(folder:) ⇒ GitStrategy

Returns a new instance of GitStrategy.



7
8
9
10
# File 'lib/churn_vs_complexity/git_strategy.rb', line 7

def initialize(folder:)
  @repo = Git.open(folder)
  @folder = folder
end

Instance Method Details

#add_worktree(wt_folder) ⇒ Object



67
68
69
70
# File 'lib/churn_vs_complexity/git_strategy.rb', line 67

def add_worktree(wt_folder)
  command = "(cd #{@folder} && git worktree add -f #{wt_folder}) > /dev/null 2>&1"
  `#{command}`
end

#changes(commit:) ⇒ Object



30
31
32
33
34
35
# File 'lib/churn_vs_complexity/git_strategy.rb', line 30

def changes(commit:)
  commit_object = @repo.object(commit)
  diff_from_parent(commit_object).map do |change|
    { path: change.path, type: change.type.to_sym }
  end
end

#checkout_in_worktree(worktree_folder, sha) ⇒ Object



37
38
39
40
# File 'lib/churn_vs_complexity/git_strategy.rb', line 37

def checkout_in_worktree(worktree_folder, sha)
  command = "(cd #{worktree_folder} && git checkout #{sha}) > /dev/null 2>&1"
  `#{command}`
end

#commits_in(git_period) ⇒ Object

Both ends are given an explicit time. A bare date is an approximate date to git, resolved against the clock and the timezone, so the window it produces is not the window that was asked for.



45
46
47
48
49
50
# File 'lib/churn_vs_complexity/git_strategy.rb', line 45

def commits_in(git_period)
  @repo.log(1_000_000)
       .since(start_of_day(git_period.effective_start_date))
       .until(end_of_day(git_period.end_date))
       .execute.to_a
end

#end_of_day(date) ⇒ Object



54
# File 'lib/churn_vs_complexity/git_strategy.rb', line 54

def end_of_day(date) = date.strftime('%Y-%m-%dT23:59:59')

#object(commit) ⇒ Object



19
20
21
# File 'lib/churn_vs_complexity/git_strategy.rb', line 19

def object(commit)
  commit.is_a?(Git::Object::Commit) ? commit : @repo.object(commit)
end

#remove_worktree(worktree_folder) ⇒ Object



72
73
74
75
# File 'lib/churn_vs_complexity/git_strategy.rb', line 72

def remove_worktree(worktree_folder)
  command = "(cd #{worktree_folder} && git worktree remove -f #{worktree_folder}) > /dev/null 2>&1"
  `#{command}`
end

#resolve_commits_with_interval(git_period:, jump_days:) ⇒ Object



56
57
58
59
60
61
62
63
64
65
# File 'lib/churn_vs_complexity/git_strategy.rb', line 56

def resolve_commits_with_interval(git_period:, jump_days:)
  candidates = commits_in(git_period)

  commits_by_date = candidates.filter { |c| c.date.to_date >= git_period.effective_start_date }
                              .group_by { |c| c.date.to_date }

  found_dates = GitDate.select_dates_with_at_least_interval(commits_by_date.keys, jump_days)

  found_dates.map { |date| commits_by_date[date].max_by(&:date) }
end

#start_of_day(date) ⇒ Object



52
# File 'lib/churn_vs_complexity/git_strategy.rb', line 52

def start_of_day(date) = date.strftime('%Y-%m-%dT00:00:00')

#surrounding(commit:) ⇒ Object



23
24
25
26
27
28
# File 'lib/churn_vs_complexity/git_strategy.rb', line 23

def surrounding(commit:)
  current = object(commit)
  child_sha = `git -C #{@folder} log --reverse --ancestry-path #{current.sha}..HEAD --format=%H`.lines.first&.chomp
  next_commit = child_sha.nil? || child_sha.empty? ? nil : child_sha
  [current.parent&.sha, next_commit]
end

#valid_commit?(commit:) ⇒ Boolean

Returns:

  • (Boolean)


12
13
14
15
16
17
# File 'lib/churn_vs_complexity/git_strategy.rb', line 12

def valid_commit?(commit:)
  @repo.object(commit)
  true
rescue Git::GitExecuteError
  false
end