vclog 1.1 → 1.2
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/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
|