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 +4 -4
- data/README.md +24 -3
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/gem_hadar.gemspec +8 -7
- data/lib/gem_hadar/github.rb +57 -0
- data/lib/gem_hadar/setup.rb +41 -0
- data/lib/gem_hadar/template_compiler.rb +31 -0
- data/lib/gem_hadar/version.rb +1 -1
- data/lib/gem_hadar.rb +371 -192
- metadata +25 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 410e007cfd4db6fe45a437edb7edb73c3cc501708e94fc8dfc81d950c423d011
|
4
|
+
data.tar.gz: c9861d9f19d895d0ded7b1d774906e0026fce892f68768ff7fa4658343212e5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
26
|
-
http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3
|
27
|
-
|
48
|
+
This software is licensed under the _MIT_ license.
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.21.0
|
data/gem_hadar.gemspec
CHANGED
@@ -1,30 +1,31 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: gem_hadar 1.
|
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.
|
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 = "
|
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.
|
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.
|
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
|
data/lib/gem_hadar/version.rb
CHANGED
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 '
|
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 =
|
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
|
328
|
-
#{module_type} #{path_module}
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
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
|
361
|
-
|
362
|
-
|
363
|
-
|
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)
|
378
|
-
my_versions = versions.map { _1
|
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}
|
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['
|
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
|
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
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
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
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
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
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
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
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
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
|
-
|
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
|
-
|
825
|
-
|
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
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
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
|
-
|
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
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
859
|
-
|
860
|
-
|
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.
|
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:
|
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.
|
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.
|
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.
|
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: []
|