gitwakatime 0.0.3 → 0.1.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: 0cf4972a50946fcb26cfdf6170e2a52930ac0b17
4
- data.tar.gz: 382999961244a24765284c514aa00584574674ab
3
+ metadata.gz: 46d9e8b02b43ba532f6631155c4beadff25d65e1
4
+ data.tar.gz: 7ea139ea0454e766c82186a526bc17cad859a542
5
5
  SHA512:
6
- metadata.gz: cbbce74e5296c17b1f363b7471d29bc18cc479d36183ff773aabb41961b3a4d138b2e86123e7006dd150d3bb7c64f48829333dbb84cea8f31181840534d5ca14
7
- data.tar.gz: e6f8104a2ee6ea1b4d02707dbd4e8331140656a8f5d994300093efcb83c91bbbe1be5b37971b31a4fb5daaddebc97e852eef01de6d00707459a6628a7f3659ed
6
+ metadata.gz: baed9a3f9d7cd015d0148356e657cac46b792ae0b8276c4ad61848ec26cfc700bbfbf0b6b36abff102bf825cedf9723292143aa689033bdcd312ca1fa0bce1e9
7
+ data.tar.gz: a51aca840239070583c1f81f3326931f72cd023e893850b7e755c8da30308bfb5325f844e387891fca7ca98dffdb8dc0e5a70a0877848120de0291c180e99d5c
@@ -1,4 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.0
3
+ - 2.1.2
4
4
  script: bundle exec rake spec
5
+
6
+ addons:
7
+ code_climate:
8
+ repo_token: 214446b5fc4f8697cc9ccc3ab1f2612c2e083ea1e71266648319663719cf85b9
data/README.md CHANGED
@@ -4,10 +4,8 @@
4
4
  [![Gem Version](https://badge.fury.io/rb/gitwakatime.svg)](http://badge.fury.io/rb/gitwakatime)
5
5
  [![Code Climate](https://codeclimate.com/github/rposborne/gitwakatime/badges/gpa.svg)](https://codeclimate.com/github/rposborne/gitwakatime)
6
6
 
7
- GitWakaTime is a mashup between data obtained through "wakatime" and the data we all create using git.
8
- 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?"
9
-
10
-
7
+ GitWakaTime is a mash up between data obtained through "wakatime" and the data we all create using git.
8
+ The principal is to capture a baseline of activity for a task and answer the age old question "How much time did I spend on this?" or "What is the minimum amount I can charge for my time"
11
9
 
12
10
  ## Installation
13
11
 
@@ -15,15 +13,21 @@ Install the gem:
15
13
 
16
14
  $ gem install gitwakatime
17
15
 
18
- ## Usage
16
+ Run the setup command: (you will need your wakatime api key). Creates a .gitwakatime.yml file on the user's home directory ~/.gitwakatime.yml which will contain your api keys
19
17
 
20
- Creates a .gitwakatime.yml file on the user's home directory ~/.gitwakatime.yml which will contain your api keys
21
18
  $ gitwakatime init
22
19
 
20
+
21
+ ## Usage
23
22
  Process the current directory
24
23
 
25
24
  $ gitwakatime tally
26
25
 
26
+ Hard reset of the local cache database
27
+
28
+ $ gitwakatime reset
29
+
30
+
27
31
  ## Output
28
32
  Total Recorded time 21 hrs 59 mins 59 secs
29
33
  Total Commited Time 18 hrs 50 mins 53 secs
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.add_runtime_dependency 'chronic_duration', '>=0'
26
26
  spec.add_runtime_dependency 'colorize'
27
27
  spec.add_runtime_dependency 'activesupport'
28
+ spec.add_runtime_dependency 'sequel'
29
+ spec.add_runtime_dependency 'sqlite3'
28
30
  spec.add_development_dependency('bundler', ['>= 0'])
29
31
  spec.add_development_dependency 'rake'
30
32
  spec.add_development_dependency 'rspec'
@@ -1,5 +1,16 @@
1
+ require 'sequel'
2
+ if ENV['thor_env'] != 'test'
3
+ DB = Sequel.connect("sqlite://#{File.join(Dir.home, '.wakatime.sqlite')}")
4
+ else
5
+ # Use a in memory db to have a nice clean testing bed.
6
+ DB = Sequel.sqlite
7
+ end
8
+
9
+ DB.use_timestamp_timezones = false
10
+
1
11
  require 'gitwakatime/version'
2
- require 'gitwakatime/actions'
12
+ require 'gitwakatime/durations'
13
+ require 'gitwakatime/action'
3
14
  require 'gitwakatime/commit'
4
15
  require 'gitwakatime/mapper'
5
16
  require 'gitwakatime/query'
@@ -7,21 +18,63 @@ require 'gitwakatime/timer'
7
18
  require 'gitwakatime/log'
8
19
  require 'gitwakatime/commited_file'
9
20
  require 'gitwakatime/cli'
21
+
10
22
  # Silence is golden
11
23
  module GitWakaTime
12
24
  class Configuration
13
- attr_accessor :api_key, :log_level, :root, :project
25
+ attr_accessor :api_key, :log_level, :root, :project, :git
14
26
 
15
27
  def initialize
16
28
  self.api_key = nil
17
29
  self.log_level = :info
18
30
  end
19
31
 
32
+ def user_name
33
+ GitWakaTime.config.git.config('user.name')
34
+ end
35
+
20
36
  def load_config_yaml
21
37
  yaml = YAML.load_file(File.join(Dir.home, '.wakatime.yml'))
22
38
  self.api_key = yaml[:api_key]
23
39
  self.log_level = yaml[:log_level]
24
40
  end
41
+
42
+ def setup_local_db
43
+ DB.create_table? :commits do
44
+ primary_key :id
45
+ String :sha
46
+ String :parent_sha
47
+ String :project
48
+ integer :time_in_seconds, default: 0
49
+ datetime :date
50
+ text :message
51
+ String :author
52
+ end
53
+
54
+ DB.create_table? :commited_files do
55
+ primary_key :id
56
+ integer :commit_id
57
+ String :dependent_sha
58
+ DateTime :dependent_date
59
+ integer :time_in_seconds, default: 0
60
+ String :sha
61
+ String :name
62
+ String :project
63
+ index :dependent_sha
64
+ index :sha
65
+ end
66
+
67
+ DB.create_table? :actions do
68
+ primary_key :id
69
+ String :uuid
70
+ DateTime :time
71
+ integer :duration, default: 0
72
+ String :file
73
+ String :branch
74
+ String :project
75
+ index :uuid, unique: true
76
+ end
77
+ end
25
78
  end
26
79
 
27
80
  def self.config
@@ -0,0 +1,4 @@
1
+ module GitWakaTime
2
+ class Action < Sequel::Model
3
+ end
4
+ end
@@ -18,35 +18,51 @@ module GitWakaTime
18
18
  method_option :file, aliases: '-f', default: '.'
19
19
 
20
20
  def init
21
- api_key = ask('What is your wakatime api key? ( Get it here https://wakatime.com/settings):')
22
- say('Adding .wakatime.yml to home directory')
23
- create_file File.join(Dir.home, '.wakatime.yml') do
24
- YAML.dump(api_key: api_key, last_commit: nil, log_level: :info)
25
- end
21
+ unless File.exist?(File.join(Dir.home, '.wakatime.yml'))
22
+ api_key = ask('What is your wakatime api key? ( Get it here https://wakatime.com/settings):')
23
+ say('Adding .wakatime.yml to home directory')
24
+
25
+ create_file File.join(Dir.home, '.wakatime.yml') do
26
+ YAML.dump(api_key: api_key, last_commit: nil, log_level: :info)
27
+ end
28
+ end
29
+ reset
30
+ end
31
+
32
+ desc 'reset', 'Reset local sqlite db'
33
+ def reset
34
+ DB.disconnect
35
+
36
+ db_path = File.expand_path(File.join(Dir.home, '.wakatime.sqlite'))
37
+ FileUtils.rm_r(db_path) if File.exist?(db_path)
38
+ DB.connect("sqlite://#{db_path}")
39
+ GitWakaTime.config.setup_local_db
26
40
  end
27
41
 
28
42
  desc 'tally', 'Produce time spend for each commit and file in each commit'
29
43
  method_option :file, aliases: '-f', default: '.'
30
44
  method_option :start_on, aliases: '-s', default: nil
31
45
  def tally
46
+ GitWakaTime.config.setup_local_db
32
47
  path, GitWakaTime.config.root = File.expand_path(options.file)
33
48
  date = Date.parse(options.start_on) if options.start_on
34
49
  date = 1.month.ago.beginning_of_month unless options.start_on
35
50
  GitWakaTime.config.load_config_yaml
36
- @git_map = Mapper.new(path, start_at: date)
37
- @actions = Query.new(@git_map.commits, File.basename(path)).get
51
+ GitWakaTime.config.git = Git.open(path)
52
+ @git_map = Mapper.new(start_at: date)
53
+ @actions = Query.new(Commit.all, File.basename(path)).get
38
54
 
39
- @timer = Timer.new(@git_map.commits, @actions, File.basename(path)).process
55
+ @timer = Timer.new(Commit.all, @actions, File.basename(path)).process
40
56
 
41
57
  @timer.each do |date, commits|
42
58
  Log.new format('%-40s %-40s'.blue,
43
59
  date,
44
- "Total #{ChronicDuration.output commits.map(&:time_in_seconds).reduce(&:+)}"
60
+ "Total #{ChronicDuration.output commits.map(&:time_in_seconds).compact.reduce(&:+).to_i}"
45
61
  )
46
62
  commits.each do |commit|
47
63
  # Log.new commit.message
48
64
  Log.new commit.to_s
49
- commit.files.each { |file| Log.new file.to_s }
65
+ commit.commited_files.each { |file| Log.new file.to_s }
50
66
  end
51
67
  end
52
68
  end
@@ -1,28 +1,15 @@
1
1
  module GitWakaTime
2
- class Commit
3
- attr_accessor :raw_commit, :sha, :date, :message, :files, :time_in_seconds, :git, :author
4
-
5
- def initialize(git, commit, load_files = true)
6
- @raw_commit = commit
7
- @sha = @raw_commit.sha
8
- @date = @raw_commit.date
9
- @message = @raw_commit.message
10
- @author = @raw_commit.author
11
- @time_in_seconds = 0
12
- @git = git
13
- @load_files = load_files
14
- @files = get_files if load_files
15
- end
16
-
17
- def inspect
18
- [sha[0..8], time_in_seconds]
2
+ class Commit < Sequel::Model
3
+ one_to_many :commited_files
4
+ def after_create
5
+ get_files
19
6
  end
20
7
 
21
8
  def to_s
22
9
  format(' %-8s %8s %-30s %-80s'.green,
23
10
  sha[0..8],
24
11
  date,
25
- ChronicDuration.output(time_in_seconds),
12
+ ChronicDuration.output(time_in_seconds.to_i),
26
13
  message
27
14
  )
28
15
  end
@@ -31,13 +18,23 @@ module GitWakaTime
31
18
  @files.sort { |f| f.commit.date }.first
32
19
  end
33
20
 
21
+ def time_in_seconds
22
+ commited_files.collect {|f| f.time_in_seconds}.inject(:+)
23
+ end
24
+
34
25
  private
35
26
 
36
27
  def get_files
28
+ @raw_commit = GitWakaTime.config.git.gcommit(sha)
37
29
  # TODO: Assume gap time to lookup time prior to first commit.
38
- return [] unless @raw_commit.parent
39
- @raw_commit.diff_parent.stats[:files].keys.map do |file|
40
- CommitedFile.new(git: @git, commit: @raw_commit, name: file, dependent: false)
30
+ if @raw_commit.parent
31
+ update(parent_sha: @raw_commit.parent.sha)
32
+
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
37
+ end
41
38
  end
42
39
  end
43
40
  end
@@ -1,22 +1,18 @@
1
1
  module GitWakaTime
2
- class CommitedFile
3
- attr_reader :name, :dependent_commit, :git
4
- attr_accessor :time_in_seconds
5
- def initialize(args)
6
- @git = args[:git]
7
- @name = args[:name]
8
- @commit = args[:commit]
9
- @time_in_seconds = 0
10
-
11
- @dependent_commit = find_dependent_commit(name)
2
+ class CommitedFile < Sequel::Model
3
+ 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
+
7
+ def before_create
8
+ find_dependent_commit(name)
12
9
  end
13
10
 
14
11
  def to_s
15
- format(' %-20s %-40s %-100s '.blue,
16
- (dependent_commit.sha[0..8] if @dependent_commit),
17
- ChronicDuration.output(@time_in_seconds.to_f),
12
+ format(' %-20s %-40s %-100s '.blue,
13
+ (dependent_sha[0..8] if dependent_sha),
14
+ ChronicDuration.output(time_in_seconds.to_f),
18
15
  name
19
-
20
16
  )
21
17
  end
22
18
 
@@ -24,26 +20,43 @@ module GitWakaTime
24
20
 
25
21
  def find_dependent_commit(name)
26
22
  i = 1
27
- dependent = nil
28
- commit = 1
29
23
 
24
+ # Call git log for path, loop through till we find a valid commit or run
25
+ # out of commits to check
26
+ commits = load_dependent_commits(name)
30
27
  begin
31
- commit = load_dependent_commit(name, i: i)
32
- dependent = Commit.new(@git, commit, false) if allowed_commit(commit)
28
+ commit = commits[i]
29
+
30
+ if commit && allowed_commit(commit)
31
+
32
+ self.dependent_date = commit.date
33
+ self.dependent_sha = commit.sha
34
+
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
46
+
33
47
  i += 1
34
- end until !dependent.nil? || commit.nil?
35
- dependent
48
+ end until !dependent_sha.nil? || commit.nil?
36
49
  end
37
50
 
38
51
  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')
52
+ return false if commit.sha == sha
53
+ return false if commit.author.name != GitWakaTime.config.user_name
54
+ return false if commit.parents.size > 1
42
55
  true
43
56
  end
44
57
 
45
- def load_dependent_commit(name, i: 1)
46
- @git.log.object(@commit.sha).path(name)[i]
58
+ def load_dependent_commits(name)
59
+ GitWakaTime.config.git.log.object(sha).path(name)
47
60
  rescue Git::GitExecuteError
48
61
  puts error
49
62
  nil
@@ -0,0 +1,87 @@
1
+ module GitWakaTime
2
+ # Extract Duration Data from Actions for the WAKATIME API
3
+ class Durations
4
+ attr_accessor :actions
5
+ def initialize(args)
6
+ return @actions = args[:actions] if args[:actions]
7
+ fail if args[:project].nil?
8
+ @project = args[:project]
9
+ @args = args
10
+ @session = Wakatime::Session.new(api_key: GitWakaTime.config.api_key)
11
+ @client = Wakatime::Client.new(@session)
12
+ @actions = []
13
+ end
14
+
15
+ def load_actions
16
+ unless cached?(@args)
17
+
18
+ Log.new "querying WakaTime actions for #{@project}"
19
+ time = Benchmark.realtime do
20
+ @actions = @client.actions(@args)
21
+
22
+ # remove returned actions that do not have the project we want
23
+ @actions = @actions.keep_if do |a|
24
+ a['project'] == @project
25
+ end
26
+ end
27
+
28
+ Log.new "API took #{time}s"
29
+ persist_actions_localy(@actions)
30
+ end
31
+ true
32
+ end
33
+
34
+ def persist_actions_localy(actions)
35
+ actions.each do |action|
36
+
37
+ Action.find_or_create(uuid: action['id']) do |c|
38
+ action['uuid'] = action['id']
39
+ action['time'] = Time.at(action['time'])
40
+ action.delete('id')
41
+ c.update(action)
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ def cached?(params)
48
+ # Check to see if this date range might be stale?
49
+ max_local_timetamp = Action.max(:time)
50
+ max_local_timetamp = (Time.parse(max_local_timetamp) + 3.day).to_date if max_local_timetamp
51
+ !(params[:start].to_date..params[:end].to_date).include?(max_local_timetamp) if max_local_timetamp
52
+ end
53
+
54
+ def actions_to_durations(_project = nil, timeout = 15)
55
+ durations = []
56
+ current = nil
57
+
58
+ @actions.each do | action |
59
+ # the first action just sets state and does nothing
60
+ unless current.nil?
61
+
62
+ # get duration since last action
63
+ duration = action.time.round - current.time.round
64
+
65
+ duration = 0.0 if duration < 0
66
+
67
+ # duration not logged if greater than the timeout
68
+ if duration < timeout * 60
69
+
70
+ # add duration to current action
71
+ current.duration = duration
72
+
73
+ # save to local db
74
+ current.save
75
+
76
+ # log current action as a duration
77
+ durations << current
78
+ end
79
+ end
80
+ # set state (re-start the clock)
81
+ current = action
82
+
83
+ end
84
+ durations
85
+ end
86
+ end
87
+ end
@@ -7,6 +7,7 @@ module GitWakaTime
7
7
  end
8
8
 
9
9
  def print_message
10
+ return if ENV['waka_log'] == 'false'
10
11
  if @color.nil?
11
12
  puts @msg
12
13
  else
@@ -2,23 +2,29 @@ module GitWakaTime
2
2
  # Th
3
3
  class Mapper
4
4
  attr_accessor :commits, :git
5
- def initialize(path, commits: 500, start_at: Date.today)
5
+ def initialize(commits: 500, start_at: Date.today)
6
6
  Log.new 'Mapping commits for dependent commits'
7
7
  time = Benchmark.realtime do
8
- @git = if File.directory?(File.join(path, '.git'))
9
- Git.open(path)
10
- else
11
- Git.bare(path)
12
- end
8
+ g = GitWakaTime.config.git
9
+ project = File.basename(g.dir.path)
10
+ logs = g.log(commits).since(start_at).until(Date.today)
13
11
 
14
- logs = @git.log(commits).since(start_at).until(Date.today)
12
+ @commits = logs.map do |git_c|
15
13
 
16
- @commits = logs.map do |git_commit|
17
- next if git_commit.author.name != @git.config('user.name')
18
- Commit.new(@git, git_commit)
14
+ next if git_c.author.name != GitWakaTime.config.user_name
15
+ Commit.find_or_create(
16
+ sha: git_c.sha,
17
+ project: project
18
+ ) do |c|
19
+ c.update(
20
+ author: git_c.author.name,
21
+ message: git_c.message,
22
+ date: git_c.date
23
+ )
24
+ end
19
25
  end.compact
20
26
  end
21
- Log.new "Map Completed took #{time}s"
27
+ Log.new "Map Completed took #{time}s with #{Commit.count}"
22
28
  end
23
29
  end
24
30
  end
@@ -9,39 +9,44 @@ module GitWakaTime
9
9
  @commits = commits
10
10
  @api_limit = 15
11
11
  @project = project
12
- @actions = []
13
12
  @requests = time_params
14
13
  end
15
14
 
16
15
  def get
17
16
  @requests.each do |params|
18
17
  Log.new "Requesting actions #{params[:start].to_date} to #{params[:end].to_date}".red
19
- @actions = @actions.concat Actions.new(params).actions
18
+ Durations.new(params).load_actions
20
19
  end
21
20
 
22
- Actions.new(actions: @actions.uniq(&:id)).actions_to_durations
21
+ Durations.new(actions: actions).actions_to_durations
22
+ end
23
+
24
+ def actions
25
+ Action.where('time >= ? and time <= ? ', @start_at, @end_at).where(project: @project)
23
26
  end
24
27
 
25
28
  def time_params
26
29
  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
30
+ d_commits = CommitedFile.select(:dependent_date).all.map { |f| f.values[:dependent_date] }.compact
31
+ timestamps = (commits + d_commits.flatten).uniq.sort
32
+ @start_at = timestamps.first
33
+ @end_at = timestamps.last
34
+ # Always have a date range great than 1 as the num request will be 0/1 otherwise
35
+ num_requests = ((timestamps.last.to_date + 1) - timestamps.first.to_date) / @api_limit
32
36
  i = 0
37
+
33
38
  request_params = num_requests.to_f.ceil.times.map do
34
39
 
35
40
  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
41
+ start: (timestamps.first.to_date + (i * @api_limit)).to_time.beginning_of_day,
42
+ end: (timestamps.first.to_date + ((i + 1) * @api_limit)).to_time.end_of_day,
43
+ project: @project,
44
+ show: 'file,branch,project,time,id'
39
45
  }
40
46
  i += 1
41
47
  params
42
48
 
43
49
  end
44
-
45
50
  request_params
46
51
  end
47
52
  end
@@ -18,22 +18,25 @@ module GitWakaTime
18
18
 
19
19
  def total_commited
20
20
  total_commited = ChronicDuration.output(@commits_with_duration
21
- .map(&:time_in_seconds)
21
+ .map(&:time_in_seconds).compact
22
22
  .reduce(:+).to_f)
23
- Log.new "Total Commited Time #{total_commited} ".red
23
+ Log.new "Total Committed Time #{total_commited} ".red
24
24
  end
25
25
 
26
26
  def process
27
27
  @commits_with_duration = @commits.each do |commit|
28
28
 
29
- if !commit.files.empty?
30
- commit.files.each_with_index do |file, i|
29
+ if commit.commited_files.count > 0 || commit.parent_sha
30
+ commit.commited_files.each_with_index do |file, _i|
31
31
  time = sum_actions relevant_actions(commit, file)
32
- commit.files[i].time_in_seconds += time
33
- commit.time_in_seconds += time
32
+ file.time_in_seconds = time
33
+ commit.time_in_seconds = time
34
+
35
+ file.save
34
36
  end
37
+ commit.save
35
38
  else
36
- # commit.time_in_seconds = sum_actions(actions_before(commit.date))
39
+ commit.time_in_seconds = sum_actions(actions_before(@actions_with_durations, commit.date))
37
40
  end
38
41
  end.compact
39
42
  total
@@ -45,38 +48,38 @@ module GitWakaTime
45
48
  private
46
49
 
47
50
  def relevant_actions(commit, file)
48
- # The timestamps should be before the expected commit
49
- actions = actions_before(commit.date)
50
-
51
51
  # The file should be the same file as we expect
52
52
  # TODO: Might need to pass root_path down
53
- actions = actions.select do |action|
54
- action['file'].include?(file.name) # This is okay as other projects have already been purged
53
+ actions = @actions_with_durations.select do |action|
54
+ action[:file].include?(File.join(File.basename(GitWakaTime.config.git.dir.path), file.name))
55
55
  end
56
56
 
57
+ # The timestamps should be before the expected commit
58
+ actions = actions_before(actions, commit.date)
59
+
57
60
  # If this file had an earlier commit ensure the actions timestamp
58
61
  # is after that commit
59
- if file.dependent_commit
60
- actions = actions_after(actions, file.dependent_commit.date)
62
+ if file.dependent_date
63
+ actions = actions_after(actions, file.dependent_date)
61
64
  end
62
65
  actions
63
66
  end
64
67
 
65
- def actions_before(date)
66
- @actions_with_durations.select do |action|
67
- Time.at(action['time']) <= date
68
+ def actions_before(actions, date)
69
+ actions.select do |action|
70
+ Time.at(action[:time]) <= date
68
71
  end
69
72
  end
70
73
 
71
74
  def actions_after(actions, date)
72
75
  actions.select do |action|
73
- Time.at(action['time']) >= date
76
+ Time.at(action[:time]) >= date
74
77
  end
75
78
  end
76
79
 
77
80
  def sum_actions(actions)
78
- actions.map { |action| action['duration'] }
79
- .reduce(:+).to_f
81
+ actions.map { |action| action[:duration] }
82
+ .reduce(:+).to_i
80
83
  end
81
84
  end
82
85
  end
@@ -1,4 +1,4 @@
1
1
  # Version Number Definition
2
2
  module GitWakaTime
3
- VERSION = '0.0.3'
3
+ VERSION = '0.1.0'
4
4
  end
File without changes
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+ # * commit a4c26aeb79acb1f012201fe96e4d68e8d17c75d9 (HEAD, origin/master, origin/HEAD, master)
3
+ # | Author: rpo <rother@gmail.com>
4
+ # | Date: Sat Jan 31 15:49:07 2015 -0500
5
+ # |
6
+ # | I was edited online using git hub's editor
7
+ # |
8
+ # * commit 570f1df0505ed828656eeaf9411ddd6a6068b095
9
+ # | Author: Russell Osborne <rother@gmail.com>
10
+ # | Date: Fri Jan 30 00:19:00 2015 -0500
11
+ # |
12
+ # | And one more
13
+ # |
14
+ # * commit dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d
15
+ # | Author: Russell Osborne <rother@gmail.com>
16
+ # | Date: Fri Jan 30 00:01:54 2015 -0500
17
+ # |
18
+ # | a final commit on master
19
+ # |
20
+ # * commit 57b0d5cdb6da2b2b9ac7e9847716b0c54466d1c6
21
+ # |\ Merge: e493d6f d642b3c
22
+ # | | Author: Russell Osborne <rother@gmail.com>
23
+ # | | Date: Thu Jan 29 22:27:26 2015 -0500
24
+ # | |
25
+ # | | Merge branch 'dev'
26
+ # | |
27
+ # | * commit d642b3c04c3025655a9c33e32b9d530696dcf7cc
28
+ # | | Author: Russell Osborne <rother@gmail.com>
29
+ # | | Date: Thu Jan 29 22:26:05 2015 -0500
30
+ # | |
31
+ # | | another commit on dev.
32
+ # | |
33
+ # * | commit e493d6f2ab2a702fa7f9c168b852a3b44c524f08
34
+ # |/ Author: Russell Osborne <rother@gmail.com>
35
+ # | Date: Thu Jan 29 22:26:20 2015 -0500 or 1422570380
36
+ # |
37
+ # | conflicting commit on master.
38
+ # |
39
+ # * commit 4c1ea35f9a811a0ef79da15ec85f25fce4c446ba
40
+ # | Author: Russell Osborne <rother@gmail.com>
41
+ # | Date: Thu Jan 29 22:25:08 2015 -0500 or 1422570308
42
+ # |
43
+ # | commit on dev branch
44
+ # |
45
+ # * commit 2254dd56976b5f32a2289438842e42a35a18ff86
46
+ # | Author: Russell Osborne <rother@gmail.com>
47
+ # | Date: Thu Jan 29 21:49:31 2015 -0500
48
+ # |
49
+ # | testing
50
+ # |
51
+ # * commit 052ff8c0e8c7cd39880d1536f4e27cc554e698f6
52
+ # Author: Russell Osborne <rother@gmail.com>
53
+ # Date: Thu Jan 29 21:49:12 2015 -0500
54
+
55
+ # created readme
56
+ describe 'description' do
57
+ let (:git) { Git.open(@wdir) }
58
+
59
+ before do
60
+ GitWakaTime::Commit.dataset.destroy
61
+ GitWakaTime::Commit.dataset.destroy
62
+ end
63
+
64
+ it 'can be created ' do
65
+ GitWakaTime.config.git = git
66
+
67
+ 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)
73
+ )
74
+
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')
77
+
78
+ 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
+ )
85
+
86
+ expect(second_commit.commited_files.first.dependent_sha).to eql('4c1ea35f9a811a0ef79da15ec85f25fce4c446ba')
87
+ 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)
91
+ end
92
+
93
+ end
@@ -1,7 +1,7 @@
1
1
  autorefresh=1
2
2
  savedIncoming=0
3
- lastUsedView=1
3
+ lastUsedView=0
4
4
  savedOutgoing=0
5
- lastCheckedRemotes=2015-01-31 22:27:02 +0000
5
+ lastCheckedRemotes=2015-02-03 06:54:37 +0000
6
6
  disablerecursiveoperations=0
7
7
  autorefreshremotes=1
@@ -1,20 +1,24 @@
1
1
  require 'spec_helper'
2
- require 'gitwakatime'
3
- require 'gitwakatime/mapper'
4
2
 
5
3
  describe 'description' do
4
+ let (:git) { Git.open(@wdir) }
5
+ before(:each) do
6
+ GitWakaTime.config.git = git
7
+ GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 28))
8
+ end
9
+
6
10
  it 'can be run on dummy' do
7
- expect(GitWakaTime::Mapper.new(@wdir).commits.size).to eq 8 # 9ths is lonely
11
+ expect(GitWakaTime::Commit.all.size).to eq 8 # 9ths is lonely
8
12
  end
9
13
  it 'can be run on dummy' do
10
- expect(GitWakaTime::Mapper.new(@wdir).commits.last.raw_commit.message).to eq 'created readme'
14
+ expect(GitWakaTime::Commit.order(:date).first.message).to eq 'created readme'
11
15
  end
12
16
 
13
17
  it 'maps files dependent commits' do
14
- expect(GitWakaTime::Mapper.new(@wdir).commits.first.files.first.dependent_commit.sha).to eq 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d'
18
+ expect(GitWakaTime::Commit.all.first.commited_files.first.dependent_sha).to eq 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d'
15
19
  end
16
20
 
17
21
  it 'maps files dependent commits' do
18
- expect(GitWakaTime::Mapper.new(@wdir).commits.select { |c| c.sha == 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d' }.first.files.first.dependent_commit.sha).to eq '2254dd56976b5f32a2289438842e42a35a18ff86'
22
+ expect(GitWakaTime::Commit.all.select { |c| c.sha == 'dcd748bd06b8a0f239d779bee4f1eaf1f4aa500d' }.first.commited_files.first.dependent_sha).to eq '2254dd56976b5f32a2289438842e42a35a18ff86'
19
23
  end
20
24
  end
@@ -1,8 +1,11 @@
1
1
  require 'spec_helper'
2
- require 'gitwakatime'
3
2
 
4
3
  describe 'description' do
5
- let (:map) { GitWakaTime::Mapper.new(@wdir) }
4
+
5
+ before(:each) do
6
+ GitWakaTime.config.git = Git.open(@wdir)
7
+ GitWakaTime::Mapper.new(start_at: Date.new(2015, 1, 24))
8
+ end
6
9
 
7
10
  before do
8
11
  stub_request(:get, 'https://wakatime.com/api/v1/actions')
@@ -12,11 +15,18 @@ describe 'description' do
12
15
 
13
16
  it 'can be run on dummy' do
14
17
 
15
- timer = GitWakaTime::Query.new(map.commits, File.basename(@wdir)).get
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'
24
+ end
25
+ it 'produces valid search for api' do
26
+ actions = GitWakaTime::Query.new(GitWakaTime::Commit.all, File.basename(@wdir)).time_params
16
27
 
17
- expect(timer.size).to eq 6 # 9ths is lonely
18
- expect(timer).to be_a Array
19
- expect(timer.last).to be_a Wakatime::Models::Action
20
- expect(timer.last.branch).to eq 'master'
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)
21
31
  end
22
32
  end
@@ -4,12 +4,29 @@
4
4
  # loaded once.
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ ENV['thor_env'] = 'test'
8
+ ENV['waka_log'] = 'false'
9
+
10
+ require 'gitwakatime'
11
+
7
12
  RSpec.configure do |config|
8
13
  config.run_all_when_everything_filtered = true
9
14
  config.filter_run :focus
10
15
  config.order = 'random'
11
16
  config.before(:all) do
12
17
  @wdir = set_file_paths
18
+ GitWakaTime.config.setup_local_db
19
+ GitWakaTime::Commit.new.columns
20
+ GitWakaTime::CommitedFile.new.columns
21
+ GitWakaTime::Action.new.columns
22
+ end
23
+
24
+ config.before(:each) do
25
+ GitWakaTime::Commit.truncate
26
+ GitWakaTime::CommitedFile.truncate
27
+ GitWakaTime::Action.truncate
28
+
29
+ expect(GitWakaTime.config).to receive('user_name').and_return('Russell Osborne').at_least(:once)
13
30
  end
14
31
 
15
32
  config.after(:all) do
@@ -37,6 +54,5 @@ def create_temp_repo(clone_path)
37
54
  Dir.chdir(tmp_path) do
38
55
  FileUtils.mv('dot_git', '.git')
39
56
  end
40
- puts tmp_path
41
57
  tmp_path
42
58
  end
@@ -1,8 +1,7 @@
1
1
  require 'spec_helper'
2
- require 'gitwakatime'
3
2
 
4
3
  describe 'description' do
5
- let (:map) { GitWakaTime::Mapper.new(@wdir) }
4
+ let (:git) { Git.open(@wdir) }
6
5
 
7
6
  before do
8
7
  stub_request(:get, 'https://wakatime.com/api/v1/actions')
@@ -11,8 +10,14 @@ describe 'description' do
11
10
  end
12
11
 
13
12
  it 'can be run on dummy' do
14
- actions = GitWakaTime::Query.new(map.commits, File.basename(@wdir)).get
15
- timer = GitWakaTime::Timer.new(map.commits, actions, File.basename(@wdir)).process
16
- expect(timer.size).to eq 2
13
+ GitWakaTime.config.git = git
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
17
+
18
+ # # UTC breaks actions of 1 day
19
+ # expect(timer.size).to eq 1
20
+ # With 8 relevant commits
21
+ expect(timer[timer.keys.first].size).to eq 8
17
22
  end
18
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitwakatime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Russell Osborne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-02 00:00:00.000000000 Z
11
+ date: 2015-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -108,6 +108,34 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sequel
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: sqlite3
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
111
139
  - !ruby/object:Gem::Dependency
112
140
  name: bundler
113
141
  requirement: !ruby/object:Gem::Requirement
@@ -183,15 +211,18 @@ files:
183
211
  - bin/gitwakatime
184
212
  - gitwakatime.gemspec
185
213
  - lib/gitwakatime.rb
186
- - lib/gitwakatime/actions.rb
214
+ - lib/gitwakatime/action.rb
187
215
  - lib/gitwakatime/cli.rb
188
216
  - lib/gitwakatime/commit.rb
189
217
  - lib/gitwakatime/commited_file.rb
218
+ - lib/gitwakatime/durations.rb
190
219
  - lib/gitwakatime/log.rb
191
220
  - lib/gitwakatime/mapper.rb
192
221
  - lib/gitwakatime/query.rb
193
222
  - lib/gitwakatime/timer.rb
194
223
  - lib/gitwakatime/version.rb
224
+ - spec/commit_spec.rb
225
+ - spec/commited_file_spec.rb
195
226
  - spec/dummy/dot_git/FETCH_HEAD
196
227
  - spec/dummy/dot_git/HEAD
197
228
  - spec/dummy/dot_git/config
@@ -271,6 +302,8 @@ specification_version: 4
271
302
  summary: A Tool that will compile git data with wakatime data to establish time per
272
303
  commit
273
304
  test_files:
305
+ - spec/commit_spec.rb
306
+ - spec/commited_file_spec.rb
274
307
  - spec/dummy/dot_git/FETCH_HEAD
275
308
  - spec/dummy/dot_git/HEAD
276
309
  - spec/dummy/dot_git/config
@@ -1,59 +0,0 @@
1
- module GitWakaTime
2
- # Extract Duration Data from Actions for the WAKATIME API
3
- class Actions
4
- attr_accessor :actions
5
- def initialize(args)
6
- return @actions = args[:actions] if args[:actions]
7
- fail if args[:project].nil?
8
- @project = args[:project]
9
- @args = args
10
- @session = Wakatime::Session.new(api_key: GitWakaTime.config.api_key)
11
- @client = Wakatime::Client.new(@session)
12
- load_actions
13
- end
14
-
15
- def load_actions
16
- Log.new "querying WakaTime actions for #{@project}"
17
- time = Benchmark.realtime do
18
- @actions = @client.actions(@args)
19
- # remove returned actions that do not have the project we want
20
- @actions = @actions.keep_if do |a|
21
- a['project'] == @project
22
- end
23
-
24
- end
25
- Log.new "API took #{time}s"
26
- @actions
27
- end
28
-
29
- def actions_to_durations(_project = nil, timeout = 15)
30
- durations = []
31
- current = []
32
- @actions.each do | action |
33
- # the first action just sets state and does nothing
34
- unless current.empty?
35
-
36
- # get duration since last action
37
- duration = action.time.round - current['time'].round
38
-
39
- duration = 0.0 if duration < 0
40
-
41
- # duration not logged if greater than the timeout
42
- if duration < timeout * 60
43
-
44
- # add duration to current action
45
- current['duration'] = duration
46
-
47
- # log current action as a duration
48
- durations << current
49
- end
50
- end
51
- # set state (re-start the clock)
52
- current = action
53
- current.delete('id')
54
-
55
- end
56
- durations
57
- end
58
- end
59
- end