stackharbinger 0.4.0 → 1.0.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 +110 -34
- data/docs/index.html +64 -21
- data/lib/harbinger/analyzers/go_detector.rb +86 -0
- data/lib/harbinger/analyzers/node_detector.rb +109 -0
- data/lib/harbinger/analyzers/python_detector.rb +110 -0
- data/lib/harbinger/analyzers/rails_analyzer.rb +5 -1
- data/lib/harbinger/analyzers/rust_detector.rb +116 -0
- data/lib/harbinger/cli.rb +365 -252
- data/lib/harbinger/exporters/base_exporter.rb +5 -2
- data/lib/harbinger/version.rb +1 -1
- metadata +7 -6
|
@@ -31,7 +31,11 @@ module Harbinger
|
|
|
31
31
|
|
|
32
32
|
content = File.read(file_path)
|
|
33
33
|
match = content.match(/^\s*rails\s+\(([^)]+)\)/)
|
|
34
|
-
|
|
34
|
+
return nil unless match
|
|
35
|
+
|
|
36
|
+
version_string = match[1]
|
|
37
|
+
# Strip version constraint operators (>=, ~>, =, etc.) and extract actual version
|
|
38
|
+
version_string.sub(/^[><=~!\s]+/, "").strip
|
|
35
39
|
rescue StandardError
|
|
36
40
|
nil
|
|
37
41
|
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "docker_compose_detector"
|
|
4
|
+
|
|
5
|
+
module Harbinger
|
|
6
|
+
module Analyzers
|
|
7
|
+
class RustDetector
|
|
8
|
+
def initialize(project_path)
|
|
9
|
+
@project_path = project_path
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def detect
|
|
13
|
+
detect_from_rust_toolchain ||
|
|
14
|
+
detect_from_cargo_toml ||
|
|
15
|
+
detect_from_docker_compose ||
|
|
16
|
+
(rust_detected? ? detect_from_shell : nil)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def rust_detected?
|
|
20
|
+
File.exist?(File.join(project_path, "Cargo.toml")) ||
|
|
21
|
+
File.exist?(File.join(project_path, "Cargo.lock")) ||
|
|
22
|
+
File.exist?(File.join(project_path, "rust-toolchain")) ||
|
|
23
|
+
File.exist?(File.join(project_path, "rust-toolchain.toml")) ||
|
|
24
|
+
(File.directory?(File.join(project_path, "src")) && has_rust_files?)
|
|
25
|
+
rescue StandardError
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :project_path
|
|
32
|
+
|
|
33
|
+
def detect_from_rust_toolchain
|
|
34
|
+
# Try rust-toolchain.toml first (TOML format)
|
|
35
|
+
toml_path = File.join(project_path, "rust-toolchain.toml")
|
|
36
|
+
if File.exist?(toml_path)
|
|
37
|
+
content = File.read(toml_path)
|
|
38
|
+
# Parse: channel = "1.75.0" or channel = "stable"
|
|
39
|
+
match = content.match(/channel\s*=\s*["']([^"']+)["']/)
|
|
40
|
+
if match
|
|
41
|
+
channel = match[1]
|
|
42
|
+
# Skip "stable", "beta", "nightly" - we need specific versions
|
|
43
|
+
return extract_version(channel) unless channel =~ /^(stable|beta|nightly)$/
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Try plain rust-toolchain file
|
|
48
|
+
plain_path = File.join(project_path, "rust-toolchain")
|
|
49
|
+
if File.exist?(plain_path)
|
|
50
|
+
content = File.read(plain_path).strip
|
|
51
|
+
return extract_version(content) unless content.empty? || content =~ /^(stable|beta|nightly)$/
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
nil
|
|
55
|
+
rescue StandardError
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def detect_from_cargo_toml
|
|
60
|
+
file_path = File.join(project_path, "Cargo.toml")
|
|
61
|
+
return nil unless File.exist?(file_path)
|
|
62
|
+
|
|
63
|
+
content = File.read(file_path)
|
|
64
|
+
|
|
65
|
+
# Parse: rust-version = "1.70" or rust-version = "1.70.0"
|
|
66
|
+
# This is the MSRV (Minimum Supported Rust Version)
|
|
67
|
+
match = content.match(/rust-version\s*=\s*["']([^"']+)["']/)
|
|
68
|
+
return extract_version(match[1]) if match
|
|
69
|
+
|
|
70
|
+
nil
|
|
71
|
+
rescue StandardError
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def detect_from_docker_compose
|
|
76
|
+
docker = DockerComposeDetector.new(project_path)
|
|
77
|
+
docker.image_version("rust")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def detect_from_shell
|
|
81
|
+
output = `rustc --version 2>&1`.strip
|
|
82
|
+
return nil unless $CHILD_STATUS.success?
|
|
83
|
+
|
|
84
|
+
# Parse: "rustc 1.75.0 (82e1608df 2023-12-21)"
|
|
85
|
+
match = output.match(/rustc\s+(\d+\.\d+(?:\.\d+)?)/)
|
|
86
|
+
match[1] if match
|
|
87
|
+
rescue StandardError
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def extract_version(version_string)
|
|
92
|
+
# Remove "rust-" prefix if present
|
|
93
|
+
version = version_string.sub(/^rust-/, "")
|
|
94
|
+
|
|
95
|
+
# Strip any whitespace
|
|
96
|
+
version = version.strip
|
|
97
|
+
|
|
98
|
+
# Handle version with date: "1.75.0-2023-12-21" -> "1.75.0"
|
|
99
|
+
version = version.split("-").first if version.include?("-")
|
|
100
|
+
|
|
101
|
+
# Return major.minor or major.minor.patch format
|
|
102
|
+
# endoflife.date uses "1.75" format, but "1.75.0" also works
|
|
103
|
+
version
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def has_rust_files?
|
|
107
|
+
src_dir = File.join(project_path, "src")
|
|
108
|
+
return false unless File.directory?(src_dir)
|
|
109
|
+
|
|
110
|
+
Dir.glob(File.join(src_dir, "**/*.rs")).any?
|
|
111
|
+
rescue StandardError
|
|
112
|
+
false
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|