historian 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +35 -0
  6. data/LICENSE +20 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.rdoc +149 -0
  9. data/Rakefile +2 -0
  10. data/VERSION +1 -0
  11. data/autotest/discover.rb +1 -0
  12. data/bin/historian +12 -0
  13. data/historian.gemspec +28 -0
  14. data/lib/historian.rb +12 -0
  15. data/lib/historian/cli.rb +84 -0
  16. data/lib/historian/commit_message.rb +40 -0
  17. data/lib/historian/configuration.rb +10 -0
  18. data/lib/historian/git.rb +189 -0
  19. data/lib/historian/history_file.rb +209 -0
  20. data/lib/historian/version.rb +3 -0
  21. data/spec/example_history.txt +24 -0
  22. data/spec/fixtures/after_0_0_2 +16 -0
  23. data/spec/fixtures/after_0_0_2_changelog +6 -0
  24. data/spec/fixtures/after_0_0_2_history +17 -0
  25. data/spec/fixtures/all_types_history +17 -0
  26. data/spec/fixtures/anonymous_release_log +7 -0
  27. data/spec/fixtures/arbitrary_text +21 -0
  28. data/spec/fixtures/courageous_camel_history +13 -0
  29. data/spec/fixtures/courageous_camel_release_log +7 -0
  30. data/spec/fixtures/empty +0 -0
  31. data/spec/fixtures/invalid_significance +17 -0
  32. data/spec/fixtures/missing_significance +16 -0
  33. data/spec/fixtures/normal +10 -0
  34. data/spec/fixtures/normal_changelog_after_major +11 -0
  35. data/spec/fixtures/normal_changelog_after_minor +8 -0
  36. data/spec/fixtures/normal_history_after_major +17 -0
  37. data/spec/fixtures/normal_history_after_minor +14 -0
  38. data/spec/fixtures/patch_on_nothing +5 -0
  39. data/spec/fixtures/release_on_nothing +1 -0
  40. data/spec/fixtures/second_patch_on_nothing +6 -0
  41. data/spec/historian/cli_spec.rb +210 -0
  42. data/spec/historian/commit_message_spec.rb +95 -0
  43. data/spec/historian/git_spec.rb +199 -0
  44. data/spec/historian/history_file_spec.rb +225 -0
  45. data/spec/spec.opts +3 -0
  46. data/spec/spec_helper.rb +21 -0
  47. data/spec/support/fixture_helper.rb +8 -0
  48. data/spec/support/git_helpers.rb +53 -0
  49. data/spec/support/history_file_matchers.rb +52 -0
  50. metadata +189 -0
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,5 @@
1
+ rdoc
2
+ tmp
3
+ pkg/*
4
+ *.gem
5
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --drb
3
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in historian/.gemspec
4
+ gemspec
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ historian (0.0.1)
5
+ project_scout (>= 0.0.2)
6
+ thor
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ ZenTest (4.4.2)
12
+ autotest (4.4.6)
13
+ ZenTest (>= 4.4.1)
14
+ diff-lcs (1.1.2)
15
+ project_scout (0.0.2)
16
+ rspec (2.3.0)
17
+ rspec-core (~> 2.3.0)
18
+ rspec-expectations (~> 2.3.0)
19
+ rspec-mocks (~> 2.3.0)
20
+ rspec-core (2.3.1)
21
+ rspec-expectations (2.3.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.3.0)
24
+ thor (0.14.3)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ autotest
31
+ bundler
32
+ historian!
33
+ project_scout (>= 0.0.2)
34
+ rspec (~> 2.3.0)
35
+ thor
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Rick Lee-Morlang
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Rick Lee-Morlang
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,149 @@
1
+ = Historian
2
+
3
+ Historian automatically maintains your project's History.txt file
4
+ based on your git changelogs, and can automatically perform
5
+ releases for you.
6
+
7
+ == Historian is Opinionated Software
8
+
9
+ Historian makes a number of assumptions. You might not like them.
10
+ It works well for how I like to work, but patches are welcome.
11
+
12
+ * it (pretty much) works only with Git
13
+ * it updates history in +History.txt+ in your project root dir
14
+ * it writes your +History.txt+ file in Markdown format
15
+ * it considers three levels of "significance": major changes, minor changes, and bugfixes
16
+ * it generates version numbers when a release is triggered
17
+ * version numbers are in x.y.z format (major.minor.patch)
18
+ * the significance of changes controls how version numbers are incremented
19
+
20
+ == Usage
21
+
22
+ Install Historian's git commit hooks in your current git repository.
23
+
24
+ historian install
25
+
26
+ Make some changes, and run +git commit+. In your commit message,
27
+ prefix any lines you'd like to make part of your history with
28
+ one of the following tags, according to the significance of the
29
+ change message:
30
+
31
+ M:: A major change
32
+ m:: A minor change
33
+ b:: A bugfix
34
+
35
+ For example, suppose your commit message would normally have
36
+ been:
37
+
38
+ Rewrote network protocol, breaking compatibility with old clients.
39
+
40
+ With Historian, this becomes:
41
+
42
+ M:Rewrote network protocol, breaking compatibility with old clients.
43
+
44
+ The "M:" will be stripped out of the commit message, so it won't
45
+ show up that way in your commit history. However, Historian will
46
+ use the content on the line where the M: appears to update the
47
+ history file. If you had no +History.txt+ file before now, one
48
+ will be created with the following content:
49
+
50
+ ## In Git
51
+
52
+ ### Major Changes
53
+ * Rewrote network protocol, breaking compatibility with old clients.
54
+
55
+ Historian will bundle the change to +History.txt+ as part of your
56
+ commit.
57
+
58
+ == Adding history without it showing in your commit log
59
+
60
+ You can also insert history entries that don't show up in your
61
+ commit logs, if you prefer. Example syntax of a commit message.
62
+
63
+ Replaced ASCII protocol with XML syntax.
64
+
65
+ M#:Rewrote network protocol, breaking compatibility with old clients.
66
+
67
+ Note the "#" before the colon. This tells Historian to suppress the
68
+ content of that line in the commit message, so your commit log will
69
+ only show:
70
+
71
+ Replaced ASCII protocol with XML syntax.
72
+
73
+
74
+ == Triggering releases
75
+
76
+ You can also tell Historian that this commit marks a new release.
77
+ Any line that begins with a bang-colon "!:" will trigger a release.
78
+ The rest of the line can be empty, or it can optionally contain
79
+ a "friendly name" for the release. Examples:
80
+
81
+ !:Flux Capacitor PRO
82
+
83
+ Or, in Debian/Ubuntu style:
84
+
85
+ !:Addled Adder
86
+
87
+ When a release is triggered, Historian will check the recent History
88
+ for major, minor, and bugfix entries to determine if this is a
89
+ major, minor or bugfix release. Historian refers to this as
90
+ "significance."
91
+
92
+ Historian will also determine the most recent release number from
93
+ the History.txt file, or will default to "0.0.0".
94
+
95
+ Historian will calculate a new version number by incrementing the
96
+ appropriate major, minor, or patch triplet based on the significance
97
+ of the release.
98
+
99
+ Historian will update the +History.txt+ file with a header for
100
+ the recent history that contains the version number, date, and
101
+ (if specified) the release name.
102
+
103
+ Finally, Historian will create an annotated tag in git with the
104
+ version number of the release. The tag contents will contain
105
+ the changelog.
106
+
107
+ == Multiple history entries
108
+
109
+ Historian allows multiple entries, if you like. Example commit
110
+ message:
111
+
112
+ Numerous minor bugfixes
113
+
114
+ b: * eliminated crash when ip address not specified
115
+ b: * logs now include hostnames
116
+ b: * new connections append to logfiles instead of clobbering them
117
+
118
+ Note that any non-alphanumeric content after the colon is ignored,
119
+ so the history entries will not include the " * ".
120
+
121
+ == Manual Invocation
122
+
123
+ You can use Historian in a limited way from the commandline. These
124
+ forms update +History.txt+ only, and do not interact with Git.
125
+
126
+ The following will add two new history entries.
127
+
128
+ history update major="rewrote network protocol" \
129
+ bugfix="fixed null reference crash"
130
+
131
+ This will increment the version number.
132
+
133
+ history release
134
+
135
+
136
+ == Note on Patches/Pull Requests
137
+
138
+ * Fork the project.
139
+ * Make your feature addition or bug fix.
140
+ * Add tests for it. This is important so I don't break it in a
141
+ future version unintentionally.
142
+ * Commit, do not mess with rakefile, version, or history.
143
+ (if you want to have your own version, that is fine but
144
+ bump version in a commit by itself I can ignore when I pull)
145
+ * Send me a pull request. Bonus points for topic branches.
146
+
147
+ == Copyright
148
+
149
+ Copyright (c) 2009 Rick Lee-Morlang. See LICENSE for details.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ historian_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(historian_dir) unless $LOAD_PATH.include?(historian_dir)
4
+
5
+ require 'historian'
6
+
7
+ begin
8
+ Historian::CLI.start
9
+ #rescue => err
10
+ #STDERR.puts err.message
11
+ #exit 1
12
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "historian/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "historian"
7
+ s.version = Historian::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Richard Lee-Morlang"]
10
+ s.email = ["rick@lee-morlang.com"]
11
+ s.homepage = "https://github.com/rleemorlang/historian"
12
+ s.summary = %q{Automatically extract information from git commit messages and update your project's history file.}
13
+ s.description = %q{Historian uses git commit hooks to inject itself into Git's commit workflow. Historian checks your commit messages for certain markup tokens. If found, it updates your project's history file, and amends your commit with it, while also stripping out the markup.}
14
+
15
+ #s.rubyforge_project = "historian"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "thor"
23
+ s.add_dependency "project_scout", ">= 0.0.2"
24
+
25
+ s.add_development_dependency "rspec", "~> 2.3.0"
26
+ s.add_development_dependency "bundler"
27
+ s.add_development_dependency "autotest"
28
+ end
@@ -0,0 +1,12 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ module Historian
5
+ class ParseError < StandardError; end
6
+ end
7
+
8
+ require "historian/history_file"
9
+ require "historian/git"
10
+ require "historian/commit_message"
11
+ require "historian/cli"
12
+ require "historian/version"
@@ -0,0 +1,84 @@
1
+ require 'thor'
2
+ require 'project_scout'
3
+ #require 'thor/actions'
4
+
5
+ class Historian::CLI < Thor
6
+ attr_accessor :git, :history, :repo_directory
7
+
8
+ default_task :help
9
+
10
+ def initialize(*)
11
+ super
12
+ @repo_directory = ProjectScout.scan Dir.pwd, :for => [ :git_repository ]
13
+
14
+ history_file = File.join(repo_directory, "History.txt")
15
+ unless File.exists? history_file
16
+ File.open history_file, "w"
17
+ end
18
+ @history = File.open history_file, File::RDWR
19
+ history.sync = true
20
+ history.extend Historian::HistoryFile
21
+ self.git = Historian::Git.new(repo_directory, history)
22
+ end
23
+
24
+ desc "commit_msg FILE", "Git commit-msg hook for Historian. Not intended for manual use."
25
+ def commit_msg(message_file)
26
+ return nil if File.exists? amend_flag_file
27
+
28
+ history_updated = false
29
+ release = nil
30
+ new_message = []
31
+ File.open(message_file).each_line do |line|
32
+ line = Historian::CommitMessage.parse_line line
33
+ new_message << line.to_s unless line.suppressed?
34
+ case line.significance
35
+ when :minor, :major, :patch
36
+ history.update_history line.significance => line.to_message_s
37
+ history_updated = true
38
+ when :release
39
+ release = line.to_message_s
40
+ end
41
+ end
42
+
43
+ if release
44
+ history_updated = true
45
+ history.update_history :release => release
46
+ File.open release_flag_file, "w"
47
+ end
48
+
49
+ if history_updated
50
+ File.open amend_flag_file, "w"
51
+ File.open(message_file,"w") { |f| f.puts new_message }
52
+ end
53
+ end
54
+
55
+ desc "install", "install Historian Git hooks into current repository."
56
+ def install
57
+ git.install_hook :commit_msg
58
+ git.install_hook :post_commit
59
+ end
60
+
61
+ desc "post_commit", "Git post-commit hook for Historian. Not intended for manual use."
62
+ def post_commit
63
+ if File.exists? amend_flag_file
64
+ File.unlink amend_flag_file
65
+ git.bundle_history_file
66
+ end
67
+
68
+ if File.exists? release_flag_file
69
+ File.unlink release_flag_file
70
+ git.tag_release
71
+ end
72
+ end
73
+
74
+ protected
75
+
76
+ def amend_flag_file
77
+ File.join(repo_directory, ".git", "historian-amend")
78
+ end
79
+
80
+ def release_flag_file
81
+ File.join(repo_directory, ".git", "historian-release")
82
+ end
83
+ end
84
+
@@ -0,0 +1,40 @@
1
+ require 'ostruct'
2
+
3
+ class Historian::CommitMessage
4
+ attr_reader :line, :token, :suppressed
5
+
6
+ def initialize(line)
7
+ if line =~ /^([!bmM])(#?):(.*[0-9a-zA-Z].*)$/
8
+ @token = $1
9
+ @suppressed = true if $2 == "#"
10
+ @line = $3
11
+ else
12
+ @line = line
13
+ end
14
+ end
15
+
16
+ def significance
17
+ case token
18
+ when "b"; :patch
19
+ when "m"; :minor
20
+ when "M"; :major
21
+ when "!"; :release
22
+ end
23
+ end
24
+
25
+ def suppressed?
26
+ @suppressed == true
27
+ end
28
+
29
+ def to_s
30
+ line
31
+ end
32
+
33
+ def to_message_s
34
+ line.gsub /^\W*/, '' if significance
35
+ end
36
+
37
+ def self.parse_line(line)
38
+ new line
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ require 'active_dotfile'
2
+
3
+ module Historian
4
+ class Configuration
5
+ include ActiveDotfile::Configurable
6
+ load_dotfiles_on_initialize
7
+
8
+ attr_accessor_with_default :map => {}
9
+ end
10
+ end