summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/lib/utils/poll.js11
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js19
-rw-r--r--app/assets/javascripts/notes/stores/utils.js9
-rw-r--r--app/finders/groups_finder.rb16
-rw-r--r--app/finders/personal_projects_finder.rb19
-rw-r--r--app/finders/projects_finder.rb17
-rw-r--r--app/models/project.rb1
-rw-r--r--app/views/projects/services/prometheus/_show.html.haml2
-rw-r--r--changelogs/unreleased/api-minimal-access-level.yml5
-rw-r--r--changelogs/unreleased/tz-mr-refactor-memory-reduction.yml10
-rw-r--r--doc/administration/pages/index.md44
-rw-r--r--doc/api/groups.md10
-rw-r--r--doc/api/issues.md6
-rw-r--r--doc/api/projects.md9
-rw-r--r--doc/ci/yaml/README.md38
-rw-r--r--lib/api/groups.rb3
-rw-r--r--lib/api/helpers.rb1
-rw-r--r--lib/api/projects.rb1
-rw-r--r--lib/api/users.rb1
-rw-r--r--lib/gitlab/git/repository.rb4
-rw-r--r--lib/gitlab/import_export/merge_request_parser.rb1
-rw-r--r--spec/requests/api/groups_spec.rb19
-rw-r--r--spec/requests/api/projects_spec.rb30
23 files changed, 167 insertions, 109 deletions
diff --git a/app/assets/javascripts/lib/utils/poll.js b/app/assets/javascripts/lib/utils/poll.js
index 7fca80c2fdb..91d8c30744f 100644
--- a/app/assets/javascripts/lib/utils/poll.js
+++ b/app/assets/javascripts/lib/utils/poll.js
@@ -38,7 +38,7 @@ import { normalizeHeaders } from './common_utils';
* } else {
* poll.stop();
* }
-* });
+ * });
*
* 1. Checks for response and headers before start polling
* 2. Interval is provided by `Poll-Interval` header.
@@ -51,8 +51,8 @@ export default class Poll {
constructor(options = {}) {
this.options = options;
this.options.data = options.data || {};
- this.options.notificationCallback = options.notificationCallback ||
- function notificationCallback() {};
+ this.options.notificationCallback =
+ options.notificationCallback || function notificationCallback() {};
this.intervalHeader = 'POLL-INTERVAL';
this.timeoutID = null;
@@ -63,6 +63,7 @@ export default class Poll {
const headers = normalizeHeaders(response.headers);
const pollInterval = parseInt(headers[this.intervalHeader], 10);
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
+ clearTimeout(this.timeoutID);
this.timeoutID = setTimeout(() => {
this.makeRequest();
}, pollInterval);
@@ -77,11 +78,11 @@ export default class Poll {
notificationCallback(true);
return resource[method](data)
- .then((response) => {
+ .then(response => {
this.checkConditions(response);
notificationCallback(false);
})
- .catch((error) => {
+ .catch(error => {
notificationCallback(false);
if (error.status === httpStatusCodes.ABORTED) {
return;
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index ab6a95e2601..e1b159142c9 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -174,27 +174,19 @@ export default {
[types.UPDATE_NOTE](state, note) {
const noteObj = utils.findNoteObjectById(state.discussions, note.discussion_id);
-
if (noteObj.individual_note) {
noteObj.notes.splice(0, 1, note);
} else {
const comment = utils.findNoteObjectById(noteObj.notes, note.id);
- noteObj.notes.splice(noteObj.notes.indexOf(comment), 1, note);
+ Object.assign(comment, note);
}
},
[types.UPDATE_DISCUSSION](state, noteData) {
const note = noteData;
- let index = 0;
-
- state.discussions.forEach((n, i) => {
- if (n.id === note.id) {
- index = i;
- }
- });
-
+ const selectedDiscussion = state.discussions.find(n => n.id === note.id);
note.expanded = true; // override expand flag to prevent collapse
- state.discussions.splice(index, 1, note);
+ Object.assign(selectedDiscussion, note);
},
[types.CLOSE_ISSUE](state) {
@@ -215,12 +207,9 @@ export default {
[types.SET_DISCUSSION_DIFF_LINES](state, { discussionId, diffLines }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
- const index = state.discussions.indexOf(discussion);
- const discussionWithDiffLines = Object.assign({}, discussion, {
+ Object.assign(discussion, {
truncated_diff_lines: diffLines,
});
-
- state.discussions.splice(index, 1, discussionWithDiffLines);
},
};
diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js
index a0e096ebfaf..c4a812c5af4 100644
--- a/app/assets/javascripts/notes/stores/utils.js
+++ b/app/assets/javascripts/notes/stores/utils.js
@@ -2,13 +2,11 @@ import AjaxCache from '~/lib/utils/ajax_cache';
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
-export const findNoteObjectById = (notes, id) =>
- notes.filter(n => n.id === id)[0];
+export const findNoteObjectById = (notes, id) => notes.find(n => n.id === id);
export const getQuickActionText = note => {
let text = 'Applying command';
- const quickActions =
- AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || [];
+ const quickActions = AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || [];
const executedCommands = quickActions.filter(command => {
const commandRegex = new RegExp(`/${command.name}`);
@@ -29,5 +27,4 @@ export const getQuickActionText = note => {
export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note);
-export const stripQuickActions = note =>
- note.replace(REGEX_QUICK_ACTIONS, '').trim();
+export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim();
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index 0754123a3cf..0eeba1d2428 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -8,6 +8,7 @@
# owned: boolean
# parent: Group
# all_available: boolean (defaults to true)
+# min_access_level: integer
#
# Users with full private access can see all groups. The `owned` and `parent`
# params can be used to restrict the groups that are returned.
@@ -39,6 +40,7 @@ class GroupsFinder < UnionFinder
def all_groups
return [owned_groups] if params[:owned]
+ return [groups_with_min_access_level] if min_access_level?
return [Group.all] if current_user&.full_private_access? && all_available?
groups = []
@@ -56,6 +58,16 @@ class GroupsFinder < UnionFinder
current_user.groups
end
+ def groups_with_min_access_level
+ groups = current_user
+ .groups
+ .where('members.access_level >= ?', params[:min_access_level])
+
+ Gitlab::GroupHierarchy
+ .new(groups)
+ .base_and_descendants
+ end
+
def by_parent(groups)
return groups unless params[:parent]
@@ -73,4 +85,8 @@ class GroupsFinder < UnionFinder
def all_available?
params.fetch(:all_available, true)
end
+
+ def min_access_level?
+ current_user && params[:min_access_level].present?
+ end
end
diff --git a/app/finders/personal_projects_finder.rb b/app/finders/personal_projects_finder.rb
index 5aea0cb8192..18adfea747f 100644
--- a/app/finders/personal_projects_finder.rb
+++ b/app/finders/personal_projects_finder.rb
@@ -1,6 +1,7 @@
class PersonalProjectsFinder < UnionFinder
- def initialize(user)
+ def initialize(user, params = {})
@user = user
+ @params = params
end
# Finds the projects belonging to the user in "@user", limited to either
@@ -8,6 +9,8 @@ class PersonalProjectsFinder < UnionFinder
#
# current_user - When given the list of projects is limited to those only
# visible by this user.
+ # params - Optional query parameters
+ # min_access_level: integer
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
@@ -19,11 +22,21 @@ class PersonalProjectsFinder < UnionFinder
private
def all_projects(current_user)
- projects = []
+ return [projects_with_min_access_level(current_user)] if current_user && min_access_level?
+ projects = []
projects << @user.personal_projects.visible_to_user(current_user) if current_user
projects << @user.personal_projects.public_to_user(current_user)
-
projects
end
+
+ def projects_with_min_access_level(current_user)
+ @user
+ .personal_projects
+ .visible_to_user_and_access_level(current_user, @params[:min_access_level])
+ end
+
+ def min_access_level?
+ @params[:min_access_level].present?
+ end
end
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index b06595081e7..cac6643eff3 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -17,6 +17,7 @@
# search: string
# non_archived: boolean
# archived: 'only' or boolean
+# min_access_level: integer
#
class ProjectsFinder < UnionFinder
include CustomAttributesFilter
@@ -34,7 +35,7 @@ class ProjectsFinder < UnionFinder
user = params.delete(:user)
collection =
if user
- PersonalProjectsFinder.new(user).execute(current_user)
+ PersonalProjectsFinder.new(user, finder_params).execute(current_user)
else
init_collection
end
@@ -65,6 +66,8 @@ class ProjectsFinder < UnionFinder
def collection_with_user
if owned_projects?
current_user.owned_projects
+ elsif min_access_level?
+ current_user.authorized_projects.where('project_authorizations.access_level >= ?', params[:min_access_level])
else
if private_only?
current_user.authorized_projects
@@ -76,7 +79,7 @@ class ProjectsFinder < UnionFinder
# Builds a collection for an anonymous user.
def collection_without_user
- if private_only? || owned_projects?
+ if private_only? || owned_projects? || min_access_level?
Project.none
else
Project.public_to_user
@@ -91,6 +94,10 @@ class ProjectsFinder < UnionFinder
params[:non_public].present?
end
+ def min_access_level?
+ params[:min_access_level].present?
+ end
+
def by_ids(items)
project_ids_relation ? items.where(id: project_ids_relation) : items
end
@@ -143,4 +150,10 @@ class ProjectsFinder < UnionFinder
projects
end
end
+
+ def finder_params
+ return {} unless min_access_level?
+
+ { min_access_level: params[:min_access_level] }
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 7d37c3b3893..f880d728839 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -327,6 +327,7 @@ class Project < ActiveRecord::Base
scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
scope :starred_by, ->(user) { joins(:users_star_projects).where('users_star_projects.user_id': user.id) }
scope :visible_to_user, ->(user) { where(id: user.authorized_projects.select(:id).reorder(nil)) }
+ scope :visible_to_user_and_access_level, ->(user, access_level) { where(id: user.authorized_projects.where('project_authorizations.access_level >= ?', access_level).select(:id).reorder(nil)) }
scope :archived, -> { where(archived: true) }
scope :non_archived, -> { where(archived: false) }
scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct }
diff --git a/app/views/projects/services/prometheus/_show.html.haml b/app/views/projects/services/prometheus/_show.html.haml
index 9741b783db3..1d0b0265bb7 100644
--- a/app/views/projects/services/prometheus/_show.html.haml
+++ b/app/views/projects/services/prometheus/_show.html.haml
@@ -7,4 +7,4 @@
= link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus_library/metrics'), target: '_blank', rel: "noopener noreferrer"
.col-lg-9
- = render_if_exists 'projects/services/prometheus/metrics', project: @project
+ = render 'projects/services/prometheus/metrics', project: @project
diff --git a/changelogs/unreleased/api-minimal-access-level.yml b/changelogs/unreleased/api-minimal-access-level.yml
new file mode 100644
index 00000000000..43cab246d69
--- /dev/null
+++ b/changelogs/unreleased/api-minimal-access-level.yml
@@ -0,0 +1,5 @@
+---
+title: Add filter for minimal access level in groups and projects API
+merge_request: 20478
+author: Marko, Peter
+type: added
diff --git a/changelogs/unreleased/tz-mr-refactor-memory-reduction.yml b/changelogs/unreleased/tz-mr-refactor-memory-reduction.yml
index 20b72c98bc1..16003fa9cad 100644
--- a/changelogs/unreleased/tz-mr-refactor-memory-reduction.yml
+++ b/changelogs/unreleased/tz-mr-refactor-memory-reduction.yml
@@ -1,5 +1,5 @@
----
-title: Reduces the client side memory footprint on merge requests
-merge_request: 20744
-author:
-type: performance
+---
+title: Reduces the client side memory footprint on merge requests
+merge_request: 20744
+author:
+type: performance
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 056cca17d62..eefa86f8e42 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -124,11 +124,6 @@ The Pages daemon doesn't listen to the outside world.
```
1. [Reconfigure GitLab][reconfigure]
-1. Restart gitlab-pages by running the following command:
-
- ```shell
- sudo gitlab-ctl restart gitlab-pages
- ```
Watch the [video tutorial][video-admin] for this configuration.
@@ -161,11 +156,6 @@ outside world.
respectively.
1. [Reconfigure GitLab][reconfigure]
-1. Restart gitlab-pages by running the following command:
-
- ```shell
- sudo gitlab-ctl restart gitlab-pages
- ```
## Advanced configuration
@@ -203,11 +193,6 @@ world. Custom domains are supported, but no TLS.
listens on. If you don't have IPv6, you can omit the IPv6 address.
1. [Reconfigure GitLab][reconfigure]
-1. Restart gitlab-pages by running the following command:
-
- ```shell
- sudo gitlab-ctl restart gitlab-pages
- ```
### Custom domains with TLS support
@@ -241,11 +226,6 @@ world. Custom domains and TLS are supported.
listens on. If you don't have IPv6, you can omit the IPv6 address.
1. [Reconfigure GitLab][reconfigure]
-1. Restart gitlab-pages by running the following command:
-
- ```shell
- sudo gitlab-ctl restart gitlab-pages
- ```
### Custom domain verification
@@ -290,11 +270,29 @@ are stored.
```
1. [Reconfigure GitLab][reconfigure]
-1. Restart gitlab-pages by running the following command:
+
+## Configure listener for reverse proxy requests
+
+Follow the steps below to configure the proxy listener of GitLab Pages. [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/2533) in
+Omnibus GitLab 11.1.
+
+1. By default the listener is configured to listen for requests on `localhost:8090`.
+
+ If you wish to disable it you must configure this in
+ `/etc/gitlab/gitlab.rb`:
```shell
- sudo gitlab-ctl restart gitlab-pages
- ```
+ gitlab_pages['listen_proxy'] = nil
+ ```
+
+ If you wish to make it listen on a different port you must configure this also in
+ `/etc/gitlab/gitlab.rb`:
+
+ ```shell
+ gitlab_pages['listen_proxy'] = "localhost:10080"
+ ```
+
+1. [Reconfigure GitLab][reconfigure]
## Set maximum pages size
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 11de75039ee..87be36cc815 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -10,13 +10,14 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `skip_groups` | array of integers | no | Skip the group IDs passed |
-| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin) |
+| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin); Attributes `owned` and `min_access_level` have precedence |
| `search` | string | no | Return the list of authorized groups matching the search criteria |
| `order_by` | string | no | Order groups by `name`, `path` or `id`. Default is `name` |
| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
| `statistics` | boolean | no | Include group statistics (admins only) |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
-| `owned` | boolean | no | Limit to groups owned by the current user |
+| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
+| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md) |
```
GET /groups
@@ -94,13 +95,14 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the parent group |
| `skip_groups` | array of integers | no | Skip the group IDs passed |
-| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin) |
+| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin); Attributes `owned` and `min_access_level` have precedence |
| `search` | string | no | Return the list of authorized groups matching the search criteria |
| `order_by` | string | no | Order groups by `name`, `path` or `id`. Default is `name` |
| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
| `statistics` | boolean | no | Include group statistics (admins only) |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
-| `owned` | boolean | no | Limit to groups owned by the current user |
+| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
+| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md) |
```
GET /groups/:id/subgroups
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 5613cb6d915..92fb3e9c307 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -37,7 +37,7 @@ GET /issues?my_reaction_emoji=star
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels |
-| `milestone` | string | no | The milestone title |
+| `milestone` | string | no | The milestone title. `No+Milestone` lists all issues with no milestone |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Return issues assigned to the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ |
@@ -151,7 +151,7 @@ GET /groups/:id/issues?my_reaction_emoji=star
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels |
| `iids[]` | Array[integer] | no | Return only the issues having the given `iid` |
-| `milestone` | string | no | The milestone title |
+| `milestone` | string | no | The milestone title. `No+Milestone` lists all issues with no milestone |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Return issues assigned to the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ |
@@ -265,7 +265,7 @@ GET /projects/:id/issues?my_reaction_emoji=star
| `iids[]` | Array[integer] | no | Return only the milestone having the given `iid` |
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels |
-| `milestone` | string | no | The milestone title |
+| `milestone` | string | no | The milestone title. `No+Milestone` lists all issues with no milestone |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Return issues assigned to the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ |
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 9409afc88a8..f360b49c293 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -48,7 +48,7 @@ GET /projects
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Return list of projects matching the search criteria |
| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. |
-| `owned` | boolean | no | Limit by projects owned by the current user |
+| `owned` | boolean | no | Limit by projects explicitly owned by the current user |
| `membership` | boolean | no | Limit by projects that the current user is a member of |
| `starred` | boolean | no | Limit by projects starred by the current user |
| `statistics` | boolean | no | Include project statistics |
@@ -57,6 +57,7 @@ GET /projects
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
| `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) |
When `simple=true` or the user is unauthenticated this returns something like:
@@ -273,13 +274,14 @@ GET /users/:user_id/projects
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Return list of projects matching the search criteria |
| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. |
-| `owned` | boolean | no | Limit by projects owned by the current user |
+| `owned` | boolean | no | Limit by projects explicitly owned by the current user |
| `membership` | boolean | no | Limit by projects that the current user is a member of |
| `starred` | boolean | no | Limit by projects starred by the current user |
| `statistics` | boolean | no | Include project statistics |
| `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 |
+| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
```json
[
@@ -769,13 +771,14 @@ GET /projects/:id/forks
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Return list of projects matching the search criteria |
| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. |
-| `owned` | boolean | no | Limit by projects owned by the current user |
+| `owned` | boolean | no | Limit by projects explicitly owned by the current user |
| `membership` | boolean | no | Limit by projects that the current user is a member of |
| `starred` | boolean | no | Limit by projects starred by the current user |
| `statistics` | boolean | no | Include project statistics |
| `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 |
+| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/forks"
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 096b64eb881..d95f8c7c8cc 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1411,43 +1411,6 @@ variables:
You can set it globally or per-job in the [`variables`](#variables) section.
-### Custom build directories
-
-> [Introduced][gitlab-runner-876] in Gitlab Runner 11.1
-
-NOTE: **Note:**
-This can only be used when `custom_build_dir` is set to true in the [Runner's
-configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
-
-By default, GitLab Runner clones the repository in the `/builds` directory,
-but sometimes your project might require to have the code in a specific
-directory, like the GO projects for example. In that case, you can specify
-the `CI_PROJECT_DIR` variable to tell the Runner in which directory to clone
-the repository:
-
-```yml
-image: golang:1.10-alpine3.7
-
-variables:
- CI_PROJECT_DIR: /go/src/gitlab.com/namespace/project-name
-
-stages:
- - test
-
-dir:
- stage: test
- script:
- - pwd # /go/src/gitlab.com/namespace/project-name
-```
-
-The following executors may use this feature only when
-[concurrent](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section)
-is set to `1`:
-
-- `shell`
-- `ssh`
-- `docker`, `docker+machine` when the job's working directory is mounted as a host volume.
-
## Special YAML features
It's possible to use special YAML features like anchors (`&`), aliases (`*`)
@@ -1641,6 +1604,5 @@ CI with various languages.
[ce-7983]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7983
[ce-7447]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7447
[ce-12909]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12909
-[gitlab-runner-876]: https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/876
[schedules]: ../../user/project/pipelines/schedules.md
[variables-expressions]: ../variables/README.md#variables-expressions
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 797b04df059..b4f441f6a4f 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -34,11 +34,12 @@ module API
optional :owned, type: Boolean, default: false, desc: 'Limit by owned by authenticated user'
optional :order_by, type: String, values: %w[name path id], default: 'name', desc: 'Order by name, path or id'
optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
+ optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Minimum access level of authenticated user'
use :pagination
end
def find_groups(params, parent_id = nil)
- find_params = params.slice(:all_available, :custom_attributes, :owned)
+ find_params = params.slice(:all_available, :custom_attributes, :owned, :min_access_level)
find_params[:parent] = find_group!(parent_id) if parent_id
find_params[:all_available] =
find_params.fetch(:all_available, current_user&.full_private_access?)
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index f7737468148..be17653dbb2 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -389,6 +389,7 @@ module API
finder_params[:search] = params[:search] if params[:search]
finder_params[:user] = params.delete(:user) if params[:user]
finder_params[:custom_attributes] = params[:custom_attributes] if params[:custom_attributes]
+ finder_params[:min_access_level] = params[:min_access_level] if params[:min_access_level]
finder_params
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 889e3d4f819..eadde7b17bb 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -54,6 +54,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 :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user'
use :optional_filter_params_ee
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 5aaaf104dff..6da6c2b43de 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -42,6 +42,7 @@ module API
optional :can_create_group, type: Boolean, desc: 'Flag indicating the user can create groups'
optional :external, type: Boolean, desc: 'Flag indicating the user is an external user'
optional :avatar, type: File, desc: 'Avatar image for user'
+ optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user'
all_or_none_of :extern_uid, :provider
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 21ac43f80fd..7bd5927d15e 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -826,6 +826,10 @@ module Gitlab
end
end
+ # This method, fetch_ref, is used from within
+ # Gitlab::Git::OperationService. OperationService will eventually only
+ # exist in gitaly-ruby. When we delete OperationService from gitlab-ce
+ # we can also remove fetch_ref.
def fetch_ref(source_repository, source_ref:, target_ref:)
Gitlab::Git.check_namespace!(source_repository)
source_repository = RemoteRepository.new(source_repository) unless source_repository.is_a?(RemoteRepository)
diff --git a/lib/gitlab/import_export/merge_request_parser.rb b/lib/gitlab/import_export/merge_request_parser.rb
index f3d7407383c..d0527f014a7 100644
--- a/lib/gitlab/import_export/merge_request_parser.rb
+++ b/lib/gitlab/import_export/merge_request_parser.rb
@@ -25,6 +25,7 @@ module Gitlab
@project.repository.create_branch(@merge_request.target_branch, @merge_request.target_branch_sha)
end
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1295
def fetch_ref
@project.repository.fetch_ref(@project.repository, source_ref: @diff_head_sha, target_ref: @merge_request.source_branch)
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 65b387a2170..3a8948f8477 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -226,6 +226,25 @@ describe API::Groups do
expect(json_response.first['name']).to eq(group2.name)
end
end
+
+ context 'when using min_access_level in the request' do
+ let!(:group3) { create(:group, :private) }
+ let(:response_groups) { json_response.map { |group| group['id'] } }
+
+ before do
+ group1.add_developer(user2)
+ group3.add_master(user2)
+ end
+
+ it 'returns an array of groups the user has at least master access' do
+ get api('/groups', user2), min_access_level: 40
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(response_groups).to eq([group2.id, group3.id])
+ end
+ end
end
describe "GET /groups/:id" do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 5ac008c7e40..71e3436fa76 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -400,6 +400,22 @@ describe API::Projects do
end
end
end
+
+ context 'and with min_access_level' do
+ before do
+ project2.add_master(user2)
+ project3.add_developer(user2)
+ project4.add_reporter(user2)
+ end
+
+ it 'returns an array of groups the user has at least developer access' do
+ get api('/projects', user2), { min_access_level: 30 }
+ 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 { |project| project['id'] }).to contain_exactly(project2.id, project3.id)
+ end
+ end
end
context 'when authenticated as a different user' do
@@ -681,6 +697,20 @@ describe API::Projects do
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id)
end
+
+ it 'returns projects filetered by minimal access level' do
+ private_project1 = create(:project, :private, name: 'private_project1', creator_id: user4.id, namespace: user4.namespace)
+ private_project2 = create(:project, :private, name: 'private_project2', creator_id: user4.id, namespace: user4.namespace)
+ private_project1.add_developer(user2)
+ private_project2.add_reporter(user2)
+
+ get api("/users/#{user4.id}/projects/", user2), { min_access_level: 30 }
+
+ 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 { |project| project['id'] }).to contain_exactly(private_project1.id)
+ end
end
describe 'POST /projects/user/:id' do