summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Brandl <abrandl@gitlab.com>2019-02-04 15:06:17 +0000
committerAndreas Brandl <abrandl@gitlab.com>2019-02-04 15:06:17 +0000
commitfed399c4798fb8a42dea8e69117829700957f398 (patch)
tree3ba0bc3c4c9a6a8cf210e485a80d927bd037494f
parent6b0b14f81d6def6d74b303cd27fef6f98aaabfd0 (diff)
parentb421bd316fb2e79cbf82fdc21220e23a6f564311 (diff)
downloadgitlab-ce-fed399c4798fb8a42dea8e69117829700957f398.tar.gz
Merge branch '51759-filter-by-language' into 'master'
Add programming language filtering to `/projects` Closes #51759 See merge request gitlab-org/gitlab-ce!24377
-rw-r--r--app/models/programming_language.rb6
-rw-r--r--app/models/project.rb10
-rw-r--r--changelogs/unreleased/51759-filter-by-language.yml5
-rw-r--r--doc/api/projects.md2
-rw-r--r--lib/api/projects.rb4
-rw-r--r--spec/requests/api/projects_spec.rb47
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