Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
f8cda25d
Commit
f8cda25d
authored
Dec 19, 2017
by
Kamil Trzcinski
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin-ee/master' into ee-fix-cluster-enviroment-missing
parents
be0369a1
a45b739c
Changes
69
Show whitespace changes
Inline
Side-by-side
Showing
69 changed files
with
1339 additions
and
1317 deletions
+1339
-1317
.gitlab-ci.yml
.gitlab-ci.yml
+25
-20
app/assets/javascripts/boards/components/board_sidebar.js
app/assets/javascripts/boards/components/board_sidebar.js
+1
-1
app/assets/javascripts/boards/models/issue.js
app/assets/javascripts/boards/models/issue.js
+0
-1
app/assets/javascripts/diff_notes/components/diff_note_avatars.js
...ts/javascripts/diff_notes/components/diff_note_avatars.js
+2
-2
app/assets/javascripts/dispatcher.js
app/assets/javascripts/dispatcher.js
+3
-3
app/assets/javascripts/geo_nodes.js
app/assets/javascripts/geo_nodes.js
+2
-2
app/assets/javascripts/init_issuable_sidebar.js
app/assets/javascripts/init_issuable_sidebar.js
+2
-2
app/assets/javascripts/init_notes.js
app/assets/javascripts/init_notes.js
+4
-2
app/assets/javascripts/line_highlighter.js
app/assets/javascripts/line_highlighter.js
+1
-1
app/assets/javascripts/main.js
app/assets/javascripts/main.js
+0
-4
app/assets/javascripts/merge_request.js
app/assets/javascripts/merge_request.js
+128
-132
app/assets/javascripts/merge_request_tabs.js
app/assets/javascripts/merge_request_tabs.js
+2
-2
app/assets/javascripts/notes.js
app/assets/javascripts/notes.js
+6
-0
app/assets/javascripts/repo/components/repo_preview.vue
app/assets/javascripts/repo/components/repo_preview.vue
+1
-1
app/assets/javascripts/right_sidebar.js
app/assets/javascripts/right_sidebar.js
+220
-218
app/assets/javascripts/shortcuts_issuable.js
app/assets/javascripts/shortcuts_issuable.js
+2
-2
app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
...ts/vue_merge_request_widget/services/mr_widget_service.js
+1
-1
app/assets/stylesheets/framework/stacked-progress-bar.scss
app/assets/stylesheets/framework/stacked-progress-bar.scss
+3
-1
app/controllers/projects/merge_requests_controller.rb
app/controllers/projects/merge_requests_controller.rb
+6
-2
app/helpers/issuables_helper.rb
app/helpers/issuables_helper.rb
+2
-2
app/serializers/issuable_entity.rb
app/serializers/issuable_entity.rb
+0
-8
app/serializers/issuable_sidebar_entity.rb
app/serializers/issuable_sidebar_entity.rb
+1
-5
app/serializers/issue_entity.rb
app/serializers/issue_entity.rb
+8
-0
app/serializers/merge_request_serializer.rb
app/serializers/merge_request_serializer.rb
+3
-3
app/serializers/merge_request_widget_entity.rb
app/serializers/merge_request_widget_entity.rb
+2
-4
app/views/projects/merge_requests/show.html.haml
app/views/projects/merge_requests/show.html.haml
+1
-1
app/views/shared/empty_states/_issues.html.haml
app/views/shared/empty_states/_issues.html.haml
+7
-6
changelogs/unreleased-ee/4330-show-item-count-in-tooltip.yml
changelogs/unreleased-ee/4330-show-item-count-in-tooltip.yml
+5
-0
changelogs/unreleased/osw-isolate-mr-widget-exposed-attributes.yml
...s/unreleased/osw-isolate-mr-widget-exposed-attributes.yml
+5
-0
doc/articles/laravel_with_gitlab_and_envoy/index.md
doc/articles/laravel_with_gitlab_and_envoy/index.md
+1
-1
doc/workflow/repository_mirroring.md
doc/workflow/repository_mirroring.md
+65
-31
ee/app/serializers/ee/merge_request_widget_entity.rb
ee/app/serializers/ee/merge_request_widget_entity.rb
+1
-1
qa/qa.rb
qa/qa.rb
+21
-25
qa/qa/ee.rb
qa/qa/ee.rb
+6
-6
qa/qa/ee/factory/geo/node.rb
qa/qa/ee/factory/geo/node.rb
+3
-3
qa/qa/ee/factory/license.rb
qa/qa/ee/factory/license.rb
+19
-0
qa/qa/ee/scenario/license/add.rb
qa/qa/ee/scenario/license/add.rb
+0
-21
qa/qa/ee/scenario/test/geo.rb
qa/qa/ee/scenario/test/geo.rb
+3
-9
qa/qa/ee/strategy.rb
qa/qa/ee/strategy.rb
+1
-1
qa/qa/factory/base.rb
qa/qa/factory/base.rb
+16
-0
qa/qa/factory/repository/push.rb
qa/qa/factory/repository/push.rb
+45
-0
qa/qa/factory/resource/group.rb
qa/qa/factory/resource/group.rb
+23
-0
qa/qa/factory/resource/project.rb
qa/qa/factory/resource/project.rb
+40
-0
qa/qa/factory/resource/sandbox.rb
qa/qa/factory/resource/sandbox.rb
+28
-0
qa/qa/factory/settings/hashed_storage.rb
qa/qa/factory/settings/hashed_storage.rb
+22
-0
qa/qa/scenario/gitlab/admin/hashed_storage.rb
qa/qa/scenario/gitlab/admin/hashed_storage.rb
+0
-24
qa/qa/scenario/gitlab/group/create.rb
qa/qa/scenario/gitlab/group/create.rb
+0
-27
qa/qa/scenario/gitlab/project/create.rb
qa/qa/scenario/gitlab/project/create.rb
+0
-42
qa/qa/scenario/gitlab/repository/push.rb
qa/qa/scenario/gitlab/repository/push.rb
+0
-47
qa/qa/scenario/gitlab/sandbox/prepare.rb
qa/qa/scenario/gitlab/sandbox/prepare.rb
+0
-28
qa/qa/specs/features/ee/geo/replication_spec.rb
qa/qa/specs/features/ee/geo/replication_spec.rb
+3
-3
qa/qa/specs/features/project/create_spec.rb
qa/qa/specs/features/project/create_spec.rb
+1
-1
qa/qa/specs/features/repository/clone_spec.rb
qa/qa/specs/features/repository/clone_spec.rb
+1
-1
qa/qa/specs/features/repository/push_spec.rb
qa/qa/specs/features/repository/push_spec.rb
+2
-2
spec/controllers/projects/merge_requests_controller_spec.rb
spec/controllers/projects/merge_requests_controller_spec.rb
+4
-4
spec/ee/spec/serializers/epic_entity_spec.rb
spec/ee/spec/serializers/epic_entity_spec.rb
+1
-2
spec/ee/spec/serializers/merge_request_widget_entity_spec.rb
spec/ee/spec/serializers/merge_request_widget_entity_spec.rb
+1
-1
spec/features/issues_spec.rb
spec/features/issues_spec.rb
+538
-514
spec/features/merge_requests/mini_pipeline_graph_spec.rb
spec/features/merge_requests/mini_pipeline_graph_spec.rb
+4
-4
spec/fixtures/api/schemas/entities/merge_request_widget.json
spec/fixtures/api/schemas/entities/merge_request_widget.json
+4
-4
spec/javascripts/collapsed_sidebar_todo_spec.js
spec/javascripts/collapsed_sidebar_todo_spec.js
+1
-2
spec/javascripts/line_highlighter_spec.js
spec/javascripts/line_highlighter_spec.js
+1
-2
spec/javascripts/merge_request_notes_spec.js
spec/javascripts/merge_request_notes_spec.js
+1
-3
spec/javascripts/merge_request_spec.js
spec/javascripts/merge_request_spec.js
+1
-2
spec/javascripts/merge_request_tabs_spec.js
spec/javascripts/merge_request_tabs_spec.js
+9
-10
spec/javascripts/notes_spec.js
spec/javascripts/notes_spec.js
+1
-3
spec/javascripts/right_sidebar_spec.js
spec/javascripts/right_sidebar_spec.js
+1
-2
spec/serializers/merge_request_serializer_spec.rb
spec/serializers/merge_request_serializer_spec.rb
+27
-21
spec/serializers/merge_request_widget_entity_spec.rb
spec/serializers/merge_request_widget_entity_spec.rb
+1
-44
No files found.
.gitlab-ci.yml
View file @
f8cda25d
image
:
"
dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-chrome-62.0-node-8.x-yarn-1.2-postgresql-9.6"
.dedicated-runner
:
&dedicated-runner
retry
:
1
tags
:
-
gitlab-org
.default-cache
:
&default-cache
key
:
"
ruby-235-with-yarn"
paths
:
...
...
@@ -18,7 +23,6 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git
variables
:
MYSQL_ALLOW_EMPTY_PASSWORD
:
"
1"
ELASTIC_URL
:
"
http://elastic:changeme@docker.elastic.co-elasticsearch-elasticsearch:9200"
RAILS_ENV
:
"
test"
NODE_ENV
:
"
test"
SIMPLECOV
:
"
true"
...
...
@@ -28,8 +32,10 @@ variables:
KNAPSACK_RSPEC_SUITE_REPORT_PATH
:
knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
KNAPSACK_SPINACH_SUITE_REPORT_PATH
:
knapsack/${CI_PROJECT_NAME}/spinach_report-master.json
FLAKY_RSPEC_SUITE_REPORT_PATH
:
rspec_flaky/report-suite.json
## EE specific variables ##
# This hack is needed to make ES not that memory hungry
ES_JAVA_OPTS
:
"
-Xms256m
-Xmx256m"
ELASTIC_URL
:
"
http://elastic:changeme@docker.elastic.co-elasticsearch-elasticsearch:9200"
before_script
:
-
bundle --version
...
...
@@ -45,11 +51,6 @@ stages:
-
post-cleanup
# Predefined scopes
.dedicated-runner
:
&dedicated-runner
retry
:
1
tags
:
-
gitlab-org
.tests-metadata-state
:
&tests-metadata-state
<<
:
*dedicated-runner
variables
:
...
...
@@ -89,8 +90,8 @@ stages:
.rspec-metadata
:
&rspec-metadata
<<
:
*dedicated-runner
<<
:
*pull-cache
<<
:
*except-docs
<<
:
*pull-cache
stage
:
test
script
:
-
JOB_NAME=( $CI_JOB_NAME )
...
...
@@ -138,8 +139,8 @@ stages:
.spinach-metadata
:
&spinach-metadata
<<
:
*dedicated-runner
<<
:
*pull-cache
<<
:
*except-docs
<<
:
*pull-cache
stage
:
test
script
:
-
JOB_NAME=( $CI_JOB_NAME )
...
...
@@ -178,6 +179,7 @@ stages:
# Trigger a package build in omnibus-gitlab repository
#
package-qa
:
<<
:
*dedicated-runner
image
:
ruby:2.4-alpine
before_script
:
[]
stage
:
build
...
...
@@ -191,6 +193,7 @@ package-qa:
# Review docs base
.review-docs
:
&review-docs
<<
:
*dedicated-runner
image
:
ruby:2.4-alpine
before_script
:
-
gem install gitlab --no-doc
...
...
@@ -297,9 +300,9 @@ flaky-examples-check:
-
scripts/detect-new-flaky-examples $NEW_FLAKY_SPECS_REPORT
setup-test-env
:
<<
:
*use-pg
<<
:
*dedicated-runner
<<
:
*except-docs
<<
:
*use-pg
stage
:
prepare
cache
:
<<
:
*default-cache
...
...
@@ -390,18 +393,18 @@ spinach-mysql 3 4: *spinach-metadata-mysql
SETUP_DB
:
"
false"
.rake-exec
:
&rake-exec
<<
:
*ruby-static-analysis
<<
:
*dedicated-runner
<<
:
*except-docs
<<
:
*pull-cache
<<
:
*ruby-static-analysis
stage
:
test
script
:
-
bundle exec rake $CI_JOB_NAME
static-analysis
:
<<
:
*ruby-static-analysis
<<
:
*dedicated-runner
<<
:
*except-docs
<<
:
*ruby-static-analysis
stage
:
test
script
:
-
scripts/static-analysis
...
...
@@ -467,10 +470,16 @@ db:migrate:reset-mysql:
<<
:
*db-migrate-reset
<<
:
*use-mysql
db:check-schema-pg:
<<
:
*db-migrate-reset
<<
:
*use-pg
script
:
-
source scripts/schema_changed.sh
.migration-paths
:
&migration-paths
<<
:
*dedicated-runner
<<
:
*pull-cache
<<
:
*except-docs
<<
:
*pull-cache
stage
:
test
variables
:
SETUP_DB
:
"
false"
...
...
@@ -538,12 +547,6 @@ db:seed_fu-mysql:
<<
:
*db-seed_fu
<<
:
*use-mysql
db:check-schema-pg:
<<
:
*db-migrate-reset
<<
:
*use-pg
script
:
-
sh scripts/schema_changed.sh
# Frontend-related jobs
gitlab:assets:compile:
<<
:
*dedicated-runner
...
...
@@ -568,10 +571,10 @@ gitlab:assets:compile:
-
webpack-report/
karma
:
<<
:
*use-pg
<<
:
*dedicated-runner
<<
:
*except-docs
<<
:
*pull-cache
<<
:
*use-pg
stage
:
test
variables
:
BABEL_ENV
:
"
coverage"
...
...
@@ -610,6 +613,7 @@ codequality:
paths
:
[
codeclimate.json
]
qa:internal:
<<
:
*dedicated-runner
<<
:
*except-docs
stage
:
test
variables
:
...
...
@@ -699,8 +703,9 @@ cache gems:
-
master@gitlab-org/gitlab-ee
gitlab_git_test
:
<<
:
*
pull-cache
<<
:
*
dedicated-runner
<<
:
*except-docs
<<
:
*pull-cache
variables
:
SETUP_DB
:
"
false"
script
:
...
...
app/assets/javascripts/boards/components/board_sidebar.js
View file @
f8cda25d
/* eslint-disable comma-dangle, space-before-function-paren, no-new */
/* global MilestoneSelect */
/* global Sidebar */
import
Vue
from
'
vue
'
;
import
weight
from
'
ee/sidebar/components/weight/weight.vue
'
;
import
Flash
from
'
../../flash
'
;
import
Sidebar
from
'
../../right_sidebar
'
;
import
eventHub
from
'
../../sidebar/event_hub
'
;
import
assigneeTitle
from
'
../../sidebar/components/assignees/assignee_title
'
;
import
assignees
from
'
../../sidebar/components/assignees/assignees
'
;
...
...
app/assets/javascripts/boards/models/issue.js
View file @
f8cda25d
...
...
@@ -25,7 +25,6 @@ class ListIssue {
this
.
isLoading
=
{
weight
:
false
,
};
this
.
isLoading
=
{};
this
.
sidebarInfoEndpoint
=
obj
.
issue_sidebar_endpoint
;
this
.
toggleSubscriptionEndpoint
=
obj
.
toggle_subscription_endpoint
;
this
.
milestone_id
=
obj
.
milestone_id
;
...
...
app/assets/javascripts/diff_notes/components/diff_note_avatars.js
View file @
f8cda25d
/* global CommentsStore */
/* global notes */
import
Vue
from
'
vue
'
;
import
collapseIcon
from
'
../icons/collapse_icon.svg
'
;
import
Notes
from
'
../../notes
'
;
import
userAvatarImage
from
'
../../vue_shared/components/user_avatar/user_avatar_image.vue
'
;
const
DiffNoteAvatars
=
Vue
.
extend
({
...
...
@@ -129,7 +129,7 @@ const DiffNoteAvatars = Vue.extend({
},
methods
:
{
clickedAvatar
(
e
)
{
notes
.
onAddDiffNote
(
e
);
Notes
.
instance
.
onAddDiffNote
(
e
);
// Toggle the active state of the toggle all button
this
.
toggleDiscussionsToggleState
();
...
...
app/assets/javascripts/dispatcher.js
View file @
f8cda25d
...
...
@@ -11,7 +11,7 @@ import NewBranchForm from './new_branch_form';
/* global NotificationsDropdown */
import
groupAvatar
from
'
./group_avatar
'
;
import
GroupLabelSubscription
from
'
./group_label_subscription
'
;
/* global LineHighlighter */
import
LineHighlighter
from
'
./line_highlighter
'
;
import
BuildArtifacts
from
'
./build_artifacts
'
;
import
CILintEditor
from
'
./ci_lint_editor
'
;
import
groupsSelect
from
'
./groups_select
'
;
...
...
@@ -21,7 +21,7 @@ import NamespaceSelect from './namespace_select';
import
NewCommitForm
from
'
./new_commit_form
'
;
import
Project
from
'
./project
'
;
import
projectAvatar
from
'
./project_avatar
'
;
/* global MergeRequest */
import
MergeRequest
from
'
./merge_request
'
;
import
Compare
from
'
./compare
'
;
import
initCompareAutocomplete
from
'
./compare_autocomplete
'
;
/* global PathLocks */
...
...
@@ -30,7 +30,7 @@ import ProjectNew from './project_new';
import
projectImport
from
'
./project_import
'
;
import
Labels
from
'
./labels
'
;
import
LabelManager
from
'
./label_manager
'
;
/* global Sidebar */
import
Sidebar
from
'
./right_sidebar
'
;
/* global WeightSelect */
/* global AdminEmailSelect */
...
...
app/assets/javascripts/geo_nodes.js
View file @
f8cda25d
...
...
@@ -104,8 +104,8 @@ class GeoNodeStatus {
graphItems
.
forEach
((
item
)
=>
{
$itemEl
.
find
(
item
.
itemSel
)
.
toggleClass
(
'
has-value has-tooltip
'
,
!!
item
.
itemCount
)
.
attr
(
'
data-original-title
'
,
`
${
item
.
itemTooltip
}
:
${
item
.
item
Percent
}
%
`
)
.
text
(
item
.
itemCount
||
''
)
.
attr
(
'
data-original-title
'
,
`
${
item
.
itemTooltip
}
:
${
item
.
item
Count
}
`
)
.
text
(
`
${
item
.
itemPercent
}
%`
||
''
)
.
css
(
'
width
'
,
`
${
item
.
itemPercent
}
%`
);
});
}
...
...
app/assets/javascripts/init_issuable_sidebar.js
View file @
f8cda25d
...
...
@@ -3,7 +3,7 @@
/* global WeightSelect */
import
LabelsSelect
from
'
./labels_select
'
;
import
IssuableContext
from
'
./issuable_context
'
;
/* global Sidebar */
import
Sidebar
from
'
./right_sidebar
'
;
import
DueDateSelectors
from
'
./due_date_select
'
;
...
...
@@ -17,5 +17,5 @@ export default () => {
new
WeightSelect
();
new
IssuableContext
(
sidebarOptions
.
currentUser
);
new
DueDateSelectors
();
window
.
sidebar
=
new
Sidebar
();
Sidebar
.
initialize
();
};
app/assets/javascripts/init_notes.js
View file @
f8cda25d
/* global Notes */
import
Notes
from
'
./notes
'
;
export
default
()
=>
{
const
dataEl
=
document
.
querySelector
(
'
.js-notes-data
'
);
...
...
@@ -10,5 +10,7 @@ export default () => {
autocomplete
,
}
=
JSON
.
parse
(
dataEl
.
innerHTML
);
window
.
notes
=
new
Notes
(
notesUrl
,
notesIds
,
now
,
diffView
,
autocomplete
);
// Create a singleton so that we don't need to assign
// into the window object, we can just access the current isntance with Notes.instance
Notes
.
initialize
(
notesUrl
,
notesIds
,
now
,
diffView
,
autocomplete
);
};
app/assets/javascripts/line_highlighter.js
View file @
f8cda25d
...
...
@@ -175,4 +175,4 @@ LineHighlighter.prototype.__setLocationHash__ = function(value) {
},
document
.
title
,
value
);
};
window
.
LineHighlighter
=
LineHighlighter
;
export
default
LineHighlighter
;
app/assets/javascripts/main.js
View file @
f8cda25d
...
...
@@ -50,10 +50,7 @@ import './layout_nav';
import
LazyLoader
from
'
./lazy_loader
'
;
import
'
./line_highlighter
'
;
import
initLogoAnimation
from
'
./logo
'
;
import
'
./merge_request
'
;
import
'
./merge_request_tabs
'
;
import
'
./milestone_select
'
;
import
'
./notes
'
;
import
'
./notifications_dropdown
'
;
import
'
./notifications_form
'
;
import
'
./pager
'
;
...
...
@@ -61,7 +58,6 @@ import './preview_markdown';
import
'
./project_import
'
;
import
'
./projects_dropdown
'
;
import
'
./render_gfm
'
;
import
'
./right_sidebar
'
;
import
initBreadcrumbs
from
'
./breadcrumb
'
;
// EE-only scripts
...
...
app/assets/javascripts/merge_request.js
View file @
f8cda25d
...
...
@@ -7,9 +7,7 @@ import './merge_request_tabs';
import
IssuablesHelper
from
'
./helpers/issuables_helper
'
;
import
{
addDelimiter
}
from
'
./lib/utils/text_utility
'
;
(
function
()
{
this
.
MergeRequest
=
(
function
()
{
function
MergeRequest
(
opts
)
{
function
MergeRequest
(
opts
)
{
// Initialize MergeRequest behavior
//
// Options:
...
...
@@ -40,26 +38,26 @@ import { addDelimiter } from './lib/utils/text_utility';
}
});
}
}
}
// Local jQuery finder
MergeRequest
.
prototype
.
$
=
function
(
selector
)
{
// Local jQuery finder
MergeRequest
.
prototype
.
$
=
function
(
selector
)
{
return
this
.
$el
.
find
(
selector
);
};
};
MergeRequest
.
prototype
.
initTabs
=
function
()
{
MergeRequest
.
prototype
.
initTabs
=
function
()
{
if
(
window
.
mrTabs
)
{
window
.
mrTabs
.
unbindEvents
();
}
window
.
mrTabs
=
new
gl
.
MergeRequestTabs
(
this
.
opts
);
};
};
MergeRequest
.
prototype
.
showAllCommits
=
function
()
{
MergeRequest
.
prototype
.
showAllCommits
=
function
()
{
this
.
$
(
'
.first-commits
'
).
remove
();
return
this
.
$
(
'
.all-commits
'
).
removeClass
(
'
hide
'
);
};
};
MergeRequest
.
prototype
.
initMRBtnListeners
=
function
()
{
MergeRequest
.
prototype
.
initMRBtnListeners
=
function
()
{
var
_this
;
_this
=
this
;
return
$
(
'
a.btn-close, a.btn-reopen
'
).
on
(
'
click
'
,
function
(
e
)
{
...
...
@@ -81,9 +79,9 @@ import { addDelimiter } from './lib/utils/text_utility';
}
}
});
};
};
MergeRequest
.
prototype
.
submitNoteForm
=
function
(
form
,
$button
)
{
MergeRequest
.
prototype
.
submitNoteForm
=
function
(
form
,
$button
)
{
var
noteText
;
noteText
=
form
.
find
(
"
textarea.js-note-text
"
).
val
();
if
(
noteText
.
trim
().
length
>
0
)
{
...
...
@@ -91,9 +89,9 @@ import { addDelimiter } from './lib/utils/text_utility';
$button
.
data
(
'
submitted
'
,
true
);
return
$button
.
trigger
(
'
click
'
);
}
};
};
MergeRequest
.
prototype
.
initCommitMessageListeners
=
function
()
{
MergeRequest
.
prototype
.
initCommitMessageListeners
=
function
()
{
$
(
document
).
on
(
'
click
'
,
'
a.js-with-description-link
'
,
function
(
e
)
{
var
textarea
=
$
(
'
textarea.js-commit-message
'
);
e
.
preventDefault
();
...
...
@@ -111,24 +109,24 @@ import { addDelimiter } from './lib/utils/text_utility';
$
(
'
.js-with-description-hint
'
).
show
();
$
(
'
.js-without-description-hint
'
).
hide
();
});
};
};
MergeRequest
.
prototype
.
updateStatusText
=
function
(
classToRemove
,
classToAdd
,
newStatusText
)
{
MergeRequest
.
prototype
.
updateStatusText
=
function
(
classToRemove
,
classToAdd
,
newStatusText
)
{
$
(
'
.detail-page-header .status-box
'
)
.
removeClass
(
classToRemove
)
.
addClass
(
classToAdd
)
.
find
(
'
span
'
)
.
text
(
newStatusText
);
};
};
MergeRequest
.
prototype
.
decreaseCounter
=
function
(
by
=
1
)
{
MergeRequest
.
prototype
.
decreaseCounter
=
function
(
by
=
1
)
{
const
$el
=
$
(
'
.nav-links .js-merge-counter
'
);
const
count
=
Math
.
max
((
parseInt
(
$el
.
text
().
replace
(
/
[^\d]
/
,
''
),
10
)
-
by
),
0
);
$el
.
text
(
addDelimiter
(
count
));
};
};
MergeRequest
.
prototype
.
hideCloseButton
=
function
()
{
MergeRequest
.
prototype
.
hideCloseButton
=
function
()
{
const
el
=
document
.
querySelector
(
'
.merge-request .js-issuable-actions
'
);
const
closeDropdownItem
=
el
.
querySelector
(
'
li.close-item
'
);
if
(
closeDropdownItem
)
{
...
...
@@ -141,8 +139,6 @@ import { addDelimiter } from './lib/utils/text_utility';
}
// Dropdown for mobile screen
el
.
querySelector
(
'
li.js-close-item
'
).
classList
.
add
(
'
hidden
'
);
};
};
return
MergeRequest
;
})();
}).
call
(
window
);
export
default
MergeRequest
;
app/assets/javascripts/merge_request_tabs.js
View file @
f8cda25d
/* eslint-disable no-new, class-methods-use-this */
/* global notes */
import
Cookies
from
'
js-cookie
'
;
import
Flash
from
'
./flash
'
;
...
...
@@ -16,6 +15,7 @@ import initDiscussionTab from './image_diff/init_discussion_tab';
import
Diff
from
'
./diff
'
;
import
{
localTimeAgo
}
from
'
./lib/utils/datetime_utility
'
;
import
syntaxHighlight
from
'
./syntax_highlight
'
;
import
Notes
from
'
./notes
'
;
/* eslint-disable max-len */
// MergeRequestTabs
...
...
@@ -325,7 +325,7 @@ import syntaxHighlight from './syntax_highlight';
if
(
anchor
&&
anchor
.
length
>
0
)
{
const
notesContent
=
anchor
.
closest
(
'
.notes_content
'
);
const
lineType
=
notesContent
.
hasClass
(
'
new
'
)
?
'
new
'
:
'
old
'
;
notes
.
toggleDiffNote
({
Notes
.
instance
.
toggleDiffNote
({
target
:
anchor
,
lineType
,
forceShow
:
true
,
...
...
app/assets/javascripts/notes.js
View file @
f8cda25d
...
...
@@ -37,6 +37,12 @@ const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const
REGEX_QUICK_ACTIONS
=
/^
\/\w
+.*$/gm
;
export
default
class
Notes
{
static
initialize
(
notes_url
,
note_ids
,
last_fetched_at
,
view
,
enableGFM
=
true
)
{
if
(
!
this
.
instance
)
{
this
.
instance
=
new
Notes
(
notes_url
,
note_ids
,
last_fetched_at
,
view
,
enableGFM
);
}
}
constructor
(
notes_url
,
note_ids
,
last_fetched_at
,
view
,
enableGFM
=
true
)
{
this
.
updateTargetButtons
=
this
.
updateTargetButtons
.
bind
(
this
);
this
.
updateComment
=
this
.
updateComment
.
bind
(
this
);
...
...
app/assets/javascripts/repo/components/repo_preview.vue
View file @
f8cda25d
<
script
>
/* global LineHighlighter */
import
{
mapGetters
}
from
'
vuex
'
;
import
LineHighlighter
from
'
../../line_highlighter
'
;
import
syntaxHighlight
from
'
../../syntax_highlight
'
;
export
default
{
...
...
app/assets/javascripts/right_sidebar.js
View file @
f8cda25d
...
...
@@ -3,25 +3,29 @@
import
_
from
'
underscore
'
;
import
Cookies
from
'
js-cookie
'
;
(
function
()
{
this
.
Sidebar
=
(
function
()
{
function
Sidebar
(
currentUser
)
{
function
Sidebar
(
currentUser
)
{
this
.
toggleTodo
=
this
.
toggleTodo
.
bind
(
this
);
this
.
sidebar
=
$
(
'
aside
'
);
this
.
removeListeners
();
this
.
addEventListeners
();
}
Sidebar
.
initialize
=
function
(
currentUser
)
{
if
(
!
this
.
instance
)
{
this
.
instance
=
new
Sidebar
(
currentUser
);
}
};
Sidebar
.
prototype
.
removeListeners
=
function
()
{
Sidebar
.
prototype
.
removeListeners
=
function
()
{
this
.
sidebar
.
off
(
'
click
'
,
'
.sidebar-collapsed-icon
'
);
this
.
sidebar
.
off
(
'
hidden.gl.dropdown
'
);
$
(
'
.dropdown
'
).
off
(
'
loading.gl.dropdown
'
);
$
(
'
.dropdown
'
).
off
(
'
loaded.gl.dropdown
'
);
$
(
document
).
off
(
'
click
'
,
'
.js-sidebar-toggle
'
);
};
};
Sidebar
.
prototype
.
addEventListeners
=
function
()
{
Sidebar
.
prototype
.
addEventListeners
=
function
()
{
const
$document
=
$
(
document
);
this
.
sidebar
.
on
(
'
click
'
,
'
.sidebar-collapsed-icon
'
,
this
,
this
.
sidebarCollapseClicked
);
...
...
@@ -31,9 +35,9 @@ import Cookies from 'js-cookie';
$document
.
on
(
'
click
'
,
'
.js-sidebar-toggle
'
,
this
.
sidebarToggleClicked
);
return
$
(
document
).
off
(
'
click
'
,
'
.js-issuable-todo
'
).
on
(
'
click
'
,
'
.js-issuable-todo
'
,
this
.
toggleTodo
);
};
};
Sidebar
.
prototype
.
sidebarToggleClicked
=
function
(
e
,
triggered
)
{
Sidebar
.
prototype
.
sidebarToggleClicked
=
function
(
e
,
triggered
)
{
var
$allGutterToggleIcons
,
$this
,
$thisIcon
;
e
.
preventDefault
();
$this
=
$
(
this
);
...
...
@@ -53,9 +57,9 @@ import Cookies from 'js-cookie';
if
(
!
triggered
)
{
Cookies
.
set
(
"
collapsed_gutter
"
,
$
(
'
.right-sidebar
'
).
hasClass
(
'
right-sidebar-collapsed
'
));
}
};
};
Sidebar
.
prototype
.
toggleTodo
=
function
(
e
)
{
Sidebar
.
prototype
.
toggleTodo
=
function
(
e
)
{
var
$btnText
,
$this
,
$todoLoading
,
ajaxType
,
url
;
$this
=
$
(
e
.
currentTarget
);
ajaxType
=
$this
.
attr
(
'
data-delete-path
'
)
?
'
DELETE
'
:
'
POST
'
;
...
...
@@ -86,9 +90,9 @@ import Cookies from 'js-cookie';
return
_this
.
todoUpdateDone
(
data
);
};
})(
this
));
};
};
Sidebar
.
prototype
.
todoUpdateDone
=
function
(
data
)
{
Sidebar
.
prototype
.
todoUpdateDone
=
function
(
data
)
{
const
deletePath
=
data
.
delete_path
?
data
.
delete_path
:
null
;
const
attrPrefix
=
deletePath
?
'
mark
'
:
'
todo
'
;
const
$todoBtns
=
$
(
'
.js-issuable-todo
'
);
...
...
@@ -115,9 +119,9 @@ import Cookies from 'js-cookie';
$elText
.
text
(
$el
.
data
(
`
${
attrPrefix
}
-text`
));
}
});
};
};
Sidebar
.
prototype
.
sidebarDropdownLoading
=
function
(
e
)
{
Sidebar
.
prototype
.
sidebarDropdownLoading
=
function
(
e
)
{
var
$loading
,
$sidebarCollapsedIcon
,
i
,
img
;
$sidebarCollapsedIcon
=
$
(
this
).
closest
(
'
.block
'
).
find
(
'
.sidebar-collapsed-icon
'
);
img
=
$sidebarCollapsedIcon
.
find
(
'
img
'
);
...
...
@@ -130,9 +134,9 @@ import Cookies from 'js-cookie';
i
.
before
(
$loading
);
return
i
.
hide
();
}
};
};
Sidebar
.
prototype
.
sidebarDropdownLoaded
=
function
(
e
)
{
Sidebar
.
prototype
.
sidebarDropdownLoaded
=
function
(
e
)
{
var
$sidebarCollapsedIcon
,
i
,
img
;
$sidebarCollapsedIcon
=
$
(
this
).
closest
(
'
.block
'
).
find
(
'
.sidebar-collapsed-icon
'
);
img
=
$sidebarCollapsedIcon
.
find
(
'
img
'
);
...
...
@@ -143,9 +147,9 @@ import Cookies from 'js-cookie';
}
else
{
return
i
.
show
();
}
};
};
Sidebar
.
prototype
.
sidebarCollapseClicked
=
function
(
e
)
{
Sidebar
.
prototype
.
sidebarCollapseClicked
=
function
(
e
)
{
var
$block
,
sidebar
;
if
(
$
(
e
.
currentTarget
).
hasClass
(
'
dont-change-state
'
))
{
return
;
...
...
@@ -154,9 +158,9 @@ import Cookies from 'js-cookie';
e
.
preventDefault
();
$block
=
$
(
this
).
closest
(
'
.block
'
);
return
sidebar
.
openDropdown
(
$block
);
};
};
Sidebar
.
prototype
.
openDropdown
=
function
(
blockOrName
)
{
Sidebar
.
prototype
.
openDropdown
=
function
(
blockOrName
)
{
var
$block
;
$block
=
_
.
isString
(
blockOrName
)
?
this
.
getBlock
(
blockOrName
)
:
blockOrName
;
if
(
!
this
.
isOpen
())
{
...
...
@@ -169,34 +173,34 @@ import Cookies from 'js-cookie';
setTimeout
(()
=>
{
$block
.
find
(
'
.js-sidebar-dropdown-toggle
'
).
trigger
(
'
click
'
);
});
};
};
Sidebar
.
prototype
.
setCollapseAfterUpdate
=
function
(
$block
)
{
Sidebar
.
prototype
.
setCollapseAfterUpdate
=
function
(
$block
)
{
$block
.
addClass
(
'
collapse-after-update
'
);
return
$
(
'
.layout-page
'
).
addClass
(
'
with-overlay
'
);
};
};
Sidebar
.
prototype
.
onSidebarDropdownHidden
=
function
(
e
)
{
Sidebar
.
prototype
.
onSidebarDropdownHidden
=
function
(
e
)
{
var
$block
,
sidebar
;
sidebar
=
e
.
data
;
e
.
preventDefault
();
$block
=
$
(
e
.
target
).
closest
(
'
.block
'
);
return
sidebar
.
sidebarDropdownHidden
(
$block
);
};
};
Sidebar
.
prototype
.
sidebarDropdownHidden
=
function
(
$block
)
{
Sidebar
.
prototype
.
sidebarDropdownHidden
=
function
(
$block
)
{
if
(
$block
.
hasClass
(
'
collapse-after-update
'
))
{
$block
.
removeClass
(
'
collapse-after-update
'
);
$
(
'
.layout-page
'
).
removeClass
(
'
with-overlay
'
);
return
this
.
toggleSidebar
(
'
hide
'
);
}
};
};
Sidebar
.
prototype
.
triggerOpenSidebar
=
function
()
{
Sidebar
.
prototype
.
triggerOpenSidebar
=
function
()
{
return
this
.
sidebar
.
find
(
'
.js-sidebar-toggle
'
).
trigger
(
'
click
'
);
};
};
Sidebar
.
prototype
.
toggleSidebar
=
function
(
action
)
{
Sidebar
.
prototype
.
toggleSidebar
=
function
(
action
)
{
if
(
action
==
null
)
{
action
=
'
toggle
'
;
}
...
...
@@ -213,16 +217,14 @@ import Cookies from 'js-cookie';
return
this
.
triggerOpenSidebar
();
}
}
};
};
Sidebar
.
prototype
.
isOpen
=
function
()
{
Sidebar
.
prototype
.
isOpen
=
function
()
{
return
this
.
sidebar
.
is
(
'
.right-sidebar-expanded
'
);
};
};
Sidebar
.
prototype
.
getBlock
=
function
(
name
)
{
Sidebar
.
prototype
.
getBlock
=
function
(
name
)
{
return
this
.
sidebar
.
find
(
"
.block.
"
+
name
);
};
};
return
Sidebar
;
})();
}).
call
(
window
);
export
default
Sidebar
;
app/assets/javascripts/shortcuts_issuable.js
View file @
f8cda25d
/* global Mousetrap */
/* global sidebar */
import
_
from
'
underscore
'
;
import
'
mousetrap
'
;
import
Sidebar
from
'
./right_sidebar
'
;
import
ShortcutsNavigation
from
'
./shortcuts_navigation
'
;
import
{
CopyAsGFM
}
from
'
./behaviors/copy_as_gfm
'
;
...
...
@@ -69,7 +69,7 @@ export default class ShortcutsIssuable extends ShortcutsNavigation {
}
static
openSidebarDropdown
(
name
)
{
sidebar
.
openDropdown
(
name
);
Sidebar
.
instance
.
openDropdown
(
name
);
return
false
;
}
}
app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
View file @
f8cda25d
...
...
@@ -6,7 +6,7 @@ Vue.use(VueResource);
export
default
class
MRWidgetService
{
constructor
(
endpoints
)
{
this
.
mergeResource
=
Vue
.
resource
(
endpoints
.
mergePath
);
this
.
mergeCheckResource
=
Vue
.
resource
(
endpoints
.
statusPath
);
this
.
mergeCheckResource
=
Vue
.
resource
(
`
${
endpoints
.
statusPath
}
?serializer=widget`
);
this
.
cancelAutoMergeResource
=
Vue
.
resource
(
endpoints
.
cancelAutoMergePath
);
this
.
removeWIPResource
=
Vue
.
resource
(
endpoints
.
removeWIPPath
);
this
.
removeSourceBranchResource
=
Vue
.
resource
(
endpoints
.
sourceBranchPath
);
...
...
app/assets/stylesheets/framework/stacked-progress-bar.scss
View file @
f8cda25d
...
...
@@ -11,12 +11,14 @@
.status-neutral
,
.status-red
,
{
height
:
100%
;
font-size
:
$tooltip-font-size
;
font-weight
:
normal
;
color
:
$white-light
;
line-height
:
20px
;
&
.has-value
{
padding
:
0
10px
;
min-width
:
25px
;
padding
:
0
5px
;
}
&
:hover
{
...
...
app/controllers/projects/merge_requests_controller.rb
View file @
f8cda25d
...
...
@@ -133,7 +133,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
.
new
(
project
,
current_user
,
wip_event:
'unwip'
)
.
execute
(
@merge_request
)
render
json:
serialize
r
.
represen
t
(
@merge_request
)
render
json:
serialize
_widge
t
(
@merge_request
)
end
def
commit_change_content
...
...
@@ -149,7 +149,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
.
new
(
@project
,
current_user
)
.
cancel
(
@merge_request
)
render
json:
serialize
r
.
represen
t
(
@merge_request
)
render
json:
serialize
_widge
t
(
@merge_request
)
end
def
merge
...
...
@@ -313,6 +313,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
end
def
serialize_widget
(
merge_request
)
serializer
.
represent
(
merge_request
,
serializer:
'widget'
)
end
def
serializer
MergeRequestSerializer
.
new
(
current_user:
current_user
,
project:
merge_request
.
project
)
end
...
...
app/helpers/issuables_helper.rb
View file @
f8cda25d
...
...
@@ -32,7 +32,7 @@ module IssuablesHelper
end
end
def
serialize_issuable
(
issuable
)
def
serialize_issuable
(
issuable
,
serializer:
nil
)
serializer_klass
=
case
issuable
when
Issue
IssueSerializer
...
...
@@ -42,7 +42,7 @@ module IssuablesHelper
serializer_klass
.
new
(
current_user:
current_user
,
project:
issuable
.
project
)
.
represent
(
issuable
)
.
represent
(
issuable
,
serializer:
serializer
)
.
to_json
end
...
...
app/serializers/issuable_entity.rb
View file @
f8cda25d
...
...
@@ -3,14 +3,6 @@ class IssuableEntity < Grape::Entity
expose
:id
expose
:iid
expose
:author_id
expose
:description
expose
:lock_version
expose
:milestone_id
expose
:title
expose
:updated_by_id
expose
:created_at
expose
:updated_at
expose
:milestone
,
using:
API
::
Entities
::
Milestone
expose
:labels
,
using:
LabelEntity
end
app/serializers/issuable_sidebar_entity.rb
View file @
f8cda25d
class
IssuableSidebarEntity
<
Grape
::
Entity
include
TimeTrackableEntity
include
RequestAwareEntity
prepend
::
EE
::
IssuableSidebarEntity
...
...
@@ -9,9 +10,4 @@ class IssuableSidebarEntity < Grape::Entity
expose
:subscribed
do
|
issuable
|
issuable
.
subscribed?
(
request
.
current_user
,
issuable
.
project
)
end
expose
:time_estimate
expose
:total_time_spent
expose
:human_time_estimate
expose
:human_total_time_spent
end
app/serializers/issue_entity.rb
View file @
f8cda25d
...
...
@@ -2,7 +2,15 @@ class IssueEntity < IssuableEntity
include
TimeTrackableEntity
expose
:state
expose
:milestone_id
expose
:updated_by_id
expose
:created_at
expose
:updated_at
expose
:deleted_at
expose
:milestone
,
using:
API
::
Entities
::
Milestone
expose
:labels
,
using:
LabelEntity
expose
:lock_version
expose
:author_id
expose
:confidential
expose
:discussion_locked
expose
:assignees
,
using:
API
::
Entities
::
UserBasic
...
...
app/serializers/merge_request_serializer.rb
View file @
f8cda25d
class
MergeRequestSerializer
<
BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `merge_request` based on `
basic
` key in `opts` param.
# to serialize the `merge_request` based on `
serializer
` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
def
represent
(
merge_request
,
opts
=
{})
entity
=
case
opts
[
:serializer
]
when
'basic'
,
'sidebar'
MergeRequestBasicEntity
else
MergeRequestEntity
when
'widget'
MergeRequest
Widget
Entity
end
super
(
merge_request
,
opts
,
entity
)
...
...
app/serializers/merge_request_entity.rb
→
app/serializers/merge_request_
widget_
entity.rb
View file @
f8cda25d
class
MergeRequestEntity
<
IssuableEntity
include
TimeTrackableEntity
prepend
::
EE
::
MergeRequestEntity
class
MergeRequestWidgetEntity
<
IssuableEntity
prepend
::
EE
::
MergeRequestWidgetEntity
expose
:state
expose
:deleted_at
expose
:in_progress_merge_commit_sha
expose
:merge_commit_sha
expose
:merge_error
...
...
app/views/projects/merge_requests/show.html.haml
View file @
f8cda25d
...
...
@@ -21,7 +21,7 @@
-# haml-lint:disable InlineJavaScript
:javascript
window
.
gl
=
window
.
gl
||
{};
window
.
gl
.
mrWidgetData
=
#{
serialize_issuable
(
@merge_request
)
}
window
.
gl
.
mrWidgetData
=
#{
serialize_issuable
(
@merge_request
,
serializer:
'widget'
)
}
// Append static, server-generated data not included in merge request entity (EE-Only)
// Object.assign would be useful here, but it blows up Phantom.js in tests
...
...
app/views/shared/empty_states/_issues.html.haml
View file @
f8cda25d
...
...
@@ -8,11 +8,12 @@
=
image_tag
'illustrations/issues.svg'
.col-xs-12
.text-content
-
if
has_button
&&
current_user
-
if
current_user
%h4
=
_
(
"The Issue Tracker is the place to add things that need to be improved or solved in a project"
)
%p
=
_
(
"Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
)
-
if
has_button
.text-center
-
if
project_select_button
=
render
'shared/new_project_item_select'
,
path:
'issues/new'
,
label:
'New issue'
,
type: :issues
...
...
changelogs/unreleased-ee/4330-show-item-count-in-tooltip.yml
0 → 100644
View file @
f8cda25d
---
title
:
'
Geo:
Show
sync
percent
on
bar
graph
and
count
within
tooltips'
merge_request
:
3794
author
:
type
:
changed
changelogs/unreleased/osw-isolate-mr-widget-exposed-attributes.yml
0 → 100644
View file @
f8cda25d
---
title
:
Stop sending milestone and labels data over the wire for MR widget requests
merge_request
:
author
:
type
:
performance
doc/articles/laravel_with_gitlab_and_envoy/index.md
View file @
f8cda25d
...
...
@@ -502,8 +502,8 @@ stages:
unit_test
:
stage
:
test
script
:
-
composer install
-
cp .env.example .env
-
composer install
-
php artisan key:generate
-
php artisan migrate
-
vendor/bin/phpunit
...
...
doc/workflow/repository_mirroring.md
View file @
f8cda25d
...
...
@@ -84,9 +84,19 @@ this branch to prevent any changes from being lost.
![
Diverged branch
](
repository_mirroring/repository_mirroring_diverged_branch.png
)
### Trigger update using API
>[Introduced][ee-3453] in GitLab Enterprise Edition 10.3.
Pull mirroring uses polling to detect new branches and commits added upstream,
often many minutes afterwards. If you notify GitLab by
[
API
][
pull-api
]
, updates
will be pulled immediately.
Read the
[
Pull Mirror Trigger API docs
][
pull-api
]
.
### Pull only protected branches
>[Introduced][ee-3326] in Git
l
ab Enterprise Edition 10.3.
>[Introduced][ee-3326] in Git
L
ab Enterprise Edition 10.3.
You can choose to only pull the protected branches from your remote repository to GitLab.
...
...
@@ -199,45 +209,50 @@ If you need to change the key at any time, you can press the `Regenerate key`
button to do so. You'll have to update the source repository with the new key
to keep the mirror running.
## How it works
##
#
How it works
Once you activate the pull mirroring feature, the mirror will be inserted into
a queue.
A scheduler will start every minute and schedule a fixed amount of mirrors for update, based
on the configured maximum capacity.
Once you activate the pull mirroring feature, the mirror will be inserted into
a queue. A scheduler will start every minute and schedule a fixed amount of
mirrors for update, based
on the configured maximum capacity.
If the mirror successfully updates it will be enqueued once again with a small
backoff
period.
If the mirror successfully updates it will be enqueued once again with a small
backoff
period.
If the mirror fails (eg: branch diverged from upstream), the project's
backoff
period will be penalized each time it fails up to a maximum amount of time.
If the mirror fails (eg: branch diverged from upstream), the project's
backoff
period will be penalized each time it fails up to a maximum amount of time.
## Pushing to a remote repository
>[Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in GitLab Enterprise Edition 8.7.
>[Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in
GitLab Enterprise Edition 8.7.
For an existing project, you can set up
mirror pushing by visiting
your project's
For an existing project, you can set up
push mirror from
your project's
**Settings ➔ Repository**
and searching for the "Push to a remote repository"
section. Check the "Remote mirror repository" box and fill in the Git URL of the
repository to push to. Hit
**Save changes**
for the changes to take effect.
section. Check the "Remote mirror repository" box and fill in the Git URL of
the repository to push to. Click
**Save changes**
for the changes to take
effect.
![
Push settings
](
repository_mirroring/repository_mirroring_push_settings.png
)
Similarly to the pull mirroring, since the upstream repository functions as a
mirror to the repository in GitLab, you are advised not to push commits directly
to the mirrored repository. Instead, all changes will end up in the mirrored repository
whenever commits are pushed to GitLab, or when a
[
forced update
](
#forcing-an-update
)
is initiated.
Similarly to pull mirroring, when push mirroring is enabled, you are advised
not to push commits directly to the mirrored repository to prevent the mirror
diverging. All changes will end up in the mirrored repository whenever commits
are pushed to GitLab, or when a
[
forced update
](
#forcing-an-update
)
is
initiated.
Pushes into GitLab are automatically pushed to the remote mirror at least once every 5 minutes
after they come in or 1 minute if
**push only protected branches**
is enabled.
Pushes into GitLab are automatically pushed to the remote mirror at least once
every 5 minutes after they are received or once every minute if
**
push only
protected branches
**
is enabled.
In case of a diverged branch, you will see an error indicated at the
**Mirror
repository**
settings.
In case of a diverged branch, you will see an error indicated at the
**
Mirror
repository
**
settings.
![
Diverged branch
](
repository_mirroring/repository_mirroring_diverged_branch_push.png
)
![
Diverged branch
](
repository_mirroring/repository_mirroring_diverged_branch_push.png
)
### Push only protected branches
>[Introduced][ee-3350] in Git
l
ab Enterprise Edition 10.3.
>[Introduced][ee-3350] in Git
L
ab Enterprise Edition 10.3.
You can choose to only push your protected branches from GitLab to your remote repository.
...
...
@@ -270,19 +285,38 @@ While mirrors are scheduled to update automatically, you can always force an upd
-
in the tags page
-
in the
**Mirror repository**
settings page
## Using both mirroring methods at the same time
## Bidirectional mirroring
> **Warning:** There is no bidirectional support without conflicts. If you
> configure a repository to pull and push to a second remote, there is no
> guarantee that it will update correctly on both remotes. If you configure
> a repository for bidirectional mirroring, you should consider when conflicts
> occur who and how they will be resolved.
Rewriting any mirrored commit on either remote will cause conflicts and
mirroring to fail. This can be prevented by
[
only pulling protected branches
](
#pull-only-protected-branches
)
and
[
only pushing protected branches
](
#push-only-protected-branches
)
. You should protect the branches you wish to
mirror on both remotes to prevent conflicts caused by rewriting history.
Currently there is no bidirectional support without conflicts. That means that
if you configure a repository to both pull and push to a second one, there is
no guarantee that it will update correctly on both remotes.
You can try
[
configuring custom Git hooks
][
hooks
]
on the GitLab server in order
to
resolve this issue
.
Bidirectional mirroring also creates a race condition where commits to the same
branch in close proximity will cause conflicts. The race condition can be
mitigated by reducing the mirroring delay by using a Push event webhook to
trigger an immediate pull to GitLab. Push mirroring from GitLab is rate limited
to
once per minute when only push mirroring protected branches
.
It may be possible to implement a locking mechanism using the server-side
`pre-receive`
hook to prevent the race condition. Read about
[
configuring
custom Git hooks
][
hooks
]
on the GitLab server.
[
ee-51
]:
https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51
[
ee-2551
]:
https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2551
[
ee-3117
]:
https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117
[
ee-3326
]:
https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3326
[
ee-3350
]:
https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350
[
ee-3453
]:
https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3453
[
perms
]:
../user/permissions.md
[
hooks
]:
https://docs.gitlab.com/ee
/administration/custom_hooks.html
[
hooks
]:
..
/administration/custom_hooks.html
[
deploy-key
]:
../ssh/README.md#deploy-keys
[
webhook
]:
../user/project/integrations/webhooks.html#push-events
[
pull-api
]:
../api/projects.html#start-the-pull-mirroring-process-for-a-project
ee/app/serializers/ee/merge_request_entity.rb
→
ee/app/serializers/ee/merge_request_
widget_
entity.rb
View file @
f8cda25d
module
EE
module
MergeRequestEntity
module
MergeRequest
Widget
Entity
extend
ActiveSupport
::
Concern
prepended
do
...
...
qa/qa.rb
View file @
f8cda25d
...
...
@@ -12,6 +12,27 @@ module QA
autoload
:Browser
,
'qa/runtime/browser'
end
##
# GitLab QA fabrication mechanisms
#
module
Factory
autoload
:Base
,
'qa/factory/base'
module
Resource
autoload
:Sandbox
,
'qa/factory/resource/sandbox'
autoload
:Group
,
'qa/factory/resource/group'
autoload
:Project
,
'qa/factory/resource/project'
end
module
Repository
autoload
:Push
,
'qa/factory/repository/push'
end
module
Settings
autoload
:HashedStorage
,
'qa/factory/settings/hashed_storage'
end
end
##
# GitLab QA Scenarios
#
...
...
@@ -34,31 +55,6 @@ module QA
autoload
:Mattermost
,
'qa/scenario/test/integration/mattermost'
end
end
##
# GitLab instance scenarios.
#
module
Gitlab
module
Group
autoload
:Create
,
'qa/scenario/gitlab/group/create'
end
module
Project
autoload
:Create
,
'qa/scenario/gitlab/project/create'
end
module
Repository
autoload
:Push
,
'qa/scenario/gitlab/repository/push'
end
module
Sandbox
autoload
:Prepare
,
'qa/scenario/gitlab/sandbox/prepare'
end
module
Admin
autoload
:HashedStorage
,
'qa/scenario/gitlab/admin/hashed_storage'
end
end
end
##
...
...
qa/qa/ee.rb
View file @
f8cda25d
...
...
@@ -16,18 +16,18 @@ module QA
end
end
module
Scenario
module
Factory
autoload
:License
,
'qa/ee/factory/license'
module
Geo
autoload
:Node
,
'qa/ee/scenario/geo/node'
autoload
:Node
,
'qa/ee/factory/geo/node'
end
end
module
Scenario
module
Test
autoload
:Geo
,
'qa/ee/scenario/test/geo'
end
module
License
autoload
:Add
,
'qa/ee/scenario/license/add'
end
end
end
end
qa/qa/ee/
scenario
/geo/node.rb
→
qa/qa/ee/
factory
/geo/node.rb
View file @
f8cda25d
module
QA
module
EE
module
Scenario
module
Factory
module
Geo
class
Node
<
QA
::
Scenario
::
Templat
e
class
Node
<
QA
::
Factory
::
Bas
e
attr_accessor
:address
def
perform
def
fabricate!
QA
::
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
QA
::
Page
::
Main
::
Menu
.
act
{
go_to_admin_area
}
QA
::
Page
::
Admin
::
Menu
.
act
{
go_to_geo_nodes
}
...
...
qa/qa/ee/factory/license.rb
0 → 100644
View file @
f8cda25d
module
QA
module
EE
module
Factory
class
License
<
QA
::
Factory
::
Base
def
fabricate!
(
license
)
QA
::
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
QA
::
Page
::
Main
::
Menu
.
act
{
go_to_admin_area
}
QA
::
Page
::
Admin
::
Menu
.
act
{
go_to_license
}
EE
::
Page
::
Admin
::
License
.
act
(
license
)
do
|
key
|
add_new_license
(
key
)
if
no_license?
end
QA
::
Page
::
Main
::
Menu
.
act
{
sign_out
}
end
end
end
end
end
qa/qa/ee/scenario/license/add.rb
deleted
100644 → 0
View file @
be0369a1
module
QA
module
EE
module
Scenario
module
License
class
Add
<
QA
::
Scenario
::
Template
def
perform
(
license
)
QA
::
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
QA
::
Page
::
Main
::
Menu
.
act
{
go_to_admin_area
}
QA
::
Page
::
Admin
::
Menu
.
act
{
go_to_license
}
EE
::
Page
::
Admin
::
License
.
act
(
license
)
do
|
key
|
add_new_license
(
key
)
if
no_license?
end
QA
::
Page
::
Main
::
Menu
.
act
{
sign_out
}
end
end
end
end
end
end
qa/qa/ee/scenario/test/geo.rb
View file @
f8cda25d
...
...
@@ -39,32 +39,26 @@ module QA
end
def
add_license
# TODO EE license to Runtime.license, gitlab-org/gitlab-qa#86
#
puts
'Adding GitLab EE license ...'
QA
::
Runtime
::
Browser
.
visit
(
:geo_primary
,
QA
::
Page
::
Main
::
Login
)
do
Scenario
::
License
::
Add
.
perform
(
ENV
[
'EE_LICENSE'
])
Factory
::
License
.
fabricate!
(
ENV
[
'EE_LICENSE'
])
end
end
def
enable_hashed_storage
# TODO, Factory::HashedStorage - gitlab-org/gitlab-qa#86
#
puts
'Enabling hashed repository storage setting ...'
QA
::
Runtime
::
Browser
.
visit
(
:geo_primary
,
QA
::
Page
::
Main
::
Login
)
do
QA
::
Scenario
::
Gitlab
::
Admin
::
HashedStorage
.
perform
(
:enabled
)
QA
::
Factory
::
Settings
::
HashedStorage
.
fabricate!
(
:enabled
)
end
end
def
add_secondary_node
# TODO, Factory::Geo::Node - gitlab-org/gitlab-qa#86
#
puts
'Adding new Geo secondary node ...'
QA
::
Runtime
::
Browser
.
visit
(
:geo_primary
,
QA
::
Page
::
Main
::
Login
)
do
Scenario
::
Geo
::
Node
.
perform
do
|
node
|
Factory
::
Geo
::
Node
.
fabricate!
do
|
node
|
node
.
address
=
QA
::
Runtime
::
Scenario
.
geo_secondary_address
end
end
...
...
qa/qa/ee/strategy.rb
View file @
f8cda25d
...
...
@@ -11,7 +11,7 @@ module QA
return
unless
ENV
[
'EE_LICENSE'
]
QA
::
Runtime
::
Browser
.
visit
(
:gitlab
,
QA
::
Page
::
Main
::
Login
)
do
EE
::
Scenario
::
License
::
Add
.
perform
(
ENV
[
'EE_LICENSE'
])
EE
::
Factory
::
License
.
fabricate!
(
ENV
[
'EE_LICENSE'
])
end
end
end
...
...
qa/qa/factory/base.rb
0 → 100644
View file @
f8cda25d
module
QA
module
Factory
class
Base
def
self
.
fabricate!
(
*
args
)
new
.
tap
do
|
factory
|
yield
factory
if
block_given?
return
factory
.
fabricate!
(
*
args
)
end
end
def
fabricate!
(
*
_args
)
raise
NotImplementedError
end
end
end
end
qa/qa/factory/repository/push.rb
0 → 100644
View file @
f8cda25d
require
"pry-byebug"
module
QA
module
Factory
module
Repository
class
Push
<
Factory
::
Base
PAGE_REGEX_CHECK
=
%r{
\/
#{
Runtime
::
Namespace
.
sandbox_name
}
\/
qa-test[^
\/
]+
\/
{1}[^
\/
]+
\z
}
.
freeze
attr_writer
:file_name
,
:file_content
,
:commit_message
,
:branch_name
def
initialize
@file_name
=
'file.txt'
@file_content
=
'# This is test project'
@commit_message
=
"Add
#{
@file_name
}
"
@branch_name
=
'master'
end
def
fabricate!
Git
::
Repository
.
perform
do
|
repository
|
repository
.
location
=
Page
::
Project
::
Show
.
act
do
unless
PAGE_REGEX_CHECK
.
match
(
current_path
)
raise
"To perform this scenario the current page should be project show."
end
choose_repository_clone_http
repository_location
end
repository
.
use_default_credentials
repository
.
clone
repository
.
configure_identity
(
'GitLab QA'
,
'root@gitlab.com'
)
repository
.
add_file
(
@file_name
,
@file_content
)
repository
.
commit
(
@commit_message
)
repository
.
push_changes
(
@branch_name
)
end
end
end
end
end
end
qa/qa/factory/resource/group.rb
0 → 100644
View file @
f8cda25d
module
QA
module
Factory
module
Resource
class
Group
<
Factory
::
Base
attr_writer
:path
,
:description
def
initialize
@path
=
Runtime
::
Namespace
.
name
@description
=
"QA test run at
#{
Runtime
::
Namespace
.
time
}
"
end
def
fabricate!
Page
::
Group
::
New
.
perform
do
|
group
|
group
.
set_path
(
@path
)
group
.
set_description
(
@description
)
group
.
set_visibility
(
'Private'
)
group
.
create
end
end
end
end
end
end
qa/qa/factory/resource/project.rb
0 → 100644
View file @
f8cda25d
require
'securerandom'
module
QA
module
Factory
module
Resource
class
Project
<
Factory
::
Base
attr_writer
:description
def
name
=
(
name
)
@name
=
"
#{
name
}
-
#{
SecureRandom
.
hex
(
8
)
}
"
end
def
fabricate!
Factory
::
Resource
::
Sandbox
.
fabricate!
Page
::
Group
::
Show
.
perform
do
|
page
|
if
page
.
has_subgroup?
(
Runtime
::
Namespace
.
name
)
page
.
go_to_subgroup
(
Runtime
::
Namespace
.
name
)
else
page
.
go_to_new_subgroup
Factory
::
Resource
::
Group
.
fabricate!
do
|
group
|
group
.
path
=
Runtime
::
Namespace
.
name
end
end
page
.
go_to_new_project
end
Page
::
Project
::
New
.
perform
do
|
page
|
page
.
choose_test_namespace
page
.
choose_name
(
@name
)
page
.
add_description
(
@description
)
page
.
create_new_project
end
end
end
end
end
end
qa/qa/factory/resource/sandbox.rb
0 → 100644
View file @
f8cda25d
module
QA
module
Factory
module
Resource
##
# Ensure we're in our sandbox namespace, either by navigating to it or by
# creating it if it doesn't yet exist.
#
class
Sandbox
<
Factory
::
Base
def
fabricate!
Page
::
Main
::
Menu
.
act
{
go_to_groups
}
Page
::
Dashboard
::
Groups
.
perform
do
|
page
|
if
page
.
has_group?
(
Runtime
::
Namespace
.
sandbox_name
)
page
.
go_to_group
(
Runtime
::
Namespace
.
sandbox_name
)
else
page
.
go_to_new_group
Resource
::
Group
.
fabricate!
do
|
group
|
group
.
path
=
Runtime
::
Namespace
.
sandbox_name
group
.
description
=
'GitLab QA Sandbox'
end
end
end
end
end
end
end
end
qa/qa/factory/settings/hashed_storage.rb
0 → 100644
View file @
f8cda25d
module
QA
module
Factory
module
Settings
class
HashedStorage
<
Factory
::
Base
def
fabricate!
(
*
traits
)
raise
ArgumentError
unless
traits
.
include?
(
:enabled
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Menu
.
act
{
go_to_admin_area
}
Page
::
Admin
::
Menu
.
act
{
go_to_settings
}
Page
::
Admin
::
Settings
.
act
do
enable_hashed_storage
save_settings
end
QA
::
Page
::
Main
::
Menu
.
act
{
sign_out
}
end
end
end
end
end
qa/qa/scenario/gitlab/admin/hashed_storage.rb
deleted
100644 → 0
View file @
be0369a1
module
QA
module
Scenario
module
Gitlab
module
Admin
class
HashedStorage
<
Scenario
::
Template
def
perform
(
*
traits
)
raise
ArgumentError
unless
traits
.
include?
(
:enabled
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Page
::
Main
::
Menu
.
act
{
go_to_admin_area
}
Page
::
Admin
::
Menu
.
act
{
go_to_settings
}
Page
::
Admin
::
Settings
.
act
do
enable_hashed_storage
save_settings
end
QA
::
Page
::
Main
::
Menu
.
act
{
sign_out
}
end
end
end
end
end
end
qa/qa/scenario/gitlab/group/create.rb
deleted
100644 → 0
View file @
be0369a1
require
'securerandom'
module
QA
module
Scenario
module
Gitlab
module
Group
class
Create
<
Scenario
::
Template
attr_writer
:path
,
:description
def
initialize
@path
=
Runtime
::
Namespace
.
name
@description
=
"QA test run at
#{
Runtime
::
Namespace
.
time
}
"
end
def
perform
Page
::
Group
::
New
.
perform
do
|
group
|
group
.
set_path
(
@path
)
group
.
set_description
(
@description
)
group
.
set_visibility
(
'Private'
)
group
.
create
end
end
end
end
end
end
end
qa/qa/scenario/gitlab/project/create.rb
deleted
100644 → 0
View file @
be0369a1
require
'securerandom'
module
QA
module
Scenario
module
Gitlab
module
Project
class
Create
<
Scenario
::
Template
attr_writer
:description
def
name
=
(
name
)
@name
=
"
#{
name
}
-
#{
SecureRandom
.
hex
(
8
)
}
"
end
def
perform
Scenario
::
Gitlab
::
Sandbox
::
Prepare
.
perform
Page
::
Group
::
Show
.
perform
do
|
page
|
if
page
.
has_subgroup?
(
Runtime
::
Namespace
.
name
)
page
.
go_to_subgroup
(
Runtime
::
Namespace
.
name
)
else
page
.
go_to_new_subgroup
Scenario
::
Gitlab
::
Group
::
Create
.
perform
do
|
group
|
group
.
path
=
Runtime
::
Namespace
.
name
end
end
page
.
go_to_new_project
end
Page
::
Project
::
New
.
perform
do
|
page
|
page
.
choose_test_namespace
page
.
choose_name
(
@name
)
page
.
add_description
(
@description
)
page
.
create_new_project
end
end
end
end
end
end
end
qa/qa/scenario/gitlab/repository/push.rb
deleted
100644 → 0
View file @
be0369a1
require
"pry-byebug"
module
QA
module
Scenario
module
Gitlab
module
Repository
class
Push
<
Scenario
::
Template
PAGE_REGEX_CHECK
=
%r{
\/
#{
Runtime
::
Namespace
.
sandbox_name
}
\/
qa-test[^
\/
]+
\/
{1}[^
\/
]+
\z
}
.
freeze
attr_writer
:file_name
,
:file_content
,
:commit_message
,
:branch_name
def
initialize
@file_name
=
'file.txt'
@file_content
=
'# This is test project'
@commit_message
=
"Add
#{
@file_name
}
"
@branch_name
=
'master'
end
def
perform
Git
::
Repository
.
perform
do
|
repository
|
repository
.
location
=
Page
::
Project
::
Show
.
act
do
unless
PAGE_REGEX_CHECK
.
match
(
current_path
)
raise
"To perform this scenario the current page should be project show."
end
choose_repository_clone_http
repository_location
end
repository
.
use_default_credentials
repository
.
clone
repository
.
configure_identity
(
'GitLab QA'
,
'root@gitlab.com'
)
repository
.
add_file
(
@file_name
,
@file_content
)
repository
.
commit
(
@commit_message
)
repository
.
push_changes
(
@branch_name
)
end
end
end
end
end
end
end
qa/qa/scenario/gitlab/sandbox/prepare.rb
deleted
100644 → 0
View file @
be0369a1
module
QA
module
Scenario
module
Gitlab
module
Sandbox
# Ensure we're in our sandbox namespace, either by navigating to it or
# by creating it if it doesn't yet exist
class
Prepare
<
Scenario
::
Template
def
perform
Page
::
Main
::
Menu
.
act
{
go_to_groups
}
Page
::
Dashboard
::
Groups
.
perform
do
|
page
|
if
page
.
has_group?
(
Runtime
::
Namespace
.
sandbox_name
)
page
.
go_to_group
(
Runtime
::
Namespace
.
sandbox_name
)
else
page
.
go_to_new_group
Scenario
::
Gitlab
::
Group
::
Create
.
perform
do
|
group
|
group
.
path
=
Runtime
::
Namespace
.
sandbox_name
group
.
description
=
'QA sandbox'
end
end
end
end
end
end
end
end
end
qa/qa/specs/features/ee/geo/replication_spec.rb
View file @
f8cda25d
...
...
@@ -4,9 +4,9 @@ module QA
Runtime
::
Browser
.
visit
(
:geo_primary
,
QA
::
Page
::
Main
::
Login
)
do
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
scenario
|
scenario
.
name
=
'geo-project'
scenario
.
description
=
'Geo test project'
Factory
::
Resource
::
Project
.
fabricate!
do
|
project
|
project
.
name
=
'geo-project'
project
.
description
=
'Geo test project'
end
geo_project_name
=
Page
::
Project
::
Show
.
act
{
project_name
}
...
...
qa/qa/specs/features/project/create_spec.rb
View file @
f8cda25d
...
...
@@ -4,7 +4,7 @@ module QA
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
project
|
Factory
::
Resource
::
Project
.
fabricate!
do
|
project
|
project
.
name
=
'awesome-project'
project
.
description
=
'create awesome project test'
end
...
...
qa/qa/specs/features/repository/clone_spec.rb
View file @
f8cda25d
...
...
@@ -12,7 +12,7 @@ module QA
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
scenario
|
Factory
::
Resource
::
Project
.
fabricate!
do
|
scenario
|
scenario
.
name
=
'project-with-code'
scenario
.
description
=
'project for git clone tests'
end
...
...
qa/qa/specs/features/repository/push_spec.rb
View file @
f8cda25d
...
...
@@ -5,12 +5,12 @@ module QA
Runtime
::
Browser
.
visit
(
:gitlab
,
Page
::
Main
::
Login
)
Page
::
Main
::
Login
.
act
{
sign_in_using_credentials
}
Scenario
::
Gitlab
::
Project
::
Create
.
perform
do
|
scenario
|
Factory
::
Resource
::
Project
.
fabricate!
do
|
scenario
|
scenario
.
name
=
'project_with_code'
scenario
.
description
=
'project with repository'
end
Scenario
::
Gitlab
::
Repository
::
Push
.
perform
do
|
scenario
|
Factory
::
Repository
::
Push
.
fabricate!
do
|
scenario
|
scenario
.
file_name
=
'README.md'
scenario
.
file_content
=
'# This is test project'
scenario
.
commit_message
=
'Add README.md'
...
...
spec/controllers/projects/merge_requests_controller_spec.rb
View file @
f8cda25d
...
...
@@ -91,11 +91,11 @@ describe Projects::MergeRequestsController do
end
end
context
'with
out basic
serializer param'
do
it
'renders
the merge request in the json format
'
do
go
(
format: :json
)
context
'with
widget
serializer param'
do
it
'renders
widget MR entity as json
'
do
go
(
serializer:
'widget'
,
format: :json
)
expect
(
response
).
to
match_response_schema
(
'entities/merge_request'
)
expect
(
response
).
to
match_response_schema
(
'entities/merge_request
_widget
'
)
end
end
end
...
...
spec/ee/spec/serializers/epic_entity_spec.rb
View file @
f8cda25d
...
...
@@ -10,8 +10,7 @@ describe EpicEntity do
subject
{
described_class
.
new
(
resource
,
request:
request
).
as_json
}
it
'has Issuable attributes'
do
expect
(
subject
).
to
include
(
:id
,
:iid
,
:author_id
,
:description
,
:lock_version
,
:milestone_id
,
:title
,
:updated_by_id
,
:created_at
,
:updated_at
,
:milestone
,
:labels
)
expect
(
subject
).
to
include
(
:id
,
:iid
,
:description
,
:title
)
end
it
'has epic specific attributes'
do
...
...
spec/ee/spec/serializers/merge_request_entity_spec.rb
→
spec/ee/spec/serializers/merge_request_
widget_
entity_spec.rb
View file @
f8cda25d
require
'spec_helper'
describe
MergeRequestEntity
do
describe
MergeRequest
Widget
Entity
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
:project
,
:repository
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
,
target_project:
project
)
}
...
...
spec/features/issues_spec.rb
View file @
f8cda25d
...
...
@@ -8,6 +8,19 @@ describe 'Issues' do
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
,
:public
)
}
describe
'while user is signed out'
do
describe
'empty state'
do
it
'user sees empty state'
do
visit
project_issues_path
(
project
)
expect
(
page
).
to
have_content
(
'Register / Sign In'
)
expect
(
page
).
to
have_content
(
'The Issue Tracker is the place to add things that need to be improved or solved in a project.'
)
expect
(
page
).
to
have_content
(
'You can register or sign in to create issues for this project.'
)
end
end
end
describe
'while user is signed in'
do
before
do
sign_in
(
user
)
user2
=
create
(
:user
)
...
...
@@ -15,6 +28,16 @@ describe 'Issues' do
project
.
team
<<
[[
user
,
user2
],
:developer
]
end
describe
'empty state'
do
it
'user sees empty state'
do
visit
project_issues_path
(
project
)
expect
(
page
).
to
have_content
(
'The Issue Tracker is the place to add things that need to be improved or solved in a project'
)
expect
(
page
).
to
have_content
(
'Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable.'
)
expect
(
page
).
to
have_content
(
'New issue'
)
end
end
describe
'Edit issue'
do
let!
(
:issue
)
do
create
(
:issue
,
...
...
@@ -769,4 +792,5 @@ describe 'Issues' do
expect
(
page
).
not_to
have_css
(
'.is-active'
)
end
end
end
end
spec/features/merge_requests/mini_pipeline_graph_spec.rb
View file @
f8cda25d
...
...
@@ -15,8 +15,8 @@ feature 'Mini Pipeline Graph', :js do
visit_merge_request
end
def
visit_merge_request
(
format
=
:htm
l
)
visit
project_merge_request_path
(
project
,
merge_request
,
format:
format
)
def
visit_merge_request
(
format
: :html
,
serializer:
ni
l
)
visit
project_merge_request_path
(
project
,
merge_request
,
format:
format
,
serializer:
serializer
)
end
it
'should display a mini pipeline graph'
do
...
...
@@ -33,12 +33,12 @@ feature 'Mini Pipeline Graph', :js do
end
it
'avoids repeated database queries'
do
before
=
ActiveRecord
::
QueryRecorder
.
new
{
visit_merge_request
(
:json
)
}
before
=
ActiveRecord
::
QueryRecorder
.
new
{
visit_merge_request
(
format: :json
,
serializer:
'widget'
)
}
create
(
:ci_build
,
pipeline:
pipeline
,
legacy_artifacts_file:
artifacts_file2
)
create
(
:ci_build
,
pipeline:
pipeline
,
when:
'manual'
)
after
=
ActiveRecord
::
QueryRecorder
.
new
{
visit_merge_request
(
:json
)
}
after
=
ActiveRecord
::
QueryRecorder
.
new
{
visit_merge_request
(
format: :json
,
serializer:
'widget'
)
}
expect
(
before
.
count
).
to
eq
(
after
.
count
)
expect
(
before
.
cached_count
).
to
eq
(
after
.
cached_count
)
...
...
spec/fixtures/api/schemas/entities/merge_request.json
→
spec/fixtures/api/schemas/entities/merge_request
_widget
.json
View file @
f8cda25d
...
...
@@ -81,15 +81,15 @@
"target_branch_tree_path"
:
{
"type"
:
"string"
},
"source_branch_path"
:
{
"type"
:
"string"
},
"conflict_resolution_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"cancel_merge_when_pipeline_succeeds_path"
:
{
"type"
:
"string"
},
"create_issue_to_resolve_discussions_path"
:
{
"type"
:
"string"
},
"merge_path"
:
{
"type"
:
"string"
},
"cancel_merge_when_pipeline_succeeds_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"create_issue_to_resolve_discussions_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"merge_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"cherry_pick_in_fork_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"revert_in_fork_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"email_patches_path"
:
{
"type"
:
"string"
},
"plain_diff_path"
:
{
"type"
:
"string"
},
"status_path"
:
{
"type"
:
"string"
},
"new_blob_path"
:
{
"type"
:
"string"
},
"new_blob_path"
:
{
"type"
:
[
"string"
,
"null"
]
},
"merge_check_path"
:
{
"type"
:
"string"
},
"ci_environments_status_path"
:
{
"type"
:
"string"
},
"merge_commit_message_with_description"
:
{
"type"
:
"string"
},
...
...
spec/javascripts/collapsed_sidebar_todo_spec.js
View file @
f8cda25d
/* global Sidebar */
/* eslint-disable no-new */
import
_
from
'
underscore
'
;
import
'
~/right_sidebar
'
;
import
Sidebar
from
'
~/right_sidebar
'
;
describe
(
'
Issuable right sidebar collapsed todo toggle
'
,
()
=>
{
const
fixtureName
=
'
issues/open-issue.html.raw
'
;
...
...
spec/javascripts/line_highlighter_spec.js
View file @
f8cda25d
/* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, jasmine/no-spec-dupes, no-underscore-dangle, max-len */
/* global LineHighlighter */
import
'
~/line_highlighter
'
;
import
LineHighlighter
from
'
~/line_highlighter
'
;
(
function
()
{
describe
(
'
LineHighlighter
'
,
function
()
{
...
...
spec/javascripts/merge_request_notes_spec.js
View file @
f8cda25d
/* global Notes */
import
'
autosize
'
;
import
'
~/gl_form
'
;
import
'
~/lib/utils/text_utility
'
;
import
'
~/render_gfm
'
;
import
'
~/render_math
'
;
import
'
~/notes
'
;
import
Notes
from
'
~/notes
'
;
const
upArrowKeyCode
=
38
;
...
...
spec/javascripts/merge_request_spec.js
View file @
f8cda25d
/* eslint-disable space-before-function-paren, no-return-assign */
/* global MergeRequest */
import
'
~/merge_request
'
;
import
MergeRequest
from
'
~/merge_request
'
;
import
CloseReopenReportToggle
from
'
~/close_reopen_report_toggle
'
;
import
IssuablesHelper
from
'
~/helpers/issuables_helper
'
;
...
...
spec/javascripts/merge_request_tabs_spec.js
View file @
f8cda25d
/* eslint-disable no-var, comma-dangle, object-shorthand */
/* global Notes */
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
'
~/merge_request_tabs
'
;
...
...
@@ -7,7 +6,7 @@ import '~/commit/pipelines/pipelines_bundle';
import
'
~/breakpoints
'
;
import
'
~/lib/utils/common_utils
'
;
import
Diff
from
'
~/diff
'
;
import
'
~/notes
'
;
import
Notes
from
'
~/notes
'
;
import
'
vendor/jquery.scrollTo
'
;
(
function
()
{
...
...
@@ -279,8 +278,8 @@ import 'vendor/jquery.scrollTo';
loadFixtures
(
'
merge_requests/diff_comment.html.raw
'
);
$
(
'
body
'
).
attr
(
'
data-page
'
,
'
projects:merge_requests:show
'
);
window
.
gl
.
ImageFile
=
()
=>
{};
window
.
notes
=
new
Notes
(
''
,
[]);
spyOn
(
window
.
notes
,
'
toggleDiffNote
'
).
and
.
callThrough
();
Notes
.
initialize
(
''
,
[]);
spyOn
(
Notes
.
instance
,
'
toggleDiffNote
'
).
and
.
callThrough
();
});
afterEach
(()
=>
{
...
...
@@ -338,7 +337,7 @@ import 'vendor/jquery.scrollTo';
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
noteId
.
length
).
toBeGreaterThan
(
0
);
expect
(
window
.
notes
.
toggleDiffNote
).
toHaveBeenCalledWith
({
expect
(
Notes
.
instance
.
toggleDiffNote
).
toHaveBeenCalledWith
({
target
:
jasmine
.
any
(
Object
),
lineType
:
'
old
'
,
forceShow
:
true
,
...
...
@@ -349,7 +348,7 @@ import 'vendor/jquery.scrollTo';
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
'
note_something-that-does-not-exist
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
window
.
notes
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
});
});
...
...
@@ -359,7 +358,7 @@ import 'vendor/jquery.scrollTo';
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
noteLineNumId
.
length
).
toBeGreaterThan
(
0
);
expect
(
window
.
notes
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
});
});
});
...
...
@@ -393,7 +392,7 @@ import 'vendor/jquery.scrollTo';
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
noteId
.
length
).
toBeGreaterThan
(
0
);
expect
(
window
.
notes
.
toggleDiffNote
).
toHaveBeenCalledWith
({
expect
(
Notes
.
instance
.
toggleDiffNote
).
toHaveBeenCalledWith
({
target
:
jasmine
.
any
(
Object
),
lineType
:
'
new
'
,
forceShow
:
true
,
...
...
@@ -404,7 +403,7 @@ import 'vendor/jquery.scrollTo';
spyOn
(
urlUtils
,
'
getLocationHash
'
).
and
.
returnValue
(
'
note_something-that-does-not-exist
'
);
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
window
.
notes
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
});
});
...
...
@@ -414,7 +413,7 @@ import 'vendor/jquery.scrollTo';
this
.
class
.
loadDiff
(
'
/foo/bar/merge_requests/1/diffs
'
);
expect
(
noteLineNumId
.
length
).
toBeGreaterThan
(
0
);
expect
(
window
.
notes
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
expect
(
Notes
.
instance
.
toggleDiffNote
).
not
.
toHaveBeenCalled
();
});
});
});
...
...
spec/javascripts/notes_spec.js
View file @
f8cda25d
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
/* global Notes */
import
*
as
urlUtils
from
'
~/lib/utils/url_utility
'
;
import
'
autosize
'
;
import
'
~/gl_form
'
;
import
'
~/lib/utils/text_utility
'
;
import
'
~/render_gfm
'
;
import
'
~/notes
'
;
import
Notes
from
'
~/notes
'
;
(
function
()
{
window
.
gon
||
(
window
.
gon
=
{});
...
...
spec/javascripts/right_sidebar_spec.js
View file @
f8cda25d
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */
/* global Sidebar */
import
'
~/commons/bootstrap
'
;
import
'
~/right_sidebar
'
;
import
Sidebar
from
'
~/right_sidebar
'
;
(
function
()
{
var
$aside
,
$icon
,
$labelsIcon
,
$page
,
$toggle
,
assertSidebarState
;
...
...
spec/serializers/merge_request_serializer_spec.rb
View file @
f8cda25d
require
'spec_helper'
describe
MergeRequestSerializer
do
let
(
:user
)
{
build_stubbed
(
:user
)
}
let
(
:merge_request
)
{
build_stubbed
(
:merge_request
)
}
let
(
:serializer
)
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:resource
)
{
create
(
:merge_request
)
}
let
(
:json_entity
)
do
described_class
.
new
(
current_user:
user
)
.
represent
(
resource
,
serializer:
serializer
)
.
with_indifferent_access
end
describe
'#represent'
do
let
(
:opts
)
{
{
serializer:
serializer_entity
}
}
subject
{
serializer
.
represent
(
merge_request
,
serializer:
serializer_entity
)
}
context
'widget merge request serialization'
do
let
(
:serializer
)
{
'widget'
}
context
'when passing basic serializer param'
do
let
(
:serializer_entity
)
{
'basic'
}
it
'matches issue json schema'
do
expect
(
json_entity
).
to
match_schema
(
'entities/merge_request_widget'
)
end
end
it
'calls super class #represent with correct params'
do
expect_any_instance_of
(
BaseSerializer
).
to
receive
(
:represent
)
.
with
(
merge_request
,
opts
,
MergeRequestBasicEntity
)
context
'sidebar merge request serialization'
do
let
(
:serializer
)
{
'sidebar'
}
subject
it
'matches basic merge request json schema'
do
expect
(
json_entity
).
to
match_schema
(
'entities/merge_request_basic'
)
end
end
context
'when serializer param is falsy'
do
let
(
:serializer_entity
)
{
nil
}
it
'calls super class #represent with correct params'
do
expect_any_instance_of
(
BaseSerializer
).
to
receive
(
:represent
)
.
with
(
merge_request
,
opts
,
MergeRequestEntity
)
context
'basic merge request serialization'
do
let
(
:serializer
)
{
'basic'
}
subject
it
'matches basic merge request json schema'
do
expect
(
json_entity
).
to
match_schema
(
'entities/merge_request_basic'
)
end
end
context
'no serializer'
do
let
(
:serializer
)
{
nil
}
it
'raises an error'
do
expect
{
json_entity
}.
to
raise_error
(
NoMethodError
)
end
end
end
spec/serializers/merge_request_entity_spec.rb
→
spec/serializers/merge_request_
widget_
entity_spec.rb
View file @
f8cda25d
require
'spec_helper'
describe
MergeRequestEntity
do
describe
MergeRequest
Widget
Entity
do
let
(
:project
)
{
create
:project
,
:repository
}
let
(
:resource
)
{
create
(
:merge_request
,
source_project:
project
,
target_project:
project
)
}
let
(
:user
)
{
create
(
:user
)
}
...
...
@@ -35,37 +35,6 @@ describe MergeRequestEntity do
end
end
it
'includes issues_links'
do
issues_links
=
subject
[
:issues_links
]
expect
(
issues_links
).
to
include
(
:closing
,
:mentioned_but_not_closing
,
:assign_to_closing
)
end
it
'has Issuable attributes'
do
expect
(
subject
).
to
include
(
:id
,
:iid
,
:author_id
,
:description
,
:lock_version
,
:milestone_id
,
:title
,
:updated_by_id
,
:created_at
,
:updated_at
,
:milestone
,
:labels
)
end
it
'has time estimation attributes'
do
expect
(
subject
).
to
include
(
:time_estimate
,
:total_time_spent
,
:human_time_estimate
,
:human_total_time_spent
)
end
it
'has important MergeRequest attributes'
do
expect
(
subject
).
to
include
(
:state
,
:deleted_at
,
:diff_head_sha
,
:merge_commit_message
,
:has_conflicts
,
:has_ci
,
:merge_path
,
:conflict_resolution_path
,
:cancel_merge_when_pipeline_succeeds_path
,
:create_issue_to_resolve_discussions_path
,
:source_branch_path
,
:target_branch_commits_path
,
:target_branch_tree_path
,
:commits_count
,
:merge_ongoing
,
:ff_only_enabled
,
## EE
:can_push_to_source_branch
,
:approvals_before_merge
,
:squash
,
:rebase_commit_sha
,
:rebase_in_progress
,
:approvals_path
)
end
it
'has email_patches_path'
do
expect
(
subject
[
:email_patches_path
])
.
to
eq
(
"/
#{
resource
.
project
.
full_path
}
/merge_requests/
#{
resource
.
iid
}
.patch"
)
...
...
@@ -120,18 +89,6 @@ describe MergeRequestEntity do
end
end
it
'includes merge_event'
do
create
(
:event
,
:merged
,
author:
user
,
project:
resource
.
project
,
target:
resource
)
expect
(
subject
[
:merge_event
]).
to
include
(
:author
,
:updated_at
)
end
it
'includes closed_event'
do
create
(
:event
,
:closed
,
author:
user
,
project:
resource
.
project
,
target:
resource
)
expect
(
subject
[
:closed_event
]).
to
include
(
:author
,
:updated_at
)
end
describe
'diverged_commits_count'
do
context
'when MR open and its diverging'
do
it
'returns diverged commits count'
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment