提交 0ec841b7 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 82f5f248
......@@ -22,17 +22,17 @@ rules:
- allow:
- __
- _links
# Disabled for now, to make the airbnb-base 12.1.0 -> 13.1.0 update smoother
no-else-return:
- error
- allowElseIf: true
import/no-unresolved:
- error
- ignore:
# https://gitlab.com/gitlab-org/gitlab/issues/38226
- '^ee_component/'
import/no-useless-path-segments: off
import/order: off
# Disabled for now, to make the airbnb-base 12.1.0 -> 13.1.0 update smoother
no-else-return:
- error
- allowElseIf: true
import/no-useless-path-segments: off
lines-between-class-members: off
# Disabled for now, to make the plugin-vue 4.5 -> 5.0 update smoother
vue/no-confusing-v-for-v-if: error
......
/* eslint-disable func-names, no-else-return, consistent-return, one-var, no-return-assign */
/* eslint-disable func-names, consistent-return, one-var, no-return-assign */
import $ from 'jquery';
......@@ -201,9 +201,8 @@ export default class ImageFile {
if (domImg) {
if (domImg.complete) {
return callback.call(this, domImg.naturalWidth, domImg.naturalHeight);
} else {
return img.on('load', () => callback.call(this, domImg.naturalWidth, domImg.naturalHeight));
}
return img.on('load', () => callback.call(this, domImg.naturalWidth, domImg.naturalHeight));
}
}
}
/* eslint-disable func-names, no-else-return */
/* eslint-disable func-names */
import $ from 'jquery';
import { __ } from './locale';
......@@ -52,9 +52,8 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
return $('<li />')
.addClass('dropdown-header')
.text(ref.header);
} else {
return $('<li />').append(link);
}
return $('<li />').append(link);
},
id(obj, $el) {
return $el.attr('data-ref');
......
/* eslint-disable no-else-return, no-lonely-if */
/* global CommentsStore */
import $ from 'jquery';
......@@ -22,27 +21,19 @@ const CommentAndResolveBtn = Vue.extend({
showButton() {
if (this.discussion) {
return this.discussion.isResolvable();
} else {
return false;
}
return false;
},
isDiscussionResolved() {
return this.discussion.isResolved();
},
buttonText() {
if (this.isDiscussionResolved) {
if (this.textareaIsEmpty) {
return __('Unresolve thread');
} else {
return __('Comment & unresolve thread');
}
} else {
if (this.textareaIsEmpty) {
return __('Resolve thread');
} else {
return __('Comment & resolve thread');
}
if (this.textareaIsEmpty) {
return this.isDiscussionResolved ? __('Unresolve thread') : __('Resolve thread');
}
return this.isDiscussionResolved
? __('Comment & unresolve thread')
: __('Comment & resolve thread');
},
},
created() {
......
/* eslint-disable func-names, no-else-return, guard-for-in, no-restricted-syntax, no-lonely-if, no-continue */
/* eslint-disable func-names, guard-for-in, no-restricted-syntax, no-lonely-if, no-continue */
/* global CommentsStore */
import $ from 'jquery';
......@@ -25,9 +25,8 @@ const JumpToDiscussion = Vue.extend({
buttonText() {
if (this.discussionId) {
return __('Jump to next unresolved thread');
} else {
return __('Jump to first unresolved thread');
}
return __('Jump to first unresolved thread');
},
allResolved() {
return this.unresolvedDiscussionCount === 0;
......@@ -36,12 +35,10 @@ const JumpToDiscussion = Vue.extend({
if (this.discussionId) {
if (this.unresolvedDiscussionCount > 1) {
return true;
} else {
return this.discussionId !== this.lastResolvedId;
}
} else {
return this.unresolvedDiscussionCount >= 1;
return this.discussionId !== this.lastResolvedId;
}
return this.unresolvedDiscussionCount >= 1;
},
lastResolvedId() {
let lastId;
......
/* eslint-disable no-useless-return, func-names, no-underscore-dangle, no-new, consistent-return, no-shadow, no-param-reassign, no-lonely-if, no-else-return, dot-notation, no-empty */
/* eslint-disable no-useless-return, func-names, no-underscore-dangle, no-new, consistent-return, no-shadow, no-param-reassign, no-lonely-if, dot-notation, no-empty */
/* global Issuable */
/* global ListLabel */
......@@ -311,9 +311,8 @@ export default class LabelsSelect {
firstLabel: selectedLabels[0],
labelCount: selectedLabels.length - 1,
});
} else {
return defaultLabel;
}
return defaultLabel;
},
fieldName: $dropdown.data('fieldName'),
id(label) {
......@@ -325,9 +324,8 @@ export default class LabelsSelect {
if ($dropdown.hasClass('js-filter-submit') && label.isAny == null) {
return label.title;
} else {
return label.id;
}
return label.id;
},
hidden() {
const page = $('body').attr('data-page');
......
/* eslint-disable func-names, no-param-reassign, operator-assignment, no-else-return, consistent-return */
/* eslint-disable func-names, no-param-reassign, operator-assignment, consistent-return */
import $ from 'jquery';
import { insertText } from '~/lib/utils/common_utils';
......@@ -217,9 +217,8 @@ export function insertMarkdownText({
}
if (val.indexOf(tag) === 0) {
return String(val.replace(tag, ''));
} else {
return String(tag) + val;
}
return String(tag) + val;
})
.join('\n');
}
......
/* eslint-disable func-names, no-underscore-dangle, no-param-reassign, consistent-return, no-else-return */
/* eslint-disable func-names, no-underscore-dangle, no-param-reassign, consistent-return */
import $ from 'jquery';
......@@ -128,9 +128,8 @@ LineHighlighter.prototype.hashToRange = function(hash) {
const first = parseInt(matches[1], 10);
const last = matches[2] ? parseInt(matches[2], 10) : null;
return [first, last];
} else {
return [null, null];
}
return [null, null];
};
// Highlight a single line
......@@ -153,9 +152,8 @@ LineHighlighter.prototype.highlightRange = function(range) {
}
return results;
} else {
return this.highlightLine(range[0]);
}
return this.highlightLine(range[0]);
};
// Set the URL hash string
......
/* eslint-disable one-var, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow */
/* eslint-disable one-var, no-self-compare, consistent-return, no-param-reassign, no-shadow */
/* global Issuable */
/* global ListMilestone */
......@@ -123,9 +123,8 @@ export default class MilestoneSelect {
toggleLabel: (selected, el) => {
if (selected && 'id' in selected && $(el).hasClass('is-active')) {
return selected.title;
} else {
return defaultLabel;
}
return defaultLabel;
},
defaultLabel,
fieldName: $dropdown.data('fieldName'),
......@@ -133,9 +132,8 @@ export default class MilestoneSelect {
id: milestone => {
if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) {
return milestone.name;
} else {
return milestone.id;
}
return milestone.id;
},
hidden: () => {
$selectBox.hide();
......@@ -244,13 +242,12 @@ export default class MilestoneSelect {
)
.find('span')
.text(data.milestone.title);
} else {
$value.html(milestoneLinkNoneTemplate);
return $sidebarCollapsedValue
.attr('data-original-title', __('Milestone'))
.find('span')
.text(__('None'));
}
$value.html(milestoneLinkNoneTemplate);
return $sidebarCollapsedValue
.attr('data-original-title', __('Milestone'))
.find('span')
.text(__('None'));
})
.catch(() => {
// eslint-disable-next-line no-jquery/no-fade
......
/* eslint-disable no-else-return */
import $ from 'jquery';
import '~/gl_dropdown';
import Api from './api';
......@@ -23,9 +21,8 @@ export default class NamespaceSelect {
toggleLabel(selected) {
if (selected.id == null) {
return selected.text;
} else {
return `${selected.kind}: ${selected.full_path}`;
}
return `${selected.kind}: ${selected.full_path}`;
},
data(term, dataCallback) {
return Api.namespaces(term, namespaces => {
......@@ -43,9 +40,8 @@ export default class NamespaceSelect {
text(namespace) {
if (namespace.id == null) {
return namespace.text;
} else {
return `${namespace.kind}: ${namespace.full_path}`;
}
return `${namespace.kind}: ${namespace.full_path}`;
},
renderRow: this.renderRow,
clicked(options) {
......
/* eslint-disable func-names, consistent-return, no-return-assign, no-else-return, @gitlab/require-i18n-strings */
/* eslint-disable func-names, consistent-return, no-return-assign, @gitlab/require-i18n-strings */
import $ from 'jquery';
import RefSelectDropdown from './ref_select_dropdown';
......@@ -76,9 +76,8 @@ export default class NewBranchForm {
const matched = this.name.val().match(restriction.pattern);
if (matched) {
return errors.concat(formatter(matched.reduce(unique, []), restriction));
} else {
return errors;
}
return errors;
};
const errors = this.restrictions.reduce(validator, []);
if (errors.length > 0) {
......
/* eslint-disable no-restricted-properties, babel/camelcase,
no-unused-expressions, default-case,
consistent-return, no-alert, no-param-reassign, no-else-return,
consistent-return, no-alert, no-param-reassign,
no-shadow, no-useless-escape,
class-methods-use-this */
......@@ -1123,10 +1123,9 @@ export default class Notes {
if (row.is('.js-temp-notes-holder')) {
// remove temporary row for diff lines
return row.remove();
} else {
// only remove the form
return form.remove();
}
// only remove the form
return form.remove();
}
cancelDiscussionForm(e) {
......
/* eslint-disable func-names, no-else-return */
/* eslint-disable func-names */
import $ from 'jquery';
import Api from './api';
......@@ -74,18 +74,17 @@ const projectSelect = () => {
},
projectsCallback,
);
} else {
return Api.projects(
query.term,
{
order_by: this.orderBy,
with_issues_enabled: this.withIssuesEnabled,
with_merge_requests_enabled: this.withMergeRequestsEnabled,
membership: !this.allProjects,
},
projectsCallback,
);
}
return Api.projects(
query.term,
{
order_by: this.orderBy,
with_issues_enabled: this.withIssuesEnabled,
with_merge_requests_enabled: this.withMergeRequestsEnabled,
membership: !this.allProjects,
},
projectsCallback,
);
},
id(project) {
if (simpleFilter) return project.id;
......
/* eslint-disable consistent-return, no-else-return */
/* eslint-disable consistent-return */
import $ from 'jquery';
......@@ -16,11 +16,10 @@ export default function syntaxHighlight(el) {
if ($(el).hasClass('js-syntax-highlight')) {
// Given the element itself, apply highlighting
return $(el).addClass(gon.user_color_scheme);
} else {
// Given a parent element, recurse to any of its applicable children
const $children = $(el).find('.js-syntax-highlight');
if ($children.length) {
return syntaxHighlight($children);
}
}
// Given a parent element, recurse to any of its applicable children
const $children = $(el).find('.js-syntax-highlight');
if ($children.length) {
return syntaxHighlight($children);
}
}
/* eslint-disable func-names, consistent-return, one-var, no-else-return, class-methods-use-this */
/* eslint-disable func-names, consistent-return, one-var, class-methods-use-this */
import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility';
......@@ -15,9 +15,8 @@ export default class TreeView {
if (e.metaKey || e.which === 2) {
e.preventDefault();
return window.open(path, '_blank');
} else {
return visitUrl(path);
}
return visitUrl(path);
}
});
// Show the "Loading commit data" for only the first element
......
/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-else-return, no-self-compare, no-unused-expressions, yoda, prefer-spread, babel/camelcase, no-param-reassign */
/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-self-compare, no-unused-expressions, yoda, prefer-spread, babel/camelcase, no-param-reassign */
/* global Issuable */
/* global emitSidebarEvent */
......@@ -148,12 +148,11 @@ function UsersSelect(currentUser, els, options = {}) {
name: selectedUser.name,
length: otherSelected.length,
});
} else {
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
name: firstUser.name,
length: selectedUsers.length - 1,
});
}
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
name: firstUser.name,
length: selectedUsers.length - 1,
});
};
$('.assign-to-me-link').on('click', e => {
......@@ -375,13 +374,11 @@ function UsersSelect(currentUser, els, options = {}) {
$dropdown.find('.dropdown-toggle-text').removeClass('is-default');
if (selected.text) {
return selected.text;
} else {
return selected.name;
}
} else {
$dropdown.find('.dropdown-toggle-text').addClass('is-default');
return defaultLabel;
return selected.name;
}
$dropdown.find('.dropdown-toggle-text').addClass('is-default');
return defaultLabel;
},
defaultLabel,
hidden() {
......
# frozen_string_literal: true
module Metrics
class UsersStarredDashboard < ApplicationRecord
self.table_name = 'metrics_users_starred_dashboards'
belongs_to :user, inverse_of: :metrics_users_starred_dashboards
belongs_to :project, inverse_of: :metrics_users_starred_dashboards
validates :user_id, presence: true
validates :project_id, presence: true
validates :dashboard_path, presence: true, length: { maximum: 255 }
validates :dashboard_path, uniqueness: { scope: %i[user_id project_id] }
end
end
......@@ -257,6 +257,7 @@ class Project < ApplicationRecord
has_many :prometheus_alerts, inverse_of: :project
has_many :prometheus_alert_events, inverse_of: :project
has_many :self_managed_prometheus_alert_events, inverse_of: :project
has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :project
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
......
......@@ -167,6 +167,8 @@ class User < ApplicationRecord
has_many :term_agreements
belongs_to :accepted_term, class_name: 'ApplicationSetting::Term'
has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :user
has_one :status, class_name: 'UserStatus'
has_one :user_preference
has_one :user_detail
......
......@@ -1294,7 +1294,7 @@
- :name: reactive_caching
:feature_category: :not_owned
:has_external_dependencies:
:urgency: :high
:urgency: :low
:resource_boundary: :cpu
:weight: 1
:idempotent:
......
......@@ -3,6 +3,6 @@
class ReactiveCachingWorker # rubocop:disable Scalability/IdempotentWorker
include ReactiveCacheableWorker
urgency :high
urgency :low
worker_resource_boundary :cpu
end
---
title: Add database relation to preserve users starred
metrics dashboard information.
merge_request: 29912
author:
type: added
# frozen_string_literal: true
class CreateMetricsUsersStarredDashboard < ActiveRecord::Migration[6.0]
DOWNTIME = false
# limit added in following migration db/migrate/20200424101920_add_text_limit_to_metrics_users_starred_dashboards_dashboard_path.rb
# to allow this migration to be run inside the transaction
# rubocop: disable Migration/AddLimitToTextColumns
def up
create_table :metrics_users_starred_dashboards do |t|
t.timestamps_with_timezone
t.bigint :project_id, null: false
t.bigint :user_id, null: false
t.text :dashboard_path, null: false
t.index :project_id
t.index %i(user_id project_id dashboard_path), name: "idx_metrics_users_starred_dashboard_on_user_project_dashboard", unique: true
end
end
# rubocop: enable Migration/AddLimitToTextColumns
def down
drop_table :metrics_users_starred_dashboards
end
end
# frozen_string_literal: true
class AddForeignKeyFromUsersToMetricsUsersStarredDashboars < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :metrics_users_starred_dashboards, :users, column: :user_id, on_delete: :cascade
end
def down
with_lock_retries do # rubocop:disable Migration/WithLockRetriesWithoutDdlTransaction
remove_foreign_key_if_exists :metrics_users_starred_dashboards, column: :user_id
end
end
end
# frozen_string_literal: true
class AddForeignKeyFromProjectsToMetricsUsersStarredDashboars < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :metrics_users_starred_dashboards, :projects, column: :project_id, on_delete: :cascade
end
def down
with_lock_retries do # rubocop:disable Migration/WithLockRetriesWithoutDdlTransaction
remove_foreign_key_if_exists :metrics_users_starred_dashboards, column: :project_id
end
end
end
# frozen_string_literal: true
class AddTextLimitToMetricsUsersStarredDashboardsDashboardPath < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_text_limit :metrics_users_starred_dashboards, :dashboard_path, 255
end
def down
remove_text_limit :metrics_users_starred_dashboards, :dashboard_path
end
end
......@@ -4033,6 +4033,25 @@ CREATE SEQUENCE public.metrics_dashboard_annotations_id_seq
ALTER SEQUENCE public.metrics_dashboard_annotations_id_seq OWNED BY public.metrics_dashboard_annotations.id;
CREATE TABLE public.metrics_users_starred_dashboards (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
project_id bigint NOT NULL,
user_id bigint NOT NULL,
dashboard_path text NOT NULL,
CONSTRAINT check_79a84a0f57 CHECK ((char_length(dashboard_path) <= 255))
);
CREATE SEQUENCE public.metrics_users_starred_dashboards_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.metrics_users_starred_dashboards_id_seq OWNED BY public.metrics_users_starred_dashboards.id;
CREATE TABLE public.milestone_releases (
milestone_id bigint NOT NULL,
release_id bigint NOT NULL
......@@ -7517,6 +7536,8 @@ ALTER TABLE ONLY public.merge_trains ALTER COLUMN id SET DEFAULT nextval('public
ALTER TABLE ONLY public.metrics_dashboard_annotations ALTER COLUMN id SET DEFAULT nextval('public.metrics_dashboard_annotations_id_seq'::regclass);
ALTER TABLE ONLY public.metrics_users_starred_dashboards ALTER COLUMN id SET DEFAULT nextval('public.metrics_users_starred_dashboards_id_seq'::regclass);
ALTER TABLE ONLY public.milestones ALTER COLUMN id SET DEFAULT nextval('public.milestones_id_seq'::regclass);
ALTER TABLE ONLY public.namespace_statistics ALTER COLUMN id SET DEFAULT nextval('public.namespace_statistics_id_seq'::regclass);
......@@ -8327,6 +8348,9 @@ ALTER TABLE ONLY public.merge_trains
ALTER TABLE ONLY public.metrics_dashboard_annotations
ADD CONSTRAINT metrics_dashboard_annotations_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.metrics_users_starred_dashboards
ADD CONSTRAINT metrics_users_starred_dashboards_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.milestones
ADD CONSTRAINT milestones_pkey PRIMARY KEY (id);
......@@ -8842,6 +8866,8 @@ CREATE INDEX idx_merge_requests_on_state_id_and_merge_status ON public.merge_req
CREATE INDEX idx_merge_requests_on_target_project_id_and_iid_opened ON public.merge_requests USING btree (target_project_id, iid) WHERE (state_id = 1);
CREATE UNIQUE INDEX idx_metrics_users_starred_dashboard_on_user_project_dashboard ON public.metrics_users_starred_dashboards USING btree (user_id, project_id, dashboard_path);
CREATE INDEX idx_mr_cc_diff_files_on_mr_cc_id_and_sha ON public.merge_request_context_commit_diff_files USING btree (merge_request_context_commit_id, sha);
CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON public.packages_packages USING btree (project_id, name, version, package_type);
......@@ -9872,6 +9898,8 @@ CREATE INDEX index_metrics_dashboard_annotations_on_cluster_id_and_3_columns ON
CREATE INDEX index_metrics_dashboard_annotations_on_environment_id_and_3_col ON public.metrics_dashboard_annotations USING btree (environment_id, dashboard_path, starting_at, ending_at) WHERE (environment_id IS NOT NULL);
CREATE INDEX index_metrics_users_starred_dashboards_on_project_id ON public.metrics_users_starred_dashboards USING btree (project_id);
CREATE INDEX index_milestone_releases_on_release_id ON public.milestone_releases USING btree (release_id);
CREATE INDEX index_milestones_on_description_trigram ON public.milestones USING gin (description public.gin_trgm_ops);
......@@ -11217,6 +11245,9 @@ ALTER TABLE ONLY public.deployments
ALTER TABLE ONLY public.gitlab_subscriptions
ADD CONSTRAINT fk_bd0c4019c3 FOREIGN KEY (hosted_plan_id) REFERENCES public.plans(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.metrics_users_starred_dashboards
ADD CONSTRAINT fk_bd6ae32fac FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.snippets
ADD CONSTRAINT fk_be41fd4bb7 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
......@@ -11271,6 +11302,9 @@ ALTER TABLE ONLY public.geo_event_log
ALTER TABLE ONLY public.lists
ADD CONSTRAINT fk_d6cf4279f7 FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.metrics_users_starred_dashboards
ADD CONSTRAINT fk_d76a2b9a8c FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.system_note_metadata
ADD CONSTRAINT fk_d83a918cb1 FOREIGN KEY (note_id) REFERENCES public.notes(id) ON DELETE CASCADE;
......@@ -13578,6 +13612,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200420094444
20200420104303
20200420104323
20200420115948
20200420162730
20200420172113
20200420172752
......@@ -13591,8 +13626,11 @@ COPY "schema_migrations" (version) FROM STDIN;
20200423080334
20200423080607
20200423081409
20200423081441
20200423081519
20200423101529
20200424050250
20200424101920
20200427064130
\.
......@@ -50,7 +50,7 @@ GitLab is the first single application for software development, security,
and operations that enables [Concurrent DevOps](https://about.gitlab.com/concurrent-devops/),
making the software lifecycle faster and radically improving the speed of business.
GitLab provides solutions for [all the stages of the DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/):
GitLab provides solutions for [each of the stages of the DevOps lifecycle](https://about.gitlab.com/stages-devops-lifecycle/):
![DevOps Stages](img/devops-stages.png)
......@@ -65,7 +65,7 @@ The following sections provide links to documentation for each DevOps stage:
|:------------------------|:------------------------------------------------------------|
| [Manage](#manage) | Statistics and analytics features. |
| [Plan](#plan) | Project planning and management features. |
| [Create](#create) | Source code and data creation and management features. |
| [Create](#create) | Source code, data creation, and management features. |
| [Verify](#verify) | Testing, code quality, and continuous integration features. |
| [Package](#package) | Docker container registry. |
| [Release](#release) | Application release and delivery features. |
......@@ -285,7 +285,7 @@ The following documentation relates to the DevOps **Release** stage:
| [Canary Deployments](user/project/canary_deployments.md) **(PREMIUM)** | Employ a popular CI strategy where a small portion of the fleet is updated to the new version first. |
| [Deploy Boards](user/project/deploy_boards.md) **(PREMIUM)** | View the current health and status of each CI environment running on Kubernetes, displaying the status of the pods in the deployment. |
| [Environments and deployments](ci/environments.md) | With environments, you can control the continuous deployment of your software within GitLab. |
| [Environment-specific variables](ci/variables/README.md#limiting-environment-scopes-of-environment-variables) | Limit scope of variables to specific environments. |
| [Environment-specific variables](ci/variables/README.md#limiting-environment-scopes-of-environment-variables) | Limit the scope of variables to specific environments. |
| [GitLab CI/CD](ci/README.md) | Explore the features and capabilities of Continuous Deployment and Delivery with GitLab. |
| [GitLab Pages](user/project/pages/index.md) | Build, test, and deploy a static site directly from GitLab. |
| [Protected Runners](ci/runners/README.md#protected-runners) | Select Runners to only pick jobs for protected branches and tags. |
......@@ -300,7 +300,7 @@ The following documentation relates to the DevOps **Release** stage:
### Configure
Automate your entire workflow from build to deploy and monitoring with GitLab
Auto DevOps. Best practice templates get you started with minimal to zero
Auto DevOps. Best practice templates help get you started with minimal to zero
configuration. Then customize everything from buildpacks to CI/CD.
The following documentation relates to the DevOps **Configure** stage:
......
......@@ -4076,8 +4076,7 @@ type Group {
visibility: String
"""
Vulnerabilities reported on the projects in the group and its subgroups.
Available only when feature flag `first_class_vulnerabilities` is enabled
Vulnerabilities reported on the projects in the group and its subgroups
"""
vulnerabilities(
"""
......@@ -7403,7 +7402,7 @@ type Project {
visibility: String
"""
Vulnerabilities reported on the project. Available only when feature flag `first_class_vulnerabilities` is enabled
Vulnerabilities reported on the project
"""
vulnerabilities(
"""
......@@ -7448,8 +7447,7 @@ type Project {
): VulnerabilityConnection
"""
Counts for each severity of vulnerability of the project. Available only when
feature flag `first_class_vulnerabilities` is enabled
Counts for each severity of vulnerability of the project
"""
vulnerabilitySeveritiesCount: VulnerabilitySeveritiesCount
......
......@@ -11490,7 +11490,7 @@
},
{
"name": "vulnerabilities",
"description": "Vulnerabilities reported on the projects in the group and its subgroups. Available only when feature flag `first_class_vulnerabilities` is enabled",
"description": "Vulnerabilities reported on the projects in the group and its subgroups",
"args": [
{
"name": "projectId",
......@@ -21926,7 +21926,7 @@
},
{
"name": "vulnerabilities",
"description": "Vulnerabilities reported on the project. Available only when feature flag `first_class_vulnerabilities` is enabled",
"description": "Vulnerabilities reported on the project",
"args": [
{
"name": "projectId",
......@@ -22051,7 +22051,7 @@
},
{
"name": "vulnerabilitySeveritiesCount",
"description": "Counts for each severity of vulnerability of the project. Available only when feature flag `first_class_vulnerabilities` is enabled",
"description": "Counts for each severity of vulnerability of the project",
"args": [
],
......
......@@ -1071,7 +1071,7 @@ Information about pagination in a connection.
| `tagList` | String | List of project topics (not Git tags) |
| `userPermissions` | ProjectPermissions! | Permissions for the current user on the resource |
| `visibility` | String | Visibility of the project |
| `vulnerabilitySeveritiesCount` | VulnerabilitySeveritiesCount | Counts for each severity of vulnerability of the project. Available only when feature flag `first_class_vulnerabilities` is enabled |
| `vulnerabilitySeveritiesCount` | VulnerabilitySeveritiesCount | Counts for each severity of vulnerability of the project |
| `webUrl` | String | Web URL of the project |
| `wikiEnabled` | Boolean | Indicates if Wikis are enabled for the current user |
......
......@@ -381,11 +381,10 @@ other environments.
## Currently supported languages
Note that not all buildpacks support Auto Test yet, as it's a relatively new
enhancement. All of Heroku's [officially supported
languages](https://devcenter.heroku.com/articles/heroku-ci#supported-languages)
support buildpacks, and some third-party buildpacks as well (such as Go, Node, Java, PHP,
Python, Ruby, Gradle, Scala, and Elixir) all support Auto Test, but notably the
multi-buildpack does not.
enhancement. All of Heroku's
[officially supported languages](https://devcenter.heroku.com/articles/heroku-ci#supported-languages)
support Auto Test. The languages supported by Heroku's Herokuish buildpacks all
support Auto Test, but notably the multi-buildpack does not.
As of GitLab 10.0, the supported buildpacks are:
......@@ -438,28 +437,36 @@ spec:
## Troubleshooting
- Auto Build and Auto Test may fail to detect your language or framework with the
following error:
```plaintext
Step 5/11 : RUN /bin/herokuish buildpack build
---> Running in eb468cd46085
-----> Unable to select a buildpack
The command '/bin/sh -c /bin/herokuish buildpack build' returned a non-zero code: 1
```
The following are possible reasons:
- Your application may be missing the key files the buildpack is looking for. For
example, for Ruby applications you must have a `Gemfile` to be properly detected,
even though it's possible to write a Ruby app without a `Gemfile`.
- There may be no buildpack for your application. Try specifying a
[custom buildpack](customize.md#custom-buildpacks).
- Auto Test may fail because of a mismatch between testing frameworks. In this
case, you may need to customize your `.gitlab-ci.yml` with your test commands.
- Auto Deploy will fail if GitLab can't create a Kubernetes namespace and
service account for your project. For help debugging this issue, see
[Troubleshooting failed deployment jobs](../../user/project/clusters/index.md#troubleshooting).
### Unable to select a buildpack
Auto Build and Auto Test may fail to detect your language or framework with the
following error:
```plaintext
Step 5/11 : RUN /bin/herokuish buildpack build
---> Running in eb468cd46085
-----> Unable to select a buildpack
The command '/bin/sh -c /bin/herokuish buildpack build' returned a non-zero code: 1
```
The following are possible reasons:
- Your application may be missing the key files the buildpack is looking for.
Ruby applications require a `Gemfile` to be properly detected,
even though it's possible to write a Ruby app without a `Gemfile`.
- No buildpack may exist for your application. Try specifying a
[custom buildpack](customize.md#custom-buildpacks).
### Mismatch between testing frameworks
Auto Test may fail because of a mismatch between testing frameworks. In this
case, you may need to customize your `.gitlab-ci.yml` with your test commands.
### Failure to create a Kubernetes namespace
Auto Deploy will fail if GitLab can't create a Kubernetes namespace and
service account for your project. For help debugging this issue, see
[Troubleshooting failed deployment jobs](../../user/project/clusters/index.md#troubleshooting).
## Development guides
......
......@@ -50,7 +50,7 @@ create issues for the same project.
![Create issue from group-level issue tracker](img/create_issue_from_group_level_issue_tracker.png)
### New issue via Service Desk **(PREMIUM)**
### New issue via Service Desk **(STARTER)**
Enable [Service Desk](../service_desk.md) for your project and offer email support.
By doing so, when your customer sends a new email, a new issue can be created in
......
# Service Desk **(PREMIUM)**
# Service Desk **(Starter)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/149) in [GitLab Premium 9.1](https://about.gitlab.com/releases/2017/04/22/gitlab-9-1-released/#service-desk-eep).
......
......@@ -67,7 +67,7 @@ Some features depend on others:
- If you disable the **Issues** option, GitLab also removes the following
features:
- **Issue Boards**
- [**Service Desk**](#service-desk-premium) **(PREMIUM)**
- [**Service Desk**](#service-desk-starter) **(STARTER)**
NOTE: **Note:**
When the **Issues** option is disabled, you can still access **Milestones**
......@@ -106,7 +106,7 @@ Set up your project's merge request settings:
![project's merge request settings](img/merge_requests_settings.png)
### Service Desk **(PREMIUM)**
### Service Desk **(STARTER)**
Enable [Service Desk](../service_desk.md) for your project to offer customer support.
......
......@@ -16,11 +16,15 @@ module Gitlab
lease = Gitlab::ExclusiveLease.new(key, timeout: ttl)
retried = false
max_attempts = 1 + retries
until uuid = lease.try_obtain
# Keep trying until we obtain the lease. To prevent hammering Redis too
# much we'll wait for a bit.
sleep(sleep_sec)
attempt_number = max_attempts - retries
delay = sleep_sec.respond_to?(:call) ? sleep_sec.call(attempt_number) : sleep_sec
sleep(delay)
(retries -= 1) < 0 ? break : retried ||= true
end
......
......@@ -96,7 +96,8 @@ module Gitlab
class << self
def configuration_toml(gitaly_dir, storage_paths)
nodes = [{ storage: 'default', address: "unix:#{gitaly_dir}/gitaly.socket", primary: true, token: 'secret' }]
config = { socket_path: "#{gitaly_dir}/praefect.socket", virtual_storage_name: 'default', token: 'secret', node: nodes }
storages = [{ name: 'default', node: nodes }]
config = { socket_path: "#{gitaly_dir}/praefect.socket", virtual_storage: storages }
config[:token] = 'secret' if Rails.env.test?
TomlRB.dump(config)
......
# frozen_string_literal: true
FactoryBot.define do
factory :metrics_users_starred_dashboard, class: '::Metrics::UsersStarredDashboard' do
dashboard_path { "custom_dashboard.yml" }
user
project
end
end
......@@ -12,6 +12,8 @@ describe 'Project navbar' do
let_it_be(:project) { create(:project, :repository) }
before do
stub_licensed_features(service_desk: false)
project.add_maintainer(user)
sign_in(user)
end
......
/* eslint-disable no-else-return, dot-notation, no-return-assign, no-new, no-underscore-dangle */
/* eslint-disable dot-notation, no-return-assign, no-new, no-underscore-dangle */
import $ from 'jquery';
import LineHighlighter from '~/line_highlighter';
......@@ -8,10 +8,9 @@ describe('LineHighlighter', function() {
const clickLine = function(number, eventData = {}) {
if ($.isEmptyObject(eventData)) {
return $(`#L${number}`).click();
} else {
const e = $.Event('click', eventData);
return $(`#L${number}`).trigger(e);
}
const e = $.Event('click', eventData);
return $(`#L${number}`).trigger(e);
};
beforeEach(function() {
loadFixtures('static/line_highlighter.html');
......
......@@ -82,10 +82,22 @@ describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state do
end
context 'when sleep second is specified' do
let(:options) { { retries: 0, sleep_sec: 0.05.seconds } }
let(:options) { { retries: 1, sleep_sec: 0.05.seconds } }
it 'receives the specified argument' do
expect(class_instance).to receive(:sleep).with(0.05.seconds).once
expect(class_instance).to receive(:sleep).with(0.05.seconds).twice
expect { subject }.to raise_error('Failed to obtain a lock')
end
end
context 'when sleep second is specified as a lambda' do
let(:options) { { retries: 2, sleep_sec: ->(num) { 0.1 + num } } }
it 'receives the specified argument' do
expect(class_instance).to receive(:sleep).with(1.1.seconds).once
expect(class_instance).to receive(:sleep).with(2.1.seconds).once
expect(class_instance).to receive(:sleep).with(3.1.seconds).once
expect { subject }.to raise_error('Failed to obtain a lock')
end
......
......@@ -487,6 +487,7 @@ project:
- daily_report_results
- jira_imports
- compliance_framework_setting
- metrics_users_starred_dashboards
- alert_management_alerts
award_emoji:
- awardable
......
# frozen_string_literal: true
require 'spec_helper'
describe Metrics::UsersStarredDashboard do
describe 'associations' do
it { is_expected.to belong_to(:project).inverse_of(:metrics_users_starred_dashboards) }
it { is_expected.to belong_to(:user).inverse_of(:metrics_users_starred_dashboards) }
end
describe 'validation' do
subject { build(:metrics_users_starred_dashboard) }
it { is_expected.to validate_presence_of(:user_id) }
it { is_expected.to validate_presence_of(:project_id) }
it { is_expected.to validate_presence_of(:dashboard_path) }
it { is_expected.to validate_length_of(:dashboard_path).is_at_most(255) }
it { is_expected.to validate_uniqueness_of(:dashboard_path).scoped_to(%i[user_id project_id]) }
end
end
......@@ -113,6 +113,7 @@ describe Project do
it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:alert_management_alerts) }
it { is_expected.to have_many(:jira_imports) }
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:project) }
it_behaves_like 'model with repository' do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
......
......@@ -54,6 +54,7 @@ describe User, :do_not_mock_admin_mode do
it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') }
it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') }
it { is_expected.to have_many(:releases).dependent(:nullify) }
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:user) }
describe "#bio" do
it 'syncs bio with `user_details.bio` on create' do
......
# frozen_string_literal: true
module ConcurrentHelpers
Cancelled = Class.new(StandardError)
# To test for contention, we may need to run some actions in parallel. This
# helper takes an array of blocks and schedules them all on different threads
# in a fixed-size thread pool.
#
# @param [Array[Proc]] blocks
# @param [Integer] task_wait_time: time to wait for each task (upper bound on
# reasonable task execution time)
# @param [Integer] max_concurrency: maximum number of tasks to run at once
#
def run_parallel(blocks, task_wait_time: 20.seconds, max_concurrency: Concurrent.processor_count - 1)
thread_pool = Concurrent::FixedThreadPool.new(
[2, max_concurrency].max, { max_queue: blocks.size }
)
opts = { executor: thread_pool }
error = Concurrent::MVar.new
blocks.map { |block| Concurrent::Future.execute(opts, &block) }.each do |future|
future.wait(task_wait_time)
if future.complete?
error.put(future.reason) if future.reason && error.empty?
else
future.cancel
error.put(Cancelled.new) if error.empty?
end
end
raise error.take if error.full?
ensure
thread_pool.shutdown
thread_pool.wait_for_termination(10)
thread_pool.kill if thread_pool.running?
end
end
# frozen_string_literal: true
class RenameableUpload < SimpleDelegator
attr_accessor :original_filename
# Get a fixture file with a new unique name, and the same extension
def self.unique_file(name)
upload = new(fixture_file_upload("spec/fixtures/#{name}"))
ext = File.extname(name)
new_name = File.basename(FactoryBot.generate(:filename), '.*')
upload.original_filename = new_name + ext
upload
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册