dvmonroe/release-notes

View on GitHub
lib/release/notes/tag.rb

Summary

Maintainability
A
25 mins
Test Coverage
# frozen_string_literal: true

module Release
  module Notes
    class Tag
      include Configurable
      attr_accessor :_hashes
      attr_reader :tag, :previous_tag

      delegate :digest_header, prefix: :writer, to: :@writer

      # Release::Notes::Tag initializer
      #
      # @param [String] tag - a git tag (ex: v2.0.0)
      # @param [Release::Notes::Write] writer - an object containing a header, title, and associated log messages
      # @param [String] previous_tag - the previous git tag (ex: v1.3.0)
      def initialize(tag:, writer:, previous_tag:)
        @tag = tag
        @writer = writer
        @previous_tag = previous_tag

        @_commits = {}
        @_hashes = []
      end

      #
      # Adds log messages to @_commits variable, and if there are commits that need to be added to
      # changelog, add the header and associated log messages
      #
      # @return none
      #
      def perform
        store_commits # adds to @_commits

        if commits_available? # true
          writer_digest_header(header) # <File:./release-notes.tmp.md (closed)>
          log_commits # hash [0,1,2...], messages for sha
        end

        self
      rescue MissingTag => e
        $stderr.puts "<#{e.class.name.demodulize}>: #{e}" # rubocop:disable Style/StderrPuts
        raise
      end

      private

      #
      # Are there git sha's with commits?
      #
      # @return [Boolean] true: commits are present, false: there are no commits
      #
      def commits_available?
        @_commits.present?
      end

      #
      # Formats a supplied date
      #
      # @param [String] date - a date
      #
      # @return [String] formatted date
      #
      def formatted_date(date = nil)
        DateFormatter.new(date).humanize
      end

      #
      # Generate header title
      #
      # @return [String] the header to be added to changelog
      #
      def header
        config_header_title_type.yield_self { |t| title(t) } # config_header_title = "tag"
      end

      #
      # Creates new commit objects from the @_commits object
      #
      # @return [Hash] unique log messages per tag
      #
      def log_commits
        @_commits.each do |key, val|
          Commits.new(title: titles[key], value: val, writer: @writer, tagger: self).perform
        end
      end

      #
      # Transform tag into date
      #
      # @return [String] date the tag was created
      #
      def tag_date
        System.tag_date(tag: tag)
      end

      #
      # Adds log messages to @_commits
      #
      # @return none
      #
      def store_commits
        all_labels.each_with_index do |lab, i|
          system_log(label: lab).tap { |str| @_commits[i] = str if str.present? }
        end

        # if log_all = true
        @_commits[all_labels.size] = system_log(log_all: true) if config_log_all
      end

      #
      # Create new system object that contains log messages between tag_from and tag_to
      # with the relevant options
      #
      # @param [Hash] opts - options like the label to grep
      #
      # @return [String] log messages that meet the criteria
      #
      def system_log(**opts)
        System.new({ tag_from: previous_tag, tag_to: tag }.merge(opts)).log
      end

      #
      # Array of strings containing all labels
      #
      # @return [Array] array of all labels
      #
      def all_labels
        [config_features, config_bugs, config_misc]
      end

      #
      # Array of strings containing all titles
      #
      # @return [Array] array of all titles
      #
      def titles
        [config_feature_title, config_bug_title,
         config_misc_title, config_log_all_title]
      end

      #
      # Title or formatted tag date
      #
      # @param [String] title - should the title be the git tag? If yes, use the git
      # tag as the title, if not use the tag date
      #
      # @return [String] tag title or formatted tag date to be added to changelog
      #
      def title(title)
        return standard_title(title) unless config_update_release_notes_before_tag? && tag == "HEAD"

        formatted_date unless title == "tag"
        return config_newest_tag if config_newest_tag.present?

        raise MissingTag, "No tag version was passed as an option when generating release notes"
      end

      def standard_title(title)
        title == "tag" ? tag : formatted_date(tag_date)
      end
    end
  end
end