gitwakatime 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86e6080229ad2143f0874a4912e4ceb6df885306
4
- data.tar.gz: 6f6aa24acd61e4f0b87217d674f8dc60a5652113
3
+ metadata.gz: 22675c8683f7ed9526d4715687b666c6b588387c
4
+ data.tar.gz: a72221a76657b3daea13882df4b5f18eb30021a2
5
5
  SHA512:
6
- metadata.gz: d50a015052568968ff6dba0efba08e131f9d5e781555e16c136b20bc6775a21deb6115c7be66b7b0bd157c38cc9bfc19ce8e30cf009ae5565b8d28e90c2f059d
7
- data.tar.gz: cef4abacec5ab099db09005c92a237d853cd5951261e65a9d8ae102d8be6dde1f7ef806327a091058d7698d7773eba19fa9a5e82f8fa249d9581bc0bd4daded6
6
+ metadata.gz: d53f9a01279650d49f4da02104108b0a0dd94ceffc5aa552dbc1a8ae5c70f55e64cb302b1b790e423e38e5bcf7807ceeb13d6fcff61ffc4efcfd380f7ad59c61
7
+ data.tar.gz: 814d9fcbb9f90a1b7138295bb3ea74e203c6367245e04067c598e91f356c58f7a9385bf148a262a7a67949f86060b4befeacd8741caec39225d36b8dc87d0492
data/README.md CHANGED
@@ -1,24 +1,22 @@
1
1
  # GitWakaTime
2
2
 
3
- TODO: Write a gem description
3
+ GitWakaTime is a mashup between data obtained through "wakatime" and the data we all create using git.
4
+ The prinicpal is to capture a baseline of activity for a task and answer the age old question "How much time did I spend on this?"
4
5
 
5
6
  ## Installation
6
7
 
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'gitwakatime'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
8
+ Install the gem:
16
9
 
17
10
  $ gem install gitwakatime
18
11
 
19
12
  ## Usage
20
13
 
21
- TODO: Write usage instructions here
14
+ Creates a .gitwakatime.yml file on the user's home directory ~/.gitwakatime.yml which will contain your api keys
15
+ $ gitwakatime init
16
+
17
+ Process the current directory
18
+
19
+ $ gitwakatime tally
22
20
 
23
21
  ## Contributing
24
22
 
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
File without changes
data/gitwakatime.gemspec CHANGED
@@ -4,27 +4,29 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'gitwakatime/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "gitwakatime"
7
+ spec.name = 'gitwakatime'
8
8
  spec.version = GitWakaTime::VERSION
9
- spec.authors = ["Russell Osborne"]
10
- spec.email = ["russosborn@gmail.com"]
11
- spec.summary = %q{A Tool that will compile git data with wakatime data to establish time per commit}
12
- spec.description = %q{A Tool that will compile git data with wakatime data to establish time per commit }
13
- spec.homepage = ""
14
- spec.license = "MIT"
9
+ spec.authors = ['Russell Osborne']
10
+ spec.email = ['russosborn@gmail.com']
11
+ spec.summary = 'A Tool that will compile git data with wakatime data to establish time per commit'
12
+ spec.description = 'A Tool that will compile git data with wakatime data to establish time per commit '
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_runtime_dependency "git", ">= 0"
22
- spec.add_runtime_dependency "wakatime", ">= 0"
23
- spec.add_runtime_dependency "logger", ">= 0"
24
- spec.add_runtime_dependency "thor", ">= 0"
25
- spec.add_runtime_dependency "chronic_duration", ">=0"
26
- spec.add_runtime_dependency "colorize"
27
- spec.add_development_dependency("bundler", [">= 0"])
28
- spec.add_development_dependency "rake"
29
- spec.add_development_dependency "rspec"
21
+ spec.add_runtime_dependency 'git', '>= 0'
22
+ spec.add_runtime_dependency 'wakatime', '>= 0.0.2'
23
+ spec.add_runtime_dependency 'logger', '>= 0'
24
+ spec.add_runtime_dependency 'thor', '>= 0'
25
+ spec.add_runtime_dependency 'chronic_duration', '>=0'
26
+ spec.add_runtime_dependency 'colorize'
27
+ spec.add_runtime_dependency 'activesupport'
28
+ spec.add_development_dependency('bundler', ['>= 0'])
29
+ spec.add_development_dependency 'rake'
30
+ spec.add_development_dependency 'rspec'
31
+ spec.add_development_dependency('webmock', ['>= 0'])
30
32
  end
@@ -1,7 +1,9 @@
1
1
  module GitWakaTime
2
2
  # Extract Duration Data from Actions for the WAKATIME API
3
3
  class Actions
4
+ attr_accessor :actions
4
5
  def initialize(args)
6
+ return @actions = args[:actions] if args[:actions]
5
7
  fail if args[:project].nil?
6
8
  @project = args[:project]
7
9
  @args = args
@@ -15,12 +17,16 @@ module GitWakaTime
15
17
  time = Benchmark.realtime do
16
18
  @actions = @client.actions(@args)
17
19
  # remove returned actions that do not have the project we want
18
- @actions.keep_if { |a| a['project'] == @project }
20
+ @actions = @actions.keep_if do |a|
21
+ a['project'] == @project
22
+ end
23
+
19
24
  end
20
25
  Log.new "API took #{time}s"
26
+ @actions
21
27
  end
22
28
 
23
- def actions_to_durations(project = nil, timeout = 15)
29
+ def actions_to_durations(_project = nil, timeout = 15)
24
30
  durations = []
25
31
  current = []
26
32
  @actions.each do | action |
@@ -4,6 +4,11 @@ require 'wakatime'
4
4
  require 'chronic_duration'
5
5
  require 'yaml'
6
6
  require 'thor'
7
+ require 'active_support/core_ext/date/calculations'
8
+ require 'active_support/core_ext/date_and_time/calculations'
9
+ require 'active_support/core_ext/integer/time'
10
+ require 'active_support/core_ext/time'
11
+
7
12
  module GitWakaTime
8
13
  # Provides two CLI actions init and tally
9
14
  class Cli < Thor
@@ -22,16 +27,27 @@ module GitWakaTime
22
27
 
23
28
  desc 'tally', 'Produce time spend for each commit and file in each commit'
24
29
  method_option :file, aliases: '-f', default: '.'
30
+ method_option :start_on, aliases: '-s', default: nil
25
31
  def tally
26
- path , GitWakaTime.config.root = File.expand_path(options.file)
32
+ path, GitWakaTime.config.root = File.expand_path(options.file)
33
+ date = Date.parse(options.start_on) if options.start_on
34
+ date = 1.month.ago.beginning_of_month unless options.start_on
27
35
  GitWakaTime.config.load_config_yaml
28
- @mapper = Mapper.new(path)
36
+ @git_map = Mapper.new(path, start_at: date)
37
+ @actions = Query.new(@git_map.commits, File.basename(path)).get
38
+
39
+ @timer = Timer.new(@git_map.commits, @actions, File.basename(path)).process
29
40
 
30
- @timer = Timer.new(@mapper.commits, File.basename(path))
31
- @commits_with_duration = @timer.process
32
- @commits_with_duration.each do |commit|
33
- Log.new commit.to_s
34
- commit.files.each { |file| Log.new file.to_s }
41
+ @timer.each do |date, commits|
42
+ Log.new format('%-40s %-40s'.blue,
43
+ date,
44
+ "Total #{ChronicDuration.output commits.map(&:time_in_seconds).reduce(&:+)}"
45
+ )
46
+ commits.each do |commit|
47
+ # Log.new commit.message
48
+ Log.new commit.to_s
49
+ commit.files.each { |file| Log.new file.to_s }
50
+ end
35
51
  end
36
52
  end
37
53
  end
@@ -1,20 +1,25 @@
1
1
  module GitWakaTime
2
2
  class Commit
3
- attr_accessor :sha, :date, :message, :files, :time_in_seconds
3
+ attr_accessor :raw_commit, :sha, :date, :message, :files, :time_in_seconds, :git, :author
4
4
 
5
5
  def initialize(git, commit, load_files = true)
6
6
  @raw_commit = commit
7
7
  @sha = @raw_commit.sha
8
8
  @date = @raw_commit.date
9
9
  @message = @raw_commit.message
10
+ @author = @raw_commit.author
10
11
  @time_in_seconds = 0
11
12
  @git = git
12
13
  @load_files = load_files
13
- @files = load if load_files
14
+ @files = get_files if load_files
15
+ end
16
+
17
+ def inspect
18
+ [sha[0..8], time_in_seconds]
14
19
  end
15
20
 
16
21
  def to_s
17
- format('%-8s %8s %-30s %-80s'.green,
22
+ format(' %-8s %8s %-30s %-80s'.green,
18
23
  sha[0..8],
19
24
  date,
20
25
  ChronicDuration.output(time_in_seconds),
@@ -22,12 +27,17 @@ module GitWakaTime
22
27
  )
23
28
  end
24
29
 
30
+ def oldest_dependent
31
+ @files.sort { |f| f.commit.date }.first
32
+ end
33
+
25
34
  private
26
35
 
27
- def load
36
+ def get_files
37
+ # TODO: Assume gap time to lookup time prior to first commit.
28
38
  return [] unless @raw_commit.parent
29
39
  @raw_commit.diff_parent.stats[:files].keys.map do |file|
30
- CommitedFile.new(git: @git , parent_commit: @raw_commit, name: file, dependent: false)
40
+ CommitedFile.new(git: @git, commit: @raw_commit, name: file, dependent: false)
31
41
  end
32
42
  end
33
43
  end
@@ -5,31 +5,47 @@ module GitWakaTime
5
5
  def initialize(args)
6
6
  @git = args[:git]
7
7
  @name = args[:name]
8
- @parent_commit = args[:parent_commit]
8
+ @commit = args[:commit]
9
9
  @time_in_seconds = 0
10
- @find_dependent = args[:dependent] || true
11
10
 
12
- write_dependent_commit(name) if @find_dependent
11
+ @dependent_commit = find_dependent_commit(name)
13
12
  end
14
13
 
15
14
  def to_s
16
- format(' %-40s %-40s %-20s'.blue ,
17
- ChronicDuration.output(time_in_seconds.to_f),
18
- name,
19
- (dependent_commit.sha[0..8] if @dependent_commit)
15
+ format(' %-20s %-40s %-100s '.blue,
16
+ (dependent_commit.sha[0..8] if @dependent_commit),
17
+ ChronicDuration.output(@time_in_seconds.to_f),
18
+ name
19
+
20
20
  )
21
21
  end
22
22
 
23
23
  private
24
24
 
25
- def write_dependent_commit(name)
26
- commit = load_dependent_commit(name)
27
- @dependent_commit = Commit.new(@git, commit , false) if commit
25
+ def find_dependent_commit(name)
26
+ i = 1
27
+ dependent = nil
28
+ commit = 1
29
+
30
+ begin
31
+ commit = load_dependent_commit(name, i: i)
32
+ dependent = Commit.new(@git, commit, false) if allowed_commit(commit)
33
+ i += 1
34
+ end until !dependent.nil? || commit.nil?
35
+ dependent
36
+ end
37
+
38
+ def allowed_commit(commit)
39
+ return false if commit.nil?
40
+ return false if commit.author.name != @git.config('user.name')
41
+ return false if commit.message.include?('Merge branch')
42
+ true
28
43
  end
29
44
 
30
- def load_dependent_commit(name)
31
- @git.log(100).until(@parent_commit.date.to_s).object(name)[1]
45
+ def load_dependent_commit(name, i: 1)
46
+ @git.log.object(@commit.sha).path(name)[i]
32
47
  rescue Git::GitExecuteError
48
+ puts error
33
49
  nil
34
50
  end
35
51
  end
@@ -2,19 +2,16 @@ module GitWakaTime
2
2
  # Th
3
3
  class Mapper
4
4
  attr_accessor :commits, :git
5
- def initialize(path, commits = 100)
5
+ def initialize(path, commits: 500, start_at: Date.today)
6
6
  Log.new 'Mapping commits for dependent commits'
7
7
  time = Benchmark.realtime do
8
8
  @git = Git.open(path)
9
- # TODO: Expose since timestamp as a CLI option
10
- # TODO: Expose number of commits as a CLI option
11
- first_of_month = Date.new(Date.today.year, Date.today.month, 1)
12
9
 
13
- logs = @git.log(commits).since(first_of_month)
10
+ logs = @git.log(commits).since(start_at).until(Date.today)
14
11
 
15
12
  @commits = logs.map do |git_commit|
16
13
  Commit.new(@git, git_commit)
17
- end
14
+ end.compact
18
15
  end
19
16
  Log.new "Map Completed took #{time}s"
20
17
  end
@@ -0,0 +1,48 @@
1
+ require 'benchmark'
2
+ require 'colorize'
3
+ require 'active_support/core_ext/time'
4
+
5
+ module GitWakaTime
6
+ # Integrates the nested hash from mapper with actions api
7
+ class Query
8
+ def initialize(commits, project, _path = nil)
9
+ @commits = commits
10
+ @api_limit = 15
11
+ @project = project
12
+ @actions = []
13
+ @requests = time_params
14
+ end
15
+
16
+ def get
17
+ @requests.each do |params|
18
+ Log.new "Requesting actions #{params[:start].to_date} to #{params[:end].to_date}".red
19
+ @actions = @actions.concat Actions.new(params).actions
20
+ end
21
+
22
+ Actions.new(actions: @actions.uniq(&:id)).actions_to_durations
23
+ end
24
+
25
+ def time_params
26
+ commits = @commits.map(&:date)
27
+ d_commits = @commits.map do |c|
28
+ c.files.map(&:dependent_commit).compact.map(&:date)
29
+ end
30
+ timestamps = (commits + d_commits.flatten).uniq
31
+ num_requests = (timestamps.first.to_date - timestamps.last.to_date) / @api_limit
32
+ i = 0
33
+ request_params = num_requests.to_f.ceil.times.map do
34
+
35
+ params = {
36
+ start: (timestamps.last.to_date + (i * @api_limit)).to_time.beginning_of_day,
37
+ end: (timestamps.last.to_date + ((i + 1) * @api_limit)).to_time.end_of_day,
38
+ project: @project
39
+ }
40
+ i += 1
41
+ params
42
+
43
+ end
44
+
45
+ request_params
46
+ end
47
+ end
48
+ end
@@ -1,42 +1,31 @@
1
1
  require 'benchmark'
2
2
  require 'colorize'
3
- require 'pry'
3
+ require 'active_support/core_ext/time'
4
+
4
5
  module GitWakaTime
5
6
  # Integrates the nested hash from mapper with actions api
6
7
  class Timer
7
- def initialize(commits, project, path = nil)
8
- @commits = commits
9
- params = time_params
10
- params[:project] = project
11
- @actions = Actions.new(params)
12
- @actions_with_durations = @actions.actions_to_durations
13
- end
14
-
15
- def time_params
16
- commits = @commits.map(&:date)
17
- d_commits = @commits.map do |c|
18
- c.files.map(&:dependent_commit).compact.map(&:date)
19
- end
20
- timestamps = (commits + d_commits.flatten).uniq
21
- api_limit = Time.now - 60 * 60 * 24 * 60
22
- min = api_limit > timestamps.min ? api_limit : timestamps.min
23
- { start: min, end: timestamps.max }
8
+ def initialize(commits, actions_with_durations, project)
9
+ @commits = commits
10
+ @actions_with_durations = actions_with_durations
11
+ @project = project
24
12
  end
25
13
 
26
14
  def total
27
- @total_time = sum_actions @actions_with_durations
28
- Log.new "Total Recorded time #{ChronicDuration.output @total_time}", :red
15
+ total_time = sum_actions @actions_with_durations
16
+ Log.new "Total Recorded time #{ChronicDuration.output total_time}", :red
29
17
  end
30
18
 
31
19
  def total_commited
32
- @total_commited = ChronicDuration.output(@commits_with_duration
33
- .map { |c| c.time_in_seconds }
20
+ total_commited = ChronicDuration.output(@commits_with_duration
21
+ .map(&:time_in_seconds)
34
22
  .reduce(:+).to_f)
35
- Log.new "Total Commited Time #{@total_commited} ".red
23
+ Log.new "Total Commited Time #{total_commited} ".red
36
24
  end
37
25
 
38
26
  def process
39
27
  @commits_with_duration = @commits.each do |commit|
28
+
40
29
  if !commit.files.empty?
41
30
  commit.files.each_with_index do |file, i|
42
31
  time = sum_actions relevant_actions(commit, file)
@@ -44,12 +33,13 @@ module GitWakaTime
44
33
  commit.time_in_seconds += time
45
34
  end
46
35
  else
47
- commit.time_in_seconds = sum_actions(actions_before(commit.date))
36
+ # commit.time_in_seconds = sum_actions(actions_before(commit.date))
48
37
  end
49
- end
38
+ end.compact
50
39
  total
51
40
  total_commited
52
41
  @commits_with_duration
42
+ @commits_with_duration_by_date = @commits_with_duration.group_by { |c| c.date.to_date }
53
43
  end
54
44
 
55
45
  private
@@ -66,11 +56,8 @@ module GitWakaTime
66
56
  # If this file had an earlier commit ensure the actions timestamp
67
57
  # is after that commit
68
58
  if file.dependent_commit
69
- actions = actions.select do |action|
70
- Time.at(action['time']) >= file.dependent_commit.date
71
- end
59
+ actions = actions_after(actions, file.dependent_commit.date)
72
60
  end
73
-
74
61
  actions
75
62
  end
76
63
 
@@ -80,6 +67,12 @@ module GitWakaTime
80
67
  end
81
68
  end
82
69
 
70
+ def actions_after(actions, date)
71
+ actions.select do |action|
72
+ Time.at(action['time']) >= date
73
+ end
74
+ end
75
+
83
76
  def sum_actions(actions)
84
77
  actions.map { |action| action['duration'] }
85
78
  .reduce(:+).to_f