historian 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/.gitignore +5 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +35 -0
- data/LICENSE +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +149 -0
- data/Rakefile +2 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +1 -0
- data/bin/historian +12 -0
- data/historian.gemspec +28 -0
- data/lib/historian.rb +12 -0
- data/lib/historian/cli.rb +84 -0
- data/lib/historian/commit_message.rb +40 -0
- data/lib/historian/configuration.rb +10 -0
- data/lib/historian/git.rb +189 -0
- data/lib/historian/history_file.rb +209 -0
- data/lib/historian/version.rb +3 -0
- data/spec/example_history.txt +24 -0
- data/spec/fixtures/after_0_0_2 +16 -0
- data/spec/fixtures/after_0_0_2_changelog +6 -0
- data/spec/fixtures/after_0_0_2_history +17 -0
- data/spec/fixtures/all_types_history +17 -0
- data/spec/fixtures/anonymous_release_log +7 -0
- data/spec/fixtures/arbitrary_text +21 -0
- data/spec/fixtures/courageous_camel_history +13 -0
- data/spec/fixtures/courageous_camel_release_log +7 -0
- data/spec/fixtures/empty +0 -0
- data/spec/fixtures/invalid_significance +17 -0
- data/spec/fixtures/missing_significance +16 -0
- data/spec/fixtures/normal +10 -0
- data/spec/fixtures/normal_changelog_after_major +11 -0
- data/spec/fixtures/normal_changelog_after_minor +8 -0
- data/spec/fixtures/normal_history_after_major +17 -0
- data/spec/fixtures/normal_history_after_minor +14 -0
- data/spec/fixtures/patch_on_nothing +5 -0
- data/spec/fixtures/release_on_nothing +1 -0
- data/spec/fixtures/second_patch_on_nothing +6 -0
- data/spec/historian/cli_spec.rb +210 -0
- data/spec/historian/commit_message_spec.rb +95 -0
- data/spec/historian/git_spec.rb +199 -0
- data/spec/historian/history_file_spec.rb +225 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/fixture_helper.rb +8 -0
- data/spec/support/git_helpers.rb +53 -0
- data/spec/support/history_file_matchers.rb +52 -0
- metadata +189 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Historian::Git do
|
4
|
+
include GitHelpers
|
5
|
+
|
6
|
+
before do
|
7
|
+
create_test_repo
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { @git }
|
11
|
+
|
12
|
+
describe "#bundle_history_file" do
|
13
|
+
before do
|
14
|
+
@history = history_for_repo :courageous_camel_history
|
15
|
+
@git = Historian::Git.new(repo_directory, @history)
|
16
|
+
end
|
17
|
+
|
18
|
+
subject { @git }
|
19
|
+
|
20
|
+
it "amends the previous commit to include changes to the history file" do
|
21
|
+
modified?(@history_file).should be_true
|
22
|
+
lambda { subject.bundle_history_file }.should_not change(self, :commits_count)
|
23
|
+
modified?(@history_file).should be_false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#install_hook" do
|
28
|
+
before do
|
29
|
+
@git = Historian::Git.new(repo_directory, nil)
|
30
|
+
@hook = "foo-bar"
|
31
|
+
@hook_sym = :foo_bar
|
32
|
+
@hook_wrapper = File.join(repo_directory, ".git", "hooks", @hook)
|
33
|
+
@hook_script = File.join(repo_directory, ".git", "hooks", @hook + ".d", "historian")
|
34
|
+
end
|
35
|
+
|
36
|
+
shared_examples_for "creating the hook sub-script" do
|
37
|
+
it "creates the hook script" do
|
38
|
+
File.exists?(@hook_script).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "makes the hook script executable" do
|
42
|
+
File.stat(@hook_script).should be_executable
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "contents" do
|
46
|
+
before do
|
47
|
+
@contents = File.readlines @hook_script
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be a bash script" do
|
51
|
+
@contents.first.start_with?("#!/bin/bash").should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should invoke the hook exactly once" do
|
55
|
+
@contents.grep("historian #{@hook_sym} $@\n").should have(1).match
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
shared_examples_for "creating the hook wrapper" do
|
61
|
+
it "creates a directory for hooks scripts" do
|
62
|
+
File.directory?(File.dirname @hook_script).should be_true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "creates a wrapper script" do
|
66
|
+
File.exists?(@hook_wrapper).should be_true
|
67
|
+
end
|
68
|
+
|
69
|
+
it "makes the hook script executable" do
|
70
|
+
File.stat(@hook_wrapper).should be_executable
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "contents" do
|
74
|
+
before do
|
75
|
+
@contents = File.readlines @hook_wrapper
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should be a bash script" do
|
79
|
+
@contents.first.start_with?("#!/bin/bash").should be_true
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should invoke all the scripts in the hook script directory" do
|
83
|
+
invoke = /for S in .*#{@hook}.d/
|
84
|
+
@contents.grep(invoke).should have(1).match
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with no existing hook" do
|
90
|
+
before do
|
91
|
+
@result = @git.install_hook(@hook_sym)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns :created" do
|
95
|
+
@result.should eq(:created)
|
96
|
+
end
|
97
|
+
|
98
|
+
it_behaves_like "creating the hook wrapper"
|
99
|
+
it_behaves_like "creating the hook sub-script"
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when the hook is already installed" do
|
103
|
+
before do
|
104
|
+
@result = @git.install_hook(@hook_sym)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "rewrites the hook file" do
|
108
|
+
File.should_receive(:open).with(@hook_script, /w/)
|
109
|
+
@git.install_hook @hook_sym
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns :exists" do
|
113
|
+
@git.install_hook(@hook_sym).should eq(:exists)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when another hook is already installed" do
|
118
|
+
before do
|
119
|
+
@original_contents = "the original script!"
|
120
|
+
File.open(@hook_wrapper, "w") { |f| f.write @original_contents }
|
121
|
+
@result = @git.install_hook(@hook_sym)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "returns :adapted" do
|
125
|
+
@result.should eq(:adapted)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "copies the original hook file into the hook's script directory" do
|
129
|
+
new_location = File.join File.dirname(@hook_script), "original"
|
130
|
+
File.read(new_location).should eq(@original_contents)
|
131
|
+
end
|
132
|
+
|
133
|
+
it_behaves_like "creating the hook wrapper"
|
134
|
+
it_behaves_like "creating the hook sub-script"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "#tag_release" do
|
139
|
+
shared_examples_for "a tagged release" do
|
140
|
+
it "creates a new tag for the latest version" do
|
141
|
+
tag = "v" + @history.current_version
|
142
|
+
tags.should_not include(tag)
|
143
|
+
subject.tag_release
|
144
|
+
tags.should include(tag)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "annotates the tag with a short message including the version" do
|
148
|
+
subject.tag_release
|
149
|
+
commit_message_for_tag("v12.0.0").should match(/tagged v12.0.0 "Courageous Camel"/)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "annotates the tag with the changelog" do
|
153
|
+
subject.tag_release
|
154
|
+
commit_message_for_tag("v12.0.0").should include(fixture :courageous_camel_release_log)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "with a dirty history file" do
|
159
|
+
before do
|
160
|
+
@history = history_for_repo :courageous_camel_history
|
161
|
+
@history.update_history :minor => "some little thing"
|
162
|
+
@git = Historian::Git.new(repo_directory, @history)
|
163
|
+
end
|
164
|
+
|
165
|
+
subject { @git }
|
166
|
+
|
167
|
+
it "releases the history file if the changelog isn't empty" do
|
168
|
+
@history.should_receive :release
|
169
|
+
subject.tag_release
|
170
|
+
end
|
171
|
+
|
172
|
+
it "commits the history file if it has unstaged changes" do
|
173
|
+
subject.should_receive(:commit_history_changes).twice
|
174
|
+
subject.tag_release
|
175
|
+
end
|
176
|
+
|
177
|
+
it_behaves_like "a tagged release"
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "with a clean history file" do
|
181
|
+
before do
|
182
|
+
@history = history_for_repo :courageous_camel_history
|
183
|
+
run_git "add", @history.path
|
184
|
+
run_git "commit", "-m", "clean the history"
|
185
|
+
@git = Historian::Git.new(repo_directory, @history)
|
186
|
+
end
|
187
|
+
|
188
|
+
subject { @git }
|
189
|
+
|
190
|
+
it "does not commit the history file" do
|
191
|
+
subject.should_not_receive :commit_history_changes
|
192
|
+
subject.tag_release
|
193
|
+
end
|
194
|
+
|
195
|
+
it_behaves_like "a tagged release"
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Historian::HistoryFile do
|
4
|
+
def history(fixture_name)
|
5
|
+
StringIO.new(fixture fixture_name).tap do |io|
|
6
|
+
io.extend Historian::HistoryFile
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
before do
|
11
|
+
@io = StringIO.new ""
|
12
|
+
@io.extend Historian::HistoryFile
|
13
|
+
end
|
14
|
+
|
15
|
+
subject { @io }
|
16
|
+
|
17
|
+
describe "#release" do
|
18
|
+
it "should invoke update_history" do
|
19
|
+
subject.should_receive(:update_history).with(:release => true)
|
20
|
+
subject.release
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with no history" do
|
25
|
+
before do
|
26
|
+
@io = StringIO.new(fixture :empty)
|
27
|
+
@io.extend Historian::HistoryFile
|
28
|
+
end
|
29
|
+
subject {@io}
|
30
|
+
|
31
|
+
context "when not adding history" do
|
32
|
+
it { should have_current_version "0.0.0" }
|
33
|
+
it { should have_next_version "0.0.1" }
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when adding a patch to history" do
|
37
|
+
before do
|
38
|
+
@io.update_history :patch => "bugfix #1"
|
39
|
+
end
|
40
|
+
|
41
|
+
it { should have_current_version "0.0.0" }
|
42
|
+
it { should have_next_version "0.0.1" }
|
43
|
+
|
44
|
+
it { should have_history_like :patch_on_nothing }
|
45
|
+
it { should have_changelog_like :patch_on_nothing }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when triggering a release" do
|
49
|
+
before do
|
50
|
+
Time.stub_chain :now, :strftime => "2010/12/12"
|
51
|
+
@io.update_history :release => "Addled Adder"
|
52
|
+
end
|
53
|
+
|
54
|
+
it { should have_current_version "0.0.1" }
|
55
|
+
it { should have_next_version "0.0.2" }
|
56
|
+
it { should have_history_like :release_on_nothing }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with unreleased history" do
|
61
|
+
before do
|
62
|
+
@io = StringIO.new(fixture :patch_on_nothing)
|
63
|
+
@io.extend Historian::HistoryFile
|
64
|
+
end
|
65
|
+
subject {@io}
|
66
|
+
|
67
|
+
context "when adding a patch to history" do
|
68
|
+
before do
|
69
|
+
@io.update_history :patch => "bugfix #2"
|
70
|
+
end
|
71
|
+
|
72
|
+
it { should have_current_version "0.0.0" }
|
73
|
+
it { should have_next_version "0.0.1" }
|
74
|
+
|
75
|
+
it { should have_history_like :second_patch_on_nothing }
|
76
|
+
it { should have_changelog_like :second_patch_on_nothing }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "with unreleased and a 0.0.2 release" do
|
81
|
+
before do
|
82
|
+
@io = StringIO.new(fixture :after_0_0_2)
|
83
|
+
@io.extend Historian::HistoryFile
|
84
|
+
end
|
85
|
+
subject {@io}
|
86
|
+
|
87
|
+
it { should have_current_version "0.0.2" }
|
88
|
+
it { should have_next_version "0.0.3" }
|
89
|
+
|
90
|
+
|
91
|
+
context "when adding a patch to history" do
|
92
|
+
before do
|
93
|
+
@io.update_history :patch => "bugfix #2"
|
94
|
+
end
|
95
|
+
|
96
|
+
it { should have_next_version "0.0.3" }
|
97
|
+
it { should have_history_like :after_0_0_2_history }
|
98
|
+
it { should have_changelog_like :after_0_0_2_changelog }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe do
|
103
|
+
before do
|
104
|
+
@io = StringIO.new(fixture :normal)
|
105
|
+
@io.extend Historian::HistoryFile
|
106
|
+
end
|
107
|
+
subject {@io}
|
108
|
+
|
109
|
+
context "after minor changes and bugfixes" do
|
110
|
+
before do
|
111
|
+
@io.update_history :patch => "bugfix #2",
|
112
|
+
:minor => "minor #1"
|
113
|
+
end
|
114
|
+
|
115
|
+
it { should have_current_version "11.22.33" }
|
116
|
+
it { should have_next_version "11.23.0" }
|
117
|
+
|
118
|
+
it { should have_history_like :normal_history_after_minor }
|
119
|
+
it { should have_changelog_like :normal_changelog_after_minor }
|
120
|
+
end
|
121
|
+
|
122
|
+
context "after major changes, minor changes and bugfixes" do
|
123
|
+
before do
|
124
|
+
@io.update_history :patch => "bugfix #2",
|
125
|
+
:minor => "minor #1",
|
126
|
+
:major => "major #1"
|
127
|
+
end
|
128
|
+
|
129
|
+
it { should have_current_version "11.22.33" }
|
130
|
+
it { should have_next_version "12.0.0" }
|
131
|
+
|
132
|
+
it { should have_history_like :normal_history_after_major }
|
133
|
+
it { should have_changelog_like :normal_changelog_after_major }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when releasing a major change" do
|
138
|
+
before do
|
139
|
+
Time.stub_chain :now, :strftime => "2010/12/12"
|
140
|
+
@io = StringIO.new(fixture :normal)
|
141
|
+
@io.extend Historian::HistoryFile
|
142
|
+
end
|
143
|
+
subject { @io }
|
144
|
+
|
145
|
+
context "with release name 'Courageous Camel'" do
|
146
|
+
before do
|
147
|
+
@io.update_history :major => "major #1",
|
148
|
+
:release => "Courageous Camel"
|
149
|
+
end
|
150
|
+
it { should have_current_version "12.0.0" }
|
151
|
+
it { should have_next_version "12.0.1" }
|
152
|
+
it { should have_history_like :courageous_camel_history }
|
153
|
+
it { should have_changelog_like :empty }
|
154
|
+
it { should have_release_log_like :courageous_camel_release_log }
|
155
|
+
it "returns the release name with #release_name" do
|
156
|
+
subject.current_release_name.should eq("Courageous Camel")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context "with no release name" do
|
161
|
+
before do
|
162
|
+
@io.update_history :major => "major #1",
|
163
|
+
:release => true
|
164
|
+
end
|
165
|
+
|
166
|
+
it { should have_release_log_like :anonymous_release_log }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when parsing a history file with a release and no unreleased changelog" do
|
171
|
+
before do
|
172
|
+
@io = StringIO.new(fixture :courageous_camel_history)
|
173
|
+
@io.extend Historian::HistoryFile
|
174
|
+
end
|
175
|
+
subject { @io }
|
176
|
+
|
177
|
+
it { should have_current_version "12.0.0" }
|
178
|
+
it "returns the release name with #release_name" do
|
179
|
+
subject.current_release_name.should eq("Courageous Camel")
|
180
|
+
end
|
181
|
+
it "returns the changelog for the release" do
|
182
|
+
subject.release_log.strip.should eql(fixture :courageous_camel_release_log)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "when parsing a history with all significance categories" do
|
187
|
+
before do
|
188
|
+
@io = StringIO.new(fixture :all_types_history)
|
189
|
+
@io.extend Historian::HistoryFile
|
190
|
+
@io.parse
|
191
|
+
end
|
192
|
+
subject { @io.changes }
|
193
|
+
|
194
|
+
it "has major changes" do
|
195
|
+
subject[:major].should_not be_empty
|
196
|
+
end
|
197
|
+
|
198
|
+
it "has minor changes" do
|
199
|
+
subject[:minor].should_not be_empty
|
200
|
+
end
|
201
|
+
|
202
|
+
it "has patch changes" do
|
203
|
+
subject[:patch].should_not be_empty
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# TODO: I've realized too late that the strict format
|
208
|
+
# I'm parsing against isn't very practical. I'll need
|
209
|
+
# to rework my parsing code to be more versatile.
|
210
|
+
context "oddly formated history files" do
|
211
|
+
it "raises an error when finding history without significance" do
|
212
|
+
lambda { history(:missing_significance).parse }.should raise_error(Historian::ParseError)
|
213
|
+
end
|
214
|
+
it "raises an error when finding an unknown significance" do
|
215
|
+
lambda { history(:invalid_significance).parse }.should raise_error(Historian::ParseError)
|
216
|
+
end
|
217
|
+
it "raises an error when finding arbitrary text" do
|
218
|
+
lambda { history(:arbitrary_text).parse }.should raise_error(Historian::ParseError)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
require File.expand_path("../../lib/historian", __FILE__)
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
require 'spackle'
|
10
|
+
Spackle.init :with => :rspec_formatter
|
11
|
+
rescue LoadError
|
12
|
+
puts "spackle gem not found -- continuing"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Requires supporting files with custom matchers and macros, etc,
|
16
|
+
# in ./support/ and its subdirectories.
|
17
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
|
21
|
+
end
|