gitwakatime 0.1.2 → 0.2.0

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: 87b1a52859dcdf8ad54d5be75e5c981961e56fab
4
- data.tar.gz: e8c3f862a72c6e6717eaaa553624e51cce2b9d4c
3
+ metadata.gz: 6d47de3815abb7edcfb65449699ce7ed4ea939de
4
+ data.tar.gz: f540146be05016d14cb0272603257403cb4a31f5
5
5
  SHA512:
6
- metadata.gz: 92157e1509a6f4f05b3ce58b86df8a13c0f4ffd9788204ad82b69b2cdb4850952723cc997ccb9c592702d9144c5872b5a32c02656a498bab6410d03df8b47d54
7
- data.tar.gz: 44b4acdc179a5d4d976e56bd43758d52f09320fa6c12b62d6e6907f81c617051de062f36803c4dab86eb1726f2ed3637e784848cd51d55447693bc02d3b2fb4c
6
+ metadata.gz: 6e9bebde6645f4b5052ef01af5d6bd7a7e6217814caa6c1766ea25aa0875fd7b1a4f6678f1083a82a97ccb2d53babeecbbef5c7b31d7a470e0b0dbbf2913e636
7
+ data.tar.gz: b6065a0f59b9f06ee0b657c48c4b109c699e7afac461ff443324f7e54e095f2cf57129af079dffae46b6eef877dff21165fb02230c5336f5643f01dbe6f113f6
data/README.md CHANGED
@@ -27,7 +27,7 @@ Process the current directory for the past 7 days
27
27
 
28
28
  $ gitwakatime tally
29
29
 
30
- Process the current directory from a given point (this will still load all actions data to prevent providing incorrect timing at the start point)
30
+ Process the current directory from a given point (this will still load all heartbeats data to prevent providing incorrect timing at the start point)
31
31
 
32
32
  $ gitwakatime tally -s 2014-02-01
33
33
 
@@ -62,10 +62,10 @@ There a currently a few limitations with this model
62
62
  4949d899a 4 mins 47 secs spec/query_spec.rb
63
63
  4949d899a 1 min 49 secs spec/spec_helper.rb
64
64
  ea23d7dd7 3 mins 3 secs spec/timer_spec.rb
65
- 30415f0a3 2015-02-04 11:54:18 -0500 1 hr 30 mins 17 secs Cache Actions locally, in sqlite.
65
+ 30415f0a3 2015-02-04 11:54:18 -0500 1 hr 30 mins 17 secs Cache Heartbeats locally, in sqlite.
66
66
  093f9e4d5 4 mins 19 secs lib/gitwakatime.rb
67
- 25 secs lib/gitwakatime/action.rb
68
- caf409884 7 mins 45 secs lib/gitwakatime/actions.rb
67
+ 25 secs lib/gitwakatime/heartbeat.rb
68
+ caf409884 7 mins 45 secs lib/gitwakatime/heartbeats.rb
69
69
  331723757 1 min 39 secs lib/gitwakatime/cli.rb
70
70
  46 mins 2 secs lib/gitwakatime/durations.rb
71
71
  b1cd1d09c 23 mins 50 secs lib/gitwakatime/query.rb
data/Rakefile CHANGED
@@ -1,6 +1,13 @@
1
1
  require 'bundler/gem_tasks'
2
2
  begin
3
- require 'rspec/core/rake_task'
4
- RSpec::Core::RakeTask.new(:spec)
5
- rescue LoadError
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts 'Run `bundle install` to install missing gems'
7
+ exit e.status_code
6
8
  end
9
+ require 'rake'
10
+ require 'rspec/core'
11
+ require 'rspec/core/rake_task'
12
+
13
+ RSpec::Core::RakeTask.new(:spec)
data/gitwakatime.gemspec CHANGED
@@ -3,32 +3,41 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'gitwakatime/version'
5
5
 
6
- Gem::Specification.new do |spec|
7
- spec.name = 'gitwakatime'
8
- spec.version = GitWakaTime::VERSION
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'
6
+ Gem::Specification.new do |s|
7
+ s.name = 'gitwakatime'
8
+ s.version = GitWakaTime::VERSION
9
+ s.authors = ['Russell Osborne']
10
+ s.email = ['russosborn@gmail.com']
11
+ s.summary = 'A Tool that will compile git data with wakatime
12
+ data to establish time per commit'
13
+ s.description = 'A Tool that will compile git data with wakatime
14
+ data to establish time per commit '
15
+ s.homepage = ''
16
+ s.license = 'MIT'
15
17
 
16
- spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ['lib']
18
+ s.files = `git ls-files`.split($RS)
19
+ s.test_files = s.files.grep(/^spec\//)
20
+ s.executables = s.files.grep(/^bin\//) { |f| File.basename(f) }
20
21
 
21
- spec.add_runtime_dependency 'git', '>= 1.2.9.1'
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_runtime_dependency 'sequel'
29
- spec.add_runtime_dependency 'sqlite3'
30
- spec.add_development_dependency('bundler', ['>= 0'])
31
- spec.add_development_dependency 'rake'
32
- spec.add_development_dependency 'rspec'
33
- spec.add_development_dependency('webmock', ['>= 0'])
22
+ s.require_paths = ['lib']
23
+ s.authors = ['Bozhidar Batsov', 'Jonas Arvidsson', 'Yuji Nakayama']
24
+ s.description = <<-EOF
25
+ Automatic Ruby code style checking tool.
26
+ Aims to enforce the community-driven Ruby Style Guide.
27
+ EOF
28
+
29
+ s.add_runtime_dependency 'git', '>= 1.2.9.1'
30
+ s.add_runtime_dependency 'wakatime', '>= 0.0.2'
31
+ s.add_runtime_dependency 'logger', '>= 0'
32
+ s.add_runtime_dependency 'thor', '>= 0'
33
+ s.add_runtime_dependency 'chronic_duration', '>=0'
34
+ s.add_runtime_dependency 'colorize'
35
+ s.add_runtime_dependency 'activesupport'
36
+ s.add_runtime_dependency 'sequel'
37
+ s.add_runtime_dependency 'sqlite3'
38
+ s.add_development_dependency('bundler', ['>= 0'])
39
+ s.add_development_dependency 'rake'
40
+ s.add_development_dependency 'rspec'
41
+ s.add_development_dependency('webmock', ['>= 0'])
42
+ s.add_development_dependency('pry', ['>= 0'])
34
43
  end
data/lib/gitwakatime.rb CHANGED
@@ -6,21 +6,26 @@ else
6
6
  DB = Sequel.sqlite
7
7
  end
8
8
 
9
+ Sequel::Model.plugin :json_serializer
9
10
  DB.use_timestamp_timezones = false
10
11
 
11
12
  require 'gitwakatime/version'
12
13
  require 'gitwakatime/durations'
13
- require 'gitwakatime/action'
14
+ require 'gitwakatime/heartbeat'
14
15
  require 'gitwakatime/commit'
15
16
  require 'gitwakatime/mapper'
16
17
  require 'gitwakatime/query'
17
18
  require 'gitwakatime/timer'
18
19
  require 'gitwakatime/log'
19
20
  require 'gitwakatime/commited_file'
21
+ require 'gitwakatime/controller'
20
22
  require 'gitwakatime/cli'
21
23
 
22
- # Silence is golden
24
+ # It's a module :)
23
25
  module GitWakaTime
26
+ ##
27
+ # Stores primary config and project information
28
+ # Currently not thread safe.
24
29
  class Configuration
25
30
  attr_accessor :api_key, :log_level, :root, :project, :git
26
31
 
@@ -40,6 +45,12 @@ module GitWakaTime
40
45
  end
41
46
 
42
47
  def setup_local_db
48
+ create_commits_table
49
+ create_commited_files_table
50
+ create_heartbeats_table
51
+ end
52
+
53
+ def create_commits_table
43
54
  DB.create_table? :commits do
44
55
  primary_key :id
45
56
  String :sha
@@ -50,7 +61,9 @@ module GitWakaTime
50
61
  text :message
51
62
  String :author
52
63
  end
64
+ end
53
65
 
66
+ def create_commited_files_table
54
67
  DB.create_table? :commited_files do
55
68
  primary_key :id
56
69
  integer :commit_id
@@ -63,8 +76,10 @@ module GitWakaTime
63
76
  index :dependent_sha
64
77
  index :sha
65
78
  end
79
+ end
66
80
 
67
- DB.create_table? :actions do
81
+ def create_heartbeats_table
82
+ DB.create_table? :heartbeats do
68
83
  primary_key :id
69
84
  String :uuid
70
85
  DateTime :time
@@ -8,9 +8,9 @@ require 'active_support/core_ext/date/calculations'
8
8
  require 'active_support/core_ext/date_and_time/calculations'
9
9
  require 'active_support/core_ext/integer/time'
10
10
  require 'active_support/core_ext/time'
11
-
11
+ require 'pry'
12
12
  module GitWakaTime
13
- # Provides two CLI actions init and tally
13
+ # Provides two CLI heartbeats init and tally
14
14
  class Cli < Thor
15
15
  include Thor::Actions
16
16
  desc 'init', 'Setups up Project for using the wakatime API
@@ -25,7 +25,7 @@ module GitWakaTime
25
25
  create_file File.join(Dir.home, '.wakatime.yml') do
26
26
  YAML.dump(api_key: api_key, last_commit: nil, log_level: :info)
27
27
  end
28
- end
28
+ end
29
29
  reset
30
30
  end
31
31
 
@@ -41,26 +41,37 @@ module GitWakaTime
41
41
 
42
42
  desc 'tally', 'Produce time spend for each commit and file in each commit'
43
43
  method_option :file, aliases: '-f', default: '.'
44
- method_option :start_on, aliases: '-s', default: nil
44
+ method_option :start_on, aliases: '-s', default: 7.days.ago.to_s
45
+ method_option :output, aliases: '-o', default: 'text', type: 'string'
46
+
45
47
  def tally
46
- GitWakaTime.config.setup_local_db
47
- path, GitWakaTime.config.root = File.expand_path(options.file)
48
- date = Date.parse(options.start_on) if options.start_on
49
- date = 7.days.ago unless options.start_on
50
- GitWakaTime.config.load_config_yaml
51
- GitWakaTime.config.git = Git.open(path)
52
- @git_map = Mapper.new(start_at: date)
53
- @project = File.basename(GitWakaTime.config.git.dir.path)
54
- @relevant_commits = Commit.where('date > ? and project = ?', date, @project).all
55
- @actions = Query.new(@relevant_commits, File.basename(path)).get
48
+ date = Date.parse(options.start_on)
56
49
 
57
- @timer = Timer.new(@relevant_commits, @actions, File.basename(path)).process
50
+ @timer = GitWakaTime::Controller.new(
51
+ path: File.expand_path(options.file), date: date
52
+ ).timer
53
+
54
+ print_output(@timer)
55
+ end
56
+
57
+ no_commands do
58
+ def print_output(timer)
59
+ if output == 'text'
60
+ timer.each do |c_date, commits|
61
+ print_commit(c_date, commits)
62
+ end
63
+ elsif output == 'json'
64
+ @timer.to_json
65
+ end
66
+ end
58
67
 
59
- @timer.each do |date, commits|
60
- Log.new format('%-40s %-40s'.blue,
61
- date,
62
- "Total #{ChronicDuration.output commits.map(&:time_in_seconds).compact.reduce(&:+).to_i}"
63
- )
68
+ def print_commit
69
+ sum_c_time = commits.map(&:time_in_seconds).compact.reduce(&:+).to_i
70
+ Log.new format(
71
+ '%-40s %-40s'.blue,
72
+ c_date,
73
+ "Total #{ChronicDuration.output sum_c_time }"
74
+ )
64
75
  commits.each do |commit|
65
76
  # Log.new commit.message
66
77
  Log.new commit.to_s
@@ -1,8 +1,11 @@
1
1
  module GitWakaTime
2
+ ##
3
+ # Cache git commit and correlate it's children
4
+ #
2
5
  class Commit < Sequel::Model
3
6
  one_to_many :commited_files
4
7
  def after_create
5
- get_files
8
+ extract_changed_files
6
9
  end
7
10
 
8
11
  def to_s
@@ -24,16 +27,15 @@ module GitWakaTime
24
27
 
25
28
  private
26
29
 
27
- def get_files
30
+ def extract_changed_files
28
31
  @raw_commit = GitWakaTime.config.git.gcommit(sha)
29
32
  # TODO: Assume gap time to lookup time prior to first commit.
30
- if @raw_commit.parent
31
- update(parent_sha: @raw_commit.parent.sha)
33
+ return unless @raw_commit.parent
34
+ update(parent_sha: @raw_commit.parent.sha)
32
35
 
33
- @raw_commit.diff_parent.stats[:files].keys.map do |file|
34
- CommitedFile.find_or_create(commit_id: id, name: file) do |c|
35
- c.update(sha: sha, project: project)
36
- end
36
+ @raw_commit.diff_parent.stats[:files].keys.map do |file|
37
+ CommitedFile.find_or_create(commit_id: id, name: file) do |c|
38
+ c.update(sha: sha, project: project)
37
39
  end
38
40
  end
39
41
  end
@@ -1,9 +1,12 @@
1
1
  module GitWakaTime
2
+ ##
3
+ # Determines When a file was lasted commit and stores time and hash.
2
4
  class CommitedFile < Sequel::Model
3
5
  many_to_one :commit
4
- # No two committed files should have the same name + dependent_date this
5
- # means a split tree, and we should split time between the two, or more, commits.
6
6
 
7
+ # No two committed files should have the same name + dependent_date this
8
+ # means a split tree, and we should split time between the two, or
9
+ # more, commits.
7
10
  def before_create
8
11
  find_dependent_commit(name)
9
12
  end
@@ -18,34 +21,37 @@ module GitWakaTime
18
21
 
19
22
  private
20
23
 
21
- def find_dependent_commit(name)
22
- i = 1
23
-
24
- # Call git log for path, loop through till we find a valid commit or run
25
- # out of commits to check
24
+ # Call git log for path, loop through till we find a valid commit or run
25
+ # out of commits to check
26
+ def find_dependent_commit(name, i = 1)
26
27
  commits = load_dependent_commits(name)
27
- begin
28
+ loop do
28
29
  commit = commits[i]
30
+ break if commit.nil?
29
31
 
30
- if commit && allowed_commit(commit)
31
-
32
- self.dependent_date = commit.date
33
- self.dependent_sha = commit.sha
32
+ next unless allowed_commit(commit)
34
33
 
35
- # This is the magical fix for the split tree issue
36
- # Current though is this will fail if more than 2 split tree files
37
- split_tree_file = CommitedFile.where(name: name, dependent_sha: commit.sha).first
38
- if split_tree_file && split_tree_file.commit
39
- if self.commit.date < split_tree_file.commit.date
40
- self.dependent_date = split_tree_file.commit.date
41
- elsif self.commit.date > split_tree_file.commit.date
42
- split_tree_file.update(dependent_date: commit.date)
43
- end
44
- end
45
- end
34
+ set dependent_sha: commit.sha, dependent_date: commit.date
46
35
 
36
+ check_and_correct_split_tree(commit)
47
37
  i += 1
48
- end until !dependent_sha.nil? || commit.nil?
38
+ break unless dependent_sha.blank?
39
+ end
40
+ end
41
+
42
+ def check_and_correct_split_tree(commit)
43
+ # This is the magical fix for the split tree issue
44
+ # Current though is this will fail if more than 2 split tree files
45
+ split_tree_file = CommitedFile.where(
46
+ name: name, dependent_sha: commit.sha
47
+ ).first
48
+ return unless split_tree_file && split_tree_file.commit
49
+
50
+ if self.commit.date < split_tree_file.commit.date
51
+ self.dependent_date = split_tree_file.commit.date
52
+ elsif self.commit.date > split_tree_file.commit.date
53
+ split_tree_file.update(dependent_date: commit.date)
54
+ end
49
55
  end
50
56
 
51
57
  def allowed_commit(commit)
@@ -0,0 +1,31 @@
1
+ module GitWakaTime
2
+ # Extract Duration Data from Heartbeats for the WAKATIME API
3
+ class Controller
4
+ def initialize(path: '.', date: nil)
5
+ @path = path
6
+ GitWakaTime.config.setup_local_db
7
+ GitWakaTime.config.root = path
8
+ GitWakaTime.config.load_config_yaml
9
+ GitWakaTime.config.git = Git.open(path)
10
+ @git_map = Mapper.new(start_at: date)
11
+ @project = File.basename(GitWakaTime.config.git.dir.path)
12
+ @relevant_commits = Commit.where(
13
+ 'date > ? and project = ?', date, @project
14
+ )
15
+
16
+ @files = CommitedFile.where(
17
+ 'commit_id IN ?', @relevant_commits.select_map(:id)
18
+ ).where('project = ?', @project)
19
+
20
+ @heartbeats = Query.new(
21
+ @relevant_commits, @files, File.basename(path)
22
+ ).get
23
+ end
24
+
25
+ def timer
26
+ Timer.new(
27
+ @relevant_commits.all, @heartbeats, File.basename(@path)
28
+ ).process
29
+ end
30
+ end
31
+ end
@@ -1,90 +1,93 @@
1
1
  module GitWakaTime
2
- # Extract Duration Data from Actions for the WAKATIME API
2
+ # Extract Duration Data from Heartbeats for the WAKATIME API
3
3
  class Durations
4
- attr_accessor :actions
4
+ attr_accessor :heartbeats
5
5
  def initialize(args)
6
- return @actions = args[:actions] if args[:actions]
6
+ return @heartbeats = args[:heartbeats] if args[:heartbeats]
7
7
  fail if args[:project].nil?
8
8
  @project = args[:project]
9
9
  @args = args
10
10
  @session = Wakatime::Session.new(api_key: GitWakaTime.config.api_key)
11
11
  @client = Wakatime::Client.new(@session)
12
- @actions = []
12
+ @heartbeats = []
13
13
  end
14
14
 
15
- def load_actions
15
+ def load_heartbeats
16
16
  unless cached?
17
17
 
18
- Log.new "querying WakaTime actions for #{@project}"
18
+ Log.new "querying WakaTime heartbeats for #{@project}"
19
19
  time = Benchmark.realtime do
20
- @actions = @client.actions(@args)
20
+ @heartbeats = @client.heartbeats(@args)
21
21
 
22
- # remove returned actions that do not have the project we want
23
- @actions = @actions.keep_if do |a|
22
+ # remove returned heartbeats that do not have the project we want
23
+ @heartbeats = @heartbeats.keep_if do |a|
24
24
  a['project'] == @project
25
25
  end
26
26
  end
27
27
 
28
28
  Log.new "API took #{time}s"
29
- persist_actions_localy(@actions)
29
+ persist_heartbeats_localy(@heartbeats)
30
30
  end
31
31
  true
32
32
  end
33
33
 
34
- def persist_actions_localy(actions)
35
- sterile_actions = actions.map do |action|
36
- action['uuid'] = action['id']
37
- action['time'] = Time.at(action['time'])
38
- action.delete('id')
39
- Action.find_or_create(uuid: action['uuid']) do |a|
40
- a.update(action)
41
- end
34
+ def persist_heartbeats_localy(heartbeats)
35
+ heartbeats.map do |heartbeat|
36
+ heartbeat['uuid'] = heartbeat['id']
37
+ heartbeat['time'] = Time.at(heartbeat['time'])
38
+ heartbeat.delete('id')
39
+ Heartbeat.find_or_create(uuid: heartbeat['uuid']) do |a|
40
+ a.update(heartbeat)
41
+ end
42
42
  end
43
-
44
43
  end
45
44
 
46
45
  def cached?
47
46
  # Check to see if this date range might be stale?
48
- if cached_actions.count > 0
49
- max_local_timetamp = (Time.parse(cached_actions.max(:time)) + 3.day).to_date
50
- !(@args[:start].to_date..@args[:end].to_date).include?(max_local_timetamp)
47
+ if cached_heartbeats.count > 0
48
+ max_local_timetamp = (
49
+ Time.parse(cached_heartbeats.max(:time)) + 3.day
50
+ ).to_date
51
+ !(
52
+ @args[:start].to_date..@args[:end].to_date
53
+ ).include?(max_local_timetamp)
51
54
  else
52
55
  false
53
56
  end
54
57
  end
55
58
 
56
- def cached_actions
57
- Action.where('time >= ?',@args[:end]).where(project: @project)
59
+ def cached_heartbeats
60
+ Heartbeat.where('time >= ?', @args[:end]).where(project: @project)
58
61
  end
59
62
 
60
- def actions_to_durations(_project = nil, timeout = 15)
63
+ def heartbeats_to_durations(_project = nil, timeout = 15)
61
64
  durations = []
62
65
  current = nil
63
66
 
64
- @actions.each do | action |
65
- # the first action just sets state and does nothing
67
+ @heartbeats.each do | heartbeat |
68
+ # the first heartbeat just sets state and does nothing
66
69
  unless current.nil?
67
70
 
68
- # get duration since last action
69
- duration = action.time.round - current.time.round
71
+ # get duration since last heartbeat
72
+ duration = heartbeat.time.round - current.time.round
70
73
 
71
74
  duration = 0.0 if duration < 0
72
75
 
73
76
  # duration not logged if greater than the timeout
74
77
  if duration < timeout * 60
75
78
 
76
- # add duration to current action
79
+ # add duration to current heartbeat
77
80
  current.duration = duration
78
81
 
79
82
  # save to local db
80
83
  current.save
81
84
 
82
- # log current action as a duration
85
+ # log current heartbeat as a duration
83
86
  durations << current
84
87
  end
85
88
  end
86
89
  # set state (re-start the clock)
87
- current = action
90
+ current = heartbeat
88
91
 
89
92
  end
90
93
  durations
@@ -0,0 +1,4 @@
1
+ module GitWakaTime
2
+ class Heartbeat < Sequel::Model
3
+ end
4
+ end
@@ -1,4 +1,6 @@
1
1
  module GitWakaTime
2
+ ##
3
+ # Pretty output, and ability to silence in testing
2
4
  class Log
3
5
  def initialize(msg, color = nil)
4
6
  @color = color
@@ -3,54 +3,76 @@ require 'colorize'
3
3
  require 'active_support/core_ext/time'
4
4
 
5
5
  module GitWakaTime
6
- # Integrates the nested hash from mapper with actions api
6
+ # Integrates the nested hash from mapper with heartbeats api
7
7
  class Query
8
- def initialize(commits, project, _path = nil)
8
+ def initialize(commits, files, project, _path = nil)
9
9
  @commits = commits
10
+ @files = files
10
11
  @api_limit = 35
11
12
  @project = project
12
- @requests = time_params
13
+ @requests = build_requests
14
+ end
15
+
16
+ def time_range
17
+ commits = @commits.select_map(:date).sort
18
+ d_commits = @files.select_map(:dependent_date).compact.sort
19
+ timestamps = (commits + d_commits.flatten).uniq.sort
20
+
21
+ # Don't query before the Wakatime Epoch
22
+ @start_at = if timestamps.first >= Time.new(2013, 5, 1)
23
+ timestamps.first
24
+ else
25
+ Time.new(2013, 5, 1)
26
+ end
27
+ @end_at = timestamps.last
13
28
  end
14
29
 
15
30
  def get
16
31
  @requests.each do |params|
17
- Log.new "Requesting actions #{params[:start].to_date} to #{params[:end].to_date}".red
18
- Durations.new(params).load_actions
32
+ Log.new "Gettting heartbeats
33
+ #{params[:start].to_date} to #{params[:end].to_date}".red
34
+ Durations.new(params).load_heartbeats
19
35
  end
20
36
 
21
- Durations.new(actions: actions).actions_to_durations
37
+ Durations.new(
38
+ heartbeats: heartbeats.where('duration <= 0')
39
+ ).heartbeats_to_durations
40
+ heartbeats.all
22
41
  end
23
42
 
24
- def actions
25
- Action.where('time >= ? and time <= ? ', @start_at, @end_at).where(project: @project)
43
+ def heartbeats
44
+ Heartbeat.where(
45
+ 'time >= ? and time <= ? ', @start_at, @end_at
46
+ ).where(project: @project)
26
47
  end
27
48
 
28
- def time_params
29
- commits = @commits.map(&:date)
30
- d_commits = CommitedFile.select(:dependent_date).all.map { |f| f.values[:dependent_date] }.compact
31
- timestamps = (commits + d_commits.flatten).uniq.sort
32
-
33
- # Don't query before the Wakatime Epoch
34
- @start_at = timestamps.first >= Time.new(2013, 5, 1) ? timestamps.first : Time.new(2013, 5, 1)
35
- @end_at = timestamps.last
49
+ def build_requests
50
+ time_range
36
51
 
37
- # Always have a date range great than 1 as the num request will be 0/1 otherwise
52
+ # Always have a date range great than 1 as the num request
53
+ # will be 0/1 otherwise
38
54
  num_requests = ((@end_at.to_date + 1) - @start_at.to_date) / @api_limit
39
55
  i = 0
40
56
 
41
57
  request_params = num_requests.to_f.ceil.times.map do
42
58
 
43
- params = {
44
- start: (@start_at.to_date + (i * @api_limit)).to_time.beginning_of_day,
45
- end: (@start_at.to_date + ((i + 1) * @api_limit)).to_time.end_of_day,
46
- project: @project,
47
- show: 'file,branch,project,time,id'
48
- }
59
+ params = construct_params(i)
49
60
  i += 1
50
61
  params
51
62
 
52
63
  end
53
64
  request_params
54
65
  end
66
+
67
+ def construct_params(i)
68
+ {
69
+ start: (
70
+ @start_at.to_date + (i * @api_limit)
71
+ ).to_time.beginning_of_day,
72
+ end: (@start_at.to_date + ((i + 1) * @api_limit)).to_time.end_of_day,
73
+ project: @project,
74
+ show: 'file,branch,project,time,id'
75
+ }
76
+ end
55
77
  end
56
78
  end
@@ -3,23 +3,23 @@ require 'colorize'
3
3
  require 'active_support/core_ext/time'
4
4
 
5
5
  module GitWakaTime
6
- # Integrates the nested hash from mapper with actions api
6
+ # Integrates the nested hash from mapper with heartbeats api
7
7
  class Timer
8
- def initialize(commits, actions_with_durations, project)
8
+ def initialize(commits, heartbeats_with_durations, project)
9
9
  @commits = commits
10
- @actions_with_durations = actions_with_durations
10
+ @heartbeats_with_durations = heartbeats_with_durations
11
11
  @project = project
12
12
  end
13
13
 
14
14
  def total
15
- total_time = sum_actions @actions_with_durations
15
+ total_time = sum_heartbeats @heartbeats_with_durations
16
16
  Log.new "Total Recorded time #{ChronicDuration.output total_time}", :red
17
17
  end
18
18
 
19
19
  def total_commited
20
20
  total_commited = ChronicDuration.output(@commits_with_duration
21
- .map(&:time_in_seconds).compact
22
- .reduce(:+).to_f)
21
+ .map(&:time_in_seconds).compact
22
+ .reduce(:+).to_f)
23
23
  Log.new "Total Committed Time #{total_commited} ".red
24
24
  end
25
25
 
@@ -28,7 +28,7 @@ module GitWakaTime
28
28
 
29
29
  if commit.commited_files.count > 0 || commit.parent_sha
30
30
  commit.commited_files.each_with_index do |file, _i|
31
- time = sum_actions relevant_actions(commit, file)
31
+ time = sum_heartbeats relevant_heartbeats(commit, file)
32
32
  file.time_in_seconds = time
33
33
  commit.time_in_seconds = time
34
34
 
@@ -36,49 +36,52 @@ module GitWakaTime
36
36
  end
37
37
  commit.save
38
38
  else
39
- commit.time_in_seconds = sum_actions(actions_before(@actions_with_durations, commit.date))
39
+ commit.time_in_seconds = sum_heartbeats(
40
+ heartbeats_before(@heartbeats_with_durations, commit.date)
41
+ )
40
42
  end
41
43
  end.compact
42
44
  total
43
45
  total_commited
44
- @commits_with_duration
45
- @commits_with_duration_by_date = @commits_with_duration.group_by { |c| c.date.to_date }
46
+ @commits_with_duration.group_by { |c| c.date.to_date }
46
47
  end
47
48
 
48
49
  private
49
50
 
50
- def relevant_actions(commit, file)
51
+ def relevant_heartbeats(commit, file)
51
52
  # The file should be the same file as we expect
52
53
  # TODO: Might need to pass root_path down
53
- actions = @actions_with_durations.select do |action|
54
- action[:file].include?(File.join(File.basename(GitWakaTime.config.git.dir.path), file.name))
54
+ heartbeats = @heartbeats_with_durations.select do |heartbeat|
55
+ heartbeat[:file].include?(
56
+ File.join(File.basename(GitWakaTime.config.git.dir.path), file.name)
57
+ )
55
58
  end
56
59
 
57
60
  # The timestamps should be before the expected commit
58
- actions = actions_before(actions, commit.date)
61
+ heartbeats = heartbeats_before(heartbeats, commit.date)
59
62
 
60
- # If this file had an earlier commit ensure the actions timestamp
63
+ # If this file had an earlier commit ensure the heartbeats timestamp
61
64
  # is after that commit
62
65
  if file.dependent_date
63
- actions = actions_after(actions, file.dependent_date)
66
+ heartbeats = heartbeats_after(heartbeats, file.dependent_date)
64
67
  end
65
- actions
68
+ heartbeats
66
69
  end
67
70
 
68
- def actions_before(actions, date)
69
- actions.select do |action|
70
- Time.at(action[:time]) <= date
71
+ def heartbeats_before(heartbeats, date)
72
+ heartbeats.select do |heartbeat|
73
+ Time.at(heartbeat[:time]) <= date
71
74
  end
72
75
  end
73
76
 
74
- def actions_after(actions, date)
75
- actions.select do |action|
76
- Time.at(action[:time]) >= date
77
+ def heartbeats_after(heartbeats, date)
78
+ heartbeats.select do |heartbeat|
79
+ Time.at(heartbeat[:time]) >= date
77
80
  end
78
81
  end
79
82
 
80
- def sum_actions(actions)
81
- actions.map { |action| action[:duration] }
83
+ def sum_heartbeats(heartbeats)
84
+ heartbeats.map { |heartbeat| heartbeat[:duration] }
82
85
  .reduce(:+).to_i
83
86
  end
84
87
  end
@@ -1,4 +1,4 @@
1
1
  # Version Number Definition
2
2
  module GitWakaTime
3
- VERSION = '0.1.2'
3
+ VERSION = '0.2.0'
4
4
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
- # * commit a4c26aeb79acb1f012201fe96e4d68e8d17c75d9 (HEAD, origin/master, origin/HEAD, master)
2
+ # * commit a4c26aeb79acb1f012201fe96e4d68e8d17c75d9
3
+ # | (HEAD, origin/master, origin/HEAD, master)
3
4
  # | Author: rpo <rother@gmail.com>
4
5
  # | Date: Sat Jan 31 15:49:07 2015 -0500
5
6
  # |
@@ -54,7 +55,7 @@ require 'spec_helper'
54
55
 
55
56
  # created readme
56
57
  describe 'description' do
57
- let (:git) { Git.open(@wdir) }
58
+ let(:git) { Git.open(@wdir) }
58
59
 
59
60
  before do
60
61
  GitWakaTime::Commit.dataset.destroy
@@ -65,29 +66,48 @@ describe 'description' do
65
66
  GitWakaTime.config.git = git
66
67
 
67
68
  first_commit = GitWakaTime::Commit.find_or_create(
68
- sha: 'e493d6f2ab2a702fa7f9c168b852a3b44c524f08',
69
- author: 'Russell Osborne',
70
- message: 'conflicting commit on blah.',
71
- project: git.repo.to_s,
72
- date: Time.at(1_422_570_380)
69
+ sha: 'e493d6f2ab2a702fa7f9c168b852a3b44c524f08',
70
+ author: 'Russell Osborne',
71
+ message: 'conflicting commit on blah.',
72
+ project: git.repo.to_s,
73
+ date: DateTime.parse('Thu Jan 29 22:26:20 2015 -0500').utc
73
74
  )
74
75
 
75
- expect(first_commit.commited_files.first.dependent_sha).to eql('4c1ea35f9a811a0ef79da15ec85f25fce4c446ba')
76
- expect(first_commit.commited_files.first.dependent_date.utc.to_s).to eql('2015-01-30 03:25:08 UTC')
76
+ expect(
77
+ first_commit.commited_files.first.dependent_sha
78
+ ).to eql(
79
+ '4c1ea35f9a811a0ef79da15ec85f25fce4c446ba'
80
+ )
81
+ expect(
82
+ first_commit.commited_files.first.dependent_date.utc.to_s
83
+ ).to eql(
84
+ '2015-01-30 03:25:08 UTC'
85
+ )
77
86
 
78
87
  second_commit = GitWakaTime::Commit.find_or_create(
79
- sha: 'd642b3c04c3025655a9c33e32b9d530696dcf7cc',
80
- author: 'Russell Osborne',
81
- message: 'conflicting commit on master.',
82
- project: git.repo.to_s,
83
- date: 'Thu Jan 29 22:26:05 2015 -0500'
84
- )
88
+ sha: 'd642b3c04c3025655a9c33e32b9d530696dcf7cc',
89
+ author: 'Russell Osborne',
90
+ message: 'conflicting commit on master.',
91
+ project: git.repo.to_s,
92
+ date: DateTime.parse('Thu Jan 29 22:26:05 2015 -0500').utc
93
+ )
94
+
95
+ # Verify that we have a split tree, both commit 1 and two should depend on
96
+ # 4c1ea
97
+ expect(
98
+ second_commit.commited_files.first.dependent_sha
99
+ ).to eql('4c1ea35f9a811a0ef79da15ec85f25fce4c446ba')
100
+
101
+ expect(
102
+ GitWakaTime::Commit.find(id: first_commit.id)
103
+ .commited_files.first.dependent_date.utc.to_s
104
+ ).to eql('2015-01-30 03:25:08 UTC')
85
105
 
86
- expect(second_commit.commited_files.first.dependent_sha).to eql('4c1ea35f9a811a0ef79da15ec85f25fce4c446ba')
106
+ # Second commit should depend on first commit not actual depedent time as
107
+ # it would duplicate time
87
108
  expect(
88
- GitWakaTime::Commit.find(id: first_commit.id).commited_files.first.dependent_date.utc.to_s
89
- ).to eql('2015-01-30 03:25:08 UTC')
90
- expect(second_commit.commited_files.first.dependent_date.utc.to_s).to eql(Time.at(1_422_570_380).utc.to_s)
109
+ second_commit.commited_files.first.dependent_date.utc.to_s
110
+ ).to eql(Time.parse('Thu Jan 29 22:26:20 2015 -0500').utc.to_s)
91
111
  end
92
112
 
93
113
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'description' do
4
- # let (:git) { Git.open(@wdir) }
4
+ # let(:git) { Git.open(@wdir) }
5
5
  before(:each) do
6
6
  # GitWakaTime.config.git = git
7
7
  # GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 28))
@@ -11,7 +11,7 @@ describe 'description' do
11
11
  pending
12
12
  end
13
13
 
14
- it 'calculates durations of actions' do
14
+ it 'calculates durations of heartbeats' do
15
15
  pending
16
16
  end
17
17
 
File without changes
data/spec/mapper_spec.rb CHANGED
@@ -1,24 +1,34 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'description' do
4
- let (:git) { Git.open(@wdir) }
4
+ let(:git) { Git.open(@wdir) }
5
5
  before(:each) do
6
6
  GitWakaTime.config.git = git
7
- GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 28))
7
+ GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 25))
8
8
  end
9
9
 
10
10
  it 'can be run on dummy' do
11
- expect(GitWakaTime::Commit.all.size).to eq 8 # 9ths is lonely
11
+ expect(
12
+ GitWakaTime::Commit.all.size
13
+ ).to eq 7 # 9ths is lonely
12
14
  end
13
15
  it 'can be run on dummy' do
14
- expect(GitWakaTime::Commit.order(:date).first.message).to eq 'created readme'
16
+ expect(
17
+ GitWakaTime::Commit.order(:date).first.message
18
+ ).to eq 'created readme'
15
19
  end
16
20
 
17
21
  it 'maps files dependent commits' do
18
- expect(GitWakaTime::Commit.all.first.commited_files.first.dependent_sha).to eq 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d'
22
+ expect(
23
+ GitWakaTime::Commit.all.first.commited_files.first.dependent_sha
24
+ ).to eq 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d'
19
25
  end
20
26
 
21
27
  it 'maps files dependent commits' do
22
- expect(GitWakaTime::Commit.all.select { |c| c.sha == 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d' }.first.commited_files.first.dependent_sha).to eq '2254dd56976b5f32a2289438842e42a35a18ff86'
28
+ expect(
29
+ GitWakaTime::Commit.all.select do |c|
30
+ c.sha == 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d'
31
+ end.first.commited_files.first.dependent_sha
32
+ ).to eq '2254dd56976b5f32a2289438842e42a35a18ff86'
23
33
  end
24
34
  end
data/spec/query_spec.rb CHANGED
@@ -5,28 +5,31 @@ describe 'description' do
5
5
  before(:each) do
6
6
  GitWakaTime.config.git = Git.open(@wdir)
7
7
  GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 24))
8
+ @commits = GitWakaTime::Commit
9
+ @files = GitWakaTime::CommitedFile
10
+ @query = GitWakaTime::Query.new(@commits, @files, File.basename(@wdir))
8
11
  end
9
12
 
10
13
  before do
11
- stub_request(:get, 'https://wakatime.com/api/v1/actions')
14
+ stub_request(:get, 'https://wakatime.com/api/v1/heartbeats')
12
15
  .with(query: hash_including(:start, :end))
13
- .to_return(body: File.read('./spec/fixtures/actions.json'), status: 200)
16
+ .to_return(body: File.read('./spec/fixtures/heartbeats.json'), status: 200)
14
17
  end
15
18
 
16
19
  it 'can be run on dummy' do
20
+ heartbeats = @query.get
17
21
 
18
- actions = GitWakaTime::Query.new(GitWakaTime::Commit.all, File.basename(@wdir)).get
19
-
20
- expect(actions).to be_a Array
21
- expect(actions.size).to eq 6 # 9ths is lonely
22
- expect(actions.last).to be_a GitWakaTime::Action
23
- expect(actions.last.branch).to eq 'master'
22
+ expect(heartbeats).to be_a Array
23
+ expect(heartbeats.size).to eq 9 # 10ths is lonely
24
+ expect(heartbeats.last).to be_a GitWakaTime::Heartbeat
25
+ expect(heartbeats.last.branch).to eq 'master'
24
26
  end
25
27
  it 'produces valid search for api' do
26
- actions = GitWakaTime::Query.new(GitWakaTime::Commit.all, File.basename(@wdir)).time_params
27
28
 
28
- expect(actions).to be_a Array
29
- expect(actions.first[:start].to_date).to eq Date.new(2015, 01, 30)
30
- expect(actions.first[:end].to_date).to eq Date.new(2015, 02, 14)
29
+ heartbeats = @query.build_requests
30
+
31
+ expect(heartbeats).to be_a Array
32
+ expect(heartbeats.first[:start].to_date).to eq Date.new(2015, 01, 29)
33
+ expect(heartbeats.first[:end].to_date).to eq Date.new(2015, 03, 05)
31
34
  end
32
35
  end
data/spec/spec_helper.rb CHANGED
@@ -18,15 +18,17 @@ RSpec.configure do |config|
18
18
  GitWakaTime.config.setup_local_db
19
19
  GitWakaTime::Commit.new.columns
20
20
  GitWakaTime::CommitedFile.new.columns
21
- GitWakaTime::Action.new.columns
21
+ GitWakaTime::Heartbeat.new.columns
22
22
  end
23
23
 
24
24
  config.before(:each) do
25
25
  GitWakaTime::Commit.truncate
26
26
  GitWakaTime::CommitedFile.truncate
27
- GitWakaTime::Action.truncate
27
+ GitWakaTime::Heartbeat.truncate
28
28
 
29
- expect(GitWakaTime.config).to receive('user_name').and_return('Russell Osborne').at_least(:once)
29
+ expect(
30
+ GitWakaTime.config
31
+ ).to receive('user_name').and_return('Russell Osborne').at_least(:once)
30
32
  end
31
33
 
32
34
  config.after(:all) do
@@ -47,12 +49,18 @@ end
47
49
 
48
50
  def create_temp_repo(clone_path)
49
51
  filename = 'git_test' + Time.now.to_i.to_s + rand(300).to_s.rjust(3, '0')
50
- @tmp_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'tmp', filename))
52
+ @tmp_path = File.expand_path(
53
+ File.join(File.dirname(__FILE__), '..', 'tmp', filename)
54
+ )
51
55
  FileUtils.mkdir_p(@tmp_path)
52
56
  FileUtils.cp_r(clone_path, @tmp_path)
53
57
  tmp_path = File.join(@tmp_path, 'dummy')
54
- Dir.chdir(tmp_path) do
58
+ activate_repo_as_git(tmp_path)
59
+ tmp_path
60
+ end
61
+
62
+ def activate_repo_as_git(path)
63
+ Dir.chdir(path) do
55
64
  FileUtils.mv('dot_git', '.git')
56
65
  end
57
- tmp_path
58
66
  end
data/spec/timer_spec.rb CHANGED
@@ -1,23 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'description' do
4
- let (:git) { Git.open(@wdir) }
4
+ let(:git) { Git.open(@wdir) }
5
5
 
6
6
  before do
7
- stub_request(:get, 'https://wakatime.com/api/v1/actions')
7
+ stub_request(:get, 'https://wakatime.com/api/v1/heartbeats')
8
8
  .with(query: hash_including(:start, :end))
9
- .to_return(body: File.read('./spec/fixtures/actions.json'), status: 200)
9
+ .to_return(body: File.read('./spec/fixtures/heartbeats.json'), status: 200)
10
10
  end
11
11
 
12
12
  it 'can be run on dummy' do
13
13
  GitWakaTime.config.git = git
14
14
  GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 24))
15
- actions = GitWakaTime::Query.new(GitWakaTime::Commit.all, File.basename(@wdir)).get
16
- timer = GitWakaTime::Timer.new(GitWakaTime::Commit.all, actions, File.basename(@wdir)).process
15
+ heartbeats = GitWakaTime::Query.new(
16
+ GitWakaTime::Commit, GitWakaTime::CommitedFile, File.basename(@wdir)
17
+ ).get
18
+ timer = GitWakaTime::Timer.new(
19
+ GitWakaTime::Commit.all, heartbeats, File.basename(@wdir)
20
+ ).process
17
21
 
18
- # # UTC breaks actions of 1 day
22
+ # # UTC breaks heartbeats of 1 day
19
23
  # expect(timer.size).to eq 1
20
- # With 8 relevant commits
21
- expect(timer[timer.keys.first].size).to eq 8
24
+ # With 7 relevant commits
25
+ expect(timer[timer.keys.first].size).to eq 7
26
+ expect(
27
+ timer[Date.new(2015, 1, 30)].map(&:time_in_seconds).compact.reduce(&:+)
28
+ ).to eql(201)
22
29
  end
23
30
  end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitwakatime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - Russell Osborne
7
+ - Bozhidar Batsov
8
+ - Jonas Arvidsson
9
+ - Yuji Nakayama
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2015-02-11 00:00:00.000000000 Z
13
+ date: 2015-02-13 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: git
@@ -192,8 +194,23 @@ dependencies:
192
194
  - - ">="
193
195
  - !ruby/object:Gem::Version
194
196
  version: '0'
195
- description: 'A Tool that will compile git data with wakatime data to establish time
196
- per commit '
197
+ - !ruby/object:Gem::Dependency
198
+ name: pry
199
+ requirement: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ type: :development
205
+ prerelease: false
206
+ version_requirements: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ version: '0'
211
+ description: |2
212
+ Automatic Ruby code style checking tool.
213
+ Aims to enforce the community-driven Ruby Style Guide.
197
214
  email:
198
215
  - russosborn@gmail.com
199
216
  executables:
@@ -211,11 +228,12 @@ files:
211
228
  - bin/gitwakatime
212
229
  - gitwakatime.gemspec
213
230
  - lib/gitwakatime.rb
214
- - lib/gitwakatime/action.rb
215
231
  - lib/gitwakatime/cli.rb
216
232
  - lib/gitwakatime/commit.rb
217
233
  - lib/gitwakatime/commited_file.rb
234
+ - lib/gitwakatime/controller.rb
218
235
  - lib/gitwakatime/durations.rb
236
+ - lib/gitwakatime/heartbeat.rb
219
237
  - lib/gitwakatime/log.rb
220
238
  - lib/gitwakatime/mapper.rb
221
239
  - lib/gitwakatime/query.rb
@@ -272,7 +290,7 @@ files:
272
290
  - spec/dummy/hi
273
291
  - spec/dummy/readme
274
292
  - spec/durations_spec.rb
275
- - spec/fixtures/actions.json
293
+ - spec/fixtures/heartbeats.json
276
294
  - spec/mapper_spec.rb
277
295
  - spec/query_spec.rb
278
296
  - spec/spec_helper.rb
@@ -354,7 +372,7 @@ test_files:
354
372
  - spec/dummy/hi
355
373
  - spec/dummy/readme
356
374
  - spec/durations_spec.rb
357
- - spec/fixtures/actions.json
375
+ - spec/fixtures/heartbeats.json
358
376
  - spec/mapper_spec.rb
359
377
  - spec/query_spec.rb
360
378
  - spec/spec_helper.rb
@@ -1,4 +0,0 @@
1
- module GitWakaTime
2
- class Action < Sequel::Model
3
- end
4
- end