ratatui_ruby-devtools 0.1.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 +7 -0
- data/.builds/ruby-4.0.yml +38 -0
- data/.pre-commit-config.yaml +16 -0
- data/.rubocop.yml +8 -0
- data/AGENTS.md +72 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +661 -0
- data/LICENSES/AGPL-3.0-or-later.txt +661 -0
- data/LICENSES/CC-BY-SA-4.0.txt +427 -0
- data/LICENSES/CC0-1.0.txt +121 -0
- data/LICENSES/MIT-0.txt +16 -0
- data/LICENSES/MIT.txt +18 -0
- data/README.md +199 -0
- data/REUSE.toml +18 -0
- data/Rakefile +13 -0
- data/bin/agent_rake +13 -0
- data/bin/announce +13 -0
- data/bin/console +14 -0
- data/bin/consolidate_md +13 -0
- data/bin/hbs +13 -0
- data/bin/setup +17 -0
- data/doc/contributors/documentation_style.md +121 -0
- data/doc/custom.css +22 -0
- data/exe/agent_rake +96 -0
- data/exe/announce +1120 -0
- data/exe/consolidate_md +246 -0
- data/exe/hbs +670 -0
- data/exe/scaffold +662 -0
- data/lib/ratatui_ruby/devtools/tasks/autodoc/examples.rb +133 -0
- data/lib/ratatui_ruby/devtools/tasks/autodoc/member.rb +116 -0
- data/lib/ratatui_ruby/devtools/tasks/autodoc/name.rb +33 -0
- data/lib/ratatui_ruby/devtools/tasks/autodoc.rake +21 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/cargo_lockfile.rb +38 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/changelog.rb +67 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/header.rb +43 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/history.rb +50 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/links.rb +78 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/manifest.rb +63 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/ruby_gem.rb +77 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/sem_ver.rb +63 -0
- data/lib/ratatui_ruby/devtools/tasks/bump/unreleased_section.rb +75 -0
- data/lib/ratatui_ruby/devtools/tasks/bump.rake +80 -0
- data/lib/ratatui_ruby/devtools/tasks/cargo.rake +47 -0
- data/lib/ratatui_ruby/devtools/tasks/doc.rake +887 -0
- data/lib/ratatui_ruby/devtools/tasks/example_viewer.html.erb +172 -0
- data/lib/ratatui_ruby/devtools/tasks/license/headers_md.rb +276 -0
- data/lib/ratatui_ruby/devtools/tasks/license/headers_rb.rb +236 -0
- data/lib/ratatui_ruby/devtools/tasks/license/license_utils.rb +143 -0
- data/lib/ratatui_ruby/devtools/tasks/license/snippets_md.rb +353 -0
- data/lib/ratatui_ruby/devtools/tasks/license/snippets_rdoc.rb +186 -0
- data/lib/ratatui_ruby/devtools/tasks/license.rake +91 -0
- data/lib/ratatui_ruby/devtools/tasks/lint.rake +84 -0
- data/lib/ratatui_ruby/devtools/tasks/rdoc_config.rb +45 -0
- data/lib/ratatui_ruby/devtools/tasks/resources/build.yml.erb +54 -0
- data/lib/ratatui_ruby/devtools/tasks/resources/rubies.yml +7 -0
- data/lib/ratatui_ruby/devtools/tasks/reuse.rake +104 -0
- data/lib/ratatui_ruby/devtools/tasks/sourcehut.rake +94 -0
- data/lib/ratatui_ruby/devtools/tasks/test.rake +18 -0
- data/lib/ratatui_ruby/devtools/templates/.builds/ruby.yml.erb +47 -0
- data/lib/ratatui_ruby/devtools/templates/.gitignore.erb +18 -0
- data/lib/ratatui_ruby/devtools/templates/.pre-commit-config.yaml.erb +16 -0
- data/lib/ratatui_ruby/devtools/templates/.rubocop.yml.erb +8 -0
- data/lib/ratatui_ruby/devtools/templates/AGENTS.md.erb +65 -0
- data/lib/ratatui_ruby/devtools/templates/CHANGELOG.md.erb +18 -0
- data/lib/ratatui_ruby/devtools/templates/Gemfile.erb +32 -0
- data/lib/ratatui_ruby/devtools/templates/README.md.erb +127 -0
- data/lib/ratatui_ruby/devtools/templates/REUSE.toml.erb +33 -0
- data/lib/ratatui_ruby/devtools/templates/Rakefile.erb +29 -0
- data/lib/ratatui_ruby/devtools/templates/bin/console.erb +18 -0
- data/lib/ratatui_ruby/devtools/templates/bin/setup.erb +24 -0
- data/lib/ratatui_ruby/devtools/templates/doc/concepts/application_architecture.md.erb +16 -0
- data/lib/ratatui_ruby/devtools/templates/doc/concepts/application_testing.md.erb +49 -0
- data/lib/ratatui_ruby/devtools/templates/doc/custom.css.erb +24 -0
- data/lib/ratatui_ruby/devtools/templates/doc/getting_started/quickstart.md.erb +56 -0
- data/lib/ratatui_ruby/devtools/templates/doc/images/.gitkeep +0 -0
- data/lib/ratatui_ruby/devtools/templates/doc/index.md.erb +25 -0
- data/lib/ratatui_ruby/devtools/templates/exe/.gitkeep +0 -0
- data/lib/ratatui_ruby/devtools/templates/gemspec.erb +58 -0
- data/lib/ratatui_ruby/devtools/templates/mise.toml.erb +12 -0
- data/lib/ratatui_ruby/devtools/templates/tasks/example_viewer.html.erb +174 -0
- data/lib/ratatui_ruby/devtools/templates/tasks/resources/build.yml.erb +62 -0
- data/lib/ratatui_ruby/devtools/templates/tasks/resources/index.html.erb +46 -0
- data/lib/ratatui_ruby/devtools/templates/tasks/resources/rubies.yml.erb +9 -0
- data/lib/ratatui_ruby/devtools/templates/vendor/goodcop/base.yml +1047 -0
- data/lib/ratatui_ruby/devtools/version.rb +13 -0
- data/lib/ratatui_ruby/devtools.rb +137 -0
- data/mise.toml +7 -0
- data/sig/ratatui_ruby/devtools.rbs +15 -0
- data/vendor/goodcop/base.yml +1047 -0
- metadata +252 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
namespace :license do
|
|
9
|
+
namespace :headers do
|
|
10
|
+
desc "Ensure markdown files have correct CC-BY-SA-4.0 headers"
|
|
11
|
+
task :md, [:files] do |_t, args|
|
|
12
|
+
files = args[:files] || ""
|
|
13
|
+
ruby "tasks/license/headers_md.rb #{files}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc "Ensure Ruby files have correct AGPL-3.0-or-later headers"
|
|
17
|
+
task :rb, [:files] do |_t, args|
|
|
18
|
+
files = args[:files] || ""
|
|
19
|
+
ruby "tasks/license/headers_rb.rb #{files}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc "Ensure all files have correct license headers"
|
|
23
|
+
task :all do
|
|
24
|
+
Rake::Task["license:headers:md"].invoke
|
|
25
|
+
Rake::Task["license:headers:rb"].invoke
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
namespace :snippets do
|
|
30
|
+
desc "Add MIT-0 SPDX snippet headers to markdown fenced code blocks"
|
|
31
|
+
task :md, [:files] do |_t, args|
|
|
32
|
+
files = args[:files] || ""
|
|
33
|
+
ruby "tasks/license/snippets_md.rb #{files}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
desc "Add MIT-0 SPDX snippet headers to RDoc code examples in Ruby files"
|
|
37
|
+
task :rdoc, [:files] do |_t, args|
|
|
38
|
+
files = args[:files] || "lib/"
|
|
39
|
+
ruby "tasks/license/snippets_rdoc.rb #{files}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc "Add MIT-0 SPDX snippet headers to all code examples"
|
|
43
|
+
task :all do
|
|
44
|
+
Rake::Task["license:snippets:md"].invoke
|
|
45
|
+
Rake::Task["license:snippets:rdoc"].invoke
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
desc "Run all license tasks (headers + snippets)"
|
|
50
|
+
task all: ["headers:all", "snippets:all"]
|
|
51
|
+
|
|
52
|
+
desc "Run license tasks on changed files only (staged + unstaged)"
|
|
53
|
+
task :new do
|
|
54
|
+
# Get changed .md and .rb files (staged and unstaged)
|
|
55
|
+
changed_md = `git diff --name-only --diff-filter=ACMR HEAD -- '*.md' 2>/dev/null`.split("\n")
|
|
56
|
+
staged_md = `git diff --name-only --cached --diff-filter=ACMR -- '*.md' 2>/dev/null`.split("\n")
|
|
57
|
+
changed_rb = `git diff --name-only --diff-filter=ACMR HEAD -- '*.rb' 2>/dev/null`.split("\n")
|
|
58
|
+
staged_rb = `git diff --name-only --cached --diff-filter=ACMR -- '*.rb' 2>/dev/null`.split("\n")
|
|
59
|
+
|
|
60
|
+
# Also get untracked new files
|
|
61
|
+
untracked = `git ls-files --others --exclude-standard`.split("\n")
|
|
62
|
+
untracked_md = untracked.select { |f| f.end_with?(".md") }
|
|
63
|
+
untracked_rb = untracked.select { |f| f.end_with?(".rb") }
|
|
64
|
+
|
|
65
|
+
md_files = (changed_md + staged_md + untracked_md).uniq.join(" ")
|
|
66
|
+
rb_files = (changed_rb + staged_rb + untracked_rb).uniq
|
|
67
|
+
|
|
68
|
+
# Filter rb files to only lib/
|
|
69
|
+
lib_rb_files = rb_files.select { |f| f.start_with?("lib/") }.join(" ")
|
|
70
|
+
|
|
71
|
+
if md_files.empty? && lib_rb_files.empty?
|
|
72
|
+
puts "No changed .md or lib/*.rb files to process"
|
|
73
|
+
else
|
|
74
|
+
unless md_files.empty?
|
|
75
|
+
puts "Processing #{md_files.split.count} changed .md file(s)..."
|
|
76
|
+
Rake::Task["license:headers:md"].invoke(md_files)
|
|
77
|
+
Rake::Task["license:headers:md"].reenable
|
|
78
|
+
Rake::Task["license:snippets:md"].invoke(md_files)
|
|
79
|
+
Rake::Task["license:snippets:md"].reenable
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
unless lib_rb_files.empty?
|
|
83
|
+
puts "Processing #{lib_rb_files.split.count} changed lib/*.rb file(s)..."
|
|
84
|
+
Rake::Task["license:headers:rb"].invoke(lib_rb_files)
|
|
85
|
+
Rake::Task["license:headers:rb"].reenable
|
|
86
|
+
Rake::Task["license:snippets:rdoc"].invoke(lib_rb_files)
|
|
87
|
+
Rake::Task["license:snippets:rdoc"].reenable
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
require "rubocop/rake_task"
|
|
9
|
+
require "rubycritic/rake_task"
|
|
10
|
+
require "inch/rake"
|
|
11
|
+
|
|
12
|
+
RuboCop::RakeTask.new
|
|
13
|
+
|
|
14
|
+
# Run rubycritic in a shell to prevent it from exiting the rake process
|
|
15
|
+
task :rubycritic do
|
|
16
|
+
paths = []
|
|
17
|
+
paths << "exe" if Dir.exist?("exe")
|
|
18
|
+
paths << "lib" if Dir.exist?("lib")
|
|
19
|
+
paths << "sig" if Dir.exist?("sig")
|
|
20
|
+
sh "bundle exec rubycritic --no-browser #{paths.join(' ')}" unless paths.empty?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Inch::Rake::Suggest.new("doc:suggest", "exe/**/*.rb", "lib/**/*.rb", "sig/**/*.rbs") do |suggest|
|
|
24
|
+
suggest.args << ""
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
namespace :lint do
|
|
28
|
+
task :safe_rdoc_coverage do
|
|
29
|
+
if Rake::Task.task_defined?("rdoc:coverage")
|
|
30
|
+
sh "bundle exec rake rdoc:coverage"
|
|
31
|
+
else
|
|
32
|
+
puts "rdoc:coverage task not defined, skipping"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Build dynamic task lists based on what's available
|
|
37
|
+
docs_tasks = %w[rubycritic reuse:lint]
|
|
38
|
+
docs_tasks.unshift("autodoc") if Rake::Task.task_defined?("autodoc")
|
|
39
|
+
docs_tasks << "safe_rdoc_coverage" if Rake::Task.task_defined?("rdoc:coverage")
|
|
40
|
+
|
|
41
|
+
code_tasks = %w[rubocop rubycritic]
|
|
42
|
+
code_tasks += %w[cargo:fmt cargo:clippy cargo:test] if Dir.exist?("ext")
|
|
43
|
+
|
|
44
|
+
task docs: docs_tasks
|
|
45
|
+
task code: code_tasks
|
|
46
|
+
task licenses: %w[reuse:lint]
|
|
47
|
+
task all: %w[docs code licenses]
|
|
48
|
+
|
|
49
|
+
namespace :fix do
|
|
50
|
+
desc "Auto-fix RuboCop offenses (most aggressive)"
|
|
51
|
+
task :rubocop do
|
|
52
|
+
sh "bundle exec rubocop --autocorrect-all"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if Dir.exist?("ext")
|
|
56
|
+
desc "Auto-fix Clippy warnings (most aggressive: --fix --allow-dirty --allow-staged)"
|
|
57
|
+
task :clippy do
|
|
58
|
+
ext_dirs = Dir.glob("ext/*").select { |d| File.directory?(d) && File.exist?("#{d}/Cargo.toml") }
|
|
59
|
+
ext_dirs.each do |dir|
|
|
60
|
+
sh "cd #{dir} && cargo clippy --fix --allow-dirty --allow-staged"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
desc "Add SPDX headers and normalize Ruby file structure"
|
|
66
|
+
task reuse: %w[reuse:fix reuse:normalize_ruby]
|
|
67
|
+
|
|
68
|
+
# Build dynamic fix:all task
|
|
69
|
+
fix_all_tasks = %w[lint:fix:rubocop lint:fix:reuse]
|
|
70
|
+
fix_all_tasks.insert(1, "lint:fix:clippy") if Dir.exist?("ext")
|
|
71
|
+
|
|
72
|
+
desc "Run all auto-fix tasks"
|
|
73
|
+
task all: fix_all_tasks
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
desc "Run all lint auto-fix tasks"
|
|
78
|
+
task("lint:fix") { Rake::Task["lint:fix:all"].invoke }
|
|
79
|
+
|
|
80
|
+
# Aliases for convenience
|
|
81
|
+
task "rubocop:autocorrect_all" => "lint:fix:rubocop"
|
|
82
|
+
|
|
83
|
+
desc "Run all lint tasks"
|
|
84
|
+
task(:lint) { Rake::Task["lint:all"].invoke }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
# Configuration for RDoc documentation generation.
|
|
9
|
+
#
|
|
10
|
+
# RDoc generates API documentation from source files. Configuring which files
|
|
11
|
+
# to include requires glob patterns. Large files slow generation. Verification
|
|
12
|
+
# examples clutter the output.
|
|
13
|
+
#
|
|
14
|
+
# This module defines the file list, size limits, and main page. Use it to
|
|
15
|
+
# configure RDoc::Task consistently across ecosystem gems.
|
|
16
|
+
module RDocConfig
|
|
17
|
+
# Maximum file size to include in documentation. Files larger than this are
|
|
18
|
+
# skipped to avoid performance issues. 100KB handles most source files while
|
|
19
|
+
# excluding chat logs and similar large artifacts.
|
|
20
|
+
MAX_FILE_SIZE = 100_000
|
|
21
|
+
|
|
22
|
+
# Files to include in RDoc generation.
|
|
23
|
+
#
|
|
24
|
+
# Includes markdown docs, readme files, library source, and executables.
|
|
25
|
+
# Excludes large files and verification examples.
|
|
26
|
+
RDOC_FILES = Dir.glob(%w[
|
|
27
|
+
doc/**/*.md
|
|
28
|
+
examples/**/*.md
|
|
29
|
+
*.md
|
|
30
|
+
*.rdoc
|
|
31
|
+
lib/**/*.rb
|
|
32
|
+
exe/**/*
|
|
33
|
+
]).reject { |f|
|
|
34
|
+
# Skip large files
|
|
35
|
+
if File.size(f) > MAX_FILE_SIZE
|
|
36
|
+
warn "RDoc: skipping #{f} (#{File.size(f) / 1024}KB > #{MAX_FILE_SIZE / 1024}KB limit)"
|
|
37
|
+
next true
|
|
38
|
+
end
|
|
39
|
+
# Skip verification examples (internal testing, not user-facing)
|
|
40
|
+
f.start_with?("examples/verify_")
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
# The main page for RDoc output.
|
|
44
|
+
MAIN = "README.md"
|
|
45
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
image: archlinux
|
|
5
|
+
packages:
|
|
6
|
+
- bash
|
|
7
|
+
- base-devel
|
|
8
|
+
- curl
|
|
9
|
+
- openssl
|
|
10
|
+
- libyaml
|
|
11
|
+
- zlib
|
|
12
|
+
- readline
|
|
13
|
+
- gdbm
|
|
14
|
+
- ncurses
|
|
15
|
+
- libffi
|
|
16
|
+
- clang
|
|
17
|
+
- git
|
|
18
|
+
artifacts:
|
|
19
|
+
- ratatui_ruby/pkg/<%= gem_filename %>
|
|
20
|
+
sources:
|
|
21
|
+
- https://git.sr.ht/~kerrick/ratatui_ruby
|
|
22
|
+
tasks:
|
|
23
|
+
- setup: |
|
|
24
|
+
curl https://mise.jdx.dev/install.sh | sh
|
|
25
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.buildenv
|
|
26
|
+
echo 'eval "$($HOME/.local/bin/mise activate bash)"' >> ~/.buildenv
|
|
27
|
+
echo 'export LANG="en_US.UTF-8"' >> ~/.buildenv
|
|
28
|
+
echo 'export LC_ALL="en_US.UTF-8"' >> ~/.buildenv
|
|
29
|
+
echo 'export BINDGEN_EXTRA_CLANG_ARGS="-include stdbool.h"' >> ~/.buildenv
|
|
30
|
+
. ~/.buildenv
|
|
31
|
+
export CI="true"
|
|
32
|
+
cd ratatui_ruby
|
|
33
|
+
sed -i 's/ruby = .*/ruby = "<%= ruby_version %>"/' mise.toml
|
|
34
|
+
mise install
|
|
35
|
+
mise x -- pip install reuse
|
|
36
|
+
mise x -- gem install bundler:<%= bundler_version %>
|
|
37
|
+
mise reshim
|
|
38
|
+
mise x -- bundle config set --local frozen 'true'
|
|
39
|
+
mise x -- bundle install
|
|
40
|
+
mise x -- bundle exec rake compile
|
|
41
|
+
- test: |
|
|
42
|
+
. ~/.buildenv
|
|
43
|
+
cd ratatui_ruby
|
|
44
|
+
echo "Testing Ruby <%= ruby_version %>"
|
|
45
|
+
mise x -- bundle exec rake test
|
|
46
|
+
- lint: |
|
|
47
|
+
. ~/.buildenv
|
|
48
|
+
cd ratatui_ruby
|
|
49
|
+
echo "Linting Ruby <%= ruby_version %>"
|
|
50
|
+
mise x -- bundle exec rake lint
|
|
51
|
+
- package: |
|
|
52
|
+
. ~/.buildenv
|
|
53
|
+
cd ratatui_ruby
|
|
54
|
+
mise x -- bundle exec rake build
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
namespace :reuse do
|
|
9
|
+
desc "Run the REUSE Tool to confirm REUSE compliance"
|
|
10
|
+
task :lint do
|
|
11
|
+
sh "reuse lint"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc "Add SPDX headers to files missing them (per AGENTS.md standards)"
|
|
15
|
+
task :fix do
|
|
16
|
+
copyright = ENV.fetch("REUSE_COPYRIGHT", "Kerrick Long <me@kerricklong.com>")
|
|
17
|
+
|
|
18
|
+
# Code files: AGPL-3.0-or-later
|
|
19
|
+
code_extensions = %w[rb rs rake gemspec rbs toml yml yaml json lock].freeze
|
|
20
|
+
code_license = ENV.fetch("REUSE_CODE_LICENSE", "AGPL-3.0-or-later")
|
|
21
|
+
|
|
22
|
+
# Documentation files: CC-BY-SA-4.0
|
|
23
|
+
doc_extensions = %w[md txt].freeze
|
|
24
|
+
doc_license = ENV.fetch("REUSE_DOC_LICENSE", "CC-BY-SA-4.0")
|
|
25
|
+
|
|
26
|
+
# Find files missing headers (listed after "no copyright and licensing" message)
|
|
27
|
+
puts "Checking for files missing REUSE headers..."
|
|
28
|
+
output = `reuse lint 2>&1`
|
|
29
|
+
in_missing_section = false
|
|
30
|
+
missing_files = output.lines.filter_map do |line|
|
|
31
|
+
in_missing_section = true if line.include?("no copyright and licensing")
|
|
32
|
+
in_missing_section = false if line.start_with?("# ") && !line.include?("copyright")
|
|
33
|
+
next unless in_missing_section
|
|
34
|
+
|
|
35
|
+
line.match(/^\* (.+)/)&.[](1)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if missing_files.empty?
|
|
39
|
+
puts "All files have REUSE headers!"
|
|
40
|
+
else
|
|
41
|
+
missing_files.each do |file|
|
|
42
|
+
ext = File.extname(file).delete(".")
|
|
43
|
+
license = if code_extensions.include?(ext)
|
|
44
|
+
code_license
|
|
45
|
+
elsif doc_extensions.include?(ext)
|
|
46
|
+
doc_license
|
|
47
|
+
else
|
|
48
|
+
puts " Skipping #{file} (unknown extension: .#{ext})"
|
|
49
|
+
next
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
puts " Annotating #{file} with #{license}"
|
|
53
|
+
sh "reuse annotate --license #{license} --copyright '#{copyright}' --skip-existing '#{file}'", verbose: false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
desc "Normalize Ruby files: frozen_string_literal at top, SPDX in #--/#++ block"
|
|
59
|
+
task :normalize_ruby do
|
|
60
|
+
ruby_extensions = %w[rb rake gemspec].freeze
|
|
61
|
+
ruby_files = Dir.glob("**/*.{#{ruby_extensions.join(',')}}")
|
|
62
|
+
.reject { |f| f.start_with?("vendor/", "tmp/", ".") }
|
|
63
|
+
|
|
64
|
+
fixed_count = 0
|
|
65
|
+
ruby_files.each do |file|
|
|
66
|
+
content = File.read(file)
|
|
67
|
+
original = content.dup
|
|
68
|
+
|
|
69
|
+
# Skip if no SPDX header
|
|
70
|
+
next unless content.match?(/# SPDX-/)
|
|
71
|
+
|
|
72
|
+
# Extract components
|
|
73
|
+
frozen = content.match?(/^# frozen_string_literal: true/)
|
|
74
|
+
spdx_match = content.match(/(# SPDX-FileCopyrightText:[^\n]+\n(?:#[^\n]*\n)*# SPDX-License-Identifier:[^\n]+\n)/m)
|
|
75
|
+
next unless spdx_match
|
|
76
|
+
|
|
77
|
+
spdx_block = spdx_match[1]
|
|
78
|
+
|
|
79
|
+
# Remove existing frozen_string_literal and SPDX block (and any #--/#++)
|
|
80
|
+
cleaned = content
|
|
81
|
+
.sub(/^# frozen_string_literal: true\n+/, "")
|
|
82
|
+
.sub(/^#--\s*\n/, "")
|
|
83
|
+
.sub(spdx_block, "")
|
|
84
|
+
.sub(/^#\+\+\s*\n/, "")
|
|
85
|
+
.sub(/\A\n+/, "") # Remove leading blank lines
|
|
86
|
+
|
|
87
|
+
# Rebuild file in correct order: frozen, blank, #--, SPDX, #++, rest
|
|
88
|
+
new_content = ""
|
|
89
|
+
new_content += "# frozen_string_literal: true\n\n" if frozen
|
|
90
|
+
new_content += "#--\n#{spdx_block}#++\n\n"
|
|
91
|
+
new_content += cleaned.sub(/\A\n+/, "") # Ensure no double blank lines
|
|
92
|
+
|
|
93
|
+
next unless new_content != original
|
|
94
|
+
|
|
95
|
+
File.write(file, new_content)
|
|
96
|
+
puts " Normalized #{file}"
|
|
97
|
+
fixed_count += 1
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
puts fixed_count.zero? ? "All Ruby files properly normalized!" : "Fixed #{fixed_count} files."
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
task(:reuse) { Rake::Task["reuse:lint"].invoke }
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
desc "Generate SourceHut build manifests from template"
|
|
9
|
+
task sourcehut: "sourcehut:build"
|
|
10
|
+
|
|
11
|
+
namespace :sourcehut do
|
|
12
|
+
desc "Build SourceHut manifests"
|
|
13
|
+
task build: "sourcehut:build:manifest"
|
|
14
|
+
|
|
15
|
+
namespace :build do
|
|
16
|
+
desc "Generate SourceHut build manifests from template"
|
|
17
|
+
task :manifest do
|
|
18
|
+
require "erb"
|
|
19
|
+
require "yaml"
|
|
20
|
+
|
|
21
|
+
gem_name = RatatuiRuby::Devtools.gem_name
|
|
22
|
+
gemspec_file = RatatuiRuby::Devtools.gemspec_file
|
|
23
|
+
version_file = RatatuiRuby::Devtools.version_file
|
|
24
|
+
|
|
25
|
+
# Detect if this is a Rust extension gem
|
|
26
|
+
has_rust = File.exist?("ext/#{gem_name}/Cargo.toml") ||
|
|
27
|
+
File.exist?("ext/#{gem_name.tr('-', '_')}/Cargo.toml")
|
|
28
|
+
|
|
29
|
+
spec = Gem::Specification.load(gemspec_file)
|
|
30
|
+
|
|
31
|
+
# Read version directly from file to ensure we get the latest version
|
|
32
|
+
# even if it was just bumped in the same Rake execution
|
|
33
|
+
version_content = File.read(version_file)
|
|
34
|
+
version = version_content.match(/VERSION = "(.+?)"/)[1]
|
|
35
|
+
|
|
36
|
+
gem_filename = "#{spec.name}-#{version}.gem"
|
|
37
|
+
|
|
38
|
+
rubies = YAML.load_file("tasks/resources/rubies.yml")
|
|
39
|
+
|
|
40
|
+
bundler_version = File.read("Gemfile.lock").match(/BUNDLED WITH\n\s+([\d.]+)/)[1]
|
|
41
|
+
|
|
42
|
+
template = File.read("tasks/resources/build.yml.erb")
|
|
43
|
+
erb = ERB.new(template, trim_mode: "-")
|
|
44
|
+
|
|
45
|
+
FileUtils.mkdir_p ".builds"
|
|
46
|
+
|
|
47
|
+
# Remove old generated files to ensure a clean state
|
|
48
|
+
Dir.glob(".builds/*.yml").each { |f| File.delete(f) }
|
|
49
|
+
|
|
50
|
+
rubies.each do |ruby_version|
|
|
51
|
+
filename = ".builds/ruby-#{ruby_version}.yml"
|
|
52
|
+
puts "Generating #{filename}..."
|
|
53
|
+
content = erb.result_with_hash(gem_name:, has_rust:, ruby_version:, gem_filename:, bundler_version:)
|
|
54
|
+
File.write(filename, content)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
desc "Update stable branch to match release and set as default"
|
|
60
|
+
task :update_stable do
|
|
61
|
+
version_file = RatatuiRuby::Devtools.version_file
|
|
62
|
+
|
|
63
|
+
# Read version to determine tag
|
|
64
|
+
version_content = File.read(version_file)
|
|
65
|
+
version = version_content.match(/VERSION = "(.+?)"/)[1]
|
|
66
|
+
tag_name = "v#{version}"
|
|
67
|
+
|
|
68
|
+
# Verify that the version file matches the actual git tag
|
|
69
|
+
# This prevents updating stable to the wrong version if the release failed
|
|
70
|
+
latest_tag = `git describe --tags --abbrev=0`.strip
|
|
71
|
+
if latest_tag != tag_name
|
|
72
|
+
abort "Fatal: Version mismatch! '#{version_file}' says #{tag_name}, " \
|
|
73
|
+
"but the latest git tag is #{latest_tag}."
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
puts "Updating stable branch to point to #{tag_name}..."
|
|
77
|
+
# Resolve the tag to a commit hash (peel annotated tags)
|
|
78
|
+
# This renders a commit SHA that can be pushed to a branch head
|
|
79
|
+
commit_sha = `git rev-parse #{tag_name}^{}`.strip
|
|
80
|
+
|
|
81
|
+
# Update local stable branch to match
|
|
82
|
+
sh "git branch -f stable #{commit_sha}"
|
|
83
|
+
|
|
84
|
+
# Push the commit to remote stable branch
|
|
85
|
+
# This creates 'stable' if it doesn't exist, or fast-forwards it.
|
|
86
|
+
sh "git push origin #{commit_sha}:stable"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if Rake::Task.task_defined?("release")
|
|
91
|
+
Rake::Task["release"].enhance do
|
|
92
|
+
Rake::Task["sourcehut:update_stable"].invoke
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
# Minitest task for pure Ruby gems.
|
|
9
|
+
#
|
|
10
|
+
# Consumer gems need test running. This provides a simple Minitest::TestTask
|
|
11
|
+
# that discovers tests in the standard locations. Gems with Rust extensions
|
|
12
|
+
# should define their own test task that includes cargo:test.
|
|
13
|
+
|
|
14
|
+
require "minitest/test_task"
|
|
15
|
+
|
|
16
|
+
Minitest::TestTask.create(:test) do |t|
|
|
17
|
+
t.test_globs = ["test/**/*_test.rb", "test/**/test_*.rb"]
|
|
18
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# REUSE-IgnoreStart
|
|
2
|
+
# SPDX-FileCopyrightText: <%= Time.now.year %> <%= copyright_holder %>
|
|
3
|
+
# SPDX-License-Identifier: <%= license %>
|
|
4
|
+
# REUSE-IgnoreEnd
|
|
5
|
+
|
|
6
|
+
image: archlinux
|
|
7
|
+
packages:
|
|
8
|
+
- bash
|
|
9
|
+
- base-devel
|
|
10
|
+
- curl
|
|
11
|
+
- openssl
|
|
12
|
+
- libyaml
|
|
13
|
+
- zlib
|
|
14
|
+
- readline
|
|
15
|
+
- gdbm
|
|
16
|
+
- ncurses
|
|
17
|
+
- libffi
|
|
18
|
+
- git
|
|
19
|
+
sources:
|
|
20
|
+
- https://git.sr.ht/~kerrick/<%= gem_name %>
|
|
21
|
+
tasks:
|
|
22
|
+
- setup: |
|
|
23
|
+
curl https://mise.jdx.dev/install.sh | sh
|
|
24
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.buildenv
|
|
25
|
+
echo 'eval "$($HOME/.local/bin/mise activate bash)"' >> ~/.buildenv
|
|
26
|
+
echo 'export LANG="en_US.UTF-8"' >> ~/.buildenv
|
|
27
|
+
echo 'export LC_ALL="en_US.UTF-8"' >> ~/.buildenv
|
|
28
|
+
. ~/.buildenv
|
|
29
|
+
export CI="true"
|
|
30
|
+
cd <%= gem_name %>
|
|
31
|
+
sed -i 's/ruby = .*/ruby = "<%= ruby_version %>"/' mise.toml
|
|
32
|
+
mise install
|
|
33
|
+
mise x -- pip install reuse
|
|
34
|
+
mise x -- gem install bundler
|
|
35
|
+
mise reshim
|
|
36
|
+
mise x -- bundle config set --local frozen 'true'
|
|
37
|
+
mise x -- bundle install
|
|
38
|
+
- test: |
|
|
39
|
+
. ~/.buildenv
|
|
40
|
+
cd <%= gem_name %>
|
|
41
|
+
echo "Testing Ruby <%= ruby_version %>"
|
|
42
|
+
mise x -- bundle exec rake test
|
|
43
|
+
- lint: |
|
|
44
|
+
. ~/.buildenv
|
|
45
|
+
cd <%= gem_name %>
|
|
46
|
+
echo "Linting Ruby <%= ruby_version %>"
|
|
47
|
+
mise x -- bundle exec rake lint
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
**/.idea/
|
|
5
|
+
**/.DS_Store
|
|
6
|
+
/.bundle/
|
|
7
|
+
/.yardoc/
|
|
8
|
+
/_yardoc/
|
|
9
|
+
/coverage/
|
|
10
|
+
/pkg/
|
|
11
|
+
/spec/reports/
|
|
12
|
+
/tmp/
|
|
13
|
+
<%- if has_rust -%>
|
|
14
|
+
/ext/<%= gem_name %>/target/
|
|
15
|
+
*.bundle
|
|
16
|
+
*.dylib
|
|
17
|
+
*.so
|
|
18
|
+
<%- end -%>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2020 Free Software Foundation Europe e.V.
|
|
2
|
+
# SPDX-License-Identifier: CC0-1.0
|
|
3
|
+
repos:
|
|
4
|
+
- repo: local
|
|
5
|
+
hooks:
|
|
6
|
+
- id: bundle-check
|
|
7
|
+
name: Check Gemfile.lock
|
|
8
|
+
entry: bundle check
|
|
9
|
+
language: system
|
|
10
|
+
files: (Gemfile|Gemfile\.lock|<%= gem_name %>\.gemspec)
|
|
11
|
+
pass_filenames: false
|
|
12
|
+
- id: rake
|
|
13
|
+
name: rake
|
|
14
|
+
entry: bundle exec rake
|
|
15
|
+
language: system
|
|
16
|
+
pass_filenames: false
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# AGENTS.md
|
|
7
|
+
|
|
8
|
+
## Project Identity
|
|
9
|
+
|
|
10
|
+
Project Name: <%= gem_name %>
|
|
11
|
+
|
|
12
|
+
Description: Part of the RatatuiRuby ecosystem.
|
|
13
|
+
|
|
14
|
+
## 1. Standards
|
|
15
|
+
|
|
16
|
+
### STRICT REQUIREMENTS
|
|
17
|
+
|
|
18
|
+
- Every file MUST begin with an SPDX-compliant header. Use `<%= license %>` for code; `CC-BY-SA-4.0` for documentation. `reuse annotate` can help you generate the header. **For Ruby files**, wrap SPDX comments in `#--` / `#++` to hide them from RDoc output.
|
|
19
|
+
- Every line of Ruby MUST be covered by tests that would stand up to mutation testing.
|
|
20
|
+
- Tests must be meaningful and verify specific behavior or rendering output; simply verifying that code "doesn't crash" is insufficient and unacceptable.
|
|
21
|
+
- **Pre-commit:** Use `agent_rake` to ensure commit-readiness. See Tools for detailed instructions.
|
|
22
|
+
- **Git Pager:** ALWAYS set `PAGER=cat` for ALL `git` commands (e.g., `PAGER=cat git diff`). This is mandatory.
|
|
23
|
+
|
|
24
|
+
### Tools
|
|
25
|
+
|
|
26
|
+
- **NEVER** run `bundle exec rake` directly. **NEVER** run `bundle exec ruby -Ilib:test ...` directly.
|
|
27
|
+
- **ALWAYS use `agent_rake`** (provided by the `ratatui_ruby-devtools` gem) for running tests, linting, or checking compilation.
|
|
28
|
+
- **Usage:**
|
|
29
|
+
- Runs default task (compile + test + lint): `agent_rake`
|
|
30
|
+
- Runs specific task: `agent_rake test:ruby` (for example)
|
|
31
|
+
- **Setup:** `bin/setup` must handle Bundler dependencies.
|
|
32
|
+
- **Git:** ALWAYS set `PAGER=cat` with `git`. **THIS IS CRITICAL!**
|
|
33
|
+
|
|
34
|
+
### Ruby Standards
|
|
35
|
+
|
|
36
|
+
- Use `Data.define` for all value objects (Ruby 3.2+).
|
|
37
|
+
- Define types in `.rbs` files. Don't use `untyped` just because it's easy; be comprehensive and accurate.
|
|
38
|
+
- Every public Ruby class/method must be documented for humans in RDoc.
|
|
39
|
+
|
|
40
|
+
## 2. Committing
|
|
41
|
+
|
|
42
|
+
- Who commits: DON'T stage (DON'T `git add`) unless explicitly instructed. DON'T commit unless explicitly instructed. DO suggest a commit message when you finish.
|
|
43
|
+
- **Format:**
|
|
44
|
+
- Format: Use [Conventional Commits](https://www.conventionalcommits.org/).
|
|
45
|
+
- Body: Explanation if necessary (wrap at 72 chars).
|
|
46
|
+
- **DON'T list the files changed or the edits made in the body.**
|
|
47
|
+
- **DON'T use markdown syntax** (no backticks, no bolding, no lists, no links).
|
|
48
|
+
|
|
49
|
+
## 3. Definition of Done (DoD)
|
|
50
|
+
|
|
51
|
+
Before considering a task complete:
|
|
52
|
+
|
|
53
|
+
1. **Default Rake Task Passes:** Run `agent_rake` (no args). Confirm it passes with ZERO errors.
|
|
54
|
+
2. **Documentation Updated:** If public APIs changed, update relevant docs.
|
|
55
|
+
3. **Changelog Updated:** If public APIs changed, update CHANGELOG.md's **Unreleased** section.
|
|
56
|
+
4. **Commit Message Suggested:** Include a suggested commit message block.
|
|
57
|
+
|
|
58
|
+
### Type Conventions
|
|
59
|
+
|
|
60
|
+
- `lib/`, `ext/`, `sig/`: Use `feat`, `fix`, `refactor`, `perf` as appropriate.
|
|
61
|
+
- `bin/`, `tasks/`, `.builds/`, CI/CD: Use `chore` for tooling internal to developing this gem. Use `feat`/`fix` for user-facing executables or changes that affect downstream users.
|
|
62
|
+
- `examples/`: Always `docs` (documentation by example).
|
|
63
|
+
- `test/`: Use `test` for new/changed tests, or match the type of the code being tested.
|
|
64
|
+
- `doc/`: Always `docs`.
|
|
65
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Changelog
|
|
7
|
+
|
|
8
|
+
All notable changes to this project will be documented in this file.
|
|
9
|
+
|
|
10
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
11
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [Unreleased]
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Initial release of <%= gem_name %>
|