Commit d71bbcaf authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2017-12-12

# Conflicts:
#	app/assets/javascripts/sidebar/sidebar_mediator.js
#	app/assets/stylesheets/pages/groups.scss
#	app/controllers/projects/merge_requests_controller.rb
#	app/models/epic.rb
#	app/models/user.rb
#	app/policies/group_policy.rb
#	app/services/ci/create_pipeline_service.rb
#	app/services/protected_branches/access_level_params.rb
#	app/services/protected_branches/api_service.rb
#	app/views/layouts/_search.html.haml
#	app/views/layouts/nav/sidebar/_group.html.haml
#	app/views/projects/commits/_commit.html.haml
#	app/views/projects/issues/show.html.haml
#	app/views/shared/_outdated_browser.html.haml
#	config/routes/group.rb
#	doc/administration/index.md
#	doc/administration/operations/index.md
#	doc/development/automatic_ce_ee_merge.md
#	doc/development/limit_ee_conflicts.md
#	lib/api/entities.rb
#	lib/api/projects.rb
#	lib/banzai/filter/epic_reference_filter.rb
#	lib/banzai/filter/upload_link_filter.rb
#	lib/banzai/reference_parser/epic_parser.rb
#	lib/gitlab/ci/pipeline/chain/command.rb
#	lib/gitlab/git_access.rb
#	lib/gitlab/utils.rb
#	spec/helpers/boards_helper_spec.rb
#	spec/helpers/merge_requests_helper_spec.rb
#	spec/javascripts/boards/boards_store_spec.js
#	spec/lib/banzai/filter/upload_link_filter_spec.rb
#	spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb
#	spec/models/namespace_spec.rb

[ci skip]
parents b5862567 8d739237
...@@ -599,6 +599,7 @@ merge request: ...@@ -599,6 +599,7 @@ merge request:
present time and never use past tense (has been/was). For example instead present time and never use past tense (has been/was). For example instead
of _prohibited this user from being saved due to the following errors:_ the of _prohibited this user from being saved due to the following errors:_ the
text should be _sorry, we could not create your account because:_ text should be _sorry, we could not create your account because:_
1. Code should be written in [US English][us-english]
This is also the style used by linting tools such as This is also the style used by linting tools such as
[RuboCop](https://github.com/bbatsov/rubocop), [RuboCop](https://github.com/bbatsov/rubocop),
...@@ -682,6 +683,7 @@ When your code contains more than 500 changes, any major breaking changes, or an ...@@ -682,6 +683,7 @@ When your code contains more than 500 changes, any major breaking changes, or an
[GitLab Inc engineering workflow]: https://about.gitlab.com/handbook/engineering/workflow/#labelling-issues [GitLab Inc engineering workflow]: https://about.gitlab.com/handbook/engineering/workflow/#labelling-issues
[polling-etag]: https://docs.gitlab.com/ce/development/polling.html [polling-etag]: https://docs.gitlab.com/ce/development/polling.html
[testing]: doc/development/testing_guide/index.md [testing]: doc/development/testing_guide/index.md
[us-english]: https://en.wikipedia.org/wiki/American_English
[^1]: Please note that specs other than JavaScript specs are considered backend [^1]: Please note that specs other than JavaScript specs are considered backend
code. code.
...@@ -295,7 +295,7 @@ group :metrics do ...@@ -295,7 +295,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false gem 'influxdb', '~> 0.2', require: false
# Prometheus # Prometheus
gem 'prometheus-client-mmap', '~> 0.7.0.beta39' gem 'prometheus-client-mmap', '~> 0.7.0.beta43'
gem 'raindrops', '~> 0.18' gem 'raindrops', '~> 0.18'
end end
...@@ -427,3 +427,6 @@ gem 'flipper-active_record', '~> 0.10.2' ...@@ -427,3 +427,6 @@ gem 'flipper-active_record', '~> 0.10.2'
# Structured logging # Structured logging
gem 'lograge', '~> 0.5' gem 'lograge', '~> 0.5'
gem 'grape_logging', '~> 1.7' gem 'grape_logging', '~> 1.7'
# Asset synchronization
gem 'asset_sync', '~> 2.2.0'
...@@ -58,6 +58,11 @@ GEM ...@@ -58,6 +58,11 @@ GEM
asciidoctor (1.5.3) asciidoctor (1.5.3)
asciidoctor-plantuml (0.0.7) asciidoctor-plantuml (0.0.7)
asciidoctor (~> 1.5) asciidoctor (~> 1.5)
asset_sync (2.2.0)
activemodel (>= 4.1.0)
fog-core
mime-types (>= 2.99)
unf
ast (2.3.0) ast (2.3.0)
atomic (1.1.99) atomic (1.1.99)
attr_encrypted (3.0.3) attr_encrypted (3.0.3)
...@@ -514,7 +519,6 @@ GEM ...@@ -514,7 +519,6 @@ GEM
mini_mime (0.1.4) mini_mime (0.1.4)
mini_portile2 (2.3.0) mini_portile2 (2.3.0)
minitest (5.7.0) minitest (5.7.0)
mmap2 (2.2.9)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.12.2) multi_json (1.12.2)
multi_xml (0.6.0) multi_xml (0.6.0)
...@@ -652,8 +656,7 @@ GEM ...@@ -652,8 +656,7 @@ GEM
parser parser
unparser unparser
procto (0.0.3) procto (0.0.3)
prometheus-client-mmap (0.7.0.beta39) prometheus-client-mmap (0.7.0.beta43)
mmap2 (~> 2.2, >= 2.2.9)
pry (0.10.4) pry (0.10.4)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
...@@ -1007,6 +1010,7 @@ DEPENDENCIES ...@@ -1007,6 +1010,7 @@ DEPENDENCIES
asana (~> 0.6.0) asana (~> 0.6.0)
asciidoctor (~> 1.5.2) asciidoctor (~> 1.5.2)
asciidoctor-plantuml (= 0.0.7) asciidoctor-plantuml (= 0.0.7)
asset_sync (~> 2.2.0)
attr_encrypted (~> 3.0.0) attr_encrypted (~> 3.0.0)
awesome_print (~> 1.2.0) awesome_print (~> 1.2.0)
aws-sdk aws-sdk
...@@ -1147,7 +1151,7 @@ DEPENDENCIES ...@@ -1147,7 +1151,7 @@ DEPENDENCIES
peek-sidekiq (~> 1.0.3) peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2) pg (~> 0.18.2)
premailer-rails (~> 1.9.7) premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.7.0.beta39) prometheus-client-mmap (~> 0.7.0.beta43)
pry-byebug (~> 3.4.1) pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4) pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1) rack-attack (~> 4.4.1)
......
{"iconCount":179,"spriteSize":81882,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} {"iconCount":180,"spriteSize":82176,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file \ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
<svg height="128" viewBox="0 0 142 128" width="142" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M94 62h20v4H94z" fill="#f0edf8"/><path d="M84.828 84l17.678 17.678-2.828 2.828L82 86.828z" fill="#fee1d3"/><path d="M42.828 24l17.678 17.678-2.828 2.828L40 26.828zM40 101.678L57.678 84l2.828 2.828-17.678 17.678z" fill="#f0edf8"/><g fill="#fee1d3"><path d="M82 41.678L99.678 24l2.828 2.828-17.678 17.678zM28 62h20v4H28z"/><rect height="30" rx="5" width="30" y="49"/></g><rect height="26" rx="5" stroke="#fdc4a8" stroke-width="4" width="26" x="2" y="51"/><rect fill="#c3b8e3" height="50" rx="10" width="50" x="46" y="39"/><rect height="46" rx="10" stroke="#6b4fbb" stroke-width="4" width="46" x="48" y="41"/><rect fill="#fef0e8" height="30" rx="5" width="30" x="84"/><rect height="26" rx="5" stroke="#fee1d3" stroke-width="4" width="26" x="86" y="2"/><rect fill="#fee1d3" height="30" rx="5" width="30" x="84" y="98"/><rect height="26" rx="5" stroke="#fdc4a8" stroke-width="4" width="26" x="86" y="100"/><rect fill="#f0edf8" height="30" rx="5" width="30" x="112" y="49"/><rect height="26" rx="5" stroke="#e1dbf1" stroke-width="4" width="26" x="114" y="51"/><rect fill="#f0edf8" height="30" rx="5" width="30" x="28" y="98"/><rect height="26" rx="5" stroke="#e1dbf1" stroke-width="4" width="26" x="30" y="100"/><rect fill="#f0edf8" height="30" rx="5" width="30" x="28"/><rect height="26" rx="5" stroke="#e1dbf1" stroke-width="4" width="26" x="30" y="2"/></g></svg> <svg height="128" viewBox="0 0 142 128" width="142" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M94 62h20v4H94z" fill="#f0edf8"/><path d="M84.828 84l17.678 17.678-2.828 2.828L82 86.828z" fill="#fee1d3"/><path d="M42.828 24l17.678 17.678-2.828 2.828L40 26.828zM40 101.678L57.678 84l2.828 2.828-17.678 17.678z" fill="#f0edf8"/><path d="M82 41.678L99.678 24l2.828 2.828-17.678 17.678zM28 62h20v4H28zM3 52h24v24H3z" fill="#fee1d3"/><path d="M31 3h24v24H31z" fill="#f0edf8"/><path d="M87 3h24v24H87z" fill="#fef0e8"/><path d="M115 52h24v24h-24z" fill="#f0edf8"/><path d="M87 101h24v24H87z" fill="#fee1d3"/><path d="M31 101h24v24H31z" fill="#f0edf8"/><path d="M49 42h44v44H49z" fill="#c3b8e3"/><g fill-rule="nonzero"><path d="M5 53a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V54a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H5a5 5 0 0 1-5-5V54a5 5 0 0 1 5-5z" fill="#fdc4a8"/><path d="M56 43a6 6 0 0 0-6 6v30a6 6 0 0 0 6 6h30a6 6 0 0 0 6-6V49a6 6 0 0 0-6-6zm0-4h30c5.523 0 10 4.477 10 10v30c0 5.523-4.477 10-10 10H56c-5.523 0-10-4.477-10-10V49c0-5.523 4.477-10 10-10z" fill="#6b4fbb"/><path d="M89 4a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H89a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z" fill="#fee1d3"/><path d="M89 102a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1v-20a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H89a5 5 0 0 1-5-5v-20a5 5 0 0 1 5-5z" fill="#fdc4a8"/><path d="M117 53a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V54a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5h-20a5 5 0 0 1-5-5V54a5 5 0 0 1 5-5zM33 102a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1v-20a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H33a5 5 0 0 1-5-5v-20a5 5 0 0 1 5-5zM33 4a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H33a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z" fill="#e1dbf1"/></g></g></svg>
\ No newline at end of file \ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 374 268" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="d" width="230" height="176" rx="10" fill="#fff"/><rect id="e" width="14" rx="2" height="4"/><rect id="f" width="14" x="40" rx="2" height="4"/><rect id="g" width="14" x="40" y="24" rx="2" height="4"/><rect id="h" width="7" x="20" y="12" rx="2" height="4"/><rect id="i" width="7" y="24" rx="2" height="4"/><rect id="j" width="7" x="33" y="12" rx="2" height="4"/><circle id="l" cx="31" cy="31" r="31"/><circle id="c" cx="35" cy="35" r="35"/><circle id="a" cx="44" cy="44" r="44"/><circle id="b" cx="31" cy="31" r="31"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(0 94)"><circle cx="57" cy="57" r="44" fill="#f9f9f9"/><g transform="rotate(-7.999 120.507 -22.508)"><use fill="#fff" xlink:href="#a"/><circle cx="44" cy="44" r="42" stroke="#eee" stroke-width="4"/><path fill="#fee1d3" fill-rule="nonzero" d="M34.394 55.736A4 4 0 0 1 36.706 55H56a6 6 0 0 0 6-6V35a6 6 0 0 0-6-6H34a6 6 0 0 0-6 6v25.26l6.394-4.529m2.312 3.264l-7.972 5.647A3.001 3.001 0 0 1 24 62.194v-27.2c0-5.523 4.477-10 10-10h22c5.523 0 10 4.477 10 10v14c0 5.523-4.477 10-10 10H36.706"/><path fill="#fc6d26" d="M38 40a2 2 0 1 1 .001 3.999A2 2 0 0 1 38 40m7 0a2 2 0 1 1 .001 3.999A2 2 0 0 1 45 40m7 0a2 2 0 1 1 .001 3.999A2 2 0 0 1 52 40"/></g></g><g transform="translate(48)"><circle cx="41" cy="41" r="31" fill="#f9f9f9"/><g transform="rotate(-7.999 84.554 -15.551)"><use fill="#fff" xlink:href="#b"/><circle cx="31" cy="31" r="29" stroke="#eee" stroke-width="4"/><rect width="20" height="4" x="21" y="29" fill="#6b4fbb" rx="2"/></g></g><path fill="#f9f9f9" d="M235.58 229H102c-6.627 0-12-5.373-12-12V65c0-6.627 5.373-12 12-12h206c6.627 0 12 5.373 12 12v18.399A34.834 34.834 0 0 1 337 79c19.33 0 35 15.67 35 35s-15.67 35-35 35a34.831 34.831 0 0 1-17-4.399v72.4c0 6.627-5.373 12-12 12h-11.58c.381 1.941.58 3.947.58 6 0 17.12-13.879 31-31 31-17.12 0-31-13.879-31-31 0-2.053.2-4.059.58-6"/><g transform="translate(87 50)"><g transform="rotate(7.999 -44.933 1563.894)"><use fill="#fff" xlink:href="#c"/><circle cx="35" cy="35" r="33" stroke="#eee" stroke-width="4"/><g transform="translate(20 19)"><circle cx="15" cy="16" r="15" fill="#f4f1fa" stroke="#6b4fbb" stroke-width="3"/><g fill="#6b4fbb"><path d="M19.419 6.996h-.007L16.959 4l-2.454 2.997H14.5L12.046 4 9.591 6.998h-.003L7.133 4 4.677 6.999H2.001c2.605-4.204 7.231-7 12.502-7 5.269 0 9.892 2.793 12.498 6.994h-2.676l-2.452-2.994-2.453 2.996"/><circle cx="9.5" cy="17.5" r="1.5"/><circle cx="20.5" cy="17.5" r="1.5"/></g></g></g><use xlink:href="#d"/><rect width="226" height="172" x="2" y="2" stroke="#eee" stroke-width="4" rx="10"/><rect width="4" height="122" x="33" y="42" fill="#eee" rx="2"/><g transform="translate(13 59)"><rect width="10" height="4" fill="#fee1d3" rx="2"/><rect width="10" height="4" y="12" fill="#f0edf8" rx="2"/><rect width="10" height="4" y="24" fill="#fef0e9" rx="2"/><rect width="10" height="4" y="36" fill="#fee1d3" rx="2"/><rect width="10" height="4" y="48" fill="#e1dbf1" rx="2"/><rect width="10" height="4" y="60" fill="#f0edf8" rx="2"/><rect width="10" height="4" y="72" fill="#fef0e9" rx="2"/><rect width="10" height="4" y="84" fill="#fee1d3" rx="2"/></g><g transform="translate(55 59)"><use fill="#6b4fbb" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#f0edf8" rx="2"/><use fill="#fef0e9" xlink:href="#f"/><rect width="14" height="4" y="12" fill="#f0edf8" rx="2"/><use fill="#fef0e9" xlink:href="#g"/><rect width="14" height="4" y="48" fill="#e1dbf1" rx="2"/><rect width="14" height="4" x="40" y="36" fill="#fef0e9" rx="2"/><use fill="#fee1d3" xlink:href="#h"/><rect width="7" height="4" x="27" y="36" fill="#6b4fbb" rx="2"/><rect width="7" height="4" x="20" y="48" fill="#fee1d3" rx="2"/><use fill="#fc6d26" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#e1dbf1" rx="2"/><rect width="21" height="4" y="36" fill="#eee" rx="2"/><use fill="#6b4fbb" xlink:href="#j"/><g transform="translate(98)"><use fill="#fee1d3" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#f0edf8" rx="2"/><use fill="#fc6d26" xlink:href="#f"/><rect width="14" height="4" y="12" fill="#fef0e9" rx="2" id="k"/><use fill="#e1dbf1" xlink:href="#g"/><rect width="14" height="4" y="48" fill="#f0edf8" rx="2"/><rect width="14" height="4" x="40" y="36" fill="#fee1d3" rx="2"/><use fill="#fc6d26" xlink:href="#h"/><rect width="7" height="4" x="27" y="36" fill="#6b4fbb" rx="2"/><rect width="7" height="4" x="20" y="48" fill="#fc6d26" rx="2"/><use fill="#6b4fbb" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#fee1d3" rx="2"/><rect width="21" height="4" y="36" fill="#fef0e9" rx="2"/><use fill="#6b4fbb" xlink:href="#j"/></g><g transform="translate(0 60)"><use fill="#f0edf8" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#6b4fbb" rx="2"/><use fill="#e1dbf1" xlink:href="#f"/><use xlink:href="#k"/><use fill="#fee1d3" xlink:href="#g"/><use fill="#eee" xlink:href="#h"/><use fill="#6b4fbb" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#fef0e9" rx="2"/><use fill="#fc6d26" xlink:href="#j"/></g><rect width="4" height="63" x="74" y="13" fill="#eee" rx="2"/></g><rect width="230" height="4" y="27" fill="#eee" rx="2"/></g><g transform="rotate(7.999 -1289.786 1797.583)"><use fill="#fff" xlink:href="#l"/><circle cx="31" cy="31" r="29" stroke="#eee" stroke-width="4"/><path fill="#fc6d26" d="M29 29h-6a2 2 0 1 0 0 4h6v6a2 2 0 1 0 4 0v-6h6a2 2 0 1 0 0-4h-6v-6a2 2 0 1 0-4 0v6"/></g></g></svg>
\ No newline at end of file
...@@ -121,7 +121,7 @@ export default class ImageFile { ...@@ -121,7 +121,7 @@ export default class ImageFile {
return $('.swipe.view', this.file).each((function(_this) { return $('.swipe.view', this.file).each((function(_this) {
return function(index, view) { return function(index, view) {
var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref; var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref;
ref = this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; ref = _this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
$swipeFrame = $('.swipe-frame', view); $swipeFrame = $('.swipe-frame', view);
$swipeWrap = $('.swipe-wrap', view); $swipeWrap = $('.swipe-wrap', view);
$swipeBar = $('.swipe-bar', view); $swipeBar = $('.swipe-bar', view);
...@@ -158,7 +158,7 @@ export default class ImageFile { ...@@ -158,7 +158,7 @@ export default class ImageFile {
return $('.onion-skin.view', this.file).each((function(_this) { return $('.onion-skin.view', this.file).each((function(_this) {
return function(index, view) { return function(index, view) {
var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false; var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false;
ref = this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; ref = _this.prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1];
$frame = $('.onion-skin-frame', view); $frame = $('.onion-skin-frame', view);
$frameAdded = $('.frame.added', view); $frameAdded = $('.frame.added', view);
$track = $('.drag-track', view); $track = $('.drag-track', view);
......
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
doAction() { doAction() {
this.isLoading = true; this.isLoading = true;
eventHub.$emit(`${this.type}.key`, this.deployKey); eventHub.$emit(`${this.type}.key`, this.deployKey, () => {
this.isLoading = false;
});
}, },
}, },
computed: { computed: {
...@@ -50,6 +52,9 @@ ...@@ -50,6 +52,9 @@
:disabled="isLoading" :disabled="isLoading"
@click="doAction"> @click="doAction">
{{ text }} {{ text }}
<loading-icon v-if="isLoading" /> <loading-icon
v-if="isLoading"
:inline="true"
/>
</button> </button>
</template> </template>
...@@ -47,12 +47,15 @@ ...@@ -47,12 +47,15 @@
.then(() => this.fetchKeys()) .then(() => this.fetchKeys())
.catch(() => new Flash('Error enabling deploy key')); .catch(() => new Flash('Error enabling deploy key'));
}, },
disableKey(deployKey) { disableKey(deployKey, callback) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (confirm('You are going to remove this deploy key. Are you sure?')) { if (confirm('You are going to remove this deploy key. Are you sure?')) {
this.service.disableKey(deployKey.id) this.service.disableKey(deployKey.id)
.then(() => this.fetchKeys()) .then(() => this.fetchKeys())
.then(callback)
.catch(() => new Flash('Error removing deploy key')); .catch(() => new Flash('Error removing deploy key'));
} else {
callback();
} }
}, },
}, },
......
...@@ -588,13 +588,6 @@ import initGroupAnalytics from './init_group_analytics'; ...@@ -588,13 +588,6 @@ import initGroupAnalytics from './init_group_analytics';
case 'projects:settings:ci_cd:show': case 'projects:settings:ci_cd:show':
// Initialize expandable settings panels // Initialize expandable settings panels
initSettingsPanels(); initSettingsPanels();
import(/* webpackChunkName: "ci-cd-settings" */ './projects/ci_cd_settings_bundle')
.then(ciCdSettings => ciCdSettings.default())
.catch((err) => {
Flash(s__('ProjectSettings|Problem setting up the CI/CD settings JavaScript'));
throw err;
});
case 'groups:settings:ci_cd:show': case 'groups:settings:ci_cd:show':
new ProjectVariables(); new ProjectVariables();
break; break;
......
...@@ -287,6 +287,10 @@ class GfmAutoComplete { ...@@ -287,6 +287,10 @@ class GfmAutoComplete {
} }
setupLabels($input) { setupLabels($input) {
const fetchData = this.fetchData.bind(this);
const LABEL_COMMAND = { LABEL: '/label', UNLABEL: '/unlabel', RELABEL: '/relabel' };
let command = '';
$input.atwho({ $input.atwho({
at: '~', at: '~',
alias: 'labels', alias: 'labels',
...@@ -309,8 +313,45 @@ class GfmAutoComplete { ...@@ -309,8 +313,45 @@ class GfmAutoComplete {
title: sanitize(m.title), title: sanitize(m.title),
color: m.color, color: m.color,
search: m.title, search: m.title,
set: m.set,
})); }));
}, },
matcher(flag, subtext) {
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
const subtextNodes = subtext.split(/\n+/g).pop().split(GfmAutoComplete.regexSubtext);
// Check if ~ is followed by '/label', '/relabel' or '/unlabel' commands.
command = subtextNodes.find((node) => {
if (node === LABEL_COMMAND.LABEL ||
node === LABEL_COMMAND.RELABEL ||
node === LABEL_COMMAND.UNLABEL) { return node; }
return null;
});
return match && match.length ? match[1] : null;
},
filter(query, data, searchKey) {
if (GfmAutoComplete.isLoading(data)) {
fetchData(this.$inputor, this.at);
return data;
}
if (data === GfmAutoComplete.defaultLoadingData) {
return $.fn.atwho.default.callbacks.filter(query, data, searchKey);
}
// The `LABEL_COMMAND.RELABEL` is intentionally skipped
// because we want to return all the labels (unfiltered) for that command.
if (command === LABEL_COMMAND.LABEL) {
// Return labels with set: undefined.
return data.filter(label => !label.set);
} else if (command === LABEL_COMMAND.UNLABEL) {
// Return labels with set: true.
return data.filter(label => label.set);
}
return data;
},
}, },
}); });
} }
...@@ -346,20 +387,7 @@ class GfmAutoComplete { ...@@ -346,20 +387,7 @@ class GfmAutoComplete {
return resultantValue; return resultantValue;
}, },
matcher(flag, subtext) { matcher(flag, subtext) {
// The below is taken from At.js source const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
const atSymbolsWithBar = Object.keys(this.app.controllers).join('|');
const atSymbolsWithoutBar = Object.keys(this.app.controllers).join('');
const targetSubtext = subtext.split(/\s+/g).pop();
const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF');
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
const match = regexp.exec(targetSubtext);
if (match) { if (match) {
return match[1]; return match[1];
...@@ -420,8 +448,27 @@ class GfmAutoComplete { ...@@ -420,8 +448,27 @@ class GfmAutoComplete {
return dataToInspect && return dataToInspect &&
(dataToInspect === loadingState || dataToInspect.name === loadingState); (dataToInspect === loadingState || dataToInspect.name === loadingState);
} }
static defaultMatcher(flag, subtext, controllers) {
// The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
const atSymbolsWithBar = Object.keys(controllers).join('|');
const atSymbolsWithoutBar = Object.keys(controllers).join('');
const targetSubtext = subtext.split(GfmAutoComplete.regexSubtext).pop();
const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF');
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
return regexp.exec(targetSubtext);
}
} }
GfmAutoComplete.regexSubtext = new RegExp(/\s+/g);
GfmAutoComplete.defaultLoadingData = ['loading']; GfmAutoComplete.defaultLoadingData = ['loading'];
GfmAutoComplete.atTypeMap = { GfmAutoComplete.atTypeMap = {
......
...@@ -5,7 +5,7 @@ import '../vue_shared/vue_resource_interceptor'; ...@@ -5,7 +5,7 @@ import '../vue_shared/vue_resource_interceptor';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const initialDataEl = document.getElementById('js-issuable-app-initial-data'); const initialDataEl = document.getElementById('js-issuable-app-initial-data');
const initialData = JSON.parse(initialDataEl.innerHTML.replace(/&quot;/g, '"')); const props = JSON.parse(initialDataEl.innerHTML.replace(/&quot;/g, '"'));
$('.issuable-edit').on('click', (e) => { $('.issuable-edit').on('click', (e) => {
e.preventDefault(); e.preventDefault();
...@@ -18,32 +18,9 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -18,32 +18,9 @@ document.addEventListener('DOMContentLoaded', () => {
components: { components: {
issuableApp, issuableApp,
}, },
data() {
return {
...initialData,
};
},
render(createElement) { render(createElement) {
return createElement('issuable-app', { return createElement('issuable-app', {
props: { props,
canUpdate: this.canUpdate,
canDestroy: this.canDestroy,
endpoint: this.endpoint,
issuableRef: this.issuableRef,
initialTitleHtml: this.initialTitleHtml,
initialTitleText: this.initialTitleText,
initialDescriptionHtml: this.initialDescriptionHtml,
initialDescriptionText: this.initialDescriptionText,
issuableTemplates: this.issuableTemplates,
markdownPreviewPath: this.markdownPreviewPath,
markdownDocsPath: this.markdownDocsPath,
projectPath: this.projectPath,
projectNamespace: this.projectNamespace,
updatedAt: this.updatedAt,
updatedByName: this.updatedByName,
updatedByPath: this.updatedByPath,
initialTaskStatus: this.initialTaskStatus,
},
}); });
}, },
}); });
......
...@@ -35,8 +35,6 @@ window.dateFormat = dateFormat; ...@@ -35,8 +35,6 @@ window.dateFormat = dateFormat;
w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago = true) { w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago = true) {
$timeagoEls.each((i, el) => { $timeagoEls.each((i, el) => {
el.setAttribute('title', el.getAttribute('title'));
if (setTimeago) { if (setTimeago) {
// Recreate with custom template // Recreate with custom template
$(el).tooltip({ $(el).tooltip({
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics), hasMetrics: convertPermissionToBoolean(metricsData.hasMetrics),
documentationPath: metricsData.documentationPath, documentationPath: metricsData.documentationPath,
settingsPath: metricsData.settingsPath, settingsPath: metricsData.settingsPath,
tagsPath: metricsData.tagsPath,
projectPath: metricsData.projectPath,
metricsEndpoint: metricsData.additionalMetrics, metricsEndpoint: metricsData.additionalMetrics,
deploymentEndpoint: metricsData.deploymentEndpoint, deploymentEndpoint: metricsData.deploymentEndpoint,
emptyGettingStartedSvgPath: metricsData.emptyGettingStartedSvgPath, emptyGettingStartedSvgPath: metricsData.emptyGettingStartedSvgPath,
...@@ -112,6 +114,8 @@ ...@@ -112,6 +114,8 @@
:hover-data="hoverData" :hover-data="hoverData"
:update-aspect-ratio="updateAspectRatio" :update-aspect-ratio="updateAspectRatio"
:deployment-data="store.deploymentData" :deployment-data="store.deploymentData"
:project-path="projectPath"
:tags-path="tagsPath"
/> />
</graph-group> </graph-group>
</div> </div>
......
...@@ -30,6 +30,14 @@ ...@@ -30,6 +30,14 @@
required: false, required: false,
default: () => ({}), default: () => ({}),
}, },
projectPath: {
type: String,
required: true,
},
tagsPath: {
type: String,
required: true,
},
}, },
mixins: [MonitoringMixin], mixins: [MonitoringMixin],
...@@ -251,6 +259,14 @@ ...@@ -251,6 +259,14 @@
:line-color="path.lineColor" :line-color="path.lineColor"
:area-color="path.areaColor" :area-color="path.areaColor"
/> />
<rect
class="prometheus-graph-overlay"
:width="(graphWidth - 70)"
:height="(graphHeight - 100)"
transform="translate(-5, 20)"
ref="graphOverlay"
@mousemove="handleMouseOverGraph($event)">
</rect>
<graph-deployment <graph-deployment
:show-deploy-info="showDeployInfo" :show-deploy-info="showDeployInfo"
:deployment-data="reducedDeploymentData" :deployment-data="reducedDeploymentData"
...@@ -267,14 +283,6 @@ ...@@ -267,14 +283,6 @@
:graph-height-offset="graphHeightOffset" :graph-height-offset="graphHeightOffset"
:show-flag-content="showFlagContent" :show-flag-content="showFlagContent"
/> />
<rect
class="prometheus-graph-overlay"
:width="(graphWidth - 70)"
:height="(graphHeight - 100)"
transform="translate(-5, 20)"
ref="graphOverlay"
@mousemove="handleMouseOverGraph($event)">
</rect>
</svg> </svg>
</svg> </svg>
</div> </div>
......
<script> <script>
import { dateFormat, timeFormat } from '../../utils/date_time_formatters'; import { dateFormatWithName, timeFormat } from '../../utils/date_time_formatters';
import Icon from '../../../vue_shared/components/icon.vue';
export default { export default {
props: { props: {
...@@ -25,6 +26,10 @@ ...@@ -25,6 +26,10 @@
}, },
}, },
components: {
Icon,
},
computed: { computed: {
calculatedHeight() { calculatedHeight() {
return this.graphHeight - this.graphHeightOffset; return this.graphHeight - this.graphHeightOffset;
...@@ -33,7 +38,7 @@ ...@@ -33,7 +38,7 @@
methods: { methods: {
refText(d) { refText(d) {
return d.tag ? d.ref : d.sha.slice(0, 6); return d.tag ? d.ref : d.sha.slice(0, 8);
}, },
formatTime(deploymentTime) { formatTime(deploymentTime) {
...@@ -41,7 +46,7 @@ ...@@ -41,7 +46,7 @@
}, },
formatDate(deploymentTime) { formatDate(deploymentTime) {
return dateFormat(deploymentTime); return dateFormatWithName(deploymentTime);
}, },
nameDeploymentClass(deployment) { nameDeploymentClass(deployment) {
...@@ -54,11 +59,19 @@ ...@@ -54,11 +59,19 @@
positionFlag(deployment) { positionFlag(deployment) {
let xPosition = 3; let xPosition = 3;
if (deployment.xPos > (this.graphWidth - 200)) { if (deployment.xPos > (this.graphWidth - 225)) {
xPosition = -97; xPosition = -142;
} }
return xPosition; return xPosition;
}, },
svgContainerHeight(tag) {
let svgHeight = 80;
if (!tag) {
svgHeight -= 20;
}
return svgHeight;
},
}, },
}; };
</script> </script>
...@@ -91,35 +104,75 @@ ...@@ -91,35 +104,75 @@
class="js-deploy-info-box" class="js-deploy-info-box"
:x="positionFlag(deployment)" :x="positionFlag(deployment)"
y="0" y="0"
width="92" width="134"
height="60"> :height="svgContainerHeight(deployment.tag)">
<rect <rect
class="rect-text-metric deploy-info-rect rect-metric" class="rect-text-metric deploy-info-rect rect-metric"
x="1" x="1"
y="1" y="1"
rx="2" rx="2"
width="90" width="132"
height="58"> :height="svgContainerHeight(deployment.tag) - 2">
</rect> </rect>
<g
transform="translate(5, 2)">
<text <text
class="deploy-info-text text-metric-bold"> class="deploy-info-text text-metric-bold"
{{refText(deployment)}}
</text>
</g>
<text
class="deploy-info-text"
y="18"
transform="translate(5, 2)"> transform="translate(5, 2)">
Deployed
</text>
<!--The date info-->
<g transform="translate(5, 20)">
<text class="deploy-info-text">
{{formatDate(deployment.time)}} {{formatDate(deployment.time)}}
</text> </text>
<text <text
class="deploy-info-text text-metric-bold" class="deploy-info-text text-metric-bold"
y="38" x="62">
transform="translate(5, 2)">
{{formatTime(deployment.time)}} {{formatTime(deployment.time)}}
</text> </text>
</g>
<line
class="divider-line"
x1="0"
y1="38"
x2="132"
:y2="38"
stroke="#000">
</line>
<!--Commit information-->
<g transform="translate(5, 40)">
<icon
name="commit"
:width="12"
:height="12"
:y="3">
</icon>
<a :xlink:href="deployment.commitUrl">
<text
class="deploy-info-text deploy-info-text-link"
transform="translate(20, 2)">
{{refText(deployment)}}
</text>
</a>
</g>
<!--Tag information-->
<g
transform="translate(5, 55)"
v-if="deployment.tag">
<icon
name="label"
:width="12"
:height="12"
:y="5">
</icon>
<a :xlink:href="deployment.tagUrl">
<text
class="deploy-info-text deploy-info-text-link"
transform="translate(20, 2)"
y="2">
{{deployment.tag}}
</text>
</a>
</g>
</svg> </svg>
</g> </g>
<svg <svg
......
...@@ -33,7 +33,9 @@ const mixins = { ...@@ -33,7 +33,9 @@ const mixins = {
id: deployment.id, id: deployment.id,
time, time,
sha: deployment.sha, sha: deployment.sha,
commitUrl: `${this.projectPath}/commit/${deployment.sha}`,
tag: deployment.tag, tag: deployment.tag,
tagUrl: `${this.tagsPath}/${deployment.tag}`,
ref: deployment.ref.name, ref: deployment.ref.name,
xPos, xPos,
showDeploymentFlag: false, showDeploymentFlag: false,
......
import d3 from 'd3'; import d3 from 'd3';
export const dateFormat = d3.time.format('%b %-d, %Y'); export const dateFormat = d3.time.format('%b %-d, %Y');
export const dateFormatWithName = d3.time.format('%a, %b %-d');
export const timeFormat = d3.time.format('%-I:%M%p'); export const timeFormat = d3.time.format('%-I:%M%p');
export const bisectDate = d3.bisector(d => d.time).left; export const bisectDate = d3.bisector(d => d.time).left;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
import issuableStateMixin from '../mixins/issuable_state'; import issuableStateMixin from '../mixins/issuable_state';
export default { export default {
name: 'issueCommentForm', name: 'commentForm',
data() { data() {
return { return {
note: '', note: '',
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import noteEditedText from './note_edited_text.vue'; import noteEditedText from './note_edited_text.vue';
import noteAwardsList from './note_awards_list.vue'; import noteAwardsList from './note_awards_list.vue';
import noteAttachment from './note_attachment.vue'; import noteAttachment from './note_attachment.vue';
import issueNoteForm from './issue_note_form.vue'; import noteForm from './note_form.vue';
import TaskList from '../../task_list'; import TaskList from '../../task_list';
import autosave from '../mixins/autosave'; import autosave from '../mixins/autosave';
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
noteEditedText, noteEditedText,
noteAwardsList, noteAwardsList,
noteAttachment, noteAttachment,
issueNoteForm, noteForm,
}, },
computed: { computed: {
noteBody() { noteBody() {
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
<div <div
v-html="note.note_html" v-html="note.note_html"
class="note-text md"></div> class="note-text md"></div>
<issue-note-form <note-form
v-if="isEditing" v-if="isEditing"
ref="noteForm" ref="noteForm"
@handleFormUpdate="handleFormUpdate" @handleFormUpdate="handleFormUpdate"
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import Flash from '../../flash'; import Flash from '../../flash';
import { SYSTEM_NOTE } from '../constants'; import { SYSTEM_NOTE } from '../constants';
import issueNote from './issue_note.vue';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import noteableNote from './noteable_note.vue';
import noteHeader from './note_header.vue'; import noteHeader from './note_header.vue';
import noteSignedOutWidget from './note_signed_out_widget.vue'; import noteSignedOutWidget from './note_signed_out_widget.vue';
import noteEditedText from './note_edited_text.vue'; import noteEditedText from './note_edited_text.vue';
import issueNoteForm from './issue_note_form.vue'; import noteForm from './note_form.vue';
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue'; import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
import autosave from '../mixins/autosave'; import autosave from '../mixins/autosave';
...@@ -25,12 +25,12 @@ ...@@ -25,12 +25,12 @@
}; };
}, },
components: { components: {
issueNote, noteableNote,
userAvatarLink, userAvatarLink,
noteHeader, noteHeader,
noteSignedOutWidget, noteSignedOutWidget,
noteEditedText, noteEditedText,
issueNoteForm, noteForm,
placeholderNote, placeholderNote,
placeholderSystemNote, placeholderSystemNote,
}, },
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
return placeholderNote; return placeholderNote;
} }
return issueNote; return noteableNote;
}, },
componentData(note) { componentData(note) {
return note.isPlaceholderNote ? note.notes[0] : note; return note.isPlaceholderNote ? note.notes[0] : note;
...@@ -209,7 +209,7 @@ ...@@ -209,7 +209,7 @@
type="button" type="button"
class="js-vue-discussion-reply btn btn-text-field" class="js-vue-discussion-reply btn btn-text-field"
title="Add a reply">Reply...</button> title="Add a reply">Reply...</button>
<issue-note-form <note-form
v-if="isReplying" v-if="isReplying"
save-button-title="Comment" save-button-title="Comment"
:discussion="note" :discussion="note"
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import noteHeader from './note_header.vue'; import noteHeader from './note_header.vue';
import noteActions from './note_actions.vue'; import noteActions from './note_actions.vue';
import issueNoteBody from './issue_note_body.vue'; import noteBody from './note_body.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
userAvatarLink, userAvatarLink,
noteHeader, noteHeader,
noteActions, noteActions,
issueNoteBody, noteBody,
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
...@@ -174,7 +174,7 @@ ...@@ -174,7 +174,7 @@
@handleDelete="deleteHandler" @handleDelete="deleteHandler"
/> />
</div> </div>
<issue-note-body <note-body
:note="note" :note="note"
:can-edit="note.current_user.can_edit" :can-edit="note.current_user.can_edit"
:is-editing="isEditing" :is-editing="isEditing"
......
...@@ -4,16 +4,16 @@ ...@@ -4,16 +4,16 @@
import Flash from '../../flash'; import Flash from '../../flash';
import store from '../stores/'; import store from '../stores/';
import * as constants from '../constants'; import * as constants from '../constants';
import issueNote from './issue_note.vue'; import noteableNote from './noteable_note.vue';
import issueDiscussion from './issue_discussion.vue'; import noteableDiscussion from './noteable_discussion.vue';
import systemNote from '../../vue_shared/components/notes/system_note.vue'; import systemNote from '../../vue_shared/components/notes/system_note.vue';
import issueCommentForm from './issue_comment_form.vue'; import commentForm from './comment_form.vue';
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue'; import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
name: 'issueNotesApp', name: 'notesApp',
props: { props: {
noteableData: { noteableData: {
type: Object, type: Object,
...@@ -36,10 +36,10 @@ ...@@ -36,10 +36,10 @@
}; };
}, },
components: { components: {
issueNote, noteableNote,
issueDiscussion, noteableDiscussion,
systemNote, systemNote,
issueCommentForm, commentForm,
loadingIcon, loadingIcon,
placeholderNote, placeholderNote,
placeholderSystemNote, placeholderSystemNote,
...@@ -69,10 +69,10 @@ ...@@ -69,10 +69,10 @@
} }
return placeholderNote; return placeholderNote;
} else if (note.individual_note) { } else if (note.individual_note) {
return note.notes[0].system ? systemNote : issueNote; return note.notes[0].system ? systemNote : noteableNote;
} }
return issueDiscussion; return noteableDiscussion;
}, },
getComponentData(note) { getComponentData(note) {
return note.individual_note ? note.notes[0] : note; return note.individual_note ? note.notes[0] : note;
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
.then(() => this.checkLocationHash()) .then(() => this.checkLocationHash())
.catch(() => { .catch(() => {
this.isLoading = false; this.isLoading = false;
Flash('Something went wrong while fetching issue comments. Please try again.'); Flash('Something went wrong while fetching comments. Please try again.');
}); });
}, },
initPolling() { initPolling() {
...@@ -147,6 +147,6 @@ ...@@ -147,6 +147,6 @@
/> />
</ul> </ul>
<issue-comment-form /> <comment-form />
</div> </div>
</template> </template>
import Vue from 'vue'; import Vue from 'vue';
import issueNotesApp from './components/issue_notes_app.vue'; import notesApp from './components/notes_app.vue';
document.addEventListener('DOMContentLoaded', () => new Vue({ document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#js-vue-notes', el: '#js-vue-notes',
components: { components: {
issueNotesApp, notesApp,
}, },
data() { data() {
const notesDataset = document.getElementById('js-vue-notes').dataset; const notesDataset = document.getElementById('js-vue-notes').dataset;
...@@ -32,7 +32,7 @@ document.addEventListener('DOMContentLoaded', () => new Vue({ ...@@ -32,7 +32,7 @@ document.addEventListener('DOMContentLoaded', () => new Vue({
}; };
}, },
render(createElement) { render(createElement) {
return createElement('issue-notes-app', { return createElement('notes-app', {
props: { props: {
noteableData: this.noteableData, noteableData: this.noteableData,
notesData: this.notesData, notesData: this.notesData,
......
function updateAutoDevopsRadios(radioWrappers) {
radioWrappers.forEach((radioWrapper) => {
const radio = radioWrapper.querySelector('.js-auto-devops-enable-radio');
const runPipelineCheckboxWrapper = radioWrapper.querySelector('.js-run-auto-devops-pipeline-checkbox-wrapper');
const runPipelineCheckbox = radioWrapper.querySelector('.js-run-auto-devops-pipeline-checkbox');
if (runPipelineCheckbox) {
runPipelineCheckbox.checked = radio.checked;
runPipelineCheckboxWrapper.classList.toggle('hide', !radio.checked);
}
});
}
export default function initCiCdSettings() {
const radioWrappers = document.querySelectorAll('.js-auto-devops-enable-radio-wrapper');
radioWrappers.forEach(radioWrapper =>
radioWrapper.addEventListener('change', () => updateAutoDevopsRadios(radioWrappers)),
);
}
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import newModal from './modal.vue'; import newModal from './modal.vue';
import upload from './upload.vue'; import upload from './upload.vue';
import icon from '../../../vue_shared/components/icon.vue';
export default { export default {
components: { components: {
icon,
newModal, newModal,
upload, upload,
}, },
...@@ -41,11 +43,14 @@ ...@@ -41,11 +43,14 @@
data-toggle="dropdown" data-toggle="dropdown"
aria-label="Create new file or directory" aria-label="Create new file or directory"
> >
<i <icon
class="fa fa-plus" name="plus"
aria-hidden="true" css-classes="pull-left"
> />
</i> <icon
name="arrow-down"
css-classes="pull-left"
/>
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li> <li>
......
<<<<<<< HEAD
import Store from 'ee/sidebar/stores/sidebar_store'; import Store from 'ee/sidebar/stores/sidebar_store';
=======
>>>>>>> upstream/master
import { visitUrl } from '../lib/utils/url_utility'; import { visitUrl } from '../lib/utils/url_utility';
import Flash from '../flash'; import Flash from '../flash';
import Service from './services/sidebar_service'; import Service from './services/sidebar_service';
......
import Project from '~/project';
import SmartInterval from '~/smart_interval'; import SmartInterval from '~/smart_interval';
import Flash from '../flash'; import Flash from '../flash';
import { import {
...@@ -140,6 +141,7 @@ export default { ...@@ -140,6 +141,7 @@ export default {
const el = document.createElement('div'); const el = document.createElement('div');
el.innerHTML = res.body; el.innerHTML = res.body;
document.body.appendChild(el); document.body.appendChild(el);
Project.initRefSwitcher();
} }
}) })
.catch(() => new Flash('Something went wrong. Please try again.')); .catch(() => new Flash('Something went wrong. Please try again.'));
......
...@@ -36,6 +36,30 @@ ...@@ -36,6 +36,30 @@
required: false, required: false,
default: '', default: '',
}, },
width: {
type: Number,
required: false,
default: null,
},
height: {
type: Number,
required: false,
default: null,
},
y: {
type: Number,
required: false,
default: null,
},
x: {
type: Number,
required: false,
default: null,
},
}, },
computed: { computed: {
...@@ -51,7 +75,11 @@ ...@@ -51,7 +75,11 @@
<template> <template>
<svg <svg
:class="[iconSizeClass, cssClasses]"> :class="[iconSizeClass, cssClasses]"
:width="width"
:height="height"
:x="x"
:y="y">
<use <use
v-bind="{'xlink:href':spriteHref}"/> v-bind="{'xlink:href':spriteHref}"/>
</svg> </svg>
......
...@@ -241,19 +241,6 @@ li.note { ...@@ -241,19 +241,6 @@ li.note {
} }
} }
.browser-alert {
padding: 10px;
text-align: center;
background: $error-bg;
color: $white-light;
font-weight: $gl-font-weight-bold;
a {
color: $white-light;
text-decoration: underline;
}
}
.warning_message { .warning_message {
border-left: 4px solid $warning-message-border; border-left: 4px solid $warning-message-border;
color: $warning-message-color; color: $warning-message-color;
......
...@@ -432,6 +432,7 @@ ...@@ -432,6 +432,7 @@
border-width: 1px; border-width: 1px;
width: 17px; width: 17px;
height: 17px; height: 17px;
top: 0;
} }
&:hover, &:hover,
......
...@@ -193,6 +193,7 @@ ...@@ -193,6 +193,7 @@
.commit-content { .commit-content {
padding-right: 10px; padding-right: 10px;
white-space: normal;
} }
.commit-actions { .commit-actions {
......
...@@ -361,8 +361,9 @@ ...@@ -361,8 +361,9 @@
stroke-width: 1; stroke-width: 1;
} }
.deploy-info-text { .divider-line {
dominant-baseline: text-before-edge; stroke-width: 1;
stroke: $gray-darkest;
} }
.prometheus-state { .prometheus-state {
...@@ -472,6 +473,20 @@ ...@@ -472,6 +473,20 @@
stroke: $gray-darker; stroke: $gray-darker;
} }
.deploy-info-text {
dominant-baseline: text-before-edge;
font-size: 12px;
}
.deploy-info-text-link {
font-family: $monospace_font;
fill: $gl-link-color;
&:hover {
fill: $gl-link-hover-color;
}
}
@media (max-width: $screen-sm-max) { @media (max-width: $screen-sm-max) {
.label-axis-text, .label-axis-text,
.text-metric-usage, .text-metric-usage,
......
...@@ -273,6 +273,7 @@ table.pipeline-project-metrics tr td { ...@@ -273,6 +273,7 @@ table.pipeline-project-metrics tr td {
border-radius: $label-border-radius; border-radius: $label-border-radius;
font-weight: $gl-font-weight-normal; font-weight: $gl-font-weight-normal;
} }
<<<<<<< HEAD
.plan-badge { .plan-badge {
margin-right: 15px; margin-right: 15px;
...@@ -308,3 +309,5 @@ table.pipeline-project-metrics tr td { ...@@ -308,3 +309,5 @@ table.pipeline-project-metrics tr td {
svg g { fill: $gl-no-plan; } svg g { fill: $gl-no-plan; }
} }
} }
=======
>>>>>>> upstream/master
...@@ -376,6 +376,12 @@ ...@@ -376,6 +376,12 @@
} }
} }
.nothing-here-block {
img {
width: 230px;
}
}
.mr-list { .mr-list {
.merge-request { .merge-request {
padding: 10px 0 10px 15px; padding: 10px 0 10px 15px;
......
...@@ -141,20 +141,20 @@ ...@@ -141,20 +141,20 @@
.sidebar-item-icon { .sidebar-item-icon {
border-radius: $border-radius-default; border-radius: $border-radius-default;
margin: 0 3px 0 -4px; margin: 0 5px 0 0;
vertical-align: middle; vertical-align: text-bottom;
&.is-active { &.is-active {
fill: $orange-600; fill: $orange-600;
} }
}
.sidebar-collapsed-icon .sidebar-item-icon { .sidebar-collapsed-icon & {
margin: 0; margin: 0;
} }
.sidebar-item-value .sidebar-item-icon { .sidebar-item-value & {
fill: $theme-gray-700; fill: $theme-gray-700;
}
} }
.sidebar-item-warning-message { .sidebar-item-warning-message {
......
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
.nav-block { .nav-block {
margin: 10px 0; margin: 10px 0;
.btn .fa,
.btn svg {
color: $gl-text-color-secondary;
}
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
display: flex; display: flex;
...@@ -91,8 +96,12 @@ ...@@ -91,8 +96,12 @@
} }
.add-to-tree { .add-to-tree {
vertical-align: middle; vertical-align: top;
padding: 6px 10px; padding: 8px;
svg {
top: 0;
}
} }
.tree-table { .tree-table {
......
...@@ -8,7 +8,7 @@ class Admin::HealthCheckController < Admin::ApplicationController ...@@ -8,7 +8,7 @@ class Admin::HealthCheckController < Admin::ApplicationController
end end
def reset_storage_health def reset_storage_health
Gitlab::Git::Storage::CircuitBreaker.reset_all! Gitlab::Git::Storage::FailureInfo.reset_all!
redirect_to admin_health_check_path, redirect_to admin_health_check_path,
notice: _('Git storage health information has been reset') notice: _('Git storage health information has been reset')
end end
......
...@@ -25,7 +25,7 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -25,7 +25,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
def update def update
@group_member = @group.group_members.find(params[:id]) @group_member = @group.members_and_requesters.find(params[:id])
return render_403 unless can?(current_user, :update_group_member, @group_member) return render_403 unless can?(current_user, :update_group_member, @group_member)
......
class HealthController < ActionController::Base class HealthController < ActionController::Base
protect_from_forgery with: :exception protect_from_forgery with: :exception, except: :storage_check
include RequiresWhitelistedMonitoringClient include RequiresWhitelistedMonitoringClient
CHECKS = [ CHECKS = [
...@@ -23,6 +23,15 @@ class HealthController < ActionController::Base ...@@ -23,6 +23,15 @@ class HealthController < ActionController::Base
render_check_results(results) render_check_results(results)
end end
def storage_check
results = Gitlab::Git::Storage::Checker.check_all
render json: {
check_interval: Gitlab::CurrentSettings.current_application_settings.circuitbreaker_check_interval,
results: results
}
end
private private
def render_check_results(results) def render_check_results(results)
......
...@@ -8,7 +8,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController ...@@ -8,7 +8,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
@personal_access_token = finder.build(personal_access_token_params) @personal_access_token = finder.build(personal_access_token_params)
if @personal_access_token.save if @personal_access_token.save
flash[:personal_access_token] = @personal_access_token.token PersonalAccessToken.redis_store!(current_user.id, @personal_access_token.token)
redirect_to profile_personal_access_tokens_path, notice: "Your new personal access token has been created." redirect_to profile_personal_access_tokens_path, notice: "Your new personal access token has been created."
else else
set_index_vars set_index_vars
...@@ -43,5 +43,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController ...@@ -43,5 +43,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
@inactive_personal_access_tokens = finder(state: 'inactive').execute @inactive_personal_access_tokens = finder(state: 'inactive').execute
@active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at) @active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at)
@new_personal_access_token = PersonalAccessToken.redis_getdel(current_user.id)
end end
end end
...@@ -2,7 +2,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController ...@@ -2,7 +2,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
before_action :load_autocomplete_service, except: [:members] before_action :load_autocomplete_service, except: [:members]
def members def members
render json: ::Projects::ParticipantsService.new(@project, current_user).execute(noteable) render json: ::Projects::ParticipantsService.new(@project, current_user).execute(target)
end end
def issues def issues
...@@ -14,7 +14,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController ...@@ -14,7 +14,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
end end
def labels def labels
render json: @autocomplete_service.labels render json: @autocomplete_service.labels(target)
end end
def milestones def milestones
...@@ -22,7 +22,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController ...@@ -22,7 +22,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
end end
def commands def commands
render json: @autocomplete_service.commands(noteable, params[:type]) render json: @autocomplete_service.commands(target, params[:type])
end end
private private
...@@ -31,13 +31,13 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController ...@@ -31,13 +31,13 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
@autocomplete_service = ::Projects::AutocompleteService.new(@project, current_user) @autocomplete_service = ::Projects::AutocompleteService.new(@project, current_user)
end end
def noteable def target
case params[:type] case params[:type]&.downcase
when 'Issue' when 'issue'
IssuesFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:type_id]) IssuesFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:type_id])
when 'MergeRequest' when 'mergerequest'
MergeRequestsFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:type_id]) MergeRequestsFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:type_id])
when 'Commit' when 'commit'
@project.commit(params[:type_id]) @project.commit(params[:type_id])
end end
end end
......
...@@ -22,7 +22,7 @@ class Projects::BoardsController < Projects::ApplicationController ...@@ -22,7 +22,7 @@ class Projects::BoardsController < Projects::ApplicationController
private private
def assign_endpoint_vars def assign_endpoint_vars
@boards_endpoint = project_boards_url(project) @boards_endpoint = project_boards_path(project)
@bulk_issues_path = bulk_update_project_issues_path(project) @bulk_issues_path = bulk_update_project_issues_path(project)
@namespace_path = project.namespace.full_path @namespace_path = project.namespace.full_path
@labels_endpoint = project_labels_path(project) @labels_endpoint = project_labels_path(project)
......
...@@ -6,8 +6,11 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -6,8 +6,11 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections include IssuableCollections
<<<<<<< HEAD
prepend ::EE::Projects::MergeRequestsController prepend ::EE::Projects::MergeRequestsController
=======
>>>>>>> upstream/master
skip_before_action :merge_request, only: [:index, :bulk_update] skip_before_action :merge_request, only: [:index, :bulk_update]
before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort] before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :set_issuables_index, only: [:index] before_action :set_issuables_index, only: [:index]
......
...@@ -29,7 +29,6 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController ...@@ -29,7 +29,6 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
:runners_token, :builds_enabled, :build_allow_git_fetch, :runners_token, :builds_enabled, :build_allow_git_fetch,
:build_timeout_in_minutes, :build_coverage_regex, :public_builds, :build_timeout_in_minutes, :build_coverage_regex, :public_builds,
:auto_cancel_pending_pipelines, :ci_config_path, :auto_cancel_pending_pipelines, :ci_config_path,
:run_auto_devops_pipeline_implicit, :run_auto_devops_pipeline_explicit,
auto_devops_attributes: [:id, :domain, :enabled] auto_devops_attributes: [:id, :domain, :enabled]
) )
end end
......
...@@ -26,7 +26,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -26,7 +26,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end end
def update def update
@project_member = @project.project_members.find(params[:id]) @project_member = @project.members_and_requesters.find(params[:id])
return render_403 unless can?(current_user, :update_project_member, @project_member) return render_403 unless can?(current_user, :update_project_member, @project_member)
......
...@@ -125,17 +125,6 @@ module ApplicationSettingsHelper ...@@ -125,17 +125,6 @@ module ApplicationSettingsHelper
_('The number of attempts GitLab will make to access a storage.') _('The number of attempts GitLab will make to access a storage.')
end end
def circuitbreaker_backoff_threshold_help_text
_("The number of failures after which GitLab will start temporarily "\
"disabling access to a storage shard on a host")
end
def circuitbreaker_failure_wait_time_help_text
_("When access to a storage fails. GitLab will prevent access to the "\
"storage for the time specified here. This allows the filesystem to "\
"recover. Repositories on failing shards are temporarly unavailable")
end
def circuitbreaker_failure_reset_time_help_text def circuitbreaker_failure_reset_time_help_text
_("The time in seconds GitLab will keep failure information. When no "\ _("The time in seconds GitLab will keep failure information. When no "\
"failures occur during this time, information about the mount is reset.") "failures occur during this time, information about the mount is reset.")
...@@ -146,6 +135,11 @@ module ApplicationSettingsHelper ...@@ -146,6 +135,11 @@ module ApplicationSettingsHelper
"timeout error will be raised.") "timeout error will be raised.")
end end
def circuitbreaker_check_interval_help_text
_("The time in seconds between storage checks. When a previous check did "\
"complete yet, GitLab will skip a check.")
end
def visible_attributes def visible_attributes
[ [
:admin_notification_email, :admin_notification_email,
...@@ -155,10 +149,9 @@ module ApplicationSettingsHelper ...@@ -155,10 +149,9 @@ module ApplicationSettingsHelper
:akismet_enabled, :akismet_enabled,
:auto_devops_enabled, :auto_devops_enabled,
:circuitbreaker_access_retries, :circuitbreaker_access_retries,
:circuitbreaker_backoff_threshold, :circuitbreaker_check_interval,
:circuitbreaker_failure_count_threshold, :circuitbreaker_failure_count_threshold,
:circuitbreaker_failure_reset_time, :circuitbreaker_failure_reset_time,
:circuitbreaker_failure_wait_time,
:circuitbreaker_storage_timeout, :circuitbreaker_storage_timeout,
:clientside_sentry_dsn, :clientside_sentry_dsn,
:clientside_sentry_enabled, :clientside_sentry_enabled,
......
...@@ -8,22 +8,6 @@ module AutoDevopsHelper ...@@ -8,22 +8,6 @@ module AutoDevopsHelper
!project.ci_service !project.ci_service
end end
def show_run_auto_devops_pipeline_checkbox_for_instance_setting?(project)
return false if project.repository.gitlab_ci_yml
if project&.auto_devops&.enabled.present?
!project.auto_devops.enabled && current_application_settings.auto_devops_enabled?
else
current_application_settings.auto_devops_enabled?
end
end
def show_run_auto_devops_pipeline_checkbox_for_explicit_setting?(project)
return false if project.repository.gitlab_ci_yml
!project.auto_devops_enabled?
end
def auto_devops_warning_message(project) def auto_devops_warning_message(project)
missing_domain = !project.auto_devops&.has_domain? missing_domain = !project.auto_devops&.has_domain?
missing_service = !project.deployment_platform&.active? missing_service = !project.deployment_platform&.active?
......
...@@ -8,7 +8,7 @@ module BoardsHelper ...@@ -8,7 +8,7 @@ module BoardsHelper
def board_data def board_data
{ {
boards_endpoint: @boards_endpoint, boards_endpoint: @boards_endpoint,
lists_endpoint: board_lists_url(board), lists_endpoint: board_lists_path(board),
board_id: board.id, board_id: board.id,
disabled: "#{!can?(current_user, :admin_list, current_board_parent)}", disabled: "#{!can?(current_user, :admin_list, current_board_parent)}",
issue_link_base: build_issue_link_base, issue_link_base: build_issue_link_base,
......
...@@ -8,7 +8,7 @@ module GraphHelper ...@@ -8,7 +8,7 @@ module GraphHelper
# append note count # append note count
notes_count = @graph.notes[commit.id] notes_count = @graph.notes[commit.id]
refs << "[#{notes_count} #{pluralize(notes_count, 'note')}]" if notes_count > 0 refs << "[#{pluralize(notes_count, 'note')}]" if notes_count > 0
refs refs
end end
......
...@@ -18,16 +18,12 @@ module StorageHealthHelper ...@@ -18,16 +18,12 @@ module StorageHealthHelper
current_failures = circuit_breaker.failure_count current_failures = circuit_breaker.failure_count
translation_params = { number_of_failures: current_failures, translation_params = { number_of_failures: current_failures,
maximum_failures: maximum_failures, maximum_failures: maximum_failures }
number_of_seconds: circuit_breaker.failure_wait_time }
if circuit_breaker.circuit_broken? if circuit_breaker.circuit_broken?
s_("%{number_of_failures} of %{maximum_failures} failures. GitLab will not "\ s_("%{number_of_failures} of %{maximum_failures} failures. GitLab will not "\
"retry automatically. Reset storage information when the problem is "\ "retry automatically. Reset storage information when the problem is "\
"resolved.") % translation_params "resolved.") % translation_params
elsif circuit_breaker.backing_off?
_("%{number_of_failures} of %{maximum_failures} failures. GitLab will "\
"block access for %{number_of_seconds} seconds.") % translation_params
else else
_("%{number_of_failures} of %{maximum_failures} failures. GitLab will "\ _("%{number_of_failures} of %{maximum_failures} failures. GitLab will "\
"allow access on the next attempt.") % translation_params "allow access on the next attempt.") % translation_params
......
...@@ -166,11 +166,10 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -166,11 +166,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true, presence: true,
numericality: { greater_than_or_equal_to: 0 } numericality: { greater_than_or_equal_to: 0 }
validates :circuitbreaker_backoff_threshold, validates :circuitbreaker_failure_count_threshold,
:circuitbreaker_failure_count_threshold,
:circuitbreaker_failure_wait_time,
:circuitbreaker_failure_reset_time, :circuitbreaker_failure_reset_time,
:circuitbreaker_storage_timeout, :circuitbreaker_storage_timeout,
:circuitbreaker_check_interval,
presence: true, presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 } numericality: { only_integer: true, greater_than_or_equal_to: 0 }
...@@ -178,13 +177,6 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -178,13 +177,6 @@ class ApplicationSetting < ActiveRecord::Base
presence: true, presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 1 } numericality: { only_integer: true, greater_than_or_equal_to: 1 }
validates_each :circuitbreaker_backoff_threshold do |record, attr, value|
if value.to_i >= record.circuitbreaker_failure_count_threshold
record.errors.add(attr, _("The circuitbreaker backoff threshold should be "\
"lower than the failure count threshold"))
end
end
validates :gitaly_timeout_default, validates :gitaly_timeout_default,
presence: true, presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 } numericality: { only_integer: true, greater_than_or_equal_to: 0 }
......
...@@ -7,6 +7,8 @@ module Ci ...@@ -7,6 +7,8 @@ module Ci
include Importable include Importable
prepend EE::Ci::Build prepend EE::Ci::Build
MissingDependenciesError = Class.new(StandardError)
belongs_to :runner belongs_to :runner
belongs_to :trigger_request belongs_to :trigger_request
belongs_to :erased_by, class_name: 'User' belongs_to :erased_by, class_name: 'User'
...@@ -143,6 +145,10 @@ module Ci ...@@ -143,6 +145,10 @@ module Ci
Ci::Build.retry(build, build.user) Ci::Build.retry(build, build.user)
end end
end end
before_transition any => [:running] do |build|
build.validates_dependencies! unless Feature.enabled?('ci_disable_validates_dependencies')
end
end end
def detailed_status(current_user) def detailed_status(current_user)
...@@ -488,6 +494,20 @@ module Ci ...@@ -488,6 +494,20 @@ module Ci
options[:dependencies]&.empty? options[:dependencies]&.empty?
end end
def validates_dependencies!
dependencies.each do |dependency|
raise MissingDependenciesError unless dependency.valid_dependency?
end
end
def valid_dependency?
return false unless complete?
return false if artifacts_expired?
return false if erased?
true
end
def hide_secrets(trace) def hide_secrets(trace)
return unless trace return unless trace
......
...@@ -43,7 +43,8 @@ class CommitStatus < ActiveRecord::Base ...@@ -43,7 +43,8 @@ class CommitStatus < ActiveRecord::Base
script_failure: 1, script_failure: 1,
api_failure: 2, api_failure: 2,
stuck_or_timeout_failure: 3, stuck_or_timeout_failure: 3,
runner_system_failure: 4 runner_system_failure: 4,
missing_dependency_failure: 5
} }
## ##
......
# ThrottledTouch can be used to throttle the number of updates triggered by
# calling "touch" on an ActiveRecord model.
module ThrottledTouch
# The amount of time to wait before "touch" can update a record again.
TOUCH_INTERVAL = 1.minute
def touch(*args)
super if (Time.zone.now - updated_at) > TOUCH_INTERVAL
end
end
# Placeholder class for model that is implemented in EE # Placeholder class for model that is implemented in EE
# It reserves '&' as a reference prefix, but the table does not exists in CE # It reserves '&' as a reference prefix, but the table does not exists in CE
class Epic < ActiveRecord::Base class Epic < ActiveRecord::Base
<<<<<<< HEAD
prepend EE::Epic prepend EE::Epic
=======
>>>>>>> upstream/master
def self.reference_prefix def self.reference_prefix
'&' '&'
end end
......
...@@ -72,7 +72,7 @@ class Event < ActiveRecord::Base ...@@ -72,7 +72,7 @@ class Event < ActiveRecord::Base
# We're using preload for "push_event_payload" as otherwise the association # We're using preload for "push_event_payload" as otherwise the association
# is not always available (depending on the query being built). # is not always available (depending on the query being built).
includes(:author, :project, project: :namespace) includes(:author, :project, project: :namespace)
.preload(:target, :push_event_payload) .preload(:push_event_payload, target: :author)
end end
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) } scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
......
...@@ -13,6 +13,10 @@ class Issue < ActiveRecord::Base ...@@ -13,6 +13,10 @@ class Issue < ActiveRecord::Base
include FasterCacheKeys include FasterCacheKeys
include RelativePositioning include RelativePositioning
include TimeTrackable include TimeTrackable
include ThrottledTouch
include IgnorableColumn
ignore_column :assignee_id
WEIGHT_RANGE = 1..9 WEIGHT_RANGE = 1..9
WEIGHT_ALL = 'Everything'.freeze WEIGHT_ALL = 'Everything'.freeze
......
...@@ -8,6 +8,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -8,6 +8,7 @@ class MergeRequest < ActiveRecord::Base
include TimeTrackable include TimeTrackable
include ManualInverseAssociation include ManualInverseAssociation
include EachBatch include EachBatch
include ThrottledTouch
ignore_column :locked_at, ignore_column :locked_at,
:ref_fetched :ref_fetched
......
...@@ -18,6 +18,7 @@ class Note < ActiveRecord::Base ...@@ -18,6 +18,7 @@ class Note < ActiveRecord::Base
include IgnorableColumn include IgnorableColumn
include Editable include Editable
include Gitlab::SQL::Pattern include Gitlab::SQL::Pattern
include ThrottledTouch
module SpecialRole module SpecialRole
FIRST_TIME_CONTRIBUTOR = :first_time_contributor FIRST_TIME_CONTRIBUTOR = :first_time_contributor
...@@ -58,7 +59,7 @@ class Note < ActiveRecord::Base ...@@ -58,7 +59,7 @@ class Note < ActiveRecord::Base
participant :author participant :author
belongs_to :project belongs_to :project
belongs_to :noteable, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :author, class_name: "User" belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User" belongs_to :updated_by, class_name: "User"
belongs_to :last_edited_by, class_name: 'User' belongs_to :last_edited_by, class_name: 'User'
...@@ -122,6 +123,7 @@ class Note < ActiveRecord::Base ...@@ -122,6 +123,7 @@ class Note < ActiveRecord::Base
before_validation :set_discussion_id, on: :create before_validation :set_discussion_id, on: :create
after_save :keep_around_commit, if: :for_project_noteable? after_save :keep_around_commit, if: :for_project_noteable?
after_save :expire_etag_cache after_save :expire_etag_cache
after_save :touch_noteable
after_destroy :expire_etag_cache after_destroy :expire_etag_cache
class << self class << self
......
...@@ -3,6 +3,8 @@ class PersonalAccessToken < ActiveRecord::Base ...@@ -3,6 +3,8 @@ class PersonalAccessToken < ActiveRecord::Base
include TokenAuthenticatable include TokenAuthenticatable
add_authentication_token_field :token add_authentication_token_field :token
REDIS_EXPIRY_TIME = 3.minutes
serialize :scopes, Array # rubocop:disable Cop/ActiveRecordSerialize serialize :scopes, Array # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :user belongs_to :user
...@@ -27,6 +29,21 @@ class PersonalAccessToken < ActiveRecord::Base ...@@ -27,6 +29,21 @@ class PersonalAccessToken < ActiveRecord::Base
!revoked? && !expired? !revoked? && !expired?
end end
def self.redis_getdel(user_id)
Gitlab::Redis::SharedState.with do |redis|
token = redis.get(redis_shared_state_key(user_id))
redis.del(redis_shared_state_key(user_id))
token
end
end
def self.redis_store!(user_id, token)
Gitlab::Redis::SharedState.with do |redis|
redis.set(redis_shared_state_key(user_id), token, ex: REDIS_EXPIRY_TIME)
token
end
end
protected protected
def validate_scopes def validate_scopes
...@@ -38,4 +55,8 @@ class PersonalAccessToken < ActiveRecord::Base ...@@ -38,4 +55,8 @@ class PersonalAccessToken < ActiveRecord::Base
def set_default_scopes def set_default_scopes
self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty? self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty?
end end
def self.redis_shared_state_key(user_id)
"gitlab:personal_access_token:#{user_id}"
end
end end
...@@ -18,9 +18,12 @@ class User < ActiveRecord::Base ...@@ -18,9 +18,12 @@ class User < ActiveRecord::Base
include CreatedAtFilterable include CreatedAtFilterable
include IgnorableColumn include IgnorableColumn
include BulkMemberAccessLoad include BulkMemberAccessLoad
<<<<<<< HEAD
prepend EE::GeoAwareAvatar prepend EE::GeoAwareAvatar
prepend EE::User prepend EE::User
=======
>>>>>>> upstream/master
DEFAULT_NOTIFICATION_LEVEL = :participating DEFAULT_NOTIFICATION_LEVEL = :participating
...@@ -1084,13 +1087,13 @@ class User < ActiveRecord::Base ...@@ -1084,13 +1087,13 @@ class User < ActiveRecord::Base
end end
def todos_done_count(force: false) def todos_done_count(force: false)
Rails.cache.fetch(['users', id, 'todos_done_count'], force: force) do Rails.cache.fetch(['users', id, 'todos_done_count'], force: force, expires_in: 20.minutes) do
TodosFinder.new(self, state: :done).execute.count TodosFinder.new(self, state: :done).execute.count
end end
end end
def todos_pending_count(force: false) def todos_pending_count(force: false)
Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force) do Rails.cache.fetch(['users', id, 'todos_pending_count'], force: force, expires_in: 20.minutes) do
TodosFinder.new(self, state: :pending).execute.count TodosFinder.new(self, state: :pending).execute.count
end end
end end
......
...@@ -39,7 +39,10 @@ class GroupPolicy < BasePolicy ...@@ -39,7 +39,10 @@ class GroupPolicy < BasePolicy
rule { guest }.policy do rule { guest }.policy do
enable :read_group enable :read_group
<<<<<<< HEAD
enable :read_list enable :read_list
=======
>>>>>>> upstream/master
enable :upload_file enable :upload_file
end end
......
...@@ -26,11 +26,15 @@ module Ci ...@@ -26,11 +26,15 @@ module Ci
save_incompleted: save_on_errors, save_incompleted: save_on_errors,
seeds_block: block, seeds_block: block,
project: project, project: project,
<<<<<<< HEAD
current_user: current_user, current_user: current_user,
# EE specific # EE specific
allow_mirror_update: mirror_update allow_mirror_update: mirror_update
) )
=======
current_user: current_user)
>>>>>>> upstream/master
sequence = Gitlab::Ci::Pipeline::Chain::Sequence sequence = Gitlab::Ci::Pipeline::Chain::Sequence
.new(pipeline, command, SEQUENCE) .new(pipeline, command, SEQUENCE)
......
...@@ -55,6 +55,9 @@ module Ci ...@@ -55,6 +55,9 @@ module Ci
# we still have to return 409 in the end, # we still have to return 409 in the end,
# to make sure that this is properly handled by runner. # to make sure that this is properly handled by runner.
valid = false valid = false
rescue Ci::Build::MissingDependenciesError
build.drop!(:missing_dependency_failure)
valid = false
end end
end end
......
...@@ -20,7 +20,7 @@ class MetricsService ...@@ -20,7 +20,7 @@ class MetricsService
end end
def metrics_text def metrics_text
"#{health_metrics_text}#{prometheus_metrics_text}" prometheus_metrics_text.concat(health_metrics_text)
end end
private private
......
...@@ -20,8 +20,23 @@ module Projects ...@@ -20,8 +20,23 @@ module Projects
MergeRequestsFinder.new(current_user, project_id: project.id, state: 'opened').execute.select([:iid, :title]) MergeRequestsFinder.new(current_user, project_id: project.id, state: 'opened').execute.select([:iid, :title])
end end
def labels def labels(target = nil)
LabelsFinder.new(current_user, project_id: project.id).execute.select([:title, :color]) labels = LabelsFinder.new(current_user, project_id: project.id).execute.select([:color, :title])
return labels unless target&.respond_to?(:labels)
issuable_label_titles = target.labels.pluck(:title)
if issuable_label_titles
labels = labels.as_json(only: [:title, :color])
issuable_label_titles.each do |issuable_label_title|
found_label = labels.find { |label| label['title'] == issuable_label_title }
found_label[:set] = true if found_label
end
end
labels
end end
def commands(noteable, type) def commands(noteable, type)
...@@ -33,7 +48,7 @@ module Projects ...@@ -33,7 +48,7 @@ module Projects
@project.merge_requests.build @project.merge_requests.build
end end
return [] unless noteable && noteable.is_a?(Issuable) return [] unless noteable&.is_a?(Issuable)
opts = { opts = {
project: project, project: project,
......
...@@ -25,7 +25,7 @@ module Projects ...@@ -25,7 +25,7 @@ module Projects
return error("Could not set the default branch") unless project.change_head(params[:default_branch]) return error("Could not set the default branch") unless project.change_head(params[:default_branch])
end end
if project.update_attributes(update_params) if project.update_attributes(params.except(:default_branch))
if project.previous_changes.include?('path') if project.previous_changes.include?('path')
project.rename_repo project.rename_repo
else else
...@@ -42,15 +42,13 @@ module Projects ...@@ -42,15 +42,13 @@ module Projects
end end
def run_auto_devops_pipeline? def run_auto_devops_pipeline?
params.dig(:run_auto_devops_pipeline_explicit) == 'true' || params.dig(:run_auto_devops_pipeline_implicit) == 'true' return false if project.repository.gitlab_ci_yml || !project.auto_devops.previous_changes.include?('enabled')
project.auto_devops.enabled? || (project.auto_devops.enabled.nil? && current_application_settings.auto_devops_enabled?)
end end
private private
def update_params
params.except(:default_branch, :run_auto_devops_pipeline_explicit, :run_auto_devops_pipeline_implicit)
end
def renaming_project_with_container_registry_tags? def renaming_project_with_container_registry_tags?
new_path = params[:path] new_path = params[:path]
......
module ProtectedBranches module ProtectedBranches
class AccessLevelParams class AccessLevelParams
<<<<<<< HEAD
prepend EE::ProtectedBranches::AccessLevelParams prepend EE::ProtectedBranches::AccessLevelParams
=======
>>>>>>> upstream/master
attr_reader :type, :params attr_reader :type, :params
def initialize(type, params) def initialize(type, params)
......
module ProtectedBranches module ProtectedBranches
class ApiService < BaseService class ApiService < BaseService
<<<<<<< HEAD
prepend EE::ProtectedBranches::ApiService prepend EE::ProtectedBranches::ApiService
=======
>>>>>>> upstream/master
def create def create
@push_params = AccessLevelParams.new(:push, params) @push_params = AccessLevelParams.new(:push, params)
@merge_params = AccessLevelParams.new(:merge, params) @merge_params = AccessLevelParams.new(:merge, params)
......
...@@ -582,6 +582,12 @@ ...@@ -582,6 +582,12 @@
%fieldset %fieldset
%legend Git Storage Circuitbreaker settings %legend Git Storage Circuitbreaker settings
.form-group
= f.label :circuitbreaker_check_interval, _('Check interval'), class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :circuitbreaker_check_interval, class: 'form-control'
.help-block
= circuitbreaker_check_interval_help_text
.form-group .form-group
= f.label :circuitbreaker_access_retries, _('Number of access attempts'), class: 'control-label col-sm-2' = f.label :circuitbreaker_access_retries, _('Number of access attempts'), class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
...@@ -594,18 +600,6 @@ ...@@ -594,18 +600,6 @@
= f.number_field :circuitbreaker_storage_timeout, class: 'form-control' = f.number_field :circuitbreaker_storage_timeout, class: 'form-control'
.help-block .help-block
= circuitbreaker_storage_timeout_help_text = circuitbreaker_storage_timeout_help_text
.form-group
= f.label :circuitbreaker_backoff_threshold, _('Number of failures before backing off'), class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :circuitbreaker_backoff_threshold, class: 'form-control'
.help-block
= circuitbreaker_backoff_threshold_help_text
.form-group
= f.label :circuitbreaker_failure_wait_time, _('Seconds to wait after a storage failure'), class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :circuitbreaker_failure_wait_time, class: 'form-control'
.help-block
= circuitbreaker_failure_wait_time_help_text
.form-group .form-group
= f.label :circuitbreaker_failure_count_threshold, _('Maximum git storage failures'), class: 'control-label col-sm-2' = f.label :circuitbreaker_failure_count_threshold, _('Maximum git storage failures'), class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
Projects are where you store your code, access issues, wiki and other features of GitLab. Projects are where you store your code, access issues, wiki and other features of GitLab.
- if current_user.can_create_group? - if current_user.can_create_group?
= link_to admin_root_path, class: "blank-state-link" do = link_to new_group_path, class: "blank-state-link" do
.blank-state .blank-state
.blank-state-icon .blank-state-icon
= custom_icon("add_new_group", size: 50) = custom_icon("add_new_group", size: 50)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
members: "#{members_project_autocomplete_sources_path(project, type: noteable_type, type_id: params[:id])}", members: "#{members_project_autocomplete_sources_path(project, type: noteable_type, type_id: params[:id])}",
issues: "#{issues_project_autocomplete_sources_path(project)}", issues: "#{issues_project_autocomplete_sources_path(project)}",
mergeRequests: "#{merge_requests_project_autocomplete_sources_path(project)}", mergeRequests: "#{merge_requests_project_autocomplete_sources_path(project)}",
labels: "#{labels_project_autocomplete_sources_path(project)}", labels: "#{labels_project_autocomplete_sources_path(project, type: noteable_type, type_id: params[:id])}",
milestones: "#{milestones_project_autocomplete_sources_path(project)}", milestones: "#{milestones_project_autocomplete_sources_path(project)}",
commands: "#{commands_project_autocomplete_sources_path(project, type: noteable_type, type_id: params[:id])}" commands: "#{commands_project_autocomplete_sources_path(project, type: noteable_type, type_id: params[:id])}"
}; };
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
- if defined?(nav) && nav - if defined?(nav) && nav
= render "layouts/nav/sidebar/#{nav}" = render "layouts/nav/sidebar/#{nav}"
.content-wrapper.page-with-new-nav .content-wrapper.page-with-new-nav
= render 'shared/outdated_browser'
.mobile-overlay .mobile-overlay
.alert-wrapper .alert-wrapper
= render "layouts/header/ee_license_banner" = render "layouts/header/ee_license_banner"
......
...@@ -18,10 +18,17 @@ ...@@ -18,10 +18,17 @@
spellcheck: false, spellcheck: false,
tabindex: '1', tabindex: '1',
autocomplete: 'off', autocomplete: 'off',
<<<<<<< HEAD
data: { toggle: 'dropdown', data: { toggle: 'dropdown',
issues_path: issues_dashboard_path, issues_path: issues_dashboard_path,
mr_path: merge_requests_dashboard_path }, mr_path: merge_requests_dashboard_path },
aria: { label: 'Search' } aria: { label: 'Search' }
=======
data: { issues_path: issues_dashboard_path,
mr_path: merge_requests_dashboard_path },
aria: { label: 'Search' }
%button.hidden.js-dropdown-search-toggle{ type: 'button', data: { toggle: 'dropdown' } }
>>>>>>> upstream/master
.dropdown-menu.dropdown-select .dropdown-menu.dropdown-select
= dropdown_content do = dropdown_content do
%ul %ul
......
...@@ -75,5 +75,3 @@ ...@@ -75,5 +75,3 @@
%span.sr-only Toggle navigation %span.sr-only Toggle navigation
= sprite_icon('more', size: 12, css_class: 'more-icon js-navbar-toggle-right') = sprite_icon('more', size: 12, css_class: 'more-icon js-navbar-toggle-right')
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left') = sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
= render 'shared/outdated_browser'
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute - issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
<<<<<<< HEAD
- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index'] - issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index']
- if @group.feature_available?(:group_issue_boards) - if @group.feature_available?(:group_issue_boards)
- issues_sub_menu_items.push('boards#index', 'boards#show') - issues_sub_menu_items.push('boards#index', 'boards#show')
=======
>>>>>>> upstream/master
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) } .nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll .nav-sidebar-inner-scroll
.context-header .context-header
......
...@@ -15,14 +15,13 @@ ...@@ -15,14 +15,13 @@
They are the only accepted password when you have Two-Factor Authentication (2FA) enabled. They are the only accepted password when you have Two-Factor Authentication (2FA) enabled.
.col-lg-8 .col-lg-8
- if @new_personal_access_token
- if flash[:personal_access_token]
.created-personal-access-token-container .created-personal-access-token-container
%h5.prepend-top-0 %h5.prepend-top-0
Your New Personal Access Token Your New Personal Access Token
.form-group .form-group
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block" = text_field_tag 'created-personal-access-token', @new_personal_access_token, readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block"
= clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left") = clipboard_button(text: @new_personal_access_token, title: "Copy personal access token to clipboard", placement: "left")
%span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again. %span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again.
%hr %hr
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- if defined?(@merge_request) && @merge_request.discussion_locked? - if defined?(@merge_request) && @merge_request.discussion_locked?
.issuable-note-warning .issuable-note-warning
= icon('lock', class: 'icon') = sprite_icon('lock', size: 16, css_class: 'icon')
%span %span
= _('This merge request is locked.') = _('This merge request is locked.')
= _('Only project members can comment.') = _('Only project members can comment.')
......
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
- if @cluster.managed? - if @cluster.managed?
.append-bottom-20 .append-bottom-20
%label.append-bottom-10 %label.append-bottom-10
= s_('ClusterIntegration|Google Container Engine') = s_('ClusterIntegration|Google Kubernetes Engine')
%p %p
- link_gke = link_to(s_('ClusterIntegration|Google Container Engine'), @cluster.gke_cluster_url, target: '_blank', rel: 'noopener noreferrer') - link_gke = link_to(s_('ClusterIntegration|Google Kubernetes Engine'), @cluster.gke_cluster_url, target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Manage your cluster by visiting %{link_gke}').html_safe % { link_gke: link_gke } = s_('ClusterIntegration|Manage your cluster by visiting %{link_gke}').html_safe % { link_gke: link_gke }
.well.form-group .well.form-group
%label.text-danger %label.text-danger
= s_('ClusterIntegration|Remove cluster integration') = s_('ClusterIntegration|Remove cluster integration')
%p %p
= s_('ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Container Engine.') = s_('ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine.')
= link_to(s_('ClusterIntegration|Remove integration'), namespace_project_cluster_path(@project.namespace, @project, @cluster.id), method: :delete, class: 'btn btn-danger', data: { confirm: "Are you sure you want to remove cluster integration from this project? This will not delete your cluster on Google Container Engine"}) = link_to(s_('ClusterIntegration|Remove integration'), namespace_project_cluster_path(@project.namespace, @project, @cluster.id), method: :delete, class: 'btn btn-danger', data: { confirm: "Are you sure you want to remove cluster integration from this project? This will not delete your cluster on Google Kubernetes Engine"})
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
.settings-content .settings-content
.hidden.js-cluster-error.alert.alert-danger.alert-block.append-bottom-10{ role: 'alert' } .hidden.js-cluster-error.alert.alert-danger.alert-block.append-bottom-10{ role: 'alert' }
= s_('ClusterIntegration|Something went wrong while creating your cluster on Google Container Engine') = s_('ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine')
%p.js-error-reason %p.js-error-reason
.hidden.js-cluster-creating.alert.alert-info.alert-block.append-bottom-10{ role: 'alert' } .hidden.js-cluster-creating.alert.alert-info.alert-block.append-bottom-10{ role: 'alert' }
= s_('ClusterIntegration|Cluster is being created on Google Container Engine...') = s_('ClusterIntegration|Cluster is being created on Google Kubernetes Engine...')
.hidden.js-cluster-success.alert.alert-success.alert-block.append-bottom-10{ role: 'alert' } .hidden.js-cluster-success.alert.alert-success.alert-block.append-bottom-10{ role: 'alert' }
= s_('ClusterIntegration|Cluster was successfully created on Google Container Engine. Refresh the page to see cluster\'s details') = s_('ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster\'s details')
%p %p
- if @cluster.enabled? - if @cluster.enabled?
......
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
= icon('chevron-down') = icon('chevron-down')
%ul.dropdown-menu.clusters-dropdown-menu.dropdown-menu-full-width %ul.dropdown-menu.clusters-dropdown-menu.dropdown-menu-full-width
%li %li
= link_to(s_('ClusterIntegration|Create cluster on Google Container Engine'), gcp_new_namespace_project_clusters_path(@project.namespace, @project)) = link_to(s_('ClusterIntegration|Create cluster on Google Kubernetes Engine'), gcp_new_namespace_project_clusters_path(@project.namespace, @project))
%li %li
= link_to(s_('ClusterIntegration|Add an existing cluster'), user_new_namespace_project_clusters_path(@project.namespace, @project)) = link_to(s_('ClusterIntegration|Add an existing cluster'), user_new_namespace_project_clusters_path(@project.namespace, @project))
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
= s_('ClusterIntegration|Please make sure that your Google account meets the following requirements:') = s_('ClusterIntegration|Please make sure that your Google account meets the following requirements:')
%ul %ul
%li %li
- link_to_container_engine = link_to(s_('ClusterIntegration|access to Google Container Engine'), 'https://console.cloud.google.com', target: '_blank', rel: 'noopener noreferrer') - link_to_kubernetes_engine = link_to(s_('ClusterIntegration|access to Google Kubernetes Engine'), 'https://console.cloud.google.com', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Your account must have %{link_to_container_engine}').html_safe % { link_to_container_engine: link_to_container_engine } = s_('ClusterIntegration|Your account must have %{link_to_kubernetes_engine}').html_safe % { link_to_kubernetes_engine: link_to_kubernetes_engine }
%li %li
- link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/container-engine/docs/quickstart', target: '_blank', rel: 'noopener noreferrer') - link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/kubernetes-engine/docs/quickstart', target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements } = s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements }
%li %li
- link_to_container_project = link_to(s_('ClusterIntegration|Google Container Engine project'), target: '_blank', rel: 'noopener noreferrer') - link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project } = s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.col-sm-4 .col-sm-4
= render 'projects/clusters/sidebar' = render 'projects/clusters/sidebar'
.col-sm-8 .col-sm-8
= render 'projects/clusters/dropdown', dropdown_text: s_('ClusterIntegration|Create cluster on Google Container Engine') = render 'projects/clusters/dropdown', dropdown_text: s_('ClusterIntegration|Create cluster on Google Kubernetes Engine')
= render 'header' = render 'header'
.row .row
.col-sm-8.col-sm-offset-4.signin-with-google .col-sm-8.col-sm-offset-4.signin-with-google
......
...@@ -5,6 +5,6 @@ ...@@ -5,6 +5,6 @@
.col-sm-4 .col-sm-4
= render 'projects/clusters/sidebar' = render 'projects/clusters/sidebar'
.col-sm-8 .col-sm-8
= render 'projects/clusters/dropdown', dropdown_text: s_('ClusterIntegration|Create cluster on Google Container Engine') = render 'projects/clusters/dropdown', dropdown_text: s_('ClusterIntegration|Create cluster on Google Kubernetes Engine')
= render 'header' = render 'header'
= render 'form' = render 'form'
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
.col-sm-8 .col-sm-8
%h4.prepend-top-0= s_('ClusterIntegration|Choose how to set up cluster integration') %h4.prepend-top-0= s_('ClusterIntegration|Choose how to set up cluster integration')
%p= s_('ClusterIntegration|Create a new cluster on Google Engine right from GitLab') %p= s_('ClusterIntegration|Create a new cluster on Google Kubernetes Engine right from GitLab')
= link_to s_('ClusterIntegration|Create on GKE'), gcp_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' = link_to s_('ClusterIntegration|Create on GKE'), gcp_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20'
%p= s_('ClusterIntegration|Enter the details for an existing Kubernetes cluster') %p= s_('ClusterIntegration|Enter the details for an existing Kubernetes cluster')
= link_to s_('ClusterIntegration|Add an existing cluster'), user_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' = link_to s_('ClusterIntegration|Add an existing cluster'), user_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20'
...@@ -13,10 +13,13 @@ ...@@ -13,10 +13,13 @@
view_details, view_details,
commit.status(ref), commit.status(ref),
I18n.locale].compact I18n.locale].compact
<<<<<<< HEAD
-# EE-only -# EE-only
- show_project_name = local_assigns.fetch(:show_project_name, false) - show_project_name = local_assigns.fetch(:show_project_name, false)
- cache_key << show_project_name - cache_key << show_project_name
=======
>>>>>>> upstream/master
= cache(cache_key, expires_in: 1.day) do = cache(cache_key, expires_in: 1.day) do
%li.commit.flex-row.js-toggle-container{ id: "commit-#{commit.short_id}" } %li.commit.flex-row.js-toggle-container{ id: "commit-#{commit.short_id}" }
......
...@@ -19,4 +19,6 @@ ...@@ -19,4 +19,6 @@
"empty-loading-svg-path": image_path('illustrations/monitoring/loading'), "empty-loading-svg-path": image_path('illustrations/monitoring/loading'),
"empty-unable-to-connect-svg-path": image_path('illustrations/monitoring/unable_to_connect'), "empty-unable-to-connect-svg-path": image_path('illustrations/monitoring/unable_to_connect'),
"additional-metrics": additional_metrics_project_environment_path(@project, @environment, format: :json), "additional-metrics": additional_metrics_project_environment_path(@project, @environment, format: :json),
"project-path": project_path(@project),
"tags-path": project_tags_path(@project),
"has-metrics": "#{@environment.has_metrics?}", deployment_endpoint: project_environment_deployments_path(@project, @environment, format: :json) } } "has-metrics": "#{@environment.has_metrics?}", deployment_endpoint: project_environment_deployments_path(@project, @environment, format: :json) } }
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
= edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago') = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago')
<<<<<<< HEAD
- if can?(current_user, :read_issue_link, @project) - if can?(current_user, :read_issue_link, @project)
.js-related-issues-root{ data: { endpoint: project_issue_links_path(@project, @issue), .js-related-issues-root{ data: { endpoint: project_issue_links_path(@project, @issue),
can_add_related_issues: "#{can?(current_user, :admin_issue_link, @issue)}", can_add_related_issues: "#{can?(current_user, :admin_issue_link, @issue)}",
...@@ -88,6 +89,8 @@ ...@@ -88,6 +89,8 @@
Related issues Related issues
=======
>>>>>>> upstream/master
#merge-requests{ data: { url: referenced_merge_requests_project_issue_path(@project, @issue) } } #merge-requests{ data: { url: referenced_merge_requests_project_issue_path(@project, @issue) } }
// This element is filled in using JavaScript. // This element is filled in using JavaScript.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), #{link_to 'among other things', help_page_path("user/project/index.md", anchor: "projects-features"), target: '_blank'}. A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), #{link_to 'among other things', help_page_path("user/project/index.md", anchor: "projects-features"), target: '_blank'}.
%p %p
All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings. All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings.
.md
= brand_new_project_guidelines = brand_new_project_guidelines
.col-lg-9.js-toggle-container .col-lg-9.js-toggle-container
%ul.nav-links.gitlab-tabs{ role: 'tablist' } %ul.nav-links.gitlab-tabs{ role: 'tablist' }
......
...@@ -6,46 +6,35 @@ ...@@ -6,46 +6,35 @@
%h5 Auto DevOps (Beta) %h5 Auto DevOps (Beta)
%p %p
Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration. Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.
This will happen starting with the next event (e.g.: push) that occurs to the project.
= link_to 'Learn more about Auto DevOps', help_page_path('topics/autodevops/index.md') = link_to 'Learn more about Auto DevOps', help_page_path('topics/autodevops/index.md')
- message = auto_devops_warning_message(@project) - message = auto_devops_warning_message(@project)
- if message - if message
%p.settings-message.text-center %p.settings-message.text-center
= message.html_safe = message.html_safe
= f.fields_for :auto_devops_attributes, @auto_devops do |form| = f.fields_for :auto_devops_attributes, @auto_devops do |form|
.radio.js-auto-devops-enable-radio-wrapper .radio
= form.label :enabled_true do = form.label :enabled_true do
= form.radio_button :enabled, 'true', class: 'js-auto-devops-enable-radio' = form.radio_button :enabled, 'true'
%strong Enable Auto DevOps %strong Enable Auto DevOps
%br %br
%span.descr %span.descr
The Auto DevOps pipeline configuration will be used when there is no <code>.gitlab-ci.yml</code> in the project. The Auto DevOps pipeline configuration will be used when there is no <code>.gitlab-ci.yml</code> in the project.
- if show_run_auto_devops_pipeline_checkbox_for_explicit_setting?(@project)
.checkbox.hide.js-run-auto-devops-pipeline-checkbox-wrapper
= label_tag 'project[run_auto_devops_pipeline_explicit]' do
= check_box_tag 'project[run_auto_devops_pipeline_explicit]', true, false, class: 'js-run-auto-devops-pipeline-checkbox'
= s_('ProjectSettings|Immediately run a pipeline on the default branch')
.radio.js-auto-devops-enable-radio-wrapper .radio
= form.label :enabled_false do = form.label :enabled_false do
= form.radio_button :enabled, 'false', class: 'js-auto-devops-enable-radio' = form.radio_button :enabled, 'false'
%strong Disable Auto DevOps %strong Disable Auto DevOps
%br %br
%span.descr %span.descr
An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continuous Integration and Delivery. An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continuous Integration and Delivery.
.radio.js-auto-devops-enable-radio-wrapper .radio
= form.label :enabled_ do = form.label :enabled_ do
= form.radio_button :enabled, '', class: 'js-auto-devops-enable-radio' = form.radio_button :enabled, ''
%strong Instance default (#{current_application_settings.auto_devops_enabled? ? 'enabled' : 'disabled'}) %strong Instance default (#{current_application_settings.auto_devops_enabled? ? 'enabled' : 'disabled'})
%br %br
%span.descr %span.descr
Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific <code>.gitlab-ci.yml</code>. Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific <code>.gitlab-ci.yml</code>.
- if show_run_auto_devops_pipeline_checkbox_for_instance_setting?(@project)
.checkbox.hide.js-run-auto-devops-pipeline-checkbox-wrapper
= label_tag 'project[run_auto_devops_pipeline_implicit]' do
= check_box_tag 'project[run_auto_devops_pipeline_implicit]', true, false, class: 'js-run-auto-devops-pipeline-checkbox'
= s_('ProjectSettings|Immediately run a pipeline on the default branch')
%p %p
You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages. You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com' = form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
......
- if on_top_of_branch?
- addtotree_toggle_attributes = { href: '#', 'data-toggle': 'dropdown', 'data-target': '.add-to-tree-dropdown' }
- else
- addtotree_toggle_attributes = { title: _("You can only add files when you are on a branch"), data: { container: 'body' }, class: 'disabled has-tooltip' }
%ul.breadcrumb.repo-breadcrumb %ul.breadcrumb.repo-breadcrumb
%li %li
= link_to project_tree_path(@project, @ref) do = link_to project_tree_path(@project, @ref) do
...@@ -8,13 +13,10 @@ ...@@ -8,13 +13,10 @@
- if current_user - if current_user
%li %li
- if !on_top_of_branch? %a.btn.add-to-tree{ addtotree_toggle_attributes }
%span.btn.add-to-tree.disabled.has-tooltip{ title: _("You can only add files when you are on a branch"), data: { container: 'body' } } = sprite_icon('plus', size: 16, css_class: 'pull-left')
= icon('plus') = sprite_icon('arrow-down', size: 16, css_class: 'pull-left')
- else - if on_top_of_branch?
%span.dropdown
%a.dropdown-toggle.btn.add-to-tree{ href: '#', "data-toggle" => "dropdown", "data-target" => ".add-to-tree-dropdown" }
= icon('plus')
.add-to-tree-dropdown .add-to-tree-dropdown
%ul.dropdown-menu %ul.dropdown-menu
- if can_edit_tree? - if can_edit_tree?
......
- if outdated_browser? - if outdated_browser?
<<<<<<< HEAD
.browser-alert .browser-alert
GitLab may not work properly because you are using an outdated web browser. GitLab may not work properly because you are using an outdated web browser.
%br %br
Please install a Please install a
= link_to 'supported web browser', help_page_path('install/requirements', anchor: 'supported-web-browsers') = link_to 'supported web browser', help_page_path('install/requirements', anchor: 'supported-web-browsers')
for a better experience. for a better experience.
=======
.flash-container
.flash-alert.text-center
GitLab may not work properly because you are using an outdated web browser.
%br
Please install a
= link_to 'supported web browser', help_page_path('install/requirements', anchor: 'supported-web-browsers')
for a better experience.
>>>>>>> upstream/master
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
- elsif discussion_locked - elsif discussion_locked
.disabled-comment.text-center.prepend-top-default .disabled-comment.text-center.prepend-top-default
%span.issuable-note-warning %span.issuable-note-warning
%span.icon= sprite_icon('lock', size: 14) = sprite_icon('lock', size: 16, css_class: 'icon')
%span %span
This This
= issuable.class.to_s.titleize.downcase = issuable.class.to_s.titleize.downcase
......
#!/usr/bin/env ruby
require 'optparse'
require 'net/http'
require 'json'
require 'socket'
require 'logger'
require_relative '../lib/gitlab/storage_check'
Gitlab::StorageCheck::CLI.start!(ARGV)
---
title: 'fix #39233 - 500 in merge request'
merge_request: 15774
author: Martin Nowak
type: fixed
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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