mytime 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +35 -0
- data/Rakefile +2 -0
- data/bin/mytime +16 -0
- data/lib/mytime.rb +85 -0
- data/lib/mytime/client.rb +59 -0
- data/lib/mytime/setup.rb +61 -0
- data/lib/mytime/timesheet.rb +31 -0
- data/lib/mytime/version.rb +3 -0
- data/mytime.gemspec +19 -0
- metadata +75 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 David Stump
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# MyTime
|
2
|
+
|
3
|
+
Use your git commit history to track your time. Uses Freshbooks API.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'mytime'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install mytime
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
To list log:
|
22
|
+
|
23
|
+
$ mytime
|
24
|
+
|
25
|
+
To submit project time:
|
26
|
+
|
27
|
+
$ mytime commit "Add an additional note if desired"
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/mytime
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# = mytime(1)
|
4
|
+
#
|
5
|
+
# == USAGE
|
6
|
+
# mytime add/manage timesheeds with git commit log. Uses Freshbooks API.
|
7
|
+
#
|
8
|
+
# == INSTALL
|
9
|
+
# RubyGem:
|
10
|
+
# gem install mytime
|
11
|
+
#
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
14
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'mytime.rb'))
|
15
|
+
|
16
|
+
Mytime.execute(*ARGV)
|
data/lib/mytime.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "mytime/version"
|
2
|
+
require "mytime/setup"
|
3
|
+
require "mytime/client"
|
4
|
+
require "mytime/timesheet"
|
5
|
+
require 'ruby-freshbooks'
|
6
|
+
require 'optparse'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
10
|
+
|
11
|
+
module Mytime
|
12
|
+
extend self
|
13
|
+
extend Mytime::Client
|
14
|
+
|
15
|
+
USER_FILE = File.expand_path('~/.mytime')
|
16
|
+
|
17
|
+
# Parses command line arguments and does what needs to be done.
|
18
|
+
#
|
19
|
+
# @returns nothing
|
20
|
+
def execute(*args)
|
21
|
+
@options = parse_options(*args)
|
22
|
+
command = args.shift || 'list'
|
23
|
+
|
24
|
+
case command.to_sym
|
25
|
+
when :setup
|
26
|
+
puts "We have all the time in the world."
|
27
|
+
setup
|
28
|
+
when :init
|
29
|
+
init
|
30
|
+
when :status, :list, :log
|
31
|
+
puts status
|
32
|
+
when :commit, :add, :a
|
33
|
+
commit(args.first, args.last)
|
34
|
+
when :push, :submit, :p
|
35
|
+
puts "Submitting Timesheet..."
|
36
|
+
push(args.first)
|
37
|
+
when :project, :detail, :info
|
38
|
+
puts "Project Details:"
|
39
|
+
puts config_details(Dir.pwd).to_yaml
|
40
|
+
else
|
41
|
+
puts @options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Save a .mytime config file. Overwrites any existing data
|
46
|
+
#
|
47
|
+
# Options:
|
48
|
+
# contents: Required hash of account data to save
|
49
|
+
#
|
50
|
+
def save(contents)
|
51
|
+
File.open(USER_FILE, 'a') do |file|
|
52
|
+
file.write contents.to_yaml
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Add yaml data to the existing .mytime config file
|
57
|
+
#
|
58
|
+
# Options:
|
59
|
+
# contents: Required hash of data to add to config file
|
60
|
+
#
|
61
|
+
def add(contents)
|
62
|
+
data = YAML.load_file USER_FILE
|
63
|
+
merged_data = data.merge(contents)
|
64
|
+
puts merged_data
|
65
|
+
File.open(USER_FILE, 'w') do |file|
|
66
|
+
file.write merged_data.to_yaml
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return details of .mytime config file
|
71
|
+
#
|
72
|
+
def config_details(path = "")
|
73
|
+
return unless YAML.load_file(USER_FILE)
|
74
|
+
data = YAML.load_file USER_FILE
|
75
|
+
if path == ""
|
76
|
+
data
|
77
|
+
else
|
78
|
+
data.each do |d|
|
79
|
+
project = data.select{|key, hash| hash["project_path"] == path }
|
80
|
+
return project.first[1]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Mytime
|
2
|
+
|
3
|
+
module Client
|
4
|
+
extend self
|
5
|
+
|
6
|
+
# Get project data from client API
|
7
|
+
#
|
8
|
+
# Option:
|
9
|
+
# project_id: Optional project_id to restrict data returned
|
10
|
+
#
|
11
|
+
def project(project_id = nil)
|
12
|
+
account = Mytime.config_details
|
13
|
+
c = FreshBooks::Client.new(account["account"], account["token"])
|
14
|
+
if project_id.nil?
|
15
|
+
c.project.list["projects"]
|
16
|
+
else
|
17
|
+
c.project.get :project_id => project_id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Submit new time entry to client API
|
22
|
+
#
|
23
|
+
# Option:
|
24
|
+
# hours: Required - number of hours spent for this time entry
|
25
|
+
# message: Optional - message to send with time entry
|
26
|
+
#
|
27
|
+
def submit(hours, message = "")
|
28
|
+
account = Mytime.config_details
|
29
|
+
c = FreshBooks::Client.new(account["account"], account["token"])
|
30
|
+
project = Mytime.config_details(Dir.pwd)
|
31
|
+
entry = c.time_entry.create(
|
32
|
+
:time_entry => {
|
33
|
+
project_id: project["project_id"],
|
34
|
+
task_id: project["task_id"],
|
35
|
+
hours: hours.to_f,
|
36
|
+
notes: message.to_s,
|
37
|
+
date: Date.today.to_s
|
38
|
+
}
|
39
|
+
)
|
40
|
+
return validate(entry)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Validate time entry to establish API success or failure
|
44
|
+
#
|
45
|
+
# Option
|
46
|
+
# entry: Required time entry parameter to validate
|
47
|
+
#
|
48
|
+
def validate(entry)
|
49
|
+
return "Oops. Please try resubmitting your time or checking accout details!" unless entry.any?
|
50
|
+
if entry["time_entry_id"]
|
51
|
+
return "Timesheet Successfully Submitted"
|
52
|
+
else
|
53
|
+
return "Oops. An error was encountered: #{entry}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/lib/mytime/setup.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Mytime
|
2
|
+
extend self
|
3
|
+
|
4
|
+
# Create .mytime file in the profile directory
|
5
|
+
# and insert the user account and Freshbooks token
|
6
|
+
#
|
7
|
+
def setup
|
8
|
+
puts "What is your Freshbooks account name?"
|
9
|
+
account_name = STDIN.gets.chomp
|
10
|
+
puts "What is your Freshbooks token?"
|
11
|
+
token = STDIN.gets.chomp
|
12
|
+
account = Hash.new
|
13
|
+
account["account"] = "#{account_name}.freshbooks.com"
|
14
|
+
account["token"] = token
|
15
|
+
self.save(account)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Setup .mytime file to include project specific data
|
19
|
+
#
|
20
|
+
def init
|
21
|
+
puts "Choose Project:"
|
22
|
+
projects = Client.project["project"]
|
23
|
+
projects.each do |project|
|
24
|
+
puts "#{project['project_id']}: #{project['name']}"
|
25
|
+
end
|
26
|
+
project_id = STDIN.gets.chomp
|
27
|
+
|
28
|
+
project = Client.project(project_id)["project"]
|
29
|
+
task_id = project["tasks"]["task"][0]["task_id"]
|
30
|
+
|
31
|
+
project_details = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
|
32
|
+
project_details[project_id]["project_path"] = Dir.pwd
|
33
|
+
project_details[project_id]["project_id"] = project_id
|
34
|
+
project_details[project_id]["task_id"] = task_id
|
35
|
+
self.add(project_details)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set configuration variables to values passed in the command line options
|
39
|
+
#
|
40
|
+
def parse_options(*args)
|
41
|
+
options = OptionParser.new do |opts|
|
42
|
+
opts.banner = "\nUsage: mytime [options] [command]"
|
43
|
+
opts.separator "mytime uses git to log your time\n\n"
|
44
|
+
opts.separator "Commands:"
|
45
|
+
opts.separator " status Prints formatted commit log from today"
|
46
|
+
opts.separator " setup Sets up mytime authorization information"
|
47
|
+
opts.separator " init Sets up mytime for this project"
|
48
|
+
opts.separator " commit Creates a custom timesheet entry"
|
49
|
+
opts.separator " push Saves timesheet entry with git commit log"
|
50
|
+
opts.separator ""
|
51
|
+
opts.separator "Options:"
|
52
|
+
opts.on('-h', '--help', 'Display this screen') { puts opts; exit }
|
53
|
+
opts.on('-v', '--version', 'Display the current version') do
|
54
|
+
puts Mytime::VERSION
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
end
|
58
|
+
options.parse!(args)
|
59
|
+
options
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Mytime
|
2
|
+
extend self
|
3
|
+
|
4
|
+
# Return log of git commits from today
|
5
|
+
#
|
6
|
+
def status
|
7
|
+
user = `git config --get user.name`
|
8
|
+
`git log --oneline --author='#{user}' --since='6am'`
|
9
|
+
end
|
10
|
+
|
11
|
+
# Send a custom time entry to API with string message
|
12
|
+
#
|
13
|
+
# Option:
|
14
|
+
# hours: Required - number of hours for this time entry
|
15
|
+
# message: Optional - custom message to send with time entry
|
16
|
+
#
|
17
|
+
def commit(hours, message = "")
|
18
|
+
puts "Submitting: #{message}"
|
19
|
+
puts Client.submit(hours, message)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Send git commit log as timesheet entry to client
|
23
|
+
#
|
24
|
+
# Options
|
25
|
+
# hours: Required parameter for number of hours on time entry
|
26
|
+
#
|
27
|
+
def push(hours)
|
28
|
+
puts Client.submit(hours, status)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/mytime.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/mytime/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["David Stump"]
|
6
|
+
gem.email = ["david@davidstump.net"]
|
7
|
+
gem.description = %q{Git commit log based timesheet powered by Freshbooks}
|
8
|
+
gem.summary = %q{MyTime is a simple command line utility for submitting git commit history to a timesheet. Powered by the Freshbooks API.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "mytime"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Mytime::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency('ruby-freshbooks')
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mytime
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Stump
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ruby-freshbooks
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: Git commit log based timesheet powered by Freshbooks
|
31
|
+
email:
|
32
|
+
- david@davidstump.net
|
33
|
+
executables:
|
34
|
+
- mytime
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- bin/mytime
|
44
|
+
- lib/mytime.rb
|
45
|
+
- lib/mytime/client.rb
|
46
|
+
- lib/mytime/setup.rb
|
47
|
+
- lib/mytime/timesheet.rb
|
48
|
+
- lib/mytime/version.rb
|
49
|
+
- mytime.gemspec
|
50
|
+
homepage: ''
|
51
|
+
licenses: []
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.8.24
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: MyTime is a simple command line utility for submitting git commit history
|
74
|
+
to a timesheet. Powered by the Freshbooks API.
|
75
|
+
test_files: []
|