gitwakatime 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 86e6080229ad2143f0874a4912e4ceb6df885306
4
+ data.tar.gz: 6f6aa24acd61e4f0b87217d674f8dc60a5652113
5
+ SHA512:
6
+ metadata.gz: d50a015052568968ff6dba0efba08e131f9d5e781555e16c136b20bc6775a21deb6115c7be66b7b0bd157c38cc9bfc19ce8e30cf009ae5565b8d28e90c2f059d
7
+ data.tar.gz: cef4abacec5ab099db09005c92a237d853cd5951261e65a9d8ae102d8be6dde1f7ef806327a091058d7698d7773eba19fa9a5e82f8fa249d9581bc0bd4daded6
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gitwakatime.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Russell Osborne
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # GitWakaTime
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'gitwakatime'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install gitwakatime
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/gitwakatime/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'thor'
3
+
4
+ require_relative '../lib/gitwakatime'
5
+
6
+ GitWakaTime::Cli.start
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gitwakatime/version'
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 = %q{A Tool that will compile git data with wakatime data to establish time per commit}
12
+ spec.description = %q{A Tool that will compile git data with wakatime data to establish time per commit }
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
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"]
20
+
21
+ spec.add_runtime_dependency "git", ">= 0"
22
+ spec.add_runtime_dependency "wakatime", ">= 0"
23
+ spec.add_runtime_dependency "logger", ">= 0"
24
+ spec.add_runtime_dependency "thor", ">= 0"
25
+ spec.add_runtime_dependency "chronic_duration", ">=0"
26
+ spec.add_runtime_dependency "colorize"
27
+ spec.add_development_dependency("bundler", [">= 0"])
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "rspec"
30
+ end
@@ -0,0 +1,33 @@
1
+ require 'gitwakatime/version'
2
+ require 'gitwakatime/actions'
3
+ require 'gitwakatime/commit'
4
+ require 'gitwakatime/mapper'
5
+ require 'gitwakatime/timer'
6
+ require 'gitwakatime/log'
7
+ require 'gitwakatime/commited_file'
8
+ require 'gitwakatime/cli'
9
+ # Silence is golden
10
+ module GitWakaTime
11
+ class Configuration
12
+ attr_accessor :api_key, :log_level, :root, :project
13
+
14
+ def initialize
15
+ self.api_key = nil
16
+ self.log_level = :info
17
+ end
18
+
19
+ def load_config_yaml
20
+ yaml = YAML.load_file(File.join(Dir.home, '.wakatime.yml'))
21
+ self.api_key = yaml[:api_key]
22
+ self.log_level = yaml[:log_level]
23
+ end
24
+ end
25
+
26
+ def self.config
27
+ @configuration ||= Configuration.new
28
+ end
29
+
30
+ def self.configure
31
+ yield(configuration) if block_given?
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ module GitWakaTime
2
+ # Extract Duration Data from Actions for the WAKATIME API
3
+ class Actions
4
+ def initialize(args)
5
+ fail if args[:project].nil?
6
+ @project = args[:project]
7
+ @args = args
8
+ @session = Wakatime::Session.new(api_key: GitWakaTime.config.api_key)
9
+ @client = Wakatime::Client.new(@session)
10
+ load_actions
11
+ end
12
+
13
+ def load_actions
14
+ Log.new "querying WakaTime actions for #{@project}"
15
+ time = Benchmark.realtime do
16
+ @actions = @client.actions(@args)
17
+ # remove returned actions that do not have the project we want
18
+ @actions.keep_if { |a| a['project'] == @project }
19
+ end
20
+ Log.new "API took #{time}s"
21
+ end
22
+
23
+ def actions_to_durations(project = nil, timeout = 15)
24
+ durations = []
25
+ current = []
26
+ @actions.each do | action |
27
+ # the first action just sets state and does nothing
28
+ unless current.empty?
29
+
30
+ # get duration since last action
31
+ duration = action.time.round - current['time'].round
32
+
33
+ duration = 0.0 if duration < 0
34
+
35
+ # duration not logged if greater than the timeout
36
+ if duration < timeout * 60
37
+
38
+ # add duration to current action
39
+ current['duration'] = duration
40
+
41
+ # log current action as a duration
42
+ durations << current
43
+ end
44
+ end
45
+ # set state (re-start the clock)
46
+ current = action
47
+ current.delete('id')
48
+
49
+ end
50
+ durations
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,38 @@
1
+ require 'git'
2
+ require 'logger'
3
+ require 'wakatime'
4
+ require 'chronic_duration'
5
+ require 'yaml'
6
+ require 'thor'
7
+ module GitWakaTime
8
+ # Provides two CLI actions init and tally
9
+ class Cli < Thor
10
+ include Thor::Actions
11
+ desc 'init', 'Setups up Project for using the wakatime API
12
+ it will also add to your git ignore file'
13
+ method_option :file, aliases: '-f', default: '.'
14
+
15
+ def init
16
+ say('Adding .wakatime.yml to home directory')
17
+
18
+ create_file File.join(Dir.home, '.wakatime.yml') do
19
+ YAML.dump(api_key: 'Your API Key', last_commit: nil, log_level: :info)
20
+ end
21
+ end
22
+
23
+ desc 'tally', 'Produce time spend for each commit and file in each commit'
24
+ method_option :file, aliases: '-f', default: '.'
25
+ def tally
26
+ path , GitWakaTime.config.root = File.expand_path(options.file)
27
+ GitWakaTime.config.load_config_yaml
28
+ @mapper = Mapper.new(path)
29
+
30
+ @timer = Timer.new(@mapper.commits, File.basename(path))
31
+ @commits_with_duration = @timer.process
32
+ @commits_with_duration.each do |commit|
33
+ Log.new commit.to_s
34
+ commit.files.each { |file| Log.new file.to_s }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ module GitWakaTime
2
+ class Commit
3
+ attr_accessor :sha, :date, :message, :files, :time_in_seconds
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
+ @time_in_seconds = 0
11
+ @git = git
12
+ @load_files = load_files
13
+ @files = load if load_files
14
+ end
15
+
16
+ def to_s
17
+ format('%-8s %8s %-30s %-80s'.green,
18
+ sha[0..8],
19
+ date,
20
+ ChronicDuration.output(time_in_seconds),
21
+ message
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def load
28
+ return [] unless @raw_commit.parent
29
+ @raw_commit.diff_parent.stats[:files].keys.map do |file|
30
+ CommitedFile.new(git: @git , parent_commit: @raw_commit, name: file, dependent: false)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
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
+ @parent_commit = args[:parent_commit]
9
+ @time_in_seconds = 0
10
+ @find_dependent = args[:dependent] || true
11
+
12
+ write_dependent_commit(name) if @find_dependent
13
+ end
14
+
15
+ def to_s
16
+ format(' %-40s %-40s %-20s'.blue ,
17
+ ChronicDuration.output(time_in_seconds.to_f),
18
+ name,
19
+ (dependent_commit.sha[0..8] if @dependent_commit)
20
+ )
21
+ end
22
+
23
+ private
24
+
25
+ def write_dependent_commit(name)
26
+ commit = load_dependent_commit(name)
27
+ @dependent_commit = Commit.new(@git, commit , false) if commit
28
+ end
29
+
30
+ def load_dependent_commit(name)
31
+ @git.log(100).until(@parent_commit.date.to_s).object(name)[1]
32
+ rescue Git::GitExecuteError
33
+ nil
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ module GitWakaTime
2
+ class Log
3
+ def initialize(msg, color = nil)
4
+ @color = color
5
+ @msg = msg
6
+ print_message
7
+ end
8
+
9
+ def print_message
10
+ if @color.nil?
11
+ puts @msg
12
+ else
13
+ puts @msg.send(@color)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module GitWakaTime
2
+ # Th
3
+ class Mapper
4
+ attr_accessor :commits, :git
5
+ def initialize(path, commits = 100)
6
+ Log.new 'Mapping commits for dependent commits'
7
+ time = Benchmark.realtime do
8
+ @git = Git.open(path)
9
+ # TODO: Expose since timestamp as a CLI option
10
+ # TODO: Expose number of commits as a CLI option
11
+ first_of_month = Date.new(Date.today.year, Date.today.month, 1)
12
+
13
+ logs = @git.log(commits).since(first_of_month)
14
+
15
+ @commits = logs.map do |git_commit|
16
+ Commit.new(@git, git_commit)
17
+ end
18
+ end
19
+ Log.new "Map Completed took #{time}s"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,88 @@
1
+ require 'benchmark'
2
+ require 'colorize'
3
+ require 'pry'
4
+ module GitWakaTime
5
+ # Integrates the nested hash from mapper with actions api
6
+ class Timer
7
+ def initialize(commits, project, path = nil)
8
+ @commits = commits
9
+ params = time_params
10
+ params[:project] = project
11
+ @actions = Actions.new(params)
12
+ @actions_with_durations = @actions.actions_to_durations
13
+ end
14
+
15
+ def time_params
16
+ commits = @commits.map(&:date)
17
+ d_commits = @commits.map do |c|
18
+ c.files.map(&:dependent_commit).compact.map(&:date)
19
+ end
20
+ timestamps = (commits + d_commits.flatten).uniq
21
+ api_limit = Time.now - 60 * 60 * 24 * 60
22
+ min = api_limit > timestamps.min ? api_limit : timestamps.min
23
+ { start: min, end: timestamps.max }
24
+ end
25
+
26
+ def total
27
+ @total_time = sum_actions @actions_with_durations
28
+ Log.new "Total Recorded time #{ChronicDuration.output @total_time}", :red
29
+ end
30
+
31
+ def total_commited
32
+ @total_commited = ChronicDuration.output(@commits_with_duration
33
+ .map { |c| c.time_in_seconds }
34
+ .reduce(:+).to_f)
35
+ Log.new "Total Commited Time #{@total_commited} ".red
36
+ end
37
+
38
+ def process
39
+ @commits_with_duration = @commits.each do |commit|
40
+ if !commit.files.empty?
41
+ commit.files.each_with_index do |file, i|
42
+ time = sum_actions relevant_actions(commit, file)
43
+ commit.files[i].time_in_seconds += time
44
+ commit.time_in_seconds += time
45
+ end
46
+ else
47
+ commit.time_in_seconds = sum_actions(actions_before(commit.date))
48
+ end
49
+ end
50
+ total
51
+ total_commited
52
+ @commits_with_duration
53
+ end
54
+
55
+ private
56
+
57
+ def relevant_actions(commit, file)
58
+ # The timestamps should be before the expected commit
59
+ actions = actions_before(commit.date)
60
+
61
+ # The file should be the same file as we expect
62
+ # TODO: Might need to pass root_path down
63
+ actions = actions.select do |action|
64
+ action['file'] == File.join(file.git.dir.path, file.name)
65
+ end
66
+ # If this file had an earlier commit ensure the actions timestamp
67
+ # is after that commit
68
+ if file.dependent_commit
69
+ actions = actions.select do |action|
70
+ Time.at(action['time']) >= file.dependent_commit.date
71
+ end
72
+ end
73
+
74
+ actions
75
+ end
76
+
77
+ def actions_before(date)
78
+ @actions_with_durations.select do |action|
79
+ Time.at(action['time']) <= date
80
+ end
81
+ end
82
+
83
+ def sum_actions(actions)
84
+ actions.map { |action| action['duration'] }
85
+ .reduce(:+).to_f
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,4 @@
1
+ # Version Number Definition
2
+ module GitWakaTime
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'description' do
4
+
5
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitwakatime
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Russell Osborne
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: git
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: wakatime
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: logger
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: chronic_duration
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: colorize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
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: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: 'A Tool that will compile git data with wakatime data to establish time
140
+ per commit '
141
+ email:
142
+ - russosborn@gmail.com
143
+ executables:
144
+ - gitlog.rb
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".gitignore"
149
+ - ".rspec"
150
+ - Gemfile
151
+ - LICENSE.txt
152
+ - README.md
153
+ - Rakefile
154
+ - bin/gitlog.rb
155
+ - gitwakatime.gemspec
156
+ - lib/gitwakatime.rb
157
+ - lib/gitwakatime/actions.rb
158
+ - lib/gitwakatime/cli.rb
159
+ - lib/gitwakatime/commit.rb
160
+ - lib/gitwakatime/commited_file.rb
161
+ - lib/gitwakatime/log.rb
162
+ - lib/gitwakatime/mapper.rb
163
+ - lib/gitwakatime/timer.rb
164
+ - lib/gitwakatime/version.rb
165
+ - spec/commit_spec.rb
166
+ - spec/spec_helper.rb
167
+ homepage: ''
168
+ licenses:
169
+ - MIT
170
+ metadata: {}
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.2.2
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: A Tool that will compile git data with wakatime data to establish time per
191
+ commit
192
+ test_files:
193
+ - spec/commit_spec.rb
194
+ - spec/spec_helper.rb