git2mite 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Alexander Lang
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ This tool allows to you to write the commit log of your git repository to your mite (http://mite.yo.lk - an impressive time tracking tool) account in order to auto-fill your timesheets.
2
+
3
+ # Usage
4
+
5
+ Just run it from within the project you want to add mite entries for and follow the onscreen instructions
6
+
7
+ ` #project_path ruby path_to_git2mite/git2mite.rb `
data/bin/git2mite ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'git2mite'
4
+ Git2Mite::App.new.run
@@ -0,0 +1,58 @@
1
+ module Git2Mite
2
+ class App
3
+ def configuration
4
+ @configuration ||= Git2Mite::Configuration.new
5
+ end
6
+
7
+ def get_api_key
8
+ configuration.api_key ||= @gui.ask('What is your api key?').strip
9
+ end
10
+
11
+ def get_sub_domain
12
+ configuration.sub_domain ||= @gui.ask('What is your account subdomain?').strip
13
+ end
14
+
15
+ def check_if_git_repo!
16
+ @gui.error "Please change to a directory that is a git repository." unless @repo.is_git_repo?
17
+ end
18
+
19
+ def check_ruby_version!
20
+ @gui.error "Sorry you need Ruby 1.8.7+ for this." if RUBY_VERSION < '1.8.7'
21
+ end
22
+
23
+
24
+ def initialize
25
+ @gui = Gui.new
26
+ @repo = GitRepo.new
27
+ end
28
+
29
+ def run
30
+ @gui.print_welcome
31
+ check_if_git_repo!
32
+ check_ruby_version!
33
+ client = MiteClient.new("http://#{get_sub_domain}.mite.yo.lk", get_api_key)
34
+ project_id = @gui.get_project_id(client.projects)
35
+ user_id = @gui.get_user_id(User.all(client))
36
+ start_date = @gui.get_date('start date')
37
+ end_date = @gui.get_date('end date')
38
+ commits = @repo.commits start_date, end_date
39
+ author = @gui.get_author commits.map{|date, message, _author| _author}.uniq
40
+
41
+ puts
42
+ puts 'Writing commits to mite'
43
+
44
+ commits.each do |date, message, _author|
45
+ next unless _author == author
46
+ entries = client.time_entries project_id, user_id, date
47
+ if entries.empty?
48
+ STDERR.puts "WARN no time entries for commit #{date.to_s}: #{message}"
49
+ else
50
+ entry = entries[rand(entries.size)]['time_entry']
51
+ client.add_message_to_entry entry, message
52
+ print "."
53
+ end
54
+ end
55
+ puts 'done'
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,46 @@
1
+ require 'yaml'
2
+
3
+ module Git2Mite
4
+ class Configuration
5
+ def initialize(config_file = nil)
6
+ @config_file = config_file || ENV['HOME'] + '/.git2mite.yml'
7
+ if File.exist?(@config_file)
8
+ @config = load_config
9
+ else
10
+ @config = {}
11
+ end
12
+ end
13
+
14
+ def api_key
15
+ @config[:api_key]
16
+ end
17
+
18
+ def sub_domain
19
+ @config[:sub_domain]
20
+ end
21
+
22
+ def sub_domain=(value)
23
+ @config[:sub_domain] = value.strip
24
+ store_config
25
+ @config[:sub_domain]
26
+ end
27
+
28
+ def api_key=(value)
29
+ @config[:api_key] = value.strip
30
+ store_config
31
+ @config[:api_key]
32
+ end
33
+
34
+ private
35
+
36
+ def store_config
37
+ File.open(@config_file, 'w') do |f|
38
+ f << @config.to_yaml
39
+ end
40
+ end
41
+
42
+ def load_config
43
+ YAML.load(File.read(@config_file))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,19 @@
1
+ module Git2Mite
2
+ class GitRepo
3
+ def is_git_repo?
4
+ status = `git status 2>&1`
5
+ !status.downcase.include?('not a git repo')
6
+ end
7
+
8
+ def commits(start_date, end_date)
9
+ lines = []
10
+ IO.popen("git log --pretty=format:%ai\\|%s\\|%ae --no-merges --before=#{end_date + 1} --after=#{start_date}") do |io|
11
+ while line = io.gets
12
+ date, message, author = line.split('|')
13
+ lines.unshift [Date.parse(date), message.strip, author.strip]
14
+ end
15
+ lines
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ module Git2Mite
2
+ class Gui
3
+ def print_welcome
4
+ puts <<-WELCOME
5
+ Welcome to git2mite
6
+
7
+ This tool allows to you to write the commit log of
8
+ your git repository to your mite account in order
9
+ to auto-fill your timesheets.
10
+
11
+ Brought to you by http://upstream-berlin.com
12
+ Question, Problems, Source Code: http://github.com/upstream/git2mite
13
+
14
+ WELCOME
15
+ end
16
+
17
+ def ask(question)
18
+ print "#{question}: "
19
+ $stdin.gets
20
+ end
21
+
22
+ def error(reason)
23
+ STDERR.puts reason
24
+ exit(-1)
25
+ end
26
+
27
+ def get_project_id(projects)
28
+ puts "=== Projects ==="
29
+ projects.each.with_index do |project, i|
30
+ puts "#{i+1}\t#{project['project']['name']}"
31
+ end
32
+ choice = ask('Which project do you want to write your commits to?')
33
+ (projects[choice.to_i - 1] || error('invalid project id'))['project']['id']
34
+ end
35
+
36
+ def get_user_id(users)
37
+ puts "\n=== Users ==="
38
+ users.each.with_index do |user, i|
39
+ puts "#{i+1}\t#{user.name}"
40
+ end
41
+ choice = ask('Which user do you want to write your commits to?')
42
+ (users[choice.to_i - 1] || error('invalid user id')).id
43
+ end
44
+
45
+ def get_author(authors)
46
+ puts "\n=== Git Authors ==="
47
+ authors.each.with_index do |name, i|
48
+ puts "#{i+1}\t#{name}"
49
+ end
50
+ choice = ask('Which author\'s commits to you want to use?')
51
+ authors[choice.to_i - 1] || error('Invalid author')
52
+ end
53
+
54
+ def get_date(label)
55
+ answer = ask("Enter the #{label} (yyyy-mm-dd) [#{Date.today}]")
56
+ begin
57
+ answer.strip.empty? ? Date.today : Date.parse(answer)
58
+ rescue(ArgumentError)
59
+ error('invalid date')
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ gem 'rest-client'
3
+ require 'rest_client'
4
+
5
+ gem 'json'
6
+ require 'json'
7
+
8
+ gem 'builder'
9
+ require 'builder'
10
+
11
+ module Git2Mite
12
+ class MiteClient
13
+
14
+ def initialize(url, api_key)
15
+ @url = url
16
+ @api_key = api_key
17
+ end
18
+
19
+ def time_entries(project_id, user_id, date)
20
+ get("/time_entries.json?project-id=#{project_id}&user-id=#{user_id}&at=#{date.to_s}")
21
+ end
22
+
23
+ def projects
24
+ get '/projects.json'
25
+ end
26
+
27
+ def add_message_to_entry(entry, message)
28
+ builder = Builder::XmlMarkup.new
29
+ builder.tag!('time-entry') do |time_entry|
30
+ time_entry.note((entry['note'].size == 0 ? '' : entry['note'] + ', ') + message)
31
+ end
32
+ put "/time_entries/#{entry['id']}.xml", builder.target!
33
+ end
34
+
35
+ def get(path)
36
+ JSON.parse(RestClient.get(@url + path, {'X-MiteApiKey' => @api_key, 'Content-Type' => 'application/json'}))
37
+ end
38
+
39
+ private
40
+
41
+ def put(path, xml)
42
+ RestClient.put(@url + path, xml, {'X-MiteApiKey' => @api_key, 'Content-Type' => 'application/xml'})
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ module Git2Mite
2
+ class User
3
+ attr_accessor :name, :id
4
+
5
+ def initialize(attributes = {})
6
+ self.name = attributes[:name]
7
+ self.id = attributes[:id]
8
+ end
9
+
10
+ def self.all(mite_client)
11
+ mite_client.get('/users.json').map do |json|
12
+ User.new :name => json['user']['name'], :id => json['user']['id']
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/git2mite.rb ADDED
@@ -0,0 +1,12 @@
1
+ # TODO
2
+ # * check if api key is valid
3
+ # * run as post commit hook?
4
+
5
+ $LOAD_PATH.unshift File.dirname(__FILE__)
6
+ require 'git2mite/app'
7
+ require 'git2mite/configuration'
8
+ require 'git2mite/user'
9
+ require 'git2mite/mite_client'
10
+ require 'git2mite/gui'
11
+ require 'git2mite/git_repo'
12
+
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'git2mite/configuration'
3
+
4
+ describe Git2Mite::Configuration do
5
+ before(:each) do
6
+ @path = 'test_config.yml'
7
+ File.unlink(@path) if File.exist?(@path)
8
+ end
9
+
10
+ after(:each) do
11
+ File.unlink(@path) if File.exist?(@path)
12
+ end
13
+
14
+ it "should persist a value" do
15
+ config = Git2Mite::Configuration.new(@path)
16
+ config.api_key = '123'
17
+ Git2Mite::Configuration.new(@path).api_key.should == '123'
18
+ end
19
+
20
+ it "should return the value on setting it" do
21
+ returned = Git2Mite::Configuration.new(@path).api_key = '234'
22
+ returned.should == '234'
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'git2mite/git_repo'
3
+
4
+
5
+ describe Git2Mite::GitRepo do
6
+ describe "commits" do
7
+ before(:each) do
8
+ @today = Date.today
9
+ end
10
+ it "should strip newlines on authors" do
11
+ IO.stub(:popen).and_yield(StringIO.new("2009-11-04 19:11:38 +0100|updated readme to include example how to run git2mite|thilo@upstream-berlin.com\n"))
12
+ Git2Mite::GitRepo.new.commits(@today, @today).first[2].should == "thilo@upstream-berlin.com"
13
+ end
14
+ end
15
+ end
data/spec/gui_spec.rb ADDED
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'git2mite/gui'
3
+
4
+ describe Git2Mite::Gui do
5
+ describe "get date" do
6
+ before(:each) do
7
+ @gui = Git2Mite::Gui.new
8
+ end
9
+
10
+ it "should use entered date" do
11
+ date = inject_input("2008-09-11"){@gui.get_date('start date')}
12
+ date.should == Date.parse('2008-09-11')
13
+ end
14
+
15
+ it "should use the current date if no date entered" do
16
+ date = inject_input("\n"){@gui.get_date('start date')}
17
+ date.should == Date.today
18
+ end
19
+
20
+ def inject_input(string, &block)
21
+ orig_in = $stdin
22
+ $stdin = StringIO.new(string)
23
+ result = yield
24
+ $stdin = orig_in
25
+ result
26
+ end
27
+ end
28
+ end
@@ -0,0 +1 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git2mite
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Lang
8
+ - Thilo Utke
9
+ - Robin Mehner
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-12-21 00:00:00 +01:00
15
+ default_executable: git2mite
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: json
19
+ type: :runtime
20
+ version_requirement:
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: "0"
26
+ version:
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ type: :runtime
30
+ version_requirement:
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ version:
37
+ - !ruby/object:Gem::Dependency
38
+ name: builder
39
+ type: :runtime
40
+ version_requirement:
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ description:
48
+ email: alex@upstre.am
49
+ executables:
50
+ - git2mite
51
+ extensions: []
52
+
53
+ extra_rdoc_files:
54
+ - LICENSE
55
+ - README.md
56
+ files:
57
+ - README.md
58
+ - lib/git2mite.rb
59
+ - lib/git2mite/app.rb
60
+ - lib/git2mite/configuration.rb
61
+ - lib/git2mite/git_repo.rb
62
+ - lib/git2mite/gui.rb
63
+ - lib/git2mite/mite_client.rb
64
+ - lib/git2mite/user.rb
65
+ - LICENSE
66
+ has_rdoc: true
67
+ homepage: http://github.com/upstream/git2mite
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --charset=UTF-8
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ requirements: []
88
+
89
+ rubyforge_project:
90
+ rubygems_version: 1.3.5
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: writes your git commit messages to your mite account
94
+ test_files:
95
+ - spec/configuration_spec.rb
96
+ - spec/git_repo_spec.rb
97
+ - spec/gui_spec.rb
98
+ - spec/spec_helper.rb