Commit cf9c3f71 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'ce-to-ee-2018-11-20' into 'master'

CE upstream - 2018-11-20 13:22 UTC

Closes gitlab-ce#54189, #8488, and gitlab-ce#54236

See merge request gitlab-org/gitlab-ee!8533
parents ed4707a2 2eaaca51
...@@ -2,10 +2,6 @@ ...@@ -2,10 +2,6 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 11.4.7 (2018-11-20)
- No changes.
## 11.4.6 (2018-11-18) ## 11.4.6 (2018-11-18)
### Security (1 change) ### Security (1 change)
...@@ -15,9 +11,8 @@ entry. ...@@ -15,9 +11,8 @@ entry.
## 11.4.5 (2018-11-04) ## 11.4.5 (2018-11-04)
### Fixed (5 changes, 1 of them is from the community) ### Fixed (4 changes, 1 of them is from the community)
- Fix stuck job warning message. !8060
- fix link to enable usage ping from convdev index. !22545 (Anand Capur) - fix link to enable usage ping from convdev index. !22545 (Anand Capur)
- Update gitlab-ui dependency to 1.8.0-hotfix.1 to fix IE11 bug. - Update gitlab-ui dependency to 1.8.0-hotfix.1 to fix IE11 bug.
- Remove duplicate escape in job sidebar. - Remove duplicate escape in job sidebar.
...@@ -324,7 +319,6 @@ entry. ...@@ -324,7 +319,6 @@ entry.
- Fix loading issue on some merge request discussion. !21982 - Fix loading issue on some merge request discussion. !21982
- Fix project deletion when there is a export available. !22276 - Fix project deletion when there is a export available. !22276
- No changes.
## 11.3.3 (2018-10-04) ## 11.3.3 (2018-10-04)
......
...@@ -103,6 +103,12 @@ picked into the stable branches) up to the 19th of the month. Such merge ...@@ -103,6 +103,12 @@ picked into the stable branches) up to the 19th of the month. Such merge
requests should have the ~"feature flag" label assigned, and don't require a requests should have the ~"feature flag" label assigned, and don't require a
corresponding exception request to be created. corresponding exception request to be created.
In order to build the final package and present the feature for self-hosted
customers, the feature flag should be removed. This should happen before the
22nd, ideally _at least_ 2 days before. That means MRs with feature
flags being picked at the 19th would have a quite tight schedule, so picking
these _earlier_ is preferable.
While rare, release managers may decide to reject picking a change into a stable While rare, release managers may decide to reject picking a change into a stable
branch, even when feature flags are used. This might be necessary if the changes branch, even when feature flags are used. This might be necessary if the changes
are deemed problematic, too invasive, or there simply isn't enough time to are deemed problematic, too invasive, or there simply isn't enough time to
......
...@@ -158,10 +158,16 @@ class GfmAutoComplete { ...@@ -158,10 +158,16 @@ class GfmAutoComplete {
// Team Members // Team Members
$input.atwho({ $input.atwho({
at: '@', at: '@',
alias: 'users',
displayTpl(value) { displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template; let tmpl = GfmAutoComplete.Loading.template;
if (value.username != null) { const { avatarTag, username, title } = value;
tmpl = GfmAutoComplete.Members.template; if (username != null) {
tmpl = GfmAutoComplete.Members.templateFunction({
avatarTag,
username,
title,
});
} }
return tmpl; return tmpl;
}, },
...@@ -572,8 +578,9 @@ GfmAutoComplete.Emoji = { ...@@ -572,8 +578,9 @@ GfmAutoComplete.Emoji = {
}; };
// Team Members // Team Members
GfmAutoComplete.Members = { GfmAutoComplete.Members = {
// eslint-disable-next-line no-template-curly-in-string templateFunction({ avatarTag, username, title }) {
template: '<li>${avatarTag} ${username} <small>${title}</small></li>', return `<li>${avatarTag} ${username} <small>${_.escape(title)}</small></li>`;
},
}; };
GfmAutoComplete.Labels = { GfmAutoComplete.Labels = {
template: template:
......
...@@ -10,6 +10,7 @@ export default class UserOverviewBlock { ...@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
limit: DEFAULT_LIMIT, limit: DEFAULT_LIMIT,
...options.requestParams, ...options.requestParams,
}; };
this.postRenderCallback = options.postRenderCallback;
this.loadData(); this.loadData();
} }
...@@ -43,5 +44,9 @@ export default class UserOverviewBlock { ...@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
} }
loadingEl.classList.add('hide'); loadingEl.classList.add('hide');
if (this.postRenderCallback) {
this.postRenderCallback.call(this);
}
} }
} }
...@@ -2,7 +2,8 @@ import $ from 'jquery'; ...@@ -2,7 +2,8 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import Activities from '~/activities'; import Activities from '~/activities';
import { localTimeAgo } from '~/lib/utils/datetime_utility'; import { localTimeAgo } from '~/lib/utils/datetime_utility';
import { __, sprintf } from '~/locale'; import AjaxCache from '~/lib/utils/ajax_cache';
import { __ } from '~/locale';
import flash from '~/flash'; import flash from '~/flash';
import ActivityCalendar from './activity_calendar'; import ActivityCalendar from './activity_calendar';
import UserOverviewBlock from './user_overview_block'; import UserOverviewBlock from './user_overview_block';
...@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block'; ...@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
* </div> * </div>
*/ */
const CALENDAR_TEMPLATES = { const CALENDAR_TEMPLATE = `
activity: ` <div class="clearfix calendar">
<div class="clearfix calendar"> <div class="js-contrib-calendar"></div>
<div class="js-contrib-calendar"></div> <div class="calendar-hint bottom-right"></div>
<div class="calendar-hint bottom-right"></div> </div>
</div> `;
`,
overview: `
<div class="clearfix calendar">
<div class="calendar-hint"></div>
<div class="js-contrib-calendar prepend-top-20"></div>
</div>
`,
};
const CALENDAR_PERIOD_6_MONTHS = 6; const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12; const CALENDAR_PERIOD_12_MONTHS = 12;
/* computation based on
* width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
* (see activity_calendar.js)
*/
const OVERVIEW_CALENDAR_BREAKPOINT = 918;
export default class UserTabs { export default class UserTabs {
constructor({ defaultAction, action, parentEl }) { constructor({ defaultAction, action, parentEl }) {
...@@ -105,6 +103,12 @@ export default class UserTabs { ...@@ -105,6 +103,12 @@ export default class UserTabs {
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]') .off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event)) .on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event))
.on('click', '.gl-pagination a', event => this.changeProjectsPage(event)); .on('click', '.gl-pagination a', event => this.changeProjectsPage(event));
window.addEventListener('resize', () => this.onResize());
}
onResize() {
this.loadActivityCalendar();
} }
changeProjectsPage(e) { changeProjectsPage(e) {
...@@ -167,8 +171,6 @@ export default class UserTabs { ...@@ -167,8 +171,6 @@ export default class UserTabs {
return; return;
} }
this.loadActivityCalendar('activity');
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Activities('#activity'); new Activities('#activity');
...@@ -180,10 +182,10 @@ export default class UserTabs { ...@@ -180,10 +182,10 @@ export default class UserTabs {
return; return;
} }
this.loadActivityCalendar('overview'); this.loadActivityCalendar();
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', { UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
requestParams: { limit: 5 }, requestParams: { limit: 10 },
}); });
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', { UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true }, requestParams: { limit: 10, skip_pagination: true },
...@@ -198,52 +200,39 @@ export default class UserTabs { ...@@ -198,52 +200,39 @@ export default class UserTabs {
container, container,
url: $(`${container} .overview-content-list`).data('href'), url: $(`${container} .overview-content-list`).data('href'),
...options, ...options,
postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
}); });
} }
loadActivityCalendar(action) { loadActivityCalendar() {
const monthsAgo = action === 'overview' ? CALENDAR_PERIOD_6_MONTHS : CALENDAR_PERIOD_12_MONTHS;
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar'); const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
const calendarPath = $calendarWrap.data('calendarPath'); const calendarPath = $calendarWrap.data('calendarPath');
AjaxCache.retrieve(calendarPath)
.then(data => UserTabs.renderActivityCalendar(data, $calendarWrap))
.catch(() => flash(__('There was an error loading users activity calendar.')));
}
static renderActivityCalendar(data, $calendarWrap) {
const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath'); const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset'); const utcOffset = $calendarWrap.data('utcOffset');
let utcFormatted = 'UTC'; const calendarHint = __('Issues, merge requests, pushes and comments.');
if (utcOffset !== 0) {
utcFormatted = `UTC${utcOffset > 0 ? '+' : ''}${utcOffset / 3600}`;
}
axios $calendarWrap.html(CALENDAR_TEMPLATE);
.get(calendarPath)
.then(({ data }) => { $calendarWrap.find('.calendar-hint').text(calendarHint);
$calendarWrap.html(CALENDAR_TEMPLATES[action]);
// eslint-disable-next-line no-new
let calendarHint = ''; new ActivityCalendar(
'.tab-pane.active .js-contrib-calendar',
if (action === 'activity') { '.tab-pane.active .user-calendar-activities',
calendarHint = sprintf( data,
__( calendarActivitiesPath,
'Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})', utcOffset,
), 0,
{ utcFormatted }, monthsAgo,
); );
} else if (action === 'overview') {
calendarHint = __('Issues, merge requests, pushes and comments.');
}
$calendarWrap.find('.calendar-hint').text(calendarHint);
// eslint-disable-next-line no-new
new ActivityCalendar(
'.tab-pane.active .js-contrib-calendar',
'.tab-pane.active .user-calendar-activities',
data,
calendarActivitiesPath,
utcOffset,
0,
monthsAgo,
);
})
.catch(() => flash(__('There was an error loading users activity calendar.')));
} }
toggleLoading(status) { toggleLoading(status) {
...@@ -267,4 +256,11 @@ export default class UserTabs { ...@@ -267,4 +256,11 @@ export default class UserTabs {
getCurrentAction() { getCurrentAction() {
return this.$parentEl.find('.nav-links a.active').data('action'); return this.$parentEl.find('.nav-links a.active').data('action');
} }
static getVisibleCalendarPeriod($calendarWrap) {
const width = $calendarWrap.width();
return width < OVERVIEW_CALENDAR_BREAKPOINT
? CALENDAR_PERIOD_6_MONTHS
: CALENDAR_PERIOD_12_MONTHS;
}
} }
...@@ -34,14 +34,7 @@ export default { ...@@ -34,14 +34,7 @@ export default {
fileSizeReadable() { fileSizeReadable() {
return numberToHumanSize(this.fileSize); return numberToHumanSize(this.fileSize);
}, },
dimensionStyles() {
if (!this.isLoaded) return {};
return {
width: `${this.width}px`,
height: `${this.height}px`,
};
},
hasFileSize() { hasFileSize() {
return this.fileSize > 0; return this.fileSize > 0;
}, },
...@@ -89,7 +82,6 @@ export default { ...@@ -89,7 +82,6 @@ export default {
<div> <div>
<div <div
:class="innerCssClasses" :class="innerCssClasses"
:style="dimensionStyles"
class="position-relative" class="position-relative"
> >
<img <img
......
...@@ -25,7 +25,7 @@ export default { ...@@ -25,7 +25,7 @@ export default {
swipeMaxWidth: undefined, swipeMaxWidth: undefined,
swipeMaxHeight: undefined, swipeMaxHeight: undefined,
swipeBarPos: 1, swipeBarPos: 1,
swipeWrapWidth: undefined, swipeWrapWidth: 0,
}; };
}, },
computed: { computed: {
...@@ -63,7 +63,7 @@ export default { ...@@ -63,7 +63,7 @@ export default {
leftValue = clientWidth - spaceLeft; leftValue = clientWidth - spaceLeft;
} }
this.swipeWrapWidth = this.swipeMaxWidth - leftValue; this.swipeWrapWidth = (leftValue / clientWidth) * 100;
this.swipeBarPos = leftValue; this.swipeBarPos = leftValue;
}, },
startDrag() { startDrag() {
...@@ -81,7 +81,6 @@ export default { ...@@ -81,7 +81,6 @@ export default {
// Add 2 for border width // Add 2 for border width
this.swipeMaxWidth = this.swipeMaxWidth =
Math.max(this.swipeOldImgInfo.renderedWidth, this.swipeNewImgInfo.renderedWidth) + 2; Math.max(this.swipeOldImgInfo.renderedWidth, this.swipeNewImgInfo.renderedWidth) + 2;
this.swipeWrapWidth = this.swipeMaxWidth;
this.swipeMaxHeight = this.swipeMaxHeight =
Math.max(this.swipeOldImgInfo.renderedHeight, this.swipeNewImgInfo.renderedHeight) + 2; Math.max(this.swipeOldImgInfo.renderedHeight, this.swipeNewImgInfo.renderedHeight) + 2;
...@@ -107,10 +106,6 @@ export default { ...@@ -107,10 +106,6 @@ export default {
<div class="swipe view"> <div class="swipe view">
<div <div
ref="swipeFrame" ref="swipeFrame"
:style="{
'width': swipeMaxPixelWidth,
'height': swipeMaxPixelHeight,
}"
class="swipe-frame"> class="swipe-frame">
<image-viewer <image-viewer
key="swipeOldImg" key="swipeOldImg"
...@@ -123,14 +118,17 @@ export default { ...@@ -123,14 +118,17 @@ export default {
<div <div
ref="swipeWrap" ref="swipeWrap"
:style="{ :style="{
'width': swipeWrapPixelWidth, width: `${swipeWrapWidth}%`
'height': swipeMaxPixelHeight,
}" }"
class="swipe-wrap"> class="swipe-wrap"
>
<image-viewer <image-viewer
key="swipeNewImg" key="swipeNewImg"
:render-info="false" :render-info="false"
:path="newPath" :path="newPath"
:style="{
width: swipeMaxPixelWidth
}"
class="frame added" class="frame added"
@imgLoaded="swipeNewImgLoaded" @imgLoaded="swipeNewImgLoaded"
> >
......
...@@ -19,18 +19,18 @@ export default { ...@@ -19,18 +19,18 @@ export default {
</script> </script>
<template> <template>
<div class="two-up view"> <div class="two-up view d-flex">
<image-viewer <image-viewer
:path="oldPath" :path="oldPath"
:render-info="true" :render-info="true"
inner-css-classes="frame deleted" inner-css-classes="frame deleted"
class="wrap" class="wrap w-50"
/> />
<image-viewer <image-viewer
:path="newPath" :path="newPath"
:render-info="true" :render-info="true"
:inner-css-classes="['frame', 'added']" :inner-css-classes="['frame', 'added']"
class="wrap" class="wrap w-50"
> >
<slot <slot
slot="image-overlay" slot="image-overlay"
......
...@@ -253,19 +253,6 @@ ...@@ -253,19 +253,6 @@
right: 7px; right: 7px;
} }
.frame {
top: 0;
right: 0;
position: absolute;
&.deleted {
margin: 0;
display: block;
top: 13px;
right: 7px;
}
}
.swipe-bar { .swipe-bar {
display: block; display: block;
height: 100%; height: 100%;
...@@ -435,7 +422,7 @@ ...@@ -435,7 +422,7 @@
.onion-skin.view { .onion-skin.view {
.swipe-wrap { .swipe-wrap {
top: 0; top: 0;
right: 0; left: 0;
} }
.frame.deleted { .frame.deleted {
......
...@@ -178,7 +178,7 @@ class GroupDescendantsFinder ...@@ -178,7 +178,7 @@ class GroupDescendantsFinder
end end
def sort def sort
params.fetch(:sort, 'id_asc') params.fetch(:sort, 'created_desc')
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
......
...@@ -1053,11 +1053,19 @@ class Repository ...@@ -1053,11 +1053,19 @@ class Repository
end end
def cache def cache
@cache ||= Gitlab::RepositoryCache.new(self) @cache ||= if is_wiki
Gitlab::RepositoryCache.new(self, extra_namespace: 'wiki')
else
Gitlab::RepositoryCache.new(self)
end
end end
def request_store_cache def request_store_cache
@request_store_cache ||= Gitlab::RepositoryCache.new(self, backend: Gitlab::SafeRequestStore) @request_store_cache ||= if is_wiki
Gitlab::RepositoryCache.new(self, extra_namespace: 'wiki', backend: Gitlab::SafeRequestStore)
else
Gitlab::RepositoryCache.new(self, backend: Gitlab::SafeRequestStore)
end
end end
def tags_sorted_by_committed_date def tags_sorted_by_committed_date
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.project-header.d-flex.flex-row.flex-wrap.align-items-center.append-bottom-8 .project-header.d-flex.flex-row.flex-wrap.align-items-center.append-bottom-8
.project-title-row.d-flex.align-items-center .project-title-row.d-flex.align-items-center
.avatar-container.project-avatar.float-none .avatar-container.project-avatar.float-none
= project_icon(@project, alt: @project.name, class: 'avatar avatar-tile') = project_icon(@project, alt: @project.name, class: 'avatar avatar-tile s24', width: 24, height: 24)
%h1.project-title.d-flex.align-items-baseline.qa-project-name %h1.project-title.d-flex.align-items-baseline.qa-project-name
= @project.name = @project.name
.project-metadata.d-flex.flex-row.flex-wrap.align-items-baseline .project-metadata.d-flex.flex-row.flex-wrap.align-items-baseline
......
- diff_file = viewer.diff_file - diff_file = viewer.diff_file
- url = url_for(safe_params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path, file_identifier: diff_file.file_identifier)) - url = url_for(safe_params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path, file_identifier: diff_file.file_identifier))
.nothing-here-block.diff-collapsed{ data: { diff_for_path: url } } .nothing-here-block.diff-collapsed{ data: { diff_for_path: url } }
This diff is collapsed. = _("This diff is collapsed.")
%button.click-to-expand.btn.btn-link Click to expand it. %button.click-to-expand.btn.btn-link= _("Click to expand it.")
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.files-changed-inner .files-changed-inner
.inline-parallel-buttons.d-none.d-sm-none.d-md-block .inline-parallel-buttons.d-none.d-sm-none.d-md-block
- if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? } - if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? }
= link_to 'Expand all', url_for(safe_params.merge(expanded: 1, format: nil)), class: 'btn btn-default' = link_to _('Expand all'), url_for(safe_params.merge(expanded: 1, format: nil)), class: 'btn btn-default'
- if show_whitespace_toggle - if show_whitespace_toggle
- if current_controller?(:commit) - if current_controller?(:commit)
= commit_diff_whitespace_link(diffs.project, @commit, class: 'd-none d-sm-inline-block') = commit_diff_whitespace_link(diffs.project, @commit, class: 'd-none d-sm-inline-block')
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
- blob = diff_file.blob - blob = diff_file.blob
.file-actions.d-none.d-sm-block .file-actions.d-none.d-sm-block
- if blob&.readable_text? - if blob&.readable_text?
= link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip', title: "Toggle comments for this file", disabled: @diff_notes_disabled do = link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip', title: _("Toggle comments for this file"), disabled: @diff_notes_disabled do
= icon('comment') = icon('comment')
\ \
- if editable_diff?(diff_file) - if editable_diff?(diff_file)
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
= diff_file.file_path = diff_file.file_path
- if diff_file.deleted_file? - if diff_file.deleted_file?
deleted = _("deleted")
= copy_file_path_button(diff_file.file_path) = copy_file_path_button(diff_file.file_path)
......
.nothing-here-block .nothing-here-block
This #{viewer.switcher_title} could not be displayed because #{diff_render_error_reason(viewer)}. = _("This %{viewer} could not be displayed because %{reason}.") % { viewer: viewer.switcher_title, reason: diff_render_error_reason(viewer) }
You can You can
= diff_render_error_options(viewer).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ').html_safe = diff_render_error_options(viewer).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ').html_safe
......
...@@ -38,4 +38,4 @@ ...@@ -38,4 +38,4 @@
\-#{diff_file.removed_lines} \-#{diff_file.removed_lines}
%li.dropdown-menu-empty-item.hidden %li.dropdown-menu-empty-item.hidden
%a %a
No files found. = _("No files found.")
- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES - too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES
- if too_big - if too_big
.suppressed-container .suppressed-container
%a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. %a.show-suppressed-diff.js-show-suppressed-diff= _("Changes suppressed. Click to show.")
%table.text-file.diff-wrap-lines.code.js-syntax-highlight.commit-diff{ data: diff_view_data, class: too_big ? 'hide' : '' } %table.text-file.diff-wrap-lines.code.js-syntax-highlight.commit-diff{ data: diff_view_data, class: too_big ? 'hide' : '' }
= render partial: "projects/diffs/line", = render partial: "projects/diffs/line",
......
.alert.alert-warning .alert.alert-warning
%h4 %h4
Too many changes to show. = _("Too many changes to show.")
.float-right .float-right
- if current_controller?(:commit) - if current_controller?(:commit)
= link_to "Plain diff", project_commit_path(@project, @commit, format: :diff), class: "btn btn-sm" = link_to _("Plain diff"), project_commit_path(@project, @commit, format: :diff), class: "btn btn-sm"
= link_to "Email patch", project_commit_path(@project, @commit, format: :patch), class: "btn btn-sm" = link_to _("Email patch"), project_commit_path(@project, @commit, format: :patch), class: "btn btn-sm"
- elsif current_controller?('projects/merge_requests/diffs') && @merge_request&.persisted? - elsif current_controller?('projects/merge_requests/diffs') && @merge_request&.persisted?
= link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-sm" = link_to _("Plain diff"), merge_request_path(@merge_request, format: :diff), class: "btn btn-sm"
= link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-sm" = link_to _("Email patch"), merge_request_path(@merge_request, format: :patch), class: "btn btn-sm"
%p %p
To preserve performance only = _("To preserve performance only <strong>%{display_size} of ${real_size}</strong> files are displayed.").html_safe % { display_size: diff_files.size, real_size: diff_files.real_size }
%strong #{diff_files.size} of #{diff_files.real_size}
files are displayed.
.nothing-here-block .nothing-here-block
File added = _("File added")
.nothing-here-block .nothing-here-block
File deleted = _("File deleted")
- diff_file = viewer.diff_file - diff_file = viewer.diff_file
.nothing-here-block .nothing-here-block
File mode changed from #{diff_file.a_mode} to #{diff_file.b_mode} = _("File mode changed from %{a_mode} to %{b_mode}") % { a_mode: diff_file.a_mode, b_mode: diff_file.b_mode }
.nothing-here-block .nothing-here-block
No preview for this file type = _("No preview for this file type")
.nothing-here-block .nothing-here-block
This diff was suppressed by a .gitattributes entry. = _("This diff was suppressed by a .gitattributes entry.")
.nothing-here-block .nothing-here-block
File moved = _("File moved")
- if environment.external_url && can?(current_user, :read_environment, environment) - if environment.external_url && can?(current_user, :read_environment, environment)
= link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url has-tooltip qa-view-deployment', title: s_('Environments|Open live environment') do = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url has-tooltip qa-view-deployment', title: s_('Environments|Open live environment') do
= sprite_icon('external-link') = sprite_icon('external-link')
View deployment = _("View deployment")
.row.prepend-top-default.append-bottom-default .row.prepend-top-default.append-bottom-default
.col-lg-3 .col-lg-3
%h4.prepend-top-0 %h4.prepend-top-0
Environments = _("Environments")
%p %p
Environments allow you to track deployments of your application - link_to_read_more = link_to(_("Read more about environments"), help_page_path("ci/environments"))
= succeed "." do = _("Environments allow you to track deployments of your application %{link_to_read_more}.").html_safe % { link_to_read_more: link_to_read_more }
= link_to "Read more about environments", help_page_path("ci/environments")
= form_for [@project.namespace.becomes(Namespace), @project, @environment], html: { class: 'col-lg-9' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @environment], html: { class: 'col-lg-9' } do |f|
= form_errors(@environment) = form_errors(@environment)
.form-group .form-group
= f.label :name, 'Name', class: 'label-bold' = f.label :name, _('Name'), class: 'label-bold'
= f.text_field :name, required: true, class: 'form-control' = f.text_field :name, required: true, class: 'form-control'
.form-group .form-group
= f.label :external_url, 'External URL', class: 'label-bold' = f.label :external_url, _('External URL'), class: 'label-bold'
= f.url_field :external_url, class: 'form-control' = f.url_field :external_url, class: 'form-control'
.form-actions .form-actions
= f.submit 'Save', class: 'btn btn-success' = f.submit _('Save'), class: 'btn btn-save'
= link_to 'Cancel', project_environments_path(@project), class: 'btn btn-cancel' = link_to _('Cancel'), project_environments_path(@project), class: 'btn btn-cancel'
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
- return unless can?(current_user, :read_environment, environment) - return unless can?(current_user, :read_environment, environment)
= link_to environment_metrics_path(environment), title: 'See metrics', class: 'btn metrics-button' do = link_to environment_metrics_path(environment), title: _('See metrics'), class: 'btn metrics-button' do
= sprite_icon('chart') = sprite_icon('chart')
Monitoring = _("Monitoring")
- @no_container = true - @no_container = true
- page_title "Edit", @environment.name, "Environments" - page_title _("Edit"), @environment.name, _("Environments")
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
Edit environment = _('Edit environment')
%hr %hr
= render 'form' = render 'form'
- @no_container = true - @no_container = true
- page_title "Environments" - page_title _("Environments")
#environments-folder-list-view{ data: { endpoint: folder_project_environments_path(@project, @folder, format: :json), #environments-folder-list-view{ data: { endpoint: folder_project_environments_path(@project, @folder, format: :json),
"folder-name" => @folder, "folder-name" => @folder,
......
- @no_container = true - @no_container = true
- page_title "Environments" - page_title _("Environments")
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project)) - add_to_breadcrumbs(_("Pipelines"), project_pipelines_path(@project))
#environments-list-view{ data: { environments_data: environments_list_data, #environments-list-view{ data: { environments_data: environments_list_data,
"can-create-deployment" => can?(current_user, :create_deployment, @project).to_s, "can-create-deployment" => can?(current_user, :create_deployment, @project).to_s,
......
- @no_container = true - @no_container = true
- page_title "Metrics for environment", @environment.name - page_title _("Metrics for environment"), @environment.name
.prometheus-container{ class: container_class } .prometheus-container{ class: container_class }
#prometheus-graphs{ data: metrics_data(@project, @environment) } #prometheus-graphs{ data: metrics_data(@project, @environment) }
- @no_container = true - @no_container = true
- breadcrumb_title "Environments" - breadcrumb_title _("Environments")
- page_title 'New Environment' - page_title _("New Environment")
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
New environment = _("New environment")
%hr %hr
= render 'form' = render 'form'
- @no_container = true - @no_container = true
- add_to_breadcrumbs "Environments", project_environments_path(@project) - add_to_breadcrumbs _("Environments"), project_environments_path(@project)
- breadcrumb_title @environment.name - breadcrumb_title @environment.name
- page_title "Environments" - page_title _("Environments")
%div{ class: container_class } %div{ class: container_class }
- if can?(current_user, :stop_environment, @environment) - if can?(current_user, :stop_environment, @environment)
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
.modal-content .modal-content
.modal-header .modal-header
%h4.modal-title.d-flex.mw-100 %h4.modal-title.d-flex.mw-100
Stopping = s_("Environments|Stopping")
%span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } } %span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } }
= @environment.name = @environment.name
? ?
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
= render 'projects/environments/external_url', environment: @environment = render 'projects/environments/external_url', environment: @environment
= render 'projects/environments/metrics_button', environment: @environment = render 'projects/environments/metrics_button', environment: @environment
- if can?(current_user, :update_environment, @environment) - if can?(current_user, :update_environment, @environment)
= link_to 'Edit', edit_project_environment_path(@project, @environment), class: 'btn' = link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
- if can?(current_user, :stop_environment, @environment) - if can?(current_user, :stop_environment, @environment)
= button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal', = button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal',
target: '#stop-environment-modal' } do target: '#stop-environment-modal' } do
...@@ -52,21 +52,19 @@ ...@@ -52,21 +52,19 @@
.empty-state .empty-state
.text-content .text-content
%h4.state-title %h4.state-title
You don't have any deployments right now. = _("You don't have any deployments right now.")
%p.blank-state-text %p.blank-state-text
Define environments in the deploy stage(s) in = _("Define environments in the deploy stage(s) in <code>.gitlab-ci.yml</code> to track deployments here.").html_safe
%code .gitlab-ci.yml
to track deployments here.
.text-center .text-center
= link_to _("Read more"), help_page_path("ci/environments"), class: "btn btn-success" = link_to _("Read more"), help_page_path("ci/environments"), class: "btn btn-success"
- else - else
.table-holder .table-holder
.ci-table.environments{ role: 'grid' } .ci-table.environments{ role: 'grid' }
.gl-responsive-table-row.table-row-header{ role: 'row' } .gl-responsive-table-row.table-row-header{ role: 'row' }
.table-section.section-10{ role: 'columnheader' } ID .table-section.section-10{ role: 'columnheader' }= _('ID')
.table-section.section-30{ role: 'columnheader' } Commit .table-section.section-30{ role: 'columnheader' }= _('Commit')
.table-section.section-25{ role: 'columnheader' } Job .table-section.section-25{ role: 'columnheader' }= _('Job')
.table-section.section-15{ role: 'columnheader' } Created .table-section.section-15{ role: 'columnheader' }= _('Created')
= render @deployments = render @deployments
......
- @no_container = true - @no_container = true
- page_title "Terminal for environment", @environment.name - page_title _("Terminal for environment"), @environment.name
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm.css" = stylesheet_link_tag "xterm.css"
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.row .row
.col-sm-6 .col-sm-6
%h3.page-title %h3.page-title
Terminal for environment = _("Terminal for environment")
= @environment.name = @environment.name
.col-sm-6 .col-sm-6
......
- @no_container = true - @no_container = true
- page_title "Charts" - page_title _("Contribution Charts")
.repo-charts{ class: container_class } .repo-charts{ class: container_class }
%h4.sub-header %h4.sub-header
......
- @no_container = true - @no_container = true
- breadcrumb_title "CI / CD Charts" - page_title _("CI / CD Charts")
- page_title _("Charts"), _("Pipelines")
%div{ class: container_class } %div{ class: container_class }
.sub-header-block .sub-header-block
......
#js-authenticate-u2f #js-authenticate-u2f
%a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' } Sign in via 2FA code %a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' }= _("Sign in via 2FA code")
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
%script#js-authenticate-u2f-in-progress{ type: "text/template" } %script#js-authenticate-u2f-in-progress{ type: "text/template" }
%p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now. %p= _("Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.")
%script#js-authenticate-u2f-error{ type: "text/template" } %script#js-authenticate-u2f-error{ type: "text/template" }
%div %div
%p <%= error_message %> (error code: <%= error_code %>) %p <%= error_message %> (#{_("error code:")} <%= error_code %>)
%a.btn.btn-block.btn-warning#js-u2f-try-again Try again? %a.btn.btn-block.btn-warning#js-u2f-try-again= _("Try again?")
%script#js-authenticate-u2f-authenticated{ type: "text/template" } %script#js-authenticate-u2f-authenticated{ type: "text/template" }
%div %div
%p We heard back from your U2F device. You have been authenticated. %p= _("We heard back from your U2F device. You have been authenticated.")
= form_tag(new_user_session_path, method: :post, id: 'js-login-u2f-form') do |f| = form_tag(new_user_session_path, method: :post, id: 'js-login-u2f-form') do |f|
- resource_params = params[resource_name].presence || params - resource_params = params[resource_name].presence || params
= hidden_field_tag 'user[remember_me]', resource_params.fetch(:remember_me, 0) = hidden_field_tag 'user[remember_me]', resource_params.fetch(:remember_me, 0)
......
...@@ -2,39 +2,39 @@ ...@@ -2,39 +2,39 @@
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
%script#js-register-u2f-not-supported{ type: "text/template" } %script#js-register-u2f-not-supported{ type: "text/template" }
%p Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer). %p= _("Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer).")
%script#js-register-u2f-setup{ type: "text/template" } %script#js-register-u2f-setup{ type: "text/template" }
- if current_user.two_factor_otp_enabled? - if current_user.two_factor_otp_enabled?
.row.append-bottom-10 .row.append-bottom-10
.col-md-4 .col-md-4
%button#js-setup-u2f-device.btn.btn-info.btn-block Set up new U2F device %button#js-setup-u2f-device.btn.btn-info.btn-block= _("Set up new U2F device")
.col-md-8 .col-md-8
%p Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left. %p= _("Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left.")
- else - else
.row.append-bottom-10 .row.append-bottom-10
.col-md-4 .col-md-4
%button#js-setup-u2f-device.btn.btn-info.btn-block{ disabled: true } Set up new U2F device %button#js-setup-u2f-device.btn.btn-info.btn-block{ disabled: true }= _("Set up new U2F device")
.col-md-8 .col-md-8
%p.text-warning You need to register a two-factor authentication app before you can set up a U2F device. %p.text-warning= _("You need to register a two-factor authentication app before you can set up a U2F device.")
%script#js-register-u2f-in-progress{ type: "text/template" } %script#js-register-u2f-in-progress{ type: "text/template" }
%p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now. %p= _("Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now.")
%script#js-register-u2f-error{ type: "text/template" } %script#js-register-u2f-error{ type: "text/template" }
%div %div
%p %p
%span <%= error_message %> (error code: <%= error_code %>) %span <%= error_message %> (#{_("error code:")} <%= error_code %>)
%a.btn.btn-warning#js-u2f-try-again Try again? %a.btn.btn-warning#js-u2f-try-again= _("Try again?")
%script#js-register-u2f-registered{ type: "text/template" } %script#js-register-u2f-registered{ type: "text/template" }
.row.append-bottom-10 .row.append-bottom-10
.col-md-12 .col-md-12
%p Your device was successfully set up! Give it a name and register it with the GitLab server. %p= _("Your device was successfully set up! Give it a name and register it with the GitLab server.")
= form_tag(create_u2f_profile_two_factor_auth_path, method: :post) do = form_tag(create_u2f_profile_two_factor_auth_path, method: :post) do
.row.append-bottom-10 .row.append-bottom-10
.col-md-3 .col-md-3
= text_field_tag 'u2f_registration[name]', nil, class: 'form-control', placeholder: "Pick a name" = text_field_tag 'u2f_registration[name]', nil, class: 'form-control', placeholder: _("Pick a name")
.col-md-3 .col-md-3
= hidden_field_tag 'u2f_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response" = hidden_field_tag 'u2f_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
= submit_tag "Register U2F device", class: "btn btn-success" = submit_tag _("Register U2F device"), class: "btn btn-success"
.row
.col-12
.calendar-block.prepend-top-default.append-bottom-default
.user-calendar.d-none.d-sm-block{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
%h4.center.light
= spinner nil, true
.user-calendar-activities.d-none.d-sm-block
.row .row
.col-md-12.col-lg-6 .col-md-12.col-lg-6
.calendar-block
.content-block.hide-bottom-border
%h4
= s_('UserProfile|Activity')
.user-calendar.d-none.d-sm-block.text-left{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
%h4.center.light
%i.fa.fa-spinner.fa-spin
.user-calendar-activities.d-none.d-sm-block
- if can?(current_user, :read_cross_project) - if can?(current_user, :read_cross_project)
.activities-block .activities-block
.border-bottom.prepend-top-16 .prepend-top-16
%h5 .d-flex.align-items-center.border-bottom
= s_('UserProfile|Recent contributions') %h4.flex-grow
= s_('UserProfile|Activity')
= link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_path } } .overview-content-list{ data: { href: user_path } }
.center.light.loading .center.light.loading
%i.fa.fa-spinner.fa-spin = spinner nil, true
.prepend-top-10
= link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.col-md-12.col-lg-6 .col-md-12.col-lg-6
.projects-block .projects-block
.border-bottom.prepend-top-16 .prepend-top-16
%h4 .d-flex.align-items-center.border-bottom
= s_('UserProfile|Personal projects') %h4.flex-grow
= s_('UserProfile|Personal projects')
= link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_projects_path } } .overview-content-list{ data: { href: user_projects_path } }
.center.light.loading .center.light.loading
%i.fa.fa-spinner.fa-spin = spinner nil, true
.prepend-top-10
= link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
...@@ -124,12 +124,6 @@ ...@@ -124,12 +124,6 @@
- if profile_tab?(:activity) - if profile_tab?(:activity)
#activity.tab-pane #activity.tab-pane
.row-content-block.calendar-block.white.second-block.d-none.d-sm-block
.user-calendar{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
%h4.center.light
%i.fa.fa-spinner.fa-spin
.user-calendar-activities
- if can?(current_user, :read_cross_project) - if can?(current_user, :read_cross_project)
%h4.prepend-top-20 %h4.prepend-top-20
= s_('UserProfile|Most Recent Activity') = s_('UserProfile|Most Recent Activity')
......
---
title: UI improvements to user's profile
merge_request: 22977
author:
type: other
---
title: Fix default sorting for subgroups and projects list
merge_request: 23058
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Fixes to AWS documentation spelling and grammar
merge_request: 23198
author: Brendan O'Leary
type: other
---
title: Drop default value on status column in deployments table
merge_request: 22971
author:
type: other
---
title: Enable even more frozen string for lib/gitlab
merge_request:
author: gfyoung
type: performance
---
title: Change breadcrumb title for contribution charts
merge_request: 23071
author: George Tsiolis
type: changed
---
title: Fix project identicon aligning Harry Kiselev
merge_request: 23166
author: Harry Kiselev
type: other
---
title: Escape user fullname while rendering autocomplete template to prevent XSS
merge_request:
author:
type: security
---
title: Prevent templated services from being imported
merge_request:
author:
type: security
...@@ -15,10 +15,10 @@ docs_paths_to_review = docs_paths_requiring_review(helper.all_changed_files) ...@@ -15,10 +15,10 @@ docs_paths_to_review = docs_paths_requiring_review(helper.all_changed_files)
unless docs_paths_to_review.empty? unless docs_paths_to_review.empty?
message 'This merge request adds or changes files that require a ' \ message 'This merge request adds or changes files that require a ' \
'review from the docs team.' 'review from the Docs team.'
markdown(<<~MARKDOWN) markdown(<<~MARKDOWN)
## Docs Review ## Docs review
The following files require a review from the Documentation team: The following files require a review from the Documentation team:
...@@ -32,24 +32,15 @@ the documentation. GitLabbers are also welcome to use the [#docs](https://gitlab ...@@ -32,24 +32,15 @@ the documentation. GitLabbers are also welcome to use the [#docs](https://gitlab
Who to ping [based on DevOps stages](https://about.gitlab.com/handbook/product/categories/#devops-stages): Who to ping [based on DevOps stages](https://about.gitlab.com/handbook/product/categories/#devops-stages):
| Stage | Tech writer | | Tech writer | Stage(s) |
| ------------- | ----------- | | ------------ | ------------------------------------------------------------ |
| ~Create | `@marcia` | | `@marcia` | ~Create ~Release |
| ~Configure | `@eread` | | `@axil` | ~Distribution ~Gitaly ~Gitter ~Monitoring ~Packaging ~Secure |
| ~Distribution | `@axil` | | `@eread` | ~Manage ~Configure ~Geo ~Verify |
| ~Geo | `@eread` | | `@mikelewis` | ~Plan |
| ~Gitaly | `@axil` |
| ~Gitter | `@axil` |
| ~Manage | `@eread` |
| ~Monitoring | `@axil` |
| ~Packaging | `@axil` |
| ~Plan | `@mikelewis`|
| ~Release | `marcia` |
| ~Secure | `@axil` |
| ~Verify | `@eread` |
If you are not sure which category the change falls within, or the change is not If you are not sure which category the change falls within, or the change is not
part of one of these categories, you can mention the whole team with `@gl-docsteam`. part of one of these categories, you can mention one of the usernames above.
MARKDOWN MARKDOWN
unless gitlab.mr_labels.include?('Documentation') unless gitlab.mr_labels.include?('Documentation')
......
# frozen_string_literal: true
class DropDefaultValueOnStatusDeployments < ActiveRecord::Migration
DOWNTIME = false
DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.state_machine.states['success'].value
def up
change_column_default :deployments, :status, nil
end
def down
change_column_default :deployments, :status, DEPLOYMENT_STATUS_SUCCESS
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20181107054254) do ActiveRecord::Schema.define(version: 20181112103239) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -924,7 +924,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do ...@@ -924,7 +924,7 @@ ActiveRecord::Schema.define(version: 20181107054254) do
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "on_stop" t.string "on_stop"
t.integer "status", limit: 2, default: 2, null: false t.integer "status", limit: 2, null: false
t.datetime_with_timezone "finished_at" t.datetime_with_timezone "finished_at"
t.index ["created_at"], name: "index_deployments_on_created_at", using: :btree t.index ["created_at"], name: "index_deployments_on_created_at", using: :btree
t.index ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree t.index ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree
......
...@@ -134,9 +134,9 @@ should be more than enough. ...@@ -134,9 +134,9 @@ should be more than enough.
When removing an index make sure to use the method `remove_concurrent_index` instead When removing an index make sure to use the method `remove_concurrent_index` instead
of the regular `remove_index` method. The `remove_concurrent_index` method of the regular `remove_index` method. The `remove_concurrent_index` method
automatically drops concurrent indexes when using PostgreSQL, removing the automatically drops concurrent indexes when using PostgreSQL, removing the
need for downtime. To use this method you must disable transactions by calling need for downtime. To use this method you must disable single-transaction mode
the method `disable_ddl_transaction!` in the body of your migration class like by calling the method `disable_ddl_transaction!` in the body of your migration
so: class like so:
```ruby ```ruby
class MyMigration < ActiveRecord::Migration class MyMigration < ActiveRecord::Migration
......
...@@ -9,7 +9,7 @@ in [significantly degraded performance](https://gitlab.com/gitlab-org/gitlab-ee/ ...@@ -9,7 +9,7 @@ in [significantly degraded performance](https://gitlab.com/gitlab-org/gitlab-ee/
GitLab on AWS can leverage many of the services that are already GitLab on AWS can leverage many of the services that are already
configurable with High Availability. These services have a lot of configurable with High Availability. These services have a lot of
flexibility and are able to adopt to most companies, best of all is the flexibility and are able to adapt to most companies, best of all is the
ability to automate both vertical and horizontal scaling. ability to automate both vertical and horizontal scaling.
In this article we'll go through a basic HA setup where we'll start by In this article we'll go through a basic HA setup where we'll start by
...@@ -55,9 +55,9 @@ and from the Actions dropdown choose Edit DNS Hostnames and select Yes. ...@@ -55,9 +55,9 @@ and from the Actions dropdown choose Edit DNS Hostnames and select Yes.
### Subnet ### Subnet
Now let's create some subnets in different Availability Zones. Make sure Now let's create some subnets in different Availability Zones. Make sure
that each subnet is associated the the VPC we just created, that it has that each subnet is associated to the VPC we just created, that it has
a distinct VPC and lastly that CIDR blocks don't overlap. This will also a distinct VPC and lastly that CIDR blocks don't overlap. This will also
allow us to enable multi AZ for redundancy. allow us to enable multi-AZ for redundancy.
We will create private and public subnets to match load balancers and We will create private and public subnets to match load balancers and
RDS instances as well. RDS instances as well.
...@@ -98,7 +98,7 @@ traffic from any destination. ...@@ -98,7 +98,7 @@ traffic from any destination.
![Subnet Config](img/ig-rt.png) ![Subnet Config](img/ig-rt.png)
Before leaving this screen select the next tab to the rgiht which is Before leaving this screen select the next tab to the right which is
Subnet Associations and add our public subnets. If you followed our Subnet Associations and add our public subnets. If you followed our
naming convention they should be easy to find. naming convention they should be easy to find.
...@@ -106,8 +106,8 @@ naming convention they should be easy to find. ...@@ -106,8 +106,8 @@ naming convention they should be easy to find.
## Database with RDS ## Database with RDS
For our database server we will use Amazon RDS which offers Multi AZ For our database server we will use Amazon RDS which offers Multi-AZ
for redundancy. Lets start by creating a subnet group and then we'll for redundancy. Let's start by creating a subnet group and then we'll
create the actual RDS instance. create the actual RDS instance.
### Subnet Group ### Subnet Group
...@@ -122,7 +122,7 @@ the VPC ID dropdown and at the bottom we can add our private subnets. ...@@ -122,7 +122,7 @@ the VPC ID dropdown and at the bottom we can add our private subnets.
Select the RDS service from the Database section and create a new Select the RDS service from the Database section and create a new
PostgreSQL instance. After choosing between a Production or PostgreSQL instance. After choosing between a Production or
Development instance we'll start with the actual configuration. On the Development instance we'll start with the actual configuration. On the
image bellow we have the settings for this article but note the image below we have the settings for this article but note the
following two options which are of particular interest for HA: following two options which are of particular interest for HA:
1. Multi-AZ-Deployment is recommended as redundancy. Read more at 1. Multi-AZ-Deployment is recommended as redundancy. Read more at
...@@ -133,7 +133,7 @@ IOPS (SSD) is best suited for HA. Read more about it at ...@@ -133,7 +133,7 @@ IOPS (SSD) is best suited for HA. Read more about it at
![RDS Instance Specs](img/instance_specs.png) ![RDS Instance Specs](img/instance_specs.png)
The rest of the setting on this page request a DB identifier, username The rest of the setting on this page request a DB identifier, username,
and a master password. We've chosen to use `gitlab-ha`, `gitlab` and a and a master password. We've chosen to use `gitlab-ha`, `gitlab` and a
very secure password respectively. Keep these in hand for later. very secure password respectively. Keep these in hand for later.
...@@ -152,7 +152,7 @@ EC is an in-memory hosted caching solution. Redis maintains its own ...@@ -152,7 +152,7 @@ EC is an in-memory hosted caching solution. Redis maintains its own
persistence and is used for certain types of application. persistence and is used for certain types of application.
Let's choose the ElastiCache service in the Database section from our Let's choose the ElastiCache service in the Database section from our
AWS console. Now lets create a cache subnet group which will be very AWS console. Now let's create a cache subnet group which will be very
similar to the RDS subnet group. Make sure to select our VPC and its similar to the RDS subnet group. Make sure to select our VPC and its
private subnets. private subnets.
...@@ -160,7 +160,7 @@ private subnets. ...@@ -160,7 +160,7 @@ private subnets.
Now press the Launch a Cache Cluster and choose Redis for our Now press the Launch a Cache Cluster and choose Redis for our
DB engine. You'll be able to configure details such as replication, DB engine. You'll be able to configure details such as replication,
Multi AZ and node types. The second section will allow us to choose our Multi-AZ and node types. The second section will allow us to choose our
subnet and security group and subnet and security group and
![Redis Cluster details](img/redis-cluster-det.png) ![Redis Cluster details](img/redis-cluster-det.png)
...@@ -274,7 +274,7 @@ username, and password. ...@@ -274,7 +274,7 @@ username, and password.
gitlab_rails['db_password'] = "mypassword" gitlab_rails['db_password'] = "mypassword"
gitlab_rails['db_host'] = "<rds-endpoint>" gitlab_rails['db_host'] = "<rds-endpoint>"
Next we only need to configure the Redis section by adding the host and Next, we only need to configure the Redis section by adding the host and
uncommenting the port. uncommenting the port.
...@@ -285,7 +285,7 @@ to make the EFS integration easier to manage. ...@@ -285,7 +285,7 @@ to make the EFS integration easier to manage.
gitlab_rails['redis_host'] = "<redis-endpoint>" gitlab_rails['redis_host'] = "<redis-endpoint>"
gitlab_rails['redis_port'] = 6379 gitlab_rails['redis_port'] = 6379
Finally run reconfigure, you might find it useful to run a check and Finally, run reconfigure. You might find it useful to run a check and
a service status to make sure everything has been set up correctly. a service status to make sure everything has been set up correctly.
sudo gitlab-ctl reconfigure sudo gitlab-ctl reconfigure
...@@ -321,10 +321,10 @@ The Load Balancer Health will allow us to indicate where to ping and what ...@@ -321,10 +321,10 @@ The Load Balancer Health will allow us to indicate where to ping and what
makes up a healthy or unhealthy instance. makes up a healthy or unhealthy instance.
We won't add the instance on the next session because we'll destroy it We won't add the instance on the next session because we'll destroy it
momentarily as we'll be using the image we where creating. We will keep momentarily as we'll be using the image we were creating. We will keep
the Enable Cross-Zone and Enable Connection Draining active. the Enable Cross-Zone and Enable Connection Draining active.
After we finish creating the Load Balancer we can re visit our Security After we finish creating the Load Balancer we can revisit our Security
Groups to improve access only through the ELB and any other requirement Groups to improve access only through the ELB and any other requirement
you might have. you might have.
...@@ -363,7 +363,7 @@ After this is launched we are able to start creating our Auto Scaling ...@@ -363,7 +363,7 @@ After this is launched we are able to start creating our Auto Scaling
Group. Start by giving it a name and assigning it our VPC and private Group. Start by giving it a name and assigning it our VPC and private
subnets. We also want to always start with two instances and if you subnets. We also want to always start with two instances and if you
scroll down to Advanced Details we can choose to receive traffic from ELBs. scroll down to Advanced Details we can choose to receive traffic from ELBs.
Lets enable that option and select our ELB. We also want to use the ELB's Let's enable that option and select our ELB. We also want to use the ELB's
health check. health check.
![Auto scaling](img/auto-scaling-det.png) ![Auto scaling](img/auto-scaling-det.png)
...@@ -388,9 +388,9 @@ we where aiming for. ...@@ -388,9 +388,9 @@ we where aiming for.
After you're done with the policies section have some fun trying to break After you're done with the policies section have some fun trying to break
instances. You should be able to see how the Auto Scaling Group and the instances. You should be able to see how the Auto Scaling Group and the
EC2 screen start bringing them up again. EC2 screen starts bringing them up again.
High Availability is a very big area, we went mostly through scaling and High Availability is a vast area, we went mostly through scaling and
some redundancy options but it might also imply Geographic replication. some redundancy options but it might also imply Geographic replication.
There is a lot of ground yet to cover so have a read through these other There is a lot of ground yet to cover so have a read through these other
resources and feel free to open an issue to request additional material. resources and feel free to open an issue to request additional material.
......
...@@ -235,7 +235,7 @@ There might be configuration options available for [`gitlab.yml`][yaml]. View th ...@@ -235,7 +235,7 @@ There might be configuration options available for [`gitlab.yml`][yaml]. View th
```sh ```sh
cd /home/git/gitlab cd /home/git/gitlab
git diff origin/11-1-stable:config/gitlab.yml.example origin/11-3-stable:config/gitlab.yml.example git diff origin/11-2-stable:config/gitlab.yml.example origin/11-3-stable:config/gitlab.yml.example
``` ```
#### Nginx configuration #### Nginx configuration
...@@ -246,10 +246,10 @@ Ensure you're still up-to-date with the latest NGINX configuration changes: ...@@ -246,10 +246,10 @@ Ensure you're still up-to-date with the latest NGINX configuration changes:
cd /home/git/gitlab cd /home/git/gitlab
# For HTTPS configurations # For HTTPS configurations
git diff origin/11-1-stable:lib/support/nginx/gitlab-ssl origin/11-3-stable:lib/support/nginx/gitlab-ssl git diff origin/11-2-stable:lib/support/nginx/gitlab-ssl origin/11-3-stable:lib/support/nginx/gitlab-ssl
# For HTTP configurations # For HTTP configurations
git diff origin/11-1-stable:lib/support/nginx/gitlab origin/11-3-stable:lib/support/nginx/gitlab git diff origin/11-2-stable:lib/support/nginx/gitlab origin/11-3-stable:lib/support/nginx/gitlab
``` ```
If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx
...@@ -283,7 +283,7 @@ There might be new configuration options available for [`gitlab.default.example` ...@@ -283,7 +283,7 @@ There might be new configuration options available for [`gitlab.default.example`
```sh ```sh
cd /home/git/gitlab cd /home/git/gitlab
git diff origin/11-1-stable:lib/support/init.d/gitlab.default.example origin/11-3-stable:lib/support/init.d/gitlab.default.example git diff origin/11-2-stable:lib/support/init.d/gitlab.default.example origin/11-3-stable:lib/support/init.d/gitlab.default.example
``` ```
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
......
...@@ -235,7 +235,7 @@ There might be configuration options available for [`gitlab.yml`][yaml]. View th ...@@ -235,7 +235,7 @@ There might be configuration options available for [`gitlab.yml`][yaml]. View th
```sh ```sh
cd /home/git/gitlab cd /home/git/gitlab
git diff origin/11-1-stable:config/gitlab.yml.example origin/11-4-stable:config/gitlab.yml.example git diff origin/11-3-stable:config/gitlab.yml.example origin/11-4-stable:config/gitlab.yml.example
``` ```
#### Nginx configuration #### Nginx configuration
...@@ -246,10 +246,10 @@ Ensure you're still up-to-date with the latest NGINX configuration changes: ...@@ -246,10 +246,10 @@ Ensure you're still up-to-date with the latest NGINX configuration changes:
cd /home/git/gitlab cd /home/git/gitlab
# For HTTPS configurations # For HTTPS configurations
git diff origin/11-1-stable:lib/support/nginx/gitlab-ssl origin/11-4-stable:lib/support/nginx/gitlab-ssl git diff origin/11-3-stable:lib/support/nginx/gitlab-ssl origin/11-4-stable:lib/support/nginx/gitlab-ssl
# For HTTP configurations # For HTTP configurations
git diff origin/11-1-stable:lib/support/nginx/gitlab origin/11-4-stable:lib/support/nginx/gitlab git diff origin/11-3-stable:lib/support/nginx/gitlab origin/11-4-stable:lib/support/nginx/gitlab
``` ```
If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx
...@@ -283,7 +283,7 @@ There might be new configuration options available for [`gitlab.default.example` ...@@ -283,7 +283,7 @@ There might be new configuration options available for [`gitlab.default.example`
```sh ```sh
cd /home/git/gitlab cd /home/git/gitlab
git diff origin/11-1-stable:lib/support/init.d/gitlab.default.example origin/11-4-stable:lib/support/init.d/gitlab.default.example git diff origin/11-3-stable:lib/support/init.d/gitlab.default.example origin/11-4-stable:lib/support/init.d/gitlab.default.example
``` ```
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
......
...@@ -28,7 +28,7 @@ module Gitlab ...@@ -28,7 +28,7 @@ module Gitlab
end end
def extract_authn_context(document) def extract_authn_context(document)
REXML::XPath.first(document, "//saml:AuthnStatement/saml:AuthnContext/saml:AuthnContextClassRef/text()").to_s REXML::XPath.first(document, "//*[name()='saml:AuthnStatement' or name()='saml2:AuthnStatement']/*[name()='saml:AuthnContext' or name()='saml2:AuthnContext']/*[name()='saml:AuthnContextClassRef' or name()='saml2:AuthnContextClassRef']/text()").to_s
end end
end end
end end
......
...@@ -42,7 +42,7 @@ module Gitlab ...@@ -42,7 +42,7 @@ module Gitlab
end end
def self.cache_key_for_project(project) def self.cache_key_for_project(project)
"#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:projects/#{project.id}/pipeline_status/#{project.commit&.sha}" "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:project:#{project.id}:pipeline_status:#{project.commit&.sha}"
end end
def self.update_for_pipeline(pipeline) def self.update_for_pipeline(pipeline)
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Ci module Ci
class Config class Config
......
...@@ -165,6 +165,8 @@ excluded_attributes: ...@@ -165,6 +165,8 @@ excluded_attributes:
- :encrypted_token_iv - :encrypted_token_iv
- :encrypted_url - :encrypted_url
- :encrypted_url_iv - :encrypted_url_iv
services:
- :template
methods: methods:
labels: labels:
......
# frozen_string_literal: true
# Inspired by https://github.com/peek/peek-pg/blob/master/lib/peek/views/pg.rb # Inspired by https://github.com/peek/peek-pg/blob/master/lib/peek/views/pg.rb
# PEEK_DB_CLIENT is a constant set in config/initializers/peek.rb # PEEK_DB_CLIENT is a constant set in config/initializers/peek.rb
module Gitlab module Gitlab
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Popen module Popen
class Runner class Runner
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Profiler module Profiler
class TotalTimeFlatPrinter < RubyProf::FlatPrinter class TotalTimeFlatPrinter < RubyProf::FlatPrinter
......
# frozen_string_literal: true
module Gitlab module Gitlab
module ProjectAuthorizations module ProjectAuthorizations
# Calculating new project authorizations when supporting nested groups. # Calculating new project authorizations when supporting nested groups.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module ProjectAuthorizations module ProjectAuthorizations
# Calculating new project authorizations when not supporting nested groups. # Calculating new project authorizations when not supporting nested groups.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module AdditionalMetricsParser module AdditionalMetricsParser
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
class Metric class Metric
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
class MetricGroup class MetricGroup
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
ParsingError = Class.new(StandardError) ParsingError = Class.new(StandardError)
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Prometheus module Prometheus
module Queries module Queries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QueryLimiting module QueryLimiting
class ActiveSupportSubscriber < ActiveSupport::Subscriber class ActiveSupportSubscriber < ActiveSupport::Subscriber
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QueryLimiting module QueryLimiting
class Transaction class Transaction
...@@ -68,7 +70,7 @@ module Gitlab ...@@ -68,7 +70,7 @@ module Gitlab
def error_message def error_message
header = 'Too many SQL queries were executed' header = 'Too many SQL queries were executed'
header += " in #{action}" if action header = "#{header} in #{action}" if action
"#{header}: a maximum of #{THRESHOLD} is allowed but #{count} SQL queries were executed" "#{header}: a maximum of #{THRESHOLD} is allowed but #{count} SQL queries were executed"
end end
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QuickActions module QuickActions
class CommandDefinition class CommandDefinition
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QuickActions module QuickActions
module Dsl module Dsl
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QuickActions module QuickActions
# This class takes an array of commands that should be extracted from a # This class takes an array of commands that should be extracted from a
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QuickActions module QuickActions
# This class takes spend command argument # This class takes spend command argument
......
# frozen_string_literal: true
module Gitlab module Gitlab
module QuickActions module QuickActions
class SubstitutionDefinition < CommandDefinition class SubstitutionDefinition < CommandDefinition
......
# frozen_string_literal: true
# please require all dependencies below: # please require all dependencies below:
require_relative 'wrapper' unless defined?(::Rails) && ::Rails.root.present? require_relative 'wrapper' unless defined?(::Rails) && ::Rails.root.present?
......
# frozen_string_literal: true
# please require all dependencies below: # please require all dependencies below:
require_relative 'wrapper' unless defined?(::Gitlab::Redis::Wrapper) require_relative 'wrapper' unless defined?(::Gitlab::Redis::Wrapper)
......
# frozen_string_literal: true
# please require all dependencies below: # please require all dependencies below:
require_relative 'wrapper' unless defined?(::Gitlab::Redis::Wrapper) require_relative 'wrapper' unless defined?(::Gitlab::Redis::Wrapper)
......
# frozen_string_literal: true
# This file should only be used by sub-classes, not directly by any clients of the sub-classes # This file should only be used by sub-classes, not directly by any clients of the sub-classes
# please require all dependencies below: # please require all dependencies below:
require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/hash/keys'
......
...@@ -7,13 +7,13 @@ module Gitlab ...@@ -7,13 +7,13 @@ module Gitlab
def initialize(repository, extra_namespace: nil, backend: Rails.cache) def initialize(repository, extra_namespace: nil, backend: Rails.cache)
@repository = repository @repository = repository
@namespace = "#{repository.full_path}:#{repository.project.id}" @namespace = "project:#{repository.project.id}"
@namespace = "#{@namespace}:#{extra_namespace}" if extra_namespace @namespace = "#{@namespace}:#{extra_namespace}" if extra_namespace
@backend = backend @backend = backend
end end
def cache_key(type) def cache_key(type)
"#{type}:#{namespace}" "#{namespace}:#{type}"
end end
def expire(key) def expire(key)
......
# frozen_string_literal: true
require 'ruby-prof' require 'ruby-prof'
module Gitlab module Gitlab
......
# frozen_string_literal: true
module Gitlab module Gitlab
module RequestProfiler module RequestProfiler
class Profile class Profile
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sanitizers module Sanitizers
module SVG module SVG
......
# frozen_string_literal: true
# Generated from: # Generated from:
# SVG element list: https://www.w3.org/TR/SVG/eltindex.html # SVG element list: https://www.w3.org/TR/SVG/eltindex.html
# SVG Attribute list: https://www.w3.org/TR/SVG/attindex.html # SVG Attribute list: https://www.w3.org/TR/SVG/attindex.html
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Search module Search
class ParsedQuery class ParsedQuery
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Search module Search
class Query < SimpleDelegator class Query < SimpleDelegator
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Serializer module Serializer
module Ci module Ci
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Serializer module Serializer
class Pagination class Pagination
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
# A collection of transactions recorded by Sherlock. # A collection of transactions recorded by Sherlock.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
class FileSample class FileSample
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
# Class for profiling code on a per line basis. # Class for profiling code on a per line basis.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
class LineSample class LineSample
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
class Location class Location
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
# Rack middleware used for tracking request metrics. # Rack middleware used for tracking request metrics.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
class Query class Query
...@@ -48,7 +50,7 @@ module Gitlab ...@@ -48,7 +50,7 @@ module Gitlab
end end
unless @query.end_with?(';') unless @query.end_with?(';')
@query += ';' @query = "#{@query};"
end end
end end
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Sherlock module Sherlock
class Transaction class Transaction
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqLogging module SidekiqLogging
class JSONFormatter class JSONFormatter
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqLogging module SidekiqLogging
class StructuredLogger class StructuredLogger
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqMiddleware module SidekiqMiddleware
class ArgumentsLogger class ArgumentsLogger
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqMiddleware module SidekiqMiddleware
class RequestStoreMiddleware class RequestStoreMiddleware
......
# frozen_string_literal: true
require 'mutex_m' require 'mutex_m'
module Gitlab module Gitlab
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqStatus module SidekiqStatus
class ClientMiddleware class ClientMiddleware
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqStatus module SidekiqStatus
class ServerMiddleware class ServerMiddleware
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SidekiqVersioning module SidekiqVersioning
module Manager module Manager
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class BaseCommand class BaseCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class Command < BaseCommand class Command < BaseCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class Deploy < BaseCommand class Deploy < BaseCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class Help < BaseCommand class Help < BaseCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class IssueCommand < BaseCommand class IssueCommand < BaseCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class IssueMove < IssueCommand class IssueMove < IssueCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class IssueNew < IssueCommand class IssueNew < IssueCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class IssueSearch < IssueCommand class IssueSearch < IssueCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
class IssueShow < IssueCommand class IssueShow < IssueCommand
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# coding: utf-8 # coding: utf-8
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SlashCommands module SlashCommands
module Presenters module Presenters
...@@ -38,10 +40,10 @@ module Gitlab ...@@ -38,10 +40,10 @@ module Gitlab
end end
def text def text
message = "**#{status_text(@resource)}**" message = ["**#{status_text(@resource)}**"]
if @resource.upvotes.zero? && @resource.downvotes.zero? && @resource.user_notes_count.zero? if @resource.upvotes.zero? && @resource.downvotes.zero? && @resource.user_notes_count.zero?
return message return message.join
end end
message << " · " message << " · "
...@@ -49,7 +51,7 @@ module Gitlab ...@@ -49,7 +51,7 @@ module Gitlab
message << ":-1: #{@resource.downvotes} " unless @resource.downvotes.zero? message << ":-1: #{@resource.downvotes} " unless @resource.downvotes.zero?
message << ":speech_balloon: #{@resource.user_notes_count}" unless @resource.user_notes_count.zero? message << ":speech_balloon: #{@resource.user_notes_count}" unless @resource.user_notes_count.zero?
message message.join
end end
def pretext def pretext
......
module Gitlab # rubocop:disable Naming/FileName # rubocop:disable Naming/FileName
# frozen_string_literal: true
module Gitlab
module SlashCommands module SlashCommands
Result = Struct.new(:type, :message) Result = Struct.new(:type, :message)
end end
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SQL module SQL
# Class for easily building CTE statements. # Class for easily building CTE statements.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SQL module SQL
module Glob module Glob
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SQL module SQL
module Pattern module Pattern
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SQL module SQL
# Class for easily building recursive CTE statements. # Class for easily building recursive CTE statements.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module SQL module SQL
# Class for building SQL UNION statements. # Class for building SQL UNION statements.
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
class BaseTemplate class BaseTemplate
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
class DockerfileTemplate < BaseTemplate class DockerfileTemplate < BaseTemplate
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
module Finders module Finders
......
# frozen_string_literal: true
# Searches and reads file present on GitLab installation directory # Searches and reads file present on GitLab installation directory
module Gitlab module Gitlab
module Template module Template
...@@ -21,7 +23,7 @@ module Gitlab ...@@ -21,7 +23,7 @@ module Gitlab
end end
def list_files_for(dir) def list_files_for(dir)
dir << '/' unless dir.end_with?('/') dir = "#{dir}/" unless dir.end_with?('/')
Dir.glob(File.join(dir, "*#{@extension}")).select { |f| f =~ self.class.filter_regex(@extension) } Dir.glob(File.join(dir, "*#{@extension}")).select { |f| f =~ self.class.filter_regex(@extension) }
end end
......
# frozen_string_literal: true
# Searches and reads files present on each GitLab project repository # Searches and reads files present on each GitLab project repository
module Gitlab module Gitlab
module Template module Template
...@@ -33,7 +35,7 @@ module Gitlab ...@@ -33,7 +35,7 @@ module Gitlab
def list_files_for(dir) def list_files_for(dir)
return [] unless @commit return [] unless @commit
dir << '/' unless dir.end_with?('/') dir = "#{dir}/" unless dir.end_with?('/')
entries = @repository.tree(:head, dir).entries entries = @repository.tree(:head, dir).entries
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
class GitignoreTemplate < BaseTemplate class GitignoreTemplate < BaseTemplate
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
class GitlabCiYmlTemplate < BaseTemplate class GitlabCiYmlTemplate < BaseTemplate
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
class IssueTemplate < BaseTemplate class IssueTemplate < BaseTemplate
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Template module Template
class MergeRequestTemplate < BaseTemplate class MergeRequestTemplate < BaseTemplate
......
# frozen_string_literal: true
# rubocop:disable Style/ClassVars # rubocop:disable Style/ClassVars
# This is inspired by http://www.salsify.com/blog/engineering/tearing-capybara-ajax-tests # This is inspired by http://www.salsify.com/blog/engineering/tearing-capybara-ajax-tests
......
# frozen_string_literal: true
# rubocop:disable Style/ClassVars # rubocop:disable Style/ClassVars
module Gitlab module Gitlab
...@@ -35,7 +37,7 @@ module Gitlab ...@@ -35,7 +37,7 @@ module Gitlab
request_headers = env_http_headers(env) request_headers = env_http_headers(env)
status, headers, body = @app.call(env) status, headers, body = @app.call(env)
full_body = '' full_body = +''
body.each { |b| full_body << b } body.each { |b| full_body << b }
request = OpenStruct.new( request = OpenStruct.new(
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Utils module Utils
module MergeHash module MergeHash
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Utils module Utils
module Override module Override
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Utils module Utils
module StrongMemoize module StrongMemoize
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Verify module Verify
class BatchVerifier class BatchVerifier
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Verify module Verify
class JobArtifacts < BatchVerifier class JobArtifacts < BatchVerifier
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Verify module Verify
class LfsObjects < BatchVerifier class LfsObjects < BatchVerifier
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Verify module Verify
class RakeTask class RakeTask
......
# frozen_string_literal: true
module Gitlab module Gitlab
module Verify module Verify
class Uploads < BatchVerifier class Uploads < BatchVerifier
......
# frozen_string_literal: true
module Gitlab module Gitlab
module View module View
module Presenter module Presenter
......
# frozen_string_literal: true
module Gitlab module Gitlab
module View module View
module Presenter module Presenter
......
# frozen_string_literal: true
module Gitlab module Gitlab
module View module View
module Presenter module Presenter
......
# frozen_string_literal: true
module Gitlab module Gitlab
module View module View
module Presenter module Presenter
......
# frozen_string_literal: true
# This Rack middleware is intended to proxy the webpack assets directory to the # This Rack middleware is intended to proxy the webpack assets directory to the
# webpack-dev-server. It is only intended for use in development. # webpack-dev-server. It is only intended for use in development.
......
# frozen_string_literal: true
require 'webpack/rails/manifest' require 'webpack/rails/manifest'
module Gitlab module Gitlab
......
...@@ -1339,6 +1339,9 @@ msgstr "" ...@@ -1339,6 +1339,9 @@ msgstr ""
msgid "CI / CD" msgid "CI / CD"
msgstr "" msgstr ""
msgid "CI / CD Charts"
msgstr ""
msgid "CI / CD Settings" msgid "CI / CD Settings"
msgstr "" msgstr ""
...@@ -1450,6 +1453,9 @@ msgstr "" ...@@ -1450,6 +1453,9 @@ msgstr ""
msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision." msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
msgstr "" msgstr ""
msgid "Changes suppressed. Click to show."
msgstr ""
msgid "Charts" msgid "Charts"
msgstr "" msgstr ""
...@@ -2303,6 +2309,9 @@ msgstr "" ...@@ -2303,6 +2309,9 @@ msgstr ""
msgid "Contribution" msgid "Contribution"
msgstr "" msgstr ""
msgid "Contribution Charts"
msgstr ""
msgid "Contribution guide" msgid "Contribution guide"
msgstr "" msgstr ""
...@@ -2615,6 +2624,9 @@ msgstr "" ...@@ -2615,6 +2624,9 @@ msgstr ""
msgid "Define a custom pattern with cron syntax" msgid "Define a custom pattern with cron syntax"
msgstr "" msgstr ""
msgid "Define environments in the deploy stage(s) in <code>.gitlab-ci.yml</code> to track deployments here."
msgstr ""
msgid "DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after it's timer finishes." msgid "DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after it's timer finishes."
msgstr "" msgstr ""
...@@ -2944,6 +2956,9 @@ msgstr "" ...@@ -2944,6 +2956,9 @@ msgstr ""
msgid "Edit application" msgid "Edit application"
msgstr "" msgstr ""
msgid "Edit environment"
msgstr ""
msgid "Edit files in the editor and commit changes here" msgid "Edit files in the editor and commit changes here"
msgstr "" msgstr ""
...@@ -3043,6 +3058,9 @@ msgstr "" ...@@ -3043,6 +3058,9 @@ msgstr ""
msgid "Environments" msgid "Environments"
msgstr "" msgstr ""
msgid "Environments allow you to track deployments of your application %{link_to_read_more}."
msgstr ""
msgid "Environments|An error occurred while fetching the environments." msgid "Environments|An error occurred while fetching the environments."
msgstr "" msgstr ""
...@@ -3118,6 +3136,9 @@ msgstr "" ...@@ -3118,6 +3136,9 @@ msgstr ""
msgid "Environments|Stop environment" msgid "Environments|Stop environment"
msgstr "" msgstr ""
msgid "Environments|Stopping"
msgstr ""
msgid "Environments|Updated" msgid "Environments|Updated"
msgstr "" msgstr ""
...@@ -3295,6 +3316,9 @@ msgstr "" ...@@ -3295,6 +3316,9 @@ msgstr ""
msgid "External Classification Policy Authorization" msgid "External Classification Policy Authorization"
msgstr "" msgstr ""
msgid "External URL"
msgstr ""
msgid "External authentication" msgid "External authentication"
msgstr "" msgstr ""
...@@ -3439,6 +3463,18 @@ msgstr "" ...@@ -3439,6 +3463,18 @@ msgstr ""
msgid "Fields on this page are now uneditable, you can configure" msgid "Fields on this page are now uneditable, you can configure"
msgstr "" msgstr ""
msgid "File added"
msgstr ""
msgid "File deleted"
msgstr ""
msgid "File mode changed from %{a_mode} to %{b_mode}"
msgstr ""
msgid "File moved"
msgstr ""
msgid "File templates" msgid "File templates"
msgstr "" msgstr ""
...@@ -5109,6 +5145,9 @@ msgstr "" ...@@ -5109,6 +5145,9 @@ msgstr ""
msgid "Metrics and profiling" msgid "Metrics and profiling"
msgstr "" msgstr ""
msgid "Metrics for environment"
msgstr ""
msgid "Metrics|Business" msgid "Metrics|Business"
msgstr "" msgstr ""
...@@ -5352,6 +5391,9 @@ msgstr "" ...@@ -5352,6 +5391,9 @@ msgstr ""
msgid "New Application" msgid "New Application"
msgstr "" msgstr ""
msgid "New Environment"
msgstr ""
msgid "New Group" msgid "New Group"
msgstr "" msgstr ""
...@@ -5384,6 +5426,9 @@ msgstr "" ...@@ -5384,6 +5426,9 @@ msgstr ""
msgid "New directory" msgid "New directory"
msgstr "" msgstr ""
msgid "New environment"
msgstr ""
msgid "New epic" msgid "New epic"
msgstr "" msgstr ""
...@@ -5489,6 +5534,9 @@ msgstr "" ...@@ -5489,6 +5534,9 @@ msgstr ""
msgid "No packages stored for this project." msgid "No packages stored for this project."
msgstr "" msgstr ""
msgid "No preview for this file type"
msgstr ""
msgid "No prioritised labels with such name or description" msgid "No prioritised labels with such name or description"
msgstr "" msgstr ""
...@@ -5836,6 +5884,9 @@ msgstr "" ...@@ -5836,6 +5884,9 @@ msgstr ""
msgid "Personal Access Token" msgid "Personal Access Token"
msgstr "" msgstr ""
msgid "Pick a name"
msgstr ""
msgid "Pipeline" msgid "Pipeline"
msgstr "" msgstr ""
...@@ -6703,6 +6754,9 @@ msgstr "" ...@@ -6703,6 +6754,9 @@ msgstr ""
msgid "Read more" msgid "Read more"
msgstr "" msgstr ""
msgid "Read more about environments"
msgstr ""
msgid "Read more about project permissions <strong>%{link_to_help}</strong>" msgid "Read more about project permissions <strong>%{link_to_help}</strong>"
msgstr "" msgstr ""
...@@ -6738,6 +6792,9 @@ msgstr "" ...@@ -6738,6 +6792,9 @@ msgstr ""
msgid "Register / Sign In" msgid "Register / Sign In"
msgstr "" msgstr ""
msgid "Register U2F device"
msgstr ""
msgid "Register and see your runners for this group." msgid "Register and see your runners for this group."
msgstr "" msgstr ""
...@@ -7220,6 +7277,9 @@ msgstr "" ...@@ -7220,6 +7277,9 @@ msgstr ""
msgid "SecurityDashboard|Pipeline %{pipelineLink} triggered" msgid "SecurityDashboard|Pipeline %{pipelineLink} triggered"
msgstr "" msgstr ""
msgid "See metrics"
msgstr ""
msgid "Select" msgid "Select"
msgstr "" msgstr ""
...@@ -7337,6 +7397,9 @@ msgstr "" ...@@ -7337,6 +7397,9 @@ msgstr ""
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}" msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "" msgstr ""
msgid "Set up new U2F device"
msgstr ""
msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically." msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
msgstr "" msgstr ""
...@@ -7444,6 +7507,9 @@ msgstr "" ...@@ -7444,6 +7507,9 @@ msgstr ""
msgid "Sign in to %{group_name}" msgid "Sign in to %{group_name}"
msgstr "" msgstr ""
msgid "Sign in via 2FA code"
msgstr ""
msgid "Sign in with Single Sign-On" msgid "Sign in with Single Sign-On"
msgstr "" msgstr ""
...@@ -7792,9 +7858,6 @@ msgstr "" ...@@ -7792,9 +7858,6 @@ msgstr ""
msgid "Subscribed" msgid "Subscribed"
msgstr "" msgstr ""
msgid "Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})"
msgstr ""
msgid "Switch branch/tag" msgid "Switch branch/tag"
msgstr "" msgstr ""
...@@ -7914,6 +7977,9 @@ msgstr "" ...@@ -7914,6 +7977,9 @@ msgstr ""
msgid "Templates" msgid "Templates"
msgstr "" msgstr ""
msgid "Terminal for environment"
msgstr ""
msgid "Terms of Service Agreement and Privacy Policy" msgid "Terms of Service Agreement and Privacy Policy"
msgstr "" msgstr ""
...@@ -8097,6 +8163,9 @@ msgstr "" ...@@ -8097,6 +8163,9 @@ msgstr ""
msgid "Third party offers" msgid "Third party offers"
msgstr "" msgstr ""
msgid "This %{viewer} could not be displayed because %{reason}."
msgstr ""
msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area." msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area."
msgstr "" msgstr ""
...@@ -8124,6 +8193,9 @@ msgstr "" ...@@ -8124,6 +8193,9 @@ msgstr ""
msgid "This diff is collapsed." msgid "This diff is collapsed."
msgstr "" msgstr ""
msgid "This diff was suppressed by a .gitattributes entry."
msgstr ""
msgid "This directory" msgid "This directory"
msgstr "" msgstr ""
...@@ -8512,6 +8584,9 @@ msgstr "" ...@@ -8512,6 +8584,9 @@ msgstr ""
msgid "To open Jaeger and easily view tracing from GitLab, link the %{start_tag}Tracing%{end_tag} page to your server" msgid "To open Jaeger and easily view tracing from GitLab, link the %{start_tag}Tracing%{end_tag} page to your server"
msgstr "" msgstr ""
msgid "To preserve performance only <strong>%{display_size} of ${real_size}</strong> files are displayed."
msgstr ""
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:" msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr "" msgstr ""
...@@ -8542,6 +8617,9 @@ msgstr "" ...@@ -8542,6 +8617,9 @@ msgstr ""
msgid "Toggle Sidebar" msgid "Toggle Sidebar"
msgstr "" msgstr ""
msgid "Toggle comments for this file"
msgstr ""
msgid "Toggle commit description" msgid "Toggle commit description"
msgstr "" msgstr ""
...@@ -8623,9 +8701,15 @@ msgstr "" ...@@ -8623,9 +8701,15 @@ msgstr ""
msgid "Try again" msgid "Try again"
msgstr "" msgstr ""
msgid "Try again?"
msgstr ""
msgid "Try all GitLab has to offer for 30 days." msgid "Try all GitLab has to offer for 30 days."
msgstr "" msgstr ""
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
msgid "Turn on Service Desk" msgid "Turn on Service Desk"
msgstr "" msgstr ""
...@@ -8818,9 +8902,6 @@ msgstr "" ...@@ -8818,9 +8902,6 @@ msgstr ""
msgid "UserProfile|Personal projects" msgid "UserProfile|Personal projects"
msgstr "" msgstr ""
msgid "UserProfile|Recent contributions"
msgstr ""
msgid "UserProfile|Report abuse" msgid "UserProfile|Report abuse"
msgstr "" msgstr ""
...@@ -8872,6 +8953,9 @@ msgstr "" ...@@ -8872,6 +8953,9 @@ msgstr ""
msgid "View app" msgid "View app"
msgstr "" msgstr ""
msgid "View deployment"
msgstr ""
msgid "View documentation" msgid "View documentation"
msgstr "" msgstr ""
...@@ -8974,6 +9058,9 @@ msgstr "" ...@@ -8974,6 +9058,9 @@ msgstr ""
msgid "We don't have enough data to show this stage." msgid "We don't have enough data to show this stage."
msgstr "" msgstr ""
msgid "We heard back from your U2F device. You have been authenticated."
msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot." msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "" msgstr ""
...@@ -9232,6 +9319,9 @@ msgstr "" ...@@ -9232,6 +9319,9 @@ msgstr ""
msgid "You don't have any authorized applications" msgid "You don't have any authorized applications"
msgstr "" msgstr ""
msgid "You don't have any deployments right now."
msgstr ""
msgid "You have no permissions" msgid "You have no permissions"
msgstr "" msgstr ""
...@@ -9253,6 +9343,9 @@ msgstr "" ...@@ -9253,6 +9343,9 @@ msgstr ""
msgid "You need permission." msgid "You need permission."
msgstr "" msgstr ""
msgid "You need to register a two-factor authentication app before you can set up a U2F device."
msgstr ""
msgid "You will loose all changes you've made to this file. This action cannot be undone." msgid "You will loose all changes you've made to this file. This action cannot be undone."
msgstr "" msgstr ""
...@@ -9313,12 +9406,18 @@ msgstr "" ...@@ -9313,12 +9406,18 @@ msgstr ""
msgid "Your Todos" msgid "Your Todos"
msgstr "" msgstr ""
msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
msgstr ""
msgid "Your applications (%{size})" msgid "Your applications (%{size})"
msgstr "" msgstr ""
msgid "Your authorized applications" msgid "Your authorized applications"
msgstr "" msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
msgid "Your changes can be committed to %{branch_name} because a merge request is open." msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "" msgstr ""
...@@ -9331,6 +9430,9 @@ msgstr "" ...@@ -9331,6 +9430,9 @@ msgstr ""
msgid "Your comment will not be visible to the public." msgid "Your comment will not be visible to the public."
msgstr "" msgstr ""
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
msgid "Your groups" msgid "Your groups"
msgstr "" msgstr ""
...@@ -9599,6 +9701,9 @@ msgid_plural "days" ...@@ -9599,6 +9701,9 @@ msgid_plural "days"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "deleted"
msgstr ""
msgid "deploy token" msgid "deploy token"
msgstr "" msgstr ""
...@@ -9616,6 +9721,9 @@ msgstr[1] "" ...@@ -9616,6 +9721,9 @@ msgstr[1] ""
msgid "enabled" msgid "enabled"
msgstr "" msgstr ""
msgid "error code:"
msgstr ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command." msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "" msgstr ""
......
...@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do ...@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do
end end
def selected_day_activities(visible: true) def selected_day_activities(visible: true)
find('.tab-pane#activity .user-calendar-activities', visible: visible).text find('#js-overview .user-calendar-activities', visible: visible).text
end end
before do before do
...@@ -74,16 +74,16 @@ describe 'Contributions Calendar', :js do ...@@ -74,16 +74,16 @@ describe 'Contributions Calendar', :js do
describe 'calendar day selection' do describe 'calendar day selection' do
before do before do
visit user.username visit user.username
page.find('.js-activity-tab a').click page.find('.js-overview-tab a').click
wait_for_requests wait_for_requests
end end
it 'displays calendar' do it 'displays calendar' do
expect(find('.tab-pane#activity')).to have_css('.js-contrib-calendar') expect(find('#js-overview')).to have_css('.js-contrib-calendar')
end end
describe 'select calendar day' do describe 'select calendar day' do
let(:cells) { page.all('.tab-pane#activity .user-contrib-cell') } let(:cells) { page.all('#js-overview .user-contrib-cell') }
before do before do
cells[0].click cells[0].click
...@@ -109,7 +109,7 @@ describe 'Contributions Calendar', :js do ...@@ -109,7 +109,7 @@ describe 'Contributions Calendar', :js do
describe 'deselect calendar day' do describe 'deselect calendar day' do
before do before do
cells[0].click cells[0].click
page.find('.js-activity-tab a').click page.find('.js-overview-tab a').click
wait_for_requests wait_for_requests
end end
...@@ -124,7 +124,7 @@ describe 'Contributions Calendar', :js do ...@@ -124,7 +124,7 @@ describe 'Contributions Calendar', :js do
shared_context 'visit user page' do shared_context 'visit user page' do
before do before do
visit user.username visit user.username
page.find('.js-activity-tab a').click page.find('.js-overview-tab a').click
wait_for_requests wait_for_requests
end end
end end
...@@ -133,12 +133,12 @@ describe 'Contributions Calendar', :js do ...@@ -133,12 +133,12 @@ describe 'Contributions Calendar', :js do
include_context 'visit user page' include_context 'visit user page'
it 'displays calendar activity square color for 1 contribution' do it 'displays calendar activity square color for 1 contribution' do
expect(find('.tab-pane#activity')).to have_selector(get_cell_color_selector(contribution_count), count: 1) expect(find('#js-overview')).to have_selector(get_cell_color_selector(contribution_count), count: 1)
end end
it 'displays calendar activity square on the correct date' do it 'displays calendar activity square on the correct date' do
today = Date.today.strftime(date_format) today = Date.today.strftime(date_format)
expect(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1) expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
end end
end end
...@@ -153,7 +153,7 @@ describe 'Contributions Calendar', :js do ...@@ -153,7 +153,7 @@ describe 'Contributions Calendar', :js do
include_context 'visit user page' include_context 'visit user page'
it 'displays calendar activity log' do it 'displays calendar activity log' do
expect(find('.tab-pane#activity .content_list .event-target-title')).to have_content issue_title expect(find('#js-overview .overview-content-list .event-target-title')).to have_content issue_title
end end
end end
end end
...@@ -185,17 +185,17 @@ describe 'Contributions Calendar', :js do ...@@ -185,17 +185,17 @@ describe 'Contributions Calendar', :js do
include_context 'visit user page' include_context 'visit user page'
it 'displays calendar activity squares for both days' do it 'displays calendar activity squares for both days' do
expect(find('.tab-pane#activity')).to have_selector(get_cell_color_selector(1), count: 2) expect(find('#js-overview')).to have_selector(get_cell_color_selector(1), count: 2)
end end
it 'displays calendar activity square for yesterday' do it 'displays calendar activity square for yesterday' do
yesterday = Date.yesterday.strftime(date_format) yesterday = Date.yesterday.strftime(date_format)
expect(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(1, yesterday), count: 1) expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
end end
it 'displays calendar activity square for today' do it 'displays calendar activity square for today' do
today = Date.today.strftime(date_format) today = Date.today.strftime(date_format)
expect(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(1, today), count: 1) expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
end end
end end
end end
......
require 'rails_helper' require 'rails_helper'
describe 'GFM autocomplete', :js do describe 'GFM autocomplete', :js do
let(:issue_xss_title) { 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:label) { create(:label, project: project, title: 'special+') } let(:label) { create(:label, project: project, title: 'special+') }
...@@ -9,6 +13,8 @@ describe 'GFM autocomplete', :js do ...@@ -9,6 +13,8 @@ describe 'GFM autocomplete', :js do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
project.add_maintainer(user_xss)
sign_in(user) sign_in(user)
visit project_issue_path(project, issue) visit project_issue_path(project, issue)
...@@ -35,9 +41,8 @@ describe 'GFM autocomplete', :js do ...@@ -35,9 +41,8 @@ describe 'GFM autocomplete', :js do
expect(page).to have_selector('.atwho-container') expect(page).to have_selector('.atwho-container')
end end
it 'opens autocomplete menu when field starts with text with item escaping HTML characters' do it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
alert_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' create(:issue, project: project, title: issue_xss_title)
create(:issue, project: project, title: alert_title)
page.within '.timeline-content-form' do page.within '.timeline-content-form' do
find('#note-body').native.send_keys('#') find('#note-body').native.send_keys('#')
...@@ -46,7 +51,19 @@ describe 'GFM autocomplete', :js do ...@@ -46,7 +51,19 @@ describe 'GFM autocomplete', :js do
expect(page).to have_selector('.atwho-container') expect(page).to have_selector('.atwho-container')
page.within '.atwho-container #at-view-issues' do page.within '.atwho-container #at-view-issues' do
expect(page.all('li').first.text).to include(alert_title) expect(page.all('li').first.text).to include(issue_xss_title)
end
end
it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
page.within '.timeline-content-form' do
find('#note-body').native.send_keys('@ev')
end
expect(page).to have_selector('.atwho-container')
page.within '.atwho-container #at-view-users' do
expect(find('li').text).to have_content(user_xss.username)
end end
end end
...@@ -107,7 +124,7 @@ describe 'GFM autocomplete', :js do ...@@ -107,7 +124,7 @@ describe 'GFM autocomplete', :js do
wait_for_requests wait_for_requests
expect(find('#at-view-64')).to have_selector('.cur:first-of-type') expect(find('#at-view-users')).to have_selector('.cur:first-of-type')
end end
it 'includes items for assignee dropdowns with non-ASCII characters in name' do it 'includes items for assignee dropdowns with non-ASCII characters in name' do
...@@ -120,7 +137,7 @@ describe 'GFM autocomplete', :js do ...@@ -120,7 +137,7 @@ describe 'GFM autocomplete', :js do
wait_for_requests wait_for_requests
expect(find('#at-view-64')).to have_content(user.name) expect(find('#at-view-users')).to have_content(user.name)
end end
it 'selects the first item for non-assignee dropdowns if a query is entered' do it 'selects the first item for non-assignee dropdowns if a query is entered' do
......
...@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do ...@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do
end end
end end
describe 'user has 10 activities' do describe 'user has 11 activities' do
before do before do
10.times { push_code_contribution } 11.times { push_code_contribution }
end end
include_context 'visit overview tab' include_context 'visit overview tab'
it 'displays 5 entries in the list of activities' do it 'displays 10 entries in the list of activities' do
expect(find('#js-overview')).to have_selector('.event-item', count: 5) expect(find('#js-overview')).to have_selector('.event-item', count: 10)
end end
it 'shows a link to the activity list' do it 'shows a link to the activity list' do
......
...@@ -74,6 +74,13 @@ describe GroupDescendantsFinder do ...@@ -74,6 +74,13 @@ describe GroupDescendantsFinder do
end end
end end
it 'sorts elements by latest created as default' do
project1 = create(:project, namespace: group, created_at: 1.hour.ago)
project2 = create(:project, namespace: group)
expect(subject.execute).to eq([project2, project1])
end
context 'sorting by name' do context 'sorting by name' do
let!(:project1) { create(:project, namespace: group, name: 'a', path: 'project-a') } let!(:project1) { create(:project, namespace: group, name: 'a', path: 'project-a') }
let!(:project2) { create(:project, namespace: group, name: 'z', path: 'project-z') } let!(:project2) { create(:project, namespace: group, name: 'z', path: 'project-z') }
......
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://example.hello.com/access/saml" ID="jVFQbyEpSfUwqhZtJtarIaGoshwuAQMDwLoiMhzJXsv" InResponseTo="cfeooghajnhofcmogakmlhpkohnmikicnfhdnjlc" IssueInstant="2011-06-21T13:54:38.661Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://idm.orademo.com</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#jVFQbyEpSfUwqhZtJtarIaGoshwuAQMDwLoiMhzJXsv">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>uHuSry39P16Yh7srS32xESmj4Lw=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>fdghdfggfd=</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>dfghjkl</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="emmCjammnYdAbMWDuMAJeZvQIMBayeeYqqwvQoDclKE" IssueInstant="2011-06-21T13:54:38.676Z" Version="2.0">
<saml2:Issuer>https://idm.orademo.com</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" NameQualifier="idp.example.org">someone@example.org</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="cfeooghajnhofcmogakmlhpkohnmikicnfhdnjlc" NotOnOrAfter="2011-06-21T14:09:38.676Z" Recipient="https://example.hello.com/access/saml"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2011-06-21T13:54:38.683Z" NotOnOrAfter="2011-06-21T14:09:38.683Z">
<saml2:AudienceRestriction>
<saml2:Audience>hello.com</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2011-06-21T13:54:38.685Z" SessionIndex="perdkjfskdjfksdiertusfsdfsddeurtherukjdfgkdffg">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute Name="FirstName">
<saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Someone</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="LastName">
<saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Special</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</saml2p:Response>
...@@ -82,6 +82,17 @@ describe Gitlab::Auth::Saml::AuthHash do ...@@ -82,6 +82,17 @@ describe Gitlab::Auth::Saml::AuthHash do
end end
end end
context 'with SAML 2.0 response_object' do
before do
auth_hash_data[:extra][:response_object] = { document:
saml_xml(File.read('spec/fixtures/authentication/saml2_response.xml')) }
end
it 'can extract authn_context' do
expect(saml_auth_hash.authn_context).to eq 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
end
end
context 'without response_object' do context 'without response_object' do
it 'returns an empty string' do it 'returns an empty string' do
expect(saml_auth_hash.authn_context).to be_nil expect(saml_auth_hash.authn_context).to be_nil
......
...@@ -101,6 +101,28 @@ ...@@ -101,6 +101,28 @@
] ]
} }
], ],
"services": [
{
"id": 100,
"title": "JetBrains TeamCity CI",
"project_id": 5,
"created_at": "2016-06-14T15:01:51.315Z",
"updated_at": "2016-06-14T15:01:51.315Z",
"active": false,
"properties": {},
"template": true,
"push_events": true,
"issues_events": true,
"merge_requests_events": true,
"tag_push_events": true,
"note_events": true,
"job_events": true,
"type": "TeamcityService",
"category": "ci",
"default": false,
"wiki_page_events": true
}
],
"snippets": [], "snippets": [],
"hooks": [] "hooks": []
} }
...@@ -297,7 +297,8 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do ...@@ -297,7 +297,8 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
issues: 1, issues: 1,
labels: 1, labels: 1,
milestones: 1, milestones: 1,
first_issue_labels: 1 first_issue_labels: 1,
services: 1
context 'project.json file access check' do context 'project.json file access check' do
it 'does not read a symlink' do it 'does not read a symlink' do
...@@ -382,6 +383,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do ...@@ -382,6 +383,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
project_tree_restorer.instance_variable_set(:@path, "spec/lib/gitlab/import_export/project.light.json") project_tree_restorer.instance_variable_set(:@path, "spec/lib/gitlab/import_export/project.light.json")
end end
it 'does not import any templated services' do
restored_project_json
expect(project.services.where(template: true).count).to eq(0)
end
it 'imports labels' do it 'imports labels' do
create(:group_label, name: 'Another label', group: project.group) create(:group_label, name: 'Another label', group: project.group)
......
...@@ -4,14 +4,14 @@ describe Gitlab::RepositoryCache do ...@@ -4,14 +4,14 @@ describe Gitlab::RepositoryCache do
let(:backend) { double('backend').as_null_object } let(:backend) { double('backend').as_null_object }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:repository) { project.repository } let(:repository) { project.repository }
let(:namespace) { "#{repository.full_path}:#{project.id}" } let(:namespace) { "project:#{project.id}" }
let(:cache) { described_class.new(repository, backend: backend) } let(:cache) { described_class.new(repository, backend: backend) }
describe '#cache_key' do describe '#cache_key' do
subject { cache.cache_key(:foo) } subject { cache.cache_key(:foo) }
it 'includes the namespace' do it 'includes the namespace' do
expect(subject).to eq "foo:#{namespace}" expect(subject).to eq "#{namespace}:foo"
end end
context 'with a given namespace' do context 'with a given namespace' do
...@@ -22,7 +22,7 @@ describe Gitlab::RepositoryCache do ...@@ -22,7 +22,7 @@ describe Gitlab::RepositoryCache do
end end
it 'includes the full namespace' do it 'includes the full namespace' do
expect(subject).to eq "foo:#{namespace}:#{extra_namespace}" expect(subject).to eq "#{namespace}:#{extra_namespace}:foo"
end end
end end
end end
...@@ -30,21 +30,21 @@ describe Gitlab::RepositoryCache do ...@@ -30,21 +30,21 @@ describe Gitlab::RepositoryCache do
describe '#expire' do describe '#expire' do
it 'expires the given key from the cache' do it 'expires the given key from the cache' do
cache.expire(:foo) cache.expire(:foo)
expect(backend).to have_received(:delete).with("foo:#{namespace}") expect(backend).to have_received(:delete).with("#{namespace}:foo")
end end
end end
describe '#fetch' do describe '#fetch' do
it 'fetches the given key from the cache' do it 'fetches the given key from the cache' do
cache.fetch(:bar) cache.fetch(:bar)
expect(backend).to have_received(:fetch).with("bar:#{namespace}") expect(backend).to have_received(:fetch).with("#{namespace}:bar")
end end
it 'accepts a block' do it 'accepts a block' do
p = -> {} p = -> {}
cache.fetch(:baz, &p) cache.fetch(:baz, &p)
expect(backend).to have_received(:fetch).with("baz:#{namespace}", &p) expect(backend).to have_received(:fetch).with("#{namespace}:baz", &p)
end end
end end
...@@ -67,7 +67,7 @@ describe Gitlab::RepositoryCache do ...@@ -67,7 +67,7 @@ describe Gitlab::RepositoryCache do
end end
it 'caches the value' do it 'caches the value' do
expect(backend).to receive(:write).with("#{key}:#{namespace}", true) expect(backend).to receive(:write).with("#{namespace}:#{key}", true)
cache.fetch_without_caching_false(key) { true } cache.fetch_without_caching_false(key) { true }
end end
...@@ -83,7 +83,7 @@ describe Gitlab::RepositoryCache do ...@@ -83,7 +83,7 @@ describe Gitlab::RepositoryCache do
end end
it 'does not cache the value' do it 'does not cache the value' do
expect(backend).not_to receive(:write).with("#{key}:#{namespace}", true) expect(backend).not_to receive(:write).with("#{namespace}:#{key}", true)
cache.fetch_without_caching_false(key, &p) cache.fetch_without_caching_false(key, &p)
end end
...@@ -92,7 +92,7 @@ describe Gitlab::RepositoryCache do ...@@ -92,7 +92,7 @@ describe Gitlab::RepositoryCache do
context 'when the cached value is truthy' do context 'when the cached value is truthy' do
before do before do
backend.write("#{key}:#{namespace}", true) backend.write("#{namespace}:#{key}", true)
end end
it 'returns the cached value' do it 'returns the cached value' do
...@@ -116,7 +116,7 @@ describe Gitlab::RepositoryCache do ...@@ -116,7 +116,7 @@ describe Gitlab::RepositoryCache do
context 'when the cached value is falsey' do context 'when the cached value is falsey' do
before do before do
backend.write("#{key}:#{namespace}", false) backend.write("#{namespace}:#{key}", false)
end end
it 'returns the result of the block' do it 'returns the result of the block' do
...@@ -126,7 +126,7 @@ describe Gitlab::RepositoryCache do ...@@ -126,7 +126,7 @@ describe Gitlab::RepositoryCache do
end end
it 'writes the truthy value to the cache' do it 'writes the truthy value to the cache' do
expect(backend).to receive(:write).with("#{key}:#{namespace}", 'block result') expect(backend).to receive(:write).with("#{namespace}:#{key}", 'block result')
cache.fetch_without_caching_false(key) { 'block result' } cache.fetch_without_caching_false(key) { 'block result' }
end end
......
...@@ -2403,4 +2403,22 @@ describe Repository do ...@@ -2403,4 +2403,22 @@ describe Repository do
repository.merge_base('master', 'fix') repository.merge_base('master', 'fix')
end end
end end
describe '#cache' do
subject(:cache) { repository.send(:cache) }
it 'returns a RepositoryCache' do
expect(subject).to be_kind_of Gitlab::RepositoryCache
end
it 'when is_wiki it includes wiki as part of key' do
allow(repository).to receive(:is_wiki) { true }
expect(subject.namespace).to include('wiki')
end
it 'when is_wiki is false extra_namespace is nil' do
expect(subject.namespace).not_to include('wiki')
end
end
end end
...@@ -1613,15 +1613,5 @@ describe QuickActions::InterpretService do ...@@ -1613,15 +1613,5 @@ describe QuickActions::InterpretService do
expect(explanations).to eq(['Sets weight to 4.']) expect(explanations).to eq(['Sets weight to 4.'])
end end
end end
describe 'move issue to another project command' do
let(:content) { '/move test/project' }
it 'includes the project name' do
_, explanations = service.explain(content, issue)
expect(explanations).to eq(["Moves this issue to test/project."])
end
end
end end
end end
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