summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
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/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/markdown_area.scss27
-rw-r--r--app/assets/stylesheets/pages/events.scss8
-rw-r--r--app/assets/stylesheets/pages/issuable.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss8
-rw-r--r--app/assets/stylesheets/pages/notes.scss23
-rw-r--r--app/assets/stylesheets/pages/projects.scss57
-rw-r--r--app/assets/stylesheets/pages/status.scss8
-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/compare_controller.rb1
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-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.rb5
-rw-r--r--app/helpers/commits_helper.rb10
-rw-r--r--app/helpers/services_helper.rb25
-rw-r--r--app/helpers/time_helper.rb1
-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/issue.rb40
-rw-r--r--app/models/project.rb81
-rw-r--r--app/models/project_services/slack_service.rb51
-rw-r--r--app/models/service.rb14
-rw-r--r--app/models/user.rb63
-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/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/nav/_explore.html.haml4
-rw-r--r--app/views/layouts/nav/_project_settings.html.haml6
-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/ci/pipelines/_pipeline.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml3
-rw-r--r--app/views/projects/deployments/_actions.haml2
-rw-r--r--app/views/projects/edit.html.haml6
-rw-r--r--app/views/projects/forks/new.html.haml91
-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/_note.html.haml2
-rw-r--r--app/views/projects/pipelines_settings/show.html.haml103
-rw-r--r--app/views/projects/services/_form.html.haml1
-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/issuable/_sidebar.html.haml2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/workers/emails_on_push_worker.rb4
82 files changed, 925 insertions, 471 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/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/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/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 ded437625ee..7a50bc9c832 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -269,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/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 5254faf723d..4e806e60e7e 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -70,6 +70,14 @@
color: $gl-success;
}
+ &.ci-success_with_warnings {
+ color: $gl-success;
+
+ i {
+ color: $gl-warning;
+ }
+ }
+
&.ci-skipped {
background-color: #eee;
color: #888;
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/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 63853335fb6..cc3aef5199e 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -333,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;
+ }
}
}
}
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index a22d4b6f6be..99f64b5e4cc 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;
}
@@ -57,9 +58,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;
}
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/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 5f3ee71444d..10749d0fef8 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
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index df659bb8c3b..7beeb7d97d0 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -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
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 59a8365d60b..ffac28f78a0 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
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/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 1926f03af07..790001222f1 100644
--- a/app/helpers/time_helper.rb
+++ b/app/helpers/time_helper.rb
@@ -1,5 +1,6 @@
module TimeHelper
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
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/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/project.rb b/app/models/project.rb
index d08b737e813..f09d915f20e 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)
+ pipeline = pipelines.latest_successful_for(ref).to_sql
+ join_sql = "INNER JOIN (#{pipeline}) pipelines" +
+ " ON pipelines.id = #{Ci::Build.quoted_table_name}.commit_id"
+ builds.joins(join_sql).latest.with_artifacts
+ # TODO: Whenever we dropped support for MySQL, we could change to:
+ # pipeline = pipelines.latest_successful_for(ref)
+ # builds.where(pipeline: pipeline).latest.with_artifacts
+ 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
@@ -1180,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/service.rb b/app/models/service.rb
index 4821096379c..40cd9b861f0 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -26,7 +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') }
+ scope :external_wikis, -> { where(type: 'ExternalWikiService').active }
scope :active, -> { where(active: true) }
scope :without_defaults, -> { where(default: false) }
@@ -82,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
diff --git a/app/models/user.rb b/app/models/user.rb
index 975e935fa20..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
@@ -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/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/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/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/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/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index cb0ca7bc8e3..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
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index c8c7b858baa..ab9afb06afb 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
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/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/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/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/_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/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/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/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/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(