gem_hadar 1.26.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3fefed7b5fd9123e2944de9cf2defcd9f1794aaa7d0058621539b22a2e076d3
4
- data.tar.gz: 8734f8f3cf30c0a0b501e5484a58bc5b4bbc4190258133f6de7b1105f17c7383
3
+ metadata.gz: 0e57d99439c8c2f1dc0538ece4d25ba460afc75d96ba37b7ce26ff64053fea65
4
+ data.tar.gz: 4a19dd7d7968dab5f5c4090cb4daeb4f329b589dff80d926dcfbf5123619f215
5
5
  SHA512:
6
- metadata.gz: 867a63019ba90544ba9b0c91478482128d3527221d9c11473929d9f18b5c74673d2fc3ab5844bc26779680b724965a9a7a455518286c5ca9a496342371c31c1a
7
- data.tar.gz: a6fa278536336a668d025947b3d9f274d4cc02ae9e2a3d50bb2a2a87b42ee2d351bfb191d9eb472bd215b521c34b561c4ee5d9f15cfcec93576f98871df23c10
6
+ metadata.gz: caa877d26d2a9057fe6889924f164bc51ef1d902dba3300bc988b8da7ae6c9bd912341bfd161c017f4501308cdcd80b5b40df765643a0610eeb9fc41b2debd0e
7
+ data.tar.gz: af306f158d730ac15b557cdb2543d6e0dece6d752be01cd10493aa2f91dc829b7495b4102061a436eef5a2af2fe406abe31cb3d6bd3b2f260d262f83095b021c
data/README.md CHANGED
@@ -77,7 +77,7 @@ graph TD
77
77
 
78
78
  The source of this library is located at
79
79
 
80
- * http://github.com/flori/gem\_hadar
80
+ * http://github.com/flori/gem_hadar
81
81
 
82
82
  or can be installed via
83
83
 
@@ -85,6 +85,151 @@ or can be installed via
85
85
  $ gem install gem_hadar
86
86
  ```
87
87
 
88
+ ## Configuration
89
+
90
+ ### Environment Variables
91
+
92
+ The following environment variables can be used to configure `gem_hadar`:
93
+
94
+ | Variable | Description | Default |
95
+ |----------|-------------|---------|
96
+ | `GEM_HOST_API_KEY` | API key for gem hosting services | Not set |
97
+ | `GITHUB_API_TOKEN` | GitHub personal access token for releases | Not set |
98
+ | `OLLAMA_MODEL` | Ollama model name for AI generation | `llama3.1` |
99
+ | `OLLAMA_HOST` | Ollama server host URL | `localhost:11434` |
100
+ | `OLLAMA_URL` | Direct Ollama API URL (takes precedence over `OLLAMA_HOST`) | Not set |
101
+ | `OLLAMA_MODEL_OPTIONS` | JSON configuration for Ollama model | Not set |
102
+ | `HOME` | User's home directory (used for config file locations) | System default |
103
+ | `XDG_CONFIG_HOME` | XDG configuration directory override | System default |
104
+ | `MAKE` | Make program to use for building extensions | `gmake` or `make` |
105
+ | `VERSION` | Override the version string for some tasks | Not set |
106
+ | `FORCE` | Force certain operations (1 to enable) | 0 |
107
+ | `GIT_REMOTE` | Git remote name(s) for operations, space separated | `origin` |
108
+ | `GITHUB_RELEASE_ENABLED` | Enable GitHub releases (yes/no) | Auto-detected |
109
+ | `EDITOR` | Editor to use for interactive tasks | `vi` |
110
+
111
+ ### Rubygems API
112
+
113
+ To publish gems to RubyGems.org, you'll need to set up an API key:
114
+
115
+ 1. Generate a new API key at: https://rubygems.org/profile/api_keys/new
116
+ 2. Set the environment variable:
117
+
118
+ ```bash
119
+ export GEM_HOST_API_KEY="your_api_key_here"
120
+ ```
121
+
122
+ **Security Note**: Never commit your API key to version control. Use a `.env`
123
+ file or your shell's configuration with appropriate loading mechanisms.
124
+
125
+ This key is required for tasks like `rake release` which push the gem package to RubyGems.org.
126
+
127
+ ### Github API
128
+
129
+ To enable GitHub release creation and other GitHub API interactions, you'll
130
+ need to set up a personal access token.
131
+
132
+ 1. Generate a new token at: https://github.com/settings/tokens/new
133
+ 2. Grant it `repo` scope for full repository access
134
+ 3. Set the environment variable:
135
+
136
+ ```bash
137
+ export GITHUB_API_TOKEN="your_token_here"
138
+ ```
139
+
140
+ **Security Note**: Never commit your token to version control. Use a `.env`
141
+ file or your shell's configuration with appropriate loading mechanisms.
142
+
143
+ This token is required for tasks like `rake github:release` which create GitHub
144
+ releases with AI-generated changelogs.
145
+
146
+ ### Local Ollama AI
147
+
148
+ The gem supports AI-powered changelog generation using Ollama. To configure
149
+ this functionality:
150
+
151
+ 1. Install and run Ollama locally: https://ollama.com/download
152
+ 2. Pull the desired model (e.g., `ollama pull deepseek-r1:32b`)
153
+ 3. Set the following environment variables:
154
+
155
+ ```bash
156
+ export OLLAMA_HOST="http://localhost:11434"
157
+ export OLLAMA_MODEL="deepseek-r1:32b"
158
+ export OLLAMA_MODEL_OPTIONS='{"num_ctx":16384,"seed":-1,"num_predict":512,"temperature":0.4,"top_p":0.95,"top_k":20,"min_p":0}'
159
+ ```
160
+
161
+ The default model is `llama3.1` and the default host is
162
+ `http://localhost:11434`. These can be overridden based on your local Ollama
163
+ setup.
164
+
165
+ The model options example configures:
166
+
167
+ - `num_ctx`: Context window size (16384 tokens)
168
+ - `temperature`: Response randomness (0.4 for balanced output)
169
+ - `num_predict`: Maximum tokens to generate (512)
170
+ - `top_p`, `top_k`, `min_p`: Sampling parameters for controlled generation
171
+
172
+ This functionality is used by the `rake github:release` and `rake version:bump`
173
+ task to generate AI-powered changelogs or suggest a version bump.
174
+
175
+ ### Custom AI Prompts
176
+
177
+ To customize the AI prompts used by `gem_hadar`, you can override the default
178
+ prompt files in your XDG configuration directory.
179
+
180
+ First, display the current default prompts using:
181
+
182
+ ```bash
183
+ $ rake gem_hadar:config
184
+ ```
185
+
186
+ This will show you the `XDG_CONFIG_HOME`, default system and user prompts for
187
+ version bumping and release generation. The output includes the exact template
188
+ variables that are available for use in your custom prompts.
189
+
190
+ Then, create the following files in your XDG configuration home directory:
191
+
192
+ - `version_bump_system_prompt.txt`
193
+ - `version_bump_prompt.txt`
194
+ - `release_system_prompt.txt`
195
+ - `release_prompt.txt`
196
+
197
+ Start with the default values shown by `rake gem_hadar:config` and modify them
198
+ to suit your needs. The prompts support standard Ruby string interpolation with
199
+ the following variables:
200
+
201
+ For version bump prompts:
202
+ - `%{version}` - Current gem version
203
+ - `%{log_diff}` - Git diff of changes
204
+
205
+ For release prompts:
206
+ - `%{name}` - Gem name
207
+ - `%{version}` - New version being released
208
+ - `%{log_diff}` - Git diff of changes
209
+
210
+ This approach ensures your custom prompts work correctly with the template
211
+ variables while maintaining consistency with the gem's expected input format.
212
+
213
+ ### Output current configuration
214
+
215
+ To debug or verify your `gem_hadar` configuration, you can use the following
216
+ rake task:
217
+
218
+ ```bash
219
+ $ rake gem_hadar:config
220
+ ```
221
+
222
+ This task displays all current configuration values including:
223
+ - GitHub API token (masked)
224
+ - RubyGems API key (masked)
225
+ - Ollama model settings
226
+ - Repository information (gem name, version)
227
+ - Build parameters (MAKE, EDITOR)
228
+ - Git configuration (remote)
229
+ - Other flags (FORCE, VERSION, GITHUB_RELEASE_ENABLED)
230
+ - XDG/HOME directories
231
+ - AI prompt defaults
232
+
88
233
  ## Usage
89
234
 
90
235
  ### Pre-requisites
@@ -160,6 +305,115 @@ end
160
305
 
161
306
  Note that `gem_hadar` is ["self hosted"](Rakefile)
162
307
 
308
+ ### Configuration settings in the GemHadar block
309
+
310
+ #### Core Required Attributes (Mapped to GemSpec)
311
+
312
+ - **`name`** - Required gem name (raises error if not set)
313
+ - **`version`** - Required version with fallback to `VERSION` file or ENV override
314
+ - **`authors`** - Required author names (mapped from `author`)
315
+ - **`email`** - Required author email (raises error if not set)
316
+ - **`homepage`** - Required homepage URL (raises error if not set). **Validation**: When `developing` is false, validates that the URL returns an HTTP OK status after following redirects.
317
+ - **`summary`** - Required summary description (raises error if not set)
318
+ - **`description`** - Required full description (raises error if not set)
319
+
320
+ #### Core Recommended Attributes
321
+
322
+ - **`licenses`** - Default: `Set[]`. License information for the gem
323
+ - **`required_ruby_version`** - Default: `nil`. Ruby version requirement
324
+
325
+ #### Build and Package Configuration
326
+
327
+ - **`require_paths`** - Default: `Set['lib']` (mapped to `require_paths`)
328
+ - **`test_dir`** - Default: `nil`
329
+ - **`spec_dir`** - Default: `nil`
330
+ - **`extensions`** - Default: `FileList['ext/**/extconf.rb']` (mapped to `extensions`)
331
+ - **`make`** - Default: `ENV['MAKE']` or system detection
332
+ - **`executables`** - Default: `Set[]` (mapped to `executables`)
333
+ - **`ignore_files`** - Default: `Set[]`
334
+ - **`package_ignore_files`** - Default: `Set[]`
335
+
336
+ #### Documentation and Files
337
+
338
+ - **`readme`** - Default: `nil`
339
+ - **`title`** - Default: `nil`
340
+ - **`doc_files`** - Default: `nil`
341
+ - **`yard_dir`** - Default: `nil`
342
+
343
+ #### Testing Configuration
344
+
345
+ - **`test_files`** - Default: `nil`
346
+ - **`spec_pattern`** - Default: `nil`
347
+ - **`bindir`** - Default: `nil` (mapped to `bindir`)
348
+
349
+ #### RVM Configuration (Nested)
350
+
351
+ ```ruby
352
+ rvm do
353
+ use # Default: detected ruby version from `rvm tools strings`
354
+ gemset # Default: gem name
355
+ end
356
+ ```
357
+
358
+ #### Task Dependencies
359
+
360
+ - **`default_task_dependencies`** - Default: `[:gemspec, :test]`
361
+ - **`build_task_dependencies`** - Default: `[:clobber, :gemspec, :package, :'version:tag']`
362
+ - **`push_task_dependencies`** - Default: `[:modified, :build, :master:push, :version:push, :gem:push, :github:release]`
363
+
364
+ #### Configuration Flags
365
+
366
+ - **`developing`** - Default: `false`. When set to `true`, skips URL validation including homepage link verification for faster development cycles.
367
+
368
+ ### Paths and Module Types
369
+
370
+ - **`path_name`** - Default: `name`. Returns the raw gem name value by default.
371
+ It is used for generating file paths and module names. This is particularly
372
+ useful for creating consistent directory structures and file naming
373
+ conventions. It's used internally by `GemHadar` to create the root directory
374
+ for the gem (`lib/my_gem` for name "my\_gem") and generate a `version.rb` file
375
+ in that location.
376
+
377
+ This can be changed for nested namespaces if desired.
378
+
379
+ **Example**: For gems in namespaces like `ACME` like
380
+ `ACME::BrainfuckCompiler`, you might set `path_name` to
381
+ `"acme/brainfuck_compiler"` to create the directory structure
382
+ `lib/acme/brainfuck_compiler/`.
383
+
384
+ - **`path_module`** - Default: `path_name.camelize`. Automatically converts the
385
+ gem name to CamelCase format (e.g., "my\_gem" becomes "MyGem",
386
+ "namespace/my\_gem" becomes "Namespace::MyGem") for use in Ruby module and
387
+ class declarations, ensuring consistency with Ruby naming
388
+ conventions. This value can be overridden if needed.
389
+
390
+ - **`module_type`** - Default: `:module`. Determines whether the generated code
391
+ structure for the version module should be a `:module` or `:class`. This
392
+ controls the type of Ruby construct created when generating code skeletons and
393
+ version files. The value
394
+ can be set to either:
395
+
396
+ - `:module` (default) - Generates module-based structure
397
+ - `:class` - Generates class-based structure
398
+
399
+ This is used in the generated `version.rb` file to create either:
400
+ ```ruby
401
+ module MyGem
402
+ # ... version constants
403
+ end
404
+ ```
405
+ or
406
+ ```ruby
407
+ class MyGem
408
+ # ... version constants
409
+ end
410
+ ```
411
+
412
+ These computed values serve as intelligent defaults that can be overridden
413
+ based on your specific requirements. They are automatically derived from other
414
+ DSL accessors and provide powerful convenience features that enable `GemHadar`
415
+ to generate consistent, well-structured Ruby code automatically.
416
+
163
417
  ### Available Tasks
164
418
 
165
419
  You can list all available tasks with:
@@ -222,7 +476,51 @@ $ rake -T
222
476
  - `rake github:release` - Create a new GitHub release for the current version
223
477
  with AI-generated changelog
224
478
 
225
- ### Update Version
479
+ ### Code Coverage with SimpleCov
480
+
481
+ To enable detailed code coverage reporting in your project using `GemHadar`,
482
+ follow these steps:
483
+
484
+ 1. **Install Required Dependencies**
485
+
486
+ Ensure that `simplecov` is included in your `Gemfile`:
487
+
488
+ ```ruby
489
+ gem 'simplecov'
490
+ ```
491
+
492
+ 2. **Initialize Coverage in Your Test Setup**
493
+
494
+ Add this line to the top of your test helper file (e.g., `spec_helper.rb`,
495
+ `test_helper.rb`):
496
+
497
+ ```ruby
498
+ require 'gem_hadar/simplecov'
499
+ GemHadar::SimpleCov.start
500
+ ```
501
+
502
+ 3. **Enable Coverage Reporting**
503
+
504
+ Run tests with the environment variable `START_SIMPLECOV=1`:
505
+
506
+ ```bash
507
+ START_SIMPLECOV=1 bundle exec rspec
508
+ ```
509
+
510
+ This will generate coverage reports in both HTML and JSON formats.
511
+
512
+ 4. **Viewing Reports**
513
+
514
+ After running tests, you can view:
515
+ - **HTML Report**: `coverage/index.html`
516
+ - **JSON Context**: `coverage/coverage_context.json`
517
+
518
+ > 🧪 *Tip:* Enable coverage reporting by setting the `START_SIMPLECOV`
519
+ > environment variable to `1`. The JSON output includes detailed line and
520
+ > branch coverage statistics per file, making it ideal for integration with CI
521
+ > tools or custom dashboards.
522
+
523
+ ### Update Gem Version
226
524
 
227
525
  Use one of the following rake tasks to bump the version:
228
526
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.26.0
1
+ 1.28.0
data/gem_hadar.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: gem_hadar 1.26.0 ruby lib
2
+ # stub: gem_hadar 1.28.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "gem_hadar".freeze
6
- s.version = "1.26.0".freeze
6
+ s.version = "1.28.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.description = "This library contains some useful functionality to support the development of Ruby Gems".freeze
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.executables = ["gem_hadar".freeze]
15
- s.extra_rdoc_files = ["README.md".freeze, "lib/gem_hadar.rb".freeze, "lib/gem_hadar/github.rb".freeze, "lib/gem_hadar/prompt_template.rb".freeze, "lib/gem_hadar/setup.rb".freeze, "lib/gem_hadar/template_compiler.rb".freeze, "lib/gem_hadar/utils.rb".freeze, "lib/gem_hadar/version.rb".freeze]
16
- s.files = [".gitignore".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/gem_hadar".freeze, "gem_hadar.gemspec".freeze, "lib/gem_hadar.rb".freeze, "lib/gem_hadar/github.rb".freeze, "lib/gem_hadar/prompt_template.rb".freeze, "lib/gem_hadar/setup.rb".freeze, "lib/gem_hadar/template_compiler.rb".freeze, "lib/gem_hadar/utils.rb".freeze, "lib/gem_hadar/version.rb".freeze]
15
+ s.extra_rdoc_files = ["README.md".freeze, "lib/gem_hadar.rb".freeze, "lib/gem_hadar/github.rb".freeze, "lib/gem_hadar/prompt_template.rb".freeze, "lib/gem_hadar/setup.rb".freeze, "lib/gem_hadar/simplecov.rb".freeze, "lib/gem_hadar/template_compiler.rb".freeze, "lib/gem_hadar/utils.rb".freeze, "lib/gem_hadar/version.rb".freeze]
16
+ s.files = [".gitignore".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/gem_hadar".freeze, "gem_hadar.gemspec".freeze, "lib/gem_hadar.rb".freeze, "lib/gem_hadar/github.rb".freeze, "lib/gem_hadar/prompt_template.rb".freeze, "lib/gem_hadar/setup.rb".freeze, "lib/gem_hadar/simplecov.rb".freeze, "lib/gem_hadar/template_compiler.rb".freeze, "lib/gem_hadar/utils.rb".freeze, "lib/gem_hadar/version.rb".freeze]
17
17
  s.homepage = "https://github.com/flori/gem_hadar".freeze
18
18
  s.licenses = ["MIT".freeze]
19
19
  s.rdoc_options = ["--title".freeze, "GemHadar - Library for the development of Ruby Gems".freeze, "--main".freeze, "README.md".freeze]
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.specification_version = 4
24
24
 
25
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.26".freeze])
25
+ s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.27".freeze])
26
26
  s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.0".freeze])
27
27
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.0".freeze])
28
28
  s.add_runtime_dependency(%q<ollama-ruby>.freeze, ["~> 1.0".freeze])
@@ -0,0 +1,182 @@
1
+ require 'term/ansicolor'
2
+ require 'tins/xt/secure_write'
3
+ require 'fileutils'
4
+ require 'pathname'
5
+
6
+ class GemHadar
7
+ end
8
+
9
+ module GemHadar::SimpleCov
10
+ module WarnModule
11
+ # The warn method displays warning messages using orange colored output.
12
+ #
13
+ # This method takes an array of message strings, applies orange color
14
+ # formatting to each message, and then passes them to the superclass's warn
15
+ # method for display. The uplevel: 1 option ensures that the warning
16
+ # originates from the caller's context rather than from within this method
17
+ # itself.
18
+ #
19
+ # @param msgs [ Array<String> ] the array of message strings to display as warnings
20
+ def warn(*msgs)
21
+ msgs.map! { |m| color(208) { m } }
22
+ super(*msgs, uplevel: 1)
23
+ end
24
+ end
25
+
26
+ class ContextFormatter
27
+ include FileUtils
28
+
29
+ # The format method processes code coverage results and generates a
30
+ # detailed JSON report.
31
+ #
32
+ # This method takes a SimpleCov result object and transforms its coverage
33
+ # data into a structured format that includes both line and branch coverage
34
+ # statistics for individual files, as well as overall project coverage
35
+ # metrics. It calculates various percentages and counts, then writes the
36
+ # complete coverage data to a JSON file in the coverage directory.
37
+ #
38
+ # @param result [ SimpleCov::Result ] the coverage result object containing files and statistics
39
+ #
40
+ # @return [ String ] an empty string, as the method's primary purpose is to write data to a file
41
+ def format(result)
42
+ files = result.files.map do |file|
43
+ line_coverage_statistics = extract_coverage_info(file.coverage_statistics[:line])
44
+ branch_coverage_statistics = extract_coverage_info(file.coverage_statistics[:branch])
45
+ {
46
+ filename: file.filename,
47
+ line_coverage_statistics:,
48
+ branch_coverage_statistics:,
49
+ }
50
+ end
51
+ covered_files = result.files.count { |file| file.coverage_statistics[:line].covered > 0 }
52
+ uncovered_files = result.files.count { |file| file.coverage_statistics[:line].covered == 0 }
53
+ files_count = result.files.length
54
+ files_covered_percent = files_count > 0 ? (100 * covered_files.to_f / files_count).round(2) : 0
55
+ branch_covered_percent =
56
+ result.total_branches > 0 ? (result.covered_branches.to_f / result.total_branches * 100).round(2) : 0
57
+ coverage_data = {
58
+ project_name:,
59
+ version:,
60
+ timestamp: Time.now.iso8601,
61
+ files:,
62
+ overall_coverage: {
63
+ covered_percent: result.covered_percent.round(2),
64
+ total_lines: result.total_lines,
65
+ covered_lines: result.covered_lines,
66
+ missed_lines: result.missed_lines,
67
+ branch_covered_percent:,
68
+ total_branches: result.total_branches,
69
+ covered_branches: result.covered_branches,
70
+ missed_branches: result.missed_branches,
71
+ coverage_strength: result.covered_strength.round(2),
72
+ least_covered_file: result.least_covered_file,
73
+ covered_files:,
74
+ uncovered_files:,
75
+ files_count:,
76
+ files_covered_percent:,
77
+ },
78
+ }
79
+
80
+ # Write to a dedicated coverage data file,
81
+ coverage_dir = Pathname.new('coverage')
82
+ mkdir_p coverage_dir
83
+ filename = File.expand_path(coverage_dir + 'coverage_context.json')
84
+ File.secure_write(filename, JSON.pretty_generate(coverage_data))
85
+ STDERR.puts "Wrote detailed coverage context to #{filename.to_s.inspect}."
86
+ ""
87
+ end
88
+
89
+ private
90
+
91
+ include WarnModule
92
+
93
+ # The project_name method retrieves the name of the current working
94
+ # directory.
95
+ #
96
+ # This method obtains the absolute path of the current working directory
97
+ # and extracts its basename, returning it as a string. It is typically used
98
+ # to identify the project name based on the directory structure.
99
+ #
100
+ # @return [ String ] the name of the current working directory
101
+ def project_name
102
+ Pathname.pwd.basename.to_s # I hope…
103
+ end
104
+
105
+ # The version method reads and returns the current version string from the
106
+ # VERSION file.
107
+ #
108
+ # This method attempts to read the contents of the VERSION file, removing
109
+ # any trailing whitespace. If the VERSION file does not exist, it returns
110
+ # the string 'unknown' instead.
111
+ #
112
+ # @return [ String ] the version string read from the VERSION file, or
113
+ # 'unknown' if the file is missing
114
+ def version
115
+ File.read('VERSION').chomp
116
+ rescue Errno::ENOENT => e
117
+ warn "Using version 'unknown', caught #{e.class}: #{e}"
118
+ 'unknown'
119
+ end
120
+
121
+ # The extract_coverage_info method transforms coverage statistics into a
122
+ # structured hash format.
123
+ #
124
+ # This method takes a coverage statistics object and extracts specific
125
+ # attributes into a new hash, making the data more accessible for reporting
126
+ # and analysis.
127
+ #
128
+ # @param coverage_statistics [ SimpleCov::CoverageStatistics ] the coverage
129
+ # statistics object to process
130
+ #
131
+ # @return [ Hash ] a hash containing the extracted coverage metrics with
132
+ # keys :total, :covered, :missed, :strength, and :percent
133
+ def extract_coverage_info(coverage_statistics)
134
+ %i[ total covered missed strength percent ].each_with_object({}) do |attr, hash|
135
+ hash[attr] = coverage_statistics.send(attr)
136
+ end
137
+ end
138
+ end
139
+
140
+ class << self
141
+ include Term::ANSIColor
142
+
143
+ # The start method initializes and configures SimpleCov for code coverage
144
+ # analysis.
145
+ #
146
+ # This method checks if the START_SIMPLECOV environment variable is set to
147
+ # 1 before proceeding with SimpleCov setup. If disabled, it outputs a
148
+ # message indicating that SimpleCov startup is skipped. When enabled, it
149
+ # requires the simplecov gem, configures coverage to include branch
150
+ # coverage, adds a filter based on the caller's directory, and sets up
151
+ # multiple formatters including SimpleFormatter, HTMLFormatter, and a
152
+ # custom ContextFormatter.
153
+ def start
154
+ if ENV['START_SIMPLECOV'].to_i != 1
155
+ STDERR.puts color(226) {
156
+ "Skip starting Simplecov for code coverage, "\
157
+ "enable by setting env var: START_SIMPLECOV=1"
158
+ }
159
+ return
160
+ end
161
+ require 'simplecov'
162
+ STDERR.puts color(76) { "Configuring Simplecov for code coverage." }
163
+ filter = "#{File.basename(File.dirname(caller.first))}/"
164
+ SimpleCov.start do
165
+ enable_coverage :branch
166
+ add_filter filter
167
+ formatter SimpleCov::Formatter::MultiFormatter.new([
168
+ SimpleCov::Formatter::SimpleFormatter,
169
+ SimpleCov::Formatter::HTMLFormatter,
170
+ GemHadar::SimpleCov::ContextFormatter,
171
+ ])
172
+ end
173
+ rescue LoadError => e
174
+ warn "Caught #{e.class}: #{e}"
175
+ STDERR.puts "Install with: gem install simplecov"
176
+ end
177
+
178
+ private
179
+
180
+ include WarnModule
181
+ end
182
+ end
@@ -1,4 +1,20 @@
1
+ require 'pathname'
2
+
1
3
  module GemHadar::Utils
4
+ # The xdg_config_home method determines the path to the XDG configuration
5
+ # directory.
6
+ #
7
+ # It first checks if the XDG_CONFIG_HOME environment variable is set and not
8
+ # empty. If it is set, the method returns the value as a Pathname object. If
9
+ # XDG_CONFIG_HOME is not set, it defaults to using the HOME environment
10
+ # variable to construct the path within the standard .config directory.
11
+ #
12
+ # @return [ Pathname ] the Pathname object representing the XDG configuration directory
13
+ def xdg_config_home
14
+ ENV['XDG_CONFIG_HOME'].full? { Pathname.new(_1) } ||
15
+ Pathname.new(ENV.fetch('HOME')) + '.config'
16
+ end
17
+
2
18
  # The xdg_config_filename method constructs the full path to a configuration
3
19
  # file based on the XDG Base Directory specification.
4
20
  #
@@ -12,11 +28,7 @@ module GemHadar::Utils
12
28
  #
13
29
  # @return [ String ] the full path to the configuration file
14
30
  def xdg_config_filename(name)
15
- if xdg = ENV['XDG_CONFIG_HOME'].full?
16
- File.join(xdg, name)
17
- else
18
- File.join(ENV.fetch('HOME'), '.config', name)
19
- end
31
+ xdg_config_home + name
20
32
  end
21
33
 
22
34
  memoize method:
@@ -1,6 +1,6 @@
1
1
  class GemHadar
2
2
  # GemHadar version
3
- VERSION = '1.26.0'
3
+ VERSION = '1.28.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/gem_hadar.rb CHANGED
@@ -1082,12 +1082,79 @@ class GemHadar
1082
1082
  task :yard => %i[ yard:private yard:view ]
1083
1083
  end
1084
1084
 
1085
+ def config_task
1086
+ namespace :gem_hadar do
1087
+ desc "Display current gem_hadar configuration"
1088
+ task :config do
1089
+ puts "=== GemHadar Configuration ==="
1090
+
1091
+ # RubyGems
1092
+ if ENV['GEM_HOST_API_KEY'].present?
1093
+ puts "RubyGems API Key: *** (set)"
1094
+ else
1095
+ puts "RubyGems API Key: Not set"
1096
+ end
1097
+
1098
+ # GitHub
1099
+ if ENV['GITHUB_API_TOKEN'].present?
1100
+ puts "GitHub API Token: *** (set)"
1101
+ else
1102
+ puts "GitHub API Token: Not set"
1103
+ end
1104
+
1105
+ # Ollama
1106
+ puts "Ollama Model: #{ollama_model} (default is #{ollama_model_default})"
1107
+
1108
+ if url = ollama_client&.full?(:base_url)&.to_s
1109
+ puts "Ollama Base URL: #{url.inspect}"
1110
+ else
1111
+ puts "Ollama Base URL: Not set"
1112
+ end
1113
+
1114
+ if ENV['OLLAMA_MODEL_OPTIONS']
1115
+ puts "Ollama Model Options: #{ENV['OLLAMA_MODEL_OPTIONS']}"
1116
+ else
1117
+ puts "Ollama Model Options: Not set (using defaults)"
1118
+ end
1119
+
1120
+ # XDG config home
1121
+ puts "XDG config home: #{xdg_config_home.to_s.inspect}"
1122
+
1123
+ # General
1124
+ puts "Gem Name: #{name}"
1125
+ puts "Version: #{version}"
1126
+
1127
+ # Build/Development
1128
+ puts "MAKE: #{ENV['MAKE'] || 'Not set (will use gmake or make)'}"
1129
+ puts "EDITOR: #{ENV['EDITOR'] || 'Not set (will use vi)'}"
1130
+
1131
+ # Git
1132
+ puts "Git Remote(s): #{ENV['GIT_REMOTE'] || 'origin'}"
1133
+
1134
+ # Other
1135
+ puts "Force Operations: #{ENV['FORCE'] || '0'}"
1136
+ puts "Version Override: #{ENV['VERSION'] || 'Not set'}"
1137
+ puts "GitHub Release Enabled: #{ENV['GITHUB_RELEASE_ENABLED'] || 'Not set'}"
1138
+
1139
+ puts "\n=== AI Prompt Configuration (Default Values) ==="
1140
+ arrow = ?⤵
1141
+ puts bold{"version_bump_system_prompt.txt"} + "#{arrow}\n" + italic{default_version_bump_system_prompt}
1142
+ puts bold{"version_bump_prompt.txt"} + "#{arrow}\n#{default_version_bump_prompt}"
1143
+ puts bold{"release_system_prompt.txt"} + "#{arrow}\n" + italic{default_git_release_system_prompt}
1144
+ puts bold{"release_prompt.txt"} + "#{arrow}\n" + italic{default_git_release_prompt}
1145
+
1146
+ puts "=== End Configuration ==="
1147
+ end
1148
+ end
1149
+ end
1150
+
1085
1151
  # The create_all_tasks method sets up and registers all the Rake tasks for
1086
1152
  # the gem project.
1087
1153
  #
1088
1154
  # @return [GemHadar] the instance of GemHadar
1089
1155
  def create_all_tasks
1090
1156
  default_task
1157
+ config_task
1091
1158
  build_task
1092
1159
  rvm_task
1093
1160
  version_task
@@ -1144,20 +1211,53 @@ class GemHadar
1144
1211
  temp_file&.close&.unlink
1145
1212
  end
1146
1213
 
1214
+ dsl_accessor :ollama_model_default, 'llama3.1'.freeze
1215
+
1216
+ # The ollama_model method retrieves the name of the Ollama AI model to be
1217
+ # used for generating responses.
1218
+ #
1219
+ # It first checks the OLLAMA_MODEL environment variable for a custom model
1220
+ # specification. If the environment variable is not set, it falls back to
1221
+ # using the default model name, which is determined by the
1222
+ # ollama_model_default dsl method.
1223
+ #
1224
+ # @return [ String ] the name of the Ollama AI model to be used
1225
+ def ollama_model
1226
+ ENV.fetch('OLLAMA_MODEL', ollama_model_default)
1227
+ end
1228
+
1229
+ # The ollama_client method creates and returns an Ollama::Client instance
1230
+ # configured with a base URL derived from environment variables.
1231
+ #
1232
+ # It first checks for the OLLAMA_URL environment variable to determine the
1233
+ # base URL. If that is not set, it falls back to using the OLLAMA_HOST
1234
+ # environment variable, defaulting to 'localhost:11434' if that is also not
1235
+ # set. The method then constructs the full base URL and initializes an
1236
+ # Ollama::Client with appropriate timeouts for read and connect operations.
1237
+ #
1238
+ # @return [Ollama::Client, nil] An initialized Ollama::Client instance if a valid base URL is present, otherwise nil.
1239
+ def ollama_client
1240
+ base_url = ENV['OLLAMA_URL']
1241
+ if base_url.blank?
1242
+ host = ENV.fetch('OLLAMA_HOST', 'localhost:11434')
1243
+ base_url = 'http://%s' % host
1244
+ end
1245
+ base_url.present? or return
1246
+ ollama = Ollama::Client.new(base_url:, read_timeout: 600, connect_timeout: 60)
1247
+ end
1248
+
1147
1249
  # Generates a response from an AI model using the Ollama::Client.
1148
1250
  #
1149
1251
  # @param [String] system The system prompt for the AI model.
1150
1252
  # @param [String] prompt The user prompt to generate a response to.
1151
1253
  # @return [String, nil] The generated response or nil if generation fails.
1152
1254
  def ollama_generate(system:, prompt:)
1153
- base_url = ENV['OLLAMA_URL']
1154
- if base_url.blank? && host = ENV['OLLAMA_HOST'].full?
1155
- base_url = 'http://%s' % host
1255
+ unless ollama = ollama_client
1256
+ warn "Ollama is not configured. => Returning."
1257
+ return
1156
1258
  end
1157
- base_url.present? or return
1158
- ollama = Ollama::Client.new(base_url:, read_timeout: 600, connect_timeout: 60)
1159
- model = ENV.fetch('OLLAMA_MODEL', 'llama3.1')
1160
- options = ENV['OLLAMA_OPTIONS'].full? { |o| JSON.parse(o) } || {}
1259
+ model = ollama_model
1260
+ options = ENV['OLLAMA_MODEL_OPTIONS'].full? { |o| JSON.parse(o) } || {}
1161
1261
  options |= { "temperature" => 0, "top_p" => 1, "min_p" => 0.1 }
1162
1262
  ollama.generate(model:, system:, prompt:, options:, stream: false, think: false).response
1163
1263
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_hadar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.0
4
+ version: 1.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '1.26'
18
+ version: '1.27'
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '1.26'
25
+ version: '1.27'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: tins
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +119,7 @@ extra_rdoc_files:
119
119
  - lib/gem_hadar/github.rb
120
120
  - lib/gem_hadar/prompt_template.rb
121
121
  - lib/gem_hadar/setup.rb
122
+ - lib/gem_hadar/simplecov.rb
122
123
  - lib/gem_hadar/template_compiler.rb
123
124
  - lib/gem_hadar/utils.rb
124
125
  - lib/gem_hadar/version.rb
@@ -135,6 +136,7 @@ files:
135
136
  - lib/gem_hadar/github.rb
136
137
  - lib/gem_hadar/prompt_template.rb
137
138
  - lib/gem_hadar/setup.rb
139
+ - lib/gem_hadar/simplecov.rb
138
140
  - lib/gem_hadar/template_compiler.rb
139
141
  - lib/gem_hadar/utils.rb
140
142
  - lib/gem_hadar/version.rb