提交 4e06ca9e 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 8e352328
......@@ -113,14 +113,6 @@ Lint/UriEscapeUnescape:
- 'spec/lib/google_api/auth_spec.rb'
- 'spec/requests/api/files_spec.rb'
# Offense count: 3
# Cop supports --auto-correct.
Lint/UriRegexp:
Exclude:
- 'app/models/concerns/mentionable/reference_regexes.rb'
- 'app/services/projects/download_service.rb'
- 'lib/gitlab/ci/pipeline/chain/config/content/remote.rb'
# Offense count: 65
# Cop supports --auto-correct.
Migration/DepartmentName:
......@@ -539,12 +531,6 @@ Style/AccessModifierDeclarations:
Style/BarePercentLiterals:
Enabled: false
# Offense count: 5
Style/CommentedKeyword:
Exclude:
- 'lib/tasks/gitlab/backup.rake'
- 'spec/tasks/gitlab/backup_rake_spec.rb'
# Offense count: 5
# Cop supports --auto-correct.
Style/EachWithObject:
......@@ -627,13 +613,6 @@ Style/MixinUsage:
- 'spec/factories/notes.rb'
- 'spec/lib/gitlab/import_export/version_checker_spec.rb'
# Offense count: 2
# Cop supports --auto-correct.
Style/MultilineIfModifier:
Exclude:
- 'app/services/ci/process_pipeline_service.rb'
- 'lib/api/commit_statuses.rb'
# Offense count: 29
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength.
......
12d115c50517935dc8e7e2e1248aa450bf00710e
10ef65465876db3a9539dba1aa4d789f1cf2cb3b
......@@ -26,8 +26,8 @@ gem 'marginalia', '~> 1.9.0'
# Authentication libraries
gem 'devise', '~> 4.6'
gem 'doorkeeper', '~> 5.1.1'
gem 'doorkeeper-openid_connect', '~> 1.6.3'
gem 'doorkeeper', '~> 5.3.0'
gem 'doorkeeper-openid_connect', '~> 1.7.4'
gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 2.0.0'
gem 'omniauth-azure-oauth2', '~> 0.0.9'
......
......@@ -254,11 +254,11 @@ GEM
docile (1.3.2)
domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.1.1)
doorkeeper (5.3.3)
railties (>= 5)
doorkeeper-openid_connect (1.6.3)
doorkeeper (>= 5.0, < 5.2)
json-jwt (~> 1.6)
doorkeeper-openid_connect (1.7.4)
doorkeeper (>= 5.2, < 5.5)
json-jwt (>= 1.11.0)
dry-configurable (0.11.5)
concurrent-ruby (~> 1.0)
dry-core (~> 0.4, >= 0.4.7)
......@@ -1265,8 +1265,8 @@ DEPENDENCIES
diff_match_patch (~> 0.1.0)
diffy (~> 3.3)
discordrb-webhooks-blackst0ne (~> 3.3)
doorkeeper (~> 5.1.1)
doorkeeper-openid_connect (~> 1.6.3)
doorkeeper (~> 5.3.0)
doorkeeper-openid_connect (~> 1.7.4)
ed25519 (~> 1.2)
elasticsearch-api (~> 6.8)
elasticsearch-model (~> 6.1)
......
......@@ -6,20 +6,29 @@ export function getMilestone() {
}
export function formatListIssues(listIssues) {
return listIssues.nodes.reduce((map, list) => {
const issues = {};
const listData = listIssues.nodes.reduce((map, list) => {
return {
...map,
[list.id]: list.issues.nodes.map(
i =>
new ListIssue({
...i,
id: getIdFromGraphQLId(i.id),
labels: i.labels?.nodes || [],
assignees: i.assignees?.nodes || [],
}),
),
[list.id]: list.issues.nodes.map(i => {
const id = getIdFromGraphQLId(i.id);
const listIssue = new ListIssue({
...i,
id,
labels: i.labels?.nodes || [],
assignees: i.assignees?.nodes || [],
});
issues[id] = listIssue;
return id;
}),
};
}, {});
return { listData, issues };
}
export function fullBoardId(boardId) {
......
......@@ -10,4 +10,11 @@ export default {
return state.isShowingEpicsSwimlanes;
},
getIssueById: state => id => {
return state.issues[id] || {};
},
getActiveIssue: state => {
return state.issues[state.activeId] || {};
},
};
......@@ -72,8 +72,9 @@ export default {
state.isLoadingIssues = true;
},
[mutationTypes.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS]: (state, listIssues) => {
state.issuesByListId = listIssues;
[mutationTypes.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS]: (state, { listData, issues }) => {
state.issuesByListId = listData;
state.issues = issues;
state.isLoadingIssues = false;
},
......
......@@ -10,6 +10,7 @@ export default () => ({
sidebarType: '',
boardLists: [],
issuesByListId: {},
issues: {},
isLoadingIssues: false,
filterParams: {},
error: undefined,
......
......@@ -2,20 +2,18 @@ import axios from '~/lib/utils/axios_utils';
export default class DeployKeysService {
constructor(endpoint) {
this.axios = axios.create({
baseURL: endpoint,
});
this.endpoint = endpoint;
}
getKeys() {
return this.axios.get().then(response => response.data);
return axios.get(this.endpoint).then(response => response.data);
}
enableKey(id) {
return this.axios.put(`${id}/enable`).then(response => response.data);
return axios.put(`${this.endpoint}/${id}/enable`).then(response => response.data);
}
disableKey(id) {
return this.axios.put(`${id}/disable`).then(response => response.data);
return axios.put(`${this.endpoint}/${id}/disable`).then(response => response.data);
}
}
......@@ -4,7 +4,12 @@ export const parseIssuableData = () => {
try {
const initialDataEl = document.getElementById('js-issuable-app-initial-data');
return JSON.parse(sanitize(initialDataEl.textContent).replace(/&quot;/g, '"'));
const parsedData = JSON.parse(initialDataEl.textContent.replace(/&quot;/g, '"'));
parsedData.initialTitleHtml = sanitize(parsedData.initialTitleHtml);
parsedData.initialDescriptionHtml = sanitize(parsedData.initialDescriptionHtml);
return parsedData;
} catch (e) {
console.error(e); // eslint-disable-line no-console
......
......@@ -23,7 +23,6 @@
@import 'framework/flash';
@import 'framework/forms';
@import 'framework/gfm';
@import 'framework/gitlab_theme';
@import 'framework/header';
@import 'framework/highlight';
@import 'framework/issue_box';
......
......@@ -968,85 +968,6 @@ input {
.search form::placeholder {
color: #868686;
}
body.ui-indigo .navbar-gitlab {
background-color: #292961;
}
body.ui-indigo .navbar-gitlab .navbar-collapse {
color: #d1d1f0;
}
body.ui-indigo .navbar-gitlab .container-fluid .navbar-toggler {
border-left: 1px solid #6868b9;
}
body.ui-indigo .navbar-gitlab .container-fluid .navbar-toggler svg {
fill: #d1d1f0;
}
body.ui-indigo .navbar-gitlab .navbar-sub-nav > li.active > a,
body.ui-indigo .navbar-gitlab .navbar-sub-nav > li.active > button, body.ui-indigo .navbar-gitlab .navbar-sub-nav > li.dropdown.show > a,
body.ui-indigo .navbar-gitlab .navbar-sub-nav > li.dropdown.show > button,
body.ui-indigo .navbar-gitlab .navbar-nav > li.active > a,
body.ui-indigo .navbar-gitlab .navbar-nav > li.active > button,
body.ui-indigo .navbar-gitlab .navbar-nav > li.dropdown.show > a,
body.ui-indigo .navbar-gitlab .navbar-nav > li.dropdown.show > button {
color: #292961;
background-color: #fff;
}
body.ui-indigo .navbar-gitlab .navbar-sub-nav {
color: #d1d1f0;
}
body.ui-indigo .navbar-gitlab .nav > li {
color: #d1d1f0;
}
body.ui-indigo .navbar-gitlab .nav > li > a.header-user-dropdown-toggle .header-user-avatar {
border-color: #d1d1f0;
}
body.ui-indigo .navbar-gitlab .nav > li.active > a,
body.ui-indigo .navbar-gitlab .nav > li.dropdown.show > a {
color: #292961;
background-color: #fff;
}
body.ui-indigo .search form {
background-color: rgba(209, 209, 240, 0.2);
}
body.ui-indigo .search .search-input::placeholder {
color: rgba(209, 209, 240, 0.8);
}
body.ui-indigo .search .search-input-wrap .search-icon,
body.ui-indigo .search .search-input-wrap .clear-icon {
fill: rgba(209, 209, 240, 0.8);
}
body.ui-indigo .nav-sidebar li.active {
box-shadow: inset 4px 0 0 #4b4ba3;
}
body.ui-indigo .nav-sidebar li.active > a {
color: #393982;
}
body.ui-indigo .nav-sidebar li.active .nav-icon-container svg {
fill: #393982;
}
body.ui-indigo .sidebar-top-level-items > li.active .badge.badge-pill {
color: #393982;
}
body.gl-dark .logo-text svg {
fill: #303030;
}
body.gl-dark .navbar-gitlab {
background-color: #f0f0f0;
}
body.gl-dark .navbar-gitlab .navbar-sub-nav li.active > a,
body.gl-dark .navbar-gitlab .navbar-sub-nav li.active > button,
body.gl-dark .navbar-gitlab .navbar-sub-nav li.dropdown.show > a,
body.gl-dark .navbar-gitlab .navbar-sub-nav li.dropdown.show > button,
body.gl-dark .navbar-gitlab .navbar-nav li.active > a,
body.gl-dark .navbar-gitlab .navbar-nav li.active > button,
body.gl-dark .navbar-gitlab .navbar-nav li.dropdown.show > a,
body.gl-dark .navbar-gitlab .navbar-nav li.dropdown.show > button {
color: #303030;
background-color: #bfbfbf;
}
body.gl-dark .navbar-gitlab .search form {
background-color: #dbdbdb;
box-shadow: inset 0 0 0 1px #dbdbdb;
}
.navbar-gitlab {
padding: 0 16px;
z-index: 1000;
......
@import './theme_helper';
body {
&.ui-blue {
@include gitlab-theme(
$theme-blue-200,
$theme-blue-500,
$theme-blue-700,
$theme-blue-800,
$theme-blue-900,
$white
);
}
}
@import './theme_helper';
body {
&.ui-dark {
@include gitlab-theme(
$gray-200,
$gray-300,
$gray-500,
$gray-700,
$gray-900,
$white
);
}
}
@import './theme_helper';
body {
&.ui-green {
@include gitlab-theme(
$theme-green-200,
$theme-green-500,
$theme-green-700,
$theme-green-800,
$theme-green-900,
$white
);
}
}
@import '../page_bundles/mixins_and_variables_and_functions';
/**
* Styles the GitLab application with a specific color theme
*/
@mixin gitlab-theme(
$search-and-nav-links,
$active-tab-border,
......@@ -202,230 +202,3 @@
}
}
}
body {
&.ui-indigo {
@include gitlab-theme(
$indigo-200,
$indigo-500,
$indigo-700,
$indigo-800,
$indigo-900,
$white
);
}
&.ui-light-indigo {
@include gitlab-theme(
$indigo-200,
$indigo-500,
$indigo-500,
$indigo-700,
$indigo-700,
$white
);
}
&.ui-blue {
@include gitlab-theme(
$theme-blue-200,
$theme-blue-500,
$theme-blue-700,
$theme-blue-800,
$theme-blue-900,
$white
);
}
&.ui-light-blue {
@include gitlab-theme(
$theme-light-blue-200,
$theme-light-blue-500,
$theme-light-blue-500,
$theme-light-blue-700,
$theme-light-blue-700,
$white
);
}
&.ui-green {
@include gitlab-theme(
$theme-green-200,
$theme-green-500,
$theme-green-700,
$theme-green-800,
$theme-green-900,
$white
);
}
&.ui-light-green {
@include gitlab-theme(
$theme-green-200,
$theme-green-500,
$theme-green-500,
$theme-light-green-700,
$theme-light-green-700,
$white
);
}
&.ui-red {
@include gitlab-theme(
$theme-red-200,
$theme-red-500,
$theme-red-700,
$theme-red-800,
$theme-red-900,
$white
);
}
&.ui-light-red {
@include gitlab-theme(
$theme-light-red-200,
$theme-light-red-500,
$theme-light-red-500,
$theme-light-red-700,
$theme-light-red-700,
$white
);
}
&.ui-dark {
@include gitlab-theme(
$gray-200,
$gray-300,
$gray-500,
$gray-700,
$gray-900,
$white
);
}
&.ui-light {
@include gitlab-theme(
$gray-500,
$gray-700,
$gray-500,
$gray-500,
$gray-50,
$gray-500
);
.navbar-gitlab {
background-color: $gray-50;
box-shadow: 0 1px 0 0 $border-color;
.logo-text svg {
fill: $gray-900;
}
.navbar-sub-nav,
.navbar-nav {
> li {
> a:hover,
> a:focus,
> button:hover {
color: $gray-900;
}
&.active > a,
&.active > a:hover,
&.active > button {
color: $white;
}
}
}
.container-fluid {
.navbar-toggler,
.navbar-toggler:hover {
color: $gray-500;
border-left: 1px solid $gray-100;
}
}
}
.search {
form {
background-color: $white;
box-shadow: inset 0 0 0 1px $border-color;
&:hover {
background-color: $white;
box-shadow: inset 0 0 0 1px $blue-200;
}
}
.search-input-wrap {
.search-icon {
fill: $gray-100;
}
.search-input {
color: $gl-text-color;
}
}
}
.nav-sidebar li.active {
> a {
color: $gray-900;
}
svg {
fill: $gray-900;
}
}
.sidebar-top-level-items > li.active .badge.badge-pill {
color: $gray-900;
}
}
&.gl-dark {
.logo-text svg {
fill: $gl-text-color;
}
.navbar-gitlab {
background-color: $gray-50;
.navbar-sub-nav,
.navbar-nav {
li {
> a:hover,
> a:focus,
> button:hover,
> button:focus {
color: $gl-text-color;
background-color: $gray-200;
}
}
li.active,
li.dropdown.show {
> a,
> button {
color: $gl-text-color;
background-color: $gray-200;
}
}
}
.search {
form {
background-color: $gray-100;
box-shadow: inset 0 0 0 1px $border-color;
&:active,
&:hover {
background-color: $gray-100;
box-shadow: inset 0 0 0 1px $blue-200;
}
}
}
}
}
}
@import './theme_helper';
body {
&.ui-indigo {
@include gitlab-theme(
$indigo-200,
$indigo-500,
$indigo-700,
$indigo-800,
$indigo-900,
$white
);
}
}
@import './theme_helper';
body {
&.ui-light {
@include gitlab-theme(
$gray-500,
$gray-700,
$gray-500,
$gray-500,
$gray-50,
$gray-500
);
.navbar-gitlab {
background-color: $gray-50;
box-shadow: 0 1px 0 0 $border-color;
.logo-text svg {
fill: $gray-900;
}
.navbar-sub-nav,
.navbar-nav {
> li {
> a:hover,
> a:focus,
> button:hover {
color: $gray-900;
}
&.active > a,
&.active > a:hover,
&.active > button {
color: $white;
}
}
}
.container-fluid {
.navbar-toggler,
.navbar-toggler:hover {
color: $gray-500;
border-left: 1px solid $gray-100;
}
}
}
.search {
form {
background-color: $white;
box-shadow: inset 0 0 0 1px $border-color;
&:hover {
background-color: $white;
box-shadow: inset 0 0 0 1px $blue-200;
}
}
.search-input-wrap {
.search-icon {
fill: $gray-100;
}
.search-input {
color: $gl-text-color;
}
}
}
.nav-sidebar li.active {
> a {
color: $gray-900;
}
svg {
fill: $gray-900;
}
}
.sidebar-top-level-items > li.active .badge.badge-pill {
color: $gray-900;
}
}
&.gl-dark {
.logo-text svg {
fill: $gl-text-color;
}
.navbar-gitlab {
background-color: $gray-50;
.navbar-sub-nav,
.navbar-nav {
li {
> a:hover,
> a:focus,
> button:hover,
> button:focus {
color: $gl-text-color;
background-color: $gray-200;
}
}
li.active,
li.dropdown.show {
> a,
> button {
color: $gl-text-color;
background-color: $gray-200;
}
}
}
.search {
form {
background-color: $gray-100;
box-shadow: inset 0 0 0 1px $border-color;
&:active,
&:hover {
background-color: $gray-100;
box-shadow: inset 0 0 0 1px $blue-200;
}
}
}
}
}
}
@import './theme_helper';
body {
&.ui-light-blue {
@include gitlab-theme(
$theme-light-blue-200,
$theme-light-blue-500,
$theme-light-blue-500,
$theme-light-blue-700,
$theme-light-blue-700,
$white
);
}
}
@import './theme_helper';
body {
&.ui-light-green {
@include gitlab-theme(
$theme-green-200,
$theme-green-500,
$theme-green-500,
$theme-light-green-700,
$theme-light-green-700,
$white
);
}
}
@import './theme_helper';
body {
&.ui-light-indigo {
@include gitlab-theme(
$indigo-200,
$indigo-500,
$indigo-500,
$indigo-700,
$indigo-700,
$white
);
}
}
@import './theme_helper';
body {
&.ui-light-red {
@include gitlab-theme(
$theme-light-red-200,
$theme-light-red-500,
$theme-light-red-500,
$theme-light-red-700,
$theme-light-red-700,
$white
);
}
}
@import './theme_helper';
body {
&.ui-red {
@include gitlab-theme(
$theme-red-200,
$theme-red-500,
$theme-red-700,
$theme-red-800,
$theme-red-900,
$white
);
}
}
......@@ -14,6 +14,7 @@ class Oauth::Jira::AuthorizationsController < ApplicationController
redirect_to oauth_authorization_path(client_id: params['client_id'],
response_type: 'code',
scope: params['scope'],
redirect_uri: oauth_jira_callback_url)
end
......
......@@ -61,6 +61,10 @@ module PreferencesHelper
@user_application_theme ||= Gitlab::Themes.for_user(current_user).css_class
end
def user_application_theme_name
@user_application_theme_name ||= Gitlab::Themes.for_user(current_user).name.downcase.tr(' ', '_')
end
def user_color_scheme
Gitlab::ColorSchemes.for_user(current_user).css_class
end
......
......@@ -20,7 +20,8 @@ module Enums
{
business: 0,
response: 1,
system: 2
system: 2,
custom: 3
}.freeze
end
......@@ -79,7 +80,11 @@ module Enums
system: {
group_title: _('System metrics (Custom)'),
priority: -10
}.freeze
}.freeze,
custom: {
group_title: _('Custom metrics'),
priority: 0
}
}.freeze
end
end
......
......@@ -30,7 +30,7 @@ module Mentionable
def self.external_pattern
strong_memoize(:external_pattern) do
issue_pattern = IssueTrackerService.reference_pattern
link_patterns = URI.regexp(%w(http https))
link_patterns = URI::DEFAULT_PARSER.make_regexp(%w(http https))
reference_pattern(link_patterns, issue_pattern)
end
end
......
......@@ -16,11 +16,13 @@ class PrometheusMetric < ApplicationRecord
validates :project, presence: true, unless: :common?
validates :project, absence: true, if: :common?
scope :for_dashboard_path, -> (dashboard_path) { where(dashboard_path: dashboard_path) }
scope :for_project, -> (project) { where(project: project) }
scope :for_group, -> (group) { where(group: group) }
scope :for_title, -> (title) { where(title: title) }
scope :for_y_label, -> (y_label) { where(y_label: y_label) }
scope :for_identifier, -> (identifier) { where(identifier: identifier) }
scope :not_identifier, -> (identifier) { where.not(identifier: identifier) }
scope :common, -> { where(common: true) }
scope :ordered, -> { reorder(created_at: :asc) }
......
......@@ -37,10 +37,12 @@ module Ci
.pluck(Arel.sql('MAX(id)'), 'name')
# mark builds that are retried
pipeline.statuses.latest
.where(name: latest_statuses.map(&:second))
.where.not(id: latest_statuses.map(&:first))
.update_all(retried: true) if latest_statuses.any?
if latest_statuses.any?
pipeline.statuses.latest
.where(name: latest_statuses.map(&:second))
.where.not(id: latest_statuses.map(&:first))
.update_all(retried: true)
end
end
# rubocop: enable CodeReuse/ActiveRecord
......
......@@ -27,7 +27,7 @@ module Projects
end
def http?(url)
url =~ /\A#{URI.regexp(%w(http https))}\z/
url =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/
end
def valid_domain?(url)
......
......@@ -16,11 +16,6 @@
= doorkeeper_errors_for application, :redirect_uri
%span.form-text.text-muted
Use one line per URI
- if Doorkeeper.configuration.native_redirect_uri
%span.form-text.text-muted
Use
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
= content_tag :div, class: 'form-group row' do
.col-sm-2.col-form-label.pt-0
......
......@@ -11,9 +11,6 @@
%span.form-text.text-muted
= _('Use one line per URI')
- if Doorkeeper.configuration.native_redirect_uri
%span.form-text.text-muted
= html_escape(_('Use %{native_redirect_uri} for local tests')) % { native_redirect_uri: tag.code(Doorkeeper.configuration.native_redirect_uri) }
.form-group.form-check
= f.check_box :confidential, class: 'form-check-input'
......
......@@ -49,6 +49,8 @@
= stylesheet_link_tag_defer "application_dark"
- else
= stylesheet_link_tag_defer "application"
- unless use_startup_css?
= stylesheet_link_tag_defer "themes/theme_#{user_application_theme_name}"
= stylesheet_link_tag "disable_animations", media: "all" if Rails.env.test? || Gitlab.config.gitlab['disable_animations']
= stylesheet_link_tag_defer 'performance_bar' if performance_bar_enabled?
......
......@@ -3,4 +3,5 @@
- startup_filename = current_path?("sessions#new") ? 'signin' : user_application_theme == 'gl-dark' ? 'dark' : 'general'
%style{ type: "text/css" }
= Rails.application.assets_manifest.find_sources("themes/theme_#{user_application_theme_name}.css").first.to_s.html_safe
= Rails.application.assets_manifest.find_sources("startup/startup-#{startup_filename}.css").first.to_s.html_safe
- page_title _('Preferences')
- @content_class = "limit-container-width" unless fluid_layout
- Gitlab::Themes.each do |theme|
= stylesheet_link_tag "themes/theme_#{theme.css_class.gsub('ui-', '')}"
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row gl-mt-3 js-preferences-form' } do |f|
.col-lg-4.application-theme#navigation-theme
%h4.gl-mt-0
......
......@@ -27,7 +27,7 @@
or
%button.attach-new-file.markdown-selector{ type: 'button' }= _("attach a new file")
%button.btn.markdown-selector.button-attach-file.btn-link{ type: 'button', tabindex: '-1' }
%button.btn.markdown-selector.button-attach-file.btn-link{ type: 'button' }
= sprite_icon('media')
%span.text-attach-file<>
= _("Attach a file")
......
---
title: Add NOT NULL constraint to merge_request_metrics.target_project_id
merge_request: 40836
author:
type: other
---
title: Add smtp_server to usage ping data
merge_request: 39844
author:
type: changed
---
title: Make file upload button on MR edit page tab accessible
merge_request: 40995
author:
type: fixed
---
title: Fix Style/CommentedKeyword cop
merge_request: 41119
author: Rajendra Kadam
type: fixed
---
title: Bump doorkeeper to 5.3.0
merge_request: 40929
author:
type: changed
---
title: Fix Lint/UriRegexp cop
merge_request: 41117
author: Rajendra Kadam
type: fixed
---
title: Fix Style/MultilineIfModifier cop
merge_request: 41113
author: Rajendra Kadam
type: fixed
......@@ -190,6 +190,8 @@ module Gitlab
config.assets.precompile << "errors.css"
config.assets.precompile << "jira_connect.js"
config.assets.precompile << "themes/*.css"
config.assets.precompile << "highlight/themes/*.css"
# Import gitlab-svgs directly from vendored directory
......
......@@ -79,13 +79,6 @@ Doorkeeper.configure do
# Check out the wiki for more information on customization
access_token_methods :from_access_token_param, :from_bearer_authorization, :from_bearer_param
# Change the native redirect uri for client apps
# When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
# The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
#
native_redirect_uri nil # 'urn:ietf:wg:oauth:2.0:oob'
# Specify what grant flows are enabled in array of Strings. The valid
# strings and the flows they enable are:
#
......
......@@ -30,7 +30,6 @@ en:
errors:
messages:
# Common error messages
invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
invalid_redirect_uri: 'The redirect URI included is not valid.'
unauthorized_client: 'The client is not authorized to perform this request using this method.'
access_denied: 'The resource owner or authorization server denied the request.'
......@@ -54,6 +53,12 @@ en:
# Password Access token errors
invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found'
invalid_request:
unknown: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
missing_param: 'Missing required parameter: %{value}.'
not_support_pkce: 'Invalid code_verifier parameter. Server does not support pkce.'
request_not_authorized: 'Request need to be authorized. Required parameter for authorizing request is missing or invalid.'
invalid_token:
revoked: "The access token was revoked"
expired: "The access token expired"
......
# frozen_string_literal: true
class AddNotValidNotNullConstraintToMrMetrics < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_not_null_constraint :merge_request_metrics, :target_project_id, validate: false
end
def down
remove_not_null_constraint :merge_request_metrics, :target_project_id
end
end
# frozen_string_literal: true
class AddTmpIndexToTargetProjectId < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
TMP_INDEX_NAME = 'tmp_index_on_mr_metrics_target_project_id_null'
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :merge_request_metrics, :id, where: 'target_project_id IS NULL', name: TMP_INDEX_NAME
end
def down
remove_concurrent_index_by_name :merge_request_metrics, name: TMP_INDEX_NAME
end
end
# frozen_string_literal: true
class EnsureTargetProjectIdIsFilled < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
BACKGROUND_MIGRATION_CLASS = 'CopyMergeRequestTargetProjectToMergeRequestMetrics'
BATCH_SIZE = 1_000
DOWNTIME = false
disable_ddl_transaction!
class MergeRequest < ActiveRecord::Base
self.table_name = 'merge_requests'
end
class MergeRequestMetrics < ActiveRecord::Base
include EachBatch
belongs_to :merge_request
self.table_name = 'merge_request_metrics'
end
def up
Gitlab::BackgroundMigration.steal(BACKGROUND_MIGRATION_CLASS)
# Do a manual update in case we lost BG jobs. The expected record count should be 0 or very low.
MergeRequestMetrics.where(target_project_id: nil).each_batch do |scope|
query_for_cte = scope.joins(:merge_request).select(
MergeRequestMetrics.arel_table[:id].as('id'),
MergeRequest.arel_table[:target_project_id].as('target_project_id')
)
MergeRequestMetrics.connection.execute <<-SQL
WITH target_project_id_and_metrics_id as (
#{query_for_cte.to_sql}
)
UPDATE #{MergeRequestMetrics.connection.quote_table_name(MergeRequestMetrics.table_name)}
SET target_project_id = target_project_id_and_metrics_id.target_project_id
FROM target_project_id_and_metrics_id
WHERE merge_request_metrics.id = target_project_id_and_metrics_id.id
SQL
end
end
def down
# no-op
end
end
# frozen_string_literal: true
class ValidateNotNullConstraintOnMrMetrics < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
TMP_INDEX_NAME = 'tmp_index_on_mr_metrics_target_project_id_null'
DOWNTIME = false
disable_ddl_transaction!
def up
validate_not_null_constraint :merge_request_metrics, :target_project_id
remove_concurrent_index_by_name :merge_request_metrics, name: TMP_INDEX_NAME
end
def down
add_concurrent_index :merge_request_metrics, :id, where: 'target_project_id IS NULL', name: TMP_INDEX_NAME
end
end
3e704cf329786e89f43fdefbc6a91272bebc6af5653dd83b5a81567937f75752
\ No newline at end of file
4cb28d6da005682bb077427f4f544996065e86f0e76d5de98fc1761555a0535b
\ No newline at end of file
c1457272bd8f0055992df5d4a8ba1a62cb74d3af3fff25447b3abd2eb090841e
\ No newline at end of file
8605268a026d4c66653008bb051c567c251044232b925b89f4407f9ad70f639c
\ No newline at end of file
......@@ -13209,7 +13209,8 @@ CREATE TABLE public.merge_request_metrics (
first_reassigned_at timestamp with time zone,
added_lines integer,
removed_lines integer,
target_project_id integer
target_project_id integer,
CONSTRAINT check_e03d0900bf CHECK ((target_project_id IS NOT NULL))
);
CREATE SEQUENCE public.merge_request_metrics_id_seq
......
---
stage: Release
group: Progressive Delivery
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
stage: none
group: Development
info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
type: reference
description: "GitLab administrator: enable and disable GitLab features deployed behind feature flags"
---
......
......@@ -12,12 +12,23 @@ files.
For broader information about the documentation, see the [Documentation guidelines](index.md).
For programmatic help adhering to the guidelines, see [Testing](index.md#testing).
For guidelines specific to text in the GitLab interface, see the Pajamas [Content](https://design.gitlab.com/content/error-messages) section.
See the GitLab Handbook for additional [writing style guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines)
that apply to all GitLab content, not just documentation.
For information on how to validate styles locally or by using GitLab CI/CD, see [Testing](index.md#testing).
View a list of [recent style guide updates](https://gitlab.com/dashboard/merge_requests?scope=all&utf8=%E2%9C%93&state=merged&label_name[]=tw-style&not[label_name][]=docs%3A%3Afix).
Use this guide for standards on grammar, formatting, word usage, and more.
You can also view a list of [recent updates to this guide](https://gitlab.com/dashboard/merge_requests?scope=all&utf8=%E2%9C%93&state=merged&label_name[]=tw-style&not[label_name][]=docs%3A%3Afix).
If you can't find what you need:
- View the GitLab Handbook for [writing style guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines) that apply to all GitLab content.
- Refer to one of the following:
- [Microsoft Style Guide](https://docs.microsoft.com/en-us/style-guide/).
- [Google Developer Documentation Style Guide](https://developers.google.com/style).
If you have questions about style, mention `@tw-style` in an issue or merge request, or, if you have access to the GitLab Slack workspace, use `#docs-process`.
## Documentation is the single source of truth (SSOT)
......
......@@ -7,16 +7,40 @@ info: "See the Technical Writers assigned to Development Guidelines: https://abo
# Feature flags in development of GitLab
[Feature Flags](../../operations/feature_flags.md)
can be used to gradually roll out changes, be
it a new feature, or a performance improvement. By using feature flags, we can
comfortably measure the impact of our changes, while still being able to easily
disable those changes, without having to revert an entire release.
Before using feature flags for GitLab's development, read through the following:
- [Process for using features flags](process.md).
- [Developing with feature flags](development.md).
- [Controlling feature flags](controls.md).
- [Documenting features deployed behind feature flags](../documentation/feature_flags.md).
- [How GitLab administrators can enable and disable features behind flags](../../administration/feature_flags.md).
Feature flags can be used to gradually deploy changes, regardless of whether
they are new features or performance improvements. By using feature flags,
you can determine the impact of GitLab-directed changes, while still being able
to disable those changes without having to revert an entire release.
Before using feature flags for GitLab's development, review the following development guides:
NOTE: **Note:**
The feature flags used by GitLab to deploy its own features **are not** the same
as the [feature flags offered as part of the product](../../operations/feature_flags.md).
For an overview about starting with feature flags in GitLab's development,
use this [training template](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/.gitlab/issue_templates/feature-flag-training.md).
Development guides:
- [Process for using features flags](process.md): When you should use
feature flags in the development of GitLab, what's the cost of using them,
and how to include them in a release.
- [Developing with feature flags](development.md): Learn about the types of
feature flags, their definition and validation, how to create them, frontend and
backend details, and other information.
- [Documenting features deployed behind feature flags](../documentation/feature_flags.md):
How to document features deployed behind feature flags, and how to update the
documentation for features' flags when their states change.
- [Controlling feature flags](controls.md): Learn the process for deploying
a new feature, enabling it on GitLab.com, communicating the change,
logging, and cleaning up.
User guides:
- [How GitLab administrators can enable and disable features behind flags](../../administration/feature_flags.md):
An explanation for GitLab administrators about how they can
enable or disable GitLab features behind feature flags.
- [What "features deployed behind flags" means to the GitLab user](../../user/feature_flags.md):
An explanation for GitLab users regarding how certain features
might not be available to them until they are enabled.
......@@ -134,3 +134,128 @@ Once you have finished testing you can stop and remove the Docker containers:
docker stop gitlab-gitaly-ha praefect postgres gitaly3 gitaly2 gitaly1
docker rm gitlab-gitaly-ha praefect postgres gitaly3 gitaly2 gitaly1
```
## Guide to run and debug monitor tests
## How to set up
To run the Monitor tests locally, against the GDK, please follow the preparation steps below:
1. Complete the [Prerequisites](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/auto_devops/index.md#prerequisites-for-gitlab-team-members-only), at least through step 5. Note that the monitor tests do not require permissions to work with GKE because they use [k3s as a Kubernetes cluster provider](https://github.com/rancher/k3s).
1. The test setup deploys the app in a Kubernetes cluster, using the Auto DevOps deployment strategy.
To enable Auto DevOps in GDK, follow the [associated setup](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/auto_devops/index.md#setup) instructions. If you have problems, review the [troubleshooting guide](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/auto_devops/tips_and_troubleshooting.md) or reach out to the `#gdk` channel in the internal GitLab Slack.
1. Do [secure your GitLab instance](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/auto_devops/index.md#secure-your-gitlab-instance) since it is now publicly accessible on `https://[YOUR-PORT].qa-tunnel.gitlab.info`.
1. Install the Kubernetes command line tool known as `kubectl`. Use the [official installation instructions](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
You might see NGINX issues when you run `gdk start` or `gdk restart`. In that case, run `sft login` to revalidate your credentials and regain access the QA Tunnel.
## How to run
Navigate to the folder in `/your-gdk/gitlab/qa` and issue the command:
```shell
QA_DEBUG=true CHROME_HEADLESS=false GITLAB_ADMIN_USERNAME=rootusername GITLAB_ADMIN_PASSWORD=rootpassword GITLAB_QA_ACCESS_TOKEN=your_token_here GITLAB_QA_ADMIN_ACCESS_TOKEN=your_token_here CLUSTER_API_URL=https://kubernetes.docker.internal:6443 bundle exec bin/qa Test::Instance::All https://[YOUR-PORT].qa-tunnel.gitlab.info/ -- qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb --tag kubernetes --tag orchestrated --tag requires_admin
```
The following includes more information on the command:
-`QA_DEBUG` - Set to `true` to verbosely log page object actions.
-`CHROME_HEADLESS` - When running locally, set to `false` to allow Chrome tests to be visible - watch your tests being run.
-`GITLAB_ADMIN_USERNAME` - Admin username to use when adding a license.
-`GITLAB_ADMIN_PASSWORD` - Admin password to use when adding a license.
-`GITLAB_QA_ACCESS_TOKEN` and `GITLAB_QA_ADMIN_ACCESS_TOKEN` - A valid personal access token with the `api` scope. This is used for API access during tests, and is used in the version that staging is currently running. The `ADMIN_ACCESS_TOKEN` is from a user with admin access. Used for API access as an admin during tests.
-`CLUSTER_API_URL` - Use the address `https://kubernetes.docker.internal:6443` . This address is used to enable the cluster to be network accessible while deploying using Auto DevOps.
-`https://[YOUR-PORT].qa-tunnel.gitlab.info/` - The address of your local GDK
-`qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb` - The path to the monitor core specs
-`--tag` - the meta-tags used to filter the specs correctly
At the moment of this writing, there are two specs which run monitor tests:
-`qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb` - has the specs of features in GitLab Core
-`qa/specs/features/ee/browser_ui/8_monitor/all_monitor_features_spec.rb` - has the specs of features for paid GitLab (Enterprise Edition)
## How to debug
The monitor tests follow this setup flow:
1. Creates a k3s cluster on your local machine.
1. Creates a project that has Auto DevOps enabled and uses an Express template (NodeJS) for the app to be deployed.
1. Associates the created cluster to the project and installs GitLab Runner, Prometheus and Ingress which are the needed components for a successful deployment.
1. Creates a CI pipeline with 2 jobs (`build` and `production`) to deploy the app on the Kubernetes cluster.
1. Goes to Operation > Metrics menu to verify data is being received and the app is being monitored successfully.
The test requires a number of components. The setup requires time to collect the metrics of a real deployment.
The complexity of the setup may lead to problems unrelated to the app. The following sections include common strategies to debug possible issues.
### Deployment with Auto DevOps
When debugging issues in the CI or locally in the CLI, open the Kubernetes job in the pipeline.
In the job log window, click on the top right icon labeled as *"Show complete raw"* to reveal raw job logs.
You can now search through the logs for *Job log*, which matches delimited sections like this one:
```shell
------- Job log: -------
```
A Job log is a subsection within these logs, related to app deployment. We use two jobs: `build` and `production`.
You can find the root causes of deployment failures in these logs, which can compromise the entire test.
If a `build` job fails, the `production` job won't run, and the test fails.
The long test setup does not take screenshots of failures, which is a known [issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/270).
However, if the spec fails (after a successful deployment) then you should be able to find screenshots which display the feature failure.
To access them in CI, go to the main job log window, look on the left side panel's Job artifacts section, and click Browse.
### Common issues
**Container Registry**
When enabling Auto DevOps in the GDK, you may see issues with the Container Registry, which stores
images of the app to be deployed.
You can access the Registry is available by opening an existing project. On the left hand menu,
select `Packages & Registries > Container Registries`. If the Registry is available, this page should load normally.
Also, the Registry should be running in Docker:
```shell
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f035f339506c registry.gitlab.com/gitlab-org/build/cng/gitlab-container-registry:v2.9.1-gitlab "/bin/sh -c 'exec /b…" 3 hours ago Up 3 hours 0.0.0.0:5000->5000/tcp jovial_proskuriakova
```
The `gdk status` command shows if the registry is running:
```shell
run: ./services/registry: (pid 2662) 10875s, normally down; run: log: (pid 65148) 177993s
run: ./services/tunnel_gitlab: (pid 2650) 10875s, normally down; run: log: (pid 65154) 177993s
run: ./services/tunnel_registry: (pid 2651) 10875s, normally down; run: log: (pid 65155) 177993s
```
Also, restarting Docker and then, on the Terminal, issue the command `docker login https://[YOUR-REGISTRY-PORT].qa-tunnel.gitlab.info:443` and use the GDK credentials to login. Note that the Registry port and GDK port are not the same. When configuring Auto DevOps in GDK, the `gdk reconfigure` command outputs the port of the Registry:
```shell
*********************************************
Tunnel URLs
GitLab: https://[PORT].qa-tunnel.gitlab.info
Registry: https://[PORT].qa-tunnel.gitlab.info
*********************************************
```
These Tunnel URLs are used by the QA SSH Tunnel generated when enabling Auto DevOps on the GDK.
**Pod Eviction**
Pod eviction happens when a node in a Kubernetes cluster is running out of memory or disk. After many local deployments this issue can happen. The UI shows that installing Prometheus, GitLab Runner and Ingress failed. How to be sure it is an Eviction? While the test is running, open another Terminal window and debug the current Kubernetes cluster by `kubectl get pods --all-namespaces`. If you observe that Pods have *Evicted status* such as the install-runner here:
```shell
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
gitlab-managed-apps install-ingress 0/1 Pending 0 25s
gitlab-managed-apps install-prometheus 0/1 Pending 0 12s
gitlab-managed-apps install-runner 0/1 Evicted 0 75s
```
You can free some memory with either of the following commands: `docker prune system` or `docker prune volume`.
......@@ -163,10 +163,15 @@ NOTE: **Note:**
For large GitLab instances you can follow the instructions for [Indexing large
instances](#indexing-large-instances) below.
In order to enable Elasticsearch, you need to have admin access in GitLab.
To enable Elasticsearch, you need to have admin access to GitLab:
1. Navigate to **Admin Area** (wrench icon), then **Settings > General**
and expand the **Elasticsearch** section.
and expand the **Elasticsearch** section.
NOTE: **Note:**
To see the Elasticsearch section, you need an active Starter
[license](../user/admin_area/license.md).
1. Configure the [Elasticsearch settings](#elasticsearch-configuration) for
your Elasticsearch cluster. Do not enable **Elasticsearch indexing** or
**Search with Elasticsearch** yet.
......
......@@ -16,6 +16,10 @@ delivery from customer launch.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an example of feature flags in action, see [GitLab for Deploys, Feature Flags, and Error Tracking](https://www.youtube.com/embed/5tw2p6lwXxo).
NOTE: **Note:**
The Feature Flags GitLab offer as a feature (described in this document) is not the same method
used for the [development of GitLab](../development/feature_flags/index.md).
## How it works
GitLab uses [Unleash](https://github.com/Unleash/unleash), a feature
......
......@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Alert details page
Navigate to the Alert details view by visiting the
[Alert list](alerts.md) and selecting an alert from the
[Alert list](./alerts.md) and selecting an alert from the
list. You need least Developer [permissions](../../user/permissions.md) to access
alerts.
......@@ -18,16 +18,16 @@ amount of information you need.
The **Overview** tab provides basic information about the alert:
![Alert Detail Overview](img/alert_detail_overview_v13_1.png)
![Alert Detail Overview](./img/alert_detail_overview_v13_1.png)
## Alert details tab
![Alert Full Details](img/alert_detail_full_v13_1.png)
![Alert Full Details](./img/alert_detail_full_v13_1.png)
### Update an Alert's status
The Alert detail view enables you to update the Alert Status.
See [Create and manage alerts in GitLab](alerts.md) for more details.
See [Create and manage alerts in GitLab](./alerts.md) for more details.
### Create an Issue from an Alert
......@@ -57,11 +57,11 @@ GitLab currently only supports a single assignee per alert.
1. To display the list of current alerts, click
**{cloud-gear}** **Operations > Alerts**:
![Alert List View Assignee(s)](img/alert_list_assignees_v13_1.png)
![Alert List View Assignee(s)](./img/alert_list_assignees_v13_1.png)
1. Select your desired alert to display its **Alert Details View**:
![Alert Details View Assignee(s)](img/alert_details_assignees_v13_1.png)
![Alert Details View Assignee(s)](./img/alert_details_assignees_v13_1.png)
1. If the right sidebar is not expanded, click
**{angle-double-right}** **Expand sidebar** to expand it.
......@@ -69,7 +69,7 @@ GitLab currently only supports a single assignee per alert.
dropdown menu, select each user you want to assign to the alert. GitLab creates
a [To-Do list item](../../user/todos.md) for each user.
![Alert Details View Assignee(s)](img/alert_todo_assignees_v13_1.png)
![Alert Details View Assignee(s)](./img/alert_todo_assignees_v13_1.png)
To remove an assignee, click **Edit** next to the **Assignee** dropdown menu and
deselect the user from the list of assignees, or click **Unassigned**.
......@@ -88,7 +88,7 @@ The following actions will result in a system note:
- [Creating an issue based on an alert](#create-an-issue-from-an-alert)
- [Assignment of an alert to a user](#update-an-alerts-assignee)
![Alert Details View System Notes](img/alert_detail_system_notes_v13_1.png)
![Alert Details View System Notes](./img/alert_detail_system_notes_v13_1.png)
### Create a To-Do from an Alert
......@@ -102,11 +102,11 @@ Alert details screen, and view them later on your **To-Do List**. To add a To-Do
1. Select your desired alert to display its **Alert Management Details View**.
1. Click the **Add a To-Do** button in the right sidebar:
![Alert Details Add A To Do](img/alert_detail_add_todo_v13_1.png)
![Alert Details Add A To Do](./img/alert_detail_add_todo_v13_1.png)
Click the **To-Do** **{todo-done}** in the navigation bar to view your current To-Do list.
![Alert Details Added to Do](img/alert_detail_added_todo_v13_1.png)
![Alert Details Added to Do](./img/alert_detail_added_todo_v13_1.png)
### View an Alert's metrics data
......@@ -145,7 +145,7 @@ notifications, simplifying communication and ownership of the alert.
After completing their portion of investigating or fixing the alert, users can
unassign their account from the alert when their role is complete.
The alert status can be updated on the [Alert list](alerts.md) to
The alert status can be updated on the [Alert list](./alerts.md) to
reflect if the alert has been resolved.
## View an Alert's logs
......
......@@ -14,7 +14,7 @@ but you can change the sort order by clicking the headers in the Alert Managemen
The alert list displays the following information:
![Alert List](img/alert_list_v13_1.png)
![Alert List](./img/alert_list_v13_1.png)
- **Search** - The alert list supports a simple free text search on the title,
description, monitoring tool, and service fields.
......@@ -58,7 +58,7 @@ To populate the alerts with data, read
You can configure an externally-managed Prometheus instance to send alerts
to GitLab. To set up this configuration, read the [configuring Prometheus](../metrics/alerts.md#external-prometheus-instances) documentation. Activating the external Prometheus
configuration also enables the [Alerts list](alerts.md).
configuration also enables the [Alerts list](./alerts.md).
To populate the alerts with data, read
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances).
......@@ -69,9 +69,9 @@ GitLab provides the Generic Alerts endpoint so you can accept alerts from a thir
alerts service. Read the
[instructions for toggling generic alerts](generic_alerts.md#setting-up-generic-alerts)
to add this option. After configuring the endpoint, the
[Alerts list](alerts.md) is enabled.
[Alerts list](./alerts.md) is enabled.
To populate the alerts with data, read [Customizing the payload](generic_alerts.md#customizing-the-payload) for requests to the alerts endpoint.
To populate the alerts with data, read [Customizing the payload](./generic_alerts.md#customizing-the-payload) for requests to the alerts endpoint.
### Opsgenie integration **(PREMIUM)**
......@@ -82,7 +82,7 @@ A new way of monitoring Alerts via a GitLab integration is with
NOTE: **Note:**
If you enable the Opsgenie integration, you can't have other GitLab alert services,
such as [Generic Alerts](generic_alerts.md) or
such as [Generic Alerts](./generic_alerts.md) or
Prometheus alerts, active at the same time.
To enable Opsgenie integration:
......@@ -104,7 +104,7 @@ Each level of alert contains a uniquely shaped and color-coded icon to help
you identify the severity of a particular alert. These severity icons help you
immediately identify which alerts you should prioritize investigating:
![Alert Management Severity System](img/alert_management_severity_v13_0.png)
![Alert Management Severity System](./img/alert_management_severity_v13_0.png)
Alerts contain one of the following icons:
......
......@@ -117,9 +117,9 @@ In GitLab versions 13.2 and greater, GitLab groups alerts based on their payload
When an incoming alert contains the same payload as another alert (excluding the
`start_time` and `hosts` attributes), GitLab groups these alerts together and
displays a counter on the
[Alert Management List](incidents.md)
[Alert Management List](./incidents.md)
and details pages.
If the existing alert is already `resolved`, then a new alert will be created instead.
![Alert Management List](img/alert_list_v13_1.png)
![Alert Management List](./img/alert_list_v13_1.png)
......@@ -13,7 +13,7 @@ For users with at least Developer [permissions](../../user/permissions.md), the
Incident Management list is available at **Operations > Incidents**
in your project's sidebar. The list contains the following metrics:
![Incident List](img/incident_list_sort_v13_3.png)
![Incident List](./img/incident_list_sort_v13_3.png)
- **Status** - To filter incidents by their status, click **Open**, **Closed**,
or **All** above the incident list.
......@@ -26,7 +26,7 @@ in your project's sidebar. The list contains the following metrics:
tooltip depending on the user's locale.
- **Assignees** - The user assigned to the incident.
- **Published** - Displays a green check mark (**{check-circle}**) if the incident is published
to a [Status Page](status_page.md).. **(ULTIMATE)**
to a [Status Page](./status_page.md).. **(ULTIMATE)**
The Incident list displays incidents sorted by incident created date.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229534) to GitLab core in 13.3).)
......@@ -47,7 +47,7 @@ to create issues when alerts are triggered:
1. Navigate to **Settings > Operations > Incidents** and expand
**Incidents**:
![Incident Management Settings](img/incident_management_settings_v13_3.png)
![Incident Management Settings](./img/incident_management_settings_v13_3.png)
1. For GitLab versions 11.11 and greater, you can select the **Create an issue**
checkbox to create an issue based on your own
......@@ -91,7 +91,7 @@ in both PagerDuty and GitLab:
1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**.
1. Select the **PagerDuty integration** tab:
![PagerDuty incidents integration](img/pagerduty_incidents_integration_v13_3.png)
![PagerDuty incidents integration](./img/pagerduty_incidents_integration_v13_3.png)
1. Activate the integration, and save the changes in GitLab.
1. Copy the value of **Webhook URL** for use in a later step.
......
......@@ -8,13 +8,13 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2877) in GitLab 13.0.
Alert Management enables developers to easily discover and view the alerts
Incident Management enables developers to easily discover and view the alerts
generated by their application. By surfacing alert information where the code is
being developed, efficiency and awareness can be increased.
GitLab offers solutions for handling incidents in your applications and services,
such as [setting up Prometheus alerts](#configure-prometheus-alerts),
[displaying metrics](alertdetails.md#embed-metrics-in-incidents-and-issues), and sending notifications.
[displaying metrics](./alert_details.md#embed-metrics-in-incidents-and-issues), and sending notifications.
## Alert notifications
......@@ -35,7 +35,7 @@ These emails contain details of the alert, and a link for more information.
To send separate email notifications to users with
[Developer permissions](../../user/permissions.md), see
[Configure incidents](incidents.md#configure-incidents).
[Configure incidents](./incidents.md#configure-incidents).
## Configure Prometheus alerts
......@@ -49,9 +49,12 @@ user, but it does not count toward your license limit.
## Configure external generic alerts
GitLab can accept alerts from any source through a generic webhook receiver. When
[configuring the generic alerts integration](generic_alerts.md),
GitLab creates a unique endpoint which receives a JSON-formatted, customizable payload.
GitLab can accept alerts from any source through a generic webhook receiver.
When [configuring the generic alerts integration](./generic_alerts.md), GitLab
creates a unique endpoint which receives a JSON-formatted, customizable payload.
After configuration, you can manage your alerts using either the
[alerts section](./alerts.md) or the [alert details section](./alert_details.md).
## Integrate incidents with Slack
......@@ -66,3 +69,13 @@ GitLab enables you to [associate a Zoom meeting with an issue](../../user/projec
for synchronous communication during incident management. After starting a Zoom
call for an incident, you can associate the conference call with an issue. Your
team members can join the Zoom call without requesting a link.
## More information
For information about GitLab and incident management, see:
- [Generic alerts](./generic_alerts.md)
- [Alerts](./alerts.md)
- [Alert details](./alert_details.md)
- [Incidents](./incidents.md)
- [Status page](./status_page.md)
......@@ -12,11 +12,11 @@ With a GitLab Status Page, you can create and deploy a static website to communi
efficiently to users during an incident. The Status Page landing page displays an
overview of recent incidents:
![Status Page landing page](img/status_page_incidents_v12_10.png)
![Status Page landing page](./img/status_page_incidents_v12_10.png)
Clicking an incident displays a detail page with more information about a particular incident:
![Status Page detail](img/status_page_detail_v12_10.png)
![Status Page detail](./img/status_page_detail_v12_10.png)
- Status on the incident, including when the incident was last updated.
- The incident title, including any emojis.
......@@ -144,7 +144,7 @@ you provided during setup. As part of publication, GitLab will:
After publication, you can access the incident's details page by clicking the
**Published on status page** button displayed under the Incident's title.
![Status Page detail link](img/status_page_detail_link_v13_1.png)
![Status Page detail link](./img/status_page_detail_link_v13_1.png)
### Update an incident
......
......@@ -155,7 +155,7 @@ The following variables allow configuration of global dependency scanning settin
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `DS_DEFAULT_ANALYZERS` | Override the names of the official default images. Read more about [customizing analyzers](analyzers.md). |
| `DS_DISABLE_DIND` | Disable Docker-in-Docker and run analyzers [individually](#enabling-docker-in-docker). This variable is `true` by default. |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs to trust. |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs to trust. The bundle of certificates provided here is also used by other tools during the scanning process, such as `git`, `yarn`, or `npm`. |
| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"` |
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info` |
......@@ -444,7 +444,6 @@ include:
variables:
SECURE_ANALYZERS_PREFIX: "docker-registry.example.com/analyzers"
GEMNASIUM_DB_REMOTE_URL: "gitlab.example.com/gemnasium-db.git"
GIT_SSL_NO_VERIFY: "true"
```
See explanations of the variables above in the [configuration section](#configuration).
......
---
stage: Release
group: Progressive Delivery
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
stage: none
group: Development
info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
description: "Understand what 'GitLab features deployed behind flags' means."
---
# GitLab functionality may be limited by feature flags
......
......@@ -45,6 +45,11 @@ The following are some possible use cases for repository mirroring:
- You have old projects in another source that you don't use actively anymore, but don't want to
remove for archiving purposes. In that case, you can create a push mirror so that your active
GitLab repository can push its changes to the old location.
- You are a GitLab self-managed user for privacy reasons and your instance is closed to the public,
but you still have certain software components that you want open sourced. In this case, utilizing
GitLab to be your primary repository which is closed from the public, and using push mirroring to a
GitLab.com repository that's public, allows you to open source specific projects and contribute back
to the open source community.
## Pushing to a remote repository **(CORE)**
......
......@@ -6,6 +6,15 @@ module API
before { authenticated_as_admin! }
resource :applications do
helpers do
def validate_redirect_uri(value)
uri = ::URI.parse(value)
!uri.is_a?(URI::HTTP) || uri.host
rescue URI::InvalidURIError
false
end
end
desc 'Create a new application' do
detail 'This feature was introduced in GitLab 10.5'
success Entities::ApplicationWithSecret
......@@ -19,6 +28,13 @@ module API
desc: 'Application will be used where the client secret is confidential'
end
post do
# Validate that host in uri is specified
# Please remove it when https://github.com/doorkeeper-gem/doorkeeper/pull/1440 is merged
# and the doorkeeper gem version is bumped
unless validate_redirect_uri(declared_params[:redirect_uri])
render_api_error!({ redirect_uri: ["must be an absolute URI."] }, :bad_request)
end
application = Doorkeeper::Application.new(declared_params)
if application.save
......
......@@ -117,8 +117,10 @@ module API
render_api_error!('invalid state', 400)
end
MergeRequest.where(source_project: user_project, source_branch: ref)
.update_all(head_pipeline_id: pipeline.id) if pipeline.latest?
if pipeline.latest?
MergeRequest.where(source_project: user_project, source_branch: ref)
.update_all(head_pipeline_id: pipeline.id)
end
present status, with: Entities::CommitStatus
rescue StateMachines::InvalidTransition => e
......
......@@ -9,7 +9,7 @@ module Gitlab
class Remote < Source
def content
strong_memoize(:content) do
next unless ci_config_path =~ URI.regexp(%w[http https])
next unless ci_config_path =~ URI::DEFAULT_PARSER.make_regexp(%w[http https])
YAML.dump('include' => [{ 'remote' => ci_config_path }])
end
......
......@@ -18,6 +18,7 @@ module Gitlab
business: 0,
response: 1,
system: 2,
custom: 3,
cluster_health: -100
}
......@@ -34,7 +35,8 @@ module Gitlab
aws_elb: _('Response metrics (AWS ELB)'),
nginx: _('Response metrics (NGINX)'),
kubernetes: _('System metrics (Kubernetes)'),
cluster_health: _('Cluster Health')
cluster_health: _('Cluster Health'),
custom: _('Custom metrics')
}
end
end
......
# frozen_string_literal: true
module Gitlab
module Metrics
module Dashboard
class Importer
def initialize(dashboard_path, project)
@dashboard_path = dashboard_path.to_s
@project = project
end
def execute
return false unless Dashboard::Validator.validate(dashboard_hash, project: project, dashboard_path: dashboard_path)
Dashboard::Importers::PrometheusMetrics.new(dashboard_hash, project: project, dashboard_path: dashboard_path).execute
rescue Gitlab::Config::Loader::FormatError
false
end
def execute!
Dashboard::Validator.validate!(dashboard_hash, project: project, dashboard_path: dashboard_path)
Dashboard::Importers::PrometheusMetrics.new(dashboard_hash, project: project, dashboard_path: dashboard_path).execute!
end
private
attr_accessor :dashboard_path, :project
def dashboard_hash
@dashboard_hash ||= begin
raw_dashboard = Dashboard::RepoDashboardFinder.read_dashboard(project, dashboard_path)
return unless raw_dashboard.present?
::Gitlab::Config::Loader::Yaml.new(raw_dashboard).load_raw!
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Metrics
module Dashboard
module Importers
class PrometheusMetrics
ALLOWED_ATTRIBUTES = %i(title query y_label unit legend group dashboard_path).freeze
# Takes a JSON schema validated dashboard hash and
# imports metrics to database
def initialize(dashboard_hash, project:, dashboard_path:)
@dashboard_hash = dashboard_hash
@project = project
@dashboard_path = dashboard_path
end
def execute
import
rescue ActiveRecord::RecordInvalid, ::Gitlab::Metrics::Dashboard::Transformers::TransformerError
false
end
def execute!
import
end
private
attr_reader :dashboard_hash, :project, :dashboard_path
def import
delete_stale_metrics
create_or_update_metrics
end
# rubocop: disable CodeReuse/ActiveRecord
def create_or_update_metrics
# TODO: use upsert and worker for callbacks?
prometheus_metrics_attributes.each do |attributes|
prometheus_metric = PrometheusMetric.find_or_initialize_by(attributes.slice(:identifier, :project))
prometheus_metric.update!(attributes.slice(*ALLOWED_ATTRIBUTES))
end
end
# rubocop: enable CodeReuse/ActiveRecord
def delete_stale_metrics
identifiers = prometheus_metrics_attributes.map { |metric_attributes| metric_attributes[:identifier] }
stale_metrics = PrometheusMetric.for_project(project)
.for_dashboard_path(dashboard_path)
.for_group(Enums::PrometheusMetric.groups[:custom])
.not_identifier(identifiers)
# TODO: use destroy_all and worker for callbacks?
stale_metrics.each(&:destroy)
end
def prometheus_metrics_attributes
@prometheus_metrics_attributes ||= begin
Dashboard::Transformers::Yml::V1::PrometheusMetrics.new(
dashboard_hash,
project: project,
dashboard_path: dashboard_path
).execute
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Metrics
module Dashboard
module Transformers
TransformerError = Class.new(StandardError)
module Errors
class MissingAttribute < TransformerError
def initialize(attribute_name)
super("Missing attribute: '#{attribute_name}'")
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Metrics
module Dashboard
module Transformers
module Yml
module V1
# Takes a JSON schema validated dashboard hash and
# maps it to PrometheusMetric model attributes
class PrometheusMetrics
def initialize(dashboard_hash, project: nil, dashboard_path: nil)
@dashboard_hash = dashboard_hash.with_indifferent_access
@project = project
@dashboard_path = dashboard_path
@dashboard_hash.default_proc = -> (h, k) { raise Transformers::Errors::MissingAttribute, k.to_s }
end
def execute
prometheus_metrics = []
dashboard_hash[:panel_groups].each do |panel_group|
panel_group[:panels].each do |panel|
panel[:metrics].each do |metric|
prometheus_metrics << {
project: project,
title: panel[:title],
y_label: panel[:y_label],
query: metric[:query_range] || metric[:query],
unit: metric[:unit],
legend: metric[:label],
identifier: metric[:id],
group: Enums::PrometheusMetric.groups[:custom],
common: false,
dashboard_path: dashboard_path
}.compact
end
end
end
prometheus_metrics
end
private
attr_reader :dashboard_hash, :project, :dashboard_path
end
end
end
end
end
end
end
......@@ -269,6 +269,9 @@ module Gitlab
database: {
adapter: alt_usage_data { Gitlab::Database.adapter_name },
version: alt_usage_data { Gitlab::Database.version }
},
mail: {
smtp_server: alt_usage_data { ActionMailer::Base.smtp_settings[:address] }
}
}
end
......
......@@ -52,7 +52,7 @@ module Mattermost
# Next methods are needed for Doorkeeper
def pre_auth
@pre_auth ||= Doorkeeper::OAuth::PreAuthorization.new(
Doorkeeper.configuration, server.client_via_uid, params)
Doorkeeper.configuration, params)
end
def authorization
......
......@@ -278,5 +278,7 @@ namespace :gitlab do
$stdout
end
end
end # namespace end: backup
end # namespace end: gitlab
end
# namespace end: backup
end
# namespace end: gitlab
......@@ -7426,6 +7426,9 @@ msgstr ""
msgid "Custom hostname (for private commit emails)"
msgstr ""
msgid "Custom metrics"
msgstr ""
msgid "Custom notification events"
msgstr ""
......@@ -26892,9 +26895,6 @@ msgstr ""
msgid "Use %{code_start}::%{code_end} to create a %{link_start}scoped label set%{link_end} (eg. %{code_start}priority::1%{code_end})"
msgstr ""
msgid "Use %{native_redirect_uri} for local tests"
msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
......
......@@ -3,8 +3,8 @@ LABEL maintainer="GitLab Quality Department <quality@gitlab.com>"
ENV DEBIAN_FRONTEND="noninteractive"
ENV DOCKER_VERSION="17.09.0-ce"
ENV CHROME_VERSION="84.0.4147.89-1"
ENV CHROME_DRIVER_VERSION="84.0.4147.30"
ENV CHROME_VERSION="85.0.4183.83-1"
ENV CHROME_DRIVER_VERSION="85.0.4183.87"
ENV CHROME_DEB="google-chrome-stable_${CHROME_VERSION}_amd64.deb"
ENV CHROME_URL="https://s3.amazonaws.com/gitlab-google-chrome-stable/${CHROME_DEB}"
......
......@@ -4,6 +4,7 @@ UsageData/LargeTable:
- 'lib/gitlab/usage_data.rb'
- 'ee/lib/ee/gitlab/usage_data.rb'
NonRelatedClasses:
- :ActionMailer::Base
- :Date
- :Feature
- :Gitlab
......
......@@ -147,13 +147,12 @@ function disable_sign_ups() {
run_task "${ruby_cmd}"
# Disable sign-ups
retry 'curl --silent --show-error --request PUT --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" "${CI_ENVIRONMENT_URL}/api/v4/application/settings?signup_enabled=false"'
local signup_enabled=$(retry 'curl --silent --show-error --request PUT --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" "${CI_ENVIRONMENT_URL}/api/v4/application/settings?signup_enabled=false" | jq ".signup_enabled"')
local signup_enabled=$(retry 'curl --silent --show-error --request GET --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" "${CI_ENVIRONMENT_URL}/api/v4/application/settings" | jq ".signup_enabled"')
if [[ "${signup_enabled}" == "false" ]]; then
echoinfo "Sign-ups have been disabled successfully."
else
echoerr "Sign-ups should be disabled but are still enabled!"
echoerr "Sign-ups are still enabled!"
false
fi
}
......
......@@ -91,4 +91,28 @@ describe('Boards - Getters', () => {
});
});
});
describe('getIssueById', () => {
const state = { issues: { '1': 'issue' } };
it.each`
id | expected
${'1'} | ${'issue'}
${''} | ${{}}
`('returns $expected when $id is passed to state', ({ id, expected }) => {
expect(getters.getIssueById(state)(id)).toEqual(expected);
});
});
describe('getActiveIssue', () => {
it.each`
id | expected
${'1'} | ${'issue'}
${''} | ${{}}
`('returns $expected when $id is passed to state', ({ id, expected }) => {
const state = { issues: { '1': 'issue' }, activeId: id };
expect(getters.getActiveIssue(state)).toEqual(expected);
});
});
});
......@@ -129,19 +129,24 @@ describe('Board Store Mutations', () => {
describe('RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS', () => {
it('sets isLoadingIssues to false and updates issuesByListId object', () => {
const listIssues = {
'1': [mockIssue],
'1': [mockIssue.id],
};
const issues = {
'1': mockIssue,
};
state = {
...state,
isLoadingIssues: true,
issuesByListId: {},
issues: {},
};
mutations.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS(state, listIssues);
mutations.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS(state, { listData: listIssues, issues });
expect(state.isLoadingIssues).toBe(false);
expect(state.issuesByListId).toEqual(listIssues);
expect(state.issues).toEqual(issues);
});
});
......
import { GlIntersectionObserver } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import { useMockIntersectionObserver } from 'helpers/mock_dom_observer';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import '~/behaviors/markdown/render_gfm';
import IssuableApp from '~/issue_show/components/app.vue';
import eventHub from '~/issue_show/event_hub';
import { initialRequest, secondRequest } from '../mock_data';
import {
appProps,
initialRequest,
publishedIncidentUrl,
secondRequest,
zoomMeetingUrl,
} from '../mock_data';
import IncidentTabs from '~/issue_show/components/incident_tabs.vue';
import DescriptionComponent from '~/issue_show/components/description.vue';
import PinnedLinks from '~/issue_show/components/pinned_links.vue';
......@@ -22,30 +27,6 @@ jest.mock('~/issue_show/event_hub');
const REALTIME_REQUEST_STACK = [initialRequest, secondRequest];
const zoomMeetingUrl = 'https://gitlab.zoom.us/j/95919234811';
const publishedIncidentUrl = 'https://status.com/';
const defaultProps = {
canUpdate: true,
canDestroy: true,
endpoint: '/gitlab-org/gitlab-shell/-/issues/9/realtime_changes',
updateEndpoint: TEST_HOST,
issuableRef: '#1',
issuableStatus: 'opened',
initialTitleHtml: '',
initialTitleText: '',
initialDescriptionHtml: 'test',
initialDescriptionText: 'test',
lockVersion: 1,
markdownPreviewPath: '/',
markdownDocsPath: '/',
projectNamespace: '/',
projectPath: '/',
issuableTemplateNamesPath: '/issuable-templates-path',
zoomMeetingUrl,
publishedIncidentUrl,
};
describe('Issuable output', () => {
useMockIntersectionObserver();
......@@ -57,7 +38,7 @@ describe('Issuable output', () => {
const mountComponent = (props = {}) => {
wrapper = mount(IssuableApp, {
propsData: { ...defaultProps, ...props },
propsData: { ...appProps, ...props },
});
};
......
import MockAdapter from 'axios-mock-adapter';
import { useMockIntersectionObserver } from 'helpers/mock_dom_observer';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import initIssuableApp from '~/issue_show/issue';
import { parseIssuableData } from '~/issue_show/utils/parse_data';
import * as parseData from '~/issue_show/utils/parse_data';
import { appProps } from './mock_data';
const mock = new MockAdapter(axios);
mock.onGet().reply(200);
useMockIntersectionObserver();
jest.mock('~/lib/utils/poll');
const setupHTML = initialData => {
document.body.innerHTML = `
<div id="js-issuable-app"></div>
<script id="js-issuable-app-initial-data" type="application/json">
${JSON.stringify(initialData)}
</script>
`;
};
describe('Issue show index', () => {
describe('initIssueableApp', () => {
// Warning: this test is currently faulty.
// More details at https://gitlab.com/gitlab-org/gitlab/-/issues/241717
// eslint-disable-next-line jest/no-disabled-tests
it.skip('should initialize app with no potential XSS attack', () => {
const d = document.createElement('div');
d.id = 'js-issuable-app-initial-data';
d.innerHTML = JSON.stringify({
initialDescriptionHtml: '&lt;img src=x onerror=alert(1)&gt;',
});
it('should initialize app with no potential XSS attack', async () => {
const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
const parseDataSpy = jest.spyOn(parseData, 'parseIssuableData');
document.body.appendChild(d);
setupHTML({
...appProps,
initialDescriptionHtml: '<svg onload=window.alert(1)>',
});
const alertSpy = jest.spyOn(window, 'alert');
const issuableData = parseIssuableData();
const issuableData = parseData.parseIssuableData();
initIssuableApp(issuableData);
await waitForPromises();
expect(parseDataSpy).toHaveBeenCalled();
expect(alertSpy).not.toHaveBeenCalled();
});
});
......
......@@ -31,3 +31,28 @@ export const descriptionProps = {
taskStatus: '',
updateUrl: TEST_HOST,
};
export const publishedIncidentUrl = 'https://status.com/';
export const zoomMeetingUrl = 'https://gitlab.zoom.us/j/95919234811';
export const appProps = {
canUpdate: true,
canDestroy: true,
endpoint: '/gitlab-org/gitlab-shell/-/issues/9/realtime_changes',
updateEndpoint: TEST_HOST,
issuableRef: '#1',
issuableStatus: 'opened',
initialTitleHtml: '',
initialTitleText: '',
initialDescriptionHtml: 'test',
initialDescriptionText: 'test',
lockVersion: 1,
markdownPreviewPath: '/',
markdownDocsPath: '/',
projectNamespace: '/',
projectPath: '/',
issuableTemplateNamesPath: '/issuable-templates-path',
zoomMeetingUrl,
publishedIncidentUrl,
};
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Metrics::Dashboard::Importer do
include MetricsDashboardHelpers
let_it_be(:dashboard_path) { '.gitlab/dashboards/sample_dashboard.yml' }
let_it_be(:project) { create(:project) }
before do
allow(subject).to receive(:dashboard_hash).and_return(dashboard_hash)
end
subject { described_class.new(dashboard_path, project) }
describe '.execute' do
context 'valid dashboard hash' do
let(:dashboard_hash) { load_sample_dashboard }
it 'imports metrics to database' do
expect { subject.execute }
.to change { PrometheusMetric.count }.from(0).to(3)
end
end
context 'invalid dashboard hash' do
let(:dashboard_hash) { {} }
it 'returns false' do
expect(subject.execute).to be(false)
end
end
end
describe '.execute!' do
context 'valid dashboard hash' do
let(:dashboard_hash) { load_sample_dashboard }
it 'imports metrics to database' do
expect { subject.execute }
.to change { PrometheusMetric.count }.from(0).to(3)
end
end
context 'invalid dashboard hash' do
let(:dashboard_hash) { {} }
it 'raises error' do
expect { subject.execute! }.to raise_error(Gitlab::Metrics::Dashboard::Validator::Errors::SchemaValidationError,
'root is missing required keys: dashboard, panel_groups')
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Metrics::Dashboard::Importers::PrometheusMetrics do
include MetricsDashboardHelpers
describe '#execute' do
let(:project) { create(:project) }
let(:dashboard_path) { 'path/to/dashboard.yml' }
subject { described_class.new(dashboard_hash, project: project, dashboard_path: dashboard_path) }
context 'valid dashboard' do
let(:dashboard_hash) { load_sample_dashboard }
context 'with all new metrics' do
it 'creates PrometheusMetrics' do
expect { subject.execute }.to change { PrometheusMetric.count }.by(3)
end
end
context 'with existing metrics' do
let!(:existing_metric) do
create(:prometheus_metric, {
project: project,
identifier: 'metric_b',
title: 'overwrite',
y_label: 'overwrite',
query: 'overwrite',
unit: 'overwrite',
legend: 'overwrite'
})
end
it 'updates existing PrometheusMetrics' do
described_class.new(dashboard_hash, project: project, dashboard_path: dashboard_path).execute
expect(existing_metric.reload.attributes.with_indifferent_access).to include({
title: 'Super Chart B',
y_label: 'y_label',
query: 'query',
unit: 'unit',
legend: 'Legend Label'
})
end
it 'creates new PrometheusMetrics' do
expect { subject.execute }.to change { PrometheusMetric.count }.by(2)
end
context 'with stale metrics' do
let!(:stale_metric) do
create(:prometheus_metric,
project: project,
identifier: 'stale_metric',
dashboard_path: dashboard_path,
group: 3
)
end
it 'deletes stale metrics' do
subject.execute
expect { stale_metric.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end
end
context 'invalid dashboard' do
let(:dashboard_hash) { {} }
it 'returns false' do
expect(subject.execute).to eq(false)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Metrics::Dashboard::Transformers::Yml::V1::PrometheusMetrics do
include MetricsDashboardHelpers
describe '#execute' do
subject { described_class.new(dashboard_hash) }
context 'valid dashboard' do
let_it_be(:dashboard_hash) do
{
panel_groups: [{
panels: [
{
title: 'Panel 1 title',
y_label: 'Panel 1 y_label',
metrics: [
{
query_range: 'Panel 1 metric 1 query_range',
unit: 'Panel 1 metric 1 unit',
label: 'Panel 1 metric 1 label',
id: 'Panel 1 metric 1 id'
},
{
query: 'Panel 1 metric 2 query',
unit: 'Panel 1 metric 2 unit',
label: 'Panel 1 metric 2 label',
id: 'Panel 1 metric 2 id'
}
]
},
{
title: 'Panel 2 title',
y_label: 'Panel 2 y_label',
metrics: [{
query_range: 'Panel 2 metric 1 query_range',
unit: 'Panel 2 metric 1 unit',
label: 'Panel 2 metric 1 label',
id: 'Panel 2 metric 1 id'
}]
}
]
}]
}
end
let(:expected_metrics) do
[
{
title: 'Panel 1 title',
y_label: 'Panel 1 y_label',
query: "Panel 1 metric 1 query_range",
unit: 'Panel 1 metric 1 unit',
legend: 'Panel 1 metric 1 label',
identifier: 'Panel 1 metric 1 id',
group: 3,
common: false
},
{
title: 'Panel 1 title',
y_label: 'Panel 1 y_label',
query: 'Panel 1 metric 2 query',
unit: 'Panel 1 metric 2 unit',
legend: 'Panel 1 metric 2 label',
identifier: 'Panel 1 metric 2 id',
group: 3,
common: false
},
{
title: 'Panel 2 title',
y_label: 'Panel 2 y_label',
query: 'Panel 2 metric 1 query_range',
unit: 'Panel 2 metric 1 unit',
legend: 'Panel 2 metric 1 label',
identifier: 'Panel 2 metric 1 id',
group: 3,
common: false
}
]
end
it 'returns collection of metrics with correct attributes' do
expect(subject.execute).to match_array(expected_metrics)
end
end
context 'invalid dashboard' do
let(:dashboard_hash) { {} }
it 'raises missing attribute error' do
expect { subject.execute }.to raise_error(
::Gitlab::Metrics::Dashboard::Transformers::Errors::MissingAttribute, "Missing attribute: 'panel_groups'"
)
end
end
end
end
......@@ -673,6 +673,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:git][:version]).to eq(Gitlab::Git.version)
expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name)
expect(subject[:database][:version]).to eq(Gitlab::Database.version)
expect(subject[:mail][:smtp_server]).to eq(ActionMailer::Base.smtp_settings[:address])
expect(subject[:gitaly][:version]).to be_present
expect(subject[:gitaly][:servers]).to be >= 1
expect(subject[:gitaly][:clusters]).to be >= 0
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200831065705_ensure_target_project_id_is_filled.rb')
RSpec.describe EnsureTargetProjectIdIsFilled, schema: 20200827085101 do
let_it_be(:namespaces) { table(:namespaces) }
let_it_be(:projects) { table(:projects) }
let_it_be(:merge_requests) { table(:merge_requests) }
let_it_be(:metrics) { table(:merge_request_metrics) }
let!(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace') }
let!(:project_1) { projects.create!(namespace_id: namespace.id) }
let!(:project_2) { projects.create!(namespace_id: namespace.id) }
let!(:merge_request_to_migrate_1) { merge_requests.create!(source_branch: 'a', target_branch: 'b', target_project_id: project_1.id) }
let!(:merge_request_to_migrate_2) { merge_requests.create!(source_branch: 'c', target_branch: 'd', target_project_id: project_2.id) }
let!(:merge_request_not_to_migrate) { merge_requests.create!(source_branch: 'e', target_branch: 'f', target_project_id: project_1.id) }
let!(:metrics_1) { metrics.create!(merge_request_id: merge_request_to_migrate_1.id) }
let!(:metrics_2) { metrics.create!(merge_request_id: merge_request_to_migrate_2.id) }
let!(:metrics_3) { metrics.create!(merge_request_id: merge_request_not_to_migrate.id, target_project_id: project_1.id) }
it 'migrates missing target_project_ids' do
migrate!
expect(metrics_1.reload.target_project_id).to eq(project_1.id)
expect(metrics_2.reload.target_project_id).to eq(project_2.id)
expect(metrics_3.reload.target_project_id).to eq(project_1.id)
end
end
......@@ -9,17 +9,6 @@ RSpec.describe MergeRequest::Metrics do
it { is_expected.to belong_to(:merged_by).class_name('User') }
end
it 'sets `target_project_id` before save' do
merge_request = create(:merge_request)
metrics = merge_request.metrics
metrics.update_column(:target_project_id, nil)
metrics.save!
expect(metrics.target_project_id).to eq(merge_request.target_project_id)
end
describe 'scopes' do
let_it_be(:metrics_1) { create(:merge_request).metrics.tap { |m| m.update!(merged_at: 10.days.ago) } }
let_it_be(:metrics_2) { create(:merge_request).metrics.tap { |m| m.update!(merged_at: 5.days.ago) } }
......
......@@ -304,18 +304,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
expect(merge_request.target_project_id).to eq(project.id)
expect(merge_request.target_project_id).to eq(merge_request.metrics.target_project_id)
end
context 'when metrics record already exists with NULL target_project_id' do
before do
merge_request.metrics.update_column(:target_project_id, nil)
end
it 'returns the metrics record' do
metrics_record = merge_request.ensure_metrics
expect(metrics_record).to be_persisted
end
end
end
end
......
......@@ -160,7 +160,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(raw_repo.empty?).to be(false)
end
end
end # backup_restore task
end
# backup_restore task
describe 'backup' do
before do
......@@ -391,7 +392,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout
end
end
end # backup_create task
end
# backup_create task
describe "Skipping items" do
before do
......@@ -486,4 +488,5 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(backup_tar).to match(/\d+_\d{4}_\d{2}_\d{2}_\d+\.\d+\.\d+.*_gitlab_backup.tar$/)
end
end
end # gitlab:app namespace
end
# gitlab:app namespace
......@@ -2085,13 +2085,12 @@ axios-mock-adapter@^1.15.0:
dependencies:
deep-equal "^1.0.1"
axios@^0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
axios@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
dependencies:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
follow-redirects "^1.10.0"
babel-eslint@^10.0.3:
version "10.0.3"
......@@ -5139,13 +5138,18 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@1.5.10, follow-redirects@^1.0.0:
follow-redirects@^1.0.0:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
debug "=3.1.0"
follow-redirects@^1.10.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
font-awesome@4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
......@@ -6194,7 +6198,7 @@ is-buffer@^1.1.5, is-buffer@~1.1.1:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-buffer@^2.0.0, is-buffer@^2.0.2:
is-buffer@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册