gitreport 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/gitreport +56 -0
- data/gitreport.gemspec +102 -0
- data/lib/batch_sender.rb +86 -0
- data/lib/commit.rb +86 -0
- data/lib/configuration.rb +68 -0
- data/lib/current_branch.rb +24 -0
- data/lib/git_configuration.rb +14 -0
- data/lib/gitreport.rb +30 -0
- data/lib/history.rb +44 -0
- data/lib/hook.rb +122 -0
- data/lib/log.rb +26 -0
- data/lib/project.rb +70 -0
- data/lib/sender.rb +63 -0
- data/lib/storage.rb +27 -0
- data/lib/supplier.rb +53 -0
- data/lib/trollop.rb +783 -0
- data/spec/gitreport_spec.rb +1 -0
- data/spec/models/batch_sender_spec.rb +37 -0
- data/spec/models/commit_spec.rb +87 -0
- data/spec/models/configuration_spec.rb +69 -0
- data/spec/models/current_branch_spec.rb +22 -0
- data/spec/models/git_configuration_spec.rb +26 -0
- data/spec/models/history_spec.rb +50 -0
- data/spec/models/hook_spec.rb +64 -0
- data/spec/models/log_spec.rb +47 -0
- data/spec/models/project_spec.rb +93 -0
- data/spec/models/sender_spec.rb +75 -0
- data/spec/models/storage_spec.rb +53 -0
- data/spec/models/supplier_spec.rb +20 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/fake_repository.rb +83 -0
- metadata +234 -0
data/lib/hook.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
|
3
|
+
module GitReport
|
4
|
+
class Hook
|
5
|
+
|
6
|
+
# creates a hook file if not exists and adds our hook line if it does not exist already
|
7
|
+
def self.set!
|
8
|
+
create_hook_file! unless hook_file_exists?
|
9
|
+
set_hook! if hook_file_exists?
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.remove!
|
13
|
+
remove_hook! if hook_file_exists?
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# creates a git hook file
|
19
|
+
def self.create_hook_file!
|
20
|
+
write_to_file doc
|
21
|
+
end
|
22
|
+
|
23
|
+
# writes given data to hook file
|
24
|
+
def self.write_to_file data
|
25
|
+
begin
|
26
|
+
File.open(hook_file, 'w') {|f| f.write(data);f.chmod(0755);f.close }
|
27
|
+
rescue Exception => e
|
28
|
+
puts "Error while writing hookfile #{hook_file}: #{e}"
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
# returns the hook files content
|
36
|
+
def self.file_content
|
37
|
+
begin
|
38
|
+
File.open(hook_file, 'r').read
|
39
|
+
# @@content ||= File.open(hook_file, 'r').read
|
40
|
+
rescue Exception => e
|
41
|
+
puts "Error while reading hookfile #{hook_file}: #{e}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# returns true if a git hook file already exists, false else
|
46
|
+
def self.hook_file_exists?
|
47
|
+
File.exists? hook_file
|
48
|
+
end
|
49
|
+
|
50
|
+
# set's our hook line into an existing hook file if it does not exist already
|
51
|
+
def self.set_hook!
|
52
|
+
puts "Successfully registered post-commit hook." if (set_line! unless line_exists?)
|
53
|
+
end
|
54
|
+
|
55
|
+
# returns true if the hook file already has a hook line in
|
56
|
+
def self.line_exists?
|
57
|
+
if file_content.match(/bundle\sexec\sgitreport\scommit\s&/)
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
# sets our hook line
|
65
|
+
def self.set_line!
|
66
|
+
write_to_file(file_content + line)
|
67
|
+
end
|
68
|
+
|
69
|
+
# returns the hook files path
|
70
|
+
def self.hook_file
|
71
|
+
@@file ||= GitReport.project.path + "/.git/hooks/post-commit"
|
72
|
+
end
|
73
|
+
|
74
|
+
# returns the document header
|
75
|
+
def self.doc
|
76
|
+
"#!/bin/sh\n" +
|
77
|
+
"# This is a post-commit hook created by gitreport (http://gitreport.com)\n" +
|
78
|
+
"#\n" +
|
79
|
+
"# To remove it issue 'bundle exec unregister' in the projects main directory\n" +
|
80
|
+
"# In case the gitreport gem is not installed anymore, simply remove this hook file\n" +
|
81
|
+
"#\n" +
|
82
|
+
"# Be aware of other post commit hooks that my be mentioned here!\n"
|
83
|
+
end
|
84
|
+
|
85
|
+
# returns the line to activate gitreport via post commit hook
|
86
|
+
def self.line
|
87
|
+
"\nbundle exec gitreport commit &\n"
|
88
|
+
end
|
89
|
+
|
90
|
+
# removes the hook
|
91
|
+
def self.remove_hook!
|
92
|
+
(remove_hook_file!; return) if hook_file_unchanged?
|
93
|
+
remove_line! if line_exists?
|
94
|
+
end
|
95
|
+
|
96
|
+
# removes the hook file
|
97
|
+
def self.remove_hook_file!
|
98
|
+
begin
|
99
|
+
File.unlink(hook_file)
|
100
|
+
puts "Successfully removed gitreport post-commit hook (file).\n"
|
101
|
+
rescue Exception => e
|
102
|
+
puts "Error while removing hookfile #{hook_file}: #{e}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# returns true if the hook file is ours and was not changed
|
107
|
+
def self.hook_file_unchanged?
|
108
|
+
Digest::SHA1.hexdigest(file_content) == "9c69e61ce35b8ce21968343411e6abeb89b237dd"
|
109
|
+
end
|
110
|
+
|
111
|
+
# removes our hook line from hook file
|
112
|
+
def self.remove_line!
|
113
|
+
puts "Successfully removed gitreport post-commit hook.\n" if write_to_file(clean_up(file_content))
|
114
|
+
end
|
115
|
+
|
116
|
+
# removes our hook line from given content
|
117
|
+
def self.clean_up content
|
118
|
+
content.gsub(/\nbundle\sexec\sgitreport\scommit\s&\n/,'')
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
data/lib/log.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module GitReport
|
2
|
+
class Log
|
3
|
+
|
4
|
+
attr_accessor :project, :commits
|
5
|
+
|
6
|
+
def initialize project = nil
|
7
|
+
raise 'No git repo found!' unless project
|
8
|
+
@project = project
|
9
|
+
end
|
10
|
+
|
11
|
+
# returns all the commits of that project of the currently checked out branch
|
12
|
+
def commits
|
13
|
+
@commits ||= @project.log.entries.sort{ |a, b| a.author.date <=> b.author.date }
|
14
|
+
end
|
15
|
+
|
16
|
+
# returns the most recent commit
|
17
|
+
def last
|
18
|
+
@@last ||= self.commits.last
|
19
|
+
end
|
20
|
+
|
21
|
+
# returns the initial commit
|
22
|
+
def first
|
23
|
+
@@first ||= self.commits.first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/project.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module GitReport
|
2
|
+
|
3
|
+
class Project
|
4
|
+
attr_accessor :project, :log, :branch
|
5
|
+
|
6
|
+
def initialize path = nil
|
7
|
+
path ||= '.'
|
8
|
+
@project = Git.open(path)
|
9
|
+
@log = GitReport::Log.new(@project)
|
10
|
+
@branch = GitReport::CurrentBranch.new(@project)
|
11
|
+
end
|
12
|
+
|
13
|
+
# returns the local project directory
|
14
|
+
def path
|
15
|
+
@path ||= @project.dir.path
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns the local name of the project extracted from the project directory
|
19
|
+
def name
|
20
|
+
@name ||= @project.dir.path.match(/.*\/(.*)$/).nil? ? "unknown" : $1
|
21
|
+
end
|
22
|
+
|
23
|
+
# returns an array of remote objects of the project
|
24
|
+
def remotes
|
25
|
+
@remotes ||= @project.remotes
|
26
|
+
end
|
27
|
+
|
28
|
+
# returns an array of names of all remote branches
|
29
|
+
def remote_branches
|
30
|
+
@remote_branches ||= @project.branches.remote.map(&:full)
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns the projects first commits hash as an identifier
|
34
|
+
def identifier
|
35
|
+
@identifier ||= self.revlist.last
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns the projects rev-list
|
39
|
+
def revlist
|
40
|
+
(`git rev-list --all`).split("\n")
|
41
|
+
end
|
42
|
+
|
43
|
+
# returns the branch name
|
44
|
+
def branchname
|
45
|
+
@branchname ||= self.branch.name
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns projects core data as a hash for transfer of a commit batch
|
49
|
+
def data
|
50
|
+
@data ||= aggregate
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# aggregates the projects core data
|
56
|
+
def aggregate
|
57
|
+
data = {}
|
58
|
+
data[:project_path] = self.path
|
59
|
+
data[:project_name] = self.name
|
60
|
+
data[:current_branch] = self.branchname
|
61
|
+
data[:remotes] = self.remotes.map(&:name)
|
62
|
+
data[:remote_urls] = self.remotes.map(&:url)
|
63
|
+
data[:remote_branches] = self.remote_branches
|
64
|
+
data[:project_identifier] = self.identifier
|
65
|
+
data
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/sender.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module GitReport
|
2
|
+
|
3
|
+
class Sender
|
4
|
+
|
5
|
+
# sends or saves the commits
|
6
|
+
def self.send! options = nil
|
7
|
+
commits = GitReport::Supplier.commits(options)
|
8
|
+
commits.each do |commit|
|
9
|
+
send_data!(commit) ? commits = commits.inject([]){ |a,i| ( a << i unless i == commit );a } : break # weird, delete fails here
|
10
|
+
end
|
11
|
+
storage.save! commits
|
12
|
+
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# sends the commit data to the server
|
19
|
+
def self.send_data! commit, options = nil
|
20
|
+
begin
|
21
|
+
response = Net::HTTP.Proxy(configuration.proxy_host, configuration.proxy_port).start(configuration.host, configuration.port) do |http|
|
22
|
+
request = Net::HTTP::Post.new(request_path options)
|
23
|
+
headers request
|
24
|
+
request.body = commit.to_json
|
25
|
+
http.open_timeout = configuration.timeout
|
26
|
+
http.read_timeout = configuration.timeout
|
27
|
+
http.request request
|
28
|
+
end
|
29
|
+
raise StandardError unless (response.code == "200" or response.code == "401")
|
30
|
+
rescue Exception => e
|
31
|
+
puts "Error during sending the commit: #{e}"
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns local storage
|
39
|
+
def self.storage
|
40
|
+
@@storage ||= GitReport::Storage.new(ENV['HOME'], '.gitreport_storage')
|
41
|
+
end
|
42
|
+
|
43
|
+
# returns configuration object
|
44
|
+
def self.configuration
|
45
|
+
@@configuration ||= GitReport.configuration
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns the request path
|
49
|
+
def self.request_path options
|
50
|
+
@@path ||= "/v#{configuration.api_version}/commits"
|
51
|
+
end
|
52
|
+
|
53
|
+
# returns the default headers
|
54
|
+
def self.headers request
|
55
|
+
request['User-Agent'] = 'gitreport-client-ruby'
|
56
|
+
request['Content-Type'] = 'application/json'
|
57
|
+
request['Accept'] = 'application/json'
|
58
|
+
request['X-gitreport-Auth-Token'] = configuration.auth_token
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/storage.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module GitReport
|
4
|
+
class Storage
|
5
|
+
|
6
|
+
# inits storage object
|
7
|
+
def initialize path, filename
|
8
|
+
@path = path
|
9
|
+
@filename = filename
|
10
|
+
end
|
11
|
+
|
12
|
+
# locally stores data
|
13
|
+
def save! data
|
14
|
+
File.open("#{@path}/#{@filename}", 'w+') do |file|
|
15
|
+
file.write Base64.encode64(Marshal.dump(data))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# loads locally stored data
|
20
|
+
def load
|
21
|
+
if File.exists?("#{@path}/#{@filename}")
|
22
|
+
data = File.read "#{@path}/#{@filename}"
|
23
|
+
Marshal.load(Base64.decode64(data)) rescue NameError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/supplier.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module GitReport
|
2
|
+
|
3
|
+
class Supplier
|
4
|
+
|
5
|
+
# returns the commits in relation to the given option
|
6
|
+
def self.commits options
|
7
|
+
raise "No option given to fetch commits" unless options
|
8
|
+
case options
|
9
|
+
when :last_and_stored
|
10
|
+
last_and_stored_commits
|
11
|
+
when :stored
|
12
|
+
stored_commits
|
13
|
+
when :history
|
14
|
+
# history_commits :user #slow
|
15
|
+
history_commits :all #fast
|
16
|
+
|
17
|
+
# we sort out the foreign commits on the server if the user has a single user account
|
18
|
+
# this way we can realize company accounts and already have all the data we need during import
|
19
|
+
else
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# returns stored commits plus the last commit taken
|
27
|
+
def self.last_and_stored_commits
|
28
|
+
@@all_commits ||= (stored_commits || []).push(recent_commit)
|
29
|
+
end
|
30
|
+
|
31
|
+
# returns the stored commits that could not be send before
|
32
|
+
def self.stored_commits
|
33
|
+
storage.load
|
34
|
+
end
|
35
|
+
|
36
|
+
# returns all commits of the actual user that were taken in the past
|
37
|
+
# DO NOT cache here!!
|
38
|
+
def self.history_commits scope
|
39
|
+
GitReport::History.commits(scope)
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns the commit that should be send now
|
43
|
+
def self.recent_commit
|
44
|
+
@@commit_data ||= GitReport::Commit.new(GitReport.project.log.last, GitReport.project.identifier)
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns local storage
|
48
|
+
def self.storage
|
49
|
+
@@storage ||= GitReport::Storage.new(ENV['HOME'], '.gitreport_storage')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|