gitwakatime 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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