Class: GemHadar::ChangelogGenerator

Inherits:
Object
  • Object
show all
Includes:
PromptTemplate, Utils
Defined in:
lib/gem_hadar/changelog_generator.rb

Overview

A class that generates changelog entries by analyzing Git history and AI processing

The ChangelogGenerator class provides functionality to create structured changelog entries based on Git commit history. It can generate individual changelog entries for specific version ranges or create complete changelogs including all version entries. The class integrates with AI models to produce human-readable changelog content by processing Git logs through configured prompts and models.

Examples:

Generating a changelog entry for a version range

generator = GemHadar::ChangelogGenerator.new
entry = generator.generate('v1.0.0', 'v1.2.0')

Generating a complete changelog

generator = GemHadar::ChangelogGenerator.new
generator.generate_full(STDOUT)

Adding changelog entries to an existing file

GemHadar::ChangelogGenerator.add_to_file('CHANGELOG.md')

Instance Method Summary collapse

Methods included from PromptTemplate

#default_changelog_prompt, #default_changelog_system_prompt, #default_git_release_prompt, #default_git_release_system_prompt, #default_version_bump_prompt, #default_version_bump_system_prompt

Methods included from Utils

#ask?, #xdg_config, #xdg_config_dir, #xdg_config_filename, #xdg_config_home

Constructor Details

#initialize(gem_hadar) ⇒ ChangelogGenerator

Returns a new instance of ChangelogGenerator.



29
30
31
# File 'lib/gem_hadar/changelog_generator.rb', line 29

def initialize(gem_hadar)
  @gem_hadar = gem_hadar
end

Instance Method Details

#add_to_file(filename) ⇒ Integer?

The add_to_file method appends new changelog entries to an existing changelog file

This method identifies the highest version already present in the changelog file, retrieves all subsequent version tags from the Git repository, and generates changelog entries for each consecutive pair of versions. It then inserts these entries into the file after the existing content, maintaining the chronological order of changes.

Parameters:

  • filename (String)

    the path to the changelog file to which entries will be added

Returns:

  • (Integer)

    the count of changelog entries inserted into the file

  • (nil)

    if no entries were added or if the file was empty

Raises:

  • (ArgumentError)

    if the changelog file does not exist or if no highest version is found



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/gem_hadar/changelog_generator.rb', line 158

def add_to_file(filename)
  highest_version = find_highest_version(filename)

  if highest_version
    versions = read_versions
    versions = versions.drop_while { |t| t < highest_version }
  else
    raise ArgumentError, "Could not find highest version in #{filename.inspect}"
  end

  return if versions.size < 2

  changelog = generate_changelog(versions)
  return if changelog.empty?
  inject_into_filename(filename, changelog)
end

#changelog_exist?TrueClass, FalseClass

The changelog_exist? method checks whether a changelog file exists in the project.

This method verifies the presence of a changelog file by checking if the file path determined by changelog_filename exists in the filesystem.

Returns:

  • (TrueClass, FalseClass)

    true if the changelog file exists, false otherwise



183
184
185
# File 'lib/gem_hadar/changelog_generator.rb', line 183

def changelog_exist?
  changelog_filename.exist?
end

#changelog_version_added?(version) ⇒ TrueClass, FalseClass

The changelog_version_added? method checks whether a specific version has already been added to the changelog file.

This method verifies if a given version is present in the changelog file by examining each line for a match with the version tag.

Parameters:

  • version (String)

    the version to check for in the changelog

Returns:

  • (TrueClass, FalseClass)

    true if the version is found in the changelog, false otherwise

Raises:

  • (ArgumentError)

    if the changelog file does not exist



199
200
201
202
203
204
205
206
207
# File 'lib/gem_hadar/changelog_generator.rb', line 199

def changelog_version_added?(version)
  version = GemHadar::VersionSpec[version]
  changelog_exist? or
    raise ArgumentError, "Changelog #{changelog_filename.to_s} doesn't exist!"
  File.new(changelog_filename).any? do |line|
    line =~ /#{version.tag}/ and return true
  end
  false
end

#generate(from, to = 'HEAD') ⇒ String

The generate method creates a changelog entry by analyzing Git history and AI processing.

This method retrieves the Git log for a specified range of commits, processes the log through an AI model using configured prompts, and formats the result into a markdown changelog entry with a date header.

Parameters:

  • from (String)

    the starting version or commit reference for the Git log range

  • to (String) (defaults to: 'HEAD')

    the ending version or commit reference for the Git log range, defaults to ‘HEAD’

Returns:

  • (String)

    a formatted markdown changelog entry including date and AI-generated content

  • (String)

    a minimal changelog entry with just date and version when no changes are found



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/gem_hadar/changelog_generator.rb', line 49

def generate(from, to = 'HEAD')
  from = GemHadar::VersionSpec[from]
  to   = GemHadar::VersionSpec[to]

  range = "#{from.tag}..#{to.tag}"

  log = `git log #{range}`
  $?.success? or raise "Failed to get git log for range #{range}"

  date = `git log -n1 --pretty='format:%cd' --date=short #{to.tag.inspect}`.chomp

  if log.strip.empty?
    return "\n## #{date} #{to.without_prefix.to_s}\n"
  end

  system          = xdg_config('gem_hadar', 'changelog_system_prompt.txt', default_changelog_system_prompt)
  prompt_template = xdg_config('gem_hadar', 'changelog_prompt.txt', default_changelog_prompt)
  prompt = prompt_template % { log_diff: log }

  response = ollama_generate(system:, prompt:)

  changes = response.gsub(/\t/, '  ')

  return "\n## #{date} #{to.tag}\n\n#{changes}\n"
end

#generate_full(output) ⇒ String

The generate_full method creates a complete changelog by processing all version tags in the repository and generating entries for each consecutive pair of versions

This method retrieves all semantic version tags from the Git repository, sorts them, and generates changelog entries for each pair of consecutive versions. It also adds an initial entry for the first version with a “Start” marker

Parameters:

  • output (IO)

    the output stream to which the complete changelog will be written

Returns:

  • (String)

    a complete changelog including all version entries and a header

Raises:

  • (RuntimeError)

    if no version tags are found in the repository



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/gem_hadar/changelog_generator.rb', line 124

def generate_full(output)
  versions = read_versions

  unless versions.any?
    raise "No version tags found in repository"
  end

  first_version = versions.first
  date          = `git log -n1 --pretty='format:%cd' --date=short #{first_version.tag.to_s}`.chomp
  changelog     = ["\n## #{date} #{first_version.tag.to_s}\n\n* Start\n"]

  changelog = generate_changelog(versions, changelog:)

  changelog.unshift "# Changes\n"

  output << changelog.join("")
end

#generate_range(output, from, to) ⇒ Object

The generate_range method creates a changelog for a specific version range by processing Git log differences and AI-generated content

This method retrieves version tags within a specified range, filters them based on the provided version boundaries, generates changelog entries for each version in the range, and writes the complete changelog to the provided output stream

Parameters:

  • output (IO)

    the output stream to which the changelog will be written

  • from (String)

    the starting version or commit reference for the range

  • to (String)

    the ending version or commit reference for the range, defaults to ‘HEAD’



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/gem_hadar/changelog_generator.rb', line 89

def generate_range(output, from, to)
  from = GemHadar::VersionSpec[from]
  to   = GemHadar::VersionSpec[to]

  versions = read_versions

  unless versions.any?
    raise "No version tags found in repository"
  end

  versions = versions.select do |v|
    v >= from && v <= to
  end

  changelog = generate_changelog(versions)

  output << changelog.join("")
end