gitwakatime 0.0.3 → 0.1.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: 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