Commit cc8ebae5 authored by Linus G Thiel's avatar Linus G Thiel

Merge branch 'master' into 22743-issue-tooltip-will-not-disappear-going-back-to-previous-page

parents 1ff140ea ba27abec
...@@ -5,7 +5,7 @@ require: ...@@ -5,7 +5,7 @@ require:
inherit_from: .rubocop_todo.yml inherit_from: .rubocop_todo.yml
AllCops: AllCops:
TargetRubyVersion: 2.3 TargetRubyVersion: 2.1
# Cop names are not d§splayed in offense messages by default. Change behavior # Cop names are not d§splayed in offense messages by default. Change behavior
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names # by overriding DisplayCopNames, or by giving the -D/--display-cop-names
# option. # option.
......
...@@ -191,7 +191,7 @@ linters: ...@@ -191,7 +191,7 @@ linters:
# Variables should be formatted with a single space separating the colon # Variables should be formatted with a single space separating the colon
# from the variable's value. # from the variable's value.
SpaceAfterVariableColon: SpaceAfterVariableColon:
enabled: false enabled: true
# Variables should be formatted with no space between the name and the # Variables should be formatted with no space between the name and the
# colon. # colon.
...@@ -201,7 +201,7 @@ linters: ...@@ -201,7 +201,7 @@ linters:
# Operators should be formatted with a single space on both sides of an # Operators should be formatted with a single space on both sides of an
# infix operator. # infix operator.
SpaceAroundOperator: SpaceAroundOperator:
enabled: false enabled: true
# Opening braces should be preceded by a single space. # Opening braces should be preceded by a single space.
SpaceBeforeBrace: SpaceBeforeBrace:
...@@ -223,7 +223,7 @@ linters: ...@@ -223,7 +223,7 @@ linters:
# Reports lines containing trailing whitespace. # Reports lines containing trailing whitespace.
TrailingWhitespace: TrailingWhitespace:
enabled: false enabled: true
# Don't write trailing zeros for numeric values with a decimal point. # Don't write trailing zeros for numeric values with a decimal point.
TrailingZero: TrailingZero:
......
...@@ -2,12 +2,35 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,12 +2,35 @@ Please view this file on the master branch, on stable branches it's out of date.
## 8.14.0 (2016-11-22) ## 8.14.0 (2016-11-22)
- Adds user project membership expired event to clarify why user was removed (Callum Dryden) - Adds user project membership expired event to clarify why user was removed (Callum Dryden)
- Trim leading and trailing whitespace on project_path (Linus Thiel)
- Prevent award emoji via notes for issues/MRs authored by user (barthc)
- Adds an optional path parameter to the Commits API to filter commits by path (Luis HGO)
- Fix extra space on Build sidebar on Firefox !7060
- Fix HipChat notifications rendering (airatshigapov, eisnerd) - Fix HipChat notifications rendering (airatshigapov, eisnerd)
- Add hover to trash icon in notes !7008 (blackst0ne)
- Escape ref and path for relative links !6050 (winniehell)
- Simpler arguments passed to named_route on toggle_award_url helper method - Simpler arguments passed to named_route on toggle_award_url helper method
- Fix: Backup restore doesn't clear cache
- Use MergeRequestsClosingIssues cache data on Issue#closed_by_merge_requests method
- Fix Sign in page 'Forgot your password?' link overlaps on medium-large screens
- Fix documents and comments on Build API `scope`
- Refactor email, use setter method instead AR callbacks for email attribute (Semyon Pupkov)
## 8.13.1 (unreleased)
- Fix bug where labels would be assigned to issues that were moved
- Fix error in generating labels
- Fix reply-by-email not working due to queue name mismatch
- Fixed hidden pipeline graph on commit and MR page !6895
- Expire and build repository cache after project import
- Fix 404 for group pages when GitLab setup uses relative url
- Simpler arguments passed to named_route on toggle_award_url helper method
- Better handle when no users were selected for adding to group or project. (Linus Thiel)
- Only show register tab if signup enabled.
## 8.13.0 (2016-10-22) ## 8.13.0 (2016-10-22)
- Removes extra line for empty issue description. (!7045)
- Fix save button on project pipeline settings page. (!6955) - Fix save button on project pipeline settings page. (!6955)
- All Sidekiq workers now use their own queue
- Avoid race condition when asynchronously removing expired artifacts. (!6881) - Avoid race condition when asynchronously removing expired artifacts. (!6881)
- Improve Merge When Build Succeeds triggers and execute on pipeline success. (!6675) - Improve Merge When Build Succeeds triggers and execute on pipeline success. (!6675)
- Respond with 404 Not Found for non-existent tags (Linus Thiel) - Respond with 404 Not Found for non-existent tags (Linus Thiel)
...@@ -26,6 +49,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -26,6 +49,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Update duration at the end of pipeline - Update duration at the end of pipeline
- ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup - ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup
- Add group level labels. (!6425) - Add group level labels. (!6425)
- Fix Cycle analytics not showing correct data when filtering by date. !6906
- Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun) - Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun)
- Cancelled pipelines could be retried. !6927 - Cancelled pipelines could be retried. !6927
- Updating verbiage on git basics to be more intuitive - Updating verbiage on git basics to be more intuitive
...@@ -33,6 +57,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -33,6 +57,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Clarify documentation for Runners API (Gennady Trafimenkov) - Clarify documentation for Runners API (Gennady Trafimenkov)
- The instrumentation for Banzai::Renderer has been restored - The instrumentation for Banzai::Renderer has been restored
- Change user & group landing page routing from /u/:username to /:username - Change user & group landing page routing from /u/:username to /:username
- Fixed issue boards user link when in subdirectory
- Added documentation for .gitattributes files - Added documentation for .gitattributes files
- Move Pipeline Metrics to separate worker - Move Pipeline Metrics to separate worker
- AbstractReferenceFilter caches project_refs on RequestStore when active - AbstractReferenceFilter caches project_refs on RequestStore when active
...@@ -83,6 +108,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -83,6 +108,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Add visibility level to project repository - Add visibility level to project repository
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison) - Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Close open merge request without source project (Katarzyna Kobierska Ula Budziszewska) - Close open merge request without source project (Katarzyna Kobierska Ula Budziszewska)
- Fix showing commits from source project for merge request !6658
- Fix that manual jobs would no longer block jobs in the next stage. !6604 - Fix that manual jobs would no longer block jobs in the next stage. !6604
- Add configurable email subject suffix (Fu Xu) - Add configurable email subject suffix (Fu Xu)
- Use defined colour for a language when available !6748 (nilsding) - Use defined colour for a language when available !6748 (nilsding)
...@@ -143,6 +169,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -143,6 +169,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fix buggy iOS tooltip layering behavior. - Fix buggy iOS tooltip layering behavior.
- Make guests unable to view MRs on private projects - Make guests unable to view MRs on private projects
- Fix broken Project API docs (Takuya Noguchi) - Fix broken Project API docs (Takuya Noguchi)
- Migrate invalid project members (owner -> master)
## 8.12.7 ## 8.12.7
...@@ -376,6 +403,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -376,6 +403,7 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fix inconsistent checkbox alignment (ClemMakesApps) - Fix inconsistent checkbox alignment (ClemMakesApps)
- Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger)
- Adds response mime type to transaction metric action when it's not HTML - Adds response mime type to transaction metric action when it's not HTML
- Fix branch protection API !6215
- Fix hover leading space bug in pipeline graph !5980 - Fix hover leading space bug in pipeline graph !5980
- Avoid conflict with admin labels when importing GitHub labels - Avoid conflict with admin labels when importing GitHub labels
- User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496 - User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496
......
...@@ -83,14 +83,15 @@ ...@@ -83,14 +83,15 @@
}; };
// Disable button if text field is empty // Disable button if text field is empty
window.disableButtonIfEmptyField = function(field_selector, button_selector) { window.disableButtonIfEmptyField = function(field_selector, button_selector, event_name) {
event_name = event_name || 'input';
var closest_submit, field; var closest_submit, field;
field = $(field_selector); field = $(field_selector);
closest_submit = field.closest('form').find(button_selector); closest_submit = field.closest('form').find(button_selector);
if (rstrip(field.val()) === "") { if (rstrip(field.val()) === "") {
closest_submit.disable(); closest_submit.disable();
} }
return field.on('input', function() { return field.on(event_name, function() {
if (rstrip($(this).val()) === "") { if (rstrip($(this).val()) === "") {
return closest_submit.disable(); return closest_submit.disable();
} else { } else {
......
...@@ -148,7 +148,7 @@ ...@@ -148,7 +148,7 @@
}; };
Build.prototype.translateSidebar = function(e) { Build.prototype.translateSidebar = function(e) {
var newPosition = this.sidebarTranslationLimits.max - document.body.scrollTop; var newPosition = this.sidebarTranslationLimits.max - (document.body.scrollTop || document.documentElement.scrollTop);
if (newPosition < this.sidebarTranslationLimits.min) newPosition = this.sidebarTranslationLimits.min; if (newPosition < this.sidebarTranslationLimits.min) newPosition = this.sidebarTranslationLimits.min;
this.$sidebar.css({ this.$sidebar.css({
top: newPosition top: newPosition
......
...@@ -36,7 +36,11 @@ ...@@ -36,7 +36,11 @@
method: 'GET', method: 'GET',
dataType: 'json', dataType: 'json',
contentType: 'application/json', contentType: 'application/json',
data: { start_date: options.startDate } data: {
cycle_analytics: {
start_date: options.startDate
}
}
}).done((data) => { }).done((data) => {
this.decorateData(data); this.decorateData(data);
this.initDropdown(); this.initDropdown();
......
...@@ -117,6 +117,9 @@ ...@@ -117,6 +117,9 @@
new ZenMode(); new ZenMode();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
break; break;
case 'projects:commit:builds':
new gl.Pipelines();
break;
case 'projects:commits:show': case 'projects:commits:show':
case 'projects:activity': case 'projects:activity':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
......
...@@ -137,8 +137,11 @@ ...@@ -137,8 +137,11 @@
} }
initValidators () { initValidators () {
// select all non-hidden inputs in form // register selectors here as needed
this.state.inputs = this.form.find(':input:not([type=hidden])').toArray() const validateSelectors = [':text', ':password', '[type=email]']
.map((selector) => `input${selector}`).join(',');
this.state.inputs = this.form.find(validateSelectors).toArray()
.filter((input) => !input.classList.contains(customValidationFlag)) .filter((input) => !input.classList.contains(customValidationFlag))
.map((input) => new GlFieldError({ input, formErrors: this })); .map((input) => new GlFieldError({ input, formErrors: this }));
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
$('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow);
$('.js-member-update-control').off('change').on('change', this.formSubmit); $('.js-member-update-control').off('change').on('change', this.formSubmit);
$('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess); $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess);
disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change');
} }
removeRow(e) { removeRow(e) {
......
...@@ -282,6 +282,7 @@ ...@@ -282,6 +282,7 @@
document.querySelector("div#builds").innerHTML = data.html; document.querySelector("div#builds").innerHTML = data.html;
gl.utils.localTimeAgo($('.js-timeago', 'div#builds')); gl.utils.localTimeAgo($('.js-timeago', 'div#builds'));
_this.buildsLoaded = true; _this.buildsLoaded = true;
if (!this.pipelines) this.pipelines = new gl.Pipelines();
return _this.scrollToElement("#builds"); return _this.scrollToElement("#builds");
}; };
})(this) })(this)
...@@ -388,28 +389,25 @@ ...@@ -388,28 +389,25 @@
// So we dont affix the tabs on these // So we dont affix the tabs on these
if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return; if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return;
var tabsWidth = $tabs.outerWidth(), var $diffTabs = $('#diff-notes-app'),
$diffTabs = $('#diff-notes-app'), $fixedNav = $('.navbar-fixed-top'),
offsetTop = $tabs.offset().top - ($('.navbar-fixed-top').height() + $('.layout-nav').height()); $layoutNav = $('.layout-nav');
$tabs.off('affix.bs.affix affix-top.bs.affix') $tabs.off('affix.bs.affix affix-top.bs.affix')
.affix({ .affix({
offset: { offset: {
top: offsetTop top: function () {
var tabsTop = $diffTabs.offset().top - $tabs.height();
tabsTop = tabsTop - ($fixedNav.height() + $layoutNav.height());
return tabsTop;
}
} }
}).on('affix.bs.affix', function () { }).on('affix.bs.affix', function () {
$tabs.css({
left: $tabs.offset().left,
width: tabsWidth
});
$diffTabs.css({ $diffTabs.css({
marginTop: $tabs.height() marginTop: $tabs.height()
}); });
}).on('affix-top.bs.affix', function () { }).on('affix-top.bs.affix', function () {
$tabs.css({
left: '',
width: ''
});
$diffTabs.css({ $diffTabs.css({
marginTop: '' marginTop: ''
}); });
......
...@@ -372,3 +372,5 @@ table { ...@@ -372,3 +372,5 @@ table {
margin-right: -$gl-padding; margin-right: -$gl-padding;
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
} }
.hide-bottom-border { border-bottom: none !important; }
...@@ -402,7 +402,7 @@ ...@@ -402,7 +402,7 @@
.dropdown-content { .dropdown-content {
max-height: 215px; max-height: 215px;
overflow-y: scroll; overflow-y: auto;
} }
.dropdown-footer { .dropdown-footer {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
padding: 15px; padding: 15px;
.form-actions { .form-actions {
margin: -$gl-padding+1; margin: -$gl-padding + 1;
margin-top: 15px; margin-top: 15px;
} }
......
...@@ -185,6 +185,10 @@ header.header-sidebar-pinned { ...@@ -185,6 +185,10 @@ header.header-sidebar-pinned {
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
padding-right: $sidebar_collapsed_width; padding-right: $sidebar_collapsed_width;
.merge-request-tabs-holder.affix {
right: $sidebar_collapsed_width;
}
} }
.sidebar-collapsed-icon { .sidebar-collapsed-icon {
...@@ -207,6 +211,10 @@ header.header-sidebar-pinned { ...@@ -207,6 +211,10 @@ header.header-sidebar-pinned {
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
padding-right: $gutter_width; padding-right: $gutter_width;
.merge-request-tabs-holder.affix {
right: $gutter_width;
}
} }
&.with-overlay { &.with-overlay {
......
...@@ -143,6 +143,7 @@ ...@@ -143,6 +143,7 @@
&:not(.active) { &:not(.active) {
background-color: $gray-light; background-color: $gray-light;
border-left: 1px solid $border-color;
} }
a { a {
...@@ -170,6 +171,31 @@ ...@@ -170,6 +171,31 @@
} }
} }
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
.new-session-tabs.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
.form-control { .form-control {
&:active, &:focus { &:active, &:focus {
...@@ -203,6 +229,7 @@ ...@@ -203,6 +229,7 @@
.login-page { .login-page {
.col-sm-5.pull-right { .col-sm-5.pull-right {
float: none !important; float: none !important;
margin-bottom: 45px;
} }
} }
} }
...@@ -244,7 +271,11 @@ ...@@ -244,7 +271,11 @@
} }
.navless-container { .navless-container {
padding: 65px; // height of footer + bottom padding of email confirmation link padding: 65px 15px; // height of footer + bottom padding of email confirmation link
@media (max-width: $screen-xs-max) {
padding: 0 15px 65px;
}
} }
} }
...@@ -255,6 +286,13 @@ ...@@ -255,6 +286,13 @@
.new_user { .new_user {
position: relative; position: relative;
padding-bottom: 35px; padding-bottom: 35px;
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
.forgot-password {
float: none !important;
margin-top: 5px;
}
}
} }
.move-submit-down { .move-submit-down {
...@@ -263,3 +301,4 @@ ...@@ -263,3 +301,4 @@
bottom: 0; bottom: 0;
} }
} }
...@@ -438,11 +438,18 @@ ...@@ -438,11 +438,18 @@
} }
} }
.merge-request-tabs { .merge-request-tabs-holder {
background-color: #fff; background-color: #fff;
&.affix { &.affix {
top: 100px; top: 100px;
left: 0;
z-index: 9; z-index: 9;
transition: right .15s;
}
&:not(.affix) .container-fluid {
padding-left: 0;
padding-right: 0;
} }
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.diff-file .diff-content { .diff-file .diff-content {
tr.line_holder:hover > td .line_note_link { tr.line_holder:hover > td .line_note_link {
opacity: 1.0; opacity: 1.0;
filter: alpha(opacity=100); filter: alpha(opacity = 100);
} }
} }
......
...@@ -13,9 +13,18 @@ ...@@ -13,9 +13,18 @@
.new_project, .new_project,
.edit-project { .edit-project {
fieldset { fieldset {
&.features .control-label {
font-weight: normal; &.features {
.label-light {
margin-bottom: 0;
}
.help-block {
margin-top: 0;
}
} }
.form-group { .form-group {
...@@ -40,6 +49,7 @@ ...@@ -40,6 +49,7 @@
} }
.input-group > div { .input-group > div {
&:last-child { &:last-child {
padding-right: 0; padding-right: 0;
} }
...@@ -47,6 +57,7 @@ ...@@ -47,6 +57,7 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.input-group > div { .input-group > div {
margin-bottom: 14px; margin-bottom: 14px;
&:last-child { &:last-child {
...@@ -60,6 +71,7 @@ ...@@ -60,6 +71,7 @@
} }
.input-group-addon { .input-group-addon {
&.static-namespace { &.static-namespace {
height: 35px; height: 35px;
border-radius: 3px; border-radius: 3px;
......
...@@ -21,6 +21,10 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -21,6 +21,10 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
def create def create
if params[:user_ids].blank?
return redirect_to(group_group_members_path(@group), alert: 'No users specified.')
end
@group.add_users( @group.add_users(
params[:user_ids].split(','), params[:user_ids].split(','),
params[:access_level], params[:access_level],
......
...@@ -2,8 +2,8 @@ class Import::GitlabProjectsController < Import::BaseController ...@@ -2,8 +2,8 @@ class Import::GitlabProjectsController < Import::BaseController
before_action :verify_gitlab_project_import_enabled before_action :verify_gitlab_project_import_enabled
def new def new
@namespace_id = project_params[:namespace_id] @namespace = Namespace.find(project_params[:namespace_id])
@namespace_name = Namespace.find(project_params[:namespace_id]).name return render_404 unless current_user.can?(:create_projects, @namespace)
@path = project_params[:path] @path = project_params[:path]
end end
......
...@@ -25,6 +25,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -25,6 +25,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end end
def create def create
if params[:user_ids].blank?
return redirect_to(namespace_project_project_members_path(@project.namespace, @project), alert: 'No users or groups specified.')
end
@project.team.add_users( @project.team.add_users(
params[:user_ids].split(','), params[:user_ids].split(','),
params[:access_level], params[:access_level],
...@@ -32,7 +36,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -32,7 +36,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
current_user: current_user current_user: current_user
) )
redirect_to namespace_project_project_members_path(@project.namespace, @project) redirect_to namespace_project_project_members_path(@project.namespace, @project), notice: 'Users were successfully added.'
end end
def update def update
......
...@@ -35,8 +35,10 @@ class LabelsFinder < UnionFinder ...@@ -35,8 +35,10 @@ class LabelsFinder < UnionFinder
end end
def with_title(items) def with_title(items)
items = items.where(title: title) if title return items if title.nil?
items return items.none if title.blank?
items.where(title: title)
end end
def group_id def group_id
...@@ -52,7 +54,7 @@ class LabelsFinder < UnionFinder ...@@ -52,7 +54,7 @@ class LabelsFinder < UnionFinder
end end
def title def title
params[:title].presence || params[:name].presence params[:title] || params[:name]
end end
def project def project
......
...@@ -3,8 +3,8 @@ module Ci ...@@ -3,8 +3,8 @@ module Ci
include TokenAuthenticatable include TokenAuthenticatable
include AfterCommitQueue include AfterCommitQueue
belongs_to :runner, class_name: 'Ci::Runner' belongs_to :runner
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest' belongs_to :trigger_request
belongs_to :erased_by, class_name: 'User' belongs_to :erased_by, class_name: 'User'
serialize :options serialize :options
......
...@@ -7,12 +7,12 @@ module Ci ...@@ -7,12 +7,12 @@ module Ci
self.table_name = 'ci_commits' self.table_name = 'ci_commits'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, foreign_key: :gl_project_id
belongs_to :user belongs_to :user
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id has_many :builds, foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id
validates_presence_of :sha, unless: :importing? validates_presence_of :sha, unless: :importing?
validates_presence_of :ref, unless: :importing? validates_presence_of :ref, unless: :importing?
......
...@@ -6,9 +6,9 @@ module Ci ...@@ -6,9 +6,9 @@ module Ci
AVAILABLE_SCOPES = %w[specific shared active paused online] AVAILABLE_SCOPES = %w[specific shared active paused online]
FORM_EDITABLE = %i[description tag_list active run_untagged locked] FORM_EDITABLE = %i[description tag_list active run_untagged locked]
has_many :builds, class_name: 'Ci::Build' has_many :builds
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject' has_many :runner_projects, dependent: :destroy
has_many :projects, through: :runner_projects, class_name: '::Project', foreign_key: :gl_project_id has_many :projects, through: :runner_projects, foreign_key: :gl_project_id
has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build' has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build'
......
...@@ -2,8 +2,8 @@ module Ci ...@@ -2,8 +2,8 @@ module Ci
class RunnerProject < ActiveRecord::Base class RunnerProject < ActiveRecord::Base
extend Ci::Model extend Ci::Model
belongs_to :runner, class_name: 'Ci::Runner' belongs_to :runner
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, foreign_key: :gl_project_id
validates_uniqueness_of :runner_id, scope: :gl_project_id validates_uniqueness_of :runner_id, scope: :gl_project_id
end end
......
...@@ -4,8 +4,8 @@ module Ci ...@@ -4,8 +4,8 @@ module Ci
acts_as_paranoid acts_as_paranoid
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, foreign_key: :gl_project_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest' has_many :trigger_requests, dependent: :destroy
validates_presence_of :token validates_presence_of :token
validates_uniqueness_of :token validates_uniqueness_of :token
......
...@@ -2,9 +2,9 @@ module Ci ...@@ -2,9 +2,9 @@ module Ci
class TriggerRequest < ActiveRecord::Base class TriggerRequest < ActiveRecord::Base
extend Ci::Model extend Ci::Model
belongs_to :trigger, class_name: 'Ci::Trigger' belongs_to :trigger
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id belongs_to :pipeline, foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build' has_many :builds
serialize :variables serialize :variables
......
...@@ -2,7 +2,7 @@ module Ci ...@@ -2,7 +2,7 @@ module Ci
class Variable < ActiveRecord::Base class Variable < ActiveRecord::Base
extend Ci::Model extend Ci::Model
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, foreign_key: :gl_project_id
validates_uniqueness_of :key, scope: :gl_project_id validates_uniqueness_of :key, scope: :gl_project_id
validates :key, validates :key,
......
...@@ -5,7 +5,7 @@ class CommitStatus < ActiveRecord::Base ...@@ -5,7 +5,7 @@ class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds' self.table_name = 'ci_builds'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, foreign_key: :gl_project_id
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
belongs_to :user belongs_to :user
......
module ProtectedBranchAccess module ProtectedBranchAccess
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do
scope :master, -> { where(access_level: Gitlab::Access::MASTER) }
scope :developer, -> { where(access_level: Gitlab::Access::DEVELOPER) }
end
def humanize def humanize
self.class.human_access_levels[self.access_level] self.class.human_access_levels[self.access_level]
end end
......
...@@ -7,10 +7,8 @@ class Email < ActiveRecord::Base ...@@ -7,10 +7,8 @@ class Email < ActiveRecord::Base
validates :email, presence: true, uniqueness: true, email: true validates :email, presence: true, uniqueness: true, email: true
validate :unique_email, if: ->(email) { email.email_changed? } validate :unique_email, if: ->(email) { email.email_changed? }
before_validation :cleanup_email def email=(value)
write_attribute(:email, value.downcase.strip)
def cleanup_email
self.email = self.email.downcase.strip
end end
def unique_email def unique_email
......
...@@ -6,7 +6,7 @@ class Group < Namespace ...@@ -6,7 +6,7 @@ class Group < Namespace
include AccessRequestable include AccessRequestable
include Referable include Referable
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source
alias_method :members, :group_members alias_method :members, :group_members
has_many :users, through: :group_members has_many :users, through: :group_members
has_many :owners, has_many :owners,
......
...@@ -211,7 +211,13 @@ class Issue < ActiveRecord::Base ...@@ -211,7 +211,13 @@ class Issue < ActiveRecord::Base
note.all_references(current_user, extractor: ext) note.all_references(current_user, extractor: ext)
end end
ext.merge_requests.select { |mr| mr.open? && mr.closes_issue?(self) } merge_requests = ext.merge_requests.select(&:open?)
if merge_requests.any?
ids = MergeRequestsClosingIssues.where(merge_request_id: merge_requests.map(&:id), issue_id: id).pluck(:merge_request_id)
merge_requests.select { |mr| mr.id.in?(ids) }
else
[]
end
end end
def moved? def moved?
......
class GroupMember < Member class GroupMember < Member
SOURCE_TYPE = 'Namespace' SOURCE_TYPE = 'Namespace'
belongs_to :group, class_name: 'Group', foreign_key: 'source_id' belongs_to :group, foreign_key: 'source_id'
# Make sure group member points only to group as it source # Make sure group member points only to group as it source
default_value_for :source_type, SOURCE_TYPE default_value_for :source_type, SOURCE_TYPE
......
...@@ -3,7 +3,7 @@ class ProjectMember < Member ...@@ -3,7 +3,7 @@ class ProjectMember < Member
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
belongs_to :project, class_name: 'Project', foreign_key: 'source_id' belongs_to :project, foreign_key: 'source_id'
# Make sure project member points only to project as it source # Make sure project member points only to project as it source
default_value_for :source_type, SOURCE_TYPE default_value_for :source_type, SOURCE_TYPE
......
...@@ -6,8 +6,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -6,8 +6,8 @@ class MergeRequest < ActiveRecord::Base
include Taskable include Taskable
include Importable include Importable
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :target_project, class_name: "Project"
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" belongs_to :source_project, class_name: "Project"
belongs_to :merge_user, class_name: "User" belongs_to :merge_user, class_name: "User"
has_many :merge_request_diffs, dependent: :destroy has_many :merge_request_diffs, dependent: :destroy
......
...@@ -299,8 +299,10 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -299,8 +299,10 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def keep_around_commits def keep_around_commits
repository.keep_around(start_commit_sha) [repository, merge_request.source_project.repository].each do |repo|
repository.keep_around(head_commit_sha) repo.keep_around(start_commit_sha)
repository.keep_around(base_commit_sha) repo.keep_around(head_commit_sha)
repo.keep_around(base_commit_sha)
end
end end
end end
...@@ -63,11 +63,11 @@ class Project < ActiveRecord::Base ...@@ -63,11 +63,11 @@ class Project < ActiveRecord::Base
alias_attribute :title, :name alias_attribute :title, :name
# Relations # Relations
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User' belongs_to :creator, class_name: 'User'
belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id' belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id'
belongs_to :namespace belongs_to :namespace
has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id' has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event'
has_many :boards, before_add: :validate_board_limit, dependent: :destroy has_many :boards, before_add: :validate_board_limit, dependent: :destroy
# Project services # Project services
...@@ -116,7 +116,7 @@ class Project < ActiveRecord::Base ...@@ -116,7 +116,7 @@ class Project < ActiveRecord::Base
has_many :hooks, dependent: :destroy, class_name: 'ProjectHook' has_many :hooks, dependent: :destroy, class_name: 'ProjectHook'
has_many :protected_branches, dependent: :destroy has_many :protected_branches, dependent: :destroy
has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'ProjectMember' has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source
alias_method :members, :project_members alias_method :members, :project_members
has_many :users, through: :project_members has_many :users, through: :project_members
...@@ -137,7 +137,7 @@ class Project < ActiveRecord::Base ...@@ -137,7 +137,7 @@ class Project < ActiveRecord::Base
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
has_one :project_feature, dependent: :destroy has_one :project_feature, dependent: :destroy
has_many :commit_statuses, dependent: :destroy, class_name: 'CommitStatus', foreign_key: :gl_project_id has_many :commit_statuses, dependent: :destroy, foreign_key: :gl_project_id
has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline', foreign_key: :gl_project_id has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline', foreign_key: :gl_project_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id
......
...@@ -419,6 +419,17 @@ class Repository ...@@ -419,6 +419,17 @@ class Repository
@exists = nil @exists = nil
end end
# expire cache that doesn't depend on repository data (when expiring)
def expire_content_cache
expire_tags_cache
expire_tag_count_cache
expire_branches_cache
expire_branch_count_cache
expire_root_ref_cache
expire_emptiness_caches
expire_exists_cache
end
# Runs code after a repository has been created. # Runs code after a repository has been created.
def after_create def after_create
expire_exists_cache expire_exists_cache
...@@ -434,14 +445,7 @@ class Repository ...@@ -434,14 +445,7 @@ class Repository
expire_cache if exists? expire_cache if exists?
# expire cache that don't depend on repository data (when expiring) expire_content_cache
expire_tags_cache
expire_tag_count_cache
expire_branches_cache
expire_branch_count_cache
expire_root_ref_cache
expire_emptiness_caches
expire_exists_cache
repository_event(:remove_repository) repository_event(:remove_repository)
end end
...@@ -473,14 +477,13 @@ class Repository ...@@ -473,14 +477,13 @@ class Repository
end end
def before_import def before_import
expire_emptiness_caches expire_content_cache
expire_exists_cache
end end
# Runs code after a repository has been forked/imported. # Runs code after a repository has been forked/imported.
def after_import def after_import
expire_emptiness_caches expire_content_cache
expire_exists_cache build_cache
end end
# Runs code after a new commit has been pushed. # Runs code after a new commit has been pushed.
......
...@@ -47,7 +47,7 @@ class User < ActiveRecord::Base ...@@ -47,7 +47,7 @@ class User < ActiveRecord::Base
# #
# Namespace for personal projects # Namespace for personal projects
has_one :namespace, -> { where type: nil }, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace" has_one :namespace, -> { where type: nil }, dependent: :destroy, foreign_key: :owner_id
# Profile # Profile
has_many :keys, dependent: :destroy has_many :keys, dependent: :destroy
...@@ -66,17 +66,17 @@ class User < ActiveRecord::Base ...@@ -66,17 +66,17 @@ class User < ActiveRecord::Base
# Projects # Projects
has_many :groups_projects, through: :groups, source: :projects has_many :groups_projects, through: :groups, source: :projects
has_many :personal_projects, through: :namespace, source: :projects has_many :personal_projects, through: :namespace, source: :projects
has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy, class_name: 'ProjectMember' has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy
has_many :projects, through: :project_members has_many :projects, through: :project_members
has_many :created_projects, foreign_key: :creator_id, class_name: 'Project' has_many :created_projects, foreign_key: :creator_id, class_name: 'Project'
has_many :users_star_projects, dependent: :destroy has_many :users_star_projects, dependent: :destroy
has_many :starred_projects, through: :users_star_projects, source: :project has_many :starred_projects, through: :users_star_projects, source: :project
has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet" has_many :snippets, dependent: :destroy, foreign_key: :author_id
has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :issues, dependent: :destroy, foreign_key: :author_id
has_many :notes, dependent: :destroy, foreign_key: :author_id has_many :notes, dependent: :destroy, foreign_key: :author_id
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id has_many :merge_requests, dependent: :destroy, foreign_key: :author_id
has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event" has_many :events, dependent: :destroy, foreign_key: :author_id
has_many :subscriptions, dependent: :destroy has_many :subscriptions, dependent: :destroy
has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event" has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
...@@ -309,7 +309,7 @@ class User < ActiveRecord::Base ...@@ -309,7 +309,7 @@ class User < ActiveRecord::Base
username username
end end
def to_reference(_from_project = nil) def to_reference(_from_project = nil, _target_project = nil)
"#{self.class.reference_prefix}#{username}" "#{self.class.reference_prefix}#{username}"
end end
......
...@@ -4,7 +4,7 @@ module MergeRequests ...@@ -4,7 +4,7 @@ module MergeRequests
@assignable_issues ||= begin @assignable_issues ||= begin
if current_user == merge_request.author if current_user == merge_request.author
closes_issues.select do |issue| closes_issues.select do |issue|
!issue.assignee_id? && can?(current_user, :admin_issue, issue) !issue.is_a?(ExternalIssue) && !issue.assignee_id? && can?(current_user, :admin_issue, issue)
end end
else else
[] []
......
...@@ -7,9 +7,11 @@ module Notes ...@@ -7,9 +7,11 @@ module Notes
if note.award_emoji? if note.award_emoji?
noteable = note.noteable noteable = note.noteable
if noteable.user_can_award?(current_user, note.award_emoji_name)
todo_service.new_award_emoji(noteable, current_user) todo_service.new_award_emoji(noteable, current_user)
return noteable.create_award_emoji(note.award_emoji_name, current_user) return noteable.create_award_emoji(note.award_emoji_name, current_user)
end end
end
# We execute commands (extracted from `params[:note]`) on the noteable # We execute commands (extracted from `params[:note]`) on the noteable
# **before** we save the note because if the note consists of commands # **before** we save the note because if the note consists of commands
......
# The protected branches API still uses the `developers_can_push` and `developers_can_merge`
# flags for backward compatibility, and so performs translation between that format and the
# internal data model (separate access levels). The translation code is non-trivial, and so
# lives in this service.
module ProtectedBranches
class ApiCreateService < BaseService
def execute
push_access_level =
if params.delete(:developers_can_push)
Gitlab::Access::DEVELOPER
else
Gitlab::Access::MASTER
end
merge_access_level =
if params.delete(:developers_can_merge)
Gitlab::Access::DEVELOPER
else
Gitlab::Access::MASTER
end
@params.merge!(push_access_levels_attributes: [{ access_level: push_access_level }],
merge_access_levels_attributes: [{ access_level: merge_access_level }])
service = ProtectedBranches::CreateService.new(@project, @current_user, @params)
service.execute
end
end
end
# The protected branches API still uses the `developers_can_push` and `developers_can_merge`
# flags for backward compatibility, and so performs translation between that format and the
# internal data model (separate access levels). The translation code is non-trivial, and so
# lives in this service.
module ProtectedBranches
class ApiUpdateService < BaseService
def execute(protected_branch)
@developers_can_push = params.delete(:developers_can_push)
@developers_can_merge = params.delete(:developers_can_merge)
@protected_branch = protected_branch
protected_branch.transaction do
delete_redundant_access_levels
case @developers_can_push
when true
params.merge!(push_access_levels_attributes: [{ access_level: Gitlab::Access::DEVELOPER }])
when false
params.merge!(push_access_levels_attributes: [{ access_level: Gitlab::Access::MASTER }])
end
case @developers_can_merge
when true
params.merge!(merge_access_levels_attributes: [{ access_level: Gitlab::Access::DEVELOPER }])
when false
params.merge!(merge_access_levels_attributes: [{ access_level: Gitlab::Access::MASTER }])
end
service = ProtectedBranches::UpdateService.new(@project, @current_user, @params)
service.execute(protected_branch)
end
end
private
def delete_redundant_access_levels
unless @developers_can_merge.nil?
@protected_branch.merge_access_levels.destroy_all
end
unless @developers_can_push.nil?
@protected_branch.push_access_levels.destroy_all
end
end
end
end
...@@ -75,4 +75,4 @@ ...@@ -75,4 +75,4 @@
- @runners.each do |runner| - @runners.each do |runner|
= render "admin/runners/runner", runner: runner = render "admin/runners/runner", runner: runner
= paginate @runners = paginate @runners, theme: "gitlab"
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
= form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f| = form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f|
= f.hidden_field :runner_id, value: @runner.id = f.hidden_field :runner_id, value: @runner.id
= f.submit 'Enable', class: 'btn btn-xs' = f.submit 'Enable', class: 'btn btn-xs'
= paginate @projects = paginate @projects, theme: "gitlab"
.col-md-6 .col-md-6
%h4 Recent builds served by this Runner %h4 Recent builds served by this Runner
......
...@@ -12,5 +12,5 @@ ...@@ -12,5 +12,5 @@
%label{for: "user_remember_me"} %label{for: "user_remember_me"}
= f.check_box :remember_me = f.check_box :remember_me
%span Remember me %span Remember me
.pull-right .pull-right.forgot-password
= link_to "Forgot your password?", new_password_path(resource_name) = link_to "Forgot your password?", new_password_path(resource_name)
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: 'edit_user show-gl-field-errors' }) do |f| = form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: 'edit_user show-gl-field-errors' }) do |f|
- resource_params = params[resource_name].presence || params - resource_params = params[resource_name].presence || params
= f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0) = f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
.form-group %div
= f.label 'Two-Factor Authentication code', name: :otp_attempt = f.label 'Two-Factor Authentication code', name: :otp_attempt
= f.text_field :otp_attempt, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: 'This field is required.' = f.text_field :otp_attempt, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: 'This field is required.'
%p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes. %p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
......
%ul.new-session-tabs.nav-links.nav-tabs %ul.new-session-tabs.nav-links.nav-tabs{ class: ('custom-provider-tabs' if form_based_providers.any?) }
- if crowd_enabled? - if crowd_enabled?
%li.active %li.active
= link_to "Crowd", "#crowd", 'data-toggle' => 'tab' = link_to "Crowd", "#crowd", 'data-toggle' => 'tab'
......
%ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist'} %ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist'}
%li.active{ role: 'presentation' } %li.active{ role: 'presentation' }
%a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab'} Sign in %a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab'} Sign in
- if signin_enabled? && signup_enabled?
%li{ role: 'presentation'} %li{ role: 'presentation'}
%a{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab'} Register %a{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab'} Register
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
%p %p
Project will be imported as Project will be imported as
%strong %strong
#{@namespace_name}/#{@path} #{@namespace.name}/#{@path}
%p %p
To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here. To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here.
.form-group .form-group
= hidden_field_tag :namespace_id, @namespace_id = hidden_field_tag :namespace_id, @namespace.id
= hidden_field_tag :path, @path = hidden_field_tag :path, @path
= label_tag :file, class: 'control-label' do = label_tag :file, class: 'control-label' do
%span GitLab project export %span GitLab project export
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
":title" => "label.description", ":title" => "label.description",
data: { container: 'body' } } data: { container: 'body' } }
{{ label.title }} {{ label.title }}
%a.has-tooltip{ ":href" => "'/' + issue.assignee.username", %a.has-tooltip{ ":href" => "'#{root_path}' + issue.assignee.username",
":title" => "'Assigned to ' + issue.assignee.name", ":title" => "'Assigned to ' + issue.assignee.name",
"v-if" => "issue.assignee", "v-if" => "issue.assignee",
data: { container: 'body' } } data: { container: 'body' } }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
= button_tag type: 'button', class: "form-control compare-dropdown-toggle js-compare-dropdown", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do = button_tag type: 'button', class: "form-control compare-dropdown-toggle js-compare-dropdown", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do
.dropdown-toggle-text= params[:from] || 'Select branch/tag' .dropdown-toggle-text= params[:from] || 'Select branch/tag'
= render "ref_dropdown" = render "ref_dropdown"
.compare-ellipsis ... .compare-ellipsis.inline ...
.form-group.dropdown.compare-form-group.to.js-compare-to-dropdown .form-group.dropdown.compare-form-group.to.js-compare-to-dropdown
.input-group.inline-input-group .input-group.inline-input-group
%span.input-group-addon to %span.input-group-addon to
......
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
Git Large File Storage Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
- if Gitlab.config.lfs.enabled && current_user.admin? - if Gitlab.config.registry.enabled
.form-group .form-group
.checkbox .checkbox
= f.label :container_registry_enabled do = f.label :container_registry_enabled do
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
.issue-details.issuable-details .issue-details.issuable-details
.detail-page-description.content-block .detail-page-description.content-block{ class: ('hide-bottom-border' unless @issue.description.present? ) }
%h2.title %h2.title
= markdown_field(@issue, :title) = markdown_field(@issue, :title)
- if @issue.description.present? - if @issue.description.present?
......
...@@ -47,7 +47,9 @@ ...@@ -47,7 +47,9 @@
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- if @commits_count.nonzero? - if @commits_count.nonzero?
%ul.merge-request-tabs.nav-links.no-top.no-bottom{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') } .merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
%div{ class: container_class }
%ul.merge-request-tabs.nav-links.no-top.no-bottom
%li.notes-tab %li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
Discussion Discussion
......
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
Most recent commits displayed first Most recent commits displayed first
%ol#commits-list.list-unstyled %ol#commits-list.list-unstyled
= render "projects/commits/commits", project: @merge_request.project = render "projects/commits/commits", project: @merge_request.source_project
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
= link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do = link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do
Delete Delete
.detail-page-description.milestone-detail .detail-page-description.milestone-detail{ class: ('hide-bottom-border' unless @milestone.description.present? ) }
%h2.title %h2.title
= markdown_field(@milestone, :title) = markdown_field(@milestone, :title)
%div %div
......
...@@ -127,6 +127,11 @@ ...@@ -127,6 +127,11 @@
} }
}); });
$('#new_project').submit(function(){
var $path = $('#project_path');
$path.val($path.val().trim());
});
$('#project_path').keyup(function(){ $('#project_path').keyup(function(){
if($(this).val().length !=0) { if($(this).val().length !=0) {
$('.btn_import_gitlab_project').attr('disabled', false); $('.btn_import_gitlab_project').attr('disabled', false);
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
= link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do
= icon('pencil', class: 'link-highlight') = icon('pencil', class: 'link-highlight')
= 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 = 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') = icon('trash-o', class: 'danger-highlight')
.note-body{class: note_editable ? 'js-task-list-container' : ''} .note-body{class: note_editable ? 'js-task-list-container' : ''}
.note-text.md .note-text.md
= preserve do = preserve do
......
...@@ -26,4 +26,4 @@ ...@@ -26,4 +26,4 @@
%h4.underlined-title Available specific runners %h4.underlined-title Available specific runners
%ul.bordered-list.available-specific-runners %ul.bordered-list.available-specific-runners
= render partial: 'runner', collection: @assignable_runners, as: :runner = render partial: 'runner', collection: @assignable_runners, as: :runner
= paginate @assignable_runners = paginate @assignable_runners, theme: "gitlab"
class AdminEmailWorker class AdminEmailWorker
include Sidekiq::Worker include Sidekiq::Worker
include CronjobQueue
sidekiq_options retry: false # this job auto-repeats via sidekiq-cron
def perform def perform
repository_check_failed_count = Project.where(last_repository_check_failed: true).count repository_check_failed_count = Project.where(last_repository_check_failed: true).count
......
class BuildCoverageWorker class BuildCoverageWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :default include BuildQueue
def perform(build_id) def perform(build_id)
Ci::Build.find_by(id: build_id) Ci::Build.find_by(id: build_id)
......
class BuildEmailWorker class BuildEmailWorker
include Sidekiq::Worker include Sidekiq::Worker
include BuildQueue
def perform(build_id, recipients, push_data) def perform(build_id, recipients, push_data)
recipients.each do |recipient| recipients.each do |recipient|
......
class BuildFinishedWorker class BuildFinishedWorker
include Sidekiq::Worker include Sidekiq::Worker
include BuildQueue
def perform(build_id) def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build| Ci::Build.find_by(id: build_id).try do |build|
......
class BuildHooksWorker class BuildHooksWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :default include BuildQueue
def perform(build_id) def perform(build_id)
Ci::Build.find_by(id: build_id) Ci::Build.find_by(id: build_id)
......
class BuildSuccessWorker class BuildSuccessWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :default include BuildQueue
def perform(build_id) def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build| Ci::Build.find_by(id: build_id).try do |build|
......
# This worker clears all cache fields in the database, working in batches. # This worker clears all cache fields in the database, working in batches.
class ClearDatabaseCacheWorker class ClearDatabaseCacheWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
BATCH_SIZE = 1000 BATCH_SIZE = 1000
......
# Concern for setting Sidekiq settings for the various CI build workers.
module BuildQueue
extend ActiveSupport::Concern
included do
sidekiq_options queue: :build
end
end
# Concern that sets various Sidekiq settings for workers executed using a
# cronjob.
module CronjobQueue
extend ActiveSupport::Concern
included do
sidekiq_options queue: :cronjob, retry: false
end
end
# Concern that sets the queue of a Sidekiq worker based on the worker's class
# name/namespace.
module DedicatedSidekiqQueue
extend ActiveSupport::Concern
included do
sidekiq_options queue: name.sub(/Worker\z/, '').underscore.tr('/', '_')
end
end
# Concern for setting Sidekiq settings for the various CI pipeline workers.
module PipelineQueue
extend ActiveSupport::Concern
included do
sidekiq_options queue: :pipeline
end
end
# Concern for setting Sidekiq settings for the various repository check workers.
module RepositoryCheckQueue
extend ActiveSupport::Concern
included do
sidekiq_options queue: :repository_check, retry: false
end
end
class DeleteUserWorker class DeleteUserWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
def perform(current_user_id, delete_user_id, options = {}) def perform(current_user_id, delete_user_id, options = {})
delete_user = User.find(delete_user_id) delete_user = User.find(delete_user_id)
......
class EmailReceiverWorker class EmailReceiverWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
sidekiq_options queue: :incoming_email
def perform(raw) def perform(raw)
return unless Gitlab::IncomingEmail.enabled? return unless Gitlab::IncomingEmail.enabled?
......
class EmailsOnPushWorker class EmailsOnPushWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
sidekiq_options queue: :mailers
attr_reader :email, :skip_premailer attr_reader :email, :skip_premailer
def perform(project_id, recipients, push_data, options = {}) def perform(project_id, recipients, push_data, options = {})
......
class ExpireBuildArtifactsWorker class ExpireBuildArtifactsWorker
include Sidekiq::Worker include Sidekiq::Worker
include CronjobQueue
def perform def perform
Rails.logger.info 'Scheduling removal of build artifacts' Rails.logger.info 'Scheduling removal of build artifacts'
......
class ExpireBuildInstanceArtifactsWorker class ExpireBuildInstanceArtifactsWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
def perform(build_id) def perform(build_id)
build = Ci::Build build = Ci::Build
......
class GitGarbageCollectWorker class GitGarbageCollectWorker
include Sidekiq::Worker include Sidekiq::Worker
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include DedicatedSidekiqQueue
sidekiq_options queue: :gitlab_shell, retry: false sidekiq_options retry: false
def perform(project_id) def perform(project_id)
project = Project.find(project_id) project = Project.find(project_id)
......
class GitlabShellWorker class GitlabShellWorker
include Sidekiq::Worker include Sidekiq::Worker
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include DedicatedSidekiqQueue
sidekiq_options queue: :gitlab_shell
def perform(action, *arg) def perform(action, *arg)
gitlab_shell.send(action, *arg) gitlab_shell.send(action, *arg)
......
class GroupDestroyWorker class GroupDestroyWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
sidekiq_options queue: :default
def perform(group_id, user_id) def perform(group_id, user_id)
begin begin
......
class ImportExportProjectCleanupWorker class ImportExportProjectCleanupWorker
include Sidekiq::Worker include Sidekiq::Worker
include CronjobQueue
sidekiq_options queue: :default
def perform def perform
ImportExportCleanUpService.new.execute ImportExportCleanUpService.new.execute
......
...@@ -3,6 +3,7 @@ require 'socket' ...@@ -3,6 +3,7 @@ require 'socket'
class IrkerWorker class IrkerWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
def perform(project_id, chans, colors, push_data, settings) def perform(project_id, chans, colors, push_data, settings)
project = Project.find(project_id) project = Project.find(project_id)
......
class MergeWorker class MergeWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
sidekiq_options queue: :default
def perform(merge_request_id, current_user_id, params) def perform(merge_request_id, current_user_id, params)
params = params.with_indifferent_access params = params.with_indifferent_access
......
class NewNoteWorker class NewNoteWorker
include Sidekiq::Worker include Sidekiq::Worker
include DedicatedSidekiqQueue
sidekiq_options queue: :default
def perform(note_id, note_params) def perform(note_id, note_params)
note = Note.find(note_id) note = Note.find(note_id)
......
class PipelineHooksWorker class PipelineHooksWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :default include PipelineQueue
def perform(pipeline_id) def perform(pipeline_id)
Ci::Pipeline.find_by(id: pipeline_id) Ci::Pipeline.find_by(id: pipeline_id)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment