Commit fed399c4 authored by Andreas Brandl's avatar Andreas Brandl

Merge branch '51759-filter-by-language' into 'master'

Add programming language filtering to `/projects`

Closes #51759

See merge request gitlab-org/gitlab-ce!24377
parents 6b0b14f8 b421bd31
...@@ -3,4 +3,10 @@ ...@@ -3,4 +3,10 @@
class ProgrammingLanguage < ActiveRecord::Base class ProgrammingLanguage < ActiveRecord::Base
validates :name, presence: true validates :name, presence: true
validates :color, allow_blank: false, color: true validates :color, allow_blank: false, color: true
# Returns all programming languages which match the given name (case
# insensitively).
scope :with_name_case_insensitive, ->(name) do
where(arel_table[:name].matches(sanitize_sql_like(name)))
end
end end
...@@ -389,6 +389,16 @@ class Project < ActiveRecord::Base ...@@ -389,6 +389,16 @@ class Project < ActiveRecord::Base
with_project_feature.where(project_features: { access_level_attribute => level }) with_project_feature.where(project_features: { access_level_attribute => level })
} }
# Picks projects which use the given programming language
scope :with_programming_language, ->(language_name) do
lang_id_query = ProgrammingLanguage
.with_name_case_insensitive(language_name)
.select(:id)
joins(:repository_languages)
.where(repository_languages: { programming_language_id: lang_id_query })
end
scope :with_builds_enabled, -> { with_feature_enabled(:builds) } scope :with_builds_enabled, -> { with_feature_enabled(:builds) }
scope :with_issues_enabled, -> { with_feature_enabled(:issues) } scope :with_issues_enabled, -> { with_feature_enabled(:issues) }
scope :with_issues_available_for_user, ->(current_user) { with_feature_available_for_user(:issues, current_user) } scope :with_issues_available_for_user, ->(current_user) { with_feature_available_for_user(:issues, current_user) }
......
---
title: Add `with_programming_language` filter for projects to API
merge_request: 24377
author: Dylan MacKenzie
type: added
...@@ -54,6 +54,7 @@ GET /projects ...@@ -54,6 +54,7 @@ GET /projects
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) | | `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
| `with_issues_enabled` | boolean | no | Limit by enabled issues feature | | `with_issues_enabled` | boolean | no | Limit by enabled issues feature |
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature | | `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
| `with_programming_language` | string | no | Limit by projects which use the given programming language |
| `wiki_checksum_failed` | boolean | no | Limit projects where the wiki checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ | | `wiki_checksum_failed` | boolean | no | Limit projects where the wiki checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ |
| `repository_checksum_failed` | boolean | no | Limit projects where the repository checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ | | `repository_checksum_failed` | boolean | no | Limit projects where the repository checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ |
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) | | `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
...@@ -279,6 +280,7 @@ GET /users/:user_id/projects ...@@ -279,6 +280,7 @@ GET /users/:user_id/projects
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) | | `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
| `with_issues_enabled` | boolean | no | Limit by enabled issues feature | | `with_issues_enabled` | boolean | no | Limit by enabled issues feature |
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature | | `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
| `with_programming_language` | string | no | Limit by projects which use the given programming language |
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) | | `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
```json ```json
......
...@@ -25,6 +25,9 @@ module API ...@@ -25,6 +25,9 @@ module API
projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled] projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled]
projects = projects.with_statistics if params[:statistics] projects = projects.with_statistics if params[:statistics]
lang = params[:with_programming_language]
projects = projects.with_programming_language(lang) if lang
projects projects
end end
...@@ -91,6 +94,7 @@ module API ...@@ -91,6 +94,7 @@ module API
optional :membership, type: Boolean, default: false, desc: 'Limit by projects that the current user is a member of' optional :membership, type: Boolean, default: false, desc: 'Limit by projects that the current user is a member of'
optional :with_issues_enabled, type: Boolean, default: false, desc: 'Limit by enabled issues feature' optional :with_issues_enabled, type: Boolean, default: false, desc: 'Limit by enabled issues feature'
optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature' optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature'
optional :with_programming_language, type: String, desc: 'Limit to repositories which use the given programming language'
optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user' optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user'
use :optional_filter_params_ee use :optional_filter_params_ee
......
...@@ -49,6 +49,27 @@ describe API::Projects do ...@@ -49,6 +49,27 @@ describe API::Projects do
namespace: user4.namespace) namespace: user4.namespace)
end end
shared_context 'with language detection' do
let(:ruby) { create(:programming_language, name: 'Ruby') }
let(:javascript) { create(:programming_language, name: 'JavaScript') }
let(:html) { create(:programming_language, name: 'HTML') }
let(:mock_repo_languages) do
{
project => { ruby => 0.5, html => 0.5 },
project3 => { html => 0.7, javascript => 0.3 }
}
end
before do
mock_repo_languages.each do |proj, lang_shares|
lang_shares.each do |lang, share|
create(:repository_language, project: proj, programming_language: lang, share: share)
end
end
end
end
describe 'GET /projects' do describe 'GET /projects' do
shared_examples_for 'projects response' do shared_examples_for 'projects response' do
it 'returns an array of projects' do it 'returns an array of projects' do
...@@ -344,6 +365,19 @@ describe API::Projects do ...@@ -344,6 +365,19 @@ describe API::Projects do
end end
end end
context 'and using the programming language filter' do
include_context 'with language detection'
it 'filters case-insensitively by programming language' do
get api('/projects', user), params: { with_programming_language: 'javascript' }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |p| p['id'] }).to contain_exactly(project3.id)
end
end
context 'and using sorting' do context 'and using sorting' do
it 'returns the correct order when sorted by id' do it 'returns the correct order when sorted by id' do
get api('/projects', user), params: { order_by: 'id', sort: 'desc' } get api('/projects', user), params: { order_by: 'id', sort: 'desc' }
...@@ -755,6 +789,19 @@ describe API::Projects do ...@@ -755,6 +789,19 @@ describe API::Projects do
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(private_project1.id) expect(json_response.map { |project| project['id'] }).to contain_exactly(private_project1.id)
end end
context 'and using the programming language filter' do
include_context 'with language detection'
it 'filters case-insensitively by programming language' do
get api('/projects', user), params: { with_programming_language: 'ruby' }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |p| p['id'] }).to contain_exactly(project.id)
end
end
end end
describe 'POST /projects/user/:id' do describe 'POST /projects/user/:id' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment