79a5d76801
Our friends at GitHub show the programming languages for a long time, and inspired by that this commit means to create about the same functionality. Language detection is done through Linguist, as before, where the difference is that we cache the result in the database. Also, Gitaly can incrementaly scan a repository. This is done through a shell out, which creates overhead of about 3s each run. For now this won't be improved. Scans are triggered by pushed to the default branch, usually `master`. However, one exception to this rule the charts page. If we're requesting this expensive data anyway, we just cache it in the database. Edge cases where there is no repository, or its empty are caught in the Repository model. This makes use of Redis caching, which is probably already loaded. The added model is called RepositoryLanguage, which will make it harder if/when GitLab supports multiple repositories per project. However, for now I think this shouldn't be a concern. Also, Language could be confused with the i18n languages and felt like the current name was suiteable too. Design of the Project#Show page is done with help from @dimitrieh. This change is not visible to the end user unless detections are done.
85 lines
2.8 KiB
Ruby
85 lines
2.8 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe Gitlab::LanguageDetection do
|
|
set(:project) { create(:project, :repository) }
|
|
set(:ruby) { create(:programming_language, name: 'Ruby') }
|
|
set(:haskell) { create(:programming_language, name: 'Haskell') }
|
|
let(:repository) { project.repository }
|
|
let(:detection) do
|
|
[{ value: 66.63, label: "Ruby", color: "#701516", highlight: "#701516" },
|
|
{ value: 12.96, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
|
|
{ value: 7.9, label: "Elixir", color: "#e34c26", highlight: "#e34c26" },
|
|
{ value: 2.51, label: "CoffeeScript", color: "#244776", highlight: "#244776" },
|
|
{ value: 1.51, label: "Go", color: "#2a4776", highlight: "#244776" },
|
|
{ value: 1.1, label: "MepmepLang", color: "#2a4776", highlight: "#244776" }]
|
|
end
|
|
let(:repository_languages) do
|
|
[RepositoryLanguage.new(share: 10, programming_language: ruby)]
|
|
end
|
|
|
|
subject { described_class.new(repository, repository_languages) }
|
|
|
|
before do
|
|
allow(repository).to receive(:languages).and_return(detection)
|
|
end
|
|
|
|
describe '#languages' do
|
|
it 'returns the language names' do
|
|
expect(subject.languages).to eq(%w[Ruby JavaScript Elixir CoffeeScript Go])
|
|
end
|
|
end
|
|
|
|
describe '#insertions' do
|
|
let(:programming_languages) { [ruby, haskell] }
|
|
let(:detection) do
|
|
[{ value: 10, label: haskell.name, color: haskell.color }]
|
|
end
|
|
|
|
it 'only includes new languages' do
|
|
insertions = subject.insertions(programming_languages)
|
|
|
|
expect(insertions).not_to be_empty
|
|
expect(insertions.first[:project_id]).to be(project.id)
|
|
expect(insertions.first[:programming_language_id]).to be(haskell.id)
|
|
expect(insertions.first[:share]).to be(10)
|
|
end
|
|
end
|
|
|
|
describe '#updates' do
|
|
it 'updates the share of languages' do
|
|
first_update = subject.updates.first
|
|
|
|
expect(first_update).not_to be_nil
|
|
expect(first_update[:programming_language_id]).to eq(ruby.id)
|
|
expect(first_update[:share]).to eq(66.63)
|
|
end
|
|
|
|
it 'does not include languages to be removed' do
|
|
ids = subject.updates.map { |h| h[:programming_language_id] }
|
|
|
|
expect(ids).not_to include(haskell.id)
|
|
end
|
|
|
|
context 'when silent writes occur' do
|
|
let(:repository_languages) do
|
|
[RepositoryLanguage.new(share: 66.63, programming_language: ruby)]
|
|
end
|
|
|
|
it "doesn't include them in the result" do
|
|
expect(subject.updates).to be_empty
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#deletions' do
|
|
let(:repository_languages) do
|
|
[RepositoryLanguage.new(share: 10, programming_language: ruby),
|
|
RepositoryLanguage.new(share: 5, programming_language: haskell)]
|
|
end
|
|
|
|
it 'lists undetected languages' do
|
|
expect(subject.deletions).not_to be_empty
|
|
expect(subject.deletions).to include(haskell.id)
|
|
end
|
|
end
|
|
end
|