summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authortiagonbotelho <tiagonbotelho@hotmail.com>2016-07-22 21:57:46 +0100
committertiagonbotelho <tiagonbotelho@hotmail.com>2016-07-22 21:57:46 +0100
commit850813d29867aac5935e1128880784f97071a6d8 (patch)
treed5da375e2dcdaf54d653bc50aa75d2e4dd7f096e /app
parent2d64bda01f983c43f915e96bd5bf8fcb0790eb0e (diff)
parent08b5bec2fa3beb2880d451a9d9270813b0a22519 (diff)
downloadgitlab-ce-850813d29867aac5935e1128880784f97071a6d8.tar.gz
Merge branch 'master' into filter-branch-by-name
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/admin.js.coffee11
-rw-r--r--app/assets/javascripts/files_comment_button.js.coffee15
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee15
-rw-r--r--app/assets/javascripts/graphs/graphs_bundle.js.coffee (renamed from app/assets/javascripts/graphs/application.js.coffee)0
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee15
-rw-r--r--app/assets/javascripts/network/network_bundle.js.coffee (renamed from app/assets/javascripts/network/application.js.coffee)0
-rw-r--r--app/assets/javascripts/notes.js.coffee6
-rw-r--r--app/assets/javascripts/profile/profile_bundle.js.coffee (renamed from app/assets/javascripts/profile/application.js.coffee)0
-rw-r--r--app/assets/javascripts/right_sidebar.js.coffee3
-rw-r--r--app/assets/javascripts/users/users_bundle.js.coffee (renamed from app/assets/javascripts/users/application.js.coffee)0
-rw-r--r--app/assets/stylesheets/framework/blocks.scss4
-rw-r--r--app/assets/stylesheets/framework/buttons.scss18
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss27
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss4
-rw-r--r--app/assets/stylesheets/pages/builds.scss8
-rw-r--r--app/assets/stylesheets/pages/commit.scss6
-rw-r--r--app/assets/stylesheets/pages/events.scss8
-rw-r--r--app/assets/stylesheets/pages/issuable.scss5
-rw-r--r--app/assets/stylesheets/pages/issues.scss8
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss23
-rw-r--r--app/assets/stylesheets/pages/notes.scss23
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss37
-rw-r--r--app/assets/stylesheets/pages/projects.scss73
-rw-r--r--app/assets/stylesheets/pages/status.scss25
-rw-r--r--app/assets/stylesheets/pages/tags.scss7
-rw-r--r--app/controllers/admin/application_settings_controller.rb6
-rw-r--r--app/controllers/admin/groups_controller.rb2
-rw-r--r--app/controllers/admin/services_controller.rb15
-rw-r--r--app/controllers/concerns/service_params.rb35
-rw-r--r--app/controllers/groups_controller.rb2
-rw-r--r--app/controllers/help_controller.rb2
-rw-r--r--app/controllers/projects/badges_controller.rb5
-rw-r--r--app/controllers/projects/commit_controller.rb4
-rw-r--r--app/controllers/projects/compare_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests_controller.rb10
-rw-r--r--app/controllers/projects/notes_controller.rb65
-rw-r--r--app/controllers/projects/pipelines_settings_controller.rb30
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects/services_controller.rb27
-rw-r--r--app/controllers/projects/uploads_controller.rb8
-rw-r--r--app/controllers/projects_controller.rb2
-rw-r--r--app/helpers/avatars_helper.rb30
-rw-r--r--app/helpers/ci_status_helper.rb23
-rw-r--r--app/helpers/commits_helper.rb10
-rw-r--r--app/helpers/diff_helper.rb16
-rw-r--r--app/helpers/external_wiki_helper.rb5
-rw-r--r--app/helpers/notes_helper.rb37
-rw-r--r--app/helpers/search_helper.rb3
-rw-r--r--app/helpers/services_helper.rb25
-rw-r--r--app/helpers/time_helper.rb27
-rw-r--r--app/models/ability.rb4
-rw-r--r--app/models/application_setting.rb52
-rw-r--r--app/models/ci/build.rb51
-rw-r--r--app/models/ci/pipeline.rb22
-rw-r--r--app/models/ci/runner.rb8
-rw-r--r--app/models/ci/trigger_request.rb8
-rw-r--r--app/models/commit_status.rb6
-rw-r--r--app/models/concerns/note_on_diff.rb25
-rw-r--r--app/models/discussion.rb91
-rw-r--r--app/models/issue.rb40
-rw-r--r--app/models/note.rb7
-rw-r--r--app/models/project.rb97
-rw-r--r--app/models/project_services/slack_service.rb51
-rw-r--r--app/models/project_team.rb2
-rw-r--r--app/models/repository.rb53
-rw-r--r--app/models/service.rb20
-rw-r--r--app/models/user.rb65
-rw-r--r--app/services/delete_branch_service.rb2
-rw-r--r--app/services/delete_tag_service.rb2
-rw-r--r--app/services/git_tag_push_service.rb4
-rw-r--r--app/services/repository_archive_clean_up_service.rb33
-rw-r--r--app/uploaders/file_uploader.rb5
-rw-r--r--app/uploaders/uploader_helper.rb41
-rw-r--r--app/views/admin/application_settings/_form.html.haml57
-rw-r--r--app/views/admin/groups/_form.html.haml4
-rw-r--r--app/views/discussions/_diff_discussion.html.haml6
-rw-r--r--app/views/discussions/_diff_with_notes.html.haml14
-rw-r--r--app/views/discussions/_discussion.html.haml45
-rw-r--r--app/views/discussions/_notes.html.haml5
-rw-r--r--app/views/discussions/_parallel_diff_discussion.html.haml22
-rw-r--r--app/views/events/_event.html.haml6
-rw-r--r--app/views/events/_event_scope.html.haml7
-rw-r--r--app/views/events/event/_common.html.haml9
-rw-r--r--app/views/events/event/_created_project.html.haml2
-rw-r--r--app/views/events/event/_note.html.haml11
-rw-r--r--app/views/events/event/_push.html.haml6
-rw-r--r--app/views/groups/edit.html.haml4
-rw-r--r--app/views/layouts/_init_auto_complete.html.haml10
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml2
-rw-r--r--app/views/layouts/nav/_explore.html.haml4
-rw-r--r--app/views/layouts/nav/_project_settings.html.haml6
-rw-r--r--app/views/layouts/project.html.haml2
-rw-r--r--app/views/profiles/_head.html.haml2
-rw-r--r--app/views/projects/_activity.html.haml3
-rw-r--r--app/views/projects/_builds_settings.html.haml65
-rw-r--r--app/views/projects/badges/index.html.haml23
-rw-r--r--app/views/projects/branches/_commit.html.haml2
-rw-r--r--app/views/projects/builds/_sidebar.html.haml2
-rw-r--r--app/views/projects/buttons/_fork.html.haml4
-rw-r--r--app/views/projects/ci/builds/_build.html.haml10
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml4
-rw-r--r--app/views/projects/commit/_pipeline.html.haml4
-rw-r--r--app/views/projects/commits/_commit.html.haml8
-rw-r--r--app/views/projects/deployments/_actions.haml2
-rw-r--r--app/views/projects/diffs/_match_line_parallel.html.haml4
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml51
-rw-r--r--app/views/projects/diffs/_text_file.html.haml6
-rw-r--r--app/views/projects/edit.html.haml6
-rw-r--r--app/views/projects/forks/index.html.haml4
-rw-r--r--app/views/projects/forks/new.html.haml91
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml2
-rw-r--r--app/views/projects/graphs/_head.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/_heading.html.haml2
-rw-r--r--app/views/projects/network/show.html.haml2
-rw-r--r--app/views/projects/new.html.haml24
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply.html.haml7
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml25
-rw-r--r--app/views/projects/notes/_discussion.html.haml46
-rw-r--r--app/views/projects/notes/_note.html.haml2
-rw-r--r--app/views/projects/notes/_notes.html.haml12
-rw-r--r--app/views/projects/notes/discussions/_diff_with_notes.html.haml17
-rw-r--r--app/views/projects/notes/discussions/_notes.html.haml6
-rw-r--r--app/views/projects/pipelines_settings/show.html.haml103
-rw-r--r--app/views/projects/protected_branches/index.html.haml13
-rw-r--r--app/views/projects/services/_form.html.haml1
-rw-r--r--app/views/projects/tags/show.html.haml67
-rw-r--r--app/views/shared/_allow_request_access.html.haml6
-rw-r--r--app/views/shared/_service_settings.html.haml81
-rw-r--r--app/views/shared/icons/_icon_fork.svg3
-rw-r--r--app/views/shared/icons/_icon_status_cancel.svg12
-rw-r--r--app/views/shared/icons/_icon_status_failed.svg12
-rw-r--r--app/views/shared/icons/_icon_status_pending.svg13
-rw-r--r--app/views/shared/icons/_icon_status_running.svg12
-rw-r--r--app/views/shared/icons/_icon_status_success.svg15
-rw-r--r--app/views/shared/icons/_icon_status_warning.svg15
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/workers/emails_on_push_worker.rb4
-rw-r--r--app/workers/repository_archive_cache_worker.rb2
139 files changed, 1616 insertions, 831 deletions
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
index b2b8e1b7ffb..90c09619f8c 100644
--- a/app/assets/javascripts/admin.js.coffee
+++ b/app/assets/javascripts/admin.js.coffee
@@ -38,3 +38,14 @@ class @Admin
$('li.group_member').bind 'ajax:success', ->
Turbolinks.visit(location.href)
+
+ showBlacklistType = ->
+ if $("input[name='blacklist_type']:checked").val() == 'file'
+ $('.blacklist-file').show()
+ $('.blacklist-raw').hide()
+ else
+ $('.blacklist-file').hide()
+ $('.blacklist-raw').show()
+
+ $("input[name='blacklist_type']").click showBlacklistType
+ showBlacklistType()
diff --git a/app/assets/javascripts/files_comment_button.js.coffee b/app/assets/javascripts/files_comment_button.js.coffee
index db0bf7082a9..5ab82c39fcd 100644
--- a/app/assets/javascripts/files_comment_button.js.coffee
+++ b/app/assets/javascripts/files_comment_button.js.coffee
@@ -7,7 +7,6 @@ class @FilesCommentButton
UNFOLDABLE_LINE_CLASS = 'js-unfold'
EMPTY_CELL_CLASS = 'empty-cell'
OLD_LINE_CLASS = 'old_line'
- NEW_CLASS = 'new'
LINE_COLUMN_CLASSES = ".#{LINE_NUMBER_CLASS}, .line_content"
TEXT_FILE_SELECTOR = '.text-file'
DEBOUNCE_TIMEOUT_DURATION = 100
@@ -18,6 +17,8 @@ class @FilesCommentButton
debounce = _.debounce @render, DEBOUNCE_TIMEOUT_DURATION
$(document)
+ .off 'mouseover', LINE_COLUMN_CLASSES
+ .off 'mouseleave', LINE_COLUMN_CLASSES
.on 'mouseover', LINE_COLUMN_CLASSES, debounce
.on 'mouseleave', LINE_COLUMN_CLASSES, @destroy
@@ -64,20 +65,20 @@ class @FilesCommentButton
getLineContent: (hoveredElement) ->
return hoveredElement if hoveredElement.hasClass LINE_CONTENT_CLASS
- $(".#{LINE_CONTENT_CLASS + @diffTypeClass hoveredElement}", hoveredElement.parent())
+ if @VIEW_TYPE is 'inline'
+ return $(hoveredElement).closest(LINE_HOLDER_CLASS).find ".#{LINE_CONTENT_CLASS}"
+ else
+ return $(hoveredElement).next ".#{LINE_CONTENT_CLASS}"
getButtonParent: (hoveredElement) ->
if @VIEW_TYPE is 'inline'
return hoveredElement if hoveredElement.hasClass OLD_LINE_CLASS
- $(".#{OLD_LINE_CLASS}", hoveredElement.parent())
+ hoveredElement.parent().find ".#{OLD_LINE_CLASS}"
else
return hoveredElement if hoveredElement.hasClass LINE_NUMBER_CLASS
- $(".#{LINE_NUMBER_CLASS + @diffTypeClass hoveredElement}", hoveredElement.parent())
-
- diffTypeClass: (hoveredElement) ->
- if hoveredElement.hasClass(NEW_CLASS) then '.new' else '.old'
+ $(hoveredElement).prev ".#{LINE_NUMBER_CLASS}"
isMovingToSameType: (e) ->
newButtonParent = @getButtonParent $(e.toElement)
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index 951530e03a5..7086ece29b8 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -210,9 +210,22 @@ class GitLabDropdown
data: =>
return @fullData
callback: (data) =>
- currentIndex = -1
@parseData data
+ unless @filterInput.val() is ''
+ selector = '.dropdown-content li:not(.divider):visible'
+
+ if @dropdown.find('.dropdown-toggle-page').length
+ selector = ".dropdown-page-one #{selector}"
+
+ $(selector, @dropdown)
+ .first()
+ .find('a')
+ .addClass('is-focused')
+
+ currentIndex = 0
+
+
# Event listeners
@dropdown.on "shown.bs.dropdown", @opened
diff --git a/app/assets/javascripts/graphs/application.js.coffee b/app/assets/javascripts/graphs/graphs_bundle.js.coffee
index e0f681acf0b..e0f681acf0b 100644
--- a/app/assets/javascripts/graphs/application.js.coffee
+++ b/app/assets/javascripts/graphs/graphs_bundle.js.coffee
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index 779f536d9f0..963a0550c35 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -55,10 +55,13 @@ class @MergeRequestWidget
$('.mr-state-widget').replaceWith(data)
ciLabelForStatus: (status) ->
- if status is 'success'
- 'passed'
- else
- status
+ switch status
+ when 'success'
+ 'passed'
+ when 'success_with_warnings'
+ 'passed with warnings'
+ else
+ status
pollCIStatus: ->
@fetchBuildStatusInterval = setInterval ( =>
@@ -116,7 +119,7 @@ class @MergeRequestWidget
showCIStatus: (state) ->
return if not state?
$('.ci_widget').hide()
- allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"]
+ allowed_states = ["failed", "canceled", "running", "pending", "success", "success_with_warnings", "skipped", "not_found"]
if state in allowed_states
$('.ci_widget.ci-' + state).show()
switch state
@@ -124,7 +127,7 @@ class @MergeRequestWidget
@setMergeButtonClass('btn-danger')
when "running"
@setMergeButtonClass('btn-warning')
- when "success"
+ when "success", "success_with_warnings"
@setMergeButtonClass('btn-create')
else
$('.ci_widget.ci-error').show()
diff --git a/app/assets/javascripts/network/application.js.coffee b/app/assets/javascripts/network/network_bundle.js.coffee
index f75f63869c5..f75f63869c5 100644
--- a/app/assets/javascripts/network/application.js.coffee
+++ b/app/assets/javascripts/network/network_bundle.js.coffee
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 0ea54faae1a..d4de712f88c 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -162,7 +162,7 @@ class @Notes
@last_fetched_at = data.last_fetched_at
@setPollingInterval(data.notes.length)
$.each notes, (i, note) =>
- if note.discussion_with_diff_html?
+ if note.discussion_html?
@renderDiscussionNote(note)
else
@renderNote(note)
@@ -251,7 +251,7 @@ class @Notes
discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']")
if discussionContainer.length is 0
# insert the note and the reply button after the temp row
- row.after note.discussion_html
+ row.after note.diff_discussion_html
# remove the note (will be added again below)
row.next().find(".note").remove()
@@ -265,7 +265,7 @@ class @Notes
# Init discussion on 'Discussion' page if it is merge request page
if $('body').attr('data-page').indexOf('projects:merge_request') is 0
$('ul.main-notes-list')
- .append(note.discussion_with_diff_html)
+ .append(note.discussion_html)
.syntaxHighlight()
else
# append new note to all matching discussions
diff --git a/app/assets/javascripts/profile/application.js.coffee b/app/assets/javascripts/profile/profile_bundle.js.coffee
index 91cacfece46..91cacfece46 100644
--- a/app/assets/javascripts/profile/application.js.coffee
+++ b/app/assets/javascripts/profile/profile_bundle.js.coffee
diff --git a/app/assets/javascripts/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee
index 12340bbce54..0c95301e380 100644
--- a/app/assets/javascripts/right_sidebar.js.coffee
+++ b/app/assets/javascripts/right_sidebar.js.coffee
@@ -120,6 +120,9 @@ class @Sidebar
i.show()
sidebarCollapseClicked: (e) ->
+
+ return if $(e.currentTarget).hasClass('dont-change-state')
+
sidebar = e.data
e.preventDefault()
$block = $(@).closest('.block')
diff --git a/app/assets/javascripts/users/application.js.coffee b/app/assets/javascripts/users/users_bundle.js.coffee
index 91cacfece46..91cacfece46 100644
--- a/app/assets/javascripts/users/application.js.coffee
+++ b/app/assets/javascripts/users/users_bundle.js.coffee
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index ad94e457cfd..7ce203d2ec7 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -232,7 +232,9 @@
.nav-block {
.controls {
float: right;
- margin-top: 11px;
+ margin-top: 8px;
+ padding-bottom: 7px;
+ border-bottom: 1px solid $border-color;
}
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 590b8f54363..f87b8a2ad1c 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -49,6 +49,17 @@
border-color: $border-dark;
color: $color;
}
+
+ svg {
+
+ path {
+ fill: $color;
+ }
+
+ use {
+ stroke: $color;
+ }
+ }
}
@mixin btn-green {
@@ -173,6 +184,13 @@
.caret {
margin-left: 5px;
}
+
+ svg {
+ height: 15px;
+ width: auto;
+ position: relative;
+ top: 2px;
+ }
}
.btn-lg {
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 5d3273ea64d..96565da1bc9 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -98,13 +98,30 @@
.md {
&.md-preview-holder {
- code {
- white-space: pre-wrap;
- word-break: keep-all;
- }
-
+ // Reset ul style types since we're nested inside a ul already
@include bulleted-list;
}
+
+ // On diffs code should wrap nicely and not overflow
+ code {
+ white-space: pre-wrap;
+ word-break: keep-all;
+ }
+
+ hr {
+ // Darken 'whitesmoke' a bit to make it more visible in note bodies
+ border-color: darken(#f5f5f5, 8%);
+ margin: 10px 0;
+ }
+
+ // Border around images in issue and MR comments.
+ img:not(.emoji) {
+ border: 1px solid $table-border-gray;
+ padding: 5px;
+ margin: 5px 0;
+ // Ensure that image does not exceed viewport
+ max-height: calc(100vh - 100px);
+ }
}
.toolbar-group {
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index d52e8f00172..3fa4a22258d 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -198,6 +198,10 @@ header.header-pinned-nav {
.sidebar-collapsed-icon {
cursor: pointer;
+
+ .btn {
+ background-color: $gray-light;
+ }
}
}
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 99a2cd306cf..e26f8f7080d 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -53,6 +53,14 @@
left: 70px;
}
}
+
+ .nav-links {
+ svg {
+ position: relative;
+ top: 2px;
+ margin-right: 3px;
+ }
+ }
}
.build-header {
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index 35ab28b3fea..bbe0c6c5f1f 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -68,6 +68,12 @@
}
}
+.ci-status-link {
+ svg {
+ overflow: visible;
+ }
+}
+
.commit-box {
border-top: 1px solid $border-color;
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index a2145956eb5..5c336bb1c7e 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -176,3 +176,11 @@
}
}
}
+
+// hide event scope (namespace + project) where it is not necessary
+.project-activity {
+ .event-scope {
+ display: none;
+ }
+}
+
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 542fa244689..7a50bc9c832 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -122,7 +122,8 @@
button {
float: right;
- padding: 3px 5px;
+ padding: 1px 5px;
+ background-color: $gray-light;
}
}
@@ -268,7 +269,7 @@
.issuable-header-btn {
background: $gray-normal;
border: 1px solid $border-gray-normal;
-
+
&:hover {
background: $gray-dark;
border: 1px solid $border-gray-dark;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 9807c5a808d..ee3b2d2b801 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -78,6 +78,14 @@ form.edit-issue {
}
}
+.merge-request-ci-status {
+ svg {
+ margin-right: 4px;
+ position: relative;
+ top: 1px;
+ }
+}
+
@media (max-width: $screen-xs-max) {
.issue-btn-group {
width: 100%;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index fbff0c97355..db295935b00 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -60,14 +60,25 @@
.ci_widget {
border-bottom: 1px solid #eef0f2;
- i {
+ svg {
margin-right: 4px;
+ position: relative;
+ top: 1px;
+ overflow: visible;
}
&.ci-success {
color: $gl-success;
}
+ &.ci-success_with_warnings {
+ color: $gl-success;
+
+ i {
+ color: $gl-warning;
+ }
+ }
+
&.ci-skipped {
background-color: #eee;
color: #888;
@@ -196,6 +207,16 @@
.merge-request-title {
margin-bottom: 2px;
+
+ .ci-status-link {
+
+ svg {
+ height: 16px;
+ width: 16px;
+ position: relative;
+ top: 3px;
+ }
+ }
}
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index ac8c02b59dc..a2b5437e503 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -91,34 +91,11 @@ ul.notes {
// Reset ul style types since we're nested inside a ul already
@include bulleted-list;
- // On diffs code should wrap nicely and not overflow
- code {
- white-space: pre-wrap;
- }
-
ul.task-list {
ul:not(.task-list) {
padding-left: 1.3em;
}
}
-
- hr {
- // Darken 'whitesmoke' a bit to make it more visible in note bodies
- border-color: darken(#f5f5f5, 8%);
- margin: 10px 0;
- }
-
- code {
- word-break: keep-all;
- }
-
- // Border around images in issue and MR comments.
- img:not(.emoji) {
- border: 1px solid $table-border-gray;
- padding: 5px;
- margin: 5px 0;
- max-height: calc(100vh - 100px);
- }
}
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index a3b72ec9574..c58e2ffe7f5 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -29,9 +29,18 @@
}
}
+.pipeline-holder {
+ width: 100%;
+ overflow: auto;
+}
+
.table.builds {
min-width: 1200px;
+ &.pipeline {
+ min-width: 650px;
+ }
+
tr {
th {
padding: 16px 8px;
@@ -49,6 +58,14 @@
.commit-link {
+ .ci-status {
+
+ svg {
+ top: 1px;
+ margin-right: 0;
+ }
+ }
+
a:hover {
text-decoration: none;
}
@@ -68,7 +85,7 @@
svg {
height: 14px;
- width: auto;
+ width: 14px;
vertical-align: middle;
fill: $table-text-gray;
}
@@ -85,7 +102,7 @@
.commit-title {
margin-top: 4px;
- max-width: 320px;
+ max-width: 300px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
@@ -124,6 +141,20 @@
}
}
+ .stage-cell {
+
+ svg {
+ height: 18px;
+ width: 18px;
+ vertical-align: middle;
+ overflow: visible;
+ }
+
+ .light {
+ width: 3px;
+ }
+ }
+
.duration,
.finished-at {
color: $table-text-gray;
@@ -136,7 +167,7 @@
svg {
width: 12px;
- height: auto;
+ height: 12px;
vertical-align: middle;
margin-right: 4px;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index ea9f7cf0540..cc3aef5199e 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -129,6 +129,17 @@
color: $layout-link-gray;
}
+ svg {
+
+ path {
+ fill: $layout-link-gray;
+ }
+
+ use {
+ stroke: $layout-link-gray;
+ }
+ }
+
.fa-caret-down {
margin-left: 3px;
}
@@ -322,18 +333,53 @@ a.deploy-project-label {
}
.fork-namespaces {
- .fork-thumbnail {
- text-align: center;
- margin-bottom: $gl-padding;
-
- .caption {
- padding: $gl-padding 0;
- min-height: 30px;
- }
+ .row {
+ -webkit-flex-wrap: wrap;
+ display: -webkit-flex;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+
+ .fork-thumbnail {
+ @include border-radius($border-radius-base);
+ background-color: $white-light;
+ border: 1px solid $border-white-light;
+ height: 202px;
+ margin: $gl-padding;
+ text-align: center;
+ width: 169px;
+ &:hover, &.forked {
+ background-color: $row-hover;
+ border-color: $row-hover-border;
+ }
+ .no-avatar {
+ width: 100px;
+ height: 100px;
+ background-color: $gray-light;
+ border: 1px solid $gray-dark;
+ margin: 0 auto;
+ @include border-radius(50%);
+ i {
+ font-size: 100px;
+ color: $gray-dark;
+ }
+ }
+ a {
+ display: block;
+ width: 100%;
+ height: 100%;
+ padding-top: $gl-padding;
+ color: $gl-gray;
+ .caption {
+ min-height: 30px;
+ padding: $gl-padding 0;
+ }
+ }
- img {
- @include border-radius(50%);
- max-width: 100px;
+ img {
+ @include border-radius(50%);
+ max-width: 100px;
+ }
}
}
}
@@ -486,6 +532,11 @@ pre.light-well {
> span {
margin-left: 10px;
}
+
+ svg {
+ position: relative;
+ top: 2px;
+ }
}
}
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index c6b053150be..587f2d9f3c1 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -15,7 +15,8 @@
border-color: $gl-danger;
}
- &.ci-success {
+ &.ci-success,
+ &.ci-success_with_warnings {
color: $gl-success;
border-color: $gl-success;
}
@@ -41,6 +42,15 @@
color: $blue-normal;
border-color: $blue-normal;
}
+
+ svg {
+ height: 13px;
+ width: 13px;
+ position: relative;
+ top: 1px;
+ margin: 0 3px;
+ overflow: visible;
+ }
}
.ci-status-icon-success {
@@ -49,9 +59,12 @@
.ci-status-icon-failed {
color: $gl-danger;
}
- .ci-status-icon-pending {
+
+ .ci-status-icon-pending,
+ .ci-status-icon-success_with_warning {
color: $gl-warning;
}
+
.ci-status-icon-running {
color: $blue-normal;
}
@@ -62,3 +75,11 @@
color: $gl-gray;
}
}
+
+.visible-xs-inline {
+ .ci-status-link {
+ position: relative;
+ top: 2px;
+ left: 5px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/tags.scss b/app/assets/stylesheets/pages/tags.scss
new file mode 100644
index 00000000000..24ebd3e7cfa
--- /dev/null
+++ b/app/assets/stylesheets/pages/tags.scss
@@ -0,0 +1,7 @@
+.tag-buttons {
+ line-height: 40px;
+
+ .btn:not(.dropdown-toggle) {
+ margin-left: 10px;
+ }
+}
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 23ba83aba0e..9e1dc15de84 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -64,6 +64,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
params[:application_setting][:disabled_oauth_sign_in_sources] =
AuthHelper.button_based_providers.map(&:to_s) -
Array(enabled_oauth_sign_in_sources)
+ params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file]
params.require(:application_setting).permit(
:default_projects_limit,
@@ -83,7 +84,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:default_project_visibility,
:default_snippet_visibility,
:default_group_visibility,
- :restricted_signup_domains_raw,
+ :domain_whitelist_raw,
+ :domain_blacklist_enabled,
+ :domain_blacklist_raw,
+ :domain_blacklist_file,
:version_check_enabled,
:admin_notification_email,
:user_oauth_applications,
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 94b5aaa71d0..f3a88a8e6c8 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -60,6 +60,6 @@ class Admin::GroupsController < Admin::ApplicationController
end
def group_params
- params.require(:group).permit(:name, :description, :path, :avatar, :visibility_level)
+ params.require(:group).permit(:name, :description, :path, :avatar, :visibility_level, :request_access_enabled)
end
end
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index 46133588332..7c37f3155da 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -1,4 +1,6 @@
class Admin::ServicesController < Admin::ApplicationController
+ include ServiceParams
+
before_action :service, only: [:edit, :update]
def index
@@ -13,7 +15,7 @@ class Admin::ServicesController < Admin::ApplicationController
end
def update
- if service.update_attributes(application_services_params[:service])
+ if service.update_attributes(service_params[:service])
redirect_to admin_application_settings_services_path,
notice: 'Application settings saved successfully'
else
@@ -37,15 +39,4 @@ class Admin::ServicesController < Admin::ApplicationController
def service
@service ||= Service.where(id: params[:id], template: true).first
end
-
- def application_services_params
- application_services_params = params.permit(:id,
- service: Projects::ServicesController::ALLOWED_PARAMS)
- if application_services_params[:service].is_a?(Hash)
- Projects::ServicesController::FILTER_BLANK_PARAMS.each do |param|
- application_services_params[:service].delete(param) if application_services_params[:service][param].blank?
- end
- end
- application_services_params
- end
end
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb
new file mode 100644
index 00000000000..471d15af913
--- /dev/null
+++ b/app/controllers/concerns/service_params.rb
@@ -0,0 +1,35 @@
+module ServiceParams
+ extend ActiveSupport::Concern
+
+ ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_url, :api_version, :subdomain,
+ :room, :recipients, :project_url, :webhook,
+ :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
+ :build_key, :server, :teamcity_url, :drone_url, :build_type,
+ :description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
+ :colorize_messages, :channels,
+ :push_events, :issues_events, :merge_requests_events, :tag_push_events,
+ :note_events, :build_events, :wiki_page_events,
+ :notify_only_broken_builds, :add_pusher,
+ :send_from_committer_email, :disable_diffs, :external_wiki_url,
+ :notify, :color,
+ :server_host, :server_port, :default_irc_uri, :enable_ssl_verification,
+ :jira_issue_transition_id]
+
+ # Parameters to ignore if no value is specified
+ FILTER_BLANK_PARAMS = [:password]
+
+ def service_params
+ dynamic_params = []
+ dynamic_params.concat(@service.event_channel_names)
+
+ service_params = params.permit(:id, service: ALLOWED_PARAMS + dynamic_params)
+
+ if service_params[:service].is_a?(Hash)
+ FILTER_BLANK_PARAMS.each do |param|
+ service_params[:service].delete(param) if service_params[:service][param].blank?
+ end
+ end
+
+ service_params
+ end
+end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index a04bf7df722..6780a6d4d87 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -121,7 +121,7 @@ class GroupsController < Groups::ApplicationController
end
def group_params
- params.require(:group).permit(:name, :description, :path, :avatar, :public, :visibility_level, :share_with_group_lock)
+ params.require(:group).permit(:name, :description, :path, :avatar, :public, :visibility_level, :share_with_group_lock, :request_access_enabled)
end
def load_events
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index d3dd98c8a4e..f7b44099b78 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -30,7 +30,7 @@ class HelpController < ApplicationController
end
# Allow access to images in the doc folder
- format.any(:png, :gif, :jpeg) do
+ format.any(:png, :gif, :jpeg, :mp4) do
# Note: We are purposefully NOT using `Rails.root.join`
path = File.join(Rails.root, 'doc', "#{@path}.#{params[:format]}")
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index 824aa41db51..a9f482c8787 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -3,11 +3,6 @@ class Projects::BadgesController < Projects::ApplicationController
before_action :authorize_admin_project!, only: [:index]
before_action :no_cache_headers, except: [:index]
- def index
- @ref = params[:ref] || @project.default_branch || 'master'
- @build_badge = Gitlab::Badge::Build.new(@project, @ref)
- end
-
def build
badge = Gitlab::Badge::Build.new(project, params[:ref])
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 727e84b40a1..7ae034f9398 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -115,11 +115,11 @@ class Projects::CommitController < Projects::ApplicationController
end
def define_note_vars
- @grouped_diff_notes = commit.notes.grouped_diff_notes
+ @grouped_diff_discussions = commit.notes.grouped_diff_discussions
@notes = commit.notes.non_diff_notes.fresh
Banzai::NoteRenderer.render(
- @grouped_diff_notes.values.flatten + @notes,
+ @grouped_diff_discussions.values.flat_map(&:notes) + @notes,
@project,
current_user,
)
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 5f3ee71444d..8c004724f02 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -15,6 +15,7 @@ class Projects::CompareController < Projects::ApplicationController
end
def show
+ apply_diff_view_cookie!
end
def diff_for_path
@@ -53,7 +54,7 @@ class Projects::CompareController < Projects::ApplicationController
)
@diff_notes_disabled = true
- @grouped_diff_notes = {}
+ @grouped_diff_discussions = {}
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index df659bb8c3b..594a61464b9 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -97,7 +97,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
else
build_merge_request
@diff_notes_disabled = true
- @grouped_diff_notes = {}
+ @grouped_diff_discussions = {}
end
define_commit_vars
@@ -286,6 +286,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
status = pipeline.status
coverage = pipeline.try(:coverage)
+ status = "success_with_warnings" if pipeline.success? && pipeline.has_warnings?
+
status ||= "preparing"
else
ci_service = @merge_request.source_project.ci_service
@@ -376,7 +378,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# This is not executed lazily
@notes = Banzai::NoteRenderer.render(
- @discussions.flatten,
+ @discussions.flat_map(&:notes),
@project,
current_user,
@path,
@@ -402,10 +404,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
}
@use_legacy_diff_notes = !@merge_request.support_new_diff_notes?
- @grouped_diff_notes = @merge_request.notes.grouped_diff_notes
+ @grouped_diff_discussions = @merge_request.notes.grouped_diff_discussions
Banzai::NoteRenderer.render(
- @grouped_diff_notes.values.flatten,
+ @grouped_diff_discussions.values.flat_map(&:notes),
@project,
current_user,
@path,
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 3eacdbbd067..766b7e9cf22 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -73,7 +73,7 @@ class Projects::NotesController < Projects::ApplicationController
end
alias_method :awardable, :note
- def note_to_html(note)
+ def note_html(note)
render_to_string(
"projects/notes/_note",
layout: false,
@@ -82,20 +82,20 @@ class Projects::NotesController < Projects::ApplicationController
)
end
- def note_to_discussion_html(note)
- return unless note.diff_note?
+ def diff_discussion_html(discussion)
+ return unless discussion.diff_discussion?
if params[:view] == 'parallel'
- template = "projects/notes/_diff_notes_with_reply_parallel"
+ template = "discussions/_parallel_diff_discussion"
locals =
if params[:line_type] == 'old'
- { notes_left: [note], notes_right: [] }
+ { discussion_left: discussion, discussion_right: nil }
else
- { notes_left: [], notes_right: [note] }
+ { discussion_left: nil, discussion_right: discussion }
end
else
- template = "projects/notes/_diff_notes_with_reply"
- locals = { notes: [note] }
+ template = "discussions/_diff_discussion"
+ locals = { discussion: discussion }
end
render_to_string(
@@ -106,14 +106,14 @@ class Projects::NotesController < Projects::ApplicationController
)
end
- def note_to_discussion_with_diff_html(note)
- return unless note.diff_note?
+ def discussion_html(discussion)
+ return unless discussion.diff_discussion?
render_to_string(
- "projects/notes/_discussion",
+ "discussions/_discussion",
layout: false,
formats: [:html],
- locals: { discussion_notes: [note] }
+ locals: { discussion: discussion }
)
end
@@ -132,26 +132,33 @@ class Projects::NotesController < Projects::ApplicationController
valid: true,
id: note.id,
discussion_id: note.discussion_id,
- html: note_to_html(note),
+ html: note_html(note),
award: false,
- note: note.note,
- discussion_html: note_to_discussion_html(note),
- discussion_with_diff_html: note_to_discussion_with_diff_html(note)
+ note: note.note
}
- # The discussion_id is used to add the comment to the correct discussion
- # element on the merge request page. Among other things, the discussion_id
- # contains the sha of head commit of the merge request.
- # When new commits are pushed into the merge request after the initial
- # load of the merge request page, the discussion elements will still have
- # the old discussion_ids, with the old head commit sha. The new comment,
- # however, will have the new discussion_id with the new commit sha.
- # To ensure that these new comments will still end up in the correct
- # discussion element, we also send the original discussion_id, with the
- # old commit sha, along, and fall back on this value when no discussion
- # element with the new discussion_id could be found.
- if note.new_diff_note? && note.position != note.original_position
- attrs[:original_discussion_id] = note.original_discussion_id
+ if note.diff_note?
+ discussion = Discussion.new([note])
+
+ attrs.merge!(
+ diff_discussion_html: diff_discussion_html(discussion),
+ discussion_html: discussion_html(discussion)
+ )
+
+ # The discussion_id is used to add the comment to the correct discussion
+ # element on the merge request page. Among other things, the discussion_id
+ # contains the sha of head commit of the merge request.
+ # When new commits are pushed into the merge request after the initial
+ # load of the merge request page, the discussion elements will still have
+ # the old discussion_ids, with the old head commit sha. The new comment,
+ # however, will have the new discussion_id with the new commit sha.
+ # To ensure that these new comments will still end up in the correct
+ # discussion element, we also send the original discussion_id, with the
+ # old commit sha, along, and fall back on this value when no discussion
+ # element with the new discussion_id could be found.
+ if note.new_diff_note? && note.position != note.original_position
+ attrs[:original_discussion_id] = note.original_discussion_id
+ end
end
attrs
diff --git a/app/controllers/projects/pipelines_settings_controller.rb b/app/controllers/projects/pipelines_settings_controller.rb
new file mode 100644
index 00000000000..85ba706e5cd
--- /dev/null
+++ b/app/controllers/projects/pipelines_settings_controller.rb
@@ -0,0 +1,30 @@
+class Projects::PipelinesSettingsController < Projects::ApplicationController
+ before_action :authorize_admin_pipeline!
+
+ def show
+ @ref = params[:ref] || @project.default_branch || 'master'
+ @build_badge = Gitlab::Badge::Build.new(@project, @ref)
+ end
+
+ def update
+ if @project.update_attributes(update_params)
+ flash[:notice] = "CI/CD Pipelines settings for '#{@project.name}' were successfully updated."
+ redirect_to namespace_project_pipelines_settings_path(@project.namespace, @project)
+ else
+ render 'index'
+ end
+ end
+
+ private
+
+ def create_params
+ params.require(:pipeline).permit(:ref)
+ end
+
+ def update_params
+ params.require(:project).permit(
+ :runners_token, :builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
+ :public_builds
+ )
+ end
+end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index d79f16e6a5a..3602b3d5e58 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -25,7 +25,7 @@ class Projects::RefsController < Projects::ApplicationController
when "graphs_commits"
commits_namespace_project_graph_path(@project.namespace, @project, @id)
when "badges"
- namespace_project_badges_path(@project.namespace, @project, ref: @id)
+ namespace_project_pipelines_settings_path(@project.namespace, @project, ref: @id)
else
namespace_project_commits_path(@project.namespace, @project, @id)
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 1b91882048e..6a227d85f6f 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -1,20 +1,5 @@
class Projects::ServicesController < Projects::ApplicationController
- ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_url, :api_version, :subdomain,
- :room, :recipients, :project_url, :webhook,
- :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
- :build_key, :server, :teamcity_url, :drone_url, :build_type,
- :description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
- :colorize_messages, :channels,
- :push_events, :issues_events, :merge_requests_events, :tag_push_events,
- :note_events, :build_events, :wiki_page_events,
- :notify_only_broken_builds, :add_pusher,
- :send_from_committer_email, :disable_diffs, :external_wiki_url,
- :notify, :color,
- :server_host, :server_port, :default_irc_uri, :enable_ssl_verification,
- :jira_issue_transition_id]
-
- # Parameters to ignore if no value is specified
- FILTER_BLANK_PARAMS = [:password]
+ include ServiceParams
# Authorize
before_action :authorize_admin_project!
@@ -33,7 +18,7 @@ class Projects::ServicesController < Projects::ApplicationController
end
def update
- if @service.update_attributes(service_params)
+ if @service.update_attributes(service_params[:service])
redirect_to(
edit_namespace_project_service_path(@project.namespace, @project,
@service.to_param, notice:
@@ -64,12 +49,4 @@ class Projects::ServicesController < Projects::ApplicationController
def service
@service ||= @project.services.find { |service| service.to_param == params[:id] }
end
-
- def service_params
- service_params = params.require(:service).permit(ALLOWED_PARAMS)
- FILTER_BLANK_PARAMS.each do |param|
- service_params.delete(param) if service_params[param].blank?
- end
- service_params
- end
end
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index caed064dfbc..e617be8f9fb 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -1,6 +1,6 @@
class Projects::UploadsController < Projects::ApplicationController
skip_before_action :reject_blocked!, :project,
- :repository, if: -> { action_name == 'show' && image? }
+ :repository, if: -> { action_name == 'show' && image_or_video? }
before_action :authorize_upload_file!, only: [:create]
@@ -24,7 +24,7 @@ class Projects::UploadsController < Projects::ApplicationController
def show
return render_404 if uploader.nil? || !uploader.file.exists?
- disposition = uploader.image? ? 'inline' : 'attachment'
+ disposition = uploader.image_or_video? ? 'inline' : 'attachment'
send_file uploader.file.path, disposition: disposition
end
@@ -49,7 +49,7 @@ class Projects::UploadsController < Projects::ApplicationController
@uploader
end
- def image?
- uploader && uploader.file.exists? && uploader.image?
+ def image_or_video?
+ uploader && uploader.file.exists? && uploader.image_or_video?
end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 4e5bcff9cf8..ec7a2e63b9a 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -296,7 +296,7 @@ class ProjectsController < Projects::ApplicationController
:issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
- :public_builds, :only_allow_merge_if_build_succeeds
+ :public_builds, :only_allow_merge_if_build_succeeds, :request_access_enabled
)
end
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
new file mode 100644
index 00000000000..6ff40c6b461
--- /dev/null
+++ b/app/helpers/avatars_helper.rb
@@ -0,0 +1,30 @@
+module AvatarsHelper
+
+ def author_avatar(commit_or_event, options = {})
+ user_avatar(options.merge({
+ user: commit_or_event.author,
+ user_name: commit_or_event.author_name,
+ user_email: commit_or_event.author_email,
+ }))
+ end
+
+ private
+
+ def user_avatar(options = {})
+ avatar_size = options[:size] || 16
+ user_name = options[:user].try(:name) || options[:user_name]
+ avatar = image_tag(
+ avatar_icon(options[:user] || options[:user_email], avatar_size),
+ class: "avatar has-tooltip hidden-xs s#{avatar_size}",
+ alt: "#{user_name}'s avatar",
+ title: user_name
+ )
+
+ if options[:user]
+ link_to(avatar, user_path(options[:user]))
+ elsif options[:user_email]
+ mail_to(options[:user_email], avatar)
+ end
+ end
+
+end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index e6c99c9959e..ea2f5f9281a 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -15,8 +15,11 @@ module CiStatusHelper
end
def ci_label_for_status(status)
- if status == 'success'
+ case status
+ when 'success'
'passed'
+ when 'success_with_warnings'
+ 'passed with warnings'
else
status
end
@@ -26,24 +29,26 @@ module CiStatusHelper
icon_name =
case status
when 'success'
- 'check'
+ 'icon_status_success'
+ when 'success_with_warnings'
+ 'icon_status_warning'
when 'failed'
- 'close'
+ 'icon_status_failed'
when 'pending'
- 'clock-o'
+ 'icon_status_pending'
when 'running'
- 'spinner'
+ 'icon_status_running'
else
- 'circle'
+ 'icon_status_cancel'
end
- icon(icon_name + ' fw')
+ custom_icon(icon_name)
end
- def render_commit_status(commit, tooltip_placement: 'auto left', cssclass: '')
+ def render_commit_status(commit, tooltip_placement: 'auto left')
project = commit.project
path = builds_namespace_project_commit_path(project.namespace, project, commit)
- render_status_with_link('commit', commit.status, path, tooltip_placement, cssclass: cssclass)
+ render_status_with_link('commit', commit.status, path, tooltip_placement)
end
def render_pipeline_status(pipeline, tooltip_placement: 'auto left')
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 474041eccbb..052ce56809e 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -16,16 +16,6 @@ module CommitsHelper
commit_person_link(commit, options.merge(source: :committer))
end
- def commit_author_avatar(commit, options = {})
- options = options.merge(source: :author)
- user = commit.send(options[:source])
-
- source_email = clean(commit.send "#{options[:source]}_email".to_sym)
- person_email = user.try(:email) || source_email
-
- image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]} hidden-xs", width: options[:size], alt: "")
- end
-
def image_diff_class(diff)
if diff.deleted_file
"deleted"
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 75b029365f9..4c031942793 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -54,18 +54,20 @@ module DiffHelper
end
end
- def organize_comments(left, right)
- notes_left = notes_right = nil
+ def parallel_diff_discussions(left, right, diff_file)
+ discussion_left = discussion_right = nil
- unless left[:type].nil? && right[:type] == 'new'
- notes_left = @grouped_diff_notes[left[:line_code]]
+ if left && (left.unchanged? || left.removed?)
+ line_code = diff_file.line_code(left)
+ discussion_left = @grouped_diff_discussions[line_code]
end
- unless left[:type].nil? && right[:type].nil?
- notes_right = @grouped_diff_notes[right[:line_code]]
+ if right && right.added?
+ line_code = diff_file.line_code(right)
+ discussion_right = @grouped_diff_discussions[line_code]
end
- [notes_left, notes_right]
+ [discussion_left, discussion_right]
end
def inline_diff_btn
diff --git a/app/helpers/external_wiki_helper.rb b/app/helpers/external_wiki_helper.rb
index 1f3401f2906..defd87d6bbe 100644
--- a/app/helpers/external_wiki_helper.rb
+++ b/app/helpers/external_wiki_helper.rb
@@ -1,8 +1,7 @@
module ExternalWikiHelper
def get_project_wiki_path(project)
- external_wiki_service = project.services.
- find { |service| service.to_param == 'external_wiki' }
- if external_wiki_service.present? && external_wiki_service.active?
+ external_wiki_service = project.external_wiki
+ if external_wiki_service
external_wiki_service.properties['external_wiki_url']
else
namespace_project_wiki_path(project.namespace, project, :home)
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 98143dcee9b..0f60dd828ab 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -1,9 +1,4 @@
module NotesHelper
- # Helps to distinguish e.g. commit notes in mr notes list
- def note_for_main_target?(note)
- @noteable.class.name == note.noteable_type && !note.diff_note?
- end
-
def note_target_fields(note)
if note.noteable
hidden_field_tag(:target_type, note.noteable.class.name.underscore) +
@@ -44,8 +39,8 @@ module NotesHelper
# If we didn't, diff notes that would show for the same line on the changes
# tab, would show in different discussions on the discussion tab.
use_legacy_diff_note ||= begin
- line_diff_notes = @grouped_diff_notes[line_code]
- line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?)
+ discussion = @grouped_diff_discussions[line_code]
+ discussion && discussion.legacy_diff_discussion?
end
data = {
@@ -81,22 +76,10 @@ module NotesHelper
data
end
- def link_to_reply_discussion(note, line_type = nil)
+ def link_to_reply_discussion(discussion, line_type = nil)
return unless current_user
- data = {
- noteable_type: note.noteable_type,
- noteable_id: note.noteable_id,
- commit_id: note.commit_id,
- discussion_id: note.discussion_id,
- line_type: line_type
- }
-
- if note.diff_note?
- data[:note_type] = note.type
-
- data.merge!(note.diff_attributes)
- end
+ data = discussion.reply_attributes.merge(line_type: line_type)
content_tag(:div, class: "discussion-reply-holder") do
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
@@ -114,13 +97,13 @@ module NotesHelper
@max_access_by_user_id[full_key]
end
- def diff_note_path(note)
- return unless note.diff_note?
+ def discussion_diff_path(discussion)
+ return unless discussion.diff_discussion?
- if note.for_merge_request? && note.active?
- diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code)
- elsif note.for_commit?
- namespace_project_commit_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code)
+ if discussion.for_merge_request? && discussion.active?
+ diffs_namespace_project_merge_request_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code)
+ elsif discussion.for_commit?
+ namespace_project_commit_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code)
end
end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index fcb2703e837..a2bba139c17 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -112,7 +112,8 @@ module SearchHelper
search: params[:search],
project_id: params[:project_id],
group_id: params[:group_id],
- scope: params[:scope]
+ scope: params[:scope],
+ repository_ref: params[:repository_ref]
}
options = exist_opts.merge(options)
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
new file mode 100644
index 00000000000..2dd0bf5d71e
--- /dev/null
+++ b/app/helpers/services_helper.rb
@@ -0,0 +1,25 @@
+module ServicesHelper
+ def service_event_description(event)
+ case event
+ when "push"
+ "Event will be triggered by a push to the repository"
+ when "tag_push"
+ "Event will be triggered when a new tag is pushed to the repository"
+ when "note"
+ "Event will be triggered when someone adds a comment"
+ when "issue"
+ "Event will be triggered when an issue is created/updated/merged"
+ when "merge_request"
+ "Event will be triggered when a merge request is created/updated/merged"
+ when "build"
+ "Event will be triggered when a build status changes"
+ when "wiki_page"
+ "Event will be triggered when a wiki page is created/updated"
+ end
+ end
+
+ def service_event_field_name(event)
+ event = event.pluralize if %w[merge_request issue].include?(event)
+ "#{event}_events"
+ end
+end
diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb
index 8cb82c2d5cc..790001222f1 100644
--- a/app/helpers/time_helper.rb
+++ b/app/helpers/time_helper.rb
@@ -1,15 +1,6 @@
module TimeHelper
- def duration_in_words(finished_at, started_at)
- if finished_at && started_at
- interval_in_seconds = finished_at.to_i - started_at.to_i
- elsif started_at
- interval_in_seconds = Time.now.to_i - started_at.to_i
- end
-
- time_interval_in_words(interval_in_seconds)
- end
-
def time_interval_in_words(interval_in_seconds)
+ interval_in_seconds = interval_in_seconds.to_i
minutes = interval_in_seconds / 60
seconds = interval_in_seconds - minutes * 60
@@ -25,9 +16,19 @@ module TimeHelper
end
def duration_in_numbers(finished_at, started_at)
- diff_in_seconds = finished_at.to_i - started_at.to_i
- time_format = diff_in_seconds < 1.hour ? "%M:%S" : "%H:%M:%S"
+ interval = interval_in_seconds(started_at, finished_at)
+ time_format = interval < 1.hour ? "%M:%S" : "%H:%M:%S"
- Time.at(diff_in_seconds).utc.strftime(time_format)
+ Time.at(interval).utc.strftime(time_format)
+ end
+
+ private
+
+ def interval_in_seconds(started_at, finished_at = nil)
+ if started_at && finished_at
+ finished_at.to_i - started_at.to_i
+ elsif started_at
+ Time.now.to_i - started_at.to_i
+ end
end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 6fd18f2ee24..f33c8d61d3f 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -172,7 +172,7 @@ class Ability
rules << :read_build if project.public_builds?
unless owner || project.team.member?(user) || project_group_member?(project, user)
- rules << :request_access
+ rules << :request_access if project.request_access_enabled
end
end
@@ -373,7 +373,7 @@ class Ability
end
if group.public? || (group.internal? && !user.external?)
- rules << :request_access unless group.users.include?(user)
+ rules << :request_access if group.request_access_enabled && group.users.exclude?(user)
end
rules.flatten
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index c6f77cc055f..8c19d9dc9c8 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -4,12 +4,20 @@ class ApplicationSetting < ActiveRecord::Base
add_authentication_token_field :health_check_access_token
CACHE_KEY = 'application_setting.last'
+ DOMAIN_LIST_SEPARATOR = %r{\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
+ | # or
+ \s # any whitespace character
+ | # or
+ [\r\n] # any number of newline characters
+ }x
serialize :restricted_visibility_levels
serialize :import_sources
serialize :disabled_oauth_sign_in_sources, Array
- serialize :restricted_signup_domains, Array
- attr_accessor :restricted_signup_domains_raw
+ serialize :domain_whitelist, Array
+ serialize :domain_blacklist, Array
+
+ attr_accessor :domain_whitelist_raw, :domain_blacklist_raw
validates :session_expire_delay,
presence: true,
@@ -62,6 +70,10 @@ class ApplicationSetting < ActiveRecord::Base
validates :enabled_git_access_protocol,
inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true }
+ validates :domain_blacklist,
+ presence: { message: 'Domain blacklist cannot be empty if Blacklist is enabled.' },
+ if: :domain_blacklist_enabled?
+
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
@@ -129,7 +141,7 @@ class ApplicationSetting < ActiveRecord::Base
session_expire_delay: Settings.gitlab['session_expire_delay'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
- restricted_signup_domains: Settings.gitlab['restricted_signup_domains'],
+ domain_whitelist: Settings.gitlab['domain_whitelist'],
import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project],
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
max_artifacts_size: Settings.artifacts['max_size'],
@@ -150,20 +162,30 @@ class ApplicationSetting < ActiveRecord::Base
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
end
- def restricted_signup_domains_raw
- self.restricted_signup_domains.join("\n") unless self.restricted_signup_domains.nil?
+ def domain_whitelist_raw
+ self.domain_whitelist.join("\n") unless self.domain_whitelist.nil?
+ end
+
+ def domain_blacklist_raw
+ self.domain_blacklist.join("\n") unless self.domain_blacklist.nil?
+ end
+
+ def domain_whitelist_raw=(values)
+ self.domain_whitelist = []
+ self.domain_whitelist = values.split(DOMAIN_LIST_SEPARATOR)
+ self.domain_whitelist.reject! { |d| d.empty? }
+ self.domain_whitelist
+ end
+
+ def domain_blacklist_raw=(values)
+ self.domain_blacklist = []
+ self.domain_blacklist = values.split(DOMAIN_LIST_SEPARATOR)
+ self.domain_blacklist.reject! { |d| d.empty? }
+ self.domain_blacklist
end
- def restricted_signup_domains_raw=(values)
- self.restricted_signup_domains = []
- self.restricted_signup_domains = values.split(
- /\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
- | # or
- \s # any whitespace character
- | # or
- [\r\n] # any number of newline characters
- /x)
- self.restricted_signup_domains.reject! { |d| d.empty? }
+ def domain_blacklist_file=(file)
+ self.domain_blacklist_raw = file.read
end
def runners_registration_token
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index e02351ce339..cbfa14e81f1 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -12,7 +12,7 @@ module Ci
scope :unstarted, ->() { where(runner_id: nil) }
scope :ignore_failures, ->() { where(allow_failure: false) }
- scope :with_artifacts, ->() { where.not(artifacts_file: nil) }
+ scope :with_artifacts, ->() { where.not(artifacts_file: [nil, '']) }
scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) }
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
scope :manual_actions, ->() { where(when: :manual) }
@@ -97,7 +97,7 @@ module Ci
end
def other_actions
- pipeline.manual_actions.where.not(id: self)
+ pipeline.manual_actions.where.not(name: name)
end
def playable?
@@ -145,7 +145,15 @@ module Ci
end
def variables
- predefined_variables + yaml_variables + project_variables + trigger_variables
+ variables = predefined_variables
+ variables += project.predefined_variables
+ variables += pipeline.predefined_variables
+ variables += runner.predefined_variables if runner
+ variables += project.container_registry_variables
+ variables += yaml_variables
+ variables += project.secret_variables
+ variables += trigger_request.user_variables if trigger_request
+ variables
end
def merge_request
@@ -430,28 +438,23 @@ module Ci
self.update(erased_by: user, erased_at: Time.now, artifacts_expire_at: nil)
end
- def project_variables
- project.variables.map do |variable|
- { key: variable.key, value: variable.value, public: false }
- end
- end
-
- def trigger_variables
- if trigger_request && trigger_request.variables
- trigger_request.variables.map do |key, value|
- { key: key, value: value, public: false }
- end
- else
- []
- end
- end
-
def predefined_variables
- variables = []
- variables << { key: :CI_BUILD_TAG, value: ref, public: true } if tag?
- variables << { key: :CI_BUILD_NAME, value: name, public: true }
- variables << { key: :CI_BUILD_STAGE, value: stage, public: true }
- variables << { key: :CI_BUILD_TRIGGERED, value: 'true', public: true } if trigger_request
+ variables = [
+ { key: 'CI', value: 'true', public: true },
+ { key: 'GITLAB_CI', value: 'true', public: true },
+ { key: 'CI_BUILD_ID', value: id.to_s, public: true },
+ { key: 'CI_BUILD_TOKEN', value: token, public: false },
+ { key: 'CI_BUILD_REF', value: sha, public: true },
+ { key: 'CI_BUILD_BEFORE_SHA', value: before_sha, public: true },
+ { key: 'CI_BUILD_REF_NAME', value: ref, public: true },
+ { key: 'CI_BUILD_NAME', value: name, public: true },
+ { key: 'CI_BUILD_STAGE', value: stage, public: true },
+ { key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
+ { key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
+ { key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true }
+ ]
+ variables << { key: 'CI_BUILD_TAG', value: ref, public: true } if tag?
+ variables << { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true } if trigger_request
variables
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index aca8607f4e8..bce6a992af6 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -20,6 +20,11 @@ module Ci
after_touch :update_state
after_save :keep_around_commits
+ # ref can't be HEAD or SHA, can only be branch/tag name
+ scope :latest_successful_for, ->(ref = default_branch) do
+ where(ref: ref).success.order(id: :desc).limit(1)
+ end
+
def self.truncate_sha(sha)
sha[0...8]
end
@@ -146,6 +151,10 @@ module Ci
end
end
+ def has_warnings?
+ builds.latest.ignored.any?
+ end
+
def config_processor
return nil unless ci_yaml_file
return @config_processor if defined?(@config_processor)
@@ -198,6 +207,12 @@ module Ci
Note.for_commit_id(sha)
end
+ def predefined_variables
+ [
+ { key: 'CI_PIPELINE_ID', value: id.to_s, public: true }
+ ]
+ end
+
private
def build_builds_for_stages(stages, user, status, trigger_request)
@@ -206,8 +221,9 @@ module Ci
# build builds only for the first stage that has builds available.
#
stages.any? do |stage|
- CreateBuildsService.new(self)
- .execute(stage, user, status, trigger_request).present?
+ CreateBuildsService.new(self).
+ execute(stage, user, status, trigger_request).
+ any?(&:active?)
end
end
@@ -226,7 +242,7 @@ module Ci
def keep_around_commits
return unless project
-
+
project.repository.keep_around(self.sha)
project.repository.keep_around(self.before_sha)
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index b64ec79ec2b..49f05f881a2 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -114,6 +114,14 @@ module Ci
tag_list.any?
end
+ def predefined_variables
+ [
+ { key: 'CI_RUNNER_ID', value: id.to_s, public: true },
+ { key: 'CI_RUNNER_DESCRIPTION', value: description, public: true },
+ { key: 'CI_RUNNER_TAGS', value: tag_list.to_s, public: true }
+ ]
+ end
+
private
def tag_constraints
diff --git a/app/models/ci/trigger_request.rb b/app/models/ci/trigger_request.rb
index fcf2b6dc5e2..fc674871743 100644
--- a/app/models/ci/trigger_request.rb
+++ b/app/models/ci/trigger_request.rb
@@ -7,5 +7,13 @@ module Ci
has_many :builds, class_name: 'Ci::Build'
serialize :variables
+
+ def user_variables
+ return [] unless variables
+
+ variables.map do |key, value|
+ { key: key, value: value, public: false }
+ end
+ end
end
end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 535db26240a..2d185c28809 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -16,7 +16,11 @@ class CommitStatus < ActiveRecord::Base
alias_attribute :author, :user
- scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :commit_id)) }
+ scope :latest, -> do
+ max_id = unscope(:select).select("max(#{quoted_table_name}.id)")
+
+ where(id: max_id.group(:name, :commit_id))
+ end
scope :retried, -> { where.not(id: latest) }
scope :ordered, -> { order(:name) }
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
diff --git a/app/models/concerns/note_on_diff.rb b/app/models/concerns/note_on_diff.rb
index 2785fbb21c9..4be6a2f621b 100644
--- a/app/models/concerns/note_on_diff.rb
+++ b/app/models/concerns/note_on_diff.rb
@@ -1,12 +1,6 @@
module NoteOnDiff
extend ActiveSupport::Concern
- NUMBER_OF_TRUNCATED_DIFF_LINES = 16
-
- included do
- delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true
- end
-
def diff_note?
true
end
@@ -30,23 +24,4 @@ module NoteOnDiff
def can_be_award_emoji?
false
end
-
- # Returns an array of at most 16 highlighted lines above a diff note
- def truncated_diff_lines
- prev_lines = []
-
- highlighted_diff_lines.each do |line|
- if line.meta?
- prev_lines.clear
- else
- prev_lines << line
-
- break if for_line?(line)
-
- prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES
- end
- end
-
- prev_lines
- end
end
diff --git a/app/models/discussion.rb b/app/models/discussion.rb
new file mode 100644
index 00000000000..74facfd1c9c
--- /dev/null
+++ b/app/models/discussion.rb
@@ -0,0 +1,91 @@
+class Discussion
+ NUMBER_OF_TRUNCATED_DIFF_LINES = 16
+
+ attr_reader :first_note, :notes
+
+ delegate :created_at,
+ :project,
+ :author,
+
+ :noteable,
+ :for_commit?,
+ :for_merge_request?,
+
+ :line_code,
+ :diff_file,
+ :for_line?,
+ :active?,
+
+ to: :first_note
+
+ delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true
+
+ def self.for_notes(notes)
+ notes.group_by(&:discussion_id).values.map { |notes| new(notes) }
+ end
+
+ def self.for_diff_notes(notes)
+ notes.group_by(&:line_code).values.map { |notes| new(notes) }
+ end
+
+ def initialize(notes)
+ @first_note = notes.first
+ @notes = notes
+ end
+
+ def id
+ first_note.discussion_id
+ end
+
+ def diff_discussion?
+ first_note.diff_note?
+ end
+
+ def legacy_diff_discussion?
+ notes.any?(&:legacy_diff_note?)
+ end
+
+ def for_target?(target)
+ self.noteable == target && !diff_discussion?
+ end
+
+ def expanded?
+ !diff_discussion? || active?
+ end
+
+ def reply_attributes
+ data = {
+ noteable_type: first_note.noteable_type,
+ noteable_id: first_note.noteable_id,
+ commit_id: first_note.commit_id,
+ discussion_id: self.id,
+ }
+
+ if diff_discussion?
+ data[:note_type] = first_note.type
+
+ data.merge!(first_note.diff_attributes)
+ end
+
+ data
+ end
+
+ # Returns an array of at most 16 highlighted lines above a diff note
+ def truncated_diff_lines
+ prev_lines = []
+
+ highlighted_diff_lines.each do |line|
+ if line.meta?
+ prev_lines.clear
+ else
+ prev_lines << line
+
+ break if for_line?(line)
+
+ prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES
+ end
+ end
+
+ prev_lines
+ end
+end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 60abd47409e..60af8c15340 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -52,10 +52,50 @@ class Issue < ActiveRecord::Base
attributes
end
+ class << self
+ private
+
+ # Returns the project that the current scope belongs to if any, nil otherwise.
+ #
+ # Examples:
+ # - my_project.issues.without_due_date.owner_project => my_project
+ # - Issue.all.owner_project => nil
+ def owner_project
+ # No owner if we're not being called from an association
+ return unless all.respond_to?(:proxy_association)
+
+ owner = all.proxy_association.owner
+
+ # Check if the association is or belongs to a project
+ if owner.is_a?(Project)
+ owner
+ else
+ begin
+ owner.association(:project).target
+ rescue ActiveRecord::AssociationNotFoundError
+ nil
+ end
+ end
+ end
+ end
+
def self.visible_to_user(user)
return where('issues.confidential IS NULL OR issues.confidential IS FALSE') if user.blank?
return all if user.admin?
+ # Check if we are scoped to a specific project's issues
+ if owner_project
+ if owner_project.authorized_for_user?(user, Gitlab::Access::REPORTER)
+ # If the project is authorized for the user, they can see all issues in the project
+ return all
+ else
+ # else only non confidential and authored/assigned to them
+ return where('issues.confidential IS NULL OR issues.confidential IS FALSE
+ OR issues.author_id = :user_id OR issues.assignee_id = :user_id',
+ user_id: user.id)
+ end
+ end
+
where('
issues.confidential IS NULL
OR issues.confidential IS FALSE
diff --git a/app/models/note.rb b/app/models/note.rb
index 0ce10c77de9..9b0a7211b4e 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -82,11 +82,12 @@ class Note < ActiveRecord::Base
end
def discussions
- all.group_by(&:discussion_id).values
+ Discussion.for_notes(all)
end
- def grouped_diff_notes
- diff_notes.select(&:active?).sort_by(&:created_at).group_by(&:line_code)
+ def grouped_diff_discussions
+ notes = diff_notes.fresh.select(&:active?)
+ Discussion.for_diff_notes(notes).map { |d| [d.line_code, d] }.to_h
end
# Searches for notes matching the given query.
diff --git a/app/models/project.rb b/app/models/project.rb
index a805f5d97bc..5452d9f768f 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -429,6 +429,17 @@ class Project < ActiveRecord::Base
repository.commit(ref)
end
+ # ref can't be HEAD, can only be branch/tag name or SHA
+ def latest_successful_builds_for(ref = default_branch)
+ latest_pipeline = pipelines.latest_successful_for(ref).first
+
+ if latest_pipeline
+ latest_pipeline.builds.latest.with_artifacts
+ else
+ builds.none
+ end
+ end
+
def merge_base_commit(first_commit_id, second_commit_id)
sha = repository.merge_base(first_commit_id, second_commit_id)
repository.commit(sha) if sha
@@ -650,6 +661,22 @@ class Project < ActiveRecord::Base
update_column(:has_external_issue_tracker, services.external_issue_trackers.any?)
end
+ def external_wiki
+ if has_external_wiki.nil?
+ cache_has_external_wiki # Populate
+ end
+
+ if has_external_wiki
+ @external_wiki ||= services.external_wikis.first
+ else
+ nil
+ end
+ end
+
+ def cache_has_external_wiki
+ update_column(:has_external_wiki, services.external_wikis.any?)
+ end
+
def build_missing_services
services_templates = Service.where(template: true)
@@ -1164,4 +1191,74 @@ class Project < ActiveRecord::Base
def ensure_dir_exist
gitlab_shell.add_namespace(repository_storage_path, namespace.path)
end
+
+ def predefined_variables
+ [
+ { key: 'CI_PROJECT_ID', value: id.to_s, public: true },
+ { key: 'CI_PROJECT_NAME', value: path, public: true },
+ { key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true },
+ { key: 'CI_PROJECT_NAMESPACE', value: namespace.path, public: true },
+ { key: 'CI_PROJECT_URL', value: web_url, public: true }
+ ]
+ end
+
+ def container_registry_variables
+ return [] unless Gitlab.config.registry.enabled
+
+ variables = [
+ { key: 'CI_REGISTRY', value: Gitlab.config.registry.host_port, public: true }
+ ]
+
+ if container_registry_enabled?
+ variables << { key: 'CI_REGISTRY_IMAGE', value: container_registry_repository_url, public: true }
+ end
+
+ variables
+ end
+
+ def secret_variables
+ variables.map do |variable|
+ { key: variable.key, value: variable.value, public: false }
+ end
+ end
+
+ # Checks if `user` is authorized for this project, with at least the
+ # `min_access_level` (if given).
+ #
+ # If you change the logic of this method, please also update `User#authorized_projects`
+ def authorized_for_user?(user, min_access_level = nil)
+ return false unless user
+
+ return true if personal? && namespace_id == user.namespace_id
+
+ authorized_for_user_by_group?(user, min_access_level) ||
+ authorized_for_user_by_members?(user, min_access_level) ||
+ authorized_for_user_by_shared_projects?(user, min_access_level)
+ end
+
+ private
+
+ def authorized_for_user_by_group?(user, min_access_level)
+ member = user.group_members.find_by(source_id: group)
+
+ member && (!min_access_level || member.access_level >= min_access_level)
+ end
+
+ def authorized_for_user_by_members?(user, min_access_level)
+ member = members.find_by(user_id: user)
+
+ member && (!min_access_level || member.access_level >= min_access_level)
+ end
+
+ def authorized_for_user_by_shared_projects?(user, min_access_level)
+ shared_projects = user.group_members.joins(group: :shared_projects).
+ where(project_group_links: { project_id: self })
+
+ if min_access_level
+ members_scope = { access_level: Gitlab::Access.values.select { |access| access >= min_access_level } }
+ shared_projects = shared_projects.where(members: members_scope)
+ end
+
+ shared_projects.any?
+ end
end
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index cf9e4d5a8b6..abbc780dc1a 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -4,6 +4,9 @@ class SlackService < Service
validates :webhook, presence: true, url: true, if: :activated?
def initialize_properties
+ # Custom serialized properties initialization
+ self.supported_events.each { |event| self.class.prop_accessor(event_channel_name(event)) }
+
if properties.nil?
self.properties = {}
self.notify_only_broken_builds = true
@@ -29,13 +32,15 @@ class SlackService < Service
end
def fields
- [
- { type: 'text', name: 'webhook',
- placeholder: 'https://hooks.slack.com/services/...' },
- { type: 'text', name: 'username', placeholder: 'username' },
- { type: 'text', name: 'channel', placeholder: '#channel' },
- { type: 'checkbox', name: 'notify_only_broken_builds' },
- ]
+ default_fields =
+ [
+ { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' },
+ { type: 'text', name: 'username', placeholder: 'username' },
+ { type: 'text', name: 'channel', placeholder: "#general" },
+ { type: 'checkbox', name: 'notify_only_broken_builds' },
+ ]
+
+ default_fields + build_event_channels
end
def supported_events
@@ -74,7 +79,10 @@ class SlackService < Service
end
opt = {}
- opt[:channel] = channel if channel
+
+ event_channel = get_channel_field(object_kind) || channel
+
+ opt[:channel] = event_channel if event_channel
opt[:username] = username if username
if message
@@ -83,8 +91,35 @@ class SlackService < Service
end
end
+ def event_channel_names
+ supported_events.map { |event| event_channel_name(event) }
+ end
+
+ def event_field(event)
+ fields.find { |field| field[:name] == event_channel_name(event) }
+ end
+
+ def global_fields
+ fields.reject { |field| field[:name].end_with?('channel') }
+ end
+
private
+ def get_channel_field(event)
+ field_name = event_channel_name(event)
+ self.public_send(field_name)
+ end
+
+ def build_event_channels
+ supported_events.reduce([]) do |channels, event|
+ channels << { type: 'text', name: event_channel_name(event), placeholder: "#general" }
+ end
+ end
+
+ def event_channel_name(event)
+ "#{event}_channel"
+ end
+
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 0b700930641..9d312a53790 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -173,7 +173,7 @@ class ProjectTeam
invited_members = []
if project.invited_groups.any? && project.allowed_to_share_with_group?
- project.project_group_links.each do |group_link|
+ project.project_group_links.includes(group: [:group_members]).each do |group_link|
invited_group = group_link.group
im = invited_group.members
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 61f6d52dfd3..d94bb0711fb 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -11,16 +11,6 @@ class Repository
attr_accessor :path_with_namespace, :project
- def self.clean_old_archives
- Gitlab::Metrics.measure(:clean_old_archives) do
- repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
-
- return unless File.directory?(repository_downloads_path)
-
- Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
- end
- end
-
def initialize(path_with_namespace, project)
@path_with_namespace = path_with_namespace
@project = project
@@ -80,7 +70,12 @@ class Repository
def commit(ref = 'HEAD')
return nil unless exists?
- commit = Gitlab::Git::Commit.find(raw_repository, ref)
+ commit =
+ if ref.is_a?(Gitlab::Git::Commit)
+ ref
+ else
+ Gitlab::Git::Commit.find(raw_repository, ref)
+ end
commit = ::Commit.new(commit, @project) if commit
commit
rescue Rugged::OdbError
@@ -216,11 +211,20 @@ class Repository
return if kept_around?(sha)
- rugged.references.create(keep_around_ref_name(sha), sha)
+ # This will still fail if the file is corrupted (e.g. 0 bytes)
+ begin
+ rugged.references.create(keep_around_ref_name(sha), sha, force: true)
+ rescue Rugged::ReferenceError => ex
+ Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
+ end
end
def kept_around?(sha)
- ref_exists?(keep_around_ref_name(sha))
+ begin
+ ref_exists?(keep_around_ref_name(sha))
+ rescue Rugged::ReferenceError
+ false
+ end
end
def tag_names
@@ -257,10 +261,10 @@ class Repository
# Rugged seems to throw a `ReferenceError` when given branch_names rather
# than SHA-1 hashes
number_commits_behind = raw_repository.
- count_commits_between(branch.target, root_ref_hash)
+ count_commits_between(branch.target.sha, root_ref_hash)
number_commits_ahead = raw_repository.
- count_commits_between(root_ref_hash, branch.target)
+ count_commits_between(root_ref_hash, branch.target.sha)
{ behind: number_commits_behind, ahead: number_commits_ahead }
end
@@ -392,6 +396,11 @@ class Repository
expire_cache if exists?
+ # expire cache that don't depend on repository data (when expiring)
+ expire_tags_cache
+ expire_tag_count_cache
+ expire_branches_cache
+ expire_branch_count_cache
expire_root_ref_cache
expire_emptiness_caches
expire_exists_cache
@@ -681,9 +690,7 @@ class Repository
end
def local_branches
- @local_branches ||= rugged.branches.each(:local).map do |branch|
- Gitlab::Git::Branch.new(branch.name, branch.target)
- end
+ @local_branches ||= raw_repository.local_branches
end
alias_method :branches, :local_branches
@@ -824,7 +831,7 @@ class Repository
end
def revert(user, commit, base_branch, revert_tree_id = nil)
- source_sha = find_branch(base_branch).target
+ source_sha = find_branch(base_branch).target.sha
revert_tree_id ||= check_revert_content(commit, base_branch)
return false unless revert_tree_id
@@ -841,7 +848,7 @@ class Repository
end
def cherry_pick(user, commit, base_branch, cherry_pick_tree_id = nil)
- source_sha = find_branch(base_branch).target
+ source_sha = find_branch(base_branch).target.sha
cherry_pick_tree_id ||= check_cherry_pick_content(commit, base_branch)
return false unless cherry_pick_tree_id
@@ -862,7 +869,7 @@ class Repository
end
def check_revert_content(commit, base_branch)
- source_sha = find_branch(base_branch).target
+ source_sha = find_branch(base_branch).target.sha
args = [commit.id, source_sha]
args << { mainline: 1 } if commit.merge_commit?
@@ -876,7 +883,7 @@ class Repository
end
def check_cherry_pick_content(commit, base_branch)
- source_sha = find_branch(base_branch).target
+ source_sha = find_branch(base_branch).target.sha
args = [commit.id, source_sha]
args << 1 if commit.merge_commit?
@@ -1041,7 +1048,7 @@ class Repository
end
def tags_sorted_by_committed_date
- tags.sort_by { |tag| commit(tag.target).committed_date }
+ tags.sort_by { |tag| tag.target.committed_date }
end
def keep_around_ref_name(sha)
diff --git a/app/models/service.rb b/app/models/service.rb
index 5432f8c7ab4..40cd9b861f0 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -17,6 +17,7 @@ class Service < ActiveRecord::Base
after_commit :reset_updated_properties
after_commit :cache_project_has_external_issue_tracker
+ after_commit :cache_project_has_external_wiki
belongs_to :project, inverse_of: :services
has_one :service_hook
@@ -25,6 +26,7 @@ class Service < ActiveRecord::Base
scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) }
scope :issue_trackers, -> { where(category: 'issue_tracker') }
+ scope :external_wikis, -> { where(type: 'ExternalWikiService').active }
scope :active, -> { where(active: true) }
scope :without_defaults, -> { where(default: false) }
@@ -80,6 +82,18 @@ class Service < ActiveRecord::Base
Gitlab::PushDataBuilder.build_sample(project, user)
end
+ def event_channel_names
+ []
+ end
+
+ def event_field(event)
+ nil
+ end
+
+ def global_fields
+ fields
+ end
+
def supported_events
%w(push tag_push issue merge_request wiki_page)
end
@@ -212,4 +226,10 @@ class Service < ActiveRecord::Base
project.cache_has_external_issue_tracker
end
end
+
+ def cache_project_has_external_wiki
+ if project && !project.destroyed?
+ project.cache_has_external_wiki
+ end
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 3d0a033785c..db747434959 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -111,7 +111,7 @@ class User < ActiveRecord::Base
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
before_validation :generate_password, on: :create
- before_validation :restricted_signup_domains, on: :create
+ before_validation :signup_domain_valid?, on: :create
before_validation :sanitize_attrs
before_validation :set_notification_email, if: ->(user) { user.email_changed? }
before_validation :set_public_email, if: ->(user) { user.public_email_changed? }
@@ -412,6 +412,8 @@ class User < ActiveRecord::Base
end
# Returns projects user is authorized to access.
+ #
+ # If you change the logic of this method, please also update `Project#authorized_for_user`
def authorized_projects(min_access_level = nil)
Project.where("projects.id IN (#{projects_union(min_access_level).to_sql})")
end
@@ -760,29 +762,6 @@ class User < ActiveRecord::Base
Project.where(id: events)
end
- def restricted_signup_domains
- email_domains = current_application_settings.restricted_signup_domains
-
- unless email_domains.blank?
- match_found = email_domains.any? do |domain|
- escaped = Regexp.escape(domain).gsub('\*', '.*?')
- regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
- email_domain = Mail::Address.new(self.email).domain
- email_domain =~ regexp
- end
-
- unless match_found
- self.errors.add :email,
- 'is not whitelisted. ' +
- 'Email domains valid for registration are: ' +
- email_domains.join(', ')
- return false
- end
- end
-
- true
- end
-
def can_be_removed?
!solo_owned_groups.present?
end
@@ -854,7 +833,7 @@ class User < ActiveRecord::Base
groups.joins(:shared_projects).select(:project_id)]
if min_access_level
- scope = { access_level: Gitlab::Access.values.select { |access| access >= min_access_level } }
+ scope = { access_level: Gitlab::Access.all_values.select { |access| access >= min_access_level } }
relations = [relations.shift] + relations.map { |relation| relation.where(members: scope) }
end
@@ -881,4 +860,40 @@ class User < ActiveRecord::Base
self.can_create_group = false
self.projects_limit = 0
end
+
+ def signup_domain_valid?
+ valid = true
+ error = nil
+
+ if current_application_settings.domain_blacklist_enabled?
+ blocked_domains = current_application_settings.domain_blacklist
+ if domain_matches?(blocked_domains, self.email)
+ error = 'is not from an allowed domain.'
+ valid = false
+ end
+ end
+
+ allowed_domains = current_application_settings.domain_whitelist
+ unless allowed_domains.blank?
+ if domain_matches?(allowed_domains, self.email)
+ valid = true
+ else
+ error = "is not whitelisted. Email domains valid for registration are: #{allowed_domains.join(', ')}"
+ valid = false
+ end
+ end
+
+ self.errors.add(:email, error) unless valid
+
+ valid
+ end
+
+ def domain_matches?(email_domains, email)
+ signup_domain = Mail::Address.new(email).domain
+ email_domains.any? do |domain|
+ escaped = Regexp.escape(domain).gsub('\*', '.*?')
+ regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
+ signup_domain =~ regexp
+ end
+ end
end
diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb
index 332c55581a1..87f066edb6f 100644
--- a/app/services/delete_branch_service.rb
+++ b/app/services/delete_branch_service.rb
@@ -40,6 +40,6 @@ class DeleteBranchService < BaseService
def build_push_data(branch)
Gitlab::PushDataBuilder
- .build(project, current_user, branch.target, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", [])
+ .build(project, current_user, branch.target.sha, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}", [])
end
end
diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb
index 1e41fbe34b6..32e0eed6b63 100644
--- a/app/services/delete_tag_service.rb
+++ b/app/services/delete_tag_service.rb
@@ -34,6 +34,6 @@ class DeleteTagService < BaseService
def build_push_data(tag)
Gitlab::PushDataBuilder
- .build(project, current_user, tag.target, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
+ .build(project, current_user, tag.target.sha, Gitlab::Git::BLANK_SHA, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
end
end
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index 58573078048..969530c4fdc 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -26,8 +26,8 @@ class GitTagPushService < BaseService
unless Gitlab::Git.blank_ref?(params[:newrev])
tag_name = Gitlab::Git.ref_name(params[:ref])
tag = project.repository.find_tag(tag_name)
-
- if tag && tag.target == params[:newrev]
+
+ if tag && tag.object_sha == params[:newrev]
commit = project.commit(tag.target)
commits = [commit].compact
message = tag.message
diff --git a/app/services/repository_archive_clean_up_service.rb b/app/services/repository_archive_clean_up_service.rb
new file mode 100644
index 00000000000..0b56b09738d
--- /dev/null
+++ b/app/services/repository_archive_clean_up_service.rb
@@ -0,0 +1,33 @@
+class RepositoryArchiveCleanUpService
+ LAST_MODIFIED_TIME_IN_MINUTES = 120
+
+ def initialize(mmin = LAST_MODIFIED_TIME_IN_MINUTES)
+ @mmin = mmin
+ @path = Gitlab.config.gitlab.repository_downloads_path
+ end
+
+ def execute
+ Gitlab::Metrics.measure(:repository_archive_clean_up) do
+ return unless File.directory?(path)
+
+ clean_up_old_archives
+ clean_up_empty_directories
+ end
+ end
+
+ private
+
+ attr_reader :mmin, :path
+
+ def clean_up_old_archives
+ run(%W(find #{path} -not -path #{path} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -maxdepth 2 -mmin +#{mmin} -delete))
+ end
+
+ def clean_up_empty_directories
+ run(%W(find #{path} -not -path #{path} -type d -empty -name \*.git -maxdepth 1 -delete))
+ end
+
+ def run(cmd)
+ Gitlab::Popen.popen(cmd)
+ end
+end
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 1af9e9b0edb..2f5f49f7de7 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -33,16 +33,15 @@ class FileUploader < CarrierWave::Uploader::Base
end
def to_h
- filename = image? ? self.file.basename : self.file.filename
+ filename = image_or_video? ? self.file.basename : self.file.filename
escaped_filename = filename.gsub("]", "\\]")
markdown = "[#{escaped_filename}](#{self.secure_url})"
- markdown.prepend("!") if image?
+ markdown.prepend("!") if image_or_video?
{
alt: filename,
url: self.secure_url,
- is_image: image?,
markdown: markdown
}
end
diff --git a/app/uploaders/uploader_helper.rb b/app/uploaders/uploader_helper.rb
index 5ef440f3367..b10ad71d052 100644
--- a/app/uploaders/uploader_helper.rb
+++ b/app/uploaders/uploader_helper.rb
@@ -1,16 +1,37 @@
# Extra methods for uploader
module UploaderHelper
+ IMAGE_EXT = %w[png jpg jpeg gif bmp tiff]
+ # We recommend using the .mp4 format over .mov. Videos in .mov format can
+ # still be used but you really need to make sure they are served with the
+ # proper MIME type video/mp4 and not video/quicktime or your videos won't play
+ # on IE >= 9.
+ # http://archive.sublimevideo.info/20150912/docs.sublimevideo.net/troubleshooting.html
+ VIDEO_EXT = %w[mp4 m4v mov webm ogv]
+
def image?
- img_ext = %w(png jpg jpeg gif bmp tiff)
- if file.respond_to?(:extension)
- img_ext.include?(file.extension.downcase)
- else
- # Not all CarrierWave storages respond to :extension
- ext = file.path.split('.').last.downcase
- img_ext.include?(ext)
- end
- rescue
- false
+ extension_match?(IMAGE_EXT)
+ end
+
+ def video?
+ extension_match?(VIDEO_EXT)
+ end
+
+ def image_or_video?
+ image? || video?
+ end
+
+ def extension_match?(extensions)
+ return false unless file
+
+ extension =
+ if file.respond_to?(:extension)
+ file.extension
+ else
+ # Not all CarrierWave storages respond to :extension
+ File.extname(file.path).delete('.')
+ end
+
+ extensions.include?(extension.downcase)
end
def file_storage?
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 538d8176ce7..23b52d08df7 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -109,7 +109,7 @@
Newly registered users will by default be external
%fieldset
- %legend Sign-in Restrictions
+ %legend Sign-up Restrictions
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
@@ -123,6 +123,49 @@
= f.check_box :send_user_confirmation_email
Send confirmation email on sign-up
.form-group
+ = f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.text_area :domain_whitelist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
+ .help-block ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
+ .form-group
+ = f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'control-label col-sm-2'
+ .col-sm-10
+ .checkbox
+ = f.label :domain_blacklist_enabled do
+ = f.check_box :domain_blacklist_enabled
+ Enable domain blacklist for sign ups
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .radio
+ = label_tag :blacklist_type_file do
+ = radio_button_tag :blacklist_type, :file
+ .option-title
+ Upload blacklist file
+ .radio
+ = label_tag :blacklist_type_raw do
+ = radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?
+ .option-title
+ Enter blacklist manually
+ .form-group.blacklist-file
+ = f.label :domain_blacklist_file, 'Blacklist file', class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.file_field :domain_blacklist_file, class: 'form-control', accept: '.txt,.conf'
+ .help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries.
+ .form-group.blacklist-raw
+ = f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.text_area :domain_blacklist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
+ .help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
+
+ .form-group
+ = f.label :after_sign_up_text, class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.text_area :after_sign_up_text, class: 'form-control', rows: 4
+ .help-block Markdown enabled
+
+ %fieldset
+ %legend Sign-in Restrictions
+ .form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :signin_enabled do
@@ -148,11 +191,6 @@
= f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0'
.help-block Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication
.form-group
- = f.label :restricted_signup_domains, 'Restricted domains for sign-ups', class: 'control-label col-sm-2'
- .col-sm-10
- = f.text_area :restricted_signup_domains_raw, placeholder: 'domain.com', class: 'form-control'
- .help-block Only users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
- .form-group
= f.label :home_page_url, 'Home page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block'
@@ -168,11 +206,6 @@
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
- = f.label :after_sign_up_text, class: 'control-label col-sm-2'
- .col-sm-10
- = f.text_area :after_sign_up_text, class: 'form-control', rows: 4
- .help-block Markdown enabled
- .form-group
= f.label :help_page_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :help_page_text, class: 'form-control', rows: 4
@@ -352,4 +385,4 @@
.form-actions
- = f.submit 'Save', class: 'btn btn-save'
+ = f.submit 'Save', class: 'btn btn-save' \ No newline at end of file
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 0cc405401cf..5f7fdfdb011 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -9,6 +9,10 @@
= render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ = render 'shared/allow_request_access', form: f
+
- if @group.new_record?
.form-group
.col-sm-offset-2.col-sm-10
diff --git a/app/views/discussions/_diff_discussion.html.haml b/app/views/discussions/_diff_discussion.html.haml
new file mode 100644
index 00000000000..fa1ad9efa73
--- /dev/null
+++ b/app/views/discussions/_diff_discussion.html.haml
@@ -0,0 +1,6 @@
+%tr.notes_holder
+ %td.notes_line{ colspan: 2 }
+ %td.notes_content
+ %ul.notes{ data: { discussion_id: discussion.id } }
+ = render partial: "projects/notes/note", collection: discussion.notes, as: :note
+ = link_to_reply_discussion(discussion)
diff --git a/app/views/discussions/_diff_with_notes.html.haml b/app/views/discussions/_diff_with_notes.html.haml
new file mode 100644
index 00000000000..02b159ffd45
--- /dev/null
+++ b/app/views/discussions/_diff_with_notes.html.haml
@@ -0,0 +1,14 @@
+- diff_file = discussion.diff_file
+- blob = discussion.blob
+
+.diff-file.file-holder
+ .file-title
+ = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_diff_path(discussion)
+
+ .diff-content.code.js-syntax-highlight
+ %table
+ - discussion.truncated_diff_lines.each do |line|
+ = render "projects/diffs/line", line: line, diff_file: diff_file, plain: true
+
+ - if discussion.for_line?(line)
+ = render "discussions/diff_discussion", discussion: discussion
diff --git a/app/views/discussions/_discussion.html.haml b/app/views/discussions/_discussion.html.haml
new file mode 100644
index 00000000000..49702e048aa
--- /dev/null
+++ b/app/views/discussions/_discussion.html.haml
@@ -0,0 +1,45 @@
+- expanded = discussion.expanded?
+%li.note.note-discussion.timeline-entry
+ .timeline-entry-inner
+ .timeline-icon
+ = link_to user_path(discussion.author) do
+ = image_tag avatar_icon(discussion.author), class: "avatar s40"
+ .timeline-content
+ .discussion.js-toggle-container{ class: discussion.id }
+ .discussion-header
+ = link_to_member(@project, discussion.author, avatar: false)
+
+ .inline.discussion-headline-light
+ = discussion.author.to_reference
+ started a discussion on
+
+ - if discussion.for_commit?
+ - commit = discussion.noteable
+ - if commit
+ commit
+ = link_to commit.short_id, namespace_project_commit_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code), class: 'monospace'
+ - else
+ a deleted commit
+ - else
+ - if discussion.active?
+ = link_to diffs_namespace_project_merge_request_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code) do
+ the diff
+ - else
+ an outdated diff
+
+ = time_ago_with_tooltip(discussion.created_at, placement: "bottom", html_class: "note-created-ago")
+
+ .discussion-actions
+ = link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do
+ - if expanded
+ = icon("chevron-up")
+ - else
+ = icon("chevron-down")
+
+ Toggle discussion
+
+ .discussion-body.js-toggle-content{ class: ("hide" unless expanded) }
+ - if discussion.diff_discussion? && discussion.diff_file
+ = render "discussions/diff_with_notes", discussion: discussion
+ - else
+ = render "discussions/notes", discussion: discussion
diff --git a/app/views/discussions/_notes.html.haml b/app/views/discussions/_notes.html.haml
new file mode 100644
index 00000000000..a2642b839f6
--- /dev/null
+++ b/app/views/discussions/_notes.html.haml
@@ -0,0 +1,5 @@
+.panel.panel-default
+ .notes{ data: { discussion_id: discussion.id } }
+ %ul.notes.timeline
+ = render partial: "projects/notes/note", collection: discussion.notes, as: :note
+ = link_to_reply_discussion(discussion)
diff --git a/app/views/discussions/_parallel_diff_discussion.html.haml b/app/views/discussions/_parallel_diff_discussion.html.haml
new file mode 100644
index 00000000000..a798c438ea0
--- /dev/null
+++ b/app/views/discussions/_parallel_diff_discussion.html.haml
@@ -0,0 +1,22 @@
+%tr.notes_holder
+ - if discussion_left
+ %td.notes_line.old
+ %td.notes_content.parallel.old
+ %ul.notes{ data: { discussion_id: discussion_left.id } }
+ = render partial: "projects/notes/note", collection: discussion_left.notes, as: :note
+
+ = link_to_reply_discussion(discussion_left, 'old')
+ - else
+ %td.notes_line.old= ""
+ %td.notes_content.parallel.old= ""
+
+ - if discussion_right
+ %td.notes_line.new
+ %td.notes_content.parallel.new
+ %ul.notes{ data: { discussion_id: discussion_right.id } }
+ = render partial: "projects/notes/note", collection: discussion_right.notes, as: :note
+
+ = link_to_reply_discussion(discussion_right, 'new')
+ - else
+ %td.notes_line.new= ""
+ %td.notes_content.parallel.new= ""
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index e4629bae0e6..5c318cd3b8b 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -4,11 +4,7 @@
#{time_ago_with_tooltip(event.created_at)}
= cache [event, current_application_settings, "v2.2"] do
- - if event.author
- = link_to user_path(event.author) do
- = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
- - else
- = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
+ = author_avatar(event, size: 40)
- if event.created_project?
= render "events/event/created_project", event: event
diff --git a/app/views/events/_event_scope.html.haml b/app/views/events/_event_scope.html.haml
new file mode 100644
index 00000000000..8f7da7d8c4f
--- /dev/null
+++ b/app/views/events/_event_scope.html.haml
@@ -0,0 +1,7 @@
+%span.event-scope
+ = event_preposition(event)
+ - if event.project
+ = link_to_project event.project
+ - else
+ = event.project_name
+
diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml
index 2e2403347c1..bba6e0d2c20 100644
--- a/app/views/events/event/_common.html.haml
+++ b/app/views/events/event/_common.html.haml
@@ -1,6 +1,6 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label{class: event.action_name}
+ %span{class: event.action_name}
- if event.target
= event.action_name
%strong
@@ -10,12 +10,7 @@
- else
= event_action_name(event)
- = event_preposition(event)
-
- - if event.project
- = link_to_project event.project
- - else
- = event.project_name
+ = render "events/event_scope", event: event
- if event.target.respond_to?(:title)
.event-body
diff --git a/app/views/events/event/_created_project.html.haml b/app/views/events/event/_created_project.html.haml
index 5a2a469ba62..aba64dd17d0 100644
--- a/app/views/events/event/_created_project.html.haml
+++ b/app/views/events/event/_created_project.html.haml
@@ -1,6 +1,6 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label{class: event.action_name}
+ %span{class: event.action_name}
= event_action_name(event)
- if event.project
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index 830fec0b4ab..f08c96df309 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -1,14 +1,9 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label
- = event.action_name
- = event_note_title_html(event)
- at
+ = event.action_name
+ = event_note_title_html(event)
- - if event.project
- = link_to_project event.project
- - else
- = event.project_name
+ = render "events/event_scope", event: event
.event-body
.event-note
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index ea54ef226ec..44fff49d99c 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -2,14 +2,14 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label.pushed #{event.action_name} #{event.ref_type}
+ %span.pushed #{event.action_name} #{event.ref_type}
- if event.rm_ref?
%strong= event.ref_name
- else
%strong
= link_to event.ref_name, namespace_project_commits_path(project.namespace, project, event.ref_name), title: h(event.target_title)
- at
- = link_to_project project
+
+ = render "events/event_scope", event: event
- if event.push_with_commits?
.event-body
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 92cd4c553d0..decb89b2fd6 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -22,6 +22,10 @@
= render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
.form-group
+ .col-sm-offset-2.col-sm-10
+ = render 'shared/allow_request_access', form: f
+
+ .form-group
%hr
= f.label :share_with_group_lock, class: 'control-label' do
Share with group lock
diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml
index 12e7ed0e792..351100f3523 100644
--- a/app/views/layouts/_init_auto_complete.html.haml
+++ b/app/views/layouts/_init_auto_complete.html.haml
@@ -1,7 +1,7 @@
- project = @target_project || @project
+- noteable_class = @noteable.class if @noteable.present?
-- if @noteable
- :javascript
- GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: @noteable.class, type_id: params[:id])}"
- GitLab.GfmAutoComplete.cachedData = undefined;
- GitLab.GfmAutoComplete.setup();
+:javascript
+ GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: noteable_class, type_id: params[:id])}"
+ GitLab.GfmAutoComplete.cachedData = undefined;
+ GitLab.GfmAutoComplete.setup();
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 21668698814..3a14751ea8e 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -30,7 +30,7 @@
%span
Merge Requests
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count)
- = nav_link(controller: :snippets) do
+ = nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, title: 'Snippets' do
%span
Snippets
diff --git a/app/views/layouts/nav/_explore.html.haml b/app/views/layouts/nav/_explore.html.haml
index 3b40006a0cc..e5bda7b3a6f 100644
--- a/app/views/layouts/nav/_explore.html.haml
+++ b/app/views/layouts/nav/_explore.html.haml
@@ -1,21 +1,17 @@
%ul.nav.nav-sidebar
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects' do
- = icon('bookmark fw')
%span
Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups' do
- = icon('group fw')
%span
Groups
= nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets' do
- = icon('clipboard fw')
%span
Snippets
= nav_link(controller: :help) do
= link_to help_path, title: 'Help' do
- = icon('question-circle fw')
%span
Help
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index 51a54b4f262..52a5bdc1a1b 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -39,7 +39,7 @@
= link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
%span
Triggers
- = nav_link(controller: :badges) do
- = link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do
+ = nav_link(controller: :pipelines_settings) do
+ = link_to namespace_project_pipelines_settings_path(@project.namespace, @project), title: 'CI/CD Pipelines' do
%span
- Badges
+ CI/CD Pipelines
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 2049b204956..d03d5e2ca6a 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -6,7 +6,7 @@
- content_for :scripts_body_top do
- project = @target_project || @project
- if @project_wiki && @page
- - markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, params[:id])
+ - markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, @page.title)
- else
- markdown_preview_path = markdown_preview_namespace_project_path(project.namespace, project)
- if current_user
diff --git a/app/views/profiles/_head.html.haml b/app/views/profiles/_head.html.haml
index 003884a5bd9..943ebdaeffe 100644
--- a/app/views/profiles/_head.html.haml
+++ b/app/views/profiles/_head.html.haml
@@ -1,3 +1,3 @@
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/cropper.js')
- = page_specific_javascript_tag('profile/application.js')
+ = page_specific_javascript_tag('profile/profile_bundle.js')
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index 48b0dd6b121..ac50ce83f6a 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -5,7 +5,8 @@
%i.fa.fa-rss
= render 'shared/event_filter'
-.content_list{:"data-href" => activity_project_path(@project)}
+
+.content_list.project-activity{:"data-href" => activity_project_path(@project)}
= spinner
:javascript
diff --git a/app/views/projects/_builds_settings.html.haml b/app/views/projects/_builds_settings.html.haml
deleted file mode 100644
index fff30f11d82..00000000000
--- a/app/views/projects/_builds_settings.html.haml
+++ /dev/null
@@ -1,65 +0,0 @@
-%fieldset.builds-feature
- %h5.prepend-top-0
- Builds
- - unless @repository.gitlab_ci_yml
- .form-group
- %p Builds need to be configured before you can begin using Continuous Integration.
- = link_to 'Get started with Builds', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
- .form-group
- %p Get recent application code using the following command:
- .radio
- = f.label :build_allow_git_fetch_false do
- = f.radio_button :build_allow_git_fetch, 'false'
- %strong git clone
- %br
- %span.descr Slower but makes sure you have a clean dir before every build
- .radio
- = f.label :build_allow_git_fetch_true do
- = f.radio_button :build_allow_git_fetch, 'true'
- %strong git fetch
- %br
- %span.descr Faster
-
- .form-group
- = f.label :build_timeout_in_minutes, 'Timeout', class: 'label-light'
- = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
- %p.help-block per build in minutes
- .form-group
- = f.label :build_coverage_regex, "Test coverage parsing", class: 'label-light'
- .input-group
- %span.input-group-addon /
- = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
- %span.input-group-addon /
- %p.help-block
- We will use this regular expression to find test coverage output in build trace.
- Leave blank if you want to disable this feature
- .bs-callout.bs-callout-info
- %p Below are examples of regex for existing tools:
- %ul
- %li
- Simplecov (Ruby) -
- %code \(\d+.\d+\%\) covered
- %li
- pytest-cov (Python) -
- %code \d+\%\s*$
- %li
- phpunit --coverage-text --colors=never (PHP) -
- %code ^\s*Lines:\s*\d+.\d+\%
- %li
- gcovr (C/C++) -
- %code ^TOTAL.*\s+(\d+\%)$
- %li
- tap --coverage-report=text-summary (Node.js) -
- %code ^Statements\s*:\s*([^%]+)
-
- .form-group
- .checkbox
- = f.label :public_builds do
- = f.check_box :public_builds
- %strong Public builds
- .help-block Allow everyone to access builds for Public and Internal projects
-
- .form-group.append-bottom-0
- = f.label :runners_token, "Runners token", class: 'label-light'
- = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
- %p.help-block The secure token used to checkout project.
diff --git a/app/views/projects/badges/index.html.haml b/app/views/projects/badges/index.html.haml
deleted file mode 100644
index ac80951dd4f..00000000000
--- a/app/views/projects/badges/index.html.haml
+++ /dev/null
@@ -1,23 +0,0 @@
-- page_title 'Badges'
-- badges_path = namespace_project_badges_path(@project.namespace, @project)
-
-.prepend-top-10
- .panel.panel-default
- .panel-heading
- %b Builds badge &middot;
- = @build_badge.to_html
- .pull-right
- = render 'shared/ref_switcher', destination: 'badges', align_right: true
- .panel-body
- .row
- .col-md-2.text-center
- Markdown
- .col-md-10.code.js-syntax-highlight
- = highlight('.md', @build_badge.to_markdown)
- .row
- %hr
- .row
- .col-md-2.text-center
- HTML
- .col-md-10.code.js-syntax-highlight
- = highlight('.html', @build_badge.to_html)
diff --git a/app/views/projects/branches/_commit.html.haml b/app/views/projects/branches/_commit.html.haml
index 9fe65cbb104..d54c76ff9c8 100644
--- a/app/views/projects/branches/_commit.html.haml
+++ b/app/views/projects/branches/_commit.html.haml
@@ -1,5 +1,5 @@
.branch-commit
- = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-id monospace"
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-id monospace"
&middot;
%span.str-truncated
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml
index 396cc4ad925..dc57b49f27a 100644
--- a/app/views/projects/builds/_sidebar.html.haml
+++ b/app/views/projects/builds/_sidebar.html.haml
@@ -49,7 +49,7 @@
- if @build.duration
%p.build-detail-row
%span.build-light-text Duration:
- #{duration_in_words(@build.finished_at, @build.started_at)}
+ = time_interval_in_words(@build.duration)
- if @build.finished_at
%p.build-detail-row
%span.build-light-text Finished:
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index a9eaed4c5f6..a098a082854 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -2,7 +2,7 @@
- if current_user && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn has-tooltip' do
- = icon('code-fork fw')
+ = custom_icon('icon_fork')
Fork
%div.count-with-arrow
%span.arrow
@@ -10,7 +10,7 @@
= @project.forks_count
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has-tooltip' do
- = icon('code-fork fw')
+ = custom_icon('icon_fork')
Fork
%div.count-with-arrow
%span.arrow
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index 9264289987d..a9fb3c58431 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -14,16 +14,19 @@
%span ##{build.id}
- if build.stuck?
- = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
+ .icon-container
+ = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
- if defined?(retried) && retried
- = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.')
+ .icon-container
+ = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.')
- if defined?(ref) && ref
- if build.ref
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
- else
.light none
- = custom_icon("icon_commit")
+ .icon-container
+ = custom_icon("icon_commit")
- if defined?(commit_sha) && commit_sha
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace"
@@ -88,4 +91,3 @@
- elsif build.playable?
= link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do
= icon('play')
-
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index 996c9073770..2f7d54f0bdd 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -27,7 +27,7 @@
%p.commit-title
- if commit = pipeline.commit
- = commit_author_avatar(commit, size: 20)
+ = author_avatar(commit, size: 20)
= link_to_gfm truncate(commit.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "commit-row-message"
- else
Cant find HEAD commit for this branch
@@ -35,7 +35,7 @@
- stages_status = pipeline.statuses.latest.stages_status
- stages.each do |stage|
- %td
+ %td.stage-cell
- status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status || 'not found'}"
- if status
diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml
index 41fd5459429..540689f4a61 100644
--- a/app/views/projects/commit/_pipeline.html.haml
+++ b/app/views/projects/commit/_pipeline.html.haml
@@ -35,8 +35,8 @@
.bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit
-.table-holder
- %table.table.builds
+.table-holder.pipeline-holder
+ %table.table.builds.pipeline
%thead
%tr
%th Status
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index c8c7b858baa..fd888f41b1e 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -9,7 +9,8 @@
= cache(cache_key) do
%li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" }
- = commit_author_avatar(commit, size: 36)
+ = author_avatar(commit, size: 36)
+
.commit-info-block
.commit-row-title
%span.item-title
@@ -18,13 +19,14 @@
&middot;
= commit.short_id
- if commit.status
- = render_commit_status(commit, cssclass: 'visible-xs-inline')
+ .visible-xs-inline
+ = render_commit_status(commit)
- if commit.description?
%a.text-expander.hidden-xs.js-toggle-button ...
.commit-actions.hidden-xs
- if commit.status
- = render_commit_status(commit, cssclass: 'btn btn-transparent')
+ = render_commit_status(commit)
= clipboard_button(clipboard_text: commit.id)
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent"
= link_to_browse_code(project, commit)
diff --git a/app/views/projects/deployments/_actions.haml b/app/views/projects/deployments/_actions.haml
index 65d68aa2985..f70dba224fa 100644
--- a/app/views/projects/deployments/_actions.haml
+++ b/app/views/projects/deployments/_actions.haml
@@ -17,6 +17,6 @@
- if local_assigns.fetch(:allow_rollback, false)
= link_to [:retry, @project.namespace.becomes(Namespace), @project, deployment.deployable], method: :post, class: 'btn btn-build' do
- if deployment.last?
- Retry
+ Re-deploy
- else
Rollback
diff --git a/app/views/projects/diffs/_match_line_parallel.html.haml b/app/views/projects/diffs/_match_line_parallel.html.haml
deleted file mode 100644
index b9c0d9dcdfd..00000000000
--- a/app/views/projects/diffs/_match_line_parallel.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-%td.old_line.diff-line-num.empty-cell
-%td.line_content.parallel.match= line
-%td.new_line.diff-line-num.empty-cell
-%td.line_content.parallel.match= line
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index d208fcee10b..7f30faa20d8 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -5,32 +5,35 @@
- left = line[:left]
- right = line[:right]
%tr.line_holder.parallel
- - if left[:type] == 'match'
- = render "projects/diffs/match_line_parallel", { line: left[:text] }
- - elsif left[:type] == 'nonewline'
- %td.old_line.diff-line-num.empty-cell
- %td.line_content.parallel.match= left[:text]
- %td.new_line.diff-line-num.empty-cell
- %td.line_content.parallel.match= left[:text]
+ - if left
+ - if left.meta?
+ %td.old_line.diff-line-num.empty-cell
+ %td.line_content.parallel.match= left.text
+ - else
+ - left_line_code = diff_file.line_code(left)
+ - left_position = diff_file.position(left)
+ %td.old_line.diff-line-num{id: left_line_code, class: left.type, data: { linenumber: left.old_pos }}
+ %a{href: "##{left_line_code}" }= raw(left.old_pos)
+ %td.line_content.parallel.noteable_line{class: left.type, data: diff_view_line_data(left_line_code, left_position, 'old')}= diff_line_content(left.text)
- else
- %td.old_line.diff-line-num{id: left[:line_code], class: [left[:type], ('empty-cell' unless left[:number])], data: { linenumber: left[:number] }}
- %a{href: "##{left[:line_code]}" }= raw(left[:number])
- %td.line_content.parallel.noteable_line{class: [left[:type], ('empty-cell' if left[:text].empty?)], data: diff_view_line_data(left[:line_code], left[:position], 'old')}= diff_line_content(left[:text])
+ %td.old_line.diff-line-num.empty-cell
+ %td.line_content.parallel
- - if right[:type] == 'new'
- - new_line_type = 'new'
- - new_line_code = right[:line_code]
- - new_position = right[:position]
+ - if right
+ - if right.meta?
+ %td.old_line.diff-line-num.empty-cell
+ %td.line_content.parallel.match= left.text
- else
- - new_line_type = nil
- - new_line_code = left[:line_code]
- - new_position = left[:position]
-
- %td.new_line.diff-line-num{id: new_line_code, class: [new_line_type, ('empty-cell' unless right[:number])], data: { linenumber: right[:number] }}
- %a{href: "##{new_line_code}" }= raw(right[:number])
- %td.line_content.parallel.noteable_line{class: [new_line_type, ('empty-cell' if right[:text].empty?)], data: diff_view_line_data(new_line_code, new_position, 'new')}= diff_line_content(right[:text])
+ - right_line_code = diff_file.line_code(right)
+ - right_position = diff_file.position(right)
+ %td.new_line.diff-line-num{id: right_line_code, class: right.type, data: { linenumber: right.new_pos }}
+ %a{href: "##{right_line_code}" }= raw(right.new_pos)
+ %td.line_content.parallel.noteable_line{class: right.type, data: diff_view_line_data(right_line_code, right_position, 'new')}= diff_line_content(right.text)
+ - else
+ %td.old_line.diff-line-num.empty-cell
+ %td.line_content.parallel
- unless @diff_notes_disabled
- - notes_left, notes_right = organize_comments(left, right)
- - if notes_left.present? || notes_right.present?
- = render "projects/notes/diff_notes_with_reply_parallel", notes_left: notes_left, notes_right: notes_right
+ - discussion_left, discussion_right = parallel_diff_discussions(left, right, diff_file)
+ - if discussion_left || discussion_right
+ = render "discussions/parallel_diff_discussion", discussion_left: discussion_left, discussion_right: discussion_right
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index 196f8122db3..5970b9abf2b 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -11,9 +11,9 @@
- unless @diff_notes_disabled
- line_code = diff_file.line_code(line)
- - diff_notes = @grouped_diff_notes[line_code] if line_code
- - if diff_notes
- = render "projects/notes/diff_notes_with_reply", notes: diff_notes
+ - discussion = @grouped_diff_discussions[line_code] if line_code
+ - if discussion
+ = render "discussions/diff_discussion", discussion: discussion
- if last_line > 0
= render "projects/diffs/match_line", { line: "",
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 57af167180b..921155e970b 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -32,6 +32,10 @@
%strong
= visibility_level_label(@project.visibility_level)
.light= visibility_level_description(@project.visibility_level, @project)
+
+ .form-group
+ = render 'shared/allow_request_access', form: f
+
.form-group
= f.label :tag_list, "Tags", class: 'label-light'
= f.text_field :tag_list, value: @project.tag_list.to_s, maxlength: 2000, class: "form-control"
@@ -86,8 +90,6 @@
%hr
= render 'merge_request_settings', f: f
%hr
- = render 'builds_settings', f: f
- %hr
%fieldset.features.append-bottom-default
%h5.prepend-top-0
Project avatar
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index dbe9ddfde2f..a1d79bdabda 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -31,11 +31,11 @@
- if current_user && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-new' do
- = icon('code-fork fw')
+ = custom_icon('icon_fork')
Fork
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn btn-new' do
- = icon('code-fork fw')
+ = custom_icon('icon_fork')
Fork
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index 73a7fc0e1ac..5242bc72b71 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -1,45 +1,54 @@
- page_title "Fork project"
-- if @namespaces.present?
- %h3.page-title Fork project
- %p.lead
- Click to fork the project to a user or group
- %hr
- .fork-namespaces
- - @namespaces.in_groups_of(6, false) do |group|
- .row
- - group.each do |namespace|
- .col-md-2.col-sm-3
- - if fork = namespace.find_fork_of(@project)
- .fork-thumbnail
- = link_to project_path(fork), title: "Visit project fork", class: 'has-tooltip' do
- = image_tag namespace_icon(namespace, 100)
- .caption
- %strong
- = namespace.human_name
- %div.text-primary
- Already forked
-
- - else
- .fork-thumbnail
- = link_to namespace_project_forks_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has-tooltip' do
- = image_tag namespace_icon(namespace, 100)
- .caption
- %strong
- = namespace.human_name
-
- %p.light
- Fork is a copy of a project repository.
+.row.prepend-top-default
+ .col-lg-3
+ %h4.prepend-top-0
+ Fork project
+ %p
+ A fork is a copy of a project.
%br
- Forking a repository allows you to do changes without affecting the original project.
-- else
- %h3 No available namespaces to fork the project
- %p.slead
- You must have permission to create a project in a namespace before forking.
+ Forking a repository allows you to make changes without affecting the original project.
+ .col-lg-9
+ .fork-namespaces
+ - if @namespaces.present?
+ %label.label-light
+ %span
+ Click to fork the project to a user or group
+ - @namespaces.in_groups_of(6, false) do |group|
+ .row
+ - group.each do |namespace|
+ - avatar = namespace_icon(namespace, 100)
+ - if fork = namespace.find_fork_of(@project)
+ .fork-thumbnail.forked
+ = link_to project_path(fork) do
+ - if /no_((\w*)_)*avatar/.match(avatar)
+ .no-avatar
+ = icon 'question'
+ - else
+ = image_tag avatar
+ .caption
+ = namespace.human_name
+ - else
+ .fork-thumbnail
+ = link_to namespace_project_forks_path(@project.namespace, @project, namespace_key: namespace.id), method: "POST" do
+ - if /no_((\w*)_)*avatar/.match(avatar)
+ .no-avatar
+ = icon 'question'
+ - else
+ = image_tag avatar
+ .caption
+ = namespace.human_name
+ - else
+ %label.label-light
+ %span
+ No available namespaces to fork the project.
+ %br
+ %small
+ You must have permission to create a project in a namespace before forking.
-.save-project-loader.hide
- .center
- %h2
- %i.fa.fa-spinner.fa-spin
- Forking repository
- %p Please wait a moment, this page will automatically refresh when ready.
+ .save-project-loader.hide
+ .center
+ %h2
+ %i.fa.fa-spinner.fa-spin
+ Forking repository
+ %p Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
index 542827b2f15..331dc1fcc29 100644
--- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
+++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
@@ -51,7 +51,7 @@
%td.duration
- if generic_commit_status.duration
= icon("clock-o")
- #{duration_in_words(generic_commit_status.finished_at, generic_commit_status.started_at)}
+ = time_interval_in_words(generic_commit_status.duration)
%td.timestamp
- if generic_commit_status.finished_at
diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml
index ca347406dfe..45e51389c00 100644
--- a/app/views/projects/graphs/_head.html.haml
+++ b/app/views/projects/graphs/_head.html.haml
@@ -3,7 +3,7 @@
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/chart.js')
- = page_specific_javascript_tag('graphs/application.js')
+ = page_specific_javascript_tag('graphs/graphs_bundle.js')
= nav_link(action: :show) do
= link_to 'Contributors', namespace_project_graph_path
= nav_link(action: :commits) do
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 489c632ae22..6ef640bb654 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -1,6 +1,6 @@
- if @pipeline
.mr-widget-heading
- - %w[success skipped canceled failed running pending].each do |status|
+ - %w[success success_with_warnings skipped canceled failed running pending].each do |status|
.ci_widget{ class: "ci-#{status}", style: ("display:none" unless @pipeline.status == status) }
= ci_icon_for_status(status)
%span
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index 091af4df4a1..b2ece44d966 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -1,7 +1,7 @@
- page_title "Network", @ref
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/raphael.js')
- = page_specific_javascript_tag('network/application.js')
+ = page_specific_javascript_tag('network/network_bundle.js')
= render "projects/commits/head"
= render "head"
%div{ class: container_class }
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index c72d0140bb9..facdfcc9447 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -89,9 +89,9 @@
= link_to "#", class: 'btn js-toggle-button import_git' do
%i.fa.fa-git
%span Repo by URL
- %div
+ %div{ class: 'import_gitlab_project' }
- if gitlab_project_import_enabled?
- = link_to new_import_gitlab_project_path, class: 'btn import_gitlab_project project-submit' do
+ = link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do
%i.fa.fa-gitlab
%span GitLab export
@@ -130,29 +130,29 @@
$(".modal").hide();
});
- $('.import_gitlab_project').bind('click', function() {
- var _href = $("a.import_gitlab_project").attr("href");
- $(".import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val());
+ $('.btn_import_gitlab_project').bind('click', function() {
+ var _href = $("a.btn_import_gitlab_project").attr("href");
+ $(".btn_import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val());
});
- $('.import_gitlab_project').attr('disabled',true)
- $('.import_gitlab_project').attr('title', 'Project path required.');
+ $('.btn_import_gitlab_project').attr('disabled',true)
+ $('.import_gitlab_project').attr('title', 'Project path and name required.');
$('.import_gitlab_project').click(function( event ) {
- if($('.import_gitlab_project').attr('disabled')) {
+ if($('.btn_import_gitlab_project').attr('disabled')) {
event.preventDefault();
- new Flash("Please enter a path for the project to be imported to.");
+ new Flash("Please enter path and name for the project to be imported to.");
}
});
$('#project_path').keyup(function(){
if($(this).val().length !=0) {
- $('.import_gitlab_project').attr('disabled', false);
+ $('.btn_import_gitlab_project').attr('disabled', false);
$('.import_gitlab_project').attr('title','');
$(".flash-container").html("")
} else {
- $('.import_gitlab_project').attr('disabled',true);
- $('.import_gitlab_project').attr('title', 'Project path required.');
+ $('.btn_import_gitlab_project').attr('disabled',true);
+ $('.import_gitlab_project').attr('title', 'Project path and name required.');
}
});
diff --git a/app/views/projects/notes/_diff_notes_with_reply.html.haml b/app/views/projects/notes/_diff_notes_with_reply.html.haml
deleted file mode 100644
index ec6c4938efc..00000000000
--- a/app/views/projects/notes/_diff_notes_with_reply.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-- note = notes.first
-%tr.notes_holder
- %td.notes_line{ colspan: 2 }
- %td.notes_content
- %ul.notes{ data: { discussion_id: note.discussion_id } }
- = render partial: "projects/notes/note", collection: notes, as: :note
- = link_to_reply_discussion(note)
diff --git a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
deleted file mode 100644
index e50a4f86d03..00000000000
--- a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
+++ /dev/null
@@ -1,25 +0,0 @@
-- note_left = notes_left.present? ? notes_left.first : nil
-- note_right = notes_right.present? ? notes_right.first : nil
-
-%tr.notes_holder
- - if note_left
- %td.notes_line.old
- %td.notes_content.parallel.old
- %ul.notes{ data: { discussion_id: note_left.discussion_id } }
- = render partial: "projects/notes/note", collection: notes_left, as: :note
-
- = link_to_reply_discussion(note_left, 'old')
- - else
- %td.notes_line.old= ""
- %td.notes_content.parallel.old= ""
-
- - if note_right
- %td.notes_line.new
- %td.notes_content.parallel.new
- %ul.notes{ data: { discussion_id: note_right.discussion_id } }
- = render partial: "projects/notes/note", collection: notes_right, as: :note
-
- = link_to_reply_discussion(note_right, 'new')
- - else
- %td.notes_line.new= ""
- %td.notes_content.parallel.new= ""
diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml
deleted file mode 100644
index 7869d6413d8..00000000000
--- a/app/views/projects/notes/_discussion.html.haml
+++ /dev/null
@@ -1,46 +0,0 @@
-- note = discussion_notes.first
-- expanded = !note.diff_note? || note.active?
-%li.note.note-discussion.timeline-entry
- .timeline-entry-inner
- .timeline-icon
- = link_to user_path(note.author) do
- = image_tag avatar_icon(note.author), class: "avatar s40"
- .timeline-content
- .discussion.js-toggle-container{ class: note.discussion_id }
- .discussion-header
- = link_to_member(@project, note.author, avatar: false)
-
- .inline.discussion-headline-light
- = note.author.to_reference
- started a discussion on
-
- - if note.for_commit?
- - commit = note.noteable
- - if commit
- commit
- = link_to commit.short_id, namespace_project_commit_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code), class: 'monospace'
- - else
- a deleted commit
- - else
- - if note.active?
- = link_to diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code) do
- the diff
- - else
- an outdated diff
-
- = time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "note-created-ago")
-
- .discussion-actions
- = link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do
- - if expanded
- = icon("chevron-up")
- - else
- = icon("chevron-down")
-
- Toggle discussion
-
- .discussion-body.js-toggle-content{ class: ("hide" unless expanded) }
- - if note.diff_note?
- = render "projects/notes/discussions/diff_with_notes", discussion_notes: discussion_notes
- - else
- = render "projects/notes/discussions/notes", discussion_notes: discussion_notes
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index af0046886fb..71da8ac9d7c 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -30,7 +30,7 @@
= link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do
= icon('trash-o')
.note-body{class: note_editable ? 'js-task-list-container' : ''}
- .note-text
+ .note-text.md
= preserve do
= note.note_html
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago', include_author: true)
diff --git a/app/views/projects/notes/_notes.html.haml b/app/views/projects/notes/_notes.html.haml
index ebf7e8a9cb3..022578bd6db 100644
--- a/app/views/projects/notes/_notes.html.haml
+++ b/app/views/projects/notes/_notes.html.haml
@@ -1,10 +1,8 @@
- if @discussions.present?
- - @discussions.each do |discussion_notes|
- - note = discussion_notes.first
- - if note_for_main_target?(note)
- = render partial: "projects/notes/note", object: note, as: :note
+ - @discussions.each do |discussion|
+ - if discussion.for_target?(@noteable)
+ = render partial: "projects/notes/note", object: discussion.first_note, as: :note
- else
- = render 'projects/notes/discussion', discussion_notes: discussion_notes
+ = render 'discussions/discussion', discussion: discussion
- else
- - @notes.each do |note|
- = render partial: "projects/notes/note", object: note, as: :note
+ = render partial: "projects/notes/note", collection: @notes, as: :note
diff --git a/app/views/projects/notes/discussions/_diff_with_notes.html.haml b/app/views/projects/notes/discussions/_diff_with_notes.html.haml
deleted file mode 100644
index 4a69b8f8840..00000000000
--- a/app/views/projects/notes/discussions/_diff_with_notes.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- note = discussion_notes.first
-- diff_file = note.diff_file
-- return unless diff_file
-
-- blob = note.blob
-
-.diff-file.file-holder
- .file-title
- = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: note.project, url: diff_note_path(note)
-
- .diff-content.code.js-syntax-highlight
- %table
- - note.truncated_diff_lines.each do |line|
- = render "projects/diffs/line", line: line, diff_file: diff_file, plain: true
-
- - if note.for_line?(line)
- = render "projects/notes/diff_notes_with_reply", notes: discussion_notes
diff --git a/app/views/projects/notes/discussions/_notes.html.haml b/app/views/projects/notes/discussions/_notes.html.haml
deleted file mode 100644
index a785149549d..00000000000
--- a/app/views/projects/notes/discussions/_notes.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- note = discussion_notes.first
-.panel.panel-default
- .notes{ data: { discussion_id: note.discussion_id } }
- %ul.notes.timeline
- = render partial: "projects/notes/note", collection: discussion_notes, as: :note
- = link_to_reply_discussion(note)
diff --git a/app/views/projects/pipelines_settings/show.html.haml b/app/views/projects/pipelines_settings/show.html.haml
new file mode 100644
index 00000000000..228bad36ebd
--- /dev/null
+++ b/app/views/projects/pipelines_settings/show.html.haml
@@ -0,0 +1,103 @@
+- page_title "CI/CD Pipelines"
+
+.row.prepend-top-default
+ .col-lg-3.profile-settings-sidebar
+ %h4.prepend-top-0
+ = page_title
+ .col-lg-9
+ %h5.prepend-top-0
+ Pipelines
+ = form_for @project, url: namespace_project_pipelines_settings_path(@project.namespace.becomes(Namespace), @project), remote: true, authenticity_token: true do |f|
+ %fieldset.builds-feature
+ - unless @repository.gitlab_ci_yml
+ .form-group
+ %p Pipelines need to be configured before you can begin using Continuous Integration.
+ = link_to 'Get started with CI/CD Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
+ .form-group
+ %p Get recent application code using the following command:
+ .radio
+ = f.label :build_allow_git_fetch_false do
+ = f.radio_button :build_allow_git_fetch, 'false'
+ %strong git clone
+ %br
+ %span.descr Slower but makes sure you have a clean dir before every build
+ .radio
+ = f.label :build_allow_git_fetch_true do
+ = f.radio_button :build_allow_git_fetch, 'true'
+ %strong git fetch
+ %br
+ %span.descr Faster
+
+ .form-group
+ = f.label :build_timeout_in_minutes, 'Timeout', class: 'label-light'
+ = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
+ %p.help-block per build in minutes
+ .form-group
+ = f.label :build_coverage_regex, "Test coverage parsing", class: 'label-light'
+ .input-group
+ %span.input-group-addon /
+ = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
+ %span.input-group-addon /
+ %p.help-block
+ We will use this regular expression to find test coverage output in build trace.
+ Leave blank if you want to disable this feature
+ .bs-callout.bs-callout-info
+ %p Below are examples of regex for existing tools:
+ %ul
+ %li
+ Simplecov (Ruby) -
+ %code \(\d+.\d+\%\) covered
+ %li
+ pytest-cov (Python) -
+ %code \d+\%\s*$
+ %li
+ phpunit --coverage-text --colors=never (PHP) -
+ %code ^\s*Lines:\s*\d+.\d+\%
+ %li
+ gcovr (C/C++) -
+ %code ^TOTAL.*\s+(\d+\%)$
+ %li
+ tap --coverage-report=text-summary (Node.js) -
+ %code ^Statements\s*:\s*([^%]+)
+
+ .form-group
+ .checkbox
+ = f.label :public_builds do
+ = f.check_box :public_builds
+ %strong Public pipelines
+ .help-block Allow everyone to access pipelines for Public and Internal projects
+
+ .form-group.append-bottom-default
+ = f.label :runners_token, "Runners token", class: 'label-light'
+ = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
+ %p.help-block The secure token used to checkout project.
+
+ = f.submit 'Save changes', class: "btn btn-save"
+
+%hr
+
+.row.prepend-top-default
+ .col-lg-3.profile-settings-sidebar
+ %h4.prepend-top-0
+ Builds Badge
+ .col-lg-9
+ .prepend-top-10
+ .panel.panel-default
+ .panel-heading
+ %b Builds badge &middot;
+ = @build_badge.to_html
+ .pull-right
+ = render 'shared/ref_switcher', destination: 'badges', align_right: true
+ .panel-body
+ .row
+ .col-md-2.text-center
+ Markdown
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.md', @build_badge.to_markdown)
+ .row
+ %hr
+ .row
+ .col-md-2.text-center
+ HTML
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.html', @build_badge.to_html)
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index 151e1d64851..950df740bbc 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -6,12 +6,13 @@
= page_title
%p Keep stable branches secure and force developers to use merge requests.
%p.prepend-top-20
- Protected branches are designed to:
+ By default, protected branches are designed to:
%ul
- %li prevent pushes from everybody except #{link_to "masters", help_page_path("user/permissions"), class: "vlink"}
- %li prevent anyone from force pushing to the branch
- %li prevent anyone from deleting the branch
- %p.append-bottom-0 Read more about #{link_to "project permissions", help_page_path("user/permissions"), class: "underlined-link"}
+ %li prevent their creation, if not already created, from everybody except Masters
+ %li prevent pushes from everybody except Masters
+ %li prevent <strong>anyone</strong> from force pushing to the branch
+ %li prevent <strong>anyone</strong> from deleting the branch
+ %p.append-bottom-0 Read more about #{link_to "protected branches", help_page_path("user/project/protected_branches"), class: "underlined-link"} and #{link_to "project permissions", help_page_path("user/permissions"), class: "underlined-link"}.
.col-lg-9
%h5.prepend-top-0
Protect a branch
@@ -23,7 +24,7 @@
= f.label :name, "Branch", class: "label-light"
= render partial: "dropdown", locals: { f: f }
%p.help-block
- = link_to "Wildcards", help_page_path('workflow/protected_branches', anchor: "wildcard-protected-branches")
+ = link_to "Wildcards", help_page_path('user/project/protected_branches', anchor: "wildcard-protected-branches")
such as
%code *-stable
or
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 166dc4a01fc..752fbc21a11 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -8,6 +8,7 @@
.col-lg-9
= form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form|
= render 'shared/service_settings', form: form
+
= form.submit 'Save changes', class: 'btn btn-save'
&nbsp;
- if @service.valid? && @service.activated?
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index b7d7d5c5382..395d7af6cbb 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -1,36 +1,39 @@
+- @no_container = true
- page_title @tag.name, "Tags"
= render "projects/commits/head"
-.row-content-block
- .pull-right
- - if can?(current_user, :push_code, @project)
- = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn has-tooltip', title: 'Edit release notes' do
- = icon("pencil")
- = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped has-tooltip', title: 'Browse files' do
- = icon('files-o')
- = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped has-tooltip', title: 'Browse commits' do
- = icon('history')
- - if can? current_user, :download_code, @project
- = render 'projects/tags/download', ref: @tag.name, project: @project
- - if can?(current_user, :admin_project, @project)
- .pull-right
- = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
- %i.fa.fa-trash-o
- .title
- %span.item-title= @tag.name
- - if @commit
- = render 'projects/branches/commit', commit: @commit, project: @project
- - else
- Cant find HEAD commit for this tag
- - if @tag.message.present?
- %pre.body
- = strip_gpg_signature(@tag.message)
+%div{ class: container_class }
+ .sub-header-block
+ .pull-right.tag-buttons
+ - if can?(current_user, :push_code, @project)
+ = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn has-tooltip', title: 'Edit release notes' do
+ = icon("pencil")
+ = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn has-tooltip', title: 'Browse files' do
+ = icon('files-o')
+ = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn has-tooltip', title: 'Browse commits' do
+ = icon('history')
+ - if can? current_user, :download_code, @project
+ = render 'projects/tags/download', ref: @tag.name, project: @project
+ - if can?(current_user, :admin_project, @project)
+ .pull-right
+ = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
+ %i.fa.fa-trash-o
+ .tag-info.append-bottom-10
+ .title
+ %span.item-title= @tag.name
+ - if @commit
+ = render 'projects/branches/commit', commit: @commit, project: @project
+ - else
+ Cant find HEAD commit for this tag
+ - if @tag.message.present?
+ %pre.body
+ = strip_gpg_signature(@tag.message)
-.append-bottom-default.prepend-top-default
- - if @release.description.present?
- .description
- .wiki
- = preserve do
- = markdown @release.description
- - else
- This tag has no release notes.
+ .append-bottom-default.prepend-top-default
+ - if @release.description.present?
+ .description
+ .wiki
+ = preserve do
+ = markdown @release.description
+ - else
+ This tag has no release notes.
diff --git a/app/views/shared/_allow_request_access.html.haml b/app/views/shared/_allow_request_access.html.haml
new file mode 100644
index 00000000000..53a99a736c0
--- /dev/null
+++ b/app/views/shared/_allow_request_access.html.haml
@@ -0,0 +1,6 @@
+.checkbox
+ = form.label :request_access_enabled do
+ = form.check_box :request_access_enabled
+ %strong Allow users to request access
+ %br
+ %span.descr Allow users to request access if visibility is public or internal.
diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml
index 4eaf7c2a025..5254d265918 100644
--- a/app/views/shared/_service_settings.html.haml
+++ b/app/views/shared/_service_settings.html.haml
@@ -10,69 +10,28 @@
.col-sm-10
= form.check_box :active
-- if @service.supported_events.length > 1
- .form-group
- = form.label :url, "Trigger", class: 'control-label'
- .col-sm-10
- - if @service.supported_events.include?("push")
- %div
- = form.check_box :push_events, class: 'pull-left'
- .prepend-left-20
- = form.label :push_events, class: 'list-label' do
- %strong Push events
- %p.light
- This url will be triggered by a push to the repository
- - if @service.supported_events.include?("tag_push")
- %div
- = form.check_box :tag_push_events, class: 'pull-left'
- .prepend-left-20
- = form.label :tag_push_events, class: 'list-label' do
- %strong Tag push events
- %p.light
- This url will be triggered when a new tag is pushed to the repository
- - if @service.supported_events.include?("note")
- %div
- = form.check_box :note_events, class: 'pull-left'
- .prepend-left-20
- = form.label :note_events, class: 'list-label' do
- %strong Comments
- %p.light
- This url will be triggered when someone adds a comment
- - if @service.supported_events.include?("issue")
- %div
- = form.check_box :issues_events, class: 'pull-left'
- .prepend-left-20
- = form.label :issues_events, class: 'list-label' do
- %strong Issues events
- %p.light
- This url will be triggered when an issue is created/updated/merged
- - if @service.supported_events.include?("merge_request")
- %div
- = form.check_box :merge_requests_events, class: 'pull-left'
- .prepend-left-20
- = form.label :merge_requests_events, class: 'list-label' do
- %strong Merge Request events
- %p.light
- This url will be triggered when a merge request is created/updated/merged
- - if @service.supported_events.include?("build")
- %div
- = form.check_box :build_events, class: 'pull-left'
- .prepend-left-20
- = form.label :build_events, class: 'list-label' do
- %strong Build events
- %p.light
- This url will be triggered when a build status changes
- - if @service.supported_events.include?("wiki_page")
- %div
- = form.check_box :wiki_page_events, class: 'pull-left'
- .prepend-left-20
- = form.label :wiki_page_events, class: 'list-label' do
- %strong Wiki Page events
- %p.light
- This url will be triggered when a wiki page is created/updated
+.form-group
+ = form.label :url, "Trigger", class: 'control-label'
+
+ .col-sm-10
+ - @service.supported_events.each do |event|
+ %div
+ = form.check_box service_event_field_name(event), class: 'pull-left'
+ .prepend-left-20
+ = form.label service_event_field_name(event), class: 'list-label' do
+ %strong
+ = event.humanize
+
+ - field = @service.event_field(event)
+
+ - if field
+ %p
+ = form.text_field field[:name], class: "form-control", placeholder: field[:placeholder]
+ %p.light
+ = service_event_description(event)
-- @service.fields.each do |field|
+- @service.global_fields.each do |field|
- type = field[:type]
- if type == 'fieldset'
diff --git a/app/views/shared/icons/_icon_fork.svg b/app/views/shared/icons/_icon_fork.svg
new file mode 100644
index 00000000000..a21f8f3a951
--- /dev/null
+++ b/app/views/shared/icons/_icon_fork.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
+ <path fill="#7E7E7E" fill-rule="evenodd" d="M22,29.5351288 L22,22.7193602 C26.1888699,21.5098039 29.3985457,16.802989 29.3985457,16.802989 C29.740988,16.3567547 30,15.5559546 30,15.0081969 L30,10.4648712 C31.1956027,9.77325238 32,8.48056471 32,7 C32,4.790861 30.209139,3 28,3 C25.790861,3 24,4.790861 24,7 C24,8.48056471 24.8043973,9.77325238 26,10.4648712 L26,14.7083871 C26,14.8784435 25.9055559,15.0987329 25.7890533,15.2104147 C25.7890533,15.2104147 24.5373893,16.4126202 23.9488702,16.9515733 C22.5015398,18.2770075 21.1191354,19 20.090554,19 C19.0477772,19 17.6172728,18.2608988 16.1128852,16.9142923 C15.5030182,16.3683886 14.3672121,15.3403307 14.3672121,15.3403307 C14.1659605,15.1583364 14.0000086,14.7846305 14.0000192,14.5088473 C14.0000192,14.5088473 14.0000932,12.7539451 14.0001308,10.4647956 C15.1956614,9.77315812 16,8.48051074 16,7 C16,4.790861 14.209139,3 12,3 C9.790861,3 8,4.790861 8,7 C8,8.48056471 8.80439726,9.77325238 10,10.4648712 L10,15.0081969 C10,15.5446944 10.2736352,16.3534183 10.6111812,16.7893819 C10.6111812,16.7893819 13.8599776,21.3779363 18,22.6668724 L18,29.5351288 C16.8043973,30.2267476 16,31.5194353 16,33 C16,35.209139 17.790861,37 20,37 C22.209139,37 24,35.209139 24,33 C24,31.5194353 23.1956027,30.2267476 22,29.5351288 Z M14,7 C14,5.8954305 13.1045695,5 12,5 C10.8954305,5 10,5.8954305 10,7 C10,8.1045695 10.8954305,9 12,9 C13.1045695,9 14,8.1045695 14,7 Z M30,7 C30,5.8954305 29.1045695,5 28,5 C26.8954305,5 26,5.8954305 26,7 C26,8.1045695 26.8954305,9 28,9 C29.1045695,9 30,8.1045695 30,7 Z M22,33 C22,31.8954305 21.1045695,31 20,31 C18.8954305,31 18,31.8954305 18,33 C18,34.1045695 18.8954305,35 20,35 C21.1045695,35 22,34.1045695 22,33 Z"/>
+</svg>
diff --git a/app/views/shared/icons/_icon_status_cancel.svg b/app/views/shared/icons/_icon_status_cancel.svg
new file mode 100644
index 00000000000..6a0bc1490c4
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_cancel.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="a" cx="7" cy="7" r="7"/>
+ <mask id="b" width="14" height="14" x="0" y="0" fill="white">
+ <use xlink:href="#a"/>
+ </mask>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use stroke="#5C5C5C" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+ <rect width="10" height="1" x="2" y="6.5" fill="#5C5C5C" transform="rotate(45 7 7)" rx=".3"/>
+ </g>
+</svg>
diff --git a/app/views/shared/icons/_icon_status_failed.svg b/app/views/shared/icons/_icon_status_failed.svg
new file mode 100644
index 00000000000..c41ca18cae7
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_failed.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="a" cx="7" cy="7" r="7"/>
+ <mask id="b" width="14" height="14" x="0" y="0" fill="white">
+ <use xlink:href="#a"/>
+ </mask>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use stroke="#D22852" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+ <path fill="#D22852" d="M7.5,6.5 L7.5,4.30578971 C7.5,4.12531853 7.36809219,4 7.20537567,4 L6.79462433,4 C6.63904572,4 6.5,4.13690672 6.5,4.30578971 L6.5,6.5 L4.30578971,6.5 C4.12531853,6.5 4,6.63190781 4,6.79462433 L4,7.20537567 C4,7.36095428 4.13690672,7.5 4.30578971,7.5 L6.5,7.5 L6.5,9.69421029 C6.5,9.87468147 6.63190781,10 6.79462433,10 L7.20537567,10 C7.36095428,10 7.5,9.86309328 7.5,9.69421029 L7.5,7.5 L9.69421029,7.5 C9.87468147,7.5 10,7.36809219 10,7.20537567 L10,6.79462433 C10,6.63904572 9.86309328,6.5 9.69421029,6.5 L7.5,6.5 Z" transform="rotate(45 7 7)"/>
+ </g>
+</svg>
diff --git a/app/views/shared/icons/_icon_status_pending.svg b/app/views/shared/icons/_icon_status_pending.svg
new file mode 100644
index 00000000000..035cd8b4ccc
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_pending.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="a" cx="7" cy="7" r="7"/>
+ <mask id="b" width="14" height="14" x="0" y="0" fill="white">
+ <use xlink:href="#a"/>
+ </mask>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use stroke="#E75E40" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+ <rect width="1" height="4" x="5" y="5" fill="#E75E40" rx=".3"/>
+ <rect width="1" height="4" x="8" y="5" fill="#E75E40" rx=".3"/>
+ </g>
+</svg>
diff --git a/app/views/shared/icons/_icon_status_running.svg b/app/views/shared/icons/_icon_status_running.svg
new file mode 100644
index 00000000000..a48b3a25099
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_running.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="a" cx="7" cy="7" r="7"/>
+ <mask id="b" width="14" height="14" x="0" y="0" fill="white">
+ <use xlink:href="#a"/>
+ </mask>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use stroke="#2D9FD8" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+ <path fill="#2D9FD8" d="M7,3.00800862 C9.09023405,3.13960661 10.7448145,4.87657932 10.7448145,7 C10.7448145,9.209139 8.95395346,11 6.74481446,11 C5.4560962,11 4.30972054,10.3905589 3.57817301,9.44416214 L7,7 L7,3.00800862 Z"/>
+ </g>
+</svg>
diff --git a/app/views/shared/icons/_icon_status_success.svg b/app/views/shared/icons/_icon_status_success.svg
new file mode 100644
index 00000000000..260eab013a3
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_success.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="a" cx="7" cy="7" r="7"/>
+ <mask id="b" width="14" height="14" x="0" y="0" fill="white">
+ <use xlink:href="#a"/>
+ </mask>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use stroke="#31AF64" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+ <g fill="#31AF64" transform="rotate(45 -.13 10.953)">
+ <rect width="1" height="5" x="2" rx=".3"/>
+ <rect width="3" height="1" y="4" rx=".3"/>
+ </g>
+ </g>
+</svg>
diff --git a/app/views/shared/icons/_icon_status_warning.svg b/app/views/shared/icons/_icon_status_warning.svg
new file mode 100644
index 00000000000..d47e7a1c93f
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_warning.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="a" cx="7" cy="7" r="7"/>
+ <mask id="b" width="14" height="14" x="0" y="0" fill="white">
+ <use xlink:href="#a"/>
+ </mask>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <g fill="#FF8A24" transform="translate(6 3)">
+ <rect width="2" height="5" rx=".5"/>
+ <rect width="2" height="2" y="6" rx=".5"/>
+ </g>
+ <use stroke="#FF8A24" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+ </g>
+</svg>
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index e020a7d4d00..8e2fcbdfab8 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -156,7 +156,7 @@
- project_ref = cross_project_reference(@project, issuable)
.block.project-reference
- .sidebar-collapsed-icon
+ .sidebar-collapsed-icon.dont-change-state
= clipboard_button(clipboard_text: project_ref)
.cross-project-reference.hide-collapsed
%span
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index db2b4885861..c7f39868e71 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -2,7 +2,7 @@
- page_description @user.bio
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/d3.js')
- = page_specific_javascript_tag('users/application.js')
+ = page_specific_javascript_tag('users/users_bundle.js')
- header_title @user.name, user_path(@user)
- @no_container = true
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 8551288e2f2..0b6a01a3200 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -28,12 +28,12 @@ class EmailsOnPushWorker
:push
end
- merge_base_sha = project.merge_base_commit(before_sha, after_sha).try(:sha)
-
diff_refs = nil
compare = nil
reverse_compare = false
+
if action == :push
+ merge_base_sha = project.merge_base_commit(before_sha, after_sha).try(:sha)
compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
diff_refs = Gitlab::Diff::DiffRefs.new(
diff --git a/app/workers/repository_archive_cache_worker.rb b/app/workers/repository_archive_cache_worker.rb
index 47c5a670ed4..a2e49c61f59 100644
--- a/app/workers/repository_archive_cache_worker.rb
+++ b/app/workers/repository_archive_cache_worker.rb
@@ -4,6 +4,6 @@ class RepositoryArchiveCacheWorker
sidekiq_options queue: :default
def perform
- Repository.clean_old_archives
+ RepositoryArchiveCleanUpService.new.execute
end
end