gitwakatime 0.1.2 → 0.2.0

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: 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