Class: GemHadar::ChangelogGenerator
- Inherits:
-
Object
- Object
- GemHadar::ChangelogGenerator
- 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.
Instance Method Summary collapse
-
#add_to_file(filename) ⇒ Integer?
The add_to_file method appends new changelog entries to an existing changelog file.
-
#changelog_exist? ⇒ TrueClass, FalseClass
The changelog_exist? method checks whether a changelog file exists in the project.
-
#changelog_filename ⇒ Pathname
private
The changelog_filename method returns the Pathname object for the changelog file path.
-
#changelog_version_added?(version) ⇒ TrueClass, FalseClass
The changelog_version_added? method checks whether a specific version has already been added to the changelog file.
-
#find_highest_version(filename) ⇒ GemHadar::VersionSpec?
private
The find_highest_version method extracts version specifications from a changelog file and returns the highest version found.
-
#generate(from, to = 'HEAD') ⇒ String
The generate method creates a changelog entry by analyzing Git history and AI processing.
-
#generate_changelog(versions, changelog: []) ⇒ Array<String>
private
The generate_changelog method creates a series of changelog entries by processing consecutive version pairs.
-
#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.
-
#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.
-
#initialize(gem_hadar) ⇒ ChangelogGenerator
constructor
A new instance of ChangelogGenerator.
-
#inject_into_filename(filename, changelog) ⇒ Integer
private
The inject_into_filename method inserts changelog entries into a specified file.
-
#ollama_generate(**opts) ⇒ String?
private
The ollama_generate method delegates AI generation requests to the associated GemHadar instance.
-
#read_versions ⇒ Array<GemHadar::VersionSpec>
private
The read_versions method retrieves and processes semantic version tags from the Git repository.
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.
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.
183 184 185 |
# File 'lib/gem_hadar/changelog_generator.rb', line 183 def changelog_exist? changelog_filename.exist? end |
#changelog_filename ⇒ Pathname (private)
The changelog_filename method returns the Pathname object for the changelog file path.
This method accesses the changelog_filename attribute from the associated GemHadar instance and wraps it in a Pathname object for convenient file path manipulation.
219 220 221 |
# File 'lib/gem_hadar/changelog_generator.rb', line 219 def changelog_filename Pathname.new(@gem_hadar.changelog.filename) 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.
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 |
#find_highest_version(filename) ⇒ GemHadar::VersionSpec? (private)
The find_highest_version method extracts version specifications from a changelog file and returns the highest version found
This method reads through the specified file line by line, scanning for lines that match the pattern of a changelog entry header with a version number, and collects all found version specifications. It then determines and returns the version specification with the highest version number
331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/gem_hadar/changelog_generator.rb', line 331 def find_highest_version(filename) File.open(filename, ?r) do |input| specs = [] input.each do |line| line.scan(/^## \d{4}-\d{2}-\d{2} v(\d+\.\d+\.\d+)$/) do specs << GemHadar::VersionSpec[$1] end end specs.max_by(&:version) end 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.
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_changelog(versions, changelog: []) ⇒ Array<String> (private)
The generate_changelog method creates a series of changelog entries by processing consecutive version pairs.
This method takes an array of version specifications, iterates through them in pairs, and generates AI-powered changelog entries for each range. It uses the ollama_generate method to produce content for each version interval and collects the results in reverse order.
270 271 272 273 274 275 276 277 278 279 |
# File 'lib/gem_hadar/changelog_generator.rb', line 270 def generate_changelog(versions, changelog: []) versions = versions.each_cons(2). (total: versions.size - 1, label: 'Change') versions.each do |range_from, range_to| changelog << generate(range_from, range_to) + end .newline changelog.reverse 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
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
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 |
#inject_into_filename(filename, changelog) ⇒ Integer (private)
The inject_into_filename method inserts changelog entries into a specified file.
This method reads an existing file line by line and identifies the location of a “# Changes” header. When this header is found, it inserts the provided changelog entries immediately after the header and before the next empty line.
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/gem_hadar/changelog_generator.rb', line 293 def inject_into_filename(filename, changelog) File.open(filename) do |input| File.secure_write(filename) do |output| start_add = nil input.each do |line| if start_add.nil? && line =~ /^# Changes$/ start_add = true output.puts line next end if start_add && line =~ /^$/ changelog.each do |entry| output.puts entry end output.puts line start_add = false next end output.puts line end end end changelog.size end |
#ollama_generate(**opts) ⇒ String? (private)
The ollama_generate method delegates AI generation requests to the associated GemHadar instance.
This method acts as a proxy that forwards the provided options to the ollama_generate method of the parent GemHadar object, enabling AI-powered text generation using configured Ollama models.
234 235 236 |
# File 'lib/gem_hadar/changelog_generator.rb', line 234 def ollama_generate(**opts) @gem_hadar.ollama_generate(**opts) end |
#read_versions ⇒ Array<GemHadar::VersionSpec> (private)
The read_versions method retrieves and processes semantic version tags from the Git repository.
This method fetches all Git tags from the repository, filters them to include only those that match semantic versioning patterns (containing three numeric components separated by dots), removes any ‘v’ prefix from the tags, and sorts the resulting version specifications in ascending order according to semantic versioning rules.
250 251 252 253 254 255 |
# File 'lib/gem_hadar/changelog_generator.rb', line 250 def read_versions = `git tag`.lines.grep(/^v?\d+\.\d+\.\d+$/).map(&:chomp) versions = .map { |tag| GemHadar::VersionSpec[tag] } versions = versions.sort_by(&:version) end |