Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions detect/detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,129 @@ func TestRubyTools(t *testing.T) {
assertToolDetected(t, r, "lint", "RuboCop")
}

func TestRubyAndBEAMRustIntegrations(t *testing.T) {
t.Run("projects", func(t *testing.T) {
ruby := runOn(t, "../testdata/ruby-rust-project")
assertToolDetectedWithConfidence(t, ruby, "native_extension", "rb-sys", brief.ConfidenceHigh)
assertToolDetectedWithConfidence(t, ruby, "library", "Magnus", brief.ConfidenceHigh)
assertToolDetected(t, ruby, "native_extension", "mkmf")

elixir := runOn(t, "../testdata/rustler-project")
assertToolDetectedWithConfidence(t, elixir, "native_extension", "Rustler", brief.ConfidenceHigh)
})

t.Run("signals", func(t *testing.T) {
tests := []struct {
name string
files map[string]string
category string
tool string
}{
{
name: "rb-sys Ruby dependency",
files: map[string]string{
"Gemfile": "source \"https://rubygems.org\"\ngem \"rb_sys\"\n",
},
category: "native_extension",
tool: "rb-sys",
},
{
name: "rb-sys Cargo dependency",
files: map[string]string{
"Gemfile": "source \"https://rubygems.org\"\n",
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[dependencies.rb-sys]\nversion = \"0.9\"\n",
},
category: "native_extension",
tool: "rb-sys",
},
{
name: "Magnus Cargo dependency",
files: map[string]string{
"Gemfile": "source \"https://rubygems.org\"\n",
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[dependencies]\nmagnus = \"0.8\"\n",
},
category: "library",
tool: "Magnus",
},
{
name: "Rustler Mix dependency",
files: map[string]string{
"mix.exs": "defmodule Example.MixProject do\n use Mix.Project\n def project, do: [deps: [{:rustler, \"~> 0.38\"}]]\nend\n",
},
category: "native_extension",
tool: "Rustler",
},
{
name: "Rustler Cargo dependency",
files: map[string]string{
"mix.exs": "defmodule Example.MixProject do\n use Mix.Project\n def project, do: [deps: []]\nend\n",
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[dependencies.rustler]\nversion = \"0.38\"\n",
},
category: "native_extension",
tool: "Rustler",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir()
for path, content := range tt.files {
writeProjectFile(t, dir, path, content)
}
assertToolDetectedWithConfidence(t, runOn(t, dir), tt.category, tt.tool, brief.ConfidenceHigh)
})
}
})

t.Run("plain extconf", func(t *testing.T) {
dir := t.TempDir()
writeProjectFile(t, dir, "Gemfile", "source \"https://rubygems.org\"\n")
writeProjectFile(t, dir, "ext/example/extconf.rb", "require \"mkmf\"\ncreate_makefile(\"example\")\n")
writeProjectFile(
t,
dir,
"Cargo.toml",
"[package]\nname = \"near-miss\"\nversion = \"0.1.0\"\n[dependencies]\nother-rb-sys = \"1\"\nsuper-magnus = \"1\"\n",
)

r := runOn(t, dir)
assertToolDetected(t, r, "native_extension", "mkmf")
if slices.ContainsFunc(r.Tools["native_extension"], func(d brief.Detection) bool {
return d.Name == "rb-sys"
}) {
t.Error("plain extconf.rb should not detect rb-sys")
}
if slices.ContainsFunc(r.Tools["library"], func(d brief.Detection) bool {
return d.Name == "Magnus"
}) {
t.Error("plain extconf.rb should not detect Magnus")
}
})

t.Run("plain Mix project", func(t *testing.T) {
dir := t.TempDir()
writeProjectFile(
t,
dir,
"mix.exs",
"defmodule Example.MixProject do\n use Mix.Project\n def project, do: [deps: []]\nend\n",
)
writeProjectFile(
t,
dir,
"README.md",
"Rustler can be added later if this project needs a native extension.\n",
)

r := runOn(t, dir)
if slices.ContainsFunc(r.Tools["native_extension"], func(d brief.Detection) bool {
return d.Name == "Rustler"
}) {
t.Error("plain Mix project should not detect Rustler")
}
})
}

func TestRubyTaxonomyPassesThrough(t *testing.T) {
r := rubyReport(t)

Expand Down
26 changes: 26 additions & 0 deletions knowledge/elixir/rustler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[tool]
name = "Rustler"
category = "native_extension"
homepage = "https://github.com/rusterlium/rustler"
docs = "https://hexdocs.pm/rustler/"
repo = "https://github.com/rusterlium/rustler"
description = "Builds safe Erlang NIFs written in Rust"

# Match the Mix package in mix.exs and the Cargo crate in Cargo.toml rather than
# relying on the global dependency cache shared by all manifest ecosystems.
[detect]
ecosystems = ["elixir"]

[detect.file_contains]
"mix.exs" = ["{:rustler,"]
"Cargo.toml" = ["\nrustler =", "\nrustler=", "[dependencies.rustler]"]

[commands]
run = "mix compile"
alternatives = ["mix compile --force"]

[config]
files = ["mix.exs", "Cargo.toml", "native/**/Cargo.toml"]

[taxonomy]
role = ["native-extension"]
21 changes: 21 additions & 0 deletions knowledge/ruby/magnus.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[tool]
name = "Magnus"
category = "library"
homepage = "https://github.com/matsadler/magnus"
docs = "https://docs.rs/magnus/"
repo = "https://github.com/matsadler/magnus"
description = "Rust bindings for the Ruby API"

# Match the Cargo crate in Cargo.toml rather than through the global dependency
# cache so a same-named dependency from another ecosystem does not trigger it.
[detect]
ecosystems = ["ruby"]

[detect.file_contains]
"Cargo.toml" = ["\nmagnus =", "\nmagnus=", "[dependencies.magnus]"]

[config]
files = ["Cargo.toml"]

[taxonomy]
role = ["library"]
26 changes: 26 additions & 0 deletions knowledge/ruby/rb-sys.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[tool]
name = "rb-sys"
category = "native_extension"
homepage = "https://oxidize-rb.github.io/rb-sys/"
docs = "https://oxidize-rb.github.io/rb-sys/"
repo = "https://github.com/oxidize-rb/rb-sys"
description = "Builds Ruby native extensions written in Rust"

# Match the Cargo crate in Cargo.toml rather than through the global dependency
# cache so a same-named dependency from another ecosystem does not trigger it.
[detect]
dependencies = ["rb_sys"]
ecosystems = ["ruby"]

[detect.file_contains]
"Cargo.toml" = ["\nrb-sys =", "\nrb-sys=", "[dependencies.rb-sys]"]

[commands]
run = "bundle exec rake compile"
alternatives = ["rake compile"]

[config]
files = ["Gemfile", "Cargo.toml", "extconf.rb", "ext/**/extconf.rb"]

[taxonomy]
role = ["native-extension"]
11 changes: 11 additions & 0 deletions testdata/ruby-rust-project/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "ruby-rust-project"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
magnus = "0.8"
rb-sys = "0.9"
3 changes: 3 additions & 0 deletions testdata/ruby-rust-project/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source "https://rubygems.org"

gem "rb_sys"
4 changes: 4 additions & 0 deletions testdata/ruby-rust-project/ext/ruby_rust_project/extconf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "mkmf"
require "rb_sys/mkmf"

create_rust_makefile("ruby_rust_project/ruby_rust_project")
1 change: 1 addition & 0 deletions testdata/ruby-rust-project/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn fixture() {}
21 changes: 21 additions & 0 deletions testdata/rustler-project/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule RustlerProject.MixProject do
use Mix.Project

def project do
[
app: :rustler_project,
version: "0.1.0",
deps: deps()
]
end

def application do
[extra_applications: [:logger]]
end

defp deps do
[
{:rustler, "~> 0.38"}
]
end
end
10 changes: 10 additions & 0 deletions testdata/rustler-project/native/rustler_project/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "rustler_project"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
rustler = "0.38"
1 change: 1 addition & 0 deletions testdata/rustler-project/native/rustler_project/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn fixture() {}