Module: Historian::HistoryFile

Defined in:
lib/historian/history_file.rb

Constant Summary collapse

SECTION_HEADERS =

Example:

history = File.open("History.txt", "w+") # (empty file!)
history.extend Historian::HistoryFile
history.next_version # => "0.0.1"
history.update_history :minor => "added whizbangery",
                       :release => "Awesome Release"
history.rewind
puts history.read
  ## 0.1.0 Awesome Release - 2010/12/12

  ### Minor Changes
  * added whizbangery

Note that the “w+” mode is critically important if you’re extending a File object. The IO instance must be both readable and writeable.

{
  :major => "Major Changes",
  :minor => "Minor Changes",
  :patch => "Bugfixes"
}

Instance Method Summary collapse

Instance Method Details

#changelogObject

The pending changelog for the next release. See also #release_log.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/historian/history_file.rb', line 28

def changelog
  return "" unless changes? || @release

  log = []
  if @release
    release_string = @release === true ? "" : " " + @release
    date_string = " - " + Time.now.strftime("%Y/%m/%d")
    log << "== #{next_version}#{release_string}#{date_string}"
  else
    log << "== In Git"
  end
  [ :major, :minor, :patch ].each do |significance|
    unless changes[significance].empty?
      log << "\n=== #{SECTION_HEADERS[significance]}"
      changes[significance].each { |change| log << "* #{change}" }
    end
  end
  log.join("\n")
end

#changesObject

:nodoc:



48
49
50
51
52
53
54
# File 'lib/historian/history_file.rb', line 48

def changes #:nodoc:
  @changes ||= {
    :major => [],
    :minor => [],
    :patch => []
  }
end

#changes?Boolean

Whether there are changes since the last release

Returns:

  • (Boolean)


57
58
59
60
# File 'lib/historian/history_file.rb', line 57

def changes?
  parse unless parsed?
  changes.find { |(k,v)| !v.empty? }
end

#current_release_nameObject

Returns the name of the current release, either as parsed from the history file, or as provided if a release was recently performed.



156
157
158
159
# File 'lib/historian/history_file.rb', line 156

def current_release_name
  parse unless parsed?
  @current_release_name
end

#current_versionObject

The current (most-recently released) version number in “x.y.z” format



63
64
65
66
# File 'lib/historian/history_file.rb', line 63

def current_version
  parse unless parsed?
  @current_version || "0.0.0"
end

#next_versionObject

The next (upcoming release) version number, based on what pending changes currently exist. Major changes will increment the major number, else minor changes will increment the minor number, else the patch number is incremented.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/historian/history_file.rb', line 72

def next_version
  parse unless parsed?
  (major, minor, patch) = current_version.split(".").collect { |n| n.to_i }
  if !changes[:major].empty?
    major += 1
    patch = minor = 0
  elsif !changes[:minor].empty?
    minor += 1
    patch = 0
  else
    patch += 1
  end
  "%d.%d.%d" % [ major, minor, patch ]
end

#parseObject

Parse the entire history file. There’s generally no need to call this method – it should be called automatically when needed.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/historian/history_file.rb', line 95

def parse
  rewind
  @changes = nil
  @buffer = []
  @release_log = []
  state = :gathering_current_history
  significance = nil
  each_line do |line|
    if state == :gathering_current_history
      case line
      when /^== ([0-9]+\.[0-9]+\.[0-9]+)(.*)/
        state = :gathering_previous_release_log
        @release_log << line
        @buffer << line
        @current_version = $1
        if $2 =~ %r{ (.*) - [0-9]{4}/[0-9]{2}/[0-9]{2}}
          @current_release_name = $1
        end
      when /^=== (.*)$/
        significance = significance_for $1
      when /^\* (.+)$/
        if significance
          changes[significance] << $1
        else
          raise ParseError.new "no significance preceeding history entry '#{$1}'"
        end
      when /^\s*$/, /^== In Git$/
        #noop
      else
        raise ParseError.new("invalid history format: #{line}")
      end
    elsif state == :gathering_previous_release_log
      if line =~ /^== ([0-9]+\.[0-9]+\.[0-9]+)(.*)/
        state = :gathering_remainder
      else
        @release_log << line
      end
      @buffer << line
    else
      @buffer << line
    end
  end
  @release_log = @release_log.join
  @parsed = true
end

#parsed?Boolean

whether the history file has already been parsed

Returns:

  • (Boolean)


88
89
90
# File 'lib/historian/history_file.rb', line 88

def parsed?
  @parsed
end

#releaseObject

Alias for update_history :release => true



142
143
144
# File 'lib/historian/history_file.rb', line 142

def release
  update_history :release => true
end

#release_logObject

If a release was just performed, this will return the changelog of the release. Otherwise, this is always nil.



148
149
150
151
# File 'lib/historian/history_file.rb', line 148

def release_log
  parse unless parsed?
  @release_log
end

#update_history(history) ⇒ Object

Update the release history with new release information. Accepts a hash with any (or all) of four key-value pairs.

:major

a message describing a major change

:major

a message describing a minor change

:patch

a message describing a bugfix or other tiny change

:release

indicates this history should be updated for a new release, if present. If true, the release has no name, but if a string is provided the release will be annotated with the string

To add multiple history entries of the same type, call this method mutiple times.

Note: this method rewrites the entire IO instance to prepend the new history information.



173
174
175
176
177
178
179
180
# File 'lib/historian/history_file.rb', line 173

def update_history(history)
  parse unless parsed?
  @release = history.delete(:release)
  history.each do |(significance,message)|
    changes[significance] << message
  end
  rewrite
end