Commit 24e7f042 authored by Steve Azzopardi's avatar Steve Azzopardi

Merge branch 'ce-to-ee-2018-11-21' into 'master'

CE upstream - 2018-11-21 20:21 UTC

Closes gitlab-ce#52699, gitlab-ce#53571, and gitlab-ce#51220

See merge request gitlab-org/gitlab-ee!8551
parents 1c1a43fe 716b90d5
...@@ -798,7 +798,8 @@ gitlab:assets:compile: ...@@ -798,7 +798,8 @@ gitlab:assets:compile:
- webpack-report/ - webpack-report/
- public/assets/ - public/assets/
tags: tags:
- docker - gitlab-org-delivery
- high-cpu
karma: karma:
<<: *dedicated-no-docs-pull-cache-job <<: *dedicated-no-docs-pull-cache-job
......
...@@ -50,7 +50,6 @@ Style/FrozenStringLiteralComment: ...@@ -50,7 +50,6 @@ Style/FrozenStringLiteralComment:
- 'danger/**/*' - 'danger/**/*'
- 'db/**/*' - 'db/**/*'
- 'ee/**/*' - 'ee/**/*'
- 'lib/gitlab/**/*'
- 'lib/tasks/**/*' - 'lib/tasks/**/*'
- 'qa/**/*' - 'qa/**/*'
- 'rubocop/**/*' - 'rubocop/**/*'
......
...@@ -4,17 +4,18 @@ entry. ...@@ -4,17 +4,18 @@ entry.
## 11.5.0 (2018-11-22) ## 11.5.0 (2018-11-22)
### Security (9 changes, 1 of them is from the community) ### Security (10 changes, 1 of them is from the community)
- Escape entity title while autocomplete template rendering to prevent XSS. !2556 - Escape entity title while autocomplete template rendering to prevent XSS. !2556
- Update moment to 2.22.2. !22648 (Takuya Noguchi) - Update moment to 2.22.2. !22648 (Takuya Noguchi)
- Fix XSS in merge request source branch name. - Redact personal tokens in unsubscribe links.
- Escape user fullname while rendering autocomplete template to prevent XSS. - Escape user fullname while rendering autocomplete template to prevent XSS.
- Persist only SHA digest of PersonalAccessToken#token. - Persist only SHA digest of PersonalAccessToken#token.
- Monkey kubeclient to not follow any redirects. - Monkey kubeclient to not follow any redirects.
- Prevent SSRF attacks in HipChat integration. - Prevent SSRF attacks in HipChat integration.
- Prevent templated services from being imported.
- Validate Wiki attachments are valid temporary files. - Validate Wiki attachments are valid temporary files.
- Redact personal tokens in unsubscribe links. - Fix XSS in merge request source branch name.
### Removed (2 changes) ### Removed (2 changes)
...@@ -263,6 +264,10 @@ entry. ...@@ -263,6 +264,10 @@ entry.
- Disables stop environment button while the deploy is in progress. - Disables stop environment button while the deploy is in progress.
## 11.4.7 (2018-11-20)
- No changes.
## 11.4.6 (2018-11-18) ## 11.4.6 (2018-11-18)
### Security (1 change) ### Security (1 change)
......
This document is intended to communicate the product philosophy GitLab uses in creating GitLab Enterprise Edition. The principles can be found in the [Product Section of the GitLab Handbook](https://about.gitlab.com/handbook/product/#product-at-gitlab). This document is intended to communicate the product philosophy GitLab uses in creating GitLab Enterprise Edition. The principles can be found in the [Product Section of the GitLab Handbook](https://about.gitlab.com/handbook/product/#product-at-gitlab).
\ No newline at end of file
11.5.0-pre 11.6.0-pre
...@@ -124,7 +124,7 @@ export default class FileTemplateMediator { ...@@ -124,7 +124,7 @@ export default class FileTemplateMediator {
selectTemplateFile(selector, query, data) { selectTemplateFile(selector, query, data) {
selector.renderLoading(); selector.renderLoading();
// in case undo menu is already already there // in case undo menu is already there
this.destroyUndoMenu(); this.destroyUndoMenu();
this.fetchFileTemplate(selector.config.type, query, data) this.fetchFileTemplate(selector.config.type, query, data)
.then(file => { .then(file => {
......
...@@ -48,10 +48,19 @@ export default { ...@@ -48,10 +48,19 @@ export default {
selectable: true, selectable: true,
data: (term, callback) => { data: (term, callback) => {
this.loading = true; this.loading = true;
return Api.groupProjects(this.groupId, term, { with_issues_enabled: true }, projects => { return Api.groupProjects(
this.loading = false; this.groupId,
callback(projects); term,
}); {
with_issues_enabled: true,
with_shared: false,
include_subgroups: true,
},
projects => {
this.loading = false;
callback(projects);
},
);
}, },
renderRow(project) { renderRow(project) {
return ` return `
......
...@@ -22,7 +22,7 @@ export default class Labels { ...@@ -22,7 +22,7 @@ export default class Labels {
updateColorPreview() { updateColorPreview() {
const previewColor = $('input#label_color').val(); const previewColor = $('input#label_color').val();
return $('div.label-color-preview').css('background-color', previewColor); return $('div.label-color-preview').css('background-color', previewColor);
// Updates the the preview color with the hex-color input // Updates the preview color with the hex-color input
} }
// Updates the preview color with a click on a suggested color // Updates the preview color with a click on a suggested color
......
...@@ -14,6 +14,9 @@ export default function projectSelect() { ...@@ -14,6 +14,9 @@ export default function projectSelect() {
this.orderBy = $(select).data('orderBy') || 'id'; this.orderBy = $(select).data('orderBy') || 'id';
this.withIssuesEnabled = $(select).data('withIssuesEnabled'); this.withIssuesEnabled = $(select).data('withIssuesEnabled');
this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled');
this.withShared =
$(select).data('withShared') === undefined ? true : $(select).data('withShared');
this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false;
this.allowClear = $(select).data('allowClear') || false; this.allowClear = $(select).data('allowClear') || false;
placeholder = 'Search for project'; placeholder = 'Search for project';
...@@ -54,6 +57,8 @@ export default function projectSelect() { ...@@ -54,6 +57,8 @@ export default function projectSelect() {
{ {
with_issues_enabled: _this.withIssuesEnabled, with_issues_enabled: _this.withIssuesEnabled,
with_merge_requests_enabled: _this.withMergeRequestsEnabled, with_merge_requests_enabled: _this.withMergeRequestsEnabled,
with_shared: _this.withShared,
include_subgroups: _this.includeProjectsInSubgroups,
}, },
projectsCallback, projectsCallback,
); );
......
<script> <script>
import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import FilteredSearchDropdown from '~/vue_shared/components/filtered_search_dropdown.vue'; import FilteredSearchDropdown from '~/vue_shared/components/filtered_search_dropdown.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
import timeagoMixin from '../../vue_shared/mixins/timeago'; import timeagoMixin from '../../vue_shared/mixins/timeago';
import tooltip from '../../vue_shared/directives/tooltip';
import LoadingButton from '../../vue_shared/components/loading_button.vue'; import LoadingButton from '../../vue_shared/components/loading_button.vue';
import { visitUrl } from '../../lib/utils/url_utility'; import { visitUrl } from '../../lib/utils/url_utility';
import createFlash from '../../flash'; import createFlash from '../../flash';
...@@ -25,7 +25,7 @@ export default { ...@@ -25,7 +25,7 @@ export default {
ReviewAppLink, ReviewAppLink,
}, },
directives: { directives: {
tooltip, GlTooltip: GlTooltipDirective,
}, },
mixins: [timeagoMixin], mixins: [timeagoMixin],
props: { props: {
...@@ -42,6 +42,8 @@ export default { ...@@ -42,6 +42,8 @@ export default {
running: __('Deploying to'), running: __('Deploying to'),
success: __('Deployed to'), success: __('Deployed to'),
failed: __('Failed to deploy to'), failed: __('Failed to deploy to'),
created: __('Will deploy to'),
canceled: __('Failed to deploy to'),
}, },
data() { data() {
return { return {
...@@ -134,7 +136,7 @@ export default { ...@@ -134,7 +136,7 @@ export default {
</template> </template>
<span <span
v-if="hasDeploymentTime" v-if="hasDeploymentTime"
v-tooltip v-gl-tooltip
:title="deployment.deployed_at_formatted" :title="deployment.deployed_at_formatted"
class="js-deploy-time" class="js-deploy-time"
> >
...@@ -187,7 +189,7 @@ export default { ...@@ -187,7 +189,7 @@ export default {
</template> </template>
<span <span
v-if="deployment.stop_url" v-if="deployment.stop_url"
v-tooltip v-gl-tooltip
:title="deployInProgressTooltip" :title="deployInProgressTooltip"
class="d-inline-block" class="d-inline-block"
tabindex="0" tabindex="0"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Overrides `as_json` and `to_json` to raise an exception when called in order # Overrides `as_json` and `to_json` to raise an exception when called in order
# to prevent accidentally exposing attributes # to prevent accidentally exposing attributes
# #
# Not that that would ever happen... but just in case. # Not that would ever happen... but just in case.
module BlocksJsonSerialization module BlocksJsonSerialization
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
...@@ -190,7 +190,7 @@ class Namespace < ActiveRecord::Base ...@@ -190,7 +190,7 @@ class Namespace < ActiveRecord::Base
.base_and_ancestors .base_and_ancestors
end end
# returns all ancestors upto but excluding the the given namespace # returns all ancestors upto but excluding the given namespace
# when no namespace is given, all ancestors upto the top are returned # when no namespace is given, all ancestors upto the top are returned
def ancestors_upto(top = nil) def ancestors_upto(top = nil)
Gitlab::GroupHierarchy.new(self.class.where(id: id)) Gitlab::GroupHierarchy.new(self.class.where(id: id))
......
...@@ -36,7 +36,7 @@ module Ci ...@@ -36,7 +36,7 @@ module Ci
builds = builds.with_any_tags builds = builds.with_any_tags
end end
builds.find do |build| selection = builds.find do |build|
next unless runner.can_pick?(build) next unless runner.can_pick?(build)
begin begin
...@@ -45,7 +45,7 @@ module Ci ...@@ -45,7 +45,7 @@ module Ci
if assign_runner!(build, params) if assign_runner!(build, params)
register_success(build) register_success(build)
return Result.new(build, true) # rubocop:disable Cop/AvoidReturnFromBlocks break build
end end
rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError
# We are looping to find another build that is not conflicting # We are looping to find another build that is not conflicting
...@@ -61,6 +61,8 @@ module Ci ...@@ -61,6 +61,8 @@ module Ci
end end
end end
return Result.new(selection, true) if selection
register_failure register_failure
Result.new(nil, valid) Result.new(nil, valid)
end end
......
...@@ -7,7 +7,7 @@ module Commits ...@@ -7,7 +7,7 @@ module Commits
# - user: `User` that will be the committer # - user: `User` that will be the committer
# - params: # - params:
# - branch_name: `String` the branch that will be committed into # - branch_name: `String` the branch that will be committed into
# - start_branch: `String` the branch that will will started from # - start_branch: `String` the branch that will be started from
# - patches: `Gitlab::Git::Patches::Collection` that contains the patches # - patches: `Gitlab::Git::Patches::Collection` that contains the patches
def initialize(*args) def initialize(*args)
super super
......
...@@ -10,6 +10,7 @@ module MergeRequests ...@@ -10,6 +10,7 @@ module MergeRequests
# TODO: this should handle all quick actions that don't have side effects # TODO: this should handle all quick actions that don't have side effects
# https://gitlab.com/gitlab-org/gitlab-ce/issues/53658 # https://gitlab.com/gitlab-org/gitlab-ce/issues/53658
merge_quick_actions_into_params!(merge_request, only: [:target_branch]) merge_quick_actions_into_params!(merge_request, only: [:target_branch])
merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch) if params.has_key?(:force_remove_source_branch)
merge_request.assign_attributes(params) merge_request.assign_attributes(params)
merge_request.author = current_user merge_request.author = current_user
......
...@@ -50,7 +50,7 @@ class NotificationService ...@@ -50,7 +50,7 @@ class NotificationService
# Always notify the user about gpg key added # Always notify the user about gpg key added
# #
# This is a security email so it will be sent even if the user user disabled # This is a security email so it will be sent even if the user disabled
# notifications # notifications
def new_gpg_key(gpg_key) def new_gpg_key(gpg_key)
if gpg_key.user&.can?(:receive_notifications) if gpg_key.user&.can?(:receive_notifications)
......
- page_title _("Report abuse to GitLab") - page_title _("Report abuse to GitLab")
%h3.page-title %h3.page-title
= _('Report abuse to GitLab') = _("Report abuse to GitLab")
%p %p
= _('Please use this form to report users to GitLab who create spam issues, comments or behave inappropriately.') = _("Please use this form to report users to GitLab who create spam issues, comments or behave inappropriately.")
%p %p
= _("A member of GitLab's abuse team will review your report as soon as possible.") = _("A member of GitLab's abuse team will review your report as soon as possible.")
%hr %hr
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
.col-sm-10 .col-sm-10
= f.text_area :message, class: "form-control", rows: 2, required: true, value: sanitize(@ref_url) = f.text_area :message, class: "form-control", rows: 2, required: true, value: sanitize(@ref_url)
.form-text.text-muted .form-text.text-muted
= _('Explain the problem. If appropriate, provide a link to the relevant issue or comment.') = _("Explain the problem. If appropriate, provide a link to the relevant issue or comment.")
.form-actions .form-actions
= f.submit "Send report", class: "btn btn-success" = f.submit _("Send report"), class: "btn btn-success"
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
= render 'shared/issuable/nav', type: :issues = render 'shared/issuable/nav', type: :issues
.nav-controls .nav-controls
= render 'shared/issuable/feed_buttons' = render 'shared/issuable/feed_buttons'
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues' = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues', with_shared: false, include_projects_in_subgroups: true
= render 'shared/issuable/search_bar', type: :issues = render 'shared/issuable/search_bar', type: :issues
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= render 'shared/issuable/nav', type: :merge_requests = render 'shared/issuable/nav', type: :merge_requests
- if current_user - if current_user
.nav-controls .nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests, with_feature_enabled: 'merge_requests' = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests, with_feature_enabled: 'merge_requests', with_shared: false, include_projects_in_subgroups: true
= render 'shared/issuable/search_bar', type: :merge_requests = render 'shared/issuable/search_bar', type: :merge_requests
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
%h4.prepend-top-0 %h4.prepend-top-0
Feed token Feed token
%p %p
Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when when your calendar application loads a personalized calendar, and is included in those feed URLs. Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs.
%p %p
It cannot be used to access any other data. It cannot be used to access any other data.
.col-lg-8.feed-token-reset .col-lg-8.feed-token-reset
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
.project-item-select-holder.btn-group .project-item-select-holder.btn-group
%a.btn.btn-success.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } } %a.btn.btn-success.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } }
= icon('spinner spin') = icon('spinner spin')
= project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path] }, with_feature_enabled: local_assigns[:with_feature_enabled] = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled]
%button.btn.btn-success.new-project-item-select-button.qa-new-project-item-select-button %button.btn.btn-success.new-project-item-select-button.qa-new-project-item-select-button
= icon('caret-down') = icon('caret-down')
---
title: Fix project selector consistency in groups issues / MRs / boards pages
merge_request: 22612
author: Heinrich Lee Yu
type: fixed
---
title: Adds states to the deployment widget
merge_request:
author:
type: added
---
title: Fixes stuck tooltip on stop env button
merge_request: 23244
author:
type: fixed
---
title: Enable Rubocop on lib/gitlab
merge_request:
author: gfyoung
type: other
---
title: Adds a PHILOSOPHY.md which references GitLab Product Handbook
merge_request: 23200
author:
type: other
---
title: Use cached size when passing artifacts to Runner
merge_request:
author:
type: performance
---
title: Handle force_remove_source_branch when creating merge request
merge_request: 23281
author:
type: fixed
---
title: Prevent templated services from being imported
merge_request:
author:
type: security
...@@ -12,5 +12,5 @@ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) ...@@ -12,5 +12,5 @@ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
begin begin
require 'bootsnap/setup' require 'bootsnap/setup'
rescue LoadError rescue LoadError
# bootsnap is optional dependency, so if we don't have it it's fine # bootsnap is an optional dependency, so if we don't have it, it's fine
end end
...@@ -12,7 +12,7 @@ class AlterWebHookLogsIndexes < ActiveRecord::Migration ...@@ -12,7 +12,7 @@ class AlterWebHookLogsIndexes < ActiveRecord::Migration
disable_ddl_transaction! disable_ddl_transaction!
# "created_at" comes first so the Sidekiq worker pruning old webhook logs can # "created_at" comes first so the Sidekiq worker pruning old webhook logs can
# use a composite index index. # use a composite index.
# #
# We leave the old standalone index on "web_hook_id" in place so future code # We leave the old standalone index on "web_hook_id" in place so future code
# that doesn't care about "created_at" can still use that index. # that doesn't care about "created_at" can still use that index.
......
...@@ -112,7 +112,7 @@ not explicit. This allows for a stable API endpoint, but also means new ...@@ -112,7 +112,7 @@ not explicit. This allows for a stable API endpoint, but also means new
features can be added to the API in the same version number. features can be added to the API in the same version number.
New features and bug fixes are released in tandem with a new GitLab, and apart New features and bug fixes are released in tandem with a new GitLab, and apart
from incidental patch and security releases, are released on the 22nd each from incidental patch and security releases, are released on the 22nd of each
month. Backward incompatible changes (e.g. endpoints removal, parameters month. Backward incompatible changes (e.g. endpoints removal, parameters
removal etc.), as well as removal of entire API versions are done in tandem removal etc.), as well as removal of entire API versions are done in tandem
with a major point release of GitLab itself. All deprecations and changes with a major point release of GitLab itself. All deprecations and changes
......
...@@ -152,8 +152,10 @@ Parameters: ...@@ -152,8 +152,10 @@ Parameters:
| `simple` | boolean | no | Return only the ID, URL, name, and path of each project | | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
| `owned` | boolean | no | Limit by projects owned by the current user | | `owned` | boolean | no | Limit by projects owned by the current user |
| `starred` | boolean | no | Limit by projects starred by the current user | | `starred` | boolean | no | Limit by projects starred by the current user |
| `with_issues_enabled` | boolean | no | Limit by enabled issues feature | | `with_issues_enabled` | boolean | no | Limit by projects with issues feature enabled. Default is `false` |
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature | | `with_merge_requests_enabled` | boolean | no | Limit by projects with merge requests feature enabled. Default is `false` |
| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` |
| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
| `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) |
Example response: Example response:
......
...@@ -65,14 +65,12 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/a ...@@ -65,14 +65,12 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/a
Example response: Example response:
```json ```json
[ {
{ "content" : "home page",
"content" : "home page", "format" : "markdown",
"format" : "markdown", "slug" : "home",
"slug" : "home", "title" : "home"
"title" : "home" }
}
]
``` ```
## Create a new wiki page ## Create a new wiki page
......
...@@ -334,7 +334,7 @@ There are a few rules that apply to the usage of job policy: ...@@ -334,7 +334,7 @@ There are a few rules that apply to the usage of job policy:
* `only` and `except` are inclusive. If both `only` and `except` are defined * `only` and `except` are inclusive. If both `only` and `except` are defined
in a job specification, the ref is filtered by `only` and `except`. in a job specification, the ref is filtered by `only` and `except`.
* `only` and `except` allow the use of regular expressions. * `only` and `except` allow the use of regular expressions (using [Ruby regexp syntax](https://ruby-doc.org/core/Regexp.html)).
* `only` and `except` allow to specify a repository path to filter jobs for * `only` and `except` allow to specify a repository path to filter jobs for
forks. forks.
......
...@@ -35,9 +35,9 @@ For more information on how to use these options check out ...@@ -35,9 +35,9 @@ For more information on how to use these options check out
gitlab_rails['rack_attack_git_basic_auth'] = { gitlab_rails['rack_attack_git_basic_auth'] = {
'enabled' => true, 'enabled' => true,
'ip_whitelist' => ["127.0.0.1"], 'ip_whitelist' => ["127.0.0.1"],
'maxretry' => 10, 'maxretry' => 10, # Limit the number of Git HTTP authentication attempts per IP
'findtime' => 60, 'findtime' => 60, # Reset the auth attempt counter per IP after 60 seconds
'bantime' => 3600 'bantime' => 3600 # Ban an IP for one hour (3600s) after too many auth attempts
} }
``` ```
...@@ -55,9 +55,9 @@ The following settings can be configured: ...@@ -55,9 +55,9 @@ The following settings can be configured:
- `maxretry`: The maximum amount of times a request can be made in the - `maxretry`: The maximum amount of times a request can be made in the
specified time. specified time.
- `findtime`: The maximum amount of time failed requests can count against an IP - `findtime`: The maximum amount of time failed requests can count against an IP
before it's blacklisted. before it's blacklisted (in seconds).
- `bantime`: The total amount of time that a blacklisted IP will be blocked in - `bantime`: The total amount of time that a blacklisted IP will be blocked (in
seconds. seconds).
**Installations from source** **Installations from source**
......
...@@ -337,6 +337,25 @@ bottom of the screen with two buttons: ...@@ -337,6 +337,25 @@ bottom of the screen with two buttons:
Alternatively, every pending comment has a button to finish the entire review. Alternatively, every pending comment has a button to finish the entire review.
![Review submission](img/review_preview.png) ![Review submission](img/review_preview.png)
## Filtering notes
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/26723) in GitLab 11.5.
For issues with many comments like activity notes and user comments, sometimes
finding useful information can be hard. There is a way to filter comments from single notes and discussions for merge requests and issues.
From a merge request's **Discussion** tab, or from an issue overview, find the filter's dropdown menu on the right side of the page, from which you can choose one of the following options:
- **Show all activity**: displays all user comments and system notes
(issue updates, mentions from other issues, changes to the description, etc).
- **Show comments only**: only displays user comments in the list.
- **Show history only**: only displays activity notes.
![Notes filters dropdown options](img/index_notes_filters.png)
Once you select one of the filters in a given issue or MR, GitLab will save
your preference, so that it will persist when you visit the same page again
from any device you're logged into.
[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022 [ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
[ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125 [ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125
......
...@@ -9,7 +9,7 @@ collaborate with other people on the same project. ...@@ -9,7 +9,7 @@ collaborate with other people on the same project.
A Merge Request (**MR**) is the basis of GitLab as a code collaboration A Merge Request (**MR**) is the basis of GitLab as a code collaboration
and version control platform. and version control platform.
Is it simple as the name implies: a _request_ to _merge_ one branch into another. It is as simple as the name implies: a _request_ to _merge_ one branch into another.
With GitLab merge requests, you can: With GitLab merge requests, you can:
......
--- ---
last_updated: 2018-08-16 last_updated: 2018-11-19
author: Marcia Ramos author: Marcia Ramos
author_gitlab: marcia author_gitlab: marcia
level: beginner level: beginner
...@@ -183,7 +183,7 @@ you can use the following setup: ...@@ -183,7 +183,7 @@ you can use the following setup:
- In Cloudflare, create a DNS `A` record pointing `domain.com` to `35.185.44.232` - In Cloudflare, create a DNS `A` record pointing `domain.com` to `35.185.44.232`
- In GitLab, add the domain to GitLab Pages - In GitLab, add the domain to GitLab Pages
- In Cloudflare, create a DNS `TXT` record to verify your domain - In Cloudflare, create a DNS `TXT` record to verify your domain
- In Cloudflare, create a DNS `CNAME` record poiting `www` to `domain.com` - In Cloudflare, create a DNS `CNAME` record pointing `www` to `domain.com`
## SSL/TLS Certificates ## SSL/TLS Certificates
......
...@@ -1170,7 +1170,8 @@ module API ...@@ -1170,7 +1170,8 @@ module API
end end
class JobArtifactFile < Grape::Entity class JobArtifactFile < Grape::Entity
expose :filename, :size expose :filename
expose :cached_size, as: :size
end end
class JobArtifact < Grape::Entity class JobArtifact < Grape::Entity
......
...@@ -71,7 +71,17 @@ module API ...@@ -71,7 +71,17 @@ module API
def find_group_projects(params) def find_group_projects(params)
group = find_group!(params[:id]) group = find_group!(params[:id])
projects = GroupProjectsFinder.new(group: group, current_user: current_user, params: project_finder_params).execute options = {
only_owned: !params[:with_shared],
include_subgroups: params[:include_subgroups]
}
projects = GroupProjectsFinder.new(
group: group,
current_user: current_user,
params: project_finder_params,
options: options
).execute
projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled] projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled]
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 = reorder_projects(projects) projects = reorder_projects(projects)
...@@ -244,6 +254,8 @@ module API ...@@ -244,6 +254,8 @@ module API
optional :starred, type: Boolean, default: false, desc: 'Limit by starred status' optional :starred, type: Boolean, default: false, desc: 'Limit by starred status'
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_shared, type: Boolean, default: true, desc: 'Include projects shared to this group'
optional :include_subgroups, type: Boolean, default: false, desc: 'Includes projects in subgroups of this group'
use :pagination use :pagination
use :with_custom_attributes use :with_custom_attributes
......
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
# Class that rewrites markdown links for uploads # Class that rewrites markdown links for uploads
# #
# Using a pattern defined in `FileUploader` it copies files to a new # Using a pattern defined in `FileUploader` it copies files to a new
# project and rewrites all links to uploads in in a given text. # project and rewrites all links to uploads in a given text.
# #
# #
class UploadsRewriter class UploadsRewriter
......
...@@ -441,7 +441,7 @@ module Gitlab ...@@ -441,7 +441,7 @@ module Gitlab
gitaly_ref_client.find_ref_name(sha, ref_path) gitaly_ref_client.find_ref_name(sha, ref_path)
end end
# Get refs hash which key is is the commit id # Get refs hash which key is the commit id
# and value is a Gitlab::Git::Tag or Gitlab::Git::Branch # and value is a Gitlab::Git::Tag or Gitlab::Git::Branch
# Note that both inherit from Gitlab::Git::Ref # Note that both inherit from Gitlab::Git::Ref
def refs_hash def refs_hash
......
...@@ -251,7 +251,7 @@ module Gitlab ...@@ -251,7 +251,7 @@ module Gitlab
def validate_variable_usage(errors, translation, required_variables) def validate_variable_usage(errors, translation, required_variables)
# We don't need to validate when the message is empty. # We don't need to validate when the message is empty.
# In this case we fall back to the default, which has all the the # In this case we fall back to the default, which has all the
# required variables. # required variables.
return if translation.empty? return if translation.empty?
......
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
# used for rendering Markdown) are completely unnecessary and may even lead to # used for rendering Markdown) are completely unnecessary and may even lead to
# transaction timeouts. # transaction timeouts.
# #
# To ensure importing merge requests requests has a minimal impact and can # To ensure importing merge requests has a minimal impact and can complete in
# complete in a reasonable time we bypass all the hooks by inserting the row # a reasonable time we bypass all the hooks by inserting the row and then
# and then retrieving it. We then only perform the additional work that is # retrieving it. We then only perform the additional work that is strictly
# strictly necessary. # necessary.
module Gitlab module Gitlab
module Import module Import
class MergeRequestCreator class MergeRequestCreator
......
...@@ -7349,6 +7349,9 @@ msgstr "" ...@@ -7349,6 +7349,9 @@ msgstr ""
msgid "Send email" msgid "Send email"
msgstr "" msgstr ""
msgid "Send report"
msgstr ""
msgid "Send usage data" msgid "Send usage data"
msgstr "" msgstr ""
...@@ -9244,6 +9247,9 @@ msgstr "" ...@@ -9244,6 +9247,9 @@ msgstr ""
msgid "Wiki|Wiki Pages" msgid "Wiki|Wiki Pages"
msgstr "" msgstr ""
msgid "Will deploy to"
msgstr ""
msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members." msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members."
msgstr "" msgstr ""
......
...@@ -5,7 +5,7 @@ module QA ...@@ -5,7 +5,7 @@ module QA
describe 'SSH keys support' do describe 'SSH keys support' do
let(:key_title) { "key for ssh tests #{Time.now.to_f}" } let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
it 'user adds and then removes an SSH key' do it 'user adds and then removes an SSH key', :smoke do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials } Page::Main::Login.act { sign_in_using_credentials }
......
...@@ -152,7 +152,7 @@ describe Projects::BlobController do ...@@ -152,7 +152,7 @@ describe Projects::BlobController do
expect(match_line['meta_data']).to have_key('new_pos') expect(match_line['meta_data']).to have_key('new_pos')
end end
it 'does not add top match line when when "since" is equal 1' do it 'does not add top match line when "since" is equal 1' do
do_get(since: 1, to: 10, offset: 10, from_merge_request: true) do_get(since: 1, to: 10, offset: 10, from_merge_request: true)
match_line = JSON.parse(response.body).first match_line = JSON.parse(response.body).first
......
...@@ -42,7 +42,7 @@ describe 'Merge request > User assigns themselves' do ...@@ -42,7 +42,7 @@ describe 'Merge request > User assigns themselves' do
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
end end
it 'does not not show assignment link' do it 'does not show assignment link' do
expect(page).not_to have_content 'Assign yourself' expect(page).not_to have_content 'Assign yourself'
end end
end end
......
...@@ -325,7 +325,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do ...@@ -325,7 +325,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end end
end end
it 'allows user user to mark all discussions as resolved' do it 'allows user to mark all discussions as resolved' do
page.all('.discussion-reply-holder', count: 2).each do |reply_holder| page.all('.discussion-reply-holder', count: 2).each do |reply_holder|
page.within reply_holder do page.within reply_holder do
click_button 'Resolve discussion' click_button 'Resolve discussion'
......
...@@ -157,7 +157,7 @@ describe "User creates wiki page" do ...@@ -157,7 +157,7 @@ describe "User creates wiki page" do
expect(page).to have_field("wiki[message]", with: "Create home") expect(page).to have_field("wiki[message]", with: "Create home")
end end
it "creates a page from from the home page" do it "creates a page from the home page" do
page.within(".wiki-form") do page.within(".wiki-form") do
fill_in(:wiki_content, with: "My awesome wiki!") fill_in(:wiki_content, with: "My awesome wiki!")
......
...@@ -12,7 +12,7 @@ describe PipelineSchedulesFinder do ...@@ -12,7 +12,7 @@ describe PipelineSchedulesFinder do
context 'when the scope is nil' do context 'when the scope is nil' do
let(:params) { { scope: nil } } let(:params) { { scope: nil } }
it 'selects all pipeline pipeline schedules' do it 'selects all pipeline schedules' do
expect(subject.count).to be(2) expect(subject.count).to be(2)
expect(subject).to include(active_schedule, inactive_schedule) expect(subject).to include(active_schedule, inactive_schedule)
end end
......
...@@ -17,7 +17,7 @@ X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu, ...@@ -17,7 +17,7 @@ X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu,
13 Jun 2013 14:03:48 -0700 (PDT) 13 Jun 2013 14:03:48 -0700 (PDT)
X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1 X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1
Is there any reason the *old* candy can't be be kept in silos while the new candy Is there any reason the *old* candy can't be kept in silos while the new candy
is imported into *new* silos? is imported into *new* silos?
The thing about candy is it stays delicious for a long time -- we can just keep The thing about candy is it stays delicious for a long time -- we can just keep
......
...@@ -123,7 +123,7 @@ describe 'create_tokens' do ...@@ -123,7 +123,7 @@ describe 'create_tokens' do
create_tokens create_tokens
end end
it 'sets the the keys to the values from the environment and secrets.yml' do it 'sets the keys to the values from the environment and secrets.yml' do
create_tokens create_tokens
expect(secrets.secret_key_base).to eq('secret_key_base') expect(secrets.secret_key_base).to eq('secret_key_base')
......
...@@ -29,7 +29,7 @@ describe('ide component', () => { ...@@ -29,7 +29,7 @@ describe('ide component', () => {
resetStore(vm.$store); resetStore(vm.$store);
}); });
it('does not render right right when no files open', () => { it('does not render right when no files open', () => {
expect(vm.$el.querySelector('.panel-right')).toBeNull(); expect(vm.$el.querySelector('.panel-right')).toBeNull();
}); });
......
...@@ -59,7 +59,7 @@ describe('IDE branches actions', () => { ...@@ -59,7 +59,7 @@ describe('IDE branches actions', () => {
}); });
describe('receiveBranchesError', () => { describe('receiveBranchesError', () => {
it('should should commit error', done => { it('should commit error', done => {
testAction( testAction(
receiveBranchesError, receiveBranchesError,
{ search: TEST_SEARCH }, { search: TEST_SEARCH },
......
...@@ -39,7 +39,7 @@ describe('IDE merge requests actions', () => { ...@@ -39,7 +39,7 @@ describe('IDE merge requests actions', () => {
}); });
describe('receiveMergeRequestsError', () => { describe('receiveMergeRequestsError', () => {
it('should should commit error', done => { it('should commit error', done => {
testAction( testAction(
receiveMergeRequestsError, receiveMergeRequestsError,
{ type: 'created', search: '' }, { type: 'created', search: '' },
......
...@@ -252,5 +252,33 @@ describe('Deployment component', () => { ...@@ -252,5 +252,33 @@ describe('Deployment component', () => {
); );
}); });
}); });
describe('created', () => {
beforeEach(() => {
vm = mountComponent(Component, {
deployment: Object.assign({}, deploymentMockData, { status: 'created' }),
showMetrics: true,
});
});
it('renders information about created deployment', () => {
expect(vm.$el.querySelector('.js-deployment-info').textContent).toContain('Will deploy to');
});
});
describe('canceled', () => {
beforeEach(() => {
vm = mountComponent(Component, {
deployment: Object.assign({}, deploymentMockData, { status: 'canceled' }),
showMetrics: true,
});
});
it('renders information about canceled deployment', () => {
expect(vm.$el.querySelector('.js-deployment-info').textContent).toContain(
'Failed to deploy to',
);
});
});
}); });
}); });
...@@ -28,7 +28,7 @@ describe Banzai::Filter::AbsoluteLinkFilter do ...@@ -28,7 +28,7 @@ describe Banzai::Filter::AbsoluteLinkFilter do
end end
context 'if relative_url_root is set' do context 'if relative_url_root is set' do
it 'joins the url without without doubling the path' do it 'joins the url without doubling the path' do
allow(Gitlab.config.gitlab).to receive(:url).and_return("#{fake_url}/gitlab/") allow(Gitlab.config.gitlab).to receive(:url).and_return("#{fake_url}/gitlab/")
doc = filter(link("/gitlab/foo", 'gfm'), only_path_context) doc = filter(link("/gitlab/foo", 'gfm'), only_path_context)
expect(doc.at_css('a')['href']).to eq "#{fake_url}/gitlab/foo" expect(doc.at_css('a')['href']).to eq "#{fake_url}/gitlab/foo"
......
...@@ -498,7 +498,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -498,7 +498,7 @@ describe Gitlab::Auth::OAuth::User do
end end
end end
describe 'ensure backwards compatibility with with sync email from provider option' do describe 'ensure backwards compatibility with sync email from provider option' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') } let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
before do before do
......
...@@ -4,7 +4,7 @@ describe Gitlab::Ci::Build::Policy::Changes do ...@@ -4,7 +4,7 @@ describe Gitlab::Ci::Build::Policy::Changes do
set(:project) { create(:project) } set(:project) { create(:project) }
describe '#satisfied_by?' do describe '#satisfied_by?' do
describe 'paths matching matching' do describe 'paths matching' do
let(:pipeline) do let(:pipeline) do
build(:ci_empty_pipeline, project: project, build(:ci_empty_pipeline, project: project,
ref: 'master', ref: 'master',
......
...@@ -37,7 +37,7 @@ describe Gitlab::Ci::Config::External::File::Local do ...@@ -37,7 +37,7 @@ describe Gitlab::Ci::Config::External::File::Local do
end end
describe '#content' do describe '#content' do
context 'with a a valid file' do context 'with a valid file' do
let(:local_file_content) do let(:local_file_content) do
<<~HEREDOC <<~HEREDOC
before_script: before_script:
......
...@@ -93,7 +93,7 @@ describe Gitlab::Ci::Pipeline::Expression::Lexeme::String do ...@@ -93,7 +93,7 @@ describe Gitlab::Ci::Pipeline::Expression::Lexeme::String do
end end
describe '#evaluate' do describe '#evaluate' do
it 'returns string value it is is present' do it 'returns string value if it is present' do
string = described_class.new('my string') string = described_class.new('my string')
expect(string.evaluate).to eq 'my string' expect(string.evaluate).to eq 'my string'
......
...@@ -135,7 +135,7 @@ describe Gitlab::ContributionsCalendar do ...@@ -135,7 +135,7 @@ describe Gitlab::ContributionsCalendar do
expect(calendar(contributor).events_by_date(today)).to contain_exactly(e1, e2, e3) expect(calendar(contributor).events_by_date(today)).to contain_exactly(e1, e2, e3)
end end
context 'when the user cannot read read cross project' do context 'when the user cannot read cross project' do
before do before do
allow(Ability).to receive(:allowed?).and_call_original allow(Ability).to receive(:allowed?).and_call_original
expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
......
...@@ -50,7 +50,7 @@ describe Gitlab::CrossProjectAccess::CheckInfo do ...@@ -50,7 +50,7 @@ describe Gitlab::CrossProjectAccess::CheckInfo do
expect(info.should_run?(dummy_controller)).to be_truthy expect(info.should_run?(dummy_controller)).to be_truthy
end end
it 'returns the the opposite of #should_skip? when the check is a skip' do it 'returns the opposite of #should_skip? when the check is a skip' do
info = described_class.new({}, nil, nil, true) info = described_class.new({}, nil, nil, true)
expect(info).to receive(:should_skip?).with(dummy_controller).and_return(false) expect(info).to receive(:should_skip?).with(dummy_controller).and_return(false)
...@@ -101,7 +101,7 @@ describe Gitlab::CrossProjectAccess::CheckInfo do ...@@ -101,7 +101,7 @@ describe Gitlab::CrossProjectAccess::CheckInfo do
expect(info.should_skip?(dummy_controller)).to be_truthy expect(info.should_skip?(dummy_controller)).to be_truthy
end end
it 'returns the the opposite of #should_run? when the check is not a skip' do it 'returns the opposite of #should_run? when the check is not a skip' do
info = described_class.new({}, nil, nil, false) info = described_class.new({}, nil, nil, false)
expect(info).to receive(:should_run?).with(dummy_controller).and_return(false) expect(info).to receive(:should_run?).with(dummy_controller).and_return(false)
......
...@@ -165,7 +165,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : ...@@ -165,7 +165,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
end end
describe '#rename_namespace_dependencies' do describe '#rename_namespace_dependencies' do
it "moves the the repository for a project in the namespace" do it "moves the repository for a project in the namespace" do
create(:project, :repository, :legacy_storage, namespace: namespace, path: "the-path-project") create(:project, :repository, :legacy_storage, namespace: namespace, path: "the-path-project")
expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git") expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git")
......
...@@ -16,7 +16,7 @@ describe Gitlab::Diff::InlineDiffMarker do ...@@ -16,7 +16,7 @@ describe Gitlab::Diff::InlineDiffMarker do
end end
end end
context "when the text text is not html safe" do context "when the text is not html safe" do
let(:rich) { "abc 'def' differs" } let(:rich) { "abc 'def' differs" }
it 'marks the range' do it 'marks the range' do
......
...@@ -49,7 +49,7 @@ describe Gitlab::Email::ReplyParser do ...@@ -49,7 +49,7 @@ describe Gitlab::Email::ReplyParser do
expect(test_parse_body(fixture_file("emails/paragraphs.eml"))) expect(test_parse_body(fixture_file("emails/paragraphs.eml")))
.to eq( .to eq(
<<-BODY.strip_heredoc.chomp <<-BODY.strip_heredoc.chomp
Is there any reason the *old* candy can't be be kept in silos while the new candy Is there any reason the *old* candy can't be kept in silos while the new candy
is imported into *new* silos? is imported into *new* silos?
The thing about candy is it stays delicious for a long time -- we can just keep The thing about candy is it stays delicious for a long time -- we can just keep
......
...@@ -82,7 +82,7 @@ describe Gitlab::Git::MergeBase do ...@@ -82,7 +82,7 @@ describe Gitlab::Git::MergeBase do
end end
describe '#unknown_refs', :missing_ref do describe '#unknown_refs', :missing_ref do
it 'returns the the refs passed that are not part of the repository' do it 'returns the refs passed that are not part of the repository' do
expect(merge_base.unknown_refs).to contain_exactly('aaaa') expect(merge_base.unknown_refs).to contain_exactly('aaaa')
end end
......
...@@ -28,7 +28,7 @@ describe Gitlab::MultiCollectionPaginator do ...@@ -28,7 +28,7 @@ describe Gitlab::MultiCollectionPaginator do
expect(paginator.paginate(1)).to eq(all_projects.take(3)) expect(paginator.paginate(1)).to eq(all_projects.take(3))
end end
it 'fils the second page with a mixture of of the first & second collection' do it 'fils the second page with a mixture of the first & second collection' do
first_collection_element = all_projects.last first_collection_element = all_projects.last
second_collection_elements = all_groups.take(2) second_collection_elements = all_groups.take(2)
......
...@@ -45,11 +45,11 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do ...@@ -45,11 +45,11 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
is_expected.to eq(%w[redis database fog]) is_expected.to eq(%w[redis database fog])
end end
it 'returns redis store as the the lowest precedence' do it 'returns redis store as the lowest precedence' do
expect(subject.first).to eq('redis') expect(subject.first).to eq('redis')
end end
it 'returns fog store as the the highest precedence' do it 'returns fog store as the highest precedence' do
expect(subject.last).to eq('fog') expect(subject.last).to eq('fog')
end end
end end
......
...@@ -22,13 +22,13 @@ describe List do ...@@ -22,13 +22,13 @@ describe List do
end end
describe '#destroy' do describe '#destroy' do
it 'can be destroyed when when list_type is set to label' do it 'can be destroyed when list_type is set to label' do
subject = create(:list) subject = create(:list)
expect(subject.destroy).to be_truthy expect(subject.destroy).to be_truthy
end end
it 'can not be destroyed when when list_type is set to closed' do it 'can not be destroyed when list_type is set to closed' do
subject = create(:closed_list) subject = create(:closed_list)
expect(subject.destroy).to be_falsey expect(subject.destroy).to be_falsey
......
...@@ -70,7 +70,7 @@ describe Ci::PipelineSchedulePolicy, :models do ...@@ -70,7 +70,7 @@ describe Ci::PipelineSchedulePolicy, :models do
pipeline_schedule.update(owner: user) pipeline_schedule.update(owner: user)
end end
it 'includes abilities to do do all operations on pipeline schedule' do it 'includes abilities to do all operations on pipeline schedule' do
expect(policy).to be_allowed :play_pipeline_schedule expect(policy).to be_allowed :play_pipeline_schedule
expect(policy).to be_allowed :update_pipeline_schedule expect(policy).to be_allowed :update_pipeline_schedule
expect(policy).to be_allowed :admin_pipeline_schedule expect(policy).to be_allowed :admin_pipeline_schedule
...@@ -82,7 +82,7 @@ describe Ci::PipelineSchedulePolicy, :models do ...@@ -82,7 +82,7 @@ describe Ci::PipelineSchedulePolicy, :models do
project.add_maintainer(user) project.add_maintainer(user)
end end
it 'includes abilities to do do all operations on pipeline schedule' do it 'includes abilities to do all operations on pipeline schedule' do
expect(policy).to be_allowed :play_pipeline_schedule expect(policy).to be_allowed :play_pipeline_schedule
expect(policy).to be_allowed :update_pipeline_schedule expect(policy).to be_allowed :update_pipeline_schedule
expect(policy).to be_allowed :admin_pipeline_schedule expect(policy).to be_allowed :admin_pipeline_schedule
......
...@@ -223,7 +223,7 @@ describe ProjectPolicy do ...@@ -223,7 +223,7 @@ describe ProjectPolicy do
expect_disallowed(*other_write_abilities) expect_disallowed(*other_write_abilities)
end end
it 'does not disable other other abilities' do it 'does not disable other abilities' do
expect_allowed(*(regular_abilities - feature_write_abilities - other_write_abilities)) expect_allowed(*(regular_abilities - feature_write_abilities - other_write_abilities))
end end
end end
......
...@@ -534,7 +534,7 @@ describe API::Groups do ...@@ -534,7 +534,7 @@ describe API::Groups do
expect(json_response.first['visibility']).not_to be_present expect(json_response.first['visibility']).not_to be_present
end end
it 'filters the groups projects' do it "filters the groups projects" do
public_project = create(:project, :public, path: 'test1', group: group1) public_project = create(:project, :public, path: 'test1', group: group1)
get api("/groups/#{group1.id}/projects", user1), visibility: 'public' get api("/groups/#{group1.id}/projects", user1), visibility: 'public'
...@@ -546,6 +546,32 @@ describe API::Groups do ...@@ -546,6 +546,32 @@ describe API::Groups do
expect(json_response.first['name']).to eq(public_project.name) expect(json_response.first['name']).to eq(public_project.name)
end end
it "returns projects excluding shared" do
create(:project_group_link, project: create(:project), group: group1)
create(:project_group_link, project: create(:project), group: group1)
create(:project_group_link, project: create(:project), group: group1)
get api("/groups/#{group1.id}/projects", user1), with_shared: false
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(2)
end
it "returns projects including those in subgroups", :nested_groups do
subgroup = create(:group, parent: group1)
create(:project, group: subgroup)
create(:project, group: subgroup)
get api("/groups/#{group1.id}/projects", user1), include_subgroups: true
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(4)
end
it "does not return a non existing group" do it "does not return a non existing group" do
get api("/groups/1328/projects", user1) get api("/groups/1328/projects", user1)
......
...@@ -21,15 +21,20 @@ describe MergeRequests::BuildService do ...@@ -21,15 +21,20 @@ describe MergeRequests::BuildService do
let(:commit_2) { double(:commit_2, sha: 'f00ba7', safe_message: 'This is a bad commit message!') } let(:commit_2) { double(:commit_2, sha: 'f00ba7', safe_message: 'This is a bad commit message!') }
let(:commits) { nil } let(:commits) { nil }
let(:params) do
{
description: description,
source_branch: source_branch,
target_branch: target_branch,
source_project: source_project,
target_project: target_project,
milestone_id: milestone_id,
label_ids: label_ids
}
end
let(:service) do let(:service) do
described_class.new(project, user, described_class.new(project, user, params)
description: description,
source_branch: source_branch,
target_branch: target_branch,
source_project: source_project,
target_project: target_project,
milestone_id: milestone_id,
label_ids: label_ids)
end end
before do before do
...@@ -56,6 +61,19 @@ describe MergeRequests::BuildService do ...@@ -56,6 +61,19 @@ describe MergeRequests::BuildService do
merge_request merge_request
end end
it 'does not assign force_remove_source_branch' do
expect(merge_request.force_remove_source_branch?).to be_falsey
end
context 'with force_remove_source_branch parameter' do
let(:mr_params) { params.merge(force_remove_source_branch: '1') }
let(:merge_request) { described_class.new(project, user, mr_params).execute }
it 'assigns force_remove_source_branch' do
expect(merge_request.force_remove_source_branch?).to be_truthy
end
end
context 'missing source branch' do context 'missing source branch' do
let(:source_branch) { '' } let(:source_branch) { '' }
......
...@@ -95,7 +95,7 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do ...@@ -95,7 +95,7 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do
sha: '1234abcdef', status: 'success') sha: '1234abcdef', status: 'success')
end end
it 'it does not merge merge request' do it 'it does not merge request' do
expect(MergeWorker).not_to receive(:perform_async) expect(MergeWorker).not_to receive(:perform_async)
service.trigger(old_pipeline) service.trigger(old_pipeline)
end end
......
...@@ -7,7 +7,7 @@ describe Users::SetStatusService do ...@@ -7,7 +7,7 @@ describe Users::SetStatusService do
subject(:service) { described_class.new(current_user, params) } subject(:service) { described_class.new(current_user, params) }
describe '#execute' do describe '#execute' do
context 'when when params are set' do context 'when params are set' do
let(:params) { { emoji: 'taurus', message: 'a random status' } } let(:params) { { emoji: 'taurus', message: 'a random status' } }
it 'creates a status' do it 'creates a status' do
......
...@@ -123,7 +123,7 @@ module ExportFileHelper ...@@ -123,7 +123,7 @@ module ExportFileHelper
false false
end end
# Compares model attributes with those those found in the hash # Compares model attributes with those found in the hash
# and returns true if there is a match, ignoring some excluded attributes. # and returns true if there is a match, ignoring some excluded attributes.
def safe_model?(model, excluded_attributes, parent) def safe_model?(model, excluded_attributes, parent)
excluded_attributes += associations_for(model) excluded_attributes += associations_for(model)
......
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