class Releasinator::Changelog::Validator

Constants

RELEASE_REGEX

Public Class Methods

new(releasinator_config) click to toggle source
# File lib/changelog/validator.rb, line 12
def initialize(releasinator_config)
  @releasinator_config = releasinator_config
end

Public Instance Methods

check_semver_criteria(condition, message) click to toggle source
# File lib/changelog/validator.rb, line 62
def check_semver_criteria(condition, message)
  if !condition
    Printer.fail(message)
    abort()
  end
end
ends_with_punctuation?(line) click to toggle source
# File lib/changelog/validator.rb, line 133
def ends_with_punctuation?(line)
  line.match /.*[\!,\?:\.]$/
end
fail_punctuation(line) click to toggle source
# File lib/changelog/validator.rb, line 137
def fail_punctuation(line)
  Printer.fail("'#{line}' is invalid.  Bulleted points should end in punctuation and no trailing line whitespace.")
  abort()
end
starts_with_bullet?(line) click to toggle source
# File lib/changelog/validator.rb, line 129
def starts_with_bullet?(line)
  line.match /^\s*\*\s+.*$/
end
validate_changelog_contents(changelog_contents) click to toggle source
# File lib/changelog/validator.rb, line 69
def validate_changelog_contents(changelog_contents)
  # Modified version of Vandamme::Parser::DEFAULT_REGEX to disallow versions with leading alpha characters
  changelog_regex = Regexp.new('^#{0,3} ?(v?[\d\.-]+\.[\w\d\.-]+[a-zA-Z0-9])(?: \W (\w+ \d{1,2}(?:st|nd|rd|th)?,\s\d{4}|\d{4}-\d{2}-\d{2}|\w+))?\n?[=-]*')
  parser = Vandamme::Parser.new(changelog: changelog_contents, version_header_exp: changelog_regex, format: 'markdown')
  changelog_hash = parser.parse

  if changelog_hash.empty?
    Printer.fail("Unable to find any releases in the CHANGELOG.md.  Please check that the formatting is correct.")
    abort()
  end

  Printer.success("Found " + changelog_hash.count.to_s.bold + " release(s) in CHANGELOG.md.")

  validate_semver(changelog_hash)

  changelog_hash.each { |release, changelog|
    validate_single_changelog_entry(changelog)
  }

  latest_release, latest_release_changelog = changelog_hash.first
  CurrentRelease.new(latest_release, latest_release_changelog)
end
validate_semver(changelog_hash) click to toggle source

assume changelog_hash is not empty

# File lib/changelog/validator.rb, line 17
def validate_semver(changelog_hash)
  latest_release, latest_release_changelog = changelog_hash.first
  # extract prefix from first release to use on all subsequent releases
  latest_release_prefix = latest_release.partition(RELEASE_REGEX)[0]

  newer_version = nil
  changelog_hash.each do |key,value|

    prefix, version, suffix = key.partition(RELEASE_REGEX)
    puts "Checking version with prefix:'#{prefix}', version:'#{version}', suffix:'#{suffix}'." if @releasinator_config[:verbose]
    if prefix != latest_release_prefix
      Printer.fail("version #{key} does not start with extracted prefix '#{latest_release_prefix}'.")
      abort()
    end
    older_version = Semantic::Version.new version

    if nil != newer_version
      version_comp = newer_version <=> older_version
      if version_comp < 0
        Printer.fail("Semver releases out of order: #{older_version} should be smaller than #{newer_version}")
        abort()
      elsif version_comp == 0
        # this case cannot be found with Vandamme library because 2 versions in a row get overwritten in the underlying hash
        if suffix.empty?
          Printer.fail("2 semver releases in a row without a suffix (like -beta, -rc1, etc...) is not allowed.")
          abort()
        end
      else
        error_suffix = "version increment error - comparing #{newer_version} to #{older_version} does not pass semver validation."
        # validate the next sequence in semver
        if newer_version.major == older_version.major
          if newer_version.minor == older_version.minor
            check_semver_criteria(newer_version.patch == older_version.patch + 1, "patch #{error_suffix}")
          else
            check_semver_criteria(newer_version.minor == older_version.minor + 1 && newer_version.patch == 0, "minor #{error_suffix}")
          end
        else
          check_semver_criteria(newer_version.major == older_version.major + 1 && newer_version.minor == 0 && newer_version.patch == 0, "major #{error_suffix}")
        end
      end
    end
    newer_version = older_version
  end
end
validate_single_changelog_entry(entry) click to toggle source
# File lib/changelog/validator.rb, line 92
def validate_single_changelog_entry(entry)
  previous_line_in_progress = nil

  lines = entry.chomp.split(/\r?\n/)
  lines.each{ |line|

    if starts_with_bullet? line
      if previous_line_in_progress
        fail_punctuation(previous_line_in_progress)
      elsif ends_with_punctuation? line
        # self-contained line is a-ok, and the usual use-case
        previous_line_in_progress = nil
      else
        # line starts with bullet, but did not end with punctuation
        previous_line_in_progress = line
      end
    elsif previous_line_in_progress
      # does not start with bullet, and is continuing from previous line
      if ends_with_punctuation? line
        # multi-line ending with punctuation is ok!
        previous_line_in_progress = nil
      else
        # middle of multi-line - neither starts with bullet, nor ends with punctuation.
        previous_line_in_progress = line
      end
    else
      # don't care about empty or code lines interspersed in a changelog entry
    end
  }

  # the last line may not be clean.  Handle it.
  if previous_line_in_progress
    fail_punctuation(previous_line_in_progress)

  end
end