gem_hadar 1.19.0 → 1.21.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: 040403d6ff936fc93918a7b72ee41b7c06b0ffaf9b88cd5953c96458587513bc
4
- data.tar.gz: ce6834549c29b47f6540e65a52b4d7967fc96ff05a2ef42b21187ea12fcf0aa2
3
+ metadata.gz: 410e007cfd4db6fe45a437edb7edb73c3cc501708e94fc8dfc81d950c423d011
4
+ data.tar.gz: c9861d9f19d895d0ded7b1d774906e0026fce892f68768ff7fa4658343212e5c
5
5
  SHA512:
6
- metadata.gz: 22b85d777cdac8646cb462559ace1a6b7cb3ca0bae520f734431e3d0f8403313506ef0aa04800159f6a7692b506fba877286c52e512bced5a4b3a4a3f883c5d8
7
- data.tar.gz: 91b9a1e72041b5e7231c88f09d99f197666226af7485fd8cb4c6702417c0e0896280eb5bf6c7e673efb748bc6ebacd939d8572ae55f023bd52c4a03e831e3911
6
+ metadata.gz: 1c187a124e2f34104d533e86f724a52d579f7b21fb2e4b5be64aa7205a3b3194b3d3aa74dde3beab66a85efc32bc617aafe911e41e8d31be456a11a15c9b4584
7
+ data.tar.gz: 8c9dba1c9a4778d6e76aa389fc95299bb84d7c5ca8a5b1dd932dec7ad4ef52c3bf16b52be18c1027af86ee75994efc6c743c58e7d996b0b136ad0e8e623c53dd
data/README.md CHANGED
@@ -16,12 +16,33 @@ or can be installed via
16
16
  $ gem install gem_hadar
17
17
  ```
18
18
 
19
+ ## Usage
20
+
21
+ Create a new directory and excecute
22
+
23
+ ```
24
+ $ gem_hadar
25
+ ```
26
+
27
+ Edit the created Rakefile until
28
+
29
+ ```
30
+ $ rake gemspec
31
+ ```
32
+
33
+ and then
34
+
35
+ ```
36
+ $ rake build
37
+ ```
38
+
39
+ are perfomed as desired.
40
+
19
41
  ## Author
20
42
 
21
43
  Florian Frank \<mailto:flori@ping.de\>
44
+ **GemHadar** was written by [Florian Frank](mailto:flori@ping.de)
22
45
 
23
46
  ## License
24
47
 
25
- This software is licensed under the X11 (or MIT) license:
26
- http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3
27
-
48
+ This software is licensed under the _MIT_ license.
data/Rakefile CHANGED
@@ -17,6 +17,7 @@ GemHadar do
17
17
 
18
18
  dependency 'tins', '~> 1.0'
19
19
  dependency 'term-ansicolor', '~> 1.0'
20
+ dependency 'ollama-ruby', '~> 1.0'
20
21
  dependency 'rake'
21
22
  dependency 'yard'
22
23
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.19.0
1
+ 1.21.0
data/gem_hadar.gemspec CHANGED
@@ -1,30 +1,31 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: gem_hadar 1.19.0 ruby lib
2
+ # stub: gem_hadar 1.21.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "gem_hadar".freeze
6
- s.version = "1.19.0".freeze
6
+ s.version = "1.21.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]
10
10
  s.authors = ["Florian Frank".freeze]
11
- s.date = "2024-10-14"
11
+ s.date = "1980-01-02"
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/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/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/setup.rb".freeze, "lib/gem_hadar/template_compiler.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/setup.rb".freeze, "lib/gem_hadar/template_compiler.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]
20
- s.rubygems_version = "3.5.18".freeze
20
+ s.rubygems_version = "3.6.9".freeze
21
21
  s.summary = "Library for the development of Ruby Gems".freeze
22
22
 
23
23
  s.specification_version = 4
24
24
 
25
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.19".freeze])
25
+ s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.20".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
+ s.add_runtime_dependency(%q<ollama-ruby>.freeze, ["~> 1.0".freeze])
28
29
  s.add_runtime_dependency(%q<rake>.freeze, [">= 0".freeze])
29
30
  s.add_runtime_dependency(%q<yard>.freeze, [">= 0".freeze])
30
31
  end
@@ -0,0 +1,57 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module GemHadar::GitHub
5
+ end
6
+
7
+ class GemHadar::GitHub::ReleaseCreator
8
+ class << self
9
+ attr_accessor :github_api_url
10
+ end
11
+ self.github_api_url = 'https://api.github.com'
12
+
13
+ def initialize(owner:, repo:, token:, api_version: '2022-11-28')
14
+ @owner = owner
15
+ @repo = repo
16
+ @token = token
17
+ @api_version = api_version
18
+ end
19
+
20
+ def perform(tag_name:, target_commitish:, body:, name: tag_name, draft: false, prerelease: false)
21
+ uri = URI("#{self.class.github_api_url}/repos/#{@owner}/#{@repo}/releases")
22
+
23
+ headers = {
24
+ "Accept" => "application/vnd.github+json",
25
+ "Authorization" => "Bearer #{@token}",
26
+ "X-GitHub-Api-Version" => @api_version
27
+ }
28
+
29
+ data = {
30
+ tag_name:,
31
+ target_commitish:,
32
+ body:,
33
+ name:,
34
+ draft:,
35
+ prerelease:,
36
+ }.compact
37
+
38
+ req = Net::HTTP::Post.new(uri.request_uri, headers)
39
+ req.body = JSON(data)
40
+
41
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
42
+ http.request(req)
43
+ end
44
+
45
+ case response
46
+ when Net::HTTPSuccess
47
+ puts "Release created successfully!"
48
+ response.body
49
+ else
50
+ error_msg = "Failed to create release. Status: #{response.code}"
51
+ raise error_msg
52
+ end
53
+ rescue => e
54
+ warn "Error creating release: #{e.message}"
55
+ nil
56
+ end
57
+ end
@@ -0,0 +1,41 @@
1
+ class GemHadar::Setup
2
+ include FileUtils
3
+
4
+ def perform
5
+ mkdir_p 'lib'
6
+ unless File.exist?('VERSION')
7
+ File.open('VERSION', 'w') do |output|
8
+ output.puts '0.0.0'
9
+ end
10
+ end
11
+ unless File.exist?('Rakefile')
12
+ File.open('Rakefile', 'w') do |output|
13
+ output.puts <<~EOT
14
+ # vim: set filetype=ruby et sw=2 ts=2:
15
+
16
+ require 'gem_hadar'
17
+
18
+ GemHadar do
19
+ #developing true
20
+ #name 'TODO'
21
+ module_type :class
22
+ #author 'TODO'
23
+ #email 'todo@example.com'
24
+ #homepage "https://github.com/TODO/NAME"
25
+ #summary 'TODO'
26
+ description 'TODO'
27
+ test_dir 'spec'
28
+ ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle', '.yardoc', 'tags'
29
+ readme 'README.md'
30
+
31
+ #executables << 'bin/TODO'
32
+
33
+ #dependency 'TODO', '~>1.2.3'
34
+
35
+ #licenses << 'TODO
36
+ end
37
+ EOT
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ require 'erb'
2
+
3
+ class GemHadar::TemplateCompiler
4
+ include Tins::BlockSelf
5
+ include Tins::MethodMissingDelegator::DelegatorModule
6
+
7
+ def initialize(&block)
8
+ super block_self(&block)
9
+ @values = {}
10
+ instance_eval(&block)
11
+ end
12
+
13
+ def compile(src, dst)
14
+ template = File.read(src)
15
+ File.open(dst, 'w') do |output|
16
+ erb = ERB.new(template, nil, '-')
17
+ erb.filename = src.to_s
18
+ output.write erb.result binding
19
+ end
20
+ end
21
+
22
+ def method_missing(id, *a, &b)
23
+ if a.empty? && id && @values.key?(id)
24
+ @values[id]
25
+ elsif a.size == 1
26
+ @values[id] = a.first
27
+ else
28
+ super
29
+ end
30
+ end
31
+ end
@@ -1,6 +1,6 @@
1
1
  class GemHadar
2
2
  # GemHadar version
3
- VERSION = '1.19.0'
3
+ VERSION = '1.21.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
@@ -15,18 +15,19 @@ require 'rake/testtask'
15
15
  require 'dslkit/polite'
16
16
  require 'set'
17
17
  require 'pathname'
18
- require 'erb'
19
- require 'gem_hadar/version'
18
+ require 'ollama'
20
19
  require 'term/ansicolor'
21
20
  require_maybe 'yard'
22
21
  require_maybe 'simplecov'
23
22
  require_maybe 'rubygems/package_task'
24
23
  require_maybe 'rcov/rcovtask'
25
24
  require_maybe 'rspec/core/rake_task'
26
-
27
- def GemHadar(&block)
28
- GemHadar.new(&block).create_all_tasks
25
+ class GemHadar
29
26
  end
27
+ require 'gem_hadar/version'
28
+ require 'gem_hadar/setup'
29
+ require 'gem_hadar/template_compiler'
30
+ require 'gem_hadar/github'
30
31
 
31
32
  class GemHadar
32
33
  include Term::ANSIColor
@@ -50,18 +51,6 @@ class GemHadar
50
51
  fail "#{self.class}: #{name} has to be set for gem"
51
52
  end
52
53
 
53
- def assert_valid_link(name, orig_url)
54
- developing and return orig_url
55
- url = orig_url
56
- begin
57
- response = Net::HTTP.get_response(URI.parse(url))
58
- url = response['location']
59
- end while response.is_a?(Net::HTTPRedirection)
60
- response.is_a?(Net::HTTPOK) or
61
- fail "#{orig_url.inspect} for #{name} has to be a valid link"
62
- orig_url
63
- end
64
-
65
54
  dsl_accessor :developing, false
66
55
 
67
56
  dsl_accessor :name do
@@ -214,7 +203,7 @@ class GemHadar
214
203
  end
215
204
 
216
205
  def install_library(&block)
217
- @install_library_block = lambda do
206
+ @install_library_block = -> do
218
207
  desc 'Install executable/library into site_ruby directories'
219
208
  task :install => :prepare_install, &block
220
209
  end
@@ -268,72 +257,22 @@ class GemHadar
268
257
  end
269
258
  end
270
259
 
271
- def gem_files
272
- (files.to_a - package_ignore_files.to_a)
273
- end
274
-
275
- def gemspec
276
- Gem::Specification.new do |s|
277
- s.name = name
278
- s.version = ::Gem::Version.new(version)
279
- s.author = author
280
- s.email = email
281
- s.homepage = assert_valid_link(:homepage, homepage)
282
- s.summary = summary
283
- s.description = description
284
-
285
- gem_files.full? { |f| s.files = Array(f) }
286
- test_files.full? { |t| s.test_files = Array(t) }
287
- extensions.full? { |e| s.extensions = Array(e) }
288
- bindir.full? { |b| s.bindir = b }
289
- executables.full? { |e| s.executables = Array(e) }
290
- licenses.full? { |l| s.licenses = Array(licenses) }
291
- post_install_message.full? { |m| s.post_install_message = m }
292
-
293
- required_ruby_version.full? { |v| s.required_ruby_version = v }
294
- s.add_development_dependency('gem_hadar', "~> #{VERSION[/\A\d+\.\d+/, 0]}")
295
- for d in @development_dependencies
296
- s.add_development_dependency(*d)
297
- end
298
- for d in @dependencies
299
- if s.respond_to?(:add_runtime_dependency)
300
- s.add_runtime_dependency(*d)
301
- else
302
- s.add_dependency(*d)
303
- end
304
- end
305
-
306
- require_paths.full? { |r| s.require_paths = Array(r) }
307
-
308
- if title
309
- s.rdoc_options << '--title' << title
310
- else
311
- s.rdoc_options << '--title' << "#{name.camelize} - #{summary}"
312
- end
313
- if readme
314
- s.rdoc_options << '--main' << readme
315
- s.extra_rdoc_files << readme
316
- end
317
- doc_files.full? { |df| s.extra_rdoc_files.concat Array(df) }
318
- end
319
- end
320
-
321
260
  def version_task
322
261
  desc m = "Writing version information for #{name}-#{version}"
323
262
  task :version do
324
263
  puts m
325
264
  mkdir_p dir = File.join('lib', path_name)
326
265
  secure_write(File.join(dir, 'version.rb')) do |v|
327
- v.puts <<EOT
328
- #{module_type} #{path_module}
329
- # #{path_module} version
330
- VERSION = '#{version}'
331
- VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
332
- VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
333
- VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
334
- VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
335
- end
336
- EOT
266
+ v.puts <<~EOT
267
+ #{module_type} #{path_module}
268
+ # #{path_module} version
269
+ VERSION = '#{version}'
270
+ VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
271
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
272
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
273
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
274
+ end
275
+ EOT
337
276
  version_epilogue.full? { |ve| v.puts ve }
338
277
  end
339
278
  end
@@ -357,10 +296,36 @@ EOT
357
296
  end
358
297
  end
359
298
 
360
- def versions
361
- `git tag`.lines.grep(/^v?\d+\.\d+\.\d+$/).map(&:chomp).map {
362
- _1.sub(/\Av/, '')
363
- }.sort_by(&:version)
299
+ def version_log_diff(to_version: 'HEAD', from_version: nil)
300
+ if to_version == 'HEAD'
301
+ if from_version.blank?
302
+ from_version = versions.last
303
+ else
304
+ unless versions.find { |v| v == from_version }
305
+ fail "Could not find #{from_version.inspect}."
306
+ end
307
+ end
308
+ `git log -p #{version_identifier(from_version)}..HEAD`
309
+ else
310
+ unless versions.find { |v| v == to_version }
311
+ fail "Could not find #{to_version.inspect}."
312
+ end
313
+ if from_version.blank?
314
+ from_version = versions.each_cons(2).find do |previous_version, v|
315
+ if v == to_version
316
+ break previous_version
317
+ end
318
+ end
319
+ unless from_version
320
+ fail "Could not find version before #{to_version.inspect}."
321
+ end
322
+ else
323
+ unless versions.find { |v| v == from_version }
324
+ fail "Could not find #{from_version.inspect}."
325
+ end
326
+ end
327
+ `git log -p #{version_identifier(from_version)}..#{version_identifier(to_version)}`
328
+ end
364
329
  end
365
330
 
366
331
  def version_diff_task
@@ -374,8 +339,8 @@ EOT
374
339
 
375
340
  desc "Displaying the diff from env var VERSION to the next version or HEAD"
376
341
  task :diff do
377
- arg_version = ENV.fetch('VERSION', version).dup.prepend(?v)
378
- my_versions = versions.map { _1.prepend(?v) } + %w[ HEAD ]
342
+ arg_version = version_identifier(ENV.fetch('VERSION', version))
343
+ my_versions = versions.map { version_identifier(_1) } + %w[ HEAD ]
379
344
  start_version, end_version = my_versions[my_versions.index(arg_version), 2]
380
345
  puts color(172) {"Showing diff from version %s to %s:" % [ start_version, end_version ]}
381
346
  puts `git diff --color=always #{start_version}..#{end_version}`
@@ -489,41 +454,6 @@ EOT
489
454
  end
490
455
  end
491
456
 
492
- def self.start_simplecov
493
- defined? SimpleCov or return
494
- filter = "#{File.basename(File.dirname(caller.first))}/"
495
- SimpleCov.start do
496
- add_filter filter
497
- end
498
- end
499
-
500
- def write_ignore_file
501
- secure_write('.gitignore') do |output|
502
- output.puts(ignore.sort)
503
- end
504
- end
505
-
506
- def write_gemfile
507
- default_gemfile =<<EOT
508
- # vim: set filetype=ruby et sw=2 ts=2:
509
-
510
- source 'https://rubygems.org'
511
-
512
- gemspec
513
- EOT
514
- current_gemfile = File.exist?('Gemfile') && File.read('Gemfile')
515
- case current_gemfile
516
- when false
517
- secure_write('Gemfile') do |output|
518
- output.write default_gemfile
519
- end
520
- when default_gemfile
521
- ;;
522
- else
523
- warn "INFO: Current Gemfile differs from default Gemfile."
524
- end
525
- end
526
-
527
457
  def version_bump_task
528
458
  namespace :version do
529
459
  namespace :bump do
@@ -557,7 +487,7 @@ EOT
557
487
  task :tag do
558
488
  force = ENV['FORCE'].to_i == 1
559
489
  begin
560
- sh "git tag -a -m 'Version #{version}' #{'-f' if force} v#{version}"
490
+ sh "git tag -a -m 'Version #{version}' #{'-f' if force} #{version_identifier(version)}"
561
491
  rescue RuntimeError
562
492
  if `git diff v#{version}..HEAD`.empty?
563
493
  puts "Version #{version} is already tagged, but it's no different"
@@ -579,12 +509,6 @@ EOT
579
509
  ENV.fetch('GIT_REMOTE', 'origin').split(/\s+/).first
580
510
  end
581
511
 
582
- def git_remotes
583
- remotes = ENV['GIT_REMOTE'].full?(:split, /\s+/)
584
- remotes or remotes = `git remote`.lines.map(&:chomp)
585
- remotes
586
- end
587
-
588
512
  def master_prepare_task
589
513
  namespace :master do
590
514
  desc "Prepare a remote git repository for this project"
@@ -648,7 +572,7 @@ EOT
648
572
  if ask?("Do you really want to push #{path.inspect} to rubygems? "\
649
573
  "(yes/NO) ", /\Ayes\z/i)
650
574
  then
651
- key = ENV['GEM_API_KEY'].full? { |k| "--key #{k} " }
575
+ key = ENV['GEM_HOST_API_KEY'].full? { |k| "--key #{k} " }
652
576
  sh "gem push #{key}#{path}"
653
577
  else
654
578
  exit 1
@@ -671,12 +595,106 @@ EOT
671
595
  end
672
596
  end
673
597
 
598
+ def create_body
599
+ base_url = ENV['OLLAMA_URL']
600
+ if base_url.blank? && host = ENV['OLLAMA_HOST'].full?
601
+ base_url = 'http://%s' % host
602
+ end
603
+ base_url.present? or return
604
+ log_diff = version_log_diff(to_version: version)
605
+ model = ENV.fetch('OLLAMA_MODEL', 'llama3.1')
606
+ ollama = Ollama::Client.new(base_url:, read_timeout: 600, connect_timeout: 60)
607
+ system = <<~EOT
608
+ You are a Ruby programmer generating changelog messages in markdown
609
+ format for new releases, so users can see what has changed. Remember you
610
+ are not a chatbot of any kind.
611
+ EOT
612
+ prompt = (<<~EOT) % { name:, version:, log_diff: }
613
+ Output the content of a changelog for the new release of %{name} %{version}
614
+
615
+ **Strictly** follow these guidelines:
616
+
617
+ - Use bullet points in markdown format (`-`) to list significant changes.
618
+ - Exclude trivial updates such as:
619
+ * Version number increments
620
+ * Dependency version bumps (unless they resolve critical issues)
621
+ * Minor code style adjustments
622
+ * Internal documentation tweaks
623
+ - Include only verified and substantial changes that impact
624
+ functionality, performance, or user experience.
625
+ - If unsure about a change's significance, omit it from the output.
626
+ - Avoid adding any comments or notes; keep the output purely factual.
627
+
628
+ These are the log messages including patches for the new release:
629
+
630
+ %{log_diff}
631
+ EOT
632
+ options = ENV['OLLAMA_OPTIONS'].full? { |o| JSON.parse(o) } || {}
633
+ options |= { "temperature" => 0, "top_p" => 1, "min_p" => 0.1 }
634
+ ollama.generate(model:, system:, prompt:, options:, stream: false, think: false).response
635
+ end
636
+
637
+ def edit_temp_file(content)
638
+ editor = ENV.fetch('EDITOR', `which vi`.chomp)
639
+ unless File.exist?(editor)
640
+ warn "Can't find EDITOR. => Returning."
641
+ return
642
+ end
643
+ temp_file = Tempfile.new('changelog')
644
+ temp_file.write(content)
645
+ temp_file.close
646
+
647
+ unless system("#{editor} #{temp_file.path}")
648
+ warn "#{editor} returned #{$?.exitstatus} => Returning."
649
+ return
650
+ end
651
+
652
+ File.read(temp_file.path)
653
+ ensure
654
+ temp_file&.close&.unlink
655
+ end
656
+
657
+ def github_release_task
658
+ namespace :github do
659
+ unless github_api_token = ENV['GITHUB_API_TOKEN'].full?
660
+ warn "GITHUB_API_TOKEN not set. => Skipping github release task."
661
+ task :release
662
+ return
663
+ end
664
+ desc "Create a new GitHub release for the current version with a changelog"
665
+ task :release do
666
+ yes = ask?(
667
+ "Do you want to publish a release message on github? (y/n, %{default}) ",
668
+ /\Ay/i, default: ENV['GITHUB_RELEASE_ENABLED']
669
+ )
670
+ unless yes
671
+ warn "Skipping publication of a github release message."
672
+ next
673
+ end
674
+ if %r(\A/*(?<owner>[^/]+)/(?<repo>[^/.]+)) =~ github_remote_url&.path
675
+ rc = GitHub::ReleaseCreator.new(owner:, repo:, token: github_api_token)
676
+ tag_name = version_identifier(version)
677
+ target_commitish = `git rev-parse #{tag_name.inspect}`.chomp
678
+ body = edit_temp_file(create_body)
679
+ if body.present?
680
+ rc.perform(tag_name:, target_commitish:, body:)
681
+ else
682
+ warn "Skipping creation of github release message."
683
+ end
684
+ else
685
+ warn "Could not derive github remote url from git remotes. => Skipping github release task."
686
+ end
687
+ end
688
+ end
689
+ end
690
+
674
691
  def push_task
675
692
  master_prepare_task
676
693
  version_push_task
677
694
  master_push_task
678
695
  gem_push_task
679
696
  git_remotes_task
697
+ github_release_task
680
698
  task :modified do
681
699
  changed_files = `git status --porcelain`.gsub(/^\s*\S\s+/, '').lines
682
700
  unless changed_files.empty?
@@ -685,7 +703,7 @@ EOT
685
703
  end
686
704
  end
687
705
  desc "Push master and version #{version} all git remotes: #{git_remotes * ' '}"
688
- task :push => %i[ modified build master:push version:push gem:push ]
706
+ task :push => %i[ modified build master:push version:push gem:push github:release ]
689
707
  end
690
708
 
691
709
  def compile_task
@@ -709,11 +727,11 @@ EOT
709
727
  desc 'Create .rvmrc file'
710
728
  task :rvm do
711
729
  secure_write('.rvmrc') do |output|
712
- output.write <<EOT
713
- rvm use #{rvm.use}
714
- rvm gemset create #{rvm.gemset}
715
- rvm gemset use #{rvm.gemset}
716
- EOT
730
+ output.write <<~EOT
731
+ rvm use #{rvm.use}
732
+ rvm gemset create #{rvm.gemset}
733
+ rvm gemset use #{rvm.gemset}
734
+ EOT
717
735
  end
718
736
  end
719
737
  end
@@ -750,14 +768,10 @@ EOT
750
768
  task :yard => %i[ yard:private yard:view ]
751
769
  end
752
770
 
753
- def ask?(prompt, pattern)
754
- STDOUT.print prompt
755
- answer = STDIN.gets.chomp
756
- if answer =~ pattern
757
- $~
758
- end
759
- end
760
-
771
+ # The create_all_tasks method sets up and registers all the Rake tasks for
772
+ # the gem project.
773
+ #
774
+ # @return [GemHadar] the instance of GemHadar
761
775
  def create_all_tasks
762
776
  default_task
763
777
  build_task
@@ -791,77 +805,242 @@ EOT
791
805
  self
792
806
  end
793
807
 
794
- class TemplateCompiler
795
- include Tins::BlockSelf
796
- include Tins::MethodMissingDelegator::DelegatorModule
797
-
798
- def initialize(&block)
799
- super block_self(&block)
800
- @values = {}
801
- instance_eval(&block)
808
+ # The write_ignore_file method writes the current ignore_files configuration
809
+ # to a .gitignore file in the project root directory.
810
+ def write_ignore_file
811
+ secure_write('.gitignore') do |output|
812
+ output.puts(ignore.sort)
802
813
  end
814
+ end
803
815
 
804
- def compile(src, dst)
805
- template = File.read(src)
806
- File.open(dst, 'w') do |output|
807
- erb = ERB.new(template, nil, '-')
808
- erb.filename = src.to_s
809
- output.write erb.result binding
816
+ # The write_gemfile method creates and writes the default Gemfile content if
817
+ # it doesn't exist. If a custom Gemfile exists, it only displays a warning.
818
+ def write_gemfile
819
+ default_gemfile =<<~EOT
820
+ # vim: set filetype=ruby et sw=2 ts=2:
821
+
822
+ source 'https://rubygems.org'
823
+
824
+ gemspec
825
+ EOT
826
+ current_gemfile = File.exist?('Gemfile') && File.read('Gemfile')
827
+ case current_gemfile
828
+ when false
829
+ secure_write('Gemfile') do |output|
830
+ output.write default_gemfile
810
831
  end
832
+ when default_gemfile
833
+ ;;
834
+ else
835
+ warn "INFO: Current Gemfile differs from default Gemfile."
811
836
  end
837
+ end
838
+
839
+ # The assert_valid_link method verifies that the provided URL is valid by
840
+ # checking if it returns an HTTP OK status after following redirects, unless
841
+ # project is still `developing`.
842
+ #
843
+ # @param name [String] the name associated with the link being validated
844
+ # @param orig_url [String] the URL to validate
845
+ #
846
+ # @return [String] the original URL if validation succeeds
847
+ #
848
+ # @raise [ArgumentError] if the final response is not an HTTP OK status after
849
+ # following redirects
850
+ def assert_valid_link(name, orig_url)
851
+ developing and return orig_url
852
+ url = orig_url
853
+ begin
854
+ response = Net::HTTP.get_response(URI.parse(url))
855
+ url = response['location']
856
+ end while response.is_a?(Net::HTTPRedirection)
857
+ response.is_a?(Net::HTTPOK) or
858
+ fail "#{orig_url.inspect} for #{name} has to be a valid link"
859
+ orig_url
860
+ end
861
+
862
+ # The gemspec method creates and returns a new Gem::Specification object
863
+ # that defines the metadata and dependencies for the gem package.
864
+ #
865
+ # @return [Gem::Specification] a fully configured Gem specification object
866
+ def gemspec
867
+ Gem::Specification.new do |s|
868
+ s.name = name
869
+ s.version = ::Gem::Version.new(version)
870
+ s.author = author
871
+ s.email = email
872
+ s.homepage = assert_valid_link(:homepage, homepage)
873
+ s.summary = summary
874
+ s.description = description
875
+
876
+ gem_files.full? { |f| s.files = Array(f) }
877
+ test_files.full? { |t| s.test_files = Array(t) }
878
+ extensions.full? { |e| s.extensions = Array(e) }
879
+ bindir.full? { |b| s.bindir = b }
880
+ executables.full? { |e| s.executables = Array(e) }
881
+ licenses.full? { |l| s.licenses = Array(licenses) }
882
+ post_install_message.full? { |m| s.post_install_message = m }
812
883
 
813
- def method_missing(id, *a, &b)
814
- if a.empty? && id && @values.key?(id)
815
- @values[id]
816
- elsif a.size == 1
817
- @values[id] = a.first
884
+ required_ruby_version.full? { |v| s.required_ruby_version = v }
885
+ s.add_development_dependency('gem_hadar', "~> #{VERSION[/\A\d+\.\d+/, 0]}")
886
+ for d in @development_dependencies
887
+ s.add_development_dependency(*d)
888
+ end
889
+ for d in @dependencies
890
+ if s.respond_to?(:add_runtime_dependency)
891
+ s.add_runtime_dependency(*d)
892
+ else
893
+ s.add_dependency(*d)
894
+ end
895
+ end
896
+
897
+ require_paths.full? { |r| s.require_paths = Array(r) }
898
+
899
+ if title
900
+ s.rdoc_options << '--title' << title
818
901
  else
819
- super
902
+ s.rdoc_options << '--title' << "#{name.camelize} - #{summary}"
820
903
  end
904
+ if readme
905
+ s.rdoc_options << '--main' << readme
906
+ s.extra_rdoc_files << readme
907
+ end
908
+ doc_files.full? { |df| s.extra_rdoc_files.concat Array(df) }
821
909
  end
822
910
  end
823
911
 
824
- class Setup
825
- include FileUtils
912
+ # The warn method displays warning messages using orange colored output.
913
+ #
914
+ # @param msgs [Array<String>] the array of message strings to display
915
+ def warn(*msgs)
916
+ msgs.map! { |m| color(208) { m } }
917
+ super(*msgs, uplevel: 1)
918
+ end
826
919
 
827
- def perform
828
- mkdir_p 'lib'
829
- unless File.exist?('VERSION')
830
- File.open('VERSION', 'w') do |output|
831
- output.puts '0.0.0'
832
- end
833
- end
834
- unless File.exist?('Rakefile')
835
- File.open('Rakefile', 'w') do |output|
836
- output.puts <<~EOT
837
- # vim: set filetype=ruby et sw=2 ts=2:
920
+ # The fail method formats and displays failure messages using red colored
921
+ # output.
922
+ #
923
+ # @param args [Array] the array of arguments to be formatted and passed to super
924
+ def fail(*args)
925
+ args.map! do |a|
926
+ a.respond_to?(:to_str) ? color(196) { a.to_str } : a
927
+ end
928
+ super(*args)
929
+ end
930
+ def fail(*args)
931
+ args.map! do |a|
932
+ a.respond_to?(:to_str) ? color(196) { a.to_str } : a
933
+ end
934
+ super(*args)
935
+ end
838
936
 
839
- require 'gem_hadar'
937
+ # The git_remotes method retrieves the list of remote repositories configured
938
+ # for the current Git project.
939
+ #
940
+ # It first attempts to read the remotes from the ENV['GIT_REMOTE']
941
+ # environment variable, splitting it by whitespace. If this is not available,
942
+ # it falls back to querying the local Git repository using `git remote`.
943
+ #
944
+ # @return [ Array<String> ] an array of remote names
945
+ def git_remotes
946
+ remotes = ENV['GIT_REMOTE'].full?(:split, /\s+/)
947
+ remotes or remotes = `git remote`.lines.map(&:chomp)
948
+ remotes
949
+ end
840
950
 
841
- GemHadar do
842
- #developing true
843
- #name 'TODO'
844
- module_type :class
845
- #author 'TODO'
846
- #email 'todo@example.com'
847
- #homepage "https://github.com/TODO/NAME"
848
- #summary 'TODO'
849
- description 'TODO'
850
- test_dir 'spec'
851
- ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle', '.yardoc', 'tags'
852
- readme 'README.md'
951
+ # The ask? method prompts the user with a message and reads their input It
952
+ # returns a MatchData object if the input matches the provided pattern.
953
+ #
954
+ # @param prompt [ String ] the message to display to the user
955
+ # @param pattern [ Regexp ] the regular expression to match against the input
956
+ #
957
+ # @return [ MatchData, nil ] the result of the pattern match or nil if no match
958
+ def ask?(prompt, pattern, default: nil)
959
+ if prompt.include?('%{default}') && default.present?
960
+ prompt = prompt % { default: "default is #{default.inspect}" }
961
+ end
962
+ STDOUT.print prompt
963
+ answer = STDIN.gets.chomp
964
+ default.present? && answer.blank? and answer = default
965
+ if answer =~ pattern
966
+ $~
967
+ end
968
+ end
853
969
 
854
- #executables << 'bin/TODO'
970
+ # The gem_files method returns an array of files that are included in the gem
971
+ # package.
972
+ #
973
+ # It calculates this by subtracting the files listed in package_ignore_files
974
+ # from the list of all files.
975
+ #
976
+ # @return [ Array<String> ] the list of files to include in the gem package
977
+ def gem_files
978
+ (files.to_a - package_ignore_files.to_a)
979
+ end
855
980
 
856
- #dependency 'TODO', '~>1.2.3'
981
+ # The versions method retrieves and processes the list of git tags that match
982
+ # semantic versioning patterns.
983
+ #
984
+ # It executes `git tag` to get all available tags, filters them using a
985
+ # regular expression to identify valid version strings, removes any 'v'
986
+ # prefix from each version string, trims whitespace, and sorts the resulting
987
+ # array based on semantic versioning order.
988
+ #
989
+ # @return [ Array<String> ] an array of version strings sorted in ascending
990
+ # order according to semantic versioning rules.
991
+ def versions
992
+ @versions ||= `git tag`.lines.grep(/^v?\d+\.\d+\.\d+$/).map(&:chomp).map {
993
+ _1.sub(/\Av/, '')
994
+ }.sort_by(&:version)
995
+ end
857
996
 
858
- #licenses << 'TODO
859
- end
860
- EOT
997
+ # The version_identifier method prepends a 'v' prefix to the given version
998
+ # string.
999
+ #
1000
+ # @param version [String] the version string to modify
1001
+ # @return [String] the modified version string with a 'v' prefix
1002
+ def version_identifier(version)
1003
+ version.dup.prepend ?v
1004
+ end
1005
+
1006
+ # The github_remote_url method retrieves and parses the GitHub remote URL
1007
+ # from the local Git configuration.
1008
+ #
1009
+ # It executes `git remote -v` to get all remote configurations, extracts the
1010
+ # push URLs, processes them to construct valid URIs, and returns the first
1011
+ # URI pointing to GitHub.com.
1012
+ #
1013
+ # @return [URI, nil] The parsed GitHub remote URI or nil if not found.
1014
+ def github_remote_url
1015
+ if remotes = `git remote -v`
1016
+ remotes_urls = remotes.scan(/^(\S+)\s+(\S+)\s+\(push\)/)
1017
+ remotes_uris = remotes_urls.map do |name, url|
1018
+ if %r(\A(?<scheme>[^@]+)@(?<hostname>[A-Za-z0-9.]+):(?:\d*)(?<path>.*)) =~ url
1019
+ path = ?/ + path unless path.start_with? ?/
1020
+ url = 'ssh://%s@%s%s' % [ scheme, hostname, path ] # approximate correct URIs
861
1021
  end
1022
+ URI.parse(url)
862
1023
  end
1024
+ remotes_uris.find { |uri| uri.hostname == 'github.com' }
863
1025
  end
864
1026
  end
1027
+
1028
+ class << self
1029
+ # The start_simplecov method initializes SimpleCov and configures it to
1030
+ # ignore coverage data from the directory containing the caller. This can be
1031
+ # called from a test or spec helper.
1032
+ def start_simplecov
1033
+ defined? SimpleCov or return
1034
+ filter = "#{File.basename(File.dirname(caller.first))}/"
1035
+ SimpleCov.start do
1036
+ add_filter filter
1037
+ end
1038
+ end
1039
+ end
1040
+ end
1041
+
1042
+ def GemHadar(&block)
1043
+ GemHadar.new(&block).create_all_tasks
865
1044
  end
866
1045
 
867
1046
  def template(pathname, &block)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_hadar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.0
4
+ version: 1.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-14 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: gem_hadar
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '1.19'
18
+ version: '1.20'
20
19
  type: :development
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '1.19'
25
+ version: '1.20'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: tins
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +51,20 @@ dependencies:
52
51
  - - "~>"
53
52
  - !ruby/object:Gem::Version
54
53
  version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: ollama-ruby
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
55
68
  - !ruby/object:Gem::Dependency
56
69
  name: rake
57
70
  requirement: !ruby/object:Gem::Requirement
@@ -89,6 +102,9 @@ extensions: []
89
102
  extra_rdoc_files:
90
103
  - README.md
91
104
  - lib/gem_hadar.rb
105
+ - lib/gem_hadar/github.rb
106
+ - lib/gem_hadar/setup.rb
107
+ - lib/gem_hadar/template_compiler.rb
92
108
  - lib/gem_hadar/version.rb
93
109
  files:
94
110
  - ".gitignore"
@@ -100,12 +116,14 @@ files:
100
116
  - bin/gem_hadar
101
117
  - gem_hadar.gemspec
102
118
  - lib/gem_hadar.rb
119
+ - lib/gem_hadar/github.rb
120
+ - lib/gem_hadar/setup.rb
121
+ - lib/gem_hadar/template_compiler.rb
103
122
  - lib/gem_hadar/version.rb
104
123
  homepage: https://github.com/flori/gem_hadar
105
124
  licenses:
106
125
  - MIT
107
126
  metadata: {}
108
- post_install_message:
109
127
  rdoc_options:
110
128
  - "--title"
111
129
  - GemHadar - Library for the development of Ruby Gems
@@ -124,8 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
142
  - !ruby/object:Gem::Version
125
143
  version: '0'
126
144
  requirements: []
127
- rubygems_version: 3.5.18
128
- signing_key:
145
+ rubygems_version: 3.6.9
129
146
  specification_version: 4
130
147
  summary: Library for the development of Ruby Gems
131
148
  test_files: []