gitreport 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,7 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem 'json'
4
- gem 'git', '~>1.2.5'
5
4
 
6
5
  group :development do
7
6
  # gem 'ruby-debug'
data/Gemfile.lock CHANGED
@@ -31,7 +31,6 @@ PLATFORMS
31
31
 
32
32
  DEPENDENCIES
33
33
  bundler (~> 1.0.0)
34
- git (~> 1.2.5)
35
34
  jeweler (~> 1.6.4)
36
35
  json
37
36
  rcov
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
data/gitreport.gemspec CHANGED
@@ -4,15 +4,14 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{gitreport}
8
- s.version = "0.0.2"
7
+ s.name = "gitreport"
8
+ s.version = "0.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jan Roesner"]
12
- s.date = %q{2011-10-14}
13
- s.default_executable = %q{gitreport}
14
- s.description = %q{gitreport keeps track of your projects. It collects info about commited and pushed data, submits it to our servers and provides a gorgous frontend to examine, discover and extract the data that you need to generate the payment recipes for your customers. No longer searching or `what did I commit when and where`...}
15
- s.email = %q{jan@roesner.it}
12
+ s.date = "2011-10-16"
13
+ s.description = "gitreport keeps track of your projects. It collects info about commited and pushed data, submits it to our servers and provides a gorgous frontend to examine, discover and extract the data that you need to generate the payment recipes for your customers. No longer searching or `what did I commit when and where`..."
14
+ s.email = "jan@roesner.it"
16
15
  s.executables = ["gitreport"]
17
16
  s.extra_rdoc_files = [
18
17
  "LICENSE.txt",
@@ -32,6 +31,23 @@ Gem::Specification.new do |s|
32
31
  "lib/commit.rb",
33
32
  "lib/configuration.rb",
34
33
  "lib/current_branch.rb",
34
+ "lib/git.rb",
35
+ "lib/git/author.rb",
36
+ "lib/git/base.rb",
37
+ "lib/git/branch.rb",
38
+ "lib/git/branches.rb",
39
+ "lib/git/diff.rb",
40
+ "lib/git/index.rb",
41
+ "lib/git/lib.rb",
42
+ "lib/git/log.rb",
43
+ "lib/git/object.rb",
44
+ "lib/git/path.rb",
45
+ "lib/git/remote.rb",
46
+ "lib/git/repository.rb",
47
+ "lib/git/stash.rb",
48
+ "lib/git/stashes.rb",
49
+ "lib/git/status.rb",
50
+ "lib/git/working_directory.rb",
35
51
  "lib/git_configuration.rb",
36
52
  "lib/gitreport.rb",
37
53
  "lib/history.rb",
@@ -58,19 +74,17 @@ Gem::Specification.new do |s|
58
74
  "spec/spec_helper.rb",
59
75
  "spec/support/fake_repository.rb"
60
76
  ]
61
- s.homepage = %q{http://github.com/janroesner/gitreport}
77
+ s.homepage = "http://github.com/janroesner/gitreport"
62
78
  s.licenses = ["MIT"]
63
79
  s.require_paths = ["lib"]
64
- s.rubygems_version = %q{1.3.7}
65
- s.summary = %q{gitreport tracks commit and push info of your git projects}
80
+ s.rubygems_version = "1.8.10"
81
+ s.summary = "gitreport tracks commit and push info of your git projects"
66
82
 
67
83
  if s.respond_to? :specification_version then
68
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
69
84
  s.specification_version = 3
70
85
 
71
86
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
72
87
  s.add_runtime_dependency(%q<json>, [">= 0"])
73
- s.add_runtime_dependency(%q<git>, ["~> 1.2.5"])
74
88
  s.add_development_dependency(%q<spork>, ["> 0.9.0.rc"])
75
89
  s.add_development_dependency(%q<rspec>, [">= 0"])
76
90
  s.add_development_dependency(%q<webmock>, [">= 0"])
@@ -80,7 +94,6 @@ Gem::Specification.new do |s|
80
94
  s.add_development_dependency(%q<rcov>, [">= 0"])
81
95
  else
82
96
  s.add_dependency(%q<json>, [">= 0"])
83
- s.add_dependency(%q<git>, ["~> 1.2.5"])
84
97
  s.add_dependency(%q<spork>, ["> 0.9.0.rc"])
85
98
  s.add_dependency(%q<rspec>, [">= 0"])
86
99
  s.add_dependency(%q<webmock>, [">= 0"])
@@ -91,7 +104,6 @@ Gem::Specification.new do |s|
91
104
  end
92
105
  else
93
106
  s.add_dependency(%q<json>, [">= 0"])
94
- s.add_dependency(%q<git>, ["~> 1.2.5"])
95
107
  s.add_dependency(%q<spork>, ["> 0.9.0.rc"])
96
108
  s.add_dependency(%q<rspec>, [">= 0"])
97
109
  s.add_dependency(%q<webmock>, [">= 0"])
data/lib/git/author.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Git
2
+ class Author
3
+ attr_accessor :name, :email, :date
4
+
5
+ def initialize(author_string)
6
+ if m = /(.*?) <(.*?)> (\d+) (.*)/.match(author_string)
7
+ @name = m[1]
8
+ @email = m[2]
9
+ @date = Time.at(m[3].to_i)
10
+ end
11
+ end
12
+
13
+ end
14
+ end
data/lib/git/base.rb ADDED
@@ -0,0 +1,479 @@
1
+ module Git
2
+
3
+ class Base
4
+
5
+ # opens a bare Git Repository - no working directory options
6
+ def self.bare(git_dir, opts = {})
7
+ self.new({:repository => git_dir}.merge(opts))
8
+ end
9
+
10
+ # opens a new Git Project from a working directory
11
+ # you can specify non-standard git_dir and index file in the options
12
+ def self.open(working_dir, opts={})
13
+ self.new({:working_directory => working_dir}.merge(opts))
14
+ end
15
+
16
+ # initializes a git repository
17
+ #
18
+ # options:
19
+ # :repository
20
+ # :index_file
21
+ #
22
+ def self.init(working_dir, opts = {})
23
+ opts = {
24
+ :working_directory => working_dir,
25
+ :repository => File.join(working_dir, '.git')
26
+ }.merge(opts)
27
+
28
+ FileUtils.mkdir_p(opts[:working_directory]) if opts[:working_directory] && !File.directory?(opts[:working_directory])
29
+
30
+ # run git_init there
31
+ Git::Lib.new(opts).init
32
+
33
+ self.new(opts)
34
+ end
35
+
36
+ # clones a git repository locally
37
+ #
38
+ # repository - http://repo.or.cz/w/sinatra.git
39
+ # name - sinatra
40
+ #
41
+ # options:
42
+ # :repository
43
+ #
44
+ # :bare
45
+ # or
46
+ # :working_directory
47
+ # :index_file
48
+ #
49
+ def self.clone(repository, name, opts = {})
50
+ # run git-clone
51
+ self.new(Git::Lib.new.clone(repository, name, opts))
52
+ end
53
+
54
+ def initialize(options = {})
55
+ if working_dir = options[:working_directory]
56
+ options[:repository] ||= File.join(working_dir, '.git')
57
+ options[:index] ||= File.join(working_dir, '.git', 'index')
58
+ end
59
+ if options[:log]
60
+ @logger = options[:log]
61
+ @logger.info("Starting Git")
62
+ else
63
+ @logger = nil
64
+ end
65
+
66
+ @working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
67
+ @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
68
+ @index = options[:index] ? Git::Index.new(options[:index], false) : nil
69
+ end
70
+
71
+
72
+ # returns a reference to the working directory
73
+ # @git.dir.path
74
+ # @git.dir.writeable?
75
+ def dir
76
+ @working_directory
77
+ end
78
+
79
+ # returns reference to the git repository directory
80
+ # @git.dir.path
81
+ def repo
82
+ @repository
83
+ end
84
+
85
+ # returns reference to the git index file
86
+ def index
87
+ @index
88
+ end
89
+
90
+
91
+ def set_working(work_dir, check = true)
92
+ @lib = nil
93
+ @working_directory = Git::WorkingDirectory.new(work_dir.to_s, check)
94
+ end
95
+
96
+ def set_index(index_file, check = true)
97
+ @lib = nil
98
+ @index = Git::Index.new(index_file.to_s, check)
99
+ end
100
+
101
+ # changes current working directory for a block
102
+ # to the git working directory
103
+ #
104
+ # example
105
+ # @git.chdir do
106
+ # # write files
107
+ # @git.add
108
+ # @git.commit('message')
109
+ # end
110
+ def chdir # :yields: the Git::Path
111
+ Dir.chdir(dir.path) do
112
+ yield dir.path
113
+ end
114
+ end
115
+
116
+ # returns the repository size in bytes
117
+ def repo_size
118
+ size = 0
119
+ Dir.chdir(repo.path) do
120
+ (size, dot) = `du -s`.chomp.split
121
+ end
122
+ size.to_i
123
+ end
124
+
125
+ #g.config('user.name', 'Scott Chacon') # sets value
126
+ #g.config('user.email', 'email@email.com') # sets value
127
+ #g.config('user.name') # returns 'Scott Chacon'
128
+ #g.config # returns whole config hash
129
+ def config(name = nil, value = nil)
130
+ if(name && value)
131
+ # set value
132
+ lib.config_set(name, value)
133
+ elsif (name)
134
+ # return value
135
+ lib.config_get(name)
136
+ else
137
+ # return hash
138
+ lib.config_list
139
+ end
140
+ end
141
+
142
+ # factory methods
143
+
144
+ # returns a Git::Object of the appropriate type
145
+ # you can also call @git.gtree('tree'), but that's
146
+ # just for readability. If you call @git.gtree('HEAD') it will
147
+ # still return a Git::Object::Commit object.
148
+ #
149
+ # @git.object calls a factory method that will run a rev-parse
150
+ # on the objectish and determine the type of the object and return
151
+ # an appropriate object for that type
152
+ def object(objectish)
153
+ Git::Object.new(self, objectish)
154
+ end
155
+
156
+ def gtree(objectish)
157
+ Git::Object.new(self, objectish, 'tree')
158
+ end
159
+
160
+ def gcommit(objectish)
161
+ Git::Object.new(self, objectish, 'commit')
162
+ end
163
+
164
+ def gblob(objectish)
165
+ Git::Object.new(self, objectish, 'blob')
166
+ end
167
+
168
+ # returns a Git::Log object with count commits
169
+ def log(count = 30)
170
+ Git::Log.new(self, count)
171
+ end
172
+
173
+ # returns a Git::Status object
174
+ def status
175
+ Git::Status.new(self)
176
+ end
177
+
178
+ # returns a Git::Branches object of all the Git::Branch objects for this repo
179
+ def branches
180
+ Git::Branches.new(self)
181
+ end
182
+
183
+ # returns a Git::Branch object for branch_name
184
+ def branch(branch_name = 'master')
185
+ Git::Branch.new(self, branch_name)
186
+ end
187
+
188
+ # returns +true+ if the branch exists locally
189
+ def is_local_branch?(branch)
190
+ branch_names = self.branches.local.map {|b| b.name}
191
+ branch_names.include?(branch)
192
+ end
193
+
194
+ # returns +true+ if the branch exists remotely
195
+ def is_remote_branch?(branch)
196
+ branch_names = self.branches.local.map {|b| b.name}
197
+ branch_names.include?(branch)
198
+ end
199
+
200
+ # returns +true+ if the branch exists
201
+ def is_branch?(branch)
202
+ branch_names = self.branches.map {|b| b.name}
203
+ branch_names.include?(branch)
204
+ end
205
+
206
+ # returns a Git::Remote object
207
+ def remote(remote_name = 'origin')
208
+ Git::Remote.new(self, remote_name)
209
+ end
210
+
211
+ # this is a convenience method for accessing the class that wraps all the
212
+ # actual 'git' forked system calls. At some point I hope to replace the Git::Lib
213
+ # class with one that uses native methods or libgit C bindings
214
+ def lib
215
+ @lib ||= Git::Lib.new(self, @logger)
216
+ end
217
+
218
+ # will run a grep for 'string' on the HEAD of the git repository
219
+ #
220
+ # to be more surgical in your grep, you can call grep() off a specific
221
+ # git object. for example:
222
+ #
223
+ # @git.object("v2.3").grep('TODO')
224
+ #
225
+ # in any case, it returns a hash of arrays of the type:
226
+ # hsh[tree-ish] = [[line_no, match], [line_no, match2]]
227
+ # hsh[tree-ish] = [[line_no, match], [line_no, match2]]
228
+ #
229
+ # so you might use it like this:
230
+ #
231
+ # @git.grep("TODO").each do |sha, arr|
232
+ # puts "in blob #{sha}:"
233
+ # arr.each do |match|
234
+ # puts "\t line #{match[0]}: '#{match[1]}'"
235
+ # end
236
+ # end
237
+ def grep(string, path_limiter = nil, opts = {})
238
+ self.object('HEAD').grep(string, path_limiter, opts)
239
+ end
240
+
241
+ # returns a Git::Diff object
242
+ def diff(objectish = 'HEAD', obj2 = nil)
243
+ Git::Diff.new(self, objectish, obj2)
244
+ end
245
+
246
+ # adds files from the working directory to the git repository
247
+ def add(path = '.')
248
+ self.lib.add(path)
249
+ end
250
+
251
+ # removes file(s) from the git repository
252
+ def remove(path = '.', opts = {})
253
+ self.lib.remove(path, opts)
254
+ end
255
+
256
+ # resets the working directory to the provided commitish
257
+ def reset(commitish = nil, opts = {})
258
+ self.lib.reset(commitish, opts)
259
+ end
260
+
261
+ # resets the working directory to the commitish with '--hard'
262
+ def reset_hard(commitish = nil, opts = {})
263
+ opts = {:hard => true}.merge(opts)
264
+ self.lib.reset(commitish, opts)
265
+ end
266
+
267
+ # commits all pending changes in the index file to the git repository
268
+ #
269
+ # options:
270
+ # :add_all
271
+ # :allow_empty
272
+ # :author
273
+ def commit(message, opts = {})
274
+ self.lib.commit(message, opts)
275
+ end
276
+
277
+ # commits all pending changes in the index file to the git repository,
278
+ # but automatically adds all modified files without having to explicitly
279
+ # calling @git.add() on them.
280
+ def commit_all(message, opts = {})
281
+ opts = {:add_all => true}.merge(opts)
282
+ self.lib.commit(message, opts)
283
+ end
284
+
285
+ # checks out a branch as the new git working directory
286
+ def checkout(branch = 'master', opts = {})
287
+ self.lib.checkout(branch, opts)
288
+ end
289
+
290
+ # checks out an old version of a file
291
+ def checkout_file(version, file)
292
+ self.lib.checkout_file(version,file)
293
+ end
294
+
295
+ # fetches changes from a remote branch - this does not modify the working directory,
296
+ # it just gets the changes from the remote if there are any
297
+ def fetch(remote = 'origin')
298
+ self.lib.fetch(remote)
299
+ end
300
+
301
+ # pushes changes to a remote repository - easiest if this is a cloned repository,
302
+ # otherwise you may have to run something like this first to setup the push parameters:
303
+ #
304
+ # @git.config('remote.remote-name.push', 'refs/heads/master:refs/heads/master')
305
+ #
306
+ def push(remote = 'origin', branch = 'master', tags = false)
307
+ self.lib.push(remote, branch, tags)
308
+ end
309
+
310
+ # merges one or more branches into the current working branch
311
+ #
312
+ # you can specify more than one branch to merge by passing an array of branches
313
+ def merge(branch, message = 'merge')
314
+ self.lib.merge(branch, message)
315
+ end
316
+
317
+ # iterates over the files which are unmerged
318
+ def each_conflict(&block) # :yields: file, your_version, their_version
319
+ self.lib.conflicts(&block)
320
+ end
321
+
322
+ # fetches a branch from a remote and merges it into the current working branch
323
+ def pull(remote = 'origin', branch = 'master', message = 'origin pull')
324
+ fetch(remote)
325
+ merge(branch, message)
326
+ end
327
+
328
+ # returns an array of Git:Remote objects
329
+ def remotes
330
+ self.lib.remotes.map { |r| Git::Remote.new(self, r) }
331
+ end
332
+
333
+ # adds a new remote to this repository
334
+ # url can be a git url or a Git::Base object if it's a local reference
335
+ #
336
+ # @git.add_remote('scotts_git', 'git://repo.or.cz/rubygit.git')
337
+ # @git.fetch('scotts_git')
338
+ # @git.merge('scotts_git/master')
339
+ #
340
+ def add_remote(name, url, opts = {})
341
+ url = url.repo.path if url.is_a?(Git::Base)
342
+ self.lib.remote_add(name, url, opts)
343
+ Git::Remote.new(self, name)
344
+ end
345
+
346
+ # returns an array of all Git::Tag objects for this repository
347
+ def tags
348
+ self.lib.tags.map { |r| tag(r) }
349
+ end
350
+
351
+ # returns a Git::Tag object
352
+ def tag(tag_name)
353
+ Git::Object.new(self, tag_name, 'tag', true)
354
+ end
355
+
356
+ # creates a new git tag (Git::Tag)
357
+ def add_tag(tag_name)
358
+ self.lib.tag(tag_name)
359
+ tag(tag_name)
360
+ end
361
+
362
+ # creates an archive file of the given tree-ish
363
+ def archive(treeish, file = nil, opts = {})
364
+ self.object(treeish).archive(file, opts)
365
+ end
366
+
367
+ # repacks the repository
368
+ def repack
369
+ self.lib.repack
370
+ end
371
+
372
+ def gc
373
+ self.lib.gc
374
+ end
375
+
376
+ def apply(file)
377
+ if File.exists?(file)
378
+ self.lib.apply(file)
379
+ end
380
+ end
381
+
382
+ def apply_mail(file)
383
+ self.lib.apply_mail(file) if File.exists?(file)
384
+ end
385
+
386
+ ## LOWER LEVEL INDEX OPERATIONS ##
387
+
388
+ def with_index(new_index) # :yields: new_index
389
+ old_index = @index
390
+ set_index(new_index, false)
391
+ return_value = yield @index
392
+ set_index(old_index)
393
+ return_value
394
+ end
395
+
396
+ def with_temp_index &blk
397
+ tempfile = Tempfile.new('temp-index')
398
+ temp_path = tempfile.path
399
+ tempfile.unlink
400
+ with_index(temp_path, &blk)
401
+ end
402
+
403
+ def checkout_index(opts = {})
404
+ self.lib.checkout_index(opts)
405
+ end
406
+
407
+ def read_tree(treeish, opts = {})
408
+ self.lib.read_tree(treeish, opts)
409
+ end
410
+
411
+ def write_tree
412
+ self.lib.write_tree
413
+ end
414
+
415
+ def commit_tree(tree = nil, opts = {})
416
+ Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts))
417
+ end
418
+
419
+ def write_and_commit_tree(opts = {})
420
+ tree = write_tree
421
+ commit_tree(tree, opts)
422
+ end
423
+
424
+ def update_ref(branch, commit)
425
+ branch(branch).update_ref(commit)
426
+ end
427
+
428
+
429
+ def ls_files(location=nil)
430
+ self.lib.ls_files(location)
431
+ end
432
+
433
+ def with_working(work_dir) # :yields: the Git::WorkingDirectory
434
+ return_value = false
435
+ old_working = @working_directory
436
+ set_working(work_dir)
437
+ Dir.chdir work_dir do
438
+ return_value = yield @working_directory
439
+ end
440
+ set_working(old_working)
441
+ return_value
442
+ end
443
+
444
+ def with_temp_working &blk
445
+ tempfile = Tempfile.new("temp-workdir")
446
+ temp_dir = tempfile.path
447
+ tempfile.unlink
448
+ Dir.mkdir(temp_dir, 0700)
449
+ with_working(temp_dir, &blk)
450
+ end
451
+
452
+
453
+ # runs git rev-parse to convert the objectish to a full sha
454
+ #
455
+ # @git.revparse("HEAD^^")
456
+ # @git.revparse('v2.4^{tree}')
457
+ # @git.revparse('v2.4:/doc/index.html')
458
+ #
459
+ def revparse(objectish)
460
+ self.lib.revparse(objectish)
461
+ end
462
+
463
+ def ls_tree(objectish)
464
+ self.lib.ls_tree(objectish)
465
+ end
466
+
467
+ def cat_file(objectish)
468
+ self.lib.object_contents(objectish)
469
+ end
470
+
471
+ # returns the name of the branch the working directory is currently on
472
+ def current_branch
473
+ self.lib.branch_current
474
+ end
475
+
476
+
477
+ end
478
+
479
+ end
data/lib/git/branch.rb ADDED
@@ -0,0 +1,104 @@
1
+ module Git
2
+ class Branch < Path
3
+
4
+ attr_accessor :full, :remote, :name
5
+
6
+ def initialize(base, name)
7
+ @remote = nil
8
+ @full = name
9
+ @base = base
10
+ @gcommit = nil
11
+ @stashes = nil
12
+
13
+ parts = name.split('/')
14
+ if parts[1]
15
+ @remote = Git::Remote.new(@base, parts[0])
16
+ @name = parts[1]
17
+ else
18
+ @name = parts[0]
19
+ end
20
+ end
21
+
22
+ def gcommit
23
+ @gcommit ||= @base.gcommit(@full)
24
+ @gcommit
25
+ end
26
+
27
+ def stashes
28
+ @stashes ||= Git::Stashes.new(@base)
29
+ end
30
+
31
+ def checkout
32
+ check_if_create
33
+ @base.checkout(@full)
34
+ end
35
+
36
+ def archive(file, opts = {})
37
+ @base.lib.archive(@full, file, opts)
38
+ end
39
+
40
+ # g.branch('new_branch').in_branch do
41
+ # # create new file
42
+ # # do other stuff
43
+ # return true # auto commits and switches back
44
+ # end
45
+ def in_branch (message = 'in branch work')
46
+ old_current = @base.lib.branch_current
47
+ checkout
48
+ if yield
49
+ @base.commit_all(message)
50
+ else
51
+ @base.reset_hard
52
+ end
53
+ @base.checkout(old_current)
54
+ end
55
+
56
+ def create
57
+ check_if_create
58
+ end
59
+
60
+ def delete
61
+ @base.lib.branch_delete(@name)
62
+ end
63
+
64
+ def current
65
+ determine_current
66
+ end
67
+
68
+ def merge(branch = nil, message = nil)
69
+ if branch
70
+ in_branch do
71
+ @base.merge(branch, message)
72
+ false
73
+ end
74
+ # merge a branch into this one
75
+ else
76
+ # merge this branch into the current one
77
+ @base.merge(@name)
78
+ end
79
+ end
80
+
81
+ def update_ref(commit)
82
+ @base.lib.update_ref(@full, commit)
83
+ end
84
+
85
+ def to_a
86
+ [@full]
87
+ end
88
+
89
+ def to_s
90
+ @full
91
+ end
92
+
93
+ private
94
+
95
+ def check_if_create
96
+ @base.lib.branch_new(@name) rescue nil
97
+ end
98
+
99
+ def determine_current
100
+ @base.lib.branch_current == @name
101
+ end
102
+
103
+ end
104
+ end