gem_hadar 1.25.0 → 1.27.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 +4 -4
- data/README.md +479 -10
- data/VERSION +1 -1
- data/gem_hadar.gemspec +3 -3
- data/lib/gem_hadar/prompt_template.rb +37 -0
- data/lib/gem_hadar/setup.rb +4 -0
- data/lib/gem_hadar/template_compiler.rb +29 -0
- data/lib/gem_hadar/utils.rb +40 -5
- data/lib/gem_hadar/version.rb +1 -1
- data/lib/gem_hadar.rb +508 -53
- metadata +3 -3
data/lib/gem_hadar.rb
CHANGED
@@ -51,6 +51,12 @@ class GemHadar
|
|
51
51
|
block and instance_eval(&block)
|
52
52
|
end
|
53
53
|
|
54
|
+
# The has_to_be_set method raises an error if a required gem configuration
|
55
|
+
# attribute is not set.
|
56
|
+
#
|
57
|
+
# @param name [ String ] the name of the required attribute
|
58
|
+
#
|
59
|
+
# @raise [ ArgumentError ] if the specified attribute has not been set
|
54
60
|
def has_to_be_set(name)
|
55
61
|
fail "#{self.class}: #{name} has to be set for gem"
|
56
62
|
end
|
@@ -134,7 +140,7 @@ class GemHadar
|
|
134
140
|
end
|
135
141
|
|
136
142
|
dsl_accessor :yard_dir do
|
137
|
-
'
|
143
|
+
'doc'
|
138
144
|
end
|
139
145
|
|
140
146
|
dsl_accessor :extensions do FileList['ext/**/extconf.rb'] end
|
@@ -182,6 +188,18 @@ class GemHadar
|
|
182
188
|
dsl_accessor :gemset do @outer_scope.name end
|
183
189
|
end
|
184
190
|
|
191
|
+
# The rvm method configures RVM (Ruby Version Manager) settings for the gem
|
192
|
+
# project.
|
193
|
+
#
|
194
|
+
# This method initializes and returns an RvmConfig object that holds RVM-specific
|
195
|
+
# configuration such as the Ruby version to use and the gemset name.
|
196
|
+
# If a block is provided, it configures the RvmConfig object with the given
|
197
|
+
# settings. If no block is provided and no existing RvmConfig object exists,
|
198
|
+
# it creates a new one with default settings.
|
199
|
+
#
|
200
|
+
# @param block [ Proc ] optional block to configure RVM settings
|
201
|
+
#
|
202
|
+
# @return [ GemHadar::RvmConfig ] the RVM configuration object
|
185
203
|
def rvm(&block)
|
186
204
|
if block
|
187
205
|
@rvm = RvmConfig.new(&block)
|
@@ -193,6 +211,12 @@ class GemHadar
|
|
193
211
|
|
194
212
|
dsl_accessor :default_task_dependencies, [ :gemspec, :test ]
|
195
213
|
|
214
|
+
# The default_task method defines the default Rake task for the gem project.
|
215
|
+
#
|
216
|
+
# This method sets up a Rake task named :default that depends on the tasks
|
217
|
+
# specified in the default_task_dependencies accessor. It provides a convenient
|
218
|
+
# way to run the most common or essential tasks for the project with a single
|
219
|
+
# command.
|
196
220
|
def default_task
|
197
221
|
desc 'Default task'
|
198
222
|
task :default => default_task_dependencies
|
@@ -200,11 +224,26 @@ class GemHadar
|
|
200
224
|
|
201
225
|
dsl_accessor :build_task_dependencies, [ :clobber, :gemspec, :package, :'version:tag' ]
|
202
226
|
|
227
|
+
# The build_task method defines a Rake task that orchestrates the complete
|
228
|
+
# build process for packaging the gem.
|
229
|
+
#
|
230
|
+
# This method sets up a :build task that depends on the tasks specified in
|
231
|
+
# the build_task_dependencies accessor. It provides a convenient way to
|
232
|
+
# execute all necessary steps for building packages for a release with a
|
233
|
+
# single command.
|
203
234
|
def build_task
|
204
235
|
desc 'Build task (builds all packages for a release)'
|
205
236
|
task :build => build_task_dependencies
|
206
237
|
end
|
207
238
|
|
239
|
+
# The install_library method sets up a Rake task for installing the library
|
240
|
+
# or executable into site_ruby directories.
|
241
|
+
#
|
242
|
+
# This method configures an :install task that depends on the
|
243
|
+
# :prepare_install task and executes the provided block. It stores the block
|
244
|
+
# in an instance variable to be called later when the task is executed.
|
245
|
+
#
|
246
|
+
# @param block [ Proc ] the block containing the installation logic
|
208
247
|
def install_library(&block)
|
209
248
|
@install_library_block = -> do
|
210
249
|
desc 'Install executable/library into site_ruby directories'
|
@@ -212,6 +251,15 @@ class GemHadar
|
|
212
251
|
end
|
213
252
|
end
|
214
253
|
|
254
|
+
# The clean method manages the CLEAN file list for Rake tasks.
|
255
|
+
#
|
256
|
+
# When called without arguments, it returns the current CLEAN file list.
|
257
|
+
# When called with arguments, it adds the specified files to the CLEAN list.
|
258
|
+
#
|
259
|
+
# @param args [ Array<String> ] optional list of files to add to the CLEAN list
|
260
|
+
#
|
261
|
+
# @return [ FileList, nil ] the CLEAN file list when no arguments provided,
|
262
|
+
# nil otherwise
|
215
263
|
def clean(*args)
|
216
264
|
if args.empty?
|
217
265
|
CLEAN
|
@@ -220,6 +268,15 @@ class GemHadar
|
|
220
268
|
end
|
221
269
|
end
|
222
270
|
|
271
|
+
# The clobber method manages the CLOBBER file list for Rake tasks.
|
272
|
+
#
|
273
|
+
# When called without arguments, it returns the current CLOBBER file list.
|
274
|
+
# When called with arguments, it adds the specified files to the CLOBBER list.
|
275
|
+
#
|
276
|
+
# @param args [ Array<String> ] optional list of files to add to the CLOBBER list
|
277
|
+
#
|
278
|
+
# @return [ FileList, nil ] the CLOBBER file list when no arguments provided,
|
279
|
+
# nil otherwise
|
223
280
|
def clobber(*args)
|
224
281
|
if args.empty?
|
225
282
|
CLOBBER
|
@@ -228,6 +285,15 @@ class GemHadar
|
|
228
285
|
end
|
229
286
|
end
|
230
287
|
|
288
|
+
# The ignore method manages the list of files to be ignored by the gem.
|
289
|
+
#
|
290
|
+
# When called without arguments, it returns the current set of ignored files.
|
291
|
+
# When called with arguments, it adds the specified files to the ignore list.
|
292
|
+
#
|
293
|
+
# @param args [ Array<String> ] optional list of file patterns to add to the ignore list
|
294
|
+
#
|
295
|
+
# @return [ Set<String>, nil ] the set of ignored files when no arguments provided,
|
296
|
+
# nil otherwise
|
231
297
|
def ignore(*args)
|
232
298
|
if args.empty?
|
233
299
|
ignore_files
|
@@ -236,6 +302,17 @@ class GemHadar
|
|
236
302
|
end
|
237
303
|
end
|
238
304
|
|
305
|
+
# The package_ignore method manages the list of files to be ignored during
|
306
|
+
# gem packaging.
|
307
|
+
#
|
308
|
+
# When called without arguments, it returns the current set of package ignore
|
309
|
+
# files. When called with arguments, it adds the specified file patterns to
|
310
|
+
# the package ignore list.
|
311
|
+
#
|
312
|
+
# @param args [ Array<String> ] optional list of file patterns to add to the package ignore list
|
313
|
+
#
|
314
|
+
# @return [ Set<String>, nil ] the set of package ignore files when no arguments provided,
|
315
|
+
# nil otherwise
|
239
316
|
def package_ignore(*args)
|
240
317
|
if args.empty?
|
241
318
|
package_ignore_files
|
@@ -244,14 +321,28 @@ class GemHadar
|
|
244
321
|
end
|
245
322
|
end
|
246
323
|
|
324
|
+
# The dependency method adds a new runtime dependency to the gem.
|
325
|
+
#
|
326
|
+
# @param args [ Array ] the arguments defining the dependency
|
247
327
|
def dependency(*args)
|
248
328
|
@dependencies << args
|
249
329
|
end
|
250
330
|
|
331
|
+
# The development_dependency method adds a new development-time dependency to
|
332
|
+
# the gem.
|
333
|
+
#
|
334
|
+
# @param args [ Array ] the arguments defining the development dependency
|
251
335
|
def development_dependency(*args)
|
252
336
|
@development_dependencies << args
|
253
337
|
end
|
254
338
|
|
339
|
+
# The gems_install_task method defines a Rake task for installing all gem
|
340
|
+
# dependencies specified in the Gemfile.
|
341
|
+
#
|
342
|
+
# This method sets up a :gems:install task that executes a block to install
|
343
|
+
# gems. If no block is provided, it defaults to running 'bundle install'.
|
344
|
+
#
|
345
|
+
# @param block [ Proc ] optional block containing the installation command
|
255
346
|
def gems_install_task(&block)
|
256
347
|
block ||= proc { sh 'bundle install' }
|
257
348
|
desc 'Install all gems from the Gemfile'
|
@@ -260,6 +351,14 @@ class GemHadar
|
|
260
351
|
end
|
261
352
|
end
|
262
353
|
|
354
|
+
# The version_task method defines a Rake task that generates a version file
|
355
|
+
# for the gem.
|
356
|
+
#
|
357
|
+
# This method creates a task named :version that writes version information
|
358
|
+
# to a Ruby file in the lib directory. The generated file contains constants
|
359
|
+
# for the version and its components, as well as an optional epilogue
|
360
|
+
# section. The task ensures the target directory exists and uses secure file
|
361
|
+
# writing to prevent permission issues.
|
263
362
|
def version_task
|
264
363
|
desc m = "Writing version information for #{name}-#{version}"
|
265
364
|
task :version do
|
@@ -281,6 +380,13 @@ class GemHadar
|
|
281
380
|
end
|
282
381
|
end
|
283
382
|
|
383
|
+
# The version_show_task method defines a Rake task that displays the current
|
384
|
+
# version of the gem.
|
385
|
+
#
|
386
|
+
# This method creates a :version:show task under the Rake namespace that
|
387
|
+
# reads the version from the generated version file in the lib directory and
|
388
|
+
# compares it with the version specified in the GemHadar configuration. It
|
389
|
+
# then outputs a message indicating whether the versions match or not.
|
284
390
|
def version_show_task
|
285
391
|
namespace :version do
|
286
392
|
desc "Displaying the current version"
|
@@ -299,6 +405,21 @@ class GemHadar
|
|
299
405
|
end
|
300
406
|
end
|
301
407
|
|
408
|
+
# The version_log_diff method generates a git log output containing patch
|
409
|
+
# differences between two specified versions.
|
410
|
+
#
|
411
|
+
# This method retrieves the commit history between a starting version and an
|
412
|
+
# ending version, including detailed changes (patch format) for each commit.
|
413
|
+
# It supports comparing against the current HEAD or specific version tags,
|
414
|
+
# and automatically determines the appropriate previous version when only a
|
415
|
+
# target version is provided.
|
416
|
+
#
|
417
|
+
# @param to_version [ String ] the ending version tag or 'HEAD' to compare up to the latest commit
|
418
|
+
# @param from_version [ String, nil ] the starting version tag; if nil, it defaults based on to_version
|
419
|
+
#
|
420
|
+
# @raise [ RuntimeError ] if the specified version tags are not found in the repository
|
421
|
+
#
|
422
|
+
# @return [ String ] the git log output in patch format showing changes between the two versions
|
302
423
|
def version_log_diff(to_version: 'HEAD', from_version: nil)
|
303
424
|
if to_version == 'HEAD'
|
304
425
|
if from_version.blank?
|
@@ -331,6 +452,15 @@ class GemHadar
|
|
331
452
|
end
|
332
453
|
end
|
333
454
|
|
455
|
+
# The version_diff_task method defines Rake tasks for listing and displaying
|
456
|
+
# git version differences.
|
457
|
+
#
|
458
|
+
# This method sets up two subtasks under the :version namespace:
|
459
|
+
#
|
460
|
+
# - A :list task that fetches all git tags, ensures the operation succeeds,
|
461
|
+
# and outputs the sorted list of versions.
|
462
|
+
# - A :diff task that calculates the version range, displays a colored diff
|
463
|
+
# between the versions, and shows the changes.
|
334
464
|
def version_diff_task
|
335
465
|
namespace :version do
|
336
466
|
desc "List all versions in order"
|
@@ -349,9 +479,18 @@ class GemHadar
|
|
349
479
|
end
|
350
480
|
end
|
351
481
|
|
482
|
+
# The gem_hadar_update_task method defines a Rake task that updates the
|
483
|
+
# gem_hadar dependency version in the gemspec file.
|
484
|
+
#
|
485
|
+
# This method creates a :gem_hadar:update task under the Rake namespace that
|
486
|
+
# prompts the user to specify a new gem_hadar version.
|
487
|
+
# It then reads the existing gemspec file, modifies the version constraint
|
488
|
+
# for the gem_hadar dependency, and writes the updated content back to the
|
489
|
+
# file. If the specified version is already present in the gemspec, it skips
|
490
|
+
# the update and notifies the user.
|
352
491
|
def gem_hadar_update_task
|
353
492
|
namespace :gem_hadar do
|
354
|
-
desc 'Update gem_hadar a different version'
|
493
|
+
desc 'Update gem_hadar to a different version'
|
355
494
|
task :update do
|
356
495
|
answer = ask?("Which gem_hadar version? ", /^((?:\d+.){2}(?:\d+))$/)
|
357
496
|
unless answer
|
@@ -377,6 +516,14 @@ class GemHadar
|
|
377
516
|
end
|
378
517
|
end
|
379
518
|
|
519
|
+
# The gemspec_task method defines a Rake task that generates and writes a
|
520
|
+
# gemspec file for the project.
|
521
|
+
#
|
522
|
+
# This method creates a :gemspec task that depends on the :version task,
|
523
|
+
# ensuring the version is set before generating the gemspec. It constructs
|
524
|
+
# the filename based on the project name, displays a warning message
|
525
|
+
# indicating the file being written, and uses secure_write to create the
|
526
|
+
# gemspec file with content generated by the gemspec method.
|
380
527
|
def gemspec_task
|
381
528
|
desc 'Create a gemspec file'
|
382
529
|
task :gemspec => :version do
|
@@ -386,6 +533,12 @@ class GemHadar
|
|
386
533
|
end
|
387
534
|
end
|
388
535
|
|
536
|
+
# The package_task method sets up a Rake task for packaging the gem.
|
537
|
+
#
|
538
|
+
# This method configures a task that creates a package directory, initializes
|
539
|
+
# a Gem::PackageTask with the current gem specification, and specifies that
|
540
|
+
# tar files should be created. It also includes the files to be packaged by
|
541
|
+
# adding gem_files to the package_files attribute of the Gem::PackageTask.
|
389
542
|
def package_task
|
390
543
|
clean 'pkg'
|
391
544
|
Gem::PackageTask.new(gemspec) do |pkg|
|
@@ -394,24 +547,20 @@ class GemHadar
|
|
394
547
|
end
|
395
548
|
end
|
396
549
|
|
550
|
+
# The install_library_task method executes the installed library task block
|
551
|
+
# if it has been defined.
|
397
552
|
def install_library_task
|
398
553
|
@install_library_block.full?(:call)
|
399
554
|
end
|
400
555
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
end
|
410
|
-
cmd << ' - ' << doc_files * ' '
|
411
|
-
sh cmd
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
556
|
+
# The test_task method sets up a Rake task for executing the project's test
|
557
|
+
# suite.
|
558
|
+
#
|
559
|
+
# This method configures a Rake task named :test that runs the test suite
|
560
|
+
# using Rake::TestTask. It includes the test directory and required paths in
|
561
|
+
# the load path, specifies the test files to run, and enables verbose output.
|
562
|
+
# The task also conditionally depends on the :compile task if project
|
563
|
+
# extensions are present.
|
415
564
|
def test_task
|
416
565
|
tt = Rake::TestTask.new(:run_tests) do |t|
|
417
566
|
t.libs << test_dir
|
@@ -423,6 +572,12 @@ class GemHadar
|
|
423
572
|
task :test => [ (:compile if extensions.full?), tt.name ].compact
|
424
573
|
end
|
425
574
|
|
575
|
+
# The spec_task method sets up a Rake task for executing RSpec tests.
|
576
|
+
#
|
577
|
+
# This method configures a :spec task that runs the project's RSpec test
|
578
|
+
# suite. It initializes an RSpec::Core::RakeTask with appropriate Ruby
|
579
|
+
# options, test pattern, and verbose output. The task also conditionally
|
580
|
+
# depends on the :compile task if project extensions are present.
|
426
581
|
def spec_task
|
427
582
|
defined? ::RSpec::Core::RakeTask or return
|
428
583
|
st = RSpec::Core::RakeTask.new(:run_specs) do |t|
|
@@ -434,6 +589,15 @@ class GemHadar
|
|
434
589
|
task :spec => [ (:compile if extensions.full?), st.name ].compact
|
435
590
|
end
|
436
591
|
|
592
|
+
# The rcov_task method sets up a Rake task for executing code coverage tests
|
593
|
+
# using RCov.
|
594
|
+
#
|
595
|
+
# This method configures a :rcov task that runs the project's test suite with
|
596
|
+
# RCov to generate code coverage reports. It includes the test directory and
|
597
|
+
# required paths in the load path, specifies the test files to run, and
|
598
|
+
# enables verbose output. The task also conditionally depends on the :compile
|
599
|
+
# task if project extensions are present. If RCov is not available, it
|
600
|
+
# displays a warning message suggesting to install RCov.
|
437
601
|
def rcov_task
|
438
602
|
if defined?(::Rcov)
|
439
603
|
rt = ::Rcov::RcovTask.new(:run_rcov) do |t|
|
@@ -455,6 +619,23 @@ class GemHadar
|
|
455
619
|
end
|
456
620
|
end
|
457
621
|
|
622
|
+
# The version_bump_task method defines Rake tasks for incrementing the gem's
|
623
|
+
# version number.
|
624
|
+
#
|
625
|
+
# This method sets up a hierarchical task structure under the :version
|
626
|
+
# namespace:
|
627
|
+
#
|
628
|
+
# - It creates subtasks in the :version:bump namespace for explicitly bumping
|
629
|
+
# major, minor, or build versions.
|
630
|
+
# - It also defines a :version:bump task that automatically suggests the
|
631
|
+
# appropriate version bump type by analyzing recent changes using AI. The
|
632
|
+
# suggestion is based on the git log diff between the previous version and
|
633
|
+
# the current HEAD, and it prompts the user for confirmation before applying
|
634
|
+
# the bump.
|
635
|
+
#
|
636
|
+
# The tasks utilize the version_log_diff method to gather change information,
|
637
|
+
# the ollama_generate method to get AI-powered suggestions, and the
|
638
|
+
# version_bump_to method to perform the actual version update.
|
458
639
|
def version_bump_task
|
459
640
|
namespace :version do
|
460
641
|
namespace :bump do
|
@@ -474,7 +655,7 @@ class GemHadar
|
|
474
655
|
end
|
475
656
|
end
|
476
657
|
|
477
|
-
desc 'Bump version with suggestion'
|
658
|
+
desc 'Bump version with AI suggestion'
|
478
659
|
task :bump do
|
479
660
|
log_diff = version_log_diff(from_version: nil, to_version: 'HEAD')
|
480
661
|
system = xdg_config('version_bump_system_prompt.txt', default_version_bump_system_prompt)
|
@@ -499,6 +680,15 @@ class GemHadar
|
|
499
680
|
end
|
500
681
|
end
|
501
682
|
|
683
|
+
# The version_tag_task method defines a Rake task that creates a Git tag for
|
684
|
+
# the current version.
|
685
|
+
#
|
686
|
+
# This method sets up a :version:tag task under the Rake namespace that
|
687
|
+
# creates an annotated Git tag for the project's current version. It checks
|
688
|
+
# if a tag with the same name already exists and handles the case where the
|
689
|
+
# tag exists but is different from the current commit. If the tag already
|
690
|
+
# exists and is different, it prompts the user to confirm whether to
|
691
|
+
# overwrite it forcefully.
|
502
692
|
def version_tag_task
|
503
693
|
namespace :version do
|
504
694
|
desc "Tag this commit as version #{version}"
|
@@ -523,10 +713,24 @@ class GemHadar
|
|
523
713
|
end
|
524
714
|
end
|
525
715
|
|
716
|
+
# The git_remote method retrieves the primary Git remote name configured for
|
717
|
+
# the project.
|
718
|
+
#
|
719
|
+
# It first checks the GIT_REMOTE environment variable for a custom remote
|
720
|
+
# specification. If not set, it defaults to 'origin'. When multiple remotes
|
721
|
+
# are specified in the environment variable, only the first one is returned.
|
526
722
|
def git_remote
|
527
723
|
ENV.fetch('GIT_REMOTE', 'origin').split(/\s+/).first
|
528
724
|
end
|
529
725
|
|
726
|
+
# The master_prepare_task method defines a Rake task that sets up a remote
|
727
|
+
# Git repository for the project.
|
728
|
+
#
|
729
|
+
# This method creates a :master:prepare task under the Rake namespace that
|
730
|
+
# guides the user through creating a new bare Git repository on a remote
|
731
|
+
# server via SSH. It prompts for the remote name, directory path, and SSH
|
732
|
+
# account details to configure the repository and establish a connection back
|
733
|
+
# to the local project.
|
530
734
|
def master_prepare_task
|
531
735
|
namespace :master do
|
532
736
|
desc "Prepare a remote git repository for this project"
|
@@ -544,6 +748,20 @@ class GemHadar
|
|
544
748
|
end
|
545
749
|
end
|
546
750
|
|
751
|
+
# The version_push_task method defines Rake tasks for pushing version tags to
|
752
|
+
# Git remotes.
|
753
|
+
#
|
754
|
+
# This method sets up a hierarchical task structure under the :version
|
755
|
+
# namespace:
|
756
|
+
#
|
757
|
+
# - It creates subtasks in the :version:push namespace for each configured
|
758
|
+
# Git remote, allowing individual pushes to specific remotes.
|
759
|
+
# - It also defines a top-level :version:push task that depends on all the
|
760
|
+
# individual remote push tasks, enabling a single command to push the version
|
761
|
+
# tag to all remotes.
|
762
|
+
#
|
763
|
+
# The tasks utilize the git_remotes method to determine which remotes are
|
764
|
+
# configured and generate appropriate push commands for each one.
|
547
765
|
def version_push_task
|
548
766
|
namespace :version do
|
549
767
|
git_remotes.each do |gr|
|
@@ -560,6 +778,19 @@ class GemHadar
|
|
560
778
|
end
|
561
779
|
end
|
562
780
|
|
781
|
+
# The master_push_task method defines Rake tasks for pushing the master
|
782
|
+
# branch to configured Git remotes.
|
783
|
+
#
|
784
|
+
# This method sets up a hierarchical task structure under the :master namespace:
|
785
|
+
#
|
786
|
+
# - It creates subtasks in the :master:push namespace for each configured Git
|
787
|
+
# remote, allowing individual pushes to specific remotes.
|
788
|
+
# - It also defines a top-level :master:push task that depends on all the individual
|
789
|
+
# remote push tasks, enabling a single command to push the master branch to
|
790
|
+
# all remotes.
|
791
|
+
#
|
792
|
+
# The tasks utilize the git_remotes method to determine which remotes are
|
793
|
+
# configured and generate appropriate push commands for each one.
|
563
794
|
def master_push_task
|
564
795
|
namespace :master do
|
565
796
|
git_remotes.each do |gr|
|
@@ -576,6 +807,17 @@ class GemHadar
|
|
576
807
|
end
|
577
808
|
end
|
578
809
|
|
810
|
+
# The gem_push_task method defines a Rake task for pushing the generated gem
|
811
|
+
# file to RubyGems.
|
812
|
+
#
|
813
|
+
# This method sets up a :gem:push task under the Rake namespace that handles
|
814
|
+
# the process of uploading the gem package to RubyGems. It checks if the
|
815
|
+
# project is in developing mode and skips the push operation if so.
|
816
|
+
# Otherwise, it verifies the existence of the gem file, prompts the user for
|
817
|
+
# confirmation before pushing, and uses the gem push command with an optional
|
818
|
+
# API key from the environment. If the gem file does not exist or the user
|
819
|
+
# declines to push, appropriate messages are displayed and the task exits
|
820
|
+
# accordingly.
|
579
821
|
def gem_push_task
|
580
822
|
namespace :gem do
|
581
823
|
path = "pkg/#{name_version}.gem"
|
@@ -604,6 +846,15 @@ class GemHadar
|
|
604
846
|
end
|
605
847
|
end
|
606
848
|
|
849
|
+
# The git_remotes_task method defines a Rake task that displays all Git
|
850
|
+
# remote repositories configured for the project.
|
851
|
+
#
|
852
|
+
# This method sets up a :git_remotes task under the Rake namespace that
|
853
|
+
# retrieves and prints the list of Git remotes along with their URLs. It uses
|
854
|
+
# the git_remotes method to obtain the remote names and then fetches each
|
855
|
+
# remote's URL using the `git remote get-url` command. The output is
|
856
|
+
# formatted to show each remote name followed by its corresponding URL on
|
857
|
+
# separate lines.
|
607
858
|
def git_remotes_task
|
608
859
|
task :git_remotes do
|
609
860
|
puts git_remotes.map { |r|
|
@@ -613,6 +864,14 @@ class GemHadar
|
|
613
864
|
end
|
614
865
|
end
|
615
866
|
|
867
|
+
# The create_git_release_body method generates a changelog for a GitHub
|
868
|
+
# release by analyzing the git diff between the previous version and the
|
869
|
+
# current HEAD.
|
870
|
+
#
|
871
|
+
# It retrieves the log differences, fetches or uses default system and prompt
|
872
|
+
# templates, and utilizes an AI model to produce a formatted changelog entry.
|
873
|
+
#
|
874
|
+
# @return [ String ] the generated changelog content for the release body
|
616
875
|
def create_git_release_body
|
617
876
|
log_diff = version_log_diff(to_version: version)
|
618
877
|
system = xdg_config('release_system_prompt.txt', default_git_release_system_prompt)
|
@@ -620,26 +879,14 @@ class GemHadar
|
|
620
879
|
ollama_generate(system:, prompt:)
|
621
880
|
end
|
622
881
|
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
temp_file.close
|
632
|
-
|
633
|
-
unless system("#{editor} #{temp_file.path}")
|
634
|
-
warn "#{editor} returned #{$?.exitstatus} => Returning."
|
635
|
-
return
|
636
|
-
end
|
637
|
-
|
638
|
-
File.read(temp_file.path)
|
639
|
-
ensure
|
640
|
-
temp_file&.close&.unlink
|
641
|
-
end
|
642
|
-
|
882
|
+
# The github_release_task method defines a Rake task that creates a GitHub
|
883
|
+
# release for the current version.
|
884
|
+
#
|
885
|
+
# This method sets up a :github:release task that prompts the user to confirm
|
886
|
+
# publishing a release message on GitHub. It retrieves the GitHub API token
|
887
|
+
# from the environment, derives the repository owner and name from the git
|
888
|
+
# remote URL, generates a changelog using AI, and creates the release via the
|
889
|
+
# GitHub API.
|
643
890
|
def github_release_task
|
644
891
|
namespace :github do
|
645
892
|
unless github_api_token = ENV['GITHUB_API_TOKEN'].full?
|
@@ -647,7 +894,7 @@ class GemHadar
|
|
647
894
|
task :release
|
648
895
|
return
|
649
896
|
end
|
650
|
-
desc "Create a new GitHub release for the current version with a changelog"
|
897
|
+
desc "Create a new GitHub release for the current version with a AI-generated changelog"
|
651
898
|
task :release do
|
652
899
|
yes = ask?(
|
653
900
|
"Do you want to publish a release message on github? (y/n%{default}) ",
|
@@ -681,6 +928,14 @@ class GemHadar
|
|
681
928
|
|
682
929
|
dsl_accessor :push_task_dependencies, %i[ modified build master:push version:push gem:push github:release ]
|
683
930
|
|
931
|
+
# The push_task method defines a Rake task that orchestrates the complete
|
932
|
+
# process of pushing changes and artifacts to remote repositories and package
|
933
|
+
# managers.
|
934
|
+
#
|
935
|
+
# This method sets up multiple subtasks including preparing the master
|
936
|
+
# branch, pushing version tags, pushing to gem repositories, and creating
|
937
|
+
# GitHub releases. It also includes a check for uncommitted changes before
|
938
|
+
# proceeding with the push operations.
|
684
939
|
def push_task
|
685
940
|
master_prepare_task
|
686
941
|
version_push_task
|
@@ -695,10 +950,26 @@ class GemHadar
|
|
695
950
|
exit 1
|
696
951
|
end
|
697
952
|
end
|
698
|
-
desc "Push
|
953
|
+
desc "Push all changes for version #{version} into the internets."
|
699
954
|
task :push => push_task_dependencies
|
700
955
|
end
|
701
956
|
|
957
|
+
# The release_task method defines a Rake task that orchestrates the complete
|
958
|
+
# release process for the gem.
|
959
|
+
#
|
960
|
+
# This method sets up a :release task that depends on the :push task,
|
961
|
+
# ensuring all necessary steps for publishing the gem are executed in
|
962
|
+
# sequence. It provides a convenient way to perform a full release workflow
|
963
|
+
# with a single command.
|
964
|
+
def release_task
|
965
|
+
desc "Release the new version #{version} for the gem #{name}."
|
966
|
+
task :release => :push
|
967
|
+
end
|
968
|
+
|
969
|
+
# The compile_task method sets up a Rake task to compile project extensions.
|
970
|
+
#
|
971
|
+
# This method creates a :compile task that iterates through the configured
|
972
|
+
# extensions and compiles them using the system's make command.
|
702
973
|
def compile_task
|
703
974
|
for file in extensions
|
704
975
|
dir = File.dirname(file)
|
@@ -716,6 +987,16 @@ class GemHadar
|
|
716
987
|
end
|
717
988
|
end
|
718
989
|
|
990
|
+
# The rvm_task method creates a .rvmrc file that configures RVM to use the
|
991
|
+
# specified Ruby version and gemset for the project.
|
992
|
+
#
|
993
|
+
# This task generates a .rvmrc file in the project root directory with commands to:
|
994
|
+
# - Use the Ruby version specified by the rvm.use accessor
|
995
|
+
# - Create the gemset specified by the rvm.gemset accessor
|
996
|
+
# - Switch to using that gemset
|
997
|
+
#
|
998
|
+
# The generated file is written using the secure_write method to ensure
|
999
|
+
# proper file permissions.
|
719
1000
|
def rvm_task
|
720
1001
|
desc 'Create .rvmrc file'
|
721
1002
|
task :rvm do
|
@@ -729,15 +1010,55 @@ class GemHadar
|
|
729
1010
|
end
|
730
1011
|
end
|
731
1012
|
|
1013
|
+
def yard_doc_task
|
1014
|
+
YARD::Rake::YardocTask.new(:yard_doc) do |t|
|
1015
|
+
t.files = files.select { _1 =~ /\.rb\z/ }
|
1016
|
+
|
1017
|
+
output_dir = yard_dir
|
1018
|
+
t.options = [ "--output-dir=#{output_dir}" ]
|
1019
|
+
|
1020
|
+
# Include private & protected methods in documentation
|
1021
|
+
t.options << '--private' << '--protected'
|
1022
|
+
|
1023
|
+
# Handle readme if present
|
1024
|
+
if readme && File.exist?(readme)
|
1025
|
+
t.options << "--readme=#{readme}"
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
# Add additional documentation files
|
1029
|
+
if doc_files&.any?
|
1030
|
+
t.files.concat(doc_files.flatten)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
# Add before hook for cleaning
|
1034
|
+
t.before = proc {
|
1035
|
+
clean output_dir
|
1036
|
+
puts "Generating full documentation in #{output_dir}..."
|
1037
|
+
}
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
# The yard_task method sets up and registers Rake tasks for generating and
|
1042
|
+
# managing YARD documentation.
|
1043
|
+
#
|
1044
|
+
# It creates multiple subtasks under the :yard namespace, including tasks for
|
1045
|
+
# creating private documentation, viewing the generated documentation,
|
1046
|
+
# cleaning up documentation files, and listing undocumented elements.
|
1047
|
+
# If YARD is not available, the method returns early without defining any tasks.
|
732
1048
|
def yard_task
|
733
1049
|
defined? YARD or return
|
1050
|
+
yard_doc_task
|
1051
|
+
desc 'Create yard documentation (including private)'
|
1052
|
+
task :doc => :yard_doc
|
734
1053
|
namespace :yard do
|
735
1054
|
my_yard_dir = Pathname.new(yard_dir)
|
736
1055
|
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
1056
|
+
task :private => :yard_doc
|
1057
|
+
|
1058
|
+
task :public => :yard_doc
|
1059
|
+
|
1060
|
+
desc 'Create yard documentation'
|
1061
|
+
task :doc => :yard_doc
|
741
1062
|
|
742
1063
|
desc 'View the yard documentation'
|
743
1064
|
task :view do
|
@@ -761,12 +1082,79 @@ class GemHadar
|
|
761
1082
|
task :yard => %i[ yard:private yard:view ]
|
762
1083
|
end
|
763
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
|
+
|
764
1151
|
# The create_all_tasks method sets up and registers all the Rake tasks for
|
765
1152
|
# the gem project.
|
766
1153
|
#
|
767
1154
|
# @return [GemHadar] the instance of GemHadar
|
768
1155
|
def create_all_tasks
|
769
1156
|
default_task
|
1157
|
+
config_task
|
770
1158
|
build_task
|
771
1159
|
rvm_task
|
772
1160
|
version_task
|
@@ -775,7 +1163,6 @@ class GemHadar
|
|
775
1163
|
gem_hadar_update_task
|
776
1164
|
gemspec_task
|
777
1165
|
gems_install_task
|
778
|
-
doc_task
|
779
1166
|
if test_dir
|
780
1167
|
test_task
|
781
1168
|
rcov_task
|
@@ -787,6 +1174,7 @@ class GemHadar
|
|
787
1174
|
version_bump_task
|
788
1175
|
version_tag_task
|
789
1176
|
push_task
|
1177
|
+
release_task
|
790
1178
|
write_ignore_file
|
791
1179
|
write_gemfile
|
792
1180
|
if extensions.full?
|
@@ -798,20 +1186,78 @@ class GemHadar
|
|
798
1186
|
self
|
799
1187
|
end
|
800
1188
|
|
1189
|
+
# The edit_temp_file method creates a temporary file with the provided
|
1190
|
+
# content, opens it in an editor for user modification, and returns the
|
1191
|
+
# updated content.
|
1192
|
+
#
|
1193
|
+
# @param content [ String ] the initial content to write to the temporary file
|
1194
|
+
def edit_temp_file(content)
|
1195
|
+
editor = ENV.fetch('EDITOR', `which vi`.chomp)
|
1196
|
+
unless File.exist?(editor)
|
1197
|
+
warn "Can't find EDITOR. => Returning."
|
1198
|
+
return
|
1199
|
+
end
|
1200
|
+
temp_file = Tempfile.new('changelog')
|
1201
|
+
temp_file.write(content)
|
1202
|
+
temp_file.close
|
1203
|
+
|
1204
|
+
unless system("#{editor} #{temp_file.path}")
|
1205
|
+
warn "#{editor} returned #{$?.exitstatus} => Returning."
|
1206
|
+
return
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
File.read(temp_file.path)
|
1210
|
+
ensure
|
1211
|
+
temp_file&.close&.unlink
|
1212
|
+
end
|
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
|
+
|
801
1249
|
# Generates a response from an AI model using the Ollama::Client.
|
802
1250
|
#
|
803
1251
|
# @param [String] system The system prompt for the AI model.
|
804
1252
|
# @param [String] prompt The user prompt to generate a response to.
|
805
1253
|
# @return [String, nil] The generated response or nil if generation fails.
|
806
1254
|
def ollama_generate(system:, prompt:)
|
807
|
-
|
808
|
-
|
809
|
-
|
1255
|
+
unless ollama = ollama_client
|
1256
|
+
warn "Ollama is not configured. => Returning."
|
1257
|
+
return
|
810
1258
|
end
|
811
|
-
|
812
|
-
|
813
|
-
model = ENV.fetch('OLLAMA_MODEL', 'llama3.1')
|
814
|
-
options = ENV['OLLAMA_OPTIONS'].full? { |o| JSON.parse(o) } || {}
|
1259
|
+
model = ollama_model
|
1260
|
+
options = ENV['OLLAMA_MODEL_OPTIONS'].full? { |o| JSON.parse(o) } || {}
|
815
1261
|
options |= { "temperature" => 0, "top_p" => 1, "min_p" => 0.1 }
|
816
1262
|
ollama.generate(model:, system:, prompt:, options:, stream: false, think: false).response
|
817
1263
|
end
|
@@ -941,8 +1387,12 @@ class GemHadar
|
|
941
1387
|
s.rdoc_options << '--title' << "#{name.camelize} - #{summary}"
|
942
1388
|
end
|
943
1389
|
if readme
|
944
|
-
|
945
|
-
|
1390
|
+
if File.exist?(readme)
|
1391
|
+
s.rdoc_options << '--main' << readme
|
1392
|
+
s.extra_rdoc_files << readme
|
1393
|
+
else
|
1394
|
+
warn "Add a #{readme} file to document your gem!"
|
1395
|
+
end
|
946
1396
|
end
|
947
1397
|
doc_files.full? { |df| s.extra_rdoc_files.concat Array(df) }
|
948
1398
|
end
|
@@ -1045,6 +1495,11 @@ class GemHadar
|
|
1045
1495
|
end
|
1046
1496
|
end
|
1047
1497
|
|
1498
|
+
# The version_untag method removes the 'v' prefix from a version tag string.
|
1499
|
+
#
|
1500
|
+
# @param version_tag [ String ] the version tag string that may start with 'v'
|
1501
|
+
#
|
1502
|
+
# @return [ String ] the version string with the 'v' prefix removed
|
1048
1503
|
def version_untag(version_tag)
|
1049
1504
|
version.sub(/\Av/, '')
|
1050
1505
|
end
|