ratatui_ruby-devtools 0.1.3 → 0.2.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSES/BSD-2-Clause.txt +9 -0
  4. data/README.md +1 -1
  5. data/exe/hbs +149 -209
  6. data/exe/scaffold +169 -282
  7. data/lib/ratatui_ruby/devtools/tasks/lint.rake +3 -7
  8. data/lib/ratatui_ruby/devtools/tasks/release/ci_run.rb +44 -0
  9. data/lib/ratatui_ruby/devtools/tasks/release/github_cli.rb +36 -0
  10. data/lib/ratatui_ruby/devtools/tasks/release/native_gem_version.rb +70 -0
  11. data/lib/ratatui_ruby/devtools/tasks/release/platform_gem.rb +63 -0
  12. data/lib/ratatui_ruby/devtools/tasks/release/versioned_binary.rb +36 -0
  13. data/lib/ratatui_ruby/devtools/tasks/release.rake +87 -0
  14. data/lib/ratatui_ruby/devtools/tasks/resources/rubies.yml +1 -1
  15. data/lib/ratatui_ruby/devtools/templates/.github/workflows/build-gems.yml.erb +124 -0
  16. data/lib/ratatui_ruby/devtools/templates/.github/workflows/ci.yml.erb +77 -0
  17. data/lib/ratatui_ruby/devtools/templates/.gitignore.erb +2 -0
  18. data/lib/ratatui_ruby/devtools/templates/.rubocop.yml.erb +6 -4
  19. data/lib/ratatui_ruby/devtools/templates/AGENTS.md.erb +101 -28
  20. data/lib/ratatui_ruby/devtools/templates/CODE_OF_CONDUCT.md.erb +44 -0
  21. data/lib/ratatui_ruby/devtools/templates/CONTRIBUTING.md.erb +80 -0
  22. data/lib/ratatui_ruby/devtools/templates/Gemfile.erb +2 -2
  23. data/lib/ratatui_ruby/devtools/templates/README.md.erb +46 -13
  24. data/lib/ratatui_ruby/devtools/templates/REUSE.toml.erb +2 -2
  25. data/lib/ratatui_ruby/devtools/templates/Rakefile.erb +4 -4
  26. data/lib/ratatui_ruby/devtools/templates/bin/setup.erb +21 -11
  27. data/lib/ratatui_ruby/devtools/templates/bin/setup.ps1.erb +105 -0
  28. data/lib/ratatui_ruby/devtools/templates/doc/custom.css.erb +3 -3
  29. data/lib/ratatui_ruby/devtools/templates/doc/getting_started/quickstart.md.erb +3 -3
  30. data/lib/ratatui_ruby/devtools/templates/doc/index.md.erb +2 -2
  31. data/lib/ratatui_ruby/devtools/templates/ext/.cargo/config.toml.erb +15 -0
  32. data/lib/ratatui_ruby/devtools/templates/ext/.gitignore.erb +6 -0
  33. data/lib/ratatui_ruby/devtools/templates/ext/Cargo.toml.erb +20 -0
  34. data/lib/ratatui_ruby/devtools/templates/ext/clippy.toml.erb +9 -0
  35. data/lib/ratatui_ruby/devtools/templates/ext/extconf.rb.erb +23 -0
  36. data/lib/ratatui_ruby/devtools/templates/ext/src/lib.rs.erb +13 -0
  37. data/lib/ratatui_ruby/devtools/templates/gemspec.erb +21 -14
  38. data/lib/ratatui_ruby/devtools/templates/lib/main.rb.erb +19 -0
  39. data/lib/ratatui_ruby/devtools/templates/lib/test_helper.rb.erb +26 -0
  40. data/lib/ratatui_ruby/devtools/templates/lib/version.rb.erb +10 -0
  41. data/lib/ratatui_ruby/devtools/templates/mise.toml.erb +3 -3
  42. data/lib/ratatui_ruby/devtools/templates/tasks/example_viewer.html.erb +23 -23
  43. data/lib/ratatui_ruby/devtools/templates/tasks/resources/index.html.erb +15 -16
  44. data/lib/ratatui_ruby/devtools/templates/tasks/resources/rubies.yml.erb +5 -6
  45. data/lib/ratatui_ruby/devtools/templates/test/test_helper.rb.erb +15 -0
  46. data/lib/ratatui_ruby/devtools/version.rb +1 -1
  47. data/lib/ratatui_ruby/devtools.rb +2 -2
  48. metadata +24 -5
  49. data/lib/ratatui_ruby/devtools/tasks/resources/build.yml.erb +0 -54
  50. data/lib/ratatui_ruby/devtools/tasks/sourcehut.rake +0 -94
  51. data/lib/ratatui_ruby/devtools/templates/tasks/resources/build.yml.erb +0 -62
  52. /data/lib/ratatui_ruby/devtools/templates/{vendor/goodcop/base.yml → lib/rubocop.yml} +0 -0
@@ -0,0 +1,44 @@
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 "open3"
9
+ require "json"
10
+ require "tmpdir"
11
+
12
+ # A completed GitHub Actions workflow run for a specific commit.
13
+ class CIRun < Data.define(:id)
14
+ ##
15
+ # The GitHub Actions workflow name that produces native gem artifacts.
16
+ WORKFLOW_NAME = "Build Gems"
17
+
18
+ # Finds the most recent successful run for the given commit SHA.
19
+ def self.for_commit(sha)
20
+ out, status = Open3.capture2(
21
+ "gh", "run", "list",
22
+ "--workflow", WORKFLOW_NAME,
23
+ "--commit", sha,
24
+ "--status", "completed",
25
+ "--json", "databaseId,conclusion",
26
+ "--limit", "1"
27
+ )
28
+ return nil unless status.success?
29
+
30
+ runs = JSON.parse(out)
31
+ run = runs.first
32
+ return nil unless run
33
+ return nil unless run.fetch("conclusion") == "success"
34
+
35
+ new(id: run.fetch("databaseId"))
36
+ end
37
+
38
+ # Downloads artifacts into +dir+ and returns paths to the .gem files.
39
+ def download(dir)
40
+ puts "Downloading native gem artifacts from run #{id}..."
41
+ system("gh", "run", "download", id.to_s, "--dir", dir, exception: true)
42
+ Dir.glob("#{dir}/**/*.gem")
43
+ end
44
+ end
@@ -0,0 +1,36 @@
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
+ # GitHubCli wraps availability and authentication checks for the `gh` CLI.
9
+ class GitHubCli
10
+ # Whether the +gh+ binary is on PATH.
11
+ def available?
12
+ system("command", "-v", "gh", out: File::NULL, err: File::NULL)
13
+ end
14
+
15
+ # Whether +gh auth status+ reports a valid session.
16
+ def authenticated?
17
+ system("gh", "auth", "status", out: File::NULL, err: File::NULL)
18
+ end
19
+
20
+ # Whether the CLI is both installed and authenticated.
21
+ def ready?
22
+ available? && authenticated?
23
+ end
24
+
25
+ # Prints advisory when the +gh+ binary cannot be found.
26
+ def warn_unavailable
27
+ warn "\n⚠ 'gh' CLI not found — skipping native gem push."
28
+ warn " Install: https://cli.github.com\n\n"
29
+ end
30
+
31
+ # Prints advisory when +gh+ is installed but not logged in.
32
+ def warn_unauthenticated
33
+ warn "\n⚠ 'gh' is not authenticated — skipping native gem push."
34
+ warn " Run: gh auth login\n\n"
35
+ end
36
+ end
@@ -0,0 +1,70 @@
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 "tmpdir"
9
+
10
+ require_relative "github_cli"
11
+ require_relative "ci_run"
12
+
13
+ # A native gem version identified by its version string and commit SHA.
14
+ # Knows how to release itself by downloading CI artifacts and pushing to RubyGems.
15
+ class NativeGemVersion < Data.define(:version, :sha)
16
+ ##
17
+ # Downloads CI artifacts for this version and pushes them to RubyGems.org.
18
+ def release
19
+ cli = GitHubCli.new
20
+
21
+ unless cli.available?
22
+ cli.warn_unavailable
23
+ return
24
+ end
25
+
26
+ unless cli.authenticated?
27
+ cli.warn_unauthenticated
28
+ return
29
+ end
30
+
31
+ run = CIRun.for_commit(sha)
32
+
33
+ unless run
34
+ warn "\n⚠ No completed '#{CIRun::WORKFLOW_NAME}' run found for v#{version} (#{sha[0, 7]})."
35
+ warn " Native gems were not pushed to RubyGems.org.\n\n"
36
+ return
37
+ end
38
+
39
+ Dir.mktmpdir("native-gems") do |dir|
40
+ gem_paths = run.download(dir)
41
+
42
+ if gem_paths.empty?
43
+ warn "\n⚠ No .gem files found in artifacts for run #{run.id}."
44
+ warn " Native gems were not pushed to RubyGems.org.\n\n"
45
+ else
46
+ verify_versions!(gem_paths)
47
+ push(gem_paths)
48
+ end
49
+ end
50
+ end
51
+
52
+ private def verify_versions!(gem_paths)
53
+ expected = Gem::Version.new(version).to_s
54
+ mismatched = gem_paths.reject { |path| File.basename(path).include?(expected) }
55
+ return if mismatched.empty?
56
+
57
+ names = mismatched.map { |path| " - #{File.basename(path)}" }.join("\n")
58
+ abort "Fatal: Version mismatch in downloaded artifacts!\n" \
59
+ "Expected version #{expected} but found:\n#{names}"
60
+ end
61
+
62
+ private def push(gem_paths)
63
+ gem_paths.each do |gem_path|
64
+ name = File.basename(gem_path)
65
+ puts "Pushing #{name} to RubyGems.org..."
66
+ system("gem", "push", gem_path, exception: true)
67
+ end
68
+ puts "\n✓ Pushed #{gem_paths.size} native gem#{'s' if gem_paths.size != 1} to RubyGems.org."
69
+ end
70
+ end
@@ -0,0 +1,63 @@
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 "rubygems"
9
+ require "rubygems/package"
10
+ require "fileutils"
11
+
12
+ require_relative "versioned_binary"
13
+
14
+ # A platform-specific gem assembled from pre-compiled versioned binaries.
15
+ #
16
+ # CI builds produce one compiled binary per Ruby version per OS.
17
+ # A PlatformGem collects those binaries and packages them into a single
18
+ # installable gem that serves all supported Ruby versions.
19
+ class PlatformGem
20
+ # Loads the gemspec and scans for compiled binaries.
21
+ def initialize(
22
+ spec = Gem::Specification.load(RatatuiRuby::Devtools.gemspec_file),
23
+ lib_dir = "lib/#{RatatuiRuby::Devtools.gem_name.tr('-', '_')}"
24
+ )
25
+ @spec = spec
26
+ @lib_dir = lib_dir
27
+ @binaries = VersionedBinary.scan(lib_dir, RatatuiRuby::Devtools.gem_name)
28
+ end
29
+
30
+ # Packages the platform gem into +pkg/+.
31
+ def build
32
+ abort "No versioned binaries found in #{@lib_dir}/*/" if @binaries.empty?
33
+
34
+ @spec.platform = Gem::Platform.local
35
+ @spec.extensions.clear
36
+ @spec.files += @binaries.map(&:path)
37
+
38
+ #--
39
+ # SPDX-SnippetBegin
40
+ # SPDX-SnippetCopyrightText: rake-compiler contributors
41
+ # SPDX-License-Identifier: MIT
42
+ #
43
+ # Version constraint pattern derived from rake-compiler's
44
+ # ExtensionTask#define_native_tasks (lib/rake/extensiontask.rb).
45
+ #++
46
+ @spec.required_ruby_version = [
47
+ ">= #{@binaries.first.api_version}",
48
+ "< #{@binaries.last.api_version.succ}.dev",
49
+ ]
50
+ #--
51
+ # SPDX-SnippetEnd
52
+ #++
53
+
54
+ FileUtils.mkdir_p("pkg")
55
+ gem_file = Gem::Package.build(@spec)
56
+ FileUtils.mv(gem_file, "pkg")
57
+ puts "Built pkg/#{File.basename(gem_file)}"
58
+ end
59
+ end
60
+
61
+ if $PROGRAM_NAME == __FILE__
62
+ PlatformGem.new.build
63
+ end
@@ -0,0 +1,36 @@
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_relative "../bump/sem_ver"
9
+
10
+ # A compiled native extension binary for a specific Ruby version.
11
+ class VersionedBinary < Data.define(:path)
12
+ ##
13
+ # Returns sorted VersionedBinary instances found under +lib_dir+.
14
+ def self.scan(lib_dir, gem_name = RatatuiRuby::Devtools.gem_name)
15
+ Dir.glob("#{lib_dir}/*/#{gem_name.tr('-', '_')}.*")
16
+ .reject { |p| p.end_with?(".rb") }
17
+ .map { |p| new(path: p) }
18
+ .sort
19
+ end
20
+
21
+ # The full Ruby version string extracted from the directory name.
22
+ def ruby_version
23
+ File.basename(File.dirname(path))
24
+ end
25
+
26
+ # The major.minor API version used for Ruby version constraints.
27
+ def api_version
28
+ semver = SemVer.parse(ruby_version)
29
+ "#{semver.major}.#{semver.minor}"
30
+ end
31
+
32
+ # Sorts by API version so the binary list is in ascending Ruby order.
33
+ def <=>(other)
34
+ api_version <=> other.api_version
35
+ end
36
+ end
@@ -0,0 +1,87 @@
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_relative "release/native_gem_version"
9
+
10
+ namespace :release do
11
+ desc "Update stable branch to match release and set as default"
12
+ task :update_stable do
13
+ # Read version to determine tag
14
+ version_file = RatatuiRuby::Devtools.version_file
15
+ version_content = File.read(version_file)
16
+ version = version_content.match(/VERSION = "(.+?)"/)[1]
17
+ tag_name = "v#{version}"
18
+
19
+ # Verify that the version file matches the actual git tag
20
+ # This prevents updating stable to the wrong version if the release failed
21
+ latest_tag = `git describe --tags --abbrev=0`.strip
22
+ if latest_tag != tag_name
23
+ abort "Fatal: Version mismatch! '#{version_file}' says #{tag_name}, but the latest git tag is #{latest_tag}."
24
+ end
25
+
26
+ # Get current stable version (if stable branch exists)
27
+ stable_version_str = `git show stable:#{version_file} 2>/dev/null`.match(/VERSION = "(.+?)"/)&.[](1)
28
+ if stable_version_str
29
+ stable_version = Gem::Version.new(stable_version_str)
30
+ new_version = Gem::Version.new(version)
31
+
32
+ if new_version <= stable_version
33
+ puts "Skipping stable update: #{version} is not newer than current stable #{stable_version_str}"
34
+ next
35
+ end
36
+ end
37
+
38
+ puts "Updating stable branch to point to #{tag_name}..."
39
+ # Resolve the tag to a commit hash (peel annotated tags)
40
+ # This renders a commit SHA that can be pushed to a branch head
41
+ commit_sha = `git rev-parse #{tag_name}^{}`.strip
42
+
43
+ # Update local stable branch to match
44
+ sh "git branch -f stable #{commit_sha}"
45
+
46
+ # Push the commit to remote stable branch
47
+ # Force-push because stable is reset to each release, not fast-forwarded.
48
+ sh "git push --force origin #{commit_sha}:stable"
49
+ end
50
+ end
51
+
52
+ if Rake::Task.task_defined?("release")
53
+ Rake::Task["release"].enhance do
54
+ # Replace Bundler's normalized tag with semver-style for prerelease versions.
55
+ # Bundler creates tags using normalized Gem::Version (e.g., v1.0.0.pre.beta.1).
56
+ # Semver uses hyphens (e.g., v1.0.0-beta.1). We want only the semver tag.
57
+ version_file = RatatuiRuby::Devtools.version_file
58
+ version_content = File.read(version_file)
59
+ version = version_content.match(/VERSION = "(.+?)"/)[1]
60
+
61
+ if version.include?("-")
62
+ normalized_tag = "v#{Gem::Version.new(version)}"
63
+ semver_tag = "v#{version}"
64
+
65
+ if normalized_tag != semver_tag
66
+ puts "Replacing normalized tag #{normalized_tag} with semver tag #{semver_tag}..."
67
+ # Delete the normalized tag locally and remotely
68
+ sh "git tag -d #{normalized_tag}"
69
+ sh "git push origin :refs/tags/#{normalized_tag}"
70
+ # Create the semver tag pointing to the same commit
71
+ sh "git tag #{semver_tag} HEAD"
72
+ sh "git push origin #{semver_tag}"
73
+ end
74
+ end
75
+
76
+ gem_name = RatatuiRuby::Devtools.gem_name
77
+ has_rust = File.exist?("ext/#{gem_name}/Cargo.toml") ||
78
+ File.exist?("ext/#{gem_name.tr('-', '_')}/Cargo.toml")
79
+
80
+ if has_rust
81
+ release_sha = `git rev-parse v#{version}^{}`.strip
82
+ NativeGemVersion.new(version:, sha: release_sha).release
83
+ end
84
+
85
+ Rake::Task["release:update_stable"].invoke
86
+ end
87
+ end
@@ -4,4 +4,4 @@
4
4
  - "3.2"
5
5
  - "3.3"
6
6
  - "3.4"
7
- - "4.0.0"
7
+ - "4.0"
@@ -0,0 +1,124 @@
1
+ <%# REUSE-IgnoreStart -%>
2
+ # SPDX-FileCopyrightText: <%= Time.now.year %> <%= copyright_holder %>
3
+ # SPDX-License-Identifier: <%= license %>
4
+ <%# REUSE-IgnoreEnd -%>
5
+
6
+ name: Build Gems
7
+
8
+ on:
9
+ push:
10
+ branches:
11
+ - "release/*"
12
+
13
+ jobs:
14
+ build:
15
+ name: Build (${{ matrix.os }}, Ruby ${{ matrix.ruby }})
16
+ runs-on: ${{ matrix.os }}
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ ruby: <%= rubies.map { |r| r.split(".")[0..1].join(".") }.uniq.inspect %>
21
+ os: [ubuntu-latest, macos-latest, windows-latest]
22
+ env:
23
+ CI: "true"
24
+ BINDGEN_EXTRA_CLANG_ARGS: "-include stdbool.h"
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - name: Override Ruby version in mise.toml
29
+ shell: bash
30
+ run: sed -i.bak 's/ruby = .*/ruby = "${{ matrix.ruby }}"/' mise.toml
31
+
32
+ - name: Install Ruby via RubyInstaller (Windows)
33
+ if: runner.os == 'Windows'
34
+ uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: ${{ matrix.ruby }}
37
+
38
+ - name: Configure Windows build environment
39
+ if: runner.os == 'Windows'
40
+ shell: pwsh
41
+ run: |
42
+ Add-Content -Path .mise.local.toml -Value "[settings]`ndisable_tools = [`"ruby`"]"
43
+ $msysRoot = (Join-Path $env:RI_DEVKIT "ucrt64") -replace '\\', '/'
44
+ $clangArgs = "-include stdbool.h --target=x86_64-w64-mingw32 --sysroot=$msysRoot -I$msysRoot/include"
45
+ Add-Content -Path $env:GITHUB_ENV -Value "BINDGEN_EXTRA_CLANG_ARGS=$clangArgs"
46
+ Add-Content -Path $env:GITHUB_ENV -Value "CARGO_BUILD_TARGET=x86_64-pc-windows-gnu"
47
+ rustup target add x86_64-pc-windows-gnu
48
+
49
+ - name: Install toolchain via mise
50
+ uses: jdx/mise-action@v2
51
+
52
+ - name: Setup (Unix)
53
+ if: runner.os != 'Windows'
54
+ shell: bash
55
+ run: bin/setup
56
+
57
+ - name: Setup (Windows)
58
+ if: runner.os == 'Windows'
59
+ shell: pwsh
60
+ run: bin/setup.ps1
61
+
62
+ - name: Default task
63
+ run: mise x -- bundle exec rake
64
+
65
+ - name: Upload compiled binary
66
+ uses: actions/upload-artifact@v4
67
+ with:
68
+ name: native-${{ matrix.os }}-ruby${{ matrix.ruby }}
69
+ path: lib/<%= ext_name %>/<%= ext_name %>.*
70
+ if-no-files-found: error
71
+
72
+ package:
73
+ name: Package (${{ matrix.os }})
74
+ needs: build
75
+ runs-on: ${{ matrix.os }}
76
+ strategy:
77
+ fail-fast: false
78
+ matrix:
79
+ os: [ubuntu-latest, macos-latest, windows-latest]
80
+ steps:
81
+ - uses: actions/checkout@v4
82
+
83
+ - name: Install Ruby via RubyInstaller (Windows)
84
+ if: runner.os == 'Windows'
85
+ uses: ruby/setup-ruby@v1
86
+ with:
87
+ ruby-version: "3.4"
88
+
89
+ - name: Override Ruby version in mise.toml (Unix)
90
+ if: runner.os != 'Windows'
91
+ shell: bash
92
+ run: sed -i.bak 's/ruby = .*/ruby = "3.4"/' mise.toml
93
+
94
+ - name: Install toolchain via mise (Unix)
95
+ if: runner.os != 'Windows'
96
+ uses: jdx/mise-action@v2
97
+
98
+ - name: Configure Windows mise (skip Ruby)
99
+ if: runner.os == 'Windows'
100
+ shell: pwsh
101
+ run: |
102
+ Add-Content -Path .mise.local.toml -Value "[settings]`ndisable_tools = [`"ruby`"]"
103
+
104
+ - name: Install toolchain via mise (Windows)
105
+ if: runner.os == 'Windows'
106
+ uses: jdx/mise-action@v2
107
+
108
+ <%- rubies.map { |r| r.split(".")[0..1].join(".") }.uniq.each do |minor| -%>
109
+ - name: Download Ruby <%= minor %> binary
110
+ uses: actions/download-artifact@v4
111
+ with:
112
+ name: native-${{ matrix.os }}-ruby<%= minor %>
113
+ path: lib/<%= ext_name %>/<%= minor %>
114
+
115
+ <%- end -%>
116
+ - name: Build platform gem
117
+ run: ruby tasks/release/platform_gem.rb
118
+
119
+ - name: Upload gem artifact
120
+ uses: actions/upload-artifact@v4
121
+ with:
122
+ name: gem-${{ matrix.os }}
123
+ path: pkg/*.gem
124
+ if-no-files-found: error
@@ -0,0 +1,77 @@
1
+ <%# REUSE-IgnoreStart -%>
2
+ # SPDX-FileCopyrightText: <%= Time.now.year %> <%= copyright_holder %>
3
+ # SPDX-License-Identifier: <%= license %>
4
+ <%# REUSE-IgnoreEnd -%>
5
+
6
+ name: CI
7
+
8
+ on:
9
+ push:
10
+ <%- if has_rust -%>
11
+ branches-ignore:
12
+ - "release/*"
13
+ <%- end -%>
14
+ pull_request:
15
+
16
+ jobs:
17
+ test:
18
+ name: Test (Ruby ${{ matrix.ruby }}, ${{ matrix.os }})
19
+ runs-on: ${{ matrix.os }}
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ ruby: <%= rubies.inspect %>
24
+ os: [ubuntu-latest, macos-latest, windows-latest]
25
+ env:
26
+ CI: "true"
27
+ <%- if has_rust -%>
28
+ BINDGEN_EXTRA_CLANG_ARGS: "-include stdbool.h"
29
+ <%- end -%>
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+
33
+ - name: Override Ruby version in mise.toml
34
+ shell: bash
35
+ run: sed -i.bak 's/ruby = .*/ruby = "${{ matrix.ruby }}"/' mise.toml
36
+
37
+ - name: Install Ruby via RubyInstaller (Windows)
38
+ if: runner.os == 'Windows'
39
+ uses: ruby/setup-ruby@v1
40
+ with:
41
+ ruby-version: ${{ matrix.ruby }}
42
+
43
+ <%- if has_rust -%>
44
+ - name: Configure Windows build environment
45
+ if: runner.os == 'Windows'
46
+ shell: pwsh
47
+ run: |
48
+ Add-Content -Path .mise.local.toml -Value "[settings]`ndisable_tools = [`"ruby`"]"
49
+ $msysRoot = (Join-Path $env:RI_DEVKIT "ucrt64") -replace '\\', '/'
50
+ $clangArgs = "-include stdbool.h --target=x86_64-w64-mingw32 --sysroot=$msysRoot -I$msysRoot/include"
51
+ Add-Content -Path $env:GITHUB_ENV -Value "BINDGEN_EXTRA_CLANG_ARGS=$clangArgs"
52
+ Add-Content -Path $env:GITHUB_ENV -Value "CARGO_BUILD_TARGET=x86_64-pc-windows-gnu"
53
+ rustup target add x86_64-pc-windows-gnu
54
+
55
+ <%- else -%>
56
+ - name: Configure Windows Ruby (non-mise)
57
+ if: runner.os == 'Windows'
58
+ shell: pwsh
59
+ run: |
60
+ Add-Content -Path .mise.local.toml -Value "[settings]`ndisable_tools = [`"ruby`"]"
61
+
62
+ <%- end -%>
63
+ - name: Install toolchain via mise
64
+ uses: jdx/mise-action@v2
65
+
66
+ - name: Setup (Unix)
67
+ if: runner.os != 'Windows'
68
+ shell: bash
69
+ run: bin/setup
70
+
71
+ - name: Setup (Windows)
72
+ if: runner.os == 'Windows'
73
+ shell: pwsh
74
+ run: bin/setup.ps1
75
+
76
+ - name: Default task
77
+ run: mise x -- bundle exec rake
@@ -3,6 +3,7 @@
3
3
 
4
4
  **/.idea/
5
5
  **/.DS_Store
6
+ .mise.local.toml
6
7
  /.bundle/
7
8
  /.yardoc/
8
9
  /_yardoc/
@@ -10,6 +11,7 @@
10
11
  /pkg/
11
12
  /spec/reports/
12
13
  /tmp/
14
+ /www/
13
15
  <%- if has_rust -%>
14
16
  /ext/<%= gem_name %>/target/
15
17
  *.bundle
@@ -1,8 +1,10 @@
1
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
1
+ <%# REUSE-IgnoreStart -%>
2
+ # SPDX-FileCopyrightText: <%= Time.now.year %> <%= copyright_holder %>
3
+ # SPDX-License-Identifier: <%= license %>
4
+ <%# REUSE-IgnoreEnd -%>
3
5
 
4
- inherit_from:
5
- - ./vendor/goodcop/base.yml
6
+ inherit_gem:
7
+ <%= gem_name %>: lib/<%= require_path %>/rubocop.yml
6
8
 
7
9
  AllCops:
8
10
  TargetRubyVersion: "3.2"