vclog 1.1 → 1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +20 -0
- data/MANIFEST +5 -1
- data/TODO +12 -0
- data/bin/vclog +1 -1
- data/lib/vclog/change.rb +108 -0
- data/lib/vclog/changelog.rb +136 -146
- data/lib/vclog/cli.rb +220 -0
- data/lib/vclog/history.rb +314 -0
- data/lib/vclog/release.rb +23 -0
- data/lib/vclog/tag.rb +54 -0
- data/lib/vclog/vcs.rb +93 -16
- data/lib/vclog/vcs/git.rb +52 -21
- data/lib/vclog/vcs/svn.rb +66 -18
- data/meta/version +1 -1
- metadata +7 -3
- data/lib/vclog/command.rb +0 -168
@@ -0,0 +1,23 @@
|
|
1
|
+
module VCLog
|
2
|
+
|
3
|
+
#
|
4
|
+
class Release
|
5
|
+
attr :tag
|
6
|
+
attr :changes
|
7
|
+
#
|
8
|
+
def initialize(tag, changes)
|
9
|
+
@tag = tag
|
10
|
+
@changes = changes
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{ :tag => tag.to_h, :changes => changes }
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json
|
18
|
+
to_h.to_json
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
data/lib/vclog/tag.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module VCLog
|
2
|
+
|
3
|
+
class Tag
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :date
|
6
|
+
attr_accessor :author
|
7
|
+
attr_accessor :message
|
8
|
+
|
9
|
+
def initialize(name, date, author, message)
|
10
|
+
self.name = name
|
11
|
+
self.date = date
|
12
|
+
self.author = author
|
13
|
+
self.message = message
|
14
|
+
end
|
15
|
+
|
16
|
+
def name=(name)
|
17
|
+
@name = name.strip
|
18
|
+
end
|
19
|
+
|
20
|
+
def author=(author)
|
21
|
+
@author = author.strip
|
22
|
+
end
|
23
|
+
|
24
|
+
def date=(date)
|
25
|
+
case date
|
26
|
+
when Time
|
27
|
+
@date = date
|
28
|
+
else
|
29
|
+
@date = Time.parse(date.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def message=(msg)
|
34
|
+
@message = msg.strip
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :tagger, :author
|
38
|
+
alias_method :tagger=, :author=
|
39
|
+
|
40
|
+
def to_json
|
41
|
+
to_h.to_json
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_h
|
45
|
+
{
|
46
|
+
:name => name,
|
47
|
+
:date => date,
|
48
|
+
:author => author,
|
49
|
+
:message => message
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/vclog/vcs.rb
CHANGED
@@ -2,10 +2,9 @@ module VCLog
|
|
2
2
|
|
3
3
|
require 'time'
|
4
4
|
require 'vclog/changelog'
|
5
|
-
require 'vclog/
|
6
|
-
require 'vclog/
|
7
|
-
|
8
|
-
#require 'vclog/vcs/darcs'
|
5
|
+
require 'vclog/history'
|
6
|
+
require 'vclog/change'
|
7
|
+
require 'vclog/tag'
|
9
8
|
|
10
9
|
# TODO: Might we have a NO-VCS changelog based on
|
11
10
|
# LOG: entries in source files?
|
@@ -13,29 +12,102 @@ module VCLog
|
|
13
12
|
# = Version Control System
|
14
13
|
class VCS
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
raise ArgumentError, "Not a recognized version control system." unless @type
|
15
|
+
def self.factory(root=nil)
|
16
|
+
root = root || Dir.pwd
|
17
|
+
type = read_type(root)
|
18
|
+
raise ArgumentError, "Not a recognized version control system." unless type
|
19
|
+
VCS.const_get(type.upcase).new(root)
|
22
20
|
end
|
23
21
|
|
24
|
-
def read_type
|
22
|
+
def self.read_type(root)
|
25
23
|
dir = nil
|
26
|
-
Dir.chdir(
|
24
|
+
Dir.chdir(root) do
|
27
25
|
dir = Dir.glob("{.svn,.git,.hg,_darcs}").first
|
28
26
|
end
|
29
27
|
dir[1..-1] if dir
|
30
28
|
end
|
31
29
|
|
32
|
-
|
33
|
-
|
30
|
+
attr :root
|
31
|
+
|
32
|
+
#
|
33
|
+
def initialize(root)
|
34
|
+
@root = File.expand_path(root)
|
35
|
+
end
|
36
|
+
|
37
|
+
def tags
|
38
|
+
@tags ||= extract_tags.map{ |t| Tag===t ? t : Tag.new(*t) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def changes
|
42
|
+
@changes ||= extract_changes.map{ |c| Change===c ? c : Change.new(*c) }
|
34
43
|
end
|
35
44
|
|
36
45
|
#
|
37
|
-
def
|
38
|
-
|
46
|
+
def extract_tags
|
47
|
+
raise "Not Implemented"
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
def extract_changes
|
52
|
+
raise "Not Implemented"
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
def changelog
|
57
|
+
ChangeLog.new(changes)
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
def history(opts={})
|
62
|
+
@history ||= History.new(self, opts)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Provides a bumped version number.
|
66
|
+
def bump(part=nil)
|
67
|
+
return part unless ['major', 'minor', 'patch', ''].include?(part.to_s)
|
68
|
+
|
69
|
+
if tags.last
|
70
|
+
v = tags.last.name # TODO: ensure the latest version
|
71
|
+
else
|
72
|
+
v = '0.0.0'
|
73
|
+
end
|
74
|
+
v = v.split(/\W/) # TODO: preserve split chars
|
75
|
+
case part.to_s
|
76
|
+
when 'major'
|
77
|
+
v[0] = v[0].succ
|
78
|
+
(1..(v.size-1)).each{ |i| v[i] = '0' }
|
79
|
+
v.join('.')
|
80
|
+
when 'minor'
|
81
|
+
v[1] = '0' unless v[1]
|
82
|
+
v[1] = v[1].succ
|
83
|
+
(2..(v.size-1)).each{ |i| v[i] = '0' }
|
84
|
+
v.join('.')
|
85
|
+
when 'patch'
|
86
|
+
v[1] = '0' unless v[1]
|
87
|
+
v[2] = '0' unless v[2]
|
88
|
+
v[2] = v[2].succ
|
89
|
+
(3..(v.size-1)).each{ |i| v[i] = '0' }
|
90
|
+
v.join('.')
|
91
|
+
else
|
92
|
+
v[-1] = '0' unless v[-1]
|
93
|
+
v[-1] = v[-1].succ
|
94
|
+
v.join('.')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Looks for a "[type]" indicator at the end of the message.
|
101
|
+
def split_type(note)
|
102
|
+
note = note.strip
|
103
|
+
if md = /\A.*?\[(.*?)\]\s*$/.match(note)
|
104
|
+
t = md[1].strip.downcase
|
105
|
+
n = note.sub(/\[#{md[1]}\]\s*$/, "")
|
106
|
+
else
|
107
|
+
n, t = note, nil
|
108
|
+
end
|
109
|
+
n.gsub!(/^\s*?\n/m,'') # remove blank lines
|
110
|
+
return n, t
|
39
111
|
end
|
40
112
|
|
41
113
|
=begin
|
@@ -78,5 +150,10 @@ module VCLog
|
|
78
150
|
|
79
151
|
end
|
80
152
|
|
153
|
+
require 'vclog/vcs/svn'
|
154
|
+
require 'vclog/vcs/git'
|
155
|
+
#require 'vclog/vcs/hg'
|
156
|
+
#require 'vclog/vcs/darcs'
|
157
|
+
|
81
158
|
end
|
82
159
|
|
data/lib/vclog/vcs/git.rb
CHANGED
@@ -1,30 +1,33 @@
|
|
1
1
|
module VCLog
|
2
2
|
|
3
|
-
|
3
|
+
require 'vclog/vcs'
|
4
4
|
|
5
|
-
|
6
|
-
###
|
7
|
-
class GIT
|
5
|
+
class VCS
|
8
6
|
|
9
|
-
|
7
|
+
# = GIT Adapter
|
8
|
+
#
|
9
|
+
class GIT < VCS
|
10
10
|
|
11
|
-
|
11
|
+
#def initialize
|
12
|
+
#end
|
12
13
|
|
13
14
|
#
|
14
|
-
def changelog
|
15
|
-
|
16
|
-
end
|
15
|
+
#def changelog
|
16
|
+
# @changelog ||= ChangeLog.new(changes)
|
17
|
+
#end
|
17
18
|
|
18
|
-
#
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
changelog ||= `git-log`.strip
|
19
|
+
#
|
20
|
+
#def history(opts={})
|
21
|
+
# @history ||= History.new(self, opts)
|
22
|
+
#end
|
23
23
|
|
24
|
+
# Collect changes.
|
25
|
+
#
|
26
|
+
def extract_changes
|
27
|
+
list = []
|
28
|
+
changelog = `git-log`.strip
|
24
29
|
changes = changelog.split(/^commit/m)
|
25
|
-
|
26
30
|
changes.shift # throw the first (empty) entry away
|
27
|
-
|
28
31
|
changes.each do |text|
|
29
32
|
date, who, rev, msg = nil, nil, nil, []
|
30
33
|
text.each_line do |line|
|
@@ -40,15 +43,43 @@ module VCLog
|
|
40
43
|
msg << line.strip
|
41
44
|
end
|
42
45
|
end
|
43
|
-
|
46
|
+
msg = msg.join("\n")
|
47
|
+
msg, type = *split_type(msg)
|
48
|
+
list << [rev, date, who, msg, type]
|
44
49
|
end
|
50
|
+
list
|
51
|
+
end
|
45
52
|
|
46
|
-
|
53
|
+
# Collect tags.
|
54
|
+
#
|
55
|
+
# `git show 1.0` produces:
|
56
|
+
#
|
57
|
+
# tag 1.0
|
58
|
+
# Tagger: 7rans <transfire@gmail.com>
|
59
|
+
# Date: Sun Oct 25 09:27:58 2009 -0400
|
60
|
+
#
|
61
|
+
# version 1.0
|
62
|
+
# commit
|
63
|
+
# ...
|
64
|
+
#
|
65
|
+
def extract_tags
|
66
|
+
list = []
|
67
|
+
tags = `git tag -l`
|
68
|
+
tags.split(/\s+/).each do |tag|
|
69
|
+
info = `git show #{tag}`
|
70
|
+
md = /\Atag(.*?)\n(.*?)^commit/m.match(info)
|
71
|
+
who, date, *msg = *md[2].split(/\n/)
|
72
|
+
who = who.split(':')[1].strip
|
73
|
+
date = date[date.index(':')+1..-1].strip
|
74
|
+
msg = msg.join("\n")
|
75
|
+
list << [tag, date, who, msg]
|
76
|
+
end
|
77
|
+
list
|
47
78
|
end
|
48
79
|
|
49
|
-
end
|
80
|
+
end#class GIT
|
50
81
|
|
51
|
-
end
|
82
|
+
end#class VCS
|
52
83
|
|
53
|
-
end
|
84
|
+
end#module VCLog
|
54
85
|
|
data/lib/vclog/vcs/svn.rb
CHANGED
@@ -4,26 +4,18 @@ module VCLog
|
|
4
4
|
|
5
5
|
# = SVN
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# SVN's raw log format:
|
8
8
|
#
|
9
9
|
# ------------------------------------------------------------------------
|
10
10
|
# r34 | transami | 2006-08-02 22:10:11 -0400 (Wed, 02 Aug 2006) | 2 lines
|
11
11
|
#
|
12
12
|
# change foo to work better
|
13
13
|
#
|
14
|
-
class SVN
|
14
|
+
class SVN < VCS
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
###
|
20
|
-
def changelog
|
21
|
-
@changelog ||= generate_changelog
|
22
|
-
end
|
23
|
-
|
24
|
-
###
|
25
|
-
def generate_changelog
|
26
|
-
log = Changelog.new
|
16
|
+
#
|
17
|
+
def extract_changes
|
18
|
+
log = []
|
27
19
|
|
28
20
|
txt = `svn log`.strip
|
29
21
|
|
@@ -44,15 +36,71 @@ module VCLog
|
|
44
36
|
|
45
37
|
date = Time.parse(date)
|
46
38
|
|
47
|
-
|
39
|
+
msg, type = *split_type(msg)
|
40
|
+
|
41
|
+
log << [rev, date, who, msg, type]
|
48
42
|
end
|
49
43
|
|
50
|
-
|
44
|
+
log
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
def extract_tags
|
49
|
+
list = []
|
50
|
+
tagdir = tag_directory
|
51
|
+
|
52
|
+
if tagdir
|
53
|
+
tags = Dir.entries(tagdir).select{ |e| e.index('.') != 0 && e =~ /\d(.*)$/ }
|
54
|
+
else
|
55
|
+
tags = []
|
56
|
+
end
|
57
|
+
|
58
|
+
tags.each do |path|
|
59
|
+
dir = File.join(tagdir, path)
|
60
|
+
|
61
|
+
info = `svn info #{dir}`
|
62
|
+
info = YAML.load(info)
|
63
|
+
md = /(\d.*)$/.match(info['Path'])
|
64
|
+
name = md ? md[1] : path
|
65
|
+
date = info['Last Changed Date']
|
66
|
+
who = info['Last Changed Author']
|
67
|
+
rev = info['Revision']
|
68
|
+
|
69
|
+
commit = `svn log -r BASE #{dir}`
|
70
|
+
msg = commit.lines.to_a[2..-2].join("\n").strip
|
71
|
+
|
72
|
+
list << [name, date, who, msg]
|
73
|
+
end
|
74
|
+
list
|
75
|
+
end
|
76
|
+
|
77
|
+
# This isn't perfect, but is there really anyway for it to be?
|
78
|
+
# It ascends up the current directory tree looking for the
|
79
|
+
# best candidate for a tags directory.
|
80
|
+
def tag_directory
|
81
|
+
fnd = nil
|
82
|
+
dir = root
|
83
|
+
while dir != '/' do
|
84
|
+
entries = Dir.entries(dir)
|
85
|
+
if entries.include?('.svn')
|
86
|
+
if entries.include?('tags')
|
87
|
+
break(fnd = File.join(dir, 'tags'))
|
88
|
+
else
|
89
|
+
entries = entries.reject{ |e| e.index('.') == 0 }
|
90
|
+
entries = entries.reject{ |e| e !~ /\d$/ }
|
91
|
+
break(fnd = dir) unless entries.empty?
|
92
|
+
end
|
93
|
+
else
|
94
|
+
break(fnd=nil)
|
95
|
+
end
|
96
|
+
dir = File.dirname(dir)
|
97
|
+
end
|
98
|
+
fnd
|
51
99
|
end
|
52
100
|
|
53
|
-
end
|
101
|
+
end#class SVN
|
54
102
|
|
55
|
-
end
|
103
|
+
end#class VCS
|
56
104
|
|
57
|
-
end
|
105
|
+
end#module VCLog
|
58
106
|
|
data/meta/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vclog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "1.
|
4
|
+
version: "1.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Sawyer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-26 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -41,9 +41,13 @@ files:
|
|
41
41
|
- README
|
42
42
|
- TODO
|
43
43
|
- bin/vclog
|
44
|
+
- lib/vclog/change.rb
|
44
45
|
- lib/vclog/changelog.rb
|
45
|
-
- lib/vclog/
|
46
|
+
- lib/vclog/cli.rb
|
46
47
|
- lib/vclog/facets.rb
|
48
|
+
- lib/vclog/history.rb
|
49
|
+
- lib/vclog/release.rb
|
50
|
+
- lib/vclog/tag.rb
|
47
51
|
- lib/vclog/vcs.rb
|
48
52
|
- lib/vclog/vcs/darcs.rb
|
49
53
|
- lib/vclog/vcs/git.rb
|