Commit b7b3aef4 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge remote-tracking branch 'origin/active-record-each-batch' into...

Merge remote-tracking branch 'origin/active-record-each-batch' into fix/gb/stage-id-reference-background-migration

* origin/active-record-each-batch: (59 commits)
  Added EachBatch for iterating tables in batches
  Extend MR tabs a bit to cover up the avatar holder and collapse icon on scroll
  Update VERSION to 9.4.0-pre.
  Add CHANGELOG
  Fix some N+1 queries in the GET /projects API
  Don't show auxiliary blob viewer for README when there is no wiki
  Improve & fix the performance bar UI and behavior
  Remove orphaned haml files
  Fixed CHANGELOG.md for 9.3.4 release
  Add table for merge request commits
  34727 Remove two columned layout from project member settings
  Just draw :legacy_builds
  Re-enable polling for environments
  Cleanup minor UX issues in the performance dashboard
  Upgrade GitLab Workhorse to v2.3.0
  Added test for the chart legend
  Use correct field for label name, fix default for unit to be blank
  Fix shorter route helpers in production environment
  Encode certificate-authority-data in base64
  Revert "Merge branch 'winh-mr-widget-no-pipeline' into 'master'"
  ...
parents af0eeefc 5f9c8458
...@@ -12,7 +12,7 @@ entry. ...@@ -12,7 +12,7 @@ entry.
## 9.3.4 (2017-07-03) ## 9.3.4 (2017-07-03)
- No changes. - Update gitlab-shell to 5.1.1 !12615
## 9.3.3 (2017-06-30) ## 9.3.3 (2017-06-30)
......
9.3.0-pre 9.4.0-pre
...@@ -56,6 +56,8 @@ import GfmAutoComplete from './gfm_auto_complete'; ...@@ -56,6 +56,8 @@ import GfmAutoComplete from './gfm_auto_complete';
import ShortcutsBlob from './shortcuts_blob'; import ShortcutsBlob from './shortcuts_blob';
import initSettingsPanels from './settings_panels'; import initSettingsPanels from './settings_panels';
import initExperimentalFlags from './experimental_flags'; import initExperimentalFlags from './experimental_flags';
import OAuthRememberMe from './oauth_remember_me';
import PerformanceBar from './performance_bar';
(function() { (function() {
var Dispatcher; var Dispatcher;
...@@ -127,6 +129,7 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -127,6 +129,7 @@ import initExperimentalFlags from './experimental_flags';
case 'sessions:new': case 'sessions:new':
new UsernameValidator(); new UsernameValidator();
new ActiveTabMemoizer(); new ActiveTabMemoizer();
new OAuthRememberMe({ container: $(".omniauth-container") }).bindEvents();
break; break;
case 'projects:boards:show': case 'projects:boards:show':
case 'projects:boards:index': case 'projects:boards:index':
...@@ -513,6 +516,10 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -513,6 +516,10 @@ import initExperimentalFlags from './experimental_flags';
if (!shortcut_handler) { if (!shortcut_handler) {
new Shortcuts(); new Shortcuts();
} }
if (document.querySelector('#peek')) {
new PerformanceBar({ container: '#peek' });
}
}; };
Dispatcher.prototype.initSearch = function() { Dispatcher.prototype.initSearch = function() {
......
...@@ -105,9 +105,9 @@ ...@@ -105,9 +105,9 @@
this.measurements = measurements.small; this.measurements = measurements.small;
} }
this.data = query.result[0].values; this.data = query.result[0].values;
this.unitOfDisplay = query.unit || 'N/A'; this.unitOfDisplay = query.unit || '';
this.yAxisLabel = this.columnData.y_label || 'Values'; this.yAxisLabel = this.columnData.y_label || 'Values';
this.legendTitle = query.legend || 'Average'; this.legendTitle = query.label || 'Average';
this.graphWidth = this.$refs.baseSvg.clientWidth - this.graphWidth = this.$refs.baseSvg.clientWidth -
this.margin.left - this.margin.right; this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom; this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
...@@ -159,12 +159,12 @@ ...@@ -159,12 +159,12 @@
const xAxis = d3.svg.axis() const xAxis = d3.svg.axis()
.scale(axisXScale) .scale(axisXScale)
.ticks(measurements.ticks) .ticks(measurements.xTicks)
.orient('bottom'); .orient('bottom');
const yAxis = d3.svg.axis() const yAxis = d3.svg.axis()
.scale(this.yScale) .scale(this.yScale)
.ticks(measurements.ticks) .ticks(measurements.yTicks)
.orient('left'); .orient('left');
d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis); d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis);
...@@ -172,8 +172,12 @@ ...@@ -172,8 +172,12 @@
const width = this.graphWidth; const width = this.graphWidth;
d3.select(this.$refs.baseSvg).select('.y-axis').call(yAxis) d3.select(this.$refs.baseSvg).select('.y-axis').call(yAxis)
.selectAll('.tick') .selectAll('.tick')
.each(function createTickLines() { .each(function createTickLines(d, i) {
d3.select(this).select('line').attr('x2', width); if (i > 0) {
d3.select(this).select('line')
.attr('x2', width)
.attr('class', 'axis-tick');
} // Avoid adding the class to the first tick, to prevent coloring
}); // This will select all of the ticks once they're rendered }); // This will select all of the ticks once they're rendered
this.xScale = d3.time.scale() this.xScale = d3.time.scale()
......
...@@ -87,14 +87,14 @@ ...@@ -87,14 +87,14 @@
</rect> </rect>
<text <text
class="text-metric text-metric-bold" class="text-metric text-metric-bold"
x="8" x="16"
y="35" y="35"
transform="translate(-5, 20)"> transform="translate(-5, 20)">
{{formatTime}} {{formatTime}}
</text> </text>
<text <text
class="text-metric-date" class="text-metric"
x="8" x="16"
y="15" y="15"
transform="translate(-5, 20)"> transform="translate(-5, 20)">
{{formatDate}} {{formatDate}}
......
...@@ -109,13 +109,13 @@ ...@@ -109,13 +109,13 @@
</text> </text>
<rect <rect
class="rect-axis-text" class="rect-axis-text"
:x="xPosition + 50" :x="xPosition + 60"
:y="graphHeight - 80" :y="graphHeight - 80"
width="50" width="35"
height="50"> height="50">
</rect> </rect>
<text <text
class="label-axis-text" class="label-axis-text x-label-text"
:x="xPosition + 60" :x="xPosition + 60"
:y="yPosition" :y="yPosition"
dy=".35em"> dy=".35em">
...@@ -131,13 +131,13 @@ ...@@ -131,13 +131,13 @@
<text <text
class="text-metric-title" class="text-metric-title"
x="50" x="50"
:y="graphHeight - 40"> :y="graphHeight - 25">
{{legendTitle}} {{legendTitle}}
</text> </text>
<text <text
class="text-metric-usage" class="text-metric-usage"
x="50" x="50"
:y="graphHeight - 25"> :y="graphHeight - 10">
{{metricUsage}} {{metricUsage}}
</text> </text>
</g> </g>
......
...@@ -8,14 +8,14 @@ export default { ...@@ -8,14 +8,14 @@ export default {
}, },
legends: { legends: {
width: 15, width: 15,
height: 30, height: 25,
}, },
backgroundLegend: { backgroundLegend: {
width: 30, width: 30,
height: 50, height: 50,
}, },
axisLabelLineOffset: -20, axisLabelLineOffset: -20,
legendOffset: 52, legendOffset: 35,
}, },
large: { // This covers both md and lg screen sizes large: { // This covers both md and lg screen sizes
margin: { margin: {
...@@ -26,14 +26,15 @@ export default { ...@@ -26,14 +26,15 @@ export default {
}, },
legends: { legends: {
width: 20, width: 20,
height: 35, height: 30,
}, },
backgroundLegend: { backgroundLegend: {
width: 30, width: 30,
height: 150, height: 150,
}, },
axisLabelLineOffset: 20, axisLabelLineOffset: 20,
legendOffset: 55, legendOffset: 38,
}, },
ticks: 3, xTicks: 8,
yTicks: 3,
}; };
/**
* OAuth-based login buttons have a separate "remember me" checkbox.
*
* Toggling this checkbox adds/removes a `remember_me` parameter to the
* login buttons' href, which is passed on to the omniauth callback.
**/
export default class OAuthRememberMe {
constructor(opts = {}) {
this.container = opts.container || '';
this.loginLinkSelector = '.oauth-login';
}
bindEvents() {
$('#remember_me', this.container).on('click', this.toggleRememberMe);
}
// eslint-disable-next-line class-methods-use-this
toggleRememberMe(event) {
const rememberMe = $(event.target).is(':checked');
$('.oauth-login', this.container).each((i, element) => {
const href = $(element).attr('href');
if (rememberMe) {
$(element).attr('href', `${href}?remember_me=1`);
} else {
$(element).attr('href', href.replace('?remember_me=1', ''));
}
});
}
}
import 'vendor/peek';
import 'vendor/peek.performance_bar';
$(document).on('click', '#peek-show-queries', (e) => {
e.preventDefault();
$('.peek-rblineprof-modal').hide();
const $modal = $('#modal-peek-pg-queries');
if ($modal.length) {
$modal.modal('toggle');
}
});
$(document).on('click', '.js-lineprof-file', (e) => {
e.preventDefault();
$(e.target).parents('.peek-rblineprof-file').find('.data').toggle();
});
import 'vendor/peek';
import 'vendor/peek.performance_bar';
export default class PerformanceBar {
constructor(opts) {
if (!PerformanceBar.singleton) {
this.init(opts);
PerformanceBar.singleton = this;
}
return PerformanceBar.singleton;
}
init(opts) {
const $container = $(opts.container);
this.$sqlProfileLink = $container.find('.js-toggle-modal-peek-sql');
this.$sqlProfileModal = $container.find('#modal-peek-pg-queries');
this.$lineProfileLink = $container.find('.js-toggle-modal-peek-line-profile');
this.$lineProfileModal = $('#modal-peek-line-profile');
this.initEventListeners();
this.showModalOnLoad();
}
initEventListeners() {
this.$sqlProfileLink.on('click', () => this.handleSQLProfileLink());
this.$lineProfileLink.on('click', e => this.handleLineProfileLink(e));
$(document).on('click', '.js-lineprof-file', PerformanceBar.toggleLineProfileFile);
}
showModalOnLoad() {
// When a lineprofiler query-string param is present, we show the line
// profiler modal upon page load
if (/lineprofiler/.test(window.location.search)) {
PerformanceBar.toggleModal(this.$lineProfileModal);
}
}
handleSQLProfileLink() {
PerformanceBar.toggleModal(this.$sqlProfileModal);
}
handleLineProfileLink(e) {
const lineProfilerParameter = gl.utils.getParameterValues('lineprofiler');
const lineProfilerParameterRegex = new RegExp(`lineprofiler=${lineProfilerParameter[0]}`);
const shouldToggleModal = lineProfilerParameter.length > 0 &&
lineProfilerParameterRegex.test(e.currentTarget.href);
if (shouldToggleModal) {
e.preventDefault();
PerformanceBar.toggleModal(this.$lineProfileModal);
}
}
static toggleModal($modal) {
if ($modal.length) {
$modal.modal('toggle');
}
}
static toggleLineProfileFile(e) {
$(e.currentTarget).parents('.peek-rblineprof-file').find('.data').toggle();
}
}
...@@ -17,9 +17,6 @@ export default { ...@@ -17,9 +17,6 @@ export default {
return hasCI && !ciStatus; return hasCI && !ciStatus;
}, },
hasPipeline() {
return Object.keys(this.mr.pipeline || {}).length > 0;
},
svg() { svg() {
return statusIconEntityMap.icon_status_failed; return statusIconEntityMap.icon_status_failed;
}, },
...@@ -33,11 +30,7 @@ export default { ...@@ -33,11 +30,7 @@ export default {
template: ` template: `
<div class="mr-widget-heading"> <div class="mr-widget-heading">
<div class="ci-widget"> <div class="ci-widget">
<template v-if="!hasPipeline"> <template v-if="hasCIError">
<i class="fa fa-spinner fa-spin append-right-10" aria-hidden="true"></i>
Waiting for pipeline...
</template>
<template v-else-if="hasCIError">
<div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error"> <div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error">
<span class="js-icon-link icon-link"> <span class="js-icon-link icon-link">
<span <span
......
...@@ -21,3 +21,9 @@ body.modal-open { ...@@ -21,3 +21,9 @@ body.modal-open {
width: 860px; width: 860px;
} }
} }
@media (min-width: $screen-lg-min) {
.modal-full {
width: 98%;
}
}
...@@ -594,3 +594,15 @@ Convdev Index ...@@ -594,3 +594,15 @@ Convdev Index
$color-high-score: $green-400; $color-high-score: $green-400;
$color-average-score: $orange-400; $color-average-score: $orange-400;
$color-low-score: $red-400; $color-low-score: $red-400;
/*
Performance Bar
*/
$perf-bar-text: #999;
$perf-bar-production: #222;
$perf-bar-staging: #291430;
$perf-bar-development: #4c1210;
$perf-bar-bucket-bg: #111;
$perf-bar-bucket-color: #ccc;
$perf-bar-bucket-box-shadow-from: rgba($white-light, .2);
$perf-bar-bucket-box-shadow-to: rgba($black, .25);
...@@ -187,8 +187,7 @@ ...@@ -187,8 +187,7 @@
} }
.text-metric { .text-metric {
font-weight: 600; font-size: 12px;
font-size: 14px;
} }
.selected-metric-line { .selected-metric-line {
...@@ -232,10 +231,6 @@ ...@@ -232,10 +231,6 @@
width: 100%; width: 100%;
padding: 0; padding: 0;
padding-bottom: 100%; padding-bottom: 100%;
.text-metric-bold {
font-weight: 600;
}
} }
.prometheus-svg-container > svg { .prometheus-svg-container > svg {
...@@ -250,6 +245,10 @@ ...@@ -250,6 +245,10 @@
stroke-width: 0; stroke-width: 0;
} }
.text-metric-bold {
font-weight: 600;
}
.label-axis-text, .label-axis-text,
.text-metric-usage { .text-metric-usage {
fill: $black; fill: $black;
...@@ -269,6 +268,15 @@ ...@@ -269,6 +268,15 @@
font-size: 12px; font-size: 12px;
} }
.y-label-text,
.x-label-text {
fill: $gray-darkest;
}
.axis-tick {
stroke: $gray-darker;
}
@media (max-width: $screen-sm-max) { @media (max-width: $screen-sm-max) {
.label-axis-text, .label-axis-text,
.text-metric-usage, .text-metric-usage,
......
...@@ -731,11 +731,11 @@ ...@@ -731,11 +731,11 @@
.merge-request-tabs-holder { .merge-request-tabs-holder {
top: $header-height; top: $header-height;
z-index: 100; z-index: 200;
background-color: $white-light; background-color: $white-light;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
@media(min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
position: sticky; position: sticky;
position: -webkit-sticky; position: -webkit-sticky;
} }
...@@ -770,6 +770,12 @@ ...@@ -770,6 +770,12 @@
max-width: $limited-layout-width; max-width: $limited-layout-width;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
.inner-page-scroll-tabs {
background-color: $white-light;
margin-left: -$gl-padding;
padding-left: $gl-padding;
}
} }
} }
......
//= require peek/views/performance_bar @import "framework/variables";
//= require peek/views/rblineprof @import "peek/views/performance_bar";
@import "peek/views/rblineprof";
header.navbar-gitlab.with-peek {
top: 35px;
}
#peek { #peek {
height: 35px; height: 35px;
background: #000; background: $black;
line-height: 35px; line-height: 35px;
color: #999; color: $perf-bar-text;
&.disabled { &.disabled {
display: none; display: none;
} }
&.production { &.production {
background-color: #222; background-color: $perf-bar-production;
} }
&.staging { &.staging {
background-color: #291430; background-color: $perf-bar-staging;
} }
&.development { &.development {
background-color: #4c1210; background-color: $perf-bar-development;
} }
.wrapper { .wrapper {
width: 800px; width: 1000px;
margin: 0 auto; margin: 0 auto;
} }
// UI Elements // UI Elements
.bucket { .bucket {
background: #111; background: $perf-bar-bucket-bg;
display: inline-block; display: inline-block;
padding: 4px 6px; padding: 4px 6px;
font-family: Consolas, "Liberation Mono", Courier, monospace; font-family: Consolas, "Liberation Mono", Courier, monospace;
line-height: 1; line-height: 1;
color: #ccc; color: $perf-bar-bucket-color;
border-radius: 3px; border-radius: 3px;
box-shadow: 0 1px 0 rgba(255,255,255,.2), inset 0 1px 2px rgba(0,0,0,.25); box-shadow: 0 1px 0 $perf-bar-bucket-box-shadow-from, inset 0 1px 2px $perf-bar-bucket-box-shadow-to;
.hidden { .hidden {
display: none; display: none;
...@@ -53,12 +50,14 @@ header.navbar-gitlab.with-peek { ...@@ -53,12 +50,14 @@ header.navbar-gitlab.with-peek {
} }
strong { strong {
color: #fff; color: $white-light;
} }
table { table {
color: $black;
strong { strong {
color: #000; color: $black;
} }
} }
...@@ -90,5 +89,15 @@ header.navbar-gitlab.with-peek { ...@@ -90,5 +89,15 @@ header.navbar-gitlab.with-peek {
} }
#modal-peek-pg-queries-content { #modal-peek-pg-queries-content {
color: #000; color: $black;
}
.peek-rblineprof-file {
pre.duration {
width: 280px;
}
.data {
overflow: visible;
}
} }
...@@ -47,7 +47,7 @@ module IssuableCollections ...@@ -47,7 +47,7 @@ module IssuableCollections
end end
def merge_requests_collection def merge_requests_collection
merge_requests_finder.execute.preload(:source_project, :target_project, :author, :assignee, :labels, :milestone, :merge_request_diff, :head_pipeline, target_project: :namespace) merge_requests_finder.execute.preload(:source_project, :target_project, :author, :assignee, :labels, :milestone, :head_pipeline, target_project: :namespace, merge_request_diff: :merge_request_diff_commits)
end end
def issues_finder def issues_finder
......
class OmniauthCallbacksController < Devise::OmniauthCallbacksController class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include AuthenticatesWithTwoFactor include AuthenticatesWithTwoFactor
include Devise::Controllers::Rememberable
protect_from_forgery except: [:kerberos, :saml, :cas3] protect_from_forgery except: [:kerberos, :saml, :cas3]
...@@ -115,8 +116,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -115,8 +116,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
if @user.persisted? && @user.valid? if @user.persisted? && @user.valid?
log_audit_event(@user, with: oauth['provider']) log_audit_event(@user, with: oauth['provider'])
if @user.two_factor_enabled? if @user.two_factor_enabled?
params[:remember_me] = '1' if remember_me?
prompt_for_two_factor(@user) prompt_for_two_factor(@user)
else else
remember_me(@user) if remember_me?
sign_in_and_redirect(@user) sign_in_and_redirect(@user)
end end
else else
...@@ -147,4 +150,9 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -147,4 +150,9 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
AuditEventService.new(user, user, options) AuditEventService.new(user, user, options)
.for_authentication.security_event .for_authentication.security_event
end end
def remember_me?
request_params = request.env['omniauth.params']
(request_params['remember_me'] == '1') if request_params.present?
end
end end
...@@ -15,6 +15,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -15,6 +15,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.json do format.json do
Gitlab::PollingInterval.set_header(response, interval: 3_000)
render json: { render json: {
environments: EnvironmentSerializer environments: EnvironmentSerializer
.new(project: @project, current_user: @current_user) .new(project: @project, current_user: @current_user)
......
...@@ -14,7 +14,7 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -14,7 +14,7 @@ class Projects::VariablesController < Projects::ApplicationController
def update def update
@variable = @project.variables.find(params[:id]) @variable = @project.variables.find(params[:id])
if @variable.update_attributes(project_params) if @variable.update_attributes(variable_params)
redirect_to project_variables_path(project), notice: 'Variable was successfully updated.' redirect_to project_variables_path(project), notice: 'Variable was successfully updated.'
else else
render action: "show" render action: "show"
...@@ -22,9 +22,9 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -22,9 +22,9 @@ class Projects::VariablesController < Projects::ApplicationController
end end
def create def create
@variable = Ci::Variable.new(project_params) @variable = @project.variables.new(variable_params)
if @variable.valid? && @project.variables << @variable if @variable.save
flash[:notice] = 'Variables were successfully updated.' flash[:notice] = 'Variables were successfully updated.'
redirect_to project_settings_ci_cd_path(project) redirect_to project_settings_ci_cd_path(project)
else else
...@@ -43,8 +43,11 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -43,8 +43,11 @@ class Projects::VariablesController < Projects::ApplicationController
private private
def project_params def variable_params
params.require(:variable) params.require(:variable).permit(*variable_params_attributes)
.permit([:id, :key, :value, :protected, :_destroy]) end
def variable_params_attributes
%i[id key value protected _destroy]
end end
end end
...@@ -28,7 +28,14 @@ class ProjectsFinder < UnionFinder ...@@ -28,7 +28,14 @@ class ProjectsFinder < UnionFinder
end end
def execute def execute
collection = init_collection user = params.delete(:user)
collection =
if user
PersonalProjectsFinder.new(user).execute(current_user)
else
init_collection
end
collection = by_ids(collection) collection = by_ids(collection)
collection = by_personal(collection) collection = by_personal(collection)
collection = by_starred(collection) collection = by_starred(collection)
......
...@@ -23,7 +23,6 @@ module NavHelper ...@@ -23,7 +23,6 @@ module NavHelper
def nav_header_class def nav_header_class
class_name = '' class_name = ''
class_name << " with-horizontal-nav" if defined?(nav) && nav class_name << " with-horizontal-nav" if defined?(nav) && nav
class_name << " with-peek" if peek_enabled?
class_name class_name
end end
......
module PerformanceBarHelper
# This is a hack since using `alias_method :performance_bar_enabled?, :peek_enabled?`
# in WithPerformanceBar breaks tests (but works in the browser).
def performance_bar_enabled?
peek_enabled?
end
end
...@@ -10,5 +10,5 @@ class Appearance < ActiveRecord::Base ...@@ -10,5 +10,5 @@ class Appearance < ActiveRecord::Base
mount_uploader :logo, AttachmentUploader mount_uploader :logo, AttachmentUploader
mount_uploader :header_logo, AttachmentUploader mount_uploader :header_logo, AttachmentUploader
has_many :uploads, as: :model, dependent: :destroy has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
end end
...@@ -13,13 +13,13 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -13,13 +13,13 @@ class ApplicationSetting < ActiveRecord::Base
[\r\n] # any number of newline characters [\r\n] # any number of newline characters
}x }x
serialize :restricted_visibility_levels # rubocop:disable Cop/ActiverecordSerialize serialize :restricted_visibility_levels # rubocop:disable Cop/ActiveRecordSerialize
serialize :import_sources # rubocop:disable Cop/ActiverecordSerialize serialize :import_sources # rubocop:disable Cop/ActiveRecordSerialize
serialize :disabled_oauth_sign_in_sources, Array # rubocop:disable Cop/ActiverecordSerialize serialize :disabled_oauth_sign_in_sources, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :domain_whitelist, Array # rubocop:disable Cop/ActiverecordSerialize serialize :domain_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :domain_blacklist, Array # rubocop:disable Cop/ActiverecordSerialize serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :repository_storages # rubocop:disable Cop/ActiverecordSerialize serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize
serialize :sidekiq_throttling_queues, Array # rubocop:disable Cop/ActiverecordSerialize serialize :sidekiq_throttling_queues, Array # rubocop:disable Cop/ActiveRecordSerialize
cache_markdown_field :sign_in_text cache_markdown_field :sign_in_text
cache_markdown_field :help_page_text cache_markdown_field :help_page_text
......
class AuditEvent < ActiveRecord::Base class AuditEvent < ActiveRecord::Base
serialize :details, Hash # rubocop:disable Cop/ActiverecordSerialize serialize :details, Hash # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :user, foreign_key: :author_id belongs_to :user, foreign_key: :author_id
......
...@@ -10,5 +10,11 @@ module BlobViewer ...@@ -10,5 +10,11 @@ module BlobViewer
def visible_to?(current_user) def visible_to?(current_user)
can?(current_user, :read_wiki, project) can?(current_user, :read_wiki, project)
end end
def render_error
return if project.has_external_wiki? || (project.wiki_enabled? && project.wiki.has_home_page?)
:no_wiki
end
end end
end end
class Board < ActiveRecord::Base class Board < ActiveRecord::Base
belongs_to :project belongs_to :project
has_many :lists, -> { order(:list_type, :position) }, dependent: :delete_all has_many :lists, -> { order(:list_type, :position) }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
validates :project, presence: true validates :project, presence: true
......
...@@ -19,8 +19,8 @@ module Ci ...@@ -19,8 +19,8 @@ module Ci
) )
end end
serialize :options # rubocop:disable Cop/ActiverecordSerialize serialize :options # rubocop:disable Cop/ActiveRecordSerialize
serialize :yaml_variables, Gitlab::Serializer::Ci::Variables # rubocop:disable Cop/ActiverecordSerialize serialize :yaml_variables, Gitlab::Serializer::Ci::Variables # rubocop:disable Cop/ActiveRecordSerialize
delegate :name, to: :project, prefix: true delegate :name, to: :project, prefix: true
...@@ -186,6 +186,12 @@ module Ci ...@@ -186,6 +186,12 @@ module Ci
# Variables whose value does not depend on environment # Variables whose value does not depend on environment
def simple_variables def simple_variables
variables(environment: nil)
end
# All variables, including those dependent on environment, which could
# contain unexpanded variables.
def variables(environment: persisted_environment)
variables = predefined_variables variables = predefined_variables
variables += project.predefined_variables variables += project.predefined_variables
variables += pipeline.predefined_variables variables += pipeline.predefined_variables
...@@ -194,15 +200,11 @@ module Ci ...@@ -194,15 +200,11 @@ module Ci
variables += project.deployment_variables if has_environment? variables += project.deployment_variables if has_environment?
variables += yaml_variables variables += yaml_variables
variables += user_variables variables += user_variables
variables += project.secret_variables_for(ref).map(&:to_runner_variable) variables += secret_variables(environment: environment)
variables += trigger_request.user_variables if trigger_request variables += trigger_request.user_variables if trigger_request
variables variables += persisted_environment_variables if environment
end
# All variables, including those dependent on environment, which could variables
# contain unexpanded variables.
def variables
simple_variables.concat(persisted_environment_variables)
end end
def merge_request def merge_request
...@@ -216,7 +218,7 @@ module Ci ...@@ -216,7 +218,7 @@ module Ci
.reorder(iid: :desc) .reorder(iid: :desc)
merge_requests.find do |merge_request| merge_requests.find do |merge_request|
merge_request.commits_sha.include?(pipeline.sha) merge_request.commit_shas.include?(pipeline.sha)
end end
end end
end end
...@@ -370,6 +372,11 @@ module Ci ...@@ -370,6 +372,11 @@ module Ci
] ]
end end
def secret_variables(environment: persisted_environment)
project.secret_variables_for(ref: ref, environment: environment)
.map(&:to_runner_variable)
end
def steps def steps
[Gitlab::Ci::Build::Step.from_commands(self), [Gitlab::Ci::Build::Step.from_commands(self),
Gitlab::Ci::Build::Step.from_after_script(self)].compact Gitlab::Ci::Build::Step.from_after_script(self)].compact
......
...@@ -14,7 +14,7 @@ module Ci ...@@ -14,7 +14,7 @@ module Ci
has_many :stages has_many :stages
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, foreign_key: :commit_id has_many :builds, foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
# Merge requests for which the current pipeline is running against # Merge requests for which the current pipeline is running against
# the merge request's latest commit. # the merge request's latest commit.
......
...@@ -8,7 +8,7 @@ module Ci ...@@ -8,7 +8,7 @@ module Ci
FORM_EDITABLE = %i[description tag_list active run_untagged locked].freeze FORM_EDITABLE = %i[description tag_list active run_untagged locked].freeze
has_many :builds has_many :builds
has_many :runner_projects, dependent: :destroy has_many :runner_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :projects, through: :runner_projects has_many :projects, through: :runner_projects
has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build' has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build'
......
...@@ -6,7 +6,7 @@ module Ci ...@@ -6,7 +6,7 @@ module Ci
belongs_to :pipeline, foreign_key: :commit_id belongs_to :pipeline, foreign_key: :commit_id
has_many :builds has_many :builds
serialize :variables # rubocop:disable Cop/ActiverecordSerialize serialize :variables # rubocop:disable Cop/ActiveRecordSerialize
def user_variables def user_variables
return [] unless variables return [] unless variables
......
...@@ -2,7 +2,7 @@ module Awardable ...@@ -2,7 +2,7 @@ module Awardable
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
has_many :award_emoji, -> { includes(:user).order(:id) }, as: :awardable, dependent: :destroy has_many :award_emoji, -> { includes(:user).order(:id) }, as: :awardable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
if self < Participable if self < Participable
# By default we always load award_emoji user association # By default we always load award_emoji user association
......
...@@ -78,7 +78,7 @@ module CacheMarkdownField ...@@ -78,7 +78,7 @@ module CacheMarkdownField
def cached_html_up_to_date?(markdown_field) def cached_html_up_to_date?(markdown_field)
html_field = cached_markdown_fields.html_field(markdown_field) html_field = cached_markdown_fields.html_field(markdown_field)
cached = !cached_html_for(markdown_field).nil? && !__send__(markdown_field).nil? cached = cached_html_for(markdown_field).present? && __send__(markdown_field).present?
return false unless cached return false unless cached
markdown_changed = attribute_changed?(markdown_field) || false markdown_changed = attribute_changed?(markdown_field) || false
......
module EachBatch
extend ActiveSupport::Concern
module ClassMethods
# Iterates over the rows in a relation in batches, similar to Rails'
# `in_batches` but in a more efficient way.
#
# Unlike `in_batches` provided by Rails this method does not support a
# custom start/end range, nor does it provide support for the `load:`
# keyword argument.
#
# This method will yield an ActiveRecord::Relation to the supplied block, or
# return an Enumerator if no block is given.
#
# Example:
#
# User.each_batch do |relation|
# relation.update_all(updated_at: Time.now)
# end
#
# This will produce SQL queries along the lines of:
#
# User Load (0.7ms) SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 41654) ORDER BY "users"."id" ASC LIMIT 1 OFFSET 1000
# (0.7ms) SELECT COUNT(*) FROM "users" WHERE ("users"."id" >= 41654) AND ("users"."id" < 42687)
#
# of - The number of rows to retrieve per batch.
def each_batch(of: 1000)
start = except(:select)
.select(primary_key)
.reorder(primary_key => :asc)
.take
return unless start
start_id = start[primary_key]
arel_table = self.arel_table
loop do
stop = except(:select)
.select(primary_key)
.where(arel_table[primary_key].gteq(start_id))
.reorder(primary_key => :asc)
.offset(of)
.limit(1)
.take
relation = where(arel_table[primary_key].gteq(start_id))
if stop
stop_id = stop[primary_key]
start_id = stop_id
relation = relation.where(arel_table[primary_key].lt(stop_id))
end
# Any ORDER BYs are useless for this relation and can lead to less
# efficient UPDATE queries, hence we get rid of it.
yield relation.except(:order)
break unless stop
end
end
end
end
...@@ -30,7 +30,7 @@ module Issuable ...@@ -30,7 +30,7 @@ module Issuable
belongs_to :updated_by, class_name: "User" belongs_to :updated_by, class_name: "User"
belongs_to :last_edited_by, class_name: 'User' belongs_to :last_edited_by, class_name: 'User'
belongs_to :milestone belongs_to :milestone
has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :destroy do has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :destroy do # rubocop:disable Cop/ActiveRecordDependent
def authors_loaded? def authors_loaded?
# We check first if we're loaded to not load unnecessarily. # We check first if we're loaded to not load unnecessarily.
loaded? && to_a.all? { |note| note.association(:author).loaded? } loaded? && to_a.all? { |note| note.association(:author).loaded? }
...@@ -42,9 +42,9 @@ module Issuable ...@@ -42,9 +42,9 @@ module Issuable
end end
end end
has_many :label_links, as: :target, dependent: :destroy has_many :label_links, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :labels, through: :label_links has_many :labels, through: :label_links
has_many :todos, as: :target, dependent: :destroy has_many :todos, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :metrics has_one :metrics
......
...@@ -17,7 +17,7 @@ module ProtectedRef ...@@ -17,7 +17,7 @@ module ProtectedRef
class_methods do class_methods do
def protected_ref_access_levels(*types) def protected_ref_access_levels(*types)
types.each do |type| types.each do |type|
has_many :"#{type}_access_levels", dependent: :destroy has_many :"#{type}_access_levels", dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
validates :"#{type}_access_levels", length: { is: 1, message: "are restricted to a single instance per #{self.model_name.human}." } validates :"#{type}_access_levels", length: { is: 1, message: "are restricted to a single instance per #{self.model_name.human}." }
......
...@@ -4,8 +4,8 @@ module Routable ...@@ -4,8 +4,8 @@ module Routable
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
has_one :route, as: :source, autosave: true, dependent: :destroy has_one :route, as: :source, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :redirect_routes, as: :source, autosave: true, dependent: :destroy has_many :redirect_routes, as: :source, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
validates_associated :route validates_associated :route
validates :route, presence: true validates :route, presence: true
......
...@@ -8,7 +8,7 @@ module Spammable ...@@ -8,7 +8,7 @@ module Spammable
end end
included do included do
has_one :user_agent_detail, as: :subject, dependent: :destroy has_one :user_agent_detail, as: :subject, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
attr_accessor :spam attr_accessor :spam
attr_accessor :spam_log attr_accessor :spam_log
......
...@@ -9,7 +9,7 @@ module Subscribable ...@@ -9,7 +9,7 @@ module Subscribable
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
has_many :subscriptions, dependent: :destroy, as: :subscribable has_many :subscriptions, dependent: :destroy, as: :subscribable # rubocop:disable Cop/ActiveRecordDependent
end end
def subscribed?(user, project = nil) def subscribed?(user, project = nil)
......
...@@ -18,7 +18,7 @@ module TimeTrackable ...@@ -18,7 +18,7 @@ module TimeTrackable
validates :time_estimate, numericality: { message: 'has an invalid format' }, allow_nil: false validates :time_estimate, numericality: { message: 'has an invalid format' }, allow_nil: false
validate :check_negative_time_spent validate :check_negative_time_spent
has_many :timelogs, dependent: :destroy has_many :timelogs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
end end
def spend_time(options) def spend_time(options)
......
class DeployKey < Key class DeployKey < Key
has_many :deploy_keys_projects, dependent: :destroy has_many :deploy_keys_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :projects, through: :deploy_keys_projects has_many :projects, through: :deploy_keys_projects
scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) } scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
......
...@@ -6,9 +6,9 @@ class DiffNote < Note ...@@ -6,9 +6,9 @@ class DiffNote < Note
NOTEABLE_TYPES = %w(MergeRequest Commit).freeze NOTEABLE_TYPES = %w(MergeRequest Commit).freeze
serialize :original_position, Gitlab::Diff::Position # rubocop:disable Cop/ActiverecordSerialize serialize :original_position, Gitlab::Diff::Position # rubocop:disable Cop/ActiveRecordSerialize
serialize :position, Gitlab::Diff::Position # rubocop:disable Cop/ActiverecordSerialize serialize :position, Gitlab::Diff::Position # rubocop:disable Cop/ActiveRecordSerialize
serialize :change_position, Gitlab::Diff::Position # rubocop:disable Cop/ActiverecordSerialize serialize :change_position, Gitlab::Diff::Position # rubocop:disable Cop/ActiveRecordSerialize
validates :original_position, presence: true validates :original_position, presence: true
validates :position, presence: true validates :position, presence: true
......
...@@ -6,7 +6,7 @@ class Environment < ActiveRecord::Base ...@@ -6,7 +6,7 @@ class Environment < ActiveRecord::Base
belongs_to :project, required: true, validate: true belongs_to :project, required: true, validate: true
has_many :deployments, dependent: :destroy has_many :deployments, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :last_deployment, -> { order('deployments.id DESC') }, class_name: 'Deployment' has_one :last_deployment, -> { order('deployments.id DESC') }, class_name: 'Deployment'
before_validation :nullify_external_url before_validation :nullify_external_url
......
...@@ -50,7 +50,7 @@ class Event < ActiveRecord::Base ...@@ -50,7 +50,7 @@ class Event < ActiveRecord::Base
belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
# For Hash only # For Hash only
serialize :data # rubocop:disable Cop/ActiverecordSerialize serialize :data # rubocop:disable Cop/ActiveRecordSerialize
# Callbacks # Callbacks
after_create :reset_project_activity after_create :reset_project_activity
......
...@@ -8,7 +8,7 @@ class Group < Namespace ...@@ -8,7 +8,7 @@ class Group < Namespace
include Referable include Referable
include SelectForProjectAuthorization include SelectForProjectAuthorization
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
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,
...@@ -16,11 +16,11 @@ class Group < Namespace ...@@ -16,11 +16,11 @@ class Group < Namespace
through: :group_members, through: :group_members,
source: :user source: :user
has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
has_many :project_group_links, dependent: :destroy has_many :project_group_links, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :shared_projects, through: :project_group_links, source: :project has_many :shared_projects, through: :project_group_links, source: :project
has_many :notification_settings, dependent: :destroy, as: :source has_many :notification_settings, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
has_many :labels, class_name: 'GroupLabel' has_many :labels, class_name: 'GroupLabel'
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
...@@ -31,7 +31,7 @@ class Group < Namespace ...@@ -31,7 +31,7 @@ class Group < Namespace
validates :two_factor_grace_period, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :two_factor_grace_period, presence: true, numericality: { greater_than_or_equal_to: 0 }
mount_uploader :avatar, AvatarUploader mount_uploader :avatar, AvatarUploader
has_many :uploads, as: :model, dependent: :destroy has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
after_create :post_create_hook after_create :post_create_hook
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
......
...@@ -12,7 +12,7 @@ class WebHook < ActiveRecord::Base ...@@ -12,7 +12,7 @@ class WebHook < ActiveRecord::Base
default_value_for :repository_update_events, false default_value_for :repository_update_events, false
default_value_for :enable_ssl_verification, true default_value_for :enable_ssl_verification, true
has_many :web_hook_logs, dependent: :destroy has_many :web_hook_logs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
scope :push_hooks, -> { where(push_events: true) } scope :push_hooks, -> { where(push_events: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true) } scope :tag_push_hooks, -> { where(tag_push_events: true) }
......
class WebHookLog < ActiveRecord::Base class WebHookLog < ActiveRecord::Base
belongs_to :web_hook belongs_to :web_hook
serialize :request_headers, Hash # rubocop:disable Cop/ActiverecordSerialize serialize :request_headers, Hash # rubocop:disable Cop/ActiveRecordSerialize
serialize :request_data, Hash # rubocop:disable Cop/ActiverecordSerialize serialize :request_data, Hash # rubocop:disable Cop/ActiveRecordSerialize
serialize :response_headers, Hash # rubocop:disable Cop/ActiverecordSerialize serialize :response_headers, Hash # rubocop:disable Cop/ActiveRecordSerialize
validates :web_hook, presence: true validates :web_hook, presence: true
......
...@@ -23,9 +23,14 @@ class Issue < ActiveRecord::Base ...@@ -23,9 +23,14 @@ class Issue < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :moved_to, class_name: 'Issue' belongs_to :moved_to, class_name: 'Issue'
has_many :events, as: :target, dependent: :destroy has_many :events, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :merge_requests_closing_issues, class_name: 'MergeRequestsClosingIssues', dependent: :delete_all has_many :merge_requests_closing_issues,
class_name: 'MergeRequestsClosingIssues',
dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :issue_assignees
has_many :assignees, class_name: "User", through: :issue_assignees
has_many :issue_assignees has_many :issue_assignees
has_many :assignees, class_name: "User", through: :issue_assignees has_many :assignees, class_name: "User", through: :issue_assignees
......
...@@ -15,9 +15,9 @@ class Label < ActiveRecord::Base ...@@ -15,9 +15,9 @@ class Label < ActiveRecord::Base
default_value_for :color, DEFAULT_COLOR default_value_for :color, DEFAULT_COLOR
has_many :lists, dependent: :destroy has_many :lists, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :priorities, class_name: 'LabelPriority' has_many :priorities, class_name: 'LabelPriority'
has_many :label_links, dependent: :destroy has_many :label_links, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :issues, through: :label_links, source: :target, source_type: 'Issue' has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
has_many :merge_requests, through: :label_links, source: :target, source_type: 'MergeRequest' has_many :merge_requests, through: :label_links, source: :target, source_type: 'MergeRequest'
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
class LegacyDiffNote < Note class LegacyDiffNote < Note
include NoteOnDiff include NoteOnDiff
serialize :st_diff # rubocop:disable Cop/ActiverecordSerialize serialize :st_diff # rubocop:disable Cop/ActiveRecordSerialize
validates :line_code, presence: true, line_code: true validates :line_code, presence: true, line_code: true
......
class LfsObject < ActiveRecord::Base class LfsObject < ActiveRecord::Base
has_many :lfs_objects_projects, dependent: :destroy has_many :lfs_objects_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :projects, through: :lfs_objects_projects has_many :projects, through: :lfs_objects_projects
validates :oid, presence: true, uniqueness: true validates :oid, presence: true, uniqueness: true
......
...@@ -12,24 +12,26 @@ class MergeRequest < ActiveRecord::Base ...@@ -12,24 +12,26 @@ class MergeRequest < ActiveRecord::Base
belongs_to :source_project, 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
has_one :merge_request_diff, has_one :merge_request_diff,
-> { order('merge_request_diffs.id DESC') } -> { order('merge_request_diffs.id DESC') }
belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline" belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline"
has_many :events, as: :target, dependent: :destroy has_many :events, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :merge_requests_closing_issues, class_name: 'MergeRequestsClosingIssues', dependent: :delete_all has_many :merge_requests_closing_issues,
class_name: 'MergeRequestsClosingIssues',
dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
belongs_to :assignee, class_name: "User" belongs_to :assignee, class_name: "User"
serialize :merge_params, Hash # rubocop:disable Cop/ActiverecordSerialize serialize :merge_params, Hash # rubocop:disable Cop/ActiveRecordSerialize
after_create :ensure_merge_request_diff, unless: :importing? after_create :ensure_merge_request_diff, unless: :importing?
after_update :reload_diff_if_branch_changed after_update :reload_diff_if_branch_changed
delegate :commits, :real_size, :commits_sha, :commits_count, delegate :commits, :real_size, :commit_shas, :commits_count,
to: :merge_request_diff, prefix: nil to: :merge_request_diff, prefix: nil
# When this attribute is true some MR validation is ignored # When this attribute is true some MR validation is ignored
...@@ -516,7 +518,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -516,7 +518,7 @@ class MergeRequest < ActiveRecord::Base
def related_notes def related_notes
# Fetch comments only from last 100 commits # Fetch comments only from last 100 commits
commits_for_notes_limit = 100 commits_for_notes_limit = 100
commit_ids = commits.last(commits_for_notes_limit).map(&:id) commit_ids = commit_shas.take(commits_for_notes_limit)
Note.where( Note.where(
"(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" + "(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" +
...@@ -839,15 +841,15 @@ class MergeRequest < ActiveRecord::Base ...@@ -839,15 +841,15 @@ class MergeRequest < ActiveRecord::Base
return Ci::Pipeline.none unless source_project return Ci::Pipeline.none unless source_project
@all_pipelines ||= source_project.pipelines @all_pipelines ||= source_project.pipelines
.where(sha: all_commits_sha, ref: source_branch) .where(sha: all_commit_shas, ref: source_branch)
.order(id: :desc) .order(id: :desc)
end end
# Note that this could also return SHA from now dangling commits # Note that this could also return SHA from now dangling commits
# #
def all_commits_sha def all_commit_shas
if persisted? if persisted?
merge_request_diffs.flat_map(&:commits_sha).uniq merge_request_diffs.preload(:merge_request_diff_commits).flat_map(&:commit_shas).uniq
elsif compare_commits elsif compare_commits
compare_commits.to_a.reverse.map(&:id) compare_commits.to_a.reverse.map(&:id)
else else
......
...@@ -11,9 +11,10 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -11,9 +11,10 @@ class MergeRequestDiff < ActiveRecord::Base
belongs_to :merge_request belongs_to :merge_request
has_many :merge_request_diff_files, -> { order(:merge_request_diff_id, :relative_order) } has_many :merge_request_diff_files, -> { order(:merge_request_diff_id, :relative_order) }
has_many :merge_request_diff_commits, -> { order(:merge_request_diff_id, :relative_order) }
serialize :st_commits # rubocop:disable Cop/ActiverecordSerialize serialize :st_commits # rubocop:disable Cop/ActiveRecordSerialize
serialize :st_diffs # rubocop:disable Cop/ActiverecordSerialize serialize :st_diffs # rubocop:disable Cop/ActiveRecordSerialize
state_machine :state, initial: :empty do state_machine :state, initial: :empty do
state :collected state :collected
...@@ -47,14 +48,13 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -47,14 +48,13 @@ class MergeRequestDiff < ActiveRecord::Base
# Collect information about commits and diff from repository # Collect information about commits and diff from repository
# and save it to the database as serialized data # and save it to the database as serialized data
def save_git_content def save_git_content
ensure_commits_sha ensure_commit_shas
save_commits save_commits
reload_commits
save_diffs save_diffs
keep_around_commits keep_around_commits
end end
def ensure_commits_sha def ensure_commit_shas
merge_request.fetch_ref merge_request.fetch_ref
self.start_commit_sha ||= merge_request.target_branch_sha self.start_commit_sha ||= merge_request.target_branch_sha
self.head_commit_sha ||= merge_request.source_branch_sha self.head_commit_sha ||= merge_request.source_branch_sha
...@@ -66,7 +66,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -66,7 +66,7 @@ class MergeRequestDiff < ActiveRecord::Base
# created before version 8.4 that does not store head_commit_sha in separate db field. # created before version 8.4 that does not store head_commit_sha in separate db field.
def head_commit_sha def head_commit_sha
if persisted? && super.nil? if persisted? && super.nil?
last_commit.try(:sha) last_commit_sha
else else
super super
end end
...@@ -97,16 +97,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -97,16 +97,11 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def commits def commits
@commits ||= load_commits(st_commits) @commits ||= load_commits
end end
def reload_commits def last_commit_sha
@commits = nil commit_shas.first
commits
end
def last_commit
commits.first
end end
def first_commit def first_commit
...@@ -131,8 +126,12 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -131,8 +126,12 @@ class MergeRequestDiff < ActiveRecord::Base
project.commit(head_commit_sha) project.commit(head_commit_sha)
end end
def commits_sha def commit_shas
if st_commits.present?
st_commits.map { |commit| commit[:id] } st_commits.map { |commit| commit[:id] }
else
merge_request_diff_commits.map(&:sha)
end
end end
def diff_refs=(new_diff_refs) def diff_refs=(new_diff_refs)
...@@ -207,7 +206,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -207,7 +206,11 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def commits_count def commits_count
st_commits.count if st_commits.present?
st_commits.size
else
merge_request_diff_commits.size
end
end end
def utf8_st_diffs def utf8_st_diffs
...@@ -231,29 +234,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -231,29 +234,6 @@ class MergeRequestDiff < ActiveRecord::Base
raw.any? { |element| VALID_CLASSES.include?(element.class) } raw.any? { |element| VALID_CLASSES.include?(element.class) }
end end
def dump_commits(commits)
commits.map(&:to_hash)
end
def load_commits(array)
array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash), merge_request.source_project) }
end
# Load all commits related to current merge request diff from repo
# and save it as array of hashes in st_commits db field
def save_commits
new_attributes = {}
commits = compare.commits
if commits.present?
commits = Commit.decorate(commits, merge_request.source_project).reverse
new_attributes[:st_commits] = dump_commits(commits)
end
update_columns_serialized(new_attributes)
end
def create_merge_request_diff_files(diffs) def create_merge_request_diff_files(diffs)
rows = diffs.map.with_index do |diff, index| rows = diffs.map.with_index do |diff, index|
diff.to_hash.merge( diff.to_hash.merge(
...@@ -294,12 +274,18 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -294,12 +274,18 @@ class MergeRequestDiff < ActiveRecord::Base
end end
end end
# Load diffs between branches related to current merge request diff from repo def load_commits
# and save it as array of hashes in st_diffs db field commits = st_commits.presence || merge_request_diff_commits
commits.map do |commit|
Commit.new(Gitlab::Git::Commit.new(commit.to_hash), merge_request.source_project)
end
end
def save_diffs def save_diffs
new_attributes = {} new_attributes = {}
if commits.size.zero? if compare.commits.size.zero?
new_attributes[:state] = :empty new_attributes[:state] = :empty
else else
diff_collection = compare.diffs(Commit.max_diff_options) diff_collection = compare.diffs(Commit.max_diff_options)
...@@ -319,7 +305,13 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -319,7 +305,13 @@ class MergeRequestDiff < ActiveRecord::Base
new_attributes[:state] = :overflow if diff_collection.overflow? new_attributes[:state] = :overflow if diff_collection.overflow?
end end
update_columns_serialized(new_attributes) update(new_attributes)
end
def save_commits
MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse)
merge_request_diff_commits.reload
end end
def repository def repository
...@@ -332,29 +324,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -332,29 +324,6 @@ class MergeRequestDiff < ActiveRecord::Base
project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha) project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha)
end end
#
# #save or #update_attributes providing changes on serialized attributes do a lot of
# serialization and deserialization calls resulting in bad performance.
# Using #update_columns solves the problem with just one YAML.dump per serialized attribute that we provide.
# As a tradeoff we need to reload the current instance to properly manage time objects on those serialized
# attributes. So to keep the same behaviour as the attribute assignment we reload the instance.
# The difference is in the usage of
# #write_attribute= (#update_attributes) and #raw_write_attribute= (#update_columns)
#
# Ex:
#
# new_attributes[:st_commits].first.slice(:committed_date)
# => {:committed_date=>2014-02-27 11:01:38 +0200}
# YAML.load(YAML.dump(new_attributes[:st_commits].first.slice(:committed_date)))
# => {:committed_date=>2014-02-27 10:01:38 +0100}
#
def update_columns_serialized(new_attributes)
return unless new_attributes.any?
update_columns(new_attributes.merge(updated_at: current_time_from_proper_timezone))
reload
end
def keep_around_commits def keep_around_commits
[repository, merge_request.source_project.repository].each do |repo| [repository, merge_request.source_project.repository].each do |repo|
repo.keep_around(start_commit_sha) repo.keep_around(start_commit_sha)
......
class MergeRequestDiffCommit < ActiveRecord::Base
include ShaAttribute
belongs_to :merge_request_diff
sha_attribute :sha
alias_attribute :id, :sha
def self.create_bulk(merge_request_diff_id, commits)
sha_attribute = Gitlab::Database::ShaAttribute.new
rows = commits.map.with_index do |commit, index|
# See #parent_ids.
commit_hash = commit.to_hash.except(:parent_ids)
sha = commit_hash.delete(:id)
commit_hash.merge(
merge_request_diff_id: merge_request_diff_id,
relative_order: index,
sha: sha_attribute.type_cast_for_database(sha)
)
end
Gitlab::Database.bulk_insert(self.table_name, rows)
end
def to_hash
Gitlab::Git::Commit::SERIALIZE_KEYS.each_with_object({}) do |key, hash|
hash[key] = public_send(key)
end
end
# We don't save these, because they would need a table or a serialised
# field. They aren't used anywhere, so just pretend the commit has no parents.
def parent_ids
[]
end
end
...@@ -21,7 +21,7 @@ class Milestone < ActiveRecord::Base ...@@ -21,7 +21,7 @@ class Milestone < ActiveRecord::Base
has_many :issues has_many :issues
has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues
has_many :merge_requests has_many :merge_requests
has_many :events, as: :target, dependent: :destroy has_many :events, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
scope :active, -> { with_state(:active) } scope :active, -> { with_state(:active) }
scope :closed, -> { with_state(:closed) } scope :closed, -> { with_state(:closed) }
......
...@@ -15,13 +15,13 @@ class Namespace < ActiveRecord::Base ...@@ -15,13 +15,13 @@ class Namespace < ActiveRecord::Base
cache_markdown_field :description, pipeline: :description cache_markdown_field :description, pipeline: :description
has_many :projects, dependent: :destroy has_many :projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :project_statistics has_many :project_statistics
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
belongs_to :parent, class_name: "Namespace" belongs_to :parent, class_name: "Namespace"
has_many :children, class_name: "Namespace", foreign_key: :parent_id has_many :children, class_name: "Namespace", foreign_key: :parent_id
has_one :chat_team, dependent: :destroy has_one :chat_team, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
validates :owner, presence: true, unless: ->(n) { n.type == "Group" } validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name, validates :name,
......
...@@ -46,8 +46,8 @@ class Note < ActiveRecord::Base ...@@ -46,8 +46,8 @@ class Note < ActiveRecord::Base
belongs_to :updated_by, class_name: "User" belongs_to :updated_by, class_name: "User"
belongs_to :last_edited_by, class_name: 'User' belongs_to :last_edited_by, class_name: 'User'
has_many :todos, dependent: :destroy has_many :todos, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :events, as: :target, dependent: :destroy has_many :events, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :system_note_metadata has_one :system_note_metadata
delegate :gfm_reference, :local_reference, to: :noteable delegate :gfm_reference, :local_reference, to: :noteable
......
...@@ -3,7 +3,7 @@ class PersonalAccessToken < ActiveRecord::Base ...@@ -3,7 +3,7 @@ class PersonalAccessToken < ActiveRecord::Base
include TokenAuthenticatable include TokenAuthenticatable
add_authentication_token_field :token add_authentication_token_field :token
serialize :scopes, Array # rubocop:disable Cop/ActiverecordSerialize serialize :scopes, Array # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :user belongs_to :user
......
...@@ -59,6 +59,7 @@ class Project < ActiveRecord::Base ...@@ -59,6 +59,7 @@ class Project < ActiveRecord::Base
update_column(:last_repository_updated_at, self.created_at) update_column(:last_repository_updated_at, self.created_at)
end end
before_destroy :remove_private_deploy_keys
after_destroy :remove_pages after_destroy :remove_pages
# update visibility_level of forks # update visibility_level of forks
...@@ -80,96 +81,108 @@ class Project < ActiveRecord::Base ...@@ -80,96 +81,108 @@ class Project < ActiveRecord::Base
belongs_to :namespace belongs_to :namespace
has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event' 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
# Project services # Project services
has_one :campfire_service, dependent: :destroy has_one :campfire_service
has_one :drone_ci_service, dependent: :destroy has_one :drone_ci_service
has_one :emails_on_push_service, dependent: :destroy has_one :emails_on_push_service
has_one :pipelines_email_service, dependent: :destroy has_one :pipelines_email_service
has_one :irker_service, dependent: :destroy has_one :irker_service
has_one :pivotaltracker_service, dependent: :destroy has_one :pivotaltracker_service
has_one :hipchat_service, dependent: :destroy has_one :hipchat_service
has_one :flowdock_service, dependent: :destroy has_one :flowdock_service
has_one :assembla_service, dependent: :destroy has_one :assembla_service
has_one :asana_service, dependent: :destroy has_one :asana_service
has_one :gemnasium_service, dependent: :destroy has_one :gemnasium_service
has_one :mattermost_slash_commands_service, dependent: :destroy has_one :mattermost_slash_commands_service
has_one :mattermost_service, dependent: :destroy has_one :mattermost_service
has_one :slack_slash_commands_service, dependent: :destroy has_one :slack_slash_commands_service
has_one :slack_service, dependent: :destroy has_one :slack_service
has_one :buildkite_service, dependent: :destroy has_one :buildkite_service
has_one :bamboo_service, dependent: :destroy has_one :bamboo_service
has_one :teamcity_service, dependent: :destroy has_one :teamcity_service
has_one :pushover_service, dependent: :destroy has_one :pushover_service
has_one :jira_service, dependent: :destroy has_one :jira_service
has_one :redmine_service, dependent: :destroy has_one :redmine_service
has_one :custom_issue_tracker_service, dependent: :destroy has_one :custom_issue_tracker_service
has_one :bugzilla_service, dependent: :destroy has_one :bugzilla_service
has_one :gitlab_issue_tracker_service, dependent: :destroy, inverse_of: :project has_one :gitlab_issue_tracker_service, inverse_of: :project
has_one :external_wiki_service, dependent: :destroy has_one :external_wiki_service
has_one :kubernetes_service, dependent: :destroy, inverse_of: :project has_one :kubernetes_service, inverse_of: :project
has_one :prometheus_service, dependent: :destroy, inverse_of: :project has_one :prometheus_service, inverse_of: :project
has_one :mock_ci_service, dependent: :destroy has_one :mock_ci_service
has_one :mock_deployment_service, dependent: :destroy has_one :mock_deployment_service
has_one :mock_monitoring_service, dependent: :destroy has_one :mock_monitoring_service
has_one :microsoft_teams_service, dependent: :destroy has_one :microsoft_teams_service
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_project_link, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link has_one :forked_from_project, through: :forked_project_link
has_many :forked_project_links, foreign_key: "forked_from_project_id" has_many :forked_project_links, foreign_key: "forked_from_project_id"
has_many :forks, through: :forked_project_links, source: :forked_to_project has_many :forks, through: :forked_project_links, source: :forked_to_project
# Merge Requests for target project should be removed with it # Merge Requests for target project should be removed with it
has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id' has_many :merge_requests, foreign_key: 'target_project_id'
has_many :issues, dependent: :destroy has_many :issues
has_many :labels, dependent: :destroy, class_name: 'ProjectLabel' has_many :labels, class_name: 'ProjectLabel'
has_many :services, dependent: :destroy has_many :services
has_many :events, dependent: :destroy has_many :events
has_many :milestones, dependent: :destroy has_many :milestones
has_many :notes, dependent: :destroy has_many :notes
has_many :snippets, dependent: :destroy, class_name: 'ProjectSnippet' has_many :snippets, class_name: 'ProjectSnippet'
has_many :hooks, dependent: :destroy, class_name: 'ProjectHook' has_many :hooks, class_name: 'ProjectHook'
has_many :protected_branches, dependent: :destroy has_many :protected_branches
has_many :protected_tags, dependent: :destroy has_many :protected_tags
has_many :project_authorizations has_many :project_authorizations
has_many :authorized_users, through: :project_authorizations, source: :user, class_name: 'User' has_many :authorized_users, through: :project_authorizations, source: :user, class_name: 'User'
has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source has_many :project_members, -> { where(requested_at: nil) },
as: :source, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
alias_method :members, :project_members alias_method :members, :project_members
has_many :users, through: :project_members has_many :users, through: :project_members
has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'ProjectMember' has_many :requesters, -> { where.not(requested_at: nil) },
as: :source, class_name: 'ProjectMember', dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :deploy_keys_projects, dependent: :destroy has_many :deploy_keys_projects
has_many :deploy_keys, through: :deploy_keys_projects has_many :deploy_keys, through: :deploy_keys_projects
has_many :users_star_projects, dependent: :destroy has_many :users_star_projects
has_many :starrers, through: :users_star_projects, source: :user has_many :starrers, through: :users_star_projects, source: :user
has_many :releases, dependent: :destroy has_many :releases
has_many :lfs_objects_projects, dependent: :destroy has_many :lfs_objects_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :lfs_objects, through: :lfs_objects_projects has_many :lfs_objects, through: :lfs_objects_projects
has_many :project_group_links, dependent: :destroy has_many :project_group_links
has_many :invited_groups, through: :project_group_links, source: :group has_many :invited_groups, through: :project_group_links, source: :group
has_many :pages_domains, dependent: :destroy has_many :pages_domains
has_many :todos, dependent: :destroy has_many :todos
has_many :notification_settings, dependent: :destroy, as: :source has_many :notification_settings, as: :source, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_one :import_data, dependent: :delete, class_name: 'ProjectImportData' has_one :import_data, class_name: 'ProjectImportData'
has_one :project_feature, dependent: :destroy has_one :project_feature
has_one :statistics, class_name: 'ProjectStatistics', dependent: :delete has_one :statistics, class_name: 'ProjectStatistics'
has_many :container_repositories, dependent: :destroy
# Container repositories need to remove data from the container registry,
has_many :commit_statuses, dependent: :destroy # which is not managed by the DB. Hence we're still using dependent: :destroy
has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline' # here.
has_many :builds, class_name: 'Ci::Build' # the builds are created from the commit_statuses has_many :container_repositories, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
has_many :commit_statuses
has_many :pipelines, class_name: 'Ci::Pipeline'
# Ci::Build objects store data on the file system such as artifact files and
# build traces. Currently there's no efficient way of removing this data in
# bulk that doesn't involve loading the rows into memory. As a result we're
# still using `dependent: :destroy` here.
has_many :builds, class_name: 'Ci::Build', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :runner_projects, class_name: 'Ci::RunnerProject'
has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner' has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
has_many :variables, class_name: 'Ci::Variable' has_many :variables, class_name: 'Ci::Variable'
has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger' has_many :triggers, class_name: 'Ci::Trigger'
has_many :environments, dependent: :destroy has_many :environments
has_many :deployments, dependent: :destroy has_many :deployments
has_many :pipeline_schedules, dependent: :destroy, class_name: 'Ci::PipelineSchedule' has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule'
has_many :active_runners, -> { active }, through: :runner_projects, source: :runner, class_name: 'Ci::Runner' has_many :active_runners, -> { active }, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
...@@ -224,7 +237,7 @@ class Project < ActiveRecord::Base ...@@ -224,7 +237,7 @@ class Project < ActiveRecord::Base
before_save :ensure_runners_token before_save :ensure_runners_token
mount_uploader :avatar, AvatarUploader mount_uploader :avatar, AvatarUploader
has_many :uploads, as: :model, dependent: :destroy has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# Scopes # Scopes
scope :pending_delete, -> { where(pending_delete: true) } scope :pending_delete, -> { where(pending_delete: true) }
...@@ -1240,7 +1253,13 @@ class Project < ActiveRecord::Base ...@@ -1240,7 +1253,13 @@ class Project < ActiveRecord::Base
File.join(pages_path, 'public') File.join(pages_path, 'public')
end end
def remove_private_deploy_keys
deploy_keys.where(public: false).delete_all
end
def remove_pages def remove_pages
::Projects::UpdatePagesConfigurationService.new(self).execute
# 1. We rename pages to temporary directory # 1. We rename pages to temporary directory
# 2. We wait 5 minutes, due to NFS caching # 2. We wait 5 minutes, due to NFS caching
# 3. We asynchronously remove pages with force # 3. We asynchronously remove pages with force
...@@ -1326,7 +1345,8 @@ class Project < ActiveRecord::Base ...@@ -1326,7 +1345,8 @@ class Project < ActiveRecord::Base
variables variables
end end
def secret_variables_for(ref) def secret_variables_for(ref:, environment: nil)
# EE would use the environment
if protected_for?(ref) if protected_for?(ref)
variables variables
else else
......
...@@ -10,7 +10,7 @@ class ProjectImportData < ActiveRecord::Base ...@@ -10,7 +10,7 @@ class ProjectImportData < ActiveRecord::Base
insecure_mode: true, insecure_mode: true,
algorithm: 'aes-256-cbc' algorithm: 'aes-256-cbc'
serialize :data, JSON # rubocop:disable Cop/ActiverecordSerialize serialize :data, JSON # rubocop:disable Cop/ActiveRecordSerialize
validates :project, presence: true validates :project, presence: true
......
...@@ -96,10 +96,13 @@ class KubernetesService < DeploymentService ...@@ -96,10 +96,13 @@ class KubernetesService < DeploymentService
end end
def predefined_variables def predefined_variables
config = YAML.dump(kubeconfig)
variables = [ variables = [
{ key: 'KUBE_URL', value: api_url, public: true }, { key: 'KUBE_URL', value: api_url, public: true },
{ key: 'KUBE_TOKEN', value: token, public: false }, { key: 'KUBE_TOKEN', value: token, public: false },
{ key: 'KUBE_NAMESPACE', value: actual_namespace, public: true } { key: 'KUBE_NAMESPACE', value: actual_namespace, public: true },
{ key: 'KUBECONFIG', value: config, public: false, file: true }
] ]
if ca_pem.present? if ca_pem.present?
...@@ -135,6 +138,14 @@ class KubernetesService < DeploymentService ...@@ -135,6 +138,14 @@ class KubernetesService < DeploymentService
private private
def kubeconfig
to_kubeconfig(
url: api_url,
namespace: actual_namespace,
token: token,
ca_pem: ca_pem)
end
def namespace_placeholder def namespace_placeholder
default_namespace || TEMPLATE_PLACEHOLDER default_namespace || TEMPLATE_PLACEHOLDER
end end
......
...@@ -5,7 +5,7 @@ class SlashCommandsService < Service ...@@ -5,7 +5,7 @@ class SlashCommandsService < Service
prop_accessor :token prop_accessor :token
has_many :chat_names, foreign_key: :service_id, dependent: :destroy has_many :chat_names, foreign_key: :service_id, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
def valid_token?(token) def valid_token?(token)
self.respond_to?(:token) && self.respond_to?(:token) &&
......
...@@ -63,6 +63,10 @@ class ProjectWiki ...@@ -63,6 +63,10 @@ class ProjectWiki
!!repository.exists? !!repository.exists?
end end
def has_home_page?
!!find_page('home')
end
# Returns an Array of Gitlab WikiPage instances or an # Returns an Array of Gitlab WikiPage instances or an
# empty Array if this Wiki has no pages. # empty Array if this Wiki has no pages.
def pages def pages
......
class SentNotification < ActiveRecord::Base class SentNotification < ActiveRecord::Base
serialize :position, Gitlab::Diff::Position # rubocop:disable Cop/ActiverecordSerialize serialize :position, Gitlab::Diff::Position # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :project belongs_to :project
belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# and implement a set of methods # and implement a set of methods
class Service < ActiveRecord::Base class Service < ActiveRecord::Base
include Sortable include Sortable
serialize :properties, JSON # rubocop:disable Cop/ActiverecordSerialize serialize :properties, JSON # rubocop:disable Cop/ActiveRecordSerialize
default_value_for :active, false default_value_for :active, false
default_value_for :push_events, true default_value_for :push_events, true
...@@ -51,6 +51,14 @@ class Service < ActiveRecord::Base ...@@ -51,6 +51,14 @@ class Service < ActiveRecord::Base
active active
end end
def show_active_box?
true
end
def editable?
true
end
def template? def template?
template template
end end
......
...@@ -30,7 +30,7 @@ class Snippet < ActiveRecord::Base ...@@ -30,7 +30,7 @@ class Snippet < ActiveRecord::Base
belongs_to :author, class_name: 'User' belongs_to :author, class_name: 'User'
belongs_to :project belongs_to :project
has_many :notes, as: :noteable, dependent: :destroy has_many :notes, as: :noteable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
delegate :name, :email, to: :author, prefix: true, allow_nil: true delegate :name, :email, to: :author, prefix: true, allow_nil: true
......
...@@ -41,7 +41,7 @@ class User < ActiveRecord::Base ...@@ -41,7 +41,7 @@ class User < ActiveRecord::Base
otp_secret_encryption_key: Gitlab::Application.secrets.otp_key_base otp_secret_encryption_key: Gitlab::Application.secrets.otp_key_base
devise :two_factor_backupable, otp_number_of_backup_codes: 10 devise :two_factor_backupable, otp_number_of_backup_codes: 10
serialize :otp_backup_codes, JSON # rubocop:disable Cop/ActiverecordSerialize serialize :otp_backup_codes, JSON # rubocop:disable Cop/ActiveRecordSerialize
devise :lockable, :recoverable, :rememberable, :trackable, devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable :validatable, :omniauthable, :confirmable, :registerable
...@@ -67,24 +67,24 @@ class User < ActiveRecord::Base ...@@ -67,24 +67,24 @@ class User < ActiveRecord::Base
# #
# Namespace for personal projects # Namespace for personal projects
has_one :namespace, -> { where type: nil }, dependent: :destroy, foreign_key: :owner_id, autosave: true has_one :namespace, -> { where type: nil }, dependent: :destroy, foreign_key: :owner_id, autosave: true # rubocop:disable Cop/ActiveRecordDependent
# Profile # Profile
has_many :keys, -> do has_many :keys, -> do
type = Key.arel_table[:type] type = Key.arel_table[:type]
where(type.not_eq('DeployKey').or(type.eq(nil))) where(type.not_eq('DeployKey').or(type.eq(nil)))
end, dependent: :destroy end, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :deploy_keys, -> { where(type: 'DeployKey') }, dependent: :destroy has_many :deploy_keys, -> { where(type: 'DeployKey') }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :emails, dependent: :destroy has_many :emails, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :personal_access_tokens, dependent: :destroy has_many :personal_access_tokens, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :identities, dependent: :destroy, autosave: true has_many :identities, dependent: :destroy, autosave: true # rubocop:disable Cop/ActiveRecordDependent
has_many :u2f_registrations, dependent: :destroy has_many :u2f_registrations, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :chat_names, dependent: :destroy has_many :chat_names, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# Groups # Groups
has_many :members, dependent: :destroy has_many :members, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, source: 'GroupMember' has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, source: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
has_many :groups, through: :group_members has_many :groups, through: :group_members
has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group
has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group
...@@ -92,35 +92,35 @@ class User < ActiveRecord::Base ...@@ -92,35 +92,35 @@ 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 has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
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 # rubocop:disable Cop/ActiveRecordDependent
has_many :starred_projects, through: :users_star_projects, source: :project has_many :starred_projects, through: :users_star_projects, source: :project
has_many :project_authorizations has_many :project_authorizations
has_many :authorized_projects, through: :project_authorizations, source: :project has_many :authorized_projects, through: :project_authorizations, source: :project
has_many :snippets, dependent: :destroy, foreign_key: :author_id has_many :snippets, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :notes, dependent: :destroy, foreign_key: :author_id has_many :notes, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :issues, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :merge_requests, dependent: :destroy, foreign_key: :author_id has_many :merge_requests, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :events, dependent: :destroy, foreign_key: :author_id has_many :events, dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
has_many :subscriptions, dependent: :destroy has_many :subscriptions, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
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 :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :abuse_report, dependent: :destroy, foreign_key: :user_id has_one :abuse_report, dependent: :destroy, foreign_key: :user_id # rubocop:disable Cop/ActiveRecordDependent
has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" # rubocop:disable Cop/ActiveRecordDependent
has_many :spam_logs, dependent: :destroy has_many :spam_logs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :builds, dependent: :nullify, class_name: 'Ci::Build' has_many :builds, dependent: :nullify, class_name: 'Ci::Build' # rubocop:disable Cop/ActiveRecordDependent
has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline' has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline' # rubocop:disable Cop/ActiveRecordDependent
has_many :todos, dependent: :destroy has_many :todos, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :notification_settings, dependent: :destroy has_many :notification_settings, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :award_emoji, dependent: :destroy has_many :award_emoji, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :owner_id has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :owner_id # rubocop:disable Cop/ActiveRecordDependent
has_many :issue_assignees has_many :issue_assignees
has_many :assigned_issues, class_name: "Issue", through: :issue_assignees, source: :issue has_many :assigned_issues, class_name: "Issue", through: :issue_assignees, source: :issue
has_many :assigned_merge_requests, dependent: :nullify, foreign_key: :assignee_id, class_name: "MergeRequest" has_many :assigned_merge_requests, dependent: :nullify, foreign_key: :assignee_id, class_name: "MergeRequest" # rubocop:disable Cop/ActiveRecordDependent
# #
# Validations # Validations
...@@ -211,7 +211,7 @@ class User < ActiveRecord::Base ...@@ -211,7 +211,7 @@ class User < ActiveRecord::Base
end end
mount_uploader :avatar, AvatarUploader mount_uploader :avatar, AvatarUploader
has_many :uploads, as: :model, dependent: :destroy has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# Scopes # Scopes
scope :admins, -> { where(admin: true) } scope :admins, -> { where(admin: true) }
......
...@@ -68,7 +68,7 @@ module MergeRequests ...@@ -68,7 +68,7 @@ module MergeRequests
if merge_request.source_branch == @branch_name || force_push? if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_diff(current_user) merge_request.reload_diff(current_user)
else else
mr_commit_ids = merge_request.commits_sha mr_commit_ids = merge_request.commit_shas
push_commit_ids = @commits.map(&:id) push_commit_ids = @commits.map(&:id)
matches = mr_commit_ids & push_commit_ids matches = mr_commit_ids & push_commit_ids
merge_request.reload_diff(current_user) if matches.any? merge_request.reload_diff(current_user) if matches.any?
...@@ -128,7 +128,7 @@ module MergeRequests ...@@ -128,7 +128,7 @@ module MergeRequests
return unless @commits.present? return unless @commits.present?
merge_requests_for_source_branch.each do |merge_request| merge_requests_for_source_branch.each do |merge_request|
mr_commit_ids = Set.new(merge_request.commits_sha) mr_commit_ids = Set.new(merge_request.commit_shas)
new_commits, existing_commits = @commits.partition do |commit| new_commits, existing_commits = @commits.partition do |commit|
mr_commit_ids.include?(commit.id) mr_commit_ids.include?(commit.id)
...@@ -144,7 +144,7 @@ module MergeRequests ...@@ -144,7 +144,7 @@ module MergeRequests
return unless @commits.present? return unless @commits.present?
merge_requests_for_source_branch.each do |merge_request| merge_requests_for_source_branch.each do |merge_request|
commit_shas = merge_request.commits_sha commit_shas = merge_request.commit_shas
wip_commit = @commits.detect do |commit| wip_commit = @commits.detect do |commit|
commit.work_in_progress? && commit_shas.include?(commit.sha) commit.work_in_progress? && commit_shas.include?(commit.sha)
......
...@@ -6,4 +6,7 @@ ...@@ -6,4 +6,7 @@
- providers.each do |provider| - providers.each do |provider|
%span.light %span.light
- has_icon = provider_has_icon?(provider) - has_icon = provider_has_icon?(provider)
= link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn') = link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: 'oauth-login' + (has_icon ? ' oauth-image-link' : ' btn'), id: "oauth-login-#{provider}"
%fieldset
= check_box_tag :remember_me
= label_tag :remember_me, 'Remember Me'
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
%td.shortcut %td.shortcut
.key f .key f
%td Focus Filter %td Focus Filter
- if performance_bar_enabled?
%tr %tr
%td.shortcut %td.shortcut
.key p b .key p b
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
= stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "application", media: "all"
= stylesheet_link_tag "print", media: "print" = stylesheet_link_tag "print", media: "print"
= stylesheet_link_tag "test", media: "all" if Rails.env.test? = stylesheet_link_tag "test", media: "all" if Rails.env.test?
= stylesheet_link_tag 'peek' if peek_enabled? = stylesheet_link_tag 'performance_bar' if performance_bar_enabled?
- if show_new_nav? - if show_new_nav?
= stylesheet_link_tag "new_nav", media: "all" = stylesheet_link_tag "new_nav", media: "all"
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
= webpack_bundle_tag "main" = webpack_bundle_tag "main"
= webpack_bundle_tag "raven" if current_application_settings.clientside_sentry_enabled = webpack_bundle_tag "raven" if current_application_settings.clientside_sentry_enabled
= webpack_bundle_tag "test" if Rails.env.test? = webpack_bundle_tag "test" if Rails.env.test?
= webpack_bundle_tag 'peek' if peek_enabled? = webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
- if content_for?(:page_specific_javascripts) - if content_for?(:page_specific_javascripts)
= yield :page_specific_javascripts = yield :page_specific_javascripts
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
= render "layouts/head" = render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } } %body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } }
= render "layouts/init_auto_complete" if @gfm_form = render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
- if show_new_nav? - if show_new_nav?
= render "layouts/header/new" = render "layouts/header/new"
- else - else
...@@ -11,3 +10,5 @@ ...@@ -11,3 +10,5 @@
= render 'layouts/page', sidebar: sidebar, nav: nav = render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body = yield :scripts_body
= render 'peek/bar'
Profile:
= link_to 'all', url_for(lineprofiler: 'true'), class: 'js-toggle-modal-peek-line-profile'
\/
= link_to 'app & lib', url_for(lineprofiler: 'app'), class: 'js-toggle-modal-peek-line-profile'
\/
= link_to 'views', url_for(lineprofiler: 'views'), class: 'js-toggle-modal-peek-line-profile'
%strong %strong
%a#peek-show-queries{ href: '#' } %a.js-toggle-modal-peek-sql
%span{ data: { defer_to: "#{view.defer_key}-duration" } }... %span{ data: { defer_to: "#{view.defer_key}-duration" } }...
\/ \/
%span{ data: { defer_to: "#{view.defer_key}-calls" } }... %span{ data: { defer_to: "#{view.defer_key}-calls" } }...
#modal-peek-pg-queries.modal{ tabindex: -1 } #modal-peek-pg-queries.modal{ tabindex: -1 }
.modal-dialog .modal-dialog.modal-full
#modal-peek-pg-queries-content.modal-content .modal-content
.modal-header .modal-header
%a.close{ href: "#", "data-dismiss" => "modal" } × %button.close.btn.btn-link.btn-sm{ type: 'button', data: { dismiss: 'modal' } } X
%h4 %h4
SQL queries SQL queries
.modal-body{ data: { defer_to: "#{view.defer_key}-queries" } }... .modal-body{ data: { defer_to: "#{view.defer_key}-queries" } }...
= icon('info-circle fw') = icon('info-circle fw')
= succeed '.' do = succeed '.' do
To learn more about this project, read To learn more about this project, read
= link_to "the wiki", project_wikis_path(viewer.project) = link_to "the wiki", get_project_wiki_path(viewer.project)
.panel.panel-default
.panel-heading
Group members with access to
%strong= @group.name
%span.badge= members.size
- if can?(current_user, :admin_group_member, @group)
.controls
= link_to 'Manage group members',
group_group_members_path(@group),
class: 'btn'
%ul.content-list
= render partial: 'shared/members/member',
collection: members.limit(20),
as: :member,
locals: { show_controls: false }
- if members.size > 20
%li
and #{members.count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(@group)}
.row.prepend-top-default .row.prepend-top-default
.col-lg-4.settings-sidebar .col-lg-12
%h4.prepend-top-0 %h4
Project members Project members
- if can?(current_user, :admin_project_member, @project) - if can?(current_user, :admin_project_member, @project)
%p %p
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
%i Masters %i Masters
or or
%i Owners %i Owners
.col-lg-8
.light .light
- if can?(current_user, :admin_project_member, @project) - if can?(current_user, :admin_project_member, @project)
%ul.nav-links.project-member-tabs{ role: 'tablist' } %ul.nav-links.project-member-tabs{ role: 'tablist' }
......
- @project_group_links.each do |group_links|
- shared_group = group_links.group
- shared_group_members = shared_group.members
- shared_group_users_count = shared_group_members.size
.panel.panel-default
.panel-heading
Shared with
%strong= shared_group.name
group, members with
%strong= group_links.human_access
role (#{shared_group_users_count})
- if can?(current_user, :admin_group, shared_group)
.panel-head-actions
= link_to group_group_members_path(shared_group), class: 'btn btn-sm' do
%i.fa.fa-pencil-square-o
Edit group members
%ul.content-list
= render partial: 'shared/members/member',
collection: shared_group_members.order(access_level: :desc).limit(20),
as: :member,
locals: { show_controls: false, show_roles: false }
- if shared_group_users_count > 20
%li
and #{shared_group_users_count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(shared_group)}
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
.col-lg-9 .col-lg-9
= form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors form-horizontal js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form| = form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors form-horizontal js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, subject: @service = render 'shared/service_settings', form: form, subject: @service
- if @service.editable?
.footer-block.row-content-block .footer-block.row-content-block
%button.btn.btn-save{ type: 'submit' } %button.btn.btn-save{ type: 'submit' }
= icon('spinner spin', class: 'hidden js-btn-spinner') = icon('spinner spin', class: 'hidden js-btn-spinner')
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
= render "projects/commits/head" = render "projects/commits/head"
= render 'projects/last_push' %div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render 'projects/last_push'
%div{ class: container_class }
= render 'projects/files', commit: @last_commit, project: @project, ref: @ref = render 'projects/files', commit: @last_commit, project: @project, ref: @ref
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
= markdown @service.help = markdown @service.help
.service-settings .service-settings
- if @service.show_active_box?
.form-group .form-group
= form.label :active, "Active", class: "control-label" = form.label :active, "Active", class: "control-label"
.col-sm-10 .col-sm-10
......
---
title: Honor the "Remember me" parameter for OAuth-based login
merge_request: 11963
author:
---
title: Provide KUBECONFIG from KubernetesService for runners
merge_request: 12223
author:
---
title: Add user projects API
merge_request: 12596
author: Ivan Chernov
---
title: Improve the performance of the project list API
merge_request: 12679
author:
---
title: Add Traditional Chinese in Taiwan translations of Commits Page
merge_request: 12407
author: Huang Tao
---
title: Cleanup minor UX issues in the performance dashboard
merge_request:
author:
---
title: Fixed the chart legend not being set correctly
merge_request: 12628
author:
---
title: Remove two columned layout from project member settings
merge_request:
author:
---
title: Don't show auxiliary blob viewer for README when there is no wiki
merge_request:
author:
---
title: Re-enable realtime for environments table
merge_request:
author:
---
title: Speed up project removals by adding foreign keys with cascading deletes to various tables
merge_request:
author:
---
title: Upgrade GitLab Workhorse to v2.3.0
merge_request: 12676
author:
...@@ -105,7 +105,7 @@ module Gitlab ...@@ -105,7 +105,7 @@ module Gitlab
config.assets.precompile << "katex.css" config.assets.precompile << "katex.css"
config.assets.precompile << "katex.js" config.assets.precompile << "katex.js"
config.assets.precompile << "xterm/xterm.css" config.assets.precompile << "xterm/xterm.css"
config.assets.precompile << "peek.css" config.assets.precompile << "performance_bar.css"
config.assets.precompile << "lib/ace.js" config.assets.precompile << "lib/ace.js"
config.assets.precompile << "vendor/assets/fonts/*" config.assets.precompile << "vendor/assets/fonts/*"
config.assets.precompile << "test.css" config.assets.precompile << "test.css"
...@@ -166,8 +166,9 @@ module Gitlab ...@@ -166,8 +166,9 @@ module Gitlab
config.after_initialize do config.after_initialize do
Rails.application.reload_routes! Rails.application.reload_routes!
named_routes_set = Gitlab::Application.routes.named_routes
project_url_helpers = Module.new do project_url_helpers = Module.new do
Gitlab::Application.routes.named_routes.helper_names.each do |name| named_routes_set.helper_names.each do |name|
next unless name.include?('namespace_project') next unless name.include?('namespace_project')
define_method(name.sub('namespace_project', 'project')) do |project, *args| define_method(name.sub('namespace_project', 'project')) do |project, *args|
...@@ -176,6 +177,9 @@ module Gitlab ...@@ -176,6 +177,9 @@ module Gitlab
end end
end end
named_routes_set.url_helpers_module.include project_url_helpers
named_routes_set.url_helpers_module.extend project_url_helpers
Gitlab::Routing.url_helpers.include project_url_helpers Gitlab::Routing.url_helpers.include project_url_helpers
Gitlab::Routing.url_helpers.extend project_url_helpers Gitlab::Routing.url_helpers.extend project_url_helpers
......
...@@ -619,6 +619,49 @@ test: ...@@ -619,6 +619,49 @@ test:
title: "JIRA" title: "JIRA"
url: https://sample_company.atlassian.net url: https://sample_company.atlassian.net
project_key: PROJECT project_key: PROJECT
omniauth:
enabled: true
allow_single_sign_on: true
external_providers: []
providers:
- { name: 'cas3',
label: 'cas3',
args: { url: 'https://sso.example.com',
disable_ssl_verification: false,
login_url: '/cas/login',
service_validate_url: '/cas/p3/serviceValidate',
logout_url: '/cas/logout'} }
- { name: 'github',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
url: "https://github.com/",
verify_ssl: false,
args: { scope: 'user:email' } }
- { name: 'bitbucket',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET' }
- { name: 'gitlab',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
args: { scope: 'api' } }
- { name: 'google_oauth2',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
args: { access_type: 'offline', approval_prompt: '' } }
- { name: 'facebook',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET' }
- { name: 'twitter',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET' }
- { name: 'auth0',
args: {
client_id: 'YOUR_AUTH0_CLIENT_ID',
client_secret: 'YOUR_AUTH0_CLIENT_SECRET',
namespace: 'YOUR_AUTH0_DOMAIN' } }
ldap: ldap:
enabled: false enabled: false
servers: servers:
......
- group: Kubernetes - group: AWS Elastic Load Balancer
priority: 1 priority: 10
metrics: metrics:
- title: "Memory usage" - title: "Throughput"
y_label: "Values" y_label: "Requests / Sec"
required_metrics: required_metrics:
- container_memory_usage_bytes - aws_elb_request_count_sum
weight: 1 weight: 1
queries: queries:
- query_range: 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20' - query_range: 'sum(aws_elb_request_count_sum{%{environment_filter}}) * 60'
label: Container memory label: Total
unit: MiB unit: req / sec
- title: "Current memory usage" - title: "Latency"
y_label: "Latency (ms)"
required_metrics: required_metrics:
- container_memory_usage_bytes - aws_elb_latency_average
weight: 1 weight: 1
queries: queries:
- query: 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20' - query_range: 'avg(aws_elb_latency_average{%{environment_filter}}) * 1000'
display_empty: false label: Average
unit: MiB unit: ms
- title: "CPU usage" - title: "HTTP Error Rate"
y_label: "Error Rate (%)"
required_metrics: required_metrics:
- container_cpu_usage_seconds_total - aws_elb_request_count_sum
- aws_elb_httpcode_backend_5_xx_sum
weight: 1
queries:
- query_range: 'sum(aws_elb_httpcode_backend_5_xx_sum{%{environment_filter}}) / sum(aws_elb_request_count_sum{%{environment_filter}})'
label: HTTP Errors
unit: "%"
- group: NGINX
priority: 10
metrics:
- title: "Throughput"
y_label: "Requests / Sec"
required_metrics:
- nginx_requests_total
weight: 1
queries:
- query_range: 'sum(rate(nginx_requests_total{server_zone!="*", server_zone!="_", %{environment_filter}}[2m]))'
label: Total
unit: req / sec
- title: "Latency"
y_label: "Latency (ms)"
required_metrics:
- nginx_upstream_response_msecs_avg
weight: 1
queries:
- query_range: 'avg(nginx_upstream_response_msecs_avg{%{environment_filter}}) * 1000'
label: Upstream
unit: ms
- title: "HTTP Error Rate"
y_label: "Error Rate (%)"
required_metrics:
- nginx_responses_total
weight: 1
queries:
- query_range: 'sum(nginx_responses_total{status_code="5xx", %{environment_filter}}) / sum(nginx_responses_total{server_zone!="*", server_zone!="_", %{environment_filter}})'
label: HTTP Errors
unit: "%"
- group: Kubernetes
priority: 5
metrics:
- title: "Memory Usage"
y_label: "Memory Usage (MB)"
required_metrics:
- container_memory_usage_bytes
weight: 1 weight: 1
queries: queries:
- query_range: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100' - query_range: '(sum(container_memory_usage_bytes{container_name!="POD",%{environment_filter}}) / count(container_memory_usage_bytes{container_name!="POD",%{environment_filter}})) /1024/1024'
- title: "Current CPU usage" label: Average
unit: MB
- title: "CPU Utilization"
y_label: "CPU Utilization (%)"
required_metrics: required_metrics:
- container_cpu_usage_seconds_total - container_cpu_usage_seconds_total
weight: 1 weight: 1
queries: queries:
- query: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100' - query_range: 'sum(rate(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}[2m])) / count(container_cpu_usage_seconds_total{container_name!="POD",%{environment_filter}}) * 100'
label: Average
unit: "%"
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