diff options
-rw-r--r-- | app/models/programming_language.rb | 6 | ||||
-rw-r--r-- | app/models/project.rb | 10 | ||||
-rw-r--r-- | changelogs/unreleased/51759-filter-by-language.yml | 5 | ||||
-rw-r--r-- | doc/api/projects.md | 2 | ||||
-rw-r--r-- | lib/api/projects.rb | 4 | ||||
-rw-r--r-- | spec/requests/api/projects_spec.rb | 47 |
6 files changed, 74 insertions, 0 deletions
diff --git a/app/models/programming_language.rb b/app/models/programming_language.rb index 0e667dac21e..5f0f313b7f9 100644 --- a/app/models/programming_language.rb +++ b/app/models/programming_language.rb @@ -3,4 +3,10 @@ class ProgrammingLanguage < ActiveRecord::Base validates :name, presence: 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 diff --git a/app/models/project.rb b/app/models/project.rb index f6218519533..d4e2ed883bc 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -389,6 +389,16 @@ class Project < ActiveRecord::Base 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_issues_enabled, -> { with_feature_enabled(:issues) } scope :with_issues_available_for_user, ->(current_user) { with_feature_available_for_user(:issues, current_user) } diff --git a/changelogs/unreleased/51759-filter-by-language.yml b/changelogs/unreleased/51759-filter-by-language.yml new file mode 100644 index 00000000000..6b5bedd6b2d --- /dev/null +++ b/changelogs/unreleased/51759-filter-by-language.yml @@ -0,0 +1,5 @@ +--- +title: Add `with_programming_language` filter for projects to API +merge_request: 24377 +author: Dylan MacKenzie +type: added diff --git a/doc/api/projects.md b/doc/api/projects.md index 1296b435792..3c0c956ddc2 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -54,6 +54,7 @@ GET /projects | `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_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)_ | | `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) | @@ -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_issues_enabled` | boolean | no | Limit by enabled issues 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) | ```json diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 3afa2d8a6b0..6a93ef9f3ad 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -25,6 +25,9 @@ module API projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled] projects = projects.with_statistics if params[:statistics] + lang = params[:with_programming_language] + projects = projects.with_programming_language(lang) if lang + projects end @@ -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 :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_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' use :optional_filter_params_ee diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 70686158b7d..cfa7a1a31a3 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -49,6 +49,27 @@ describe API::Projects do namespace: user4.namespace) 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 shared_examples_for 'projects response' do it 'returns an array of projects' do @@ -344,6 +365,19 @@ describe API::Projects do 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 it 'returns the correct order when sorted by id' do get api('/projects', user), params: { order_by: 'id', sort: 'desc' } @@ -755,6 +789,19 @@ describe API::Projects do expect(json_response).to be_an Array expect(json_response.map { |project| project['id'] }).to contain_exactly(private_project1.id) 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 describe 'POST /projects/user/:id' do |