gran 0.1.0 → 0.1.1
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/CHANGELOG.md +4 -1
- data/lib/gran/pathtree.rb +1 -2
- data/lib/gran/version.rb +1 -1
- data/scripts/release.rb +338 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ca48cfaefe9ad306ea4df075602e8a86e06517a3f170b2733e464b417fdc928
|
4
|
+
data.tar.gz: 88b4f8d7027278c9e1bb6fd860edd92311ab3b68d0f02b30362579fc819e43e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22c850b8eaa92af1debc66a73b79d5e1c59dafbe3477fa0f0ad9f03309b3647339959587d84fe7244638ab3bb7105868db0f62afb49cf553529f9ddc8ac77d1f
|
7
|
+
data.tar.gz: f0e9fdb5ac431a95354446344322e4bf11c055e4ee19d355bd47e802080060be91e5555c4b0a1e2ca50aa590686db15279d1967b952822c40999864ae7b50e72
|
data/CHANGELOG.md
CHANGED
data/lib/gran/pathtree.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require "pathname"
|
2
|
-
require "set"
|
3
2
|
require_relative "loggable"
|
4
3
|
|
5
4
|
module Gran
|
@@ -456,7 +455,7 @@ module Gran
|
|
456
455
|
result = []
|
457
456
|
|
458
457
|
traverse_preorder do |level, node|
|
459
|
-
q = from_root ? node.pathname : Pathname(segment)
|
458
|
+
q = from_root ? node.pathname : Pathname(segment) /
|
460
459
|
node.pathname.relative_path_from(pathname)
|
461
460
|
result << node if q.to_s.include?(sub_str)
|
462
461
|
end
|
data/lib/gran/version.rb
CHANGED
data/scripts/release.rb
ADDED
@@ -0,0 +1,338 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "pathname"
|
5
|
+
require "optparse"
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
# Release automation script for gran gem
|
9
|
+
class GranReleaseManager
|
10
|
+
GRAN_DIR = Pathname.new(__dir__).parent
|
11
|
+
|
12
|
+
VALID_COMMANDS = %w[prepare publish all].freeze
|
13
|
+
VALID_VERSION_TYPES = %w[major minor patch].freeze
|
14
|
+
|
15
|
+
attr_reader :command, :version_type, :dry_run, :yes, :specific_version
|
16
|
+
|
17
|
+
def initialize(args)
|
18
|
+
@dry_run = false
|
19
|
+
@yes = false
|
20
|
+
@specific_version = nil
|
21
|
+
parse_options(args)
|
22
|
+
validate_args
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
puts "\n=== Gran Release Manager ==="
|
27
|
+
puts "Command: #{command}"
|
28
|
+
puts "Version: #{version_type || specific_version}"
|
29
|
+
puts "Dry-run: #{dry_run}"
|
30
|
+
puts "============================\n\n"
|
31
|
+
|
32
|
+
case command
|
33
|
+
when "prepare"
|
34
|
+
prepare_release
|
35
|
+
when "publish"
|
36
|
+
publish_release
|
37
|
+
when "all"
|
38
|
+
prepare_release
|
39
|
+
publish_release
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def parse_options(args)
|
46
|
+
OptionParser.new do |opts|
|
47
|
+
opts.banner = "Usage: release.rb [options] COMMAND [VERSION]"
|
48
|
+
opts.separator ""
|
49
|
+
opts.separator "COMMAND: #{VALID_COMMANDS.join(", ")}"
|
50
|
+
opts.separator "VERSION: #{VALID_VERSION_TYPES.join(", ")} or specific version (e.g., 0.2.0)"
|
51
|
+
opts.separator ""
|
52
|
+
opts.separator "Options:"
|
53
|
+
|
54
|
+
opts.on("-n", "--dry-run", "Show what would happen without doing it") do
|
55
|
+
@dry_run = true
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on("-y", "--yes", "Skip confirmation prompts") do
|
59
|
+
@yes = true
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("-h", "--help", "Show this help message") do
|
63
|
+
puts opts
|
64
|
+
exit 0
|
65
|
+
end
|
66
|
+
end.parse!(args)
|
67
|
+
|
68
|
+
@command = args[0]
|
69
|
+
|
70
|
+
# Parse version argument
|
71
|
+
if args[1]
|
72
|
+
if VALID_VERSION_TYPES.include?(args[1])
|
73
|
+
@version_type = args[1]
|
74
|
+
elsif args[1].match?(/^\d+\.\d+\.\d+$/)
|
75
|
+
@specific_version = args[1]
|
76
|
+
else
|
77
|
+
puts "ERROR: Invalid version '#{args[1]}'. Must be #{VALID_VERSION_TYPES.join(", ")} or a version number (e.g., 0.2.0)"
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate_args
|
84
|
+
unless VALID_COMMANDS.include?(command)
|
85
|
+
puts "ERROR: Invalid command '#{command}'. Must be one of: #{VALID_COMMANDS.join(", ")}"
|
86
|
+
exit 1
|
87
|
+
end
|
88
|
+
|
89
|
+
if command != "publish" && version_type.nil? && specific_version.nil?
|
90
|
+
puts "ERROR: VERSION argument required for '#{command}' command"
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def prepare_release
|
96
|
+
puts "\n📦 Preparing gran for release...\n"
|
97
|
+
with_dir(GRAN_DIR) do
|
98
|
+
run_safety_checks
|
99
|
+
new_version = bump_version(GRAN_DIR / "lib/gran/version.rb")
|
100
|
+
update_changelog(new_version)
|
101
|
+
build_gem
|
102
|
+
create_git_commit_and_tag(new_version)
|
103
|
+
success("Gran prepared for release: v#{new_version}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def publish_release
|
108
|
+
puts "\n🚀 Publishing gran to RubyGems...\n"
|
109
|
+
with_dir(GRAN_DIR) do
|
110
|
+
push_to_github
|
111
|
+
publish_gem
|
112
|
+
success("Gran published!")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Safety Checks
|
117
|
+
def run_safety_checks
|
118
|
+
step("Running safety checks")
|
119
|
+
check_git_status
|
120
|
+
check_on_main_branch
|
121
|
+
run_tests
|
122
|
+
run_linter
|
123
|
+
end
|
124
|
+
|
125
|
+
def check_git_status
|
126
|
+
output = `git status --porcelain`.strip
|
127
|
+
unless output.empty?
|
128
|
+
error("Working directory is not clean. Commit or stash changes first.")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def check_on_main_branch
|
133
|
+
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
134
|
+
unless branch == "main"
|
135
|
+
unless confirm("You are on branch '#{branch}', not 'main'. Continue anyway?")
|
136
|
+
error("Aborted. Switch to main branch or use --yes to override.")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def run_tests
|
142
|
+
step("Running tests")
|
143
|
+
unless system("bundle exec rake test > /dev/null 2>&1")
|
144
|
+
error("Tests failed! Fix tests before releasing.")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def run_linter
|
149
|
+
step("Running linter")
|
150
|
+
unless system("bundle exec rake standard > /dev/null 2>&1")
|
151
|
+
error("Linter failed! Fix linting issues before releasing.")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Version Management
|
156
|
+
def bump_version(version_file)
|
157
|
+
current_version = extract_version(version_file)
|
158
|
+
new_version = calculate_new_version(current_version)
|
159
|
+
|
160
|
+
puts "Current version: #{current_version}"
|
161
|
+
puts "New version: #{new_version}"
|
162
|
+
|
163
|
+
unless confirm("Bump version to #{new_version}?")
|
164
|
+
error("Aborted by user")
|
165
|
+
end
|
166
|
+
|
167
|
+
update_version_file(version_file, current_version, new_version)
|
168
|
+
new_version
|
169
|
+
end
|
170
|
+
|
171
|
+
def extract_version(version_file)
|
172
|
+
content = File.read(version_file)
|
173
|
+
if content =~ /VERSION\s*=\s*"([\d.]+)"/
|
174
|
+
$1
|
175
|
+
else
|
176
|
+
error("Could not find VERSION in #{version_file}")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def calculate_new_version(current)
|
181
|
+
return specific_version if specific_version
|
182
|
+
|
183
|
+
parts = current.split(".").map(&:to_i)
|
184
|
+
case version_type
|
185
|
+
when "major"
|
186
|
+
"#{parts[0] + 1}.0.0"
|
187
|
+
when "minor"
|
188
|
+
"#{parts[0]}.#{parts[1] + 1}.0"
|
189
|
+
when "patch"
|
190
|
+
"#{parts[0]}.#{parts[1]}.#{parts[2] + 1}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def update_version_file(version_file, old_version, new_version)
|
195
|
+
content = File.read(version_file)
|
196
|
+
content.gsub!(/VERSION\s*=\s*"#{Regexp.escape(old_version)}"/,
|
197
|
+
"VERSION = \"#{new_version}\"")
|
198
|
+
|
199
|
+
if dry_run
|
200
|
+
puts "[DRY-RUN] Would update #{version_file.basename} to #{new_version}"
|
201
|
+
else
|
202
|
+
File.write(version_file, content)
|
203
|
+
puts "✓ Updated #{version_file.basename}"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Changelog
|
208
|
+
def update_changelog(version)
|
209
|
+
step("Updating CHANGELOG")
|
210
|
+
puts "⚠️ Please update the CHANGELOG manually with changes for v#{version}"
|
211
|
+
puts "Press Enter when done..."
|
212
|
+
$stdin.gets unless yes
|
213
|
+
end
|
214
|
+
|
215
|
+
# Gem Operations
|
216
|
+
def build_gem
|
217
|
+
step("Building gran gem")
|
218
|
+
|
219
|
+
if dry_run
|
220
|
+
puts "[DRY-RUN] Would run: gem build gran.gemspec"
|
221
|
+
else
|
222
|
+
unless system("gem build gran.gemspec")
|
223
|
+
error("Failed to build gem")
|
224
|
+
end
|
225
|
+
puts "✓ Gem built successfully"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def publish_gem
|
230
|
+
gem_file = Dir.glob("gran-*.gem").max_by { |f| File.mtime(f) }
|
231
|
+
|
232
|
+
unless gem_file
|
233
|
+
error("No gem file found to publish")
|
234
|
+
end
|
235
|
+
|
236
|
+
step("Publishing #{gem_file}")
|
237
|
+
|
238
|
+
unless confirm("Push #{gem_file} to RubyGems.org?")
|
239
|
+
error("Aborted by user")
|
240
|
+
end
|
241
|
+
|
242
|
+
if dry_run
|
243
|
+
puts "[DRY-RUN] Would run: gem push #{gem_file}"
|
244
|
+
else
|
245
|
+
unless system("gem push #{gem_file}")
|
246
|
+
error("Failed to publish gem")
|
247
|
+
end
|
248
|
+
puts "✓ Gem published successfully"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# Git Operations
|
253
|
+
def create_git_commit_and_tag(version)
|
254
|
+
tag_name = "gran-v#{version}"
|
255
|
+
commit_message = "Release gran v#{version}"
|
256
|
+
|
257
|
+
step("Creating git commit and tag")
|
258
|
+
|
259
|
+
if dry_run
|
260
|
+
puts "[DRY-RUN] Would run:"
|
261
|
+
puts " git add ."
|
262
|
+
puts " git commit -m '#{commit_message}'"
|
263
|
+
puts " git tag -a #{tag_name} -m '#{commit_message}'"
|
264
|
+
else
|
265
|
+
system("git add .")
|
266
|
+
unless system("git commit -m '#{commit_message}'")
|
267
|
+
error("Failed to create commit")
|
268
|
+
end
|
269
|
+
unless system("git tag -a #{tag_name} -m '#{commit_message}'")
|
270
|
+
error("Failed to create tag")
|
271
|
+
end
|
272
|
+
puts "✓ Created commit and tag: #{tag_name}"
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def push_to_github
|
277
|
+
step("Pushing to GitHub")
|
278
|
+
|
279
|
+
unless confirm("Push commits and tags to GitHub?")
|
280
|
+
error("Aborted by user")
|
281
|
+
end
|
282
|
+
|
283
|
+
if dry_run
|
284
|
+
puts "[DRY-RUN] Would run:"
|
285
|
+
puts " git push origin main"
|
286
|
+
puts " git push origin --tags"
|
287
|
+
else
|
288
|
+
unless system("git push origin main")
|
289
|
+
error("Failed to push commits")
|
290
|
+
end
|
291
|
+
unless system("git push origin --tags")
|
292
|
+
error("Failed to push tags")
|
293
|
+
end
|
294
|
+
puts "✓ Pushed to GitHub"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Helpers
|
299
|
+
def with_dir(dir)
|
300
|
+
original_dir = Dir.pwd
|
301
|
+
Dir.chdir(dir)
|
302
|
+
yield
|
303
|
+
ensure
|
304
|
+
Dir.chdir(original_dir)
|
305
|
+
end
|
306
|
+
|
307
|
+
def confirm(message)
|
308
|
+
return true if yes
|
309
|
+
print "#{message} (y/N): "
|
310
|
+
response = $stdin.gets.strip.downcase
|
311
|
+
response == "y" || response == "yes"
|
312
|
+
end
|
313
|
+
|
314
|
+
def step(message)
|
315
|
+
puts "\n→ #{message}..."
|
316
|
+
end
|
317
|
+
|
318
|
+
def success(message)
|
319
|
+
puts "\n✓ #{message}\n"
|
320
|
+
end
|
321
|
+
|
322
|
+
def error(message)
|
323
|
+
puts "\n✗ ERROR: #{message}\n"
|
324
|
+
exit 1
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
# Run the script
|
329
|
+
if __FILE__ == $0
|
330
|
+
if ARGV.empty?
|
331
|
+
puts "Usage: release.rb [options] COMMAND [VERSION]"
|
332
|
+
puts "Run with --help for more information"
|
333
|
+
exit 1
|
334
|
+
end
|
335
|
+
|
336
|
+
manager = GranReleaseManager.new(ARGV)
|
337
|
+
manager.run
|
338
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gran
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anders Rillbert
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-10-
|
11
|
+
date: 2025-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Provides classes for creatting and transforming trees of PathName nodes
|
14
14
|
email:
|
@@ -28,6 +28,7 @@ files:
|
|
28
28
|
- lib/gran/pathtree.rb
|
29
29
|
- lib/gran/tree_transformer.rb
|
30
30
|
- lib/gran/version.rb
|
31
|
+
- scripts/release.rb
|
31
32
|
homepage: https://github.com/rillbert/giblish/tree/main/gran
|
32
33
|
licenses:
|
33
34
|
- MIT
|