Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
15 changes: 14 additions & 1 deletion lib/linguist/lazy_blob.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,20 @@ def language
return @language if defined?(@language)

@language = if lang = git_attributes['linguist-language']
Language.find_by_alias(lang)
detected_language = Language.find_by_alias(lang)

# If strategies are being tracked, get the overridden strategy that would have been used with a note that it was overridden
if detected_language && Linguist.instrumenter
# Get the overridden strategy by calling super (which calls Linguist.detect)
super
overridden_strategy_info = Linguist.instrumenter.detected_info[self.name]
overridden_strategy = overridden_strategy_info ? overridden_strategy_info[:strategy] : "Unknown"

strategy_name = "#{overridden_strategy} (overridden by .gitattributes)"
strategy = Struct.new(:name).new(strategy_name)
Linguist.instrument("linguist.detected", blob: self, strategy: strategy, language: detected_language)
end
detected_language
else
super
end
Expand Down
21 changes: 21 additions & 0 deletions test/test_basic_instrumenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,25 @@ def test_tracks_filename_strategy
assert_equal "Filename", @instrumenter.detected_info[blob.name][:strategy]
assert_equal "Dockerfile", @instrumenter.detected_info[blob.name][:language]
end

def test_tracks_override_strategy
# Simulate a blob with a gitattributes override
blob = Linguist::FileBlob.new("Gemfile", "")
# Simulate detection with gitattributes strategy showing the override
strategy = Struct.new(:name).new("Filename (overridden by .gitattributes)")
language = Struct.new(:name).new("Java")
@instrumenter.instrument("linguist.detected", blob: blob, strategy: strategy, language: language) {}
assert @instrumenter.detected_info.key?(blob.name)
assert_match(/overridden by \.gitattributes/, @instrumenter.detected_info[blob.name][:strategy])
assert_equal "Java", @instrumenter.detected_info[blob.name][:language]
end
end

def test_override_strategy_is_recorded
# This file is overridden by .gitattributes to be detectable and language Markdown
blob = sample_blob("Markdown/tender.md")
Linguist.detect(blob)
assert @instrumenter.detected_info.key?(blob.name)
assert_includes ["GitAttributes"], @instrumenter.detected_info[blob.name][:strategy]
assert_equal "Markdown", @instrumenter.detected_info[blob.name][:language]
end
139 changes: 139 additions & 0 deletions test/test_cli_integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
require_relative "./helper"
require 'tmpdir'
require 'fileutils'
require 'open3'

class TestCLIIntegration < Minitest::Test
def setup
@temp_dir = Dir.mktmpdir('linguist_cli_test')
@original_dir = Dir.pwd
Dir.chdir(@temp_dir)

# Initialize a git repository
system("git init --quiet")
system("git config user.name 'Test User'")
system("git config user.email '[email protected]'")
end

def teardown
Dir.chdir(@original_dir)
FileUtils.rm_rf(@temp_dir)
end

def test_strategies_flag_with_gitattributes_override
# Create a .gitattributes file that overrides language detection
File.write('.gitattributes', "*.special linguist-language=Ruby\n")

# Create a test file with a non-Ruby extension but Ruby content
File.write('test.special', "puts 'Hello, World!'\n")

# Stage and commit the files
system("git add .")
system("git commit -m 'Initial commit' --quiet")

# Run github-linguist with --strategies flag from the original directory but pointing to our test file
stdout, stderr, status = Open3.capture3(
"bundle", "exec", "github-linguist", File.join(@temp_dir, "test.special"), "--strategies",
chdir: @original_dir
)

assert status.success?, "CLI command failed: #{stderr}"
assert_match(/language:\s+Ruby/, stdout, "Should detect Ruby language")
assert_match(/strategy:\s+.*\(overridden by \.gitattributes\)/, stdout, "Should show override in strategy")
end

def test_strategies_flag_with_normal_detection
# Create a normal Ruby file
File.write('test.rb', "puts 'Hello, World!'\n")

# Stage and commit the file
system("git add .")
system("git commit -m 'Initial commit' --quiet")

# Run github-linguist with --strategies flag
stdout, stderr, status = Open3.capture3(
"bundle", "exec", "github-linguist", File.join(@temp_dir, "test.rb"), "--strategies",
chdir: @original_dir
)

assert status.success?, "CLI command failed: #{stderr}"
assert_match(/language:\s+Ruby/, stdout, "Should detect Ruby language")
assert_match(/strategy:\s+Extension/, stdout, "Should show Extension strategy")
end

def test_breakdown_with_gitattributes_strategies
# Create multiple files with different detection methods
File.write('.gitattributes', "*.special linguist-language=JavaScript\n")
File.write('override.special', "console.log('overridden');\n")
File.write('normal.js', "console.log('normal');\n")
File.write('Dockerfile', "FROM ubuntu\n")

# Stage and commit the files
system("git add .")
system("git commit -m 'Initial commit' --quiet")

# Run github-linguist with --breakdown --strategies flags on the test repository
stdout, stderr, status = Open3.capture3(
"bundle", "exec", "github-linguist", @temp_dir, "--breakdown", "--strategies",
chdir: @original_dir
)

assert status.success?, "CLI command failed: #{stderr}"

# Check that GitAttributes strategy appears for the overridden file
assert_match(/override\.special \[.* \(overridden by \.gitattributes\)\]/, stdout, "Should show override for overridden file")

# Check that normal detection strategies appear for other files
assert_match(/normal\.js \[Extension\]/, stdout, "Should show Extension strategy for .js file")
assert_match(/Dockerfile \[Filename\]/, stdout, "Should show Filename strategy for Dockerfile")
end

def test_json_output_preserves_functionality
# Create a simple test file
File.write('test.rb', "puts 'Hello, World!'\n")

# Stage and commit the file
system("git add .")
system("git commit -m 'Initial commit' --quiet")

# Run github-linguist with --json flag
stdout, stderr, status = Open3.capture3(
"bundle", "exec", "github-linguist", File.join(@temp_dir, "test.rb"), "--json",
chdir: @original_dir
)

assert status.success?, "CLI command failed: #{stderr}"

# Parse JSON output
require 'json'
result = JSON.parse(stdout)

test_file_key = File.join(@temp_dir, "test.rb")
assert_equal "Ruby", result[test_file_key]["language"], "JSON output should contain correct language"
assert_equal "Text", result[test_file_key]["type"], "JSON output should contain correct type"
end

def test_repository_scan_with_gitattributes
# Create a more complex repository structure
FileUtils.mkdir_p('src')
File.write('.gitattributes', "*.config linguist-language=JavaScript\n")
File.write('src/app.rb', "class App\nend\n")
File.write('config.config', "var x = 1;\n")

# Stage and commit the files
system("git add .")
system("git commit -m 'Initial commit' --quiet")

# Run github-linguist on the test repository
stdout, stderr, status = Open3.capture3(
"bundle", "exec", "github-linguist", @temp_dir, "--breakdown", "--strategies",
chdir: @original_dir
)

assert status.success?, "CLI command failed: #{stderr}"

# Verify that both normal and override detection work in repository scan
assert_match(/src\/app\.rb \[Extension\]/, stdout, "Should show Extension strategy for Ruby file")
assert_match(/config\.config \[.* \(overridden by \.gitattributes\)\]/, stdout, "Should show override for overridden file")
end
end