herodotus 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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ tmp/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2
data/CHANGES ADDED
@@ -0,0 +1,10 @@
1
+ v0.0.1 [2011-07-28]:
2
+
3
+ 2011-07-23 Harold Giménez <hgimenez@thoughtbot.com>
4
+ Including "Changelog:" in the commit message will mark
5
+ that commit as available for the changelog, and will use all text
6
+ below the keyword.
7
+
8
+ 2011-07-27 Harold Giménez <hgimenez@thoughtbot.com>
9
+ Add the ability for specifying which revision to write a changelog
10
+ since. Usually, this will be a tag name.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in herodotus.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ Herodotus
2
+ ---------
3
+
4
+ Herodotus, an ancient greek historian and story teller will
5
+ help you keep a changelog updated.
6
+
7
+ Oftentimes you don't think about the changelog when you make changes to your
8
+ project. Then, when it's time to cut a release, you've really lost momentum
9
+ of how those changes affect your users. You thought about these things days or
10
+ weeks ago, when you committed them to the repo.
11
+
12
+ Herodotus can help by going over your git history since a particular release
13
+ and extracting your notes. Obviously, not every commit will contain useful or
14
+ changelog worthy information, so we'll use the commit message format to
15
+ communicate what should go in the changelog. Here are the rules:
16
+
17
+ * Tag every release, so that it is easy to tell Herodotus how far back to start
18
+ looking for changes.
19
+ * To start writing notes for use in the changelog, use the following format on
20
+ your git commit message:
21
+
22
+
23
+ ```
24
+ Real commit message subject
25
+
26
+ Some more info on the commit
27
+
28
+ Changelog:
29
+ Anything below this line will go on the changelog. Tell your users how to
30
+ upgrade the app, what has been depracated, what will break, etc.
31
+ ```
32
+
33
+ It doesn't need to be exact either. Herodotus will simply extract these
34
+ comments, format them by adding the author and date, and either append them to
35
+ your CHANGES file, or print them out to standard out. Once it's there you can
36
+ tweak it at will before pushing. But the important pieces have been thought out
37
+ at the time when you wrote the software changes - and was written right on the
38
+ commit message, and so maintaining the changelog could be easier.
39
+
40
+ ## Installation
41
+
42
+ Add herodotus to your Gemfile and run bundle.
43
+
44
+ If you're not using bundler, install via `gem install herodotus`
45
+
46
+ Then add `require 'herodotus/tasks'` to your `Rakefile`. This will provide the rake tasks with which you interface with herodotus.
47
+
48
+ ## Usage
49
+
50
+ Herodotus provides a couple of rake tasks:
51
+
52
+ ```
53
+ rake -T
54
+ rake herodotus:append[since_ref] # Appends changes to your changelog
55
+ rake herodotus:print[since_ref] # Prints out the change log from git
56
+ ```
57
+
58
+ You can optionally pass the reference (usually a tag) from which herodotus will start to look for changelog messages in your commits.
59
+ Note that some shells require you to wrap the rake task in double quotes when passing arguments. For example: `rake "herodotus:print[v1]"`
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ require 'bundler/setup'
3
+ require 'herodotus/tasks'
4
+ Bundler::GemHelper.install_tasks
5
+ include Rake::DSL
6
+
7
+ require 'rake/testtask'
8
+ Rake::TestTask.new do |t|
9
+ t.pattern = "spec/*_spec.rb"
10
+ end
11
+
12
+ task :default => :test
data/herodotus.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "herodotus/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "herodotus"
7
+ s.version = Herodotus::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Harold Giménez"]
10
+ s.email = ["harold.gimenez@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{The father of your project's history}
13
+ s.description = %q{Reads your git tags and commit messages to keep the changelog updated}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency 'grit'
21
+
22
+ s.add_development_dependency 'redgreen'
23
+ s.add_development_dependency 'rake'
24
+ s.add_development_dependency 'ruby-debug19'
25
+ s.add_development_dependency 'mocha'
26
+ end
data/lib/herodotus.rb ADDED
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'grit'
3
+
4
+ require 'herodotus/git'
5
+ require 'herodotus/collector'
6
+ require 'herodotus/reporter'
@@ -0,0 +1,46 @@
1
+ module Herodotus
2
+ class Collector
3
+ attr_accessor :git, :since_ref, :changes, :changelog_filename
4
+ CHANGES_REGEX = /changelog.*?\n(.*)/mi.freeze
5
+
6
+ def initialize(base_dir, since_ref = nil)
7
+ @git = Git.new(base_dir)
8
+ @since_ref = since_ref
9
+ @changes = []
10
+ find_changes
11
+ end
12
+
13
+ Change = Struct.new(:author, :time, :message) do
14
+ def pretty_author
15
+ "#{author.name} <#{author.email}>"
16
+ end
17
+
18
+ def log_entry
19
+ "#{time.to_date} #{pretty_author}" +
20
+ "\n#{message}" +
21
+ "\n\n"
22
+ end
23
+ end
24
+
25
+ def print
26
+ reporter.print
27
+ end
28
+
29
+ def append_to_changelog
30
+ reporter.append_to_changelog
31
+ end
32
+
33
+ def find_changes
34
+ git.commits.each do |commit|
35
+ if commit.message =~ CHANGES_REGEX
36
+ @changes.unshift Change.new(commit.author, commit.authored_date, $1)
37
+ end
38
+ end
39
+ end
40
+ private :find_changes
41
+
42
+ def reporter
43
+ Herodotus::Reporter.new(self)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ module Herodotus
2
+ class Git
3
+ attr_accessor :repo
4
+ def initialize(base_dir)
5
+ @base_dir = base_dir
6
+ @repo = Grit::Repo.new(guess_repo)
7
+ end
8
+
9
+ def commits(since_ref = nil)
10
+ if since_ref
11
+ output = repo.git.rev_list({'pretty' => 'raw'}, "#{since_ref}..")
12
+ Grit::Commit.list_from_string(repo, output)
13
+ else
14
+ Grit::Commit.find_all(@repo, since_ref)
15
+ end
16
+ end
17
+
18
+ private
19
+ def guess_repo
20
+ current_dir = File.expand_path(@base_dir)
21
+ until current_dir == '/' do
22
+ maybe_repo = File.expand_path(".git", current_dir)
23
+ if File.directory?(maybe_repo)
24
+ return maybe_repo
25
+ else
26
+ current_dir = File.expand_path('..', current_dir)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module Herodotus
2
+ class Reporter
3
+ attr_reader :collector
4
+ attr_accessor :changelog_filename
5
+
6
+ def initialize(collector)
7
+ @collector = collector
8
+ @changelog_filename = 'CHANGES'
9
+ end
10
+
11
+ def print
12
+ @collector.changes.each do |change|
13
+ puts change.log_entry
14
+ end
15
+ end
16
+
17
+ def append_to_changelog
18
+ File.open(changelog_filename, 'a') do |file|
19
+ @collector.changes.each do |change|
20
+ file.puts change.log_entry
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'herodotus'
3
+
4
+ def default_base_dir
5
+ File.expand_path(File.dirname(__FILE__))
6
+ end
7
+
8
+ namespace :herodotus do
9
+ desc 'Prints out the change log from git'
10
+ task :print, :since_ref do |t, args|
11
+ base_dir = ENV['BASE_DIR'] || default_base_dir
12
+ Herodotus::Collector.new(base_dir, args['since_ref']).
13
+ print
14
+ end
15
+
16
+ desc 'Appends changes to your changelog'
17
+ task :append, :since_ref do |t, args|
18
+ base_dir = ENV['BASE_DIR'] || default_base_dir
19
+ Herodotus::Collector.new(base_dir, args['since_ref']).
20
+ append_to_changelog
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ module Herodotus
2
+ MAJOR = 0
3
+ MINOR = 0
4
+ PATCH = 1
5
+ VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
6
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Herodotus::Collector do
4
+ def collector
5
+ @collector ||= Herodotus::Collector.new('/tmp/herodotus')
6
+ end
7
+ before do
8
+ FileUtils.mkdir_p '/tmp/herodotus'
9
+ FileUtils.cd '/tmp/herodotus' do
10
+ `git init`
11
+ `touch file1`
12
+ `git add file1`
13
+ `git commit -m "this is a change"`
14
+ `touch file2`
15
+ `git add file2`
16
+ `git commit -m "Another\nChAnGeLOg:\nBroke everything again. Don't update to this version."`
17
+ `touch file3`
18
+ `git add file3`
19
+ `git commit -m "Another\nchangelog:\nNevermind, everything is fixed now."`
20
+ end
21
+ end
22
+
23
+ after { FileUtils.rm_rf '/tmp/herodotus' }
24
+
25
+ it 'starts off with a default git, changes and a since_ref of nil' do
26
+ collector.git.wont_be_nil
27
+ collector.since_ref.must_be_nil
28
+ collector.changes.wont_be_nil
29
+ end
30
+
31
+ it 'finds commits containing the changelog keyword on the message' do
32
+ collector.changes.length.must_equal 2
33
+ collector.changes.first.message.must_equal "Broke everything again. Don't update to this version."
34
+ collector.changes.last.message.must_equal "Nevermind, everything is fixed now."
35
+ end
36
+
37
+ it 'tells the reporter to print' do
38
+ reporter = mock('reporter')
39
+ collector.stubs(:reporter).returns(reporter)
40
+ reporter.expects(:print).once
41
+ collector.print
42
+ end
43
+
44
+ it 'tells the reporter to append to changelog' do
45
+ reporter = mock('reporter')
46
+ collector.stubs(:reporter).returns(reporter)
47
+ reporter.expects(:append_to_changelog).once
48
+ collector.append_to_changelog
49
+ end
50
+ end
data/spec/git_spec.rb ADDED
@@ -0,0 +1,40 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+ require 'ruby-debug'
3
+
4
+ describe Herodotus::Git do
5
+
6
+ def git
7
+ @git ||= Herodotus::Git.new('/tmp/herodotus/bacon')
8
+ end
9
+
10
+ before do
11
+ FileUtils.mkdir_p '/tmp/herodotus'
12
+ FileUtils.cd '/tmp/herodotus' do
13
+ `git init`
14
+ `touch file`
15
+ `git add file`
16
+ `git commit -m "Added file"`
17
+ `git tag -a v1 -m "the MVP"`
18
+ `touch file2`
19
+ `git add file2`
20
+ `git commit -m "Added file2"`
21
+ FileUtils.mkdir_p 'bacon'
22
+ end
23
+ end
24
+
25
+ after do
26
+ FileUtils.rm_rf '/tmp/herodotus'
27
+ end
28
+
29
+ it 'locates the closest git repo' do
30
+ git.repo.path.must_equal '/tmp/herodotus/.git'
31
+ end
32
+
33
+ it 'pulls out commits from the repo' do
34
+ git.commits.map(&:message).must_equal ['Added file2', 'Added file']
35
+ end
36
+
37
+ it 'pulls out commits since a given ref' do
38
+ git.commits('v1').map(&:message).must_equal ['Added file2']
39
+ end
40
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Herodotus::Reporter do
4
+ def collector
5
+ @collector ||= Herodotus::Collector.new('/tmp/herodotus')
6
+ end
7
+
8
+ before do
9
+ FileUtils.mkdir_p '/tmp/herodotus'
10
+ FileUtils.cd '/tmp/herodotus' do
11
+ `git init`
12
+ `touch file1`
13
+ `git add file1`
14
+ `git commit -m "this is a change"`
15
+ `touch file2`
16
+ `git add file2`
17
+ `git commit -m "Another\nChAnGeLOg:\nBroke everything again. Don't update to this version."`
18
+ `touch file3`
19
+ `git add file3`
20
+ `git commit -m "Another\nchangelog:\nNevermind, everything is fixed now."`
21
+ end
22
+ end
23
+
24
+ after { FileUtils.rm_rf '/tmp/herodotus' }
25
+
26
+ it 'takes a Collector instance' do
27
+ reporter = Herodotus::Reporter.new(collector)
28
+ reporter.collector.must_equal collector
29
+ end
30
+
31
+ it 'has a default changelog filename of CHANGES' do
32
+ reporter = Herodotus::Reporter.new(collector)
33
+ reporter.changelog_filename.must_equal 'CHANGES'
34
+ end
35
+
36
+ it 'appends changelog entries to the changelog file' do
37
+ reporter = Herodotus::Reporter.new(collector)
38
+ reporter.changelog_filename = File.expand_path('tmp/test_changes')
39
+ reporter.append_to_changelog
40
+ changelog = IO.read(reporter.changelog_filename)
41
+ changelog.must_include "Broke everything again. Don't update to this version."
42
+ changelog.must_include "Nevermind, everything is fixed now."
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ require 'minitest/autorun'
2
+ require 'ruby-debug'
3
+ require 'mocha'
4
+
5
+ require File.expand_path(File.join('lib', 'herodotus'))
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: herodotus
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - "Harold Gim\xC3\xA9nez"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-07-28 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: grit
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: redgreen
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: rake
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: ruby-debug19
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: mocha
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
71
+ description: Reads your git tags and commit messages to keep the changelog updated
72
+ email:
73
+ - harold.gimenez@gmail.com
74
+ executables: []
75
+
76
+ extensions: []
77
+
78
+ extra_rdoc_files: []
79
+
80
+ files:
81
+ - .gitignore
82
+ - .rvmrc
83
+ - CHANGES
84
+ - Gemfile
85
+ - README.md
86
+ - Rakefile
87
+ - herodotus.gemspec
88
+ - lib/herodotus.rb
89
+ - lib/herodotus/collector.rb
90
+ - lib/herodotus/git.rb
91
+ - lib/herodotus/reporter.rb
92
+ - lib/herodotus/tasks.rb
93
+ - lib/herodotus/version.rb
94
+ - spec/collector_spec.rb
95
+ - spec/git_spec.rb
96
+ - spec/reporter_spec.rb
97
+ - spec/spec_helper.rb
98
+ has_rdoc: true
99
+ homepage: ""
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: -2072332935919534749
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: -2072332935919534749
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project:
128
+ rubygems_version: 1.6.2
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: The father of your project's history
132
+ test_files:
133
+ - spec/collector_spec.rb
134
+ - spec/git_spec.rb
135
+ - spec/reporter_spec.rb
136
+ - spec/spec_helper.rb