gitreport 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/.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
|