Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a1ed241c82
commit
89f3fa0b96
|
@ -111,5 +111,5 @@ Use the following resources to find the appropriate labels:
|
|||
- https://about.gitlab.com/handbook/product/categories/features/
|
||||
-->
|
||||
/label ~devops:: ~group: ~Category:
|
||||
|
||||
/label ~"GitLab Core"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
/label ~feature
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
|
||||
/label ~"feature" ~"group::" ~"section::" ~"Category::" ~"GitLab Core"/~"GitLab Starter"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
/label ~"feature" ~"group::" ~"section::" ~"Category::" ~"GitLab Core"/~"GitLab Premium"/~"GitLab Ultimate"
|
||||
|
||||
|
||||
<!--- Use the following resources to find the appropriate labels:
|
||||
|
|
|
@ -1 +1 @@
|
|||
9c2da9436f6a41a244a30deef6f48798f877e909
|
||||
2c7c204731f6e4f1c8cdb3d8a705caf7acf6689d
|
||||
|
|
4
Gemfile
4
Gemfile
|
@ -15,7 +15,7 @@ gem 'default_value_for', '~> 3.4.0'
|
|||
# Supported DBs
|
||||
gem 'pg', '~> 1.1'
|
||||
|
||||
gem 'rugged', '~> 0.28'
|
||||
gem 'rugged', '~> 1.0.1'
|
||||
gem 'grape-path-helpers', '~> 1.6.1'
|
||||
|
||||
gem 'faraday', '~> 1.0'
|
||||
|
@ -266,7 +266,7 @@ gem 'babosa', '~> 1.0.2'
|
|||
gem 'loofah', '~> 2.2'
|
||||
|
||||
# Working with license
|
||||
gem 'licensee', '~> 8.9'
|
||||
gem 'licensee', '~> 9.14.1'
|
||||
|
||||
# Detect and convert string character encoding
|
||||
gem 'charlock_holmes', '~> 0.7.7'
|
||||
|
|
19
Gemfile.lock
19
Gemfile.lock
|
@ -267,6 +267,7 @@ GEM
|
|||
doorkeeper-openid_connect (1.7.5)
|
||||
doorkeeper (>= 5.2, < 5.5)
|
||||
json-jwt (>= 1.11.0)
|
||||
dotenv (2.7.6)
|
||||
dry-configurable (0.12.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.5, >= 0.5.0)
|
||||
|
@ -674,8 +675,12 @@ GEM
|
|||
toml (= 0.2.0)
|
||||
with_env (= 1.1.0)
|
||||
xml-simple
|
||||
licensee (8.9.2)
|
||||
rugged (~> 0.24)
|
||||
licensee (9.14.1)
|
||||
dotenv (~> 2.0)
|
||||
octokit (~> 4.17)
|
||||
reverse_markdown (~> 1.0)
|
||||
rugged (>= 0.24, < 2.0)
|
||||
thor (>= 0.19, < 2.0)
|
||||
listen (3.2.1)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
|
@ -756,7 +761,7 @@ GEM
|
|||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
octokit (4.15.0)
|
||||
octokit (4.20.0)
|
||||
faraday (>= 0.9)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
oj (3.10.6)
|
||||
|
@ -990,6 +995,8 @@ GEM
|
|||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
retriable (3.1.2)
|
||||
reverse_markdown (1.4.0)
|
||||
nokogiri
|
||||
rexml (3.2.4)
|
||||
rinku (2.0.0)
|
||||
rotp (2.1.2)
|
||||
|
@ -1072,7 +1079,7 @@ GEM
|
|||
rubyntlm (0.6.2)
|
||||
rubypants (0.2.0)
|
||||
rubyzip (2.0.0)
|
||||
rugged (0.28.4.1)
|
||||
rugged (1.0.1)
|
||||
safe_yaml (1.0.4)
|
||||
safety_net_attestation (0.4.0)
|
||||
jwt (~> 2.0)
|
||||
|
@ -1417,7 +1424,7 @@ DEPENDENCIES
|
|||
lefthook (~> 0.7)
|
||||
letter_opener_web (~> 1.3.4)
|
||||
license_finder (~> 6.0)
|
||||
licensee (~> 8.9)
|
||||
licensee (~> 9.14.1)
|
||||
lockbox (~> 0.3.3)
|
||||
lograge (~> 0.5)
|
||||
loofah (~> 2.2)
|
||||
|
@ -1501,7 +1508,7 @@ DEPENDENCIES
|
|||
ruby-progressbar (~> 1.10)
|
||||
ruby_parser (~> 3.15)
|
||||
rubyzip (~> 2.0.0)
|
||||
rugged (~> 0.28)
|
||||
rugged (~> 1.0.1)
|
||||
sanitize (~> 5.2.1)
|
||||
sassc-rails (~> 2.1.0)
|
||||
scss_lint (~> 0.59.0)
|
||||
|
|
|
@ -13,6 +13,9 @@ export const ERROR_INSTANCE_REQUIRED_FOR_EXTENSION = __(
|
|||
|
||||
export const EDITOR_READY_EVENT = 'editor-ready';
|
||||
|
||||
export const EDITOR_TYPE_CODE = 'vs.editor.ICodeEditor';
|
||||
export const EDITOR_TYPE_DIFF = 'vs.editor.IDiffEditor';
|
||||
|
||||
//
|
||||
// EXTENSIONS' CONSTANTS
|
||||
//
|
||||
|
|
|
@ -6,7 +6,12 @@ import { registerLanguages } from '~/ide/utils';
|
|||
import { joinPaths } from '~/lib/utils/url_utility';
|
||||
import { uuids } from '~/diffs/utils/uuids';
|
||||
import { clearDomElement } from './utils';
|
||||
import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX, EDITOR_READY_EVENT } from './constants';
|
||||
import {
|
||||
EDITOR_LITE_INSTANCE_ERROR_NO_EL,
|
||||
URI_PREFIX,
|
||||
EDITOR_READY_EVENT,
|
||||
EDITOR_TYPE_DIFF,
|
||||
} from './constants';
|
||||
|
||||
export default class EditorLite {
|
||||
constructor(options = {}) {
|
||||
|
@ -29,15 +34,12 @@ export default class EditorLite {
|
|||
monacoEditor.setTheme(theme ? themeName : DEFAULT_THEME);
|
||||
}
|
||||
|
||||
static updateModelLanguage(path, instance) {
|
||||
if (!instance) return;
|
||||
const model = instance.getModel();
|
||||
static getModelLanguage(path) {
|
||||
const ext = `.${path.split('.').pop()}`;
|
||||
const language = monacoLanguages
|
||||
.getLanguages()
|
||||
.find((lang) => lang.extensions.indexOf(ext) !== -1);
|
||||
const id = language ? language.id : 'plaintext';
|
||||
monacoEditor.setModelLanguage(model, id);
|
||||
return language ? language.id : 'plaintext';
|
||||
}
|
||||
|
||||
static pushToImportsArray(arr, toImport) {
|
||||
|
@ -102,17 +104,91 @@ export default class EditorLite {
|
|||
});
|
||||
}
|
||||
|
||||
static createEditorModel({ blobPath, blobContent, blobGlobalId, instance } = {}) {
|
||||
let model = null;
|
||||
static createEditorModel({
|
||||
blobPath,
|
||||
blobContent,
|
||||
blobOriginalContent,
|
||||
blobGlobalId,
|
||||
instance,
|
||||
isDiff,
|
||||
} = {}) {
|
||||
if (!instance) {
|
||||
return null;
|
||||
}
|
||||
const uriFilePath = joinPaths(URI_PREFIX, blobGlobalId, blobPath);
|
||||
const uri = Uri.file(uriFilePath);
|
||||
const existingModel = monacoEditor.getModel(uri);
|
||||
model = existingModel || monacoEditor.createModel(blobContent, undefined, uri);
|
||||
instance.setModel(model);
|
||||
return model;
|
||||
const model = existingModel || monacoEditor.createModel(blobContent, undefined, uri);
|
||||
if (!isDiff) {
|
||||
instance.setModel(model);
|
||||
return model;
|
||||
}
|
||||
const diffModel = {
|
||||
original: monacoEditor.createModel(
|
||||
blobOriginalContent,
|
||||
EditorLite.getModelLanguage(model.uri.path),
|
||||
),
|
||||
modified: model,
|
||||
};
|
||||
instance.setModel(diffModel);
|
||||
return diffModel;
|
||||
}
|
||||
|
||||
static convertMonacoToELInstance = (inst) => {
|
||||
const editorLiteInstanceAPI = {
|
||||
updateModelLanguage: (path) => {
|
||||
return EditorLite.instanceUpdateLanguage(inst, path);
|
||||
},
|
||||
use: (exts = []) => {
|
||||
return EditorLite.instanceApplyExtension(inst, exts);
|
||||
},
|
||||
};
|
||||
const handler = {
|
||||
get(target, prop, receiver) {
|
||||
if (Reflect.has(editorLiteInstanceAPI, prop)) {
|
||||
return editorLiteInstanceAPI[prop];
|
||||
}
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
};
|
||||
return new Proxy(inst, handler);
|
||||
};
|
||||
|
||||
static instanceUpdateLanguage(inst, path) {
|
||||
const lang = EditorLite.getModelLanguage(path);
|
||||
const model = inst.getModel();
|
||||
return monacoEditor.setModelLanguage(model, lang);
|
||||
}
|
||||
|
||||
static instanceApplyExtension(inst, exts = []) {
|
||||
const extensions = [].concat(exts);
|
||||
extensions.forEach((extension) => {
|
||||
EditorLite.mixIntoInstance(extension, inst);
|
||||
});
|
||||
return inst;
|
||||
}
|
||||
|
||||
static instanceRemoveFromRegistry(editor, instance) {
|
||||
const index = editor.instances.findIndex((inst) => inst === instance);
|
||||
editor.instances.splice(index, 1);
|
||||
}
|
||||
|
||||
static instanceDisposeModels(editor, instance, model) {
|
||||
const instanceModel = instance.getModel() || model;
|
||||
if (!instanceModel) {
|
||||
return;
|
||||
}
|
||||
if (instance.getEditorType() === EDITOR_TYPE_DIFF) {
|
||||
const { original, modified } = instanceModel;
|
||||
if (original) {
|
||||
original.dispose();
|
||||
}
|
||||
if (modified) {
|
||||
modified.dispose();
|
||||
}
|
||||
} else {
|
||||
instanceModel.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,26 +204,38 @@ export default class EditorLite {
|
|||
el = undefined,
|
||||
blobPath = '',
|
||||
blobContent = '',
|
||||
blobOriginalContent = '',
|
||||
blobGlobalId = uuids()[0],
|
||||
extensions = [],
|
||||
isDiff = false,
|
||||
...instanceOptions
|
||||
} = {}) {
|
||||
EditorLite.prepareInstance(el);
|
||||
|
||||
const instance = monacoEditor.create(el, {
|
||||
...this.options,
|
||||
...instanceOptions,
|
||||
});
|
||||
const createEditorFn = isDiff ? 'createDiffEditor' : 'create';
|
||||
const instance = EditorLite.convertMonacoToELInstance(
|
||||
monacoEditor[createEditorFn].call(this, el, {
|
||||
...this.options,
|
||||
...instanceOptions,
|
||||
}),
|
||||
);
|
||||
|
||||
const model = EditorLite.createEditorModel({ blobGlobalId, blobPath, blobContent, instance });
|
||||
let model;
|
||||
if (instanceOptions.model !== null) {
|
||||
model = EditorLite.createEditorModel({
|
||||
blobGlobalId,
|
||||
blobOriginalContent,
|
||||
blobPath,
|
||||
blobContent,
|
||||
instance,
|
||||
isDiff,
|
||||
});
|
||||
}
|
||||
|
||||
instance.onDidDispose(() => {
|
||||
const index = this.instances.findIndex((inst) => inst === instance);
|
||||
this.instances.splice(index, 1);
|
||||
model.dispose();
|
||||
EditorLite.instanceRemoveFromRegistry(this, instance);
|
||||
EditorLite.instanceDisposeModels(this, instance, model);
|
||||
});
|
||||
instance.updateModelLanguage = (path) => EditorLite.updateModelLanguage(path, instance);
|
||||
instance.use = (args) => this.use(args, instance);
|
||||
|
||||
EditorLite.manageDefaultExtensions(instance, el, extensions);
|
||||
|
||||
|
@ -155,23 +243,21 @@ export default class EditorLite {
|
|||
return instance;
|
||||
}
|
||||
|
||||
createDiffInstance(args) {
|
||||
return this.createInstance({
|
||||
...args,
|
||||
isDiff: true,
|
||||
});
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.instances.forEach((instance) => instance.dispose());
|
||||
}
|
||||
|
||||
use(exts = [], instance = null) {
|
||||
const extensions = Array.isArray(exts) ? exts : [exts];
|
||||
const initExtensions = (inst) => {
|
||||
extensions.forEach((extension) => {
|
||||
EditorLite.mixIntoInstance(extension, inst);
|
||||
});
|
||||
};
|
||||
if (instance) {
|
||||
initExtensions(instance);
|
||||
} else {
|
||||
this.instances.forEach((inst) => {
|
||||
initExtensions(inst);
|
||||
});
|
||||
}
|
||||
use(exts) {
|
||||
this.instances.forEach((inst) => {
|
||||
inst.use(exts);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ module OperationsHelper
|
|||
'prometheus_authorization_key' => @project.alerting_setting&.token,
|
||||
'prometheus_api_url' => prometheus_service.api_url,
|
||||
'prometheus_url' => notify_project_prometheus_alerts_url(@project, format: :json),
|
||||
'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'),
|
||||
'alerts_setup_url' => help_page_path('operations/incident_management/integrations.md', anchor: 'configuration'),
|
||||
'alerts_usage_url' => project_alert_management_index_path(@project),
|
||||
'disabled' => disabled.to_s,
|
||||
'project_path' => @project.full_path,
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Editor Lite: support for Diff Instance'
|
||||
merge_request: 51470
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update Rugged to v1.0.1
|
||||
merge_request: 53212
|
||||
author:
|
||||
type: changed
|
|
@ -310,7 +310,7 @@
|
|||
- dompurify
|
||||
- Apache-2.0
|
||||
- :who: Lukas Eipert
|
||||
:why: "https://github.com/cure53/DOMPurify/blob/main/LICENSE and https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31928#note_346604841"
|
||||
:why: https://github.com/cure53/DOMPurify/blob/main/LICENSE and https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31928#note_346604841
|
||||
:versions: []
|
||||
:when: 2020-08-13 13:42:46.508082000 Z
|
||||
- - :permit
|
||||
|
@ -325,3 +325,9 @@
|
|||
:why: Used to generate documentation. https://pypi.org/project/docutils/0.13.1/
|
||||
:versions: []
|
||||
:when: 2020-10-05 20:22:55.955189491 Z
|
||||
- - :permit
|
||||
- WTFPL
|
||||
- :who: Stan Hu
|
||||
:why: https://github.com/xijo/reverse_markdown/blob/master/LICENSE
|
||||
:versions: []
|
||||
:when: 2021-02-03 08:47:28.792907000 Z
|
||||
|
|
|
@ -149,6 +149,7 @@ exceptions:
|
|||
- TODO
|
||||
- TOML
|
||||
- TTL
|
||||
- UDP
|
||||
- UNIX
|
||||
- URI
|
||||
- URL
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
redirect_to: 'postgresql/external.md'
|
||||
---
|
||||
|
||||
# Configure GitLab using an external PostgreSQL service
|
||||
|
||||
This content has been moved to a [new location](postgresql/external.md).
|
|
@ -106,9 +106,10 @@ POST /projects/:id/badges
|
|||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `link_url` | string | yes | URL of the badge link |
|
||||
| `image_url` | string | yes | URL of the badge image |
|
||||
| `name` | string | no | Name of the badge |
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "link_url=https://gitlab.com/gitlab-org/gitlab-foss/commits/master&image_url=https://shields.io/my/badge1&position=0" "https://gitlab.example.com/api/v4/projects/:id/badges"
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "link_url=https://gitlab.com/gitlab-org/gitlab-foss/commits/master&image_url=https://shields.io/my/badge1&name=mybadge" "https://gitlab.example.com/api/v4/projects/:id/badges"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
@ -116,6 +117,7 @@ Example response:
|
|||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "mybadge",
|
||||
"link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
|
||||
"image_url": "https://shields.io/my/badge1",
|
||||
"rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
|
||||
|
@ -138,6 +140,7 @@ PUT /projects/:id/badges/:badge_id
|
|||
| `badge_id` | integer | yes | The badge ID |
|
||||
| `link_url` | string | no | URL of the badge link |
|
||||
| `image_url` | string | no | URL of the badge image |
|
||||
| `name` | string | no | Name of the badge |
|
||||
|
||||
```shell
|
||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/badges/:badge_id"
|
||||
|
@ -148,6 +151,7 @@ Example response:
|
|||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "mybadge",
|
||||
"link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
|
||||
"image_url": "https://shields.io/my/badge",
|
||||
"rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
|
||||
|
|
|
@ -56,7 +56,7 @@ POST projects/:id/access_tokens
|
|||
| Attribute | Type | required | Description |
|
||||
|-----------|---------|----------|---------------------|
|
||||
| `name` | String | yes | The name of the project access token |
|
||||
| `scopes` | Array[String] | yes | [List of scopes](../user/project/settings/project_access_tokens.md#limiting-scopes-of-a-project-access-token) |
|
||||
| `scopes` | Array\[String] | yes | [List of scopes](../user/project/settings/project_access_tokens.md#limiting-scopes-of-a-project-access-token) |
|
||||
| `expires_at` | Date | no | The token expires at midnight UTC on that date |
|
||||
|
||||
```shell
|
||||
|
|
|
@ -65,7 +65,7 @@ GET /users?active=true
|
|||
GET /users?blocked=true
|
||||
```
|
||||
|
||||
GitLab supports bot users such as the [alert bot](../operations/incident_management/alert_integrations.md)
|
||||
GitLab supports bot users such as the [alert bot](../operations/incident_management/integrations.md)
|
||||
or the [support bot](../user/project/service_desk.md#support-bot-user).
|
||||
To exclude these users from the users' list, you can use the parameter `exclude_internal=true`
|
||||
([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241144) in GitLab 13.4).
|
||||
|
|
|
@ -3,3 +3,6 @@ redirect_to: 'styleguide/index.md'
|
|||
---
|
||||
|
||||
This document was moved to [another location](styleguide/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2022-02-13>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/components/status/'
|
||||
---
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/components/dropdown/'
|
||||
---
|
|
@ -456,7 +456,7 @@ Cluster.
|
|||
|
||||
| Attribute | Type | Required | Description |
|
||||
|:----------|:-------|:---------|:------------|
|
||||
| `alert` | Hash | yes | Alerts detail. Same format as [3rd party alert](../operations/incident_management/alert_integrations.md#customize-the-alert-payload-outside-of-gitlab). |
|
||||
| `alert` | Hash | yes | Alerts detail. Same format as [3rd party alert](../operations/incident_management/integrations.md#customize-the-alert-payload-outside-of-gitlab). |
|
||||
|
||||
```plaintext
|
||||
POST internal/kubernetes/modules/cilium_alert
|
||||
|
|
|
@ -4,10 +4,5 @@ redirect_to: 'https://about.gitlab.com/handbook/product/product-intelligence-gui
|
|||
|
||||
This document was moved to [another location](https://about.gitlab.com/handbook/product/product-intelligence-guide/).
|
||||
|
||||
<!-- Needed by the Product Intelligence group
|
||||
|
||||
Since our new standard for redirects otherwise lies within the gitlab-docs repo,
|
||||
as long as we need a redirect to the handbook, we need to retain this file.
|
||||
-->
|
||||
<!-- This redirect file can be deleted after December 1, 2021. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/product-foundations/motion/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/motion/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/product-foundations/illustration/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/product-foundations/illustration/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/resources/design-resources/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/resources/design-resources/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: 'https://design.gitlab.com/'
|
||||
---
|
||||
|
||||
The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
redirect_to: 'documentation/index.md'
|
||||
---
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
redirect_to: installation.md#gitlab-directory-structure
|
||||
---
|
||||
|
||||
This page was moved to [another location](installation.md#gitlab-directory-structure).
|
|
@ -39,6 +39,11 @@ GitLab can be integrated with the following external services to enhance securit
|
|||
|
||||
GitLab also provides features to improve the security of your own application. For more details see [GitLab Secure](../user/application_security/index.md).
|
||||
|
||||
## Security partners
|
||||
|
||||
GitLab has integrated with several security partners. For more information, see
|
||||
[Security partners integration](security_partners/index.md).
|
||||
|
||||
## Continuous integration
|
||||
|
||||
GitLab can be integrated with the following external service for continuous integration:
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
stage: Protect
|
||||
group: Container Security
|
||||
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
|
||||
type: index
|
||||
---
|
||||
|
||||
# Security partner integrations
|
||||
|
||||
You can integrate GitLab with its security partners. This page has information on how do this with
|
||||
each security partner:
|
||||
|
||||
- [Anchore](https://docs.anchore.com/current/docs/using/integration/ci_cd/gitlab/)
|
|
@ -1,199 +1,8 @@
|
|||
---
|
||||
stage: Monitor
|
||||
group: Health
|
||||
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/#assignments
|
||||
redirect_to: 'integrations.md'
|
||||
---
|
||||
|
||||
# Alert integrations **(FREE)**
|
||||
This document was moved to [another location](integrations.md).
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
|
||||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/42640) to [GitLab Core](https://about.gitlab.com/pricing/) in 12.8.
|
||||
|
||||
GitLab can accept alerts from any source via a webhook receiver. This can be configured
|
||||
generically or, in GitLab versions 13.1 and greater, you can configure
|
||||
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
|
||||
to use this endpoint.
|
||||
|
||||
## Integrations list
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/245331) in [GitLab Core](https://about.gitlab.com/pricing/) 13.5.
|
||||
|
||||
With Maintainer or higher [permissions](../../user/permissions.md), you can view
|
||||
the list of configured alerts integrations by navigating to
|
||||
**Settings > Operations** in your project's sidebar menu, and expanding **Alerts** section.
|
||||
The list displays the integration name, type, and status (enabled or disabled):
|
||||
|
||||
![Current Integrations](img/integrations_list_v13_5.png)
|
||||
|
||||
## Configuration
|
||||
|
||||
GitLab can receive alerts via a HTTP endpoint that you configure,
|
||||
or the [Prometheus integration](#external-prometheus-integration).
|
||||
|
||||
### Single HTTP Endpoint **(FREE)**
|
||||
|
||||
Enabling the HTTP Endpoint in a GitLab projects activates it to
|
||||
receive alert payloads in JSON format. You can always
|
||||
[customize the payload](#customize-the-alert-payload-outside-of-gitlab) to your liking.
|
||||
|
||||
1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
|
||||
for a project.
|
||||
1. Navigate to **Settings > Operations** in your project.
|
||||
1. Expand the **Alerts** section, and in the **Integration** dropdown menu, select **Generic**.
|
||||
1. Toggle the **Active** alert setting to display the **URL** and **Authorization Key**
|
||||
for the webhook configuration.
|
||||
|
||||
### HTTP Endpoints **PREMIUM**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4442) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.6.
|
||||
|
||||
In [GitLab Premium](https://about.gitlab.com/pricing/), you can create multiple
|
||||
unique HTTP endpoints to receive alerts from any external source in JSON format,
|
||||
and you can [customize the payload](#customize-the-alert-payload-outside-of-gitlab).
|
||||
|
||||
1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
|
||||
for a project.
|
||||
1. Navigate to **Settings > Operations** in your project.
|
||||
1. Expand the **Alerts** section.
|
||||
1. For each endpoint you want to create:
|
||||
|
||||
1. In the **Integration** dropdown menu, select **HTTP Endpoint**.
|
||||
1. Name the integration.
|
||||
1. Toggle the **Active** alert setting to display the **URL** and **Authorization Key**
|
||||
for the webhook configuration. You must also input the URL and Authorization Key
|
||||
in your external service.
|
||||
1. _(Optional)_ To generate a test alert to test the new integration, enter a
|
||||
sample payload, then click **Save and test alert payload**. Valid JSON is required.
|
||||
1. Click **Save Integration**.
|
||||
|
||||
The new HTTP Endpoint displays in the [integrations list](#integrations-list).
|
||||
You can edit the integration by selecting the **{pencil}** pencil icon on the right
|
||||
side of the integrations list.
|
||||
|
||||
### External Prometheus integration
|
||||
|
||||
For GitLab versions 13.1 and greater, please read
|
||||
[External Prometheus Instances](../metrics/alerts.md#external-prometheus-instances)
|
||||
to configure alerts for this integration.
|
||||
|
||||
## Customize the alert payload outside of GitLab
|
||||
|
||||
For all integration types, you can customize the payload by sending the following
|
||||
parameters. All fields are optional. If the incoming alert does not contain a value for the `Title` field, a default value of `New: Incident` will be applied.
|
||||
|
||||
| Property | Type | Description |
|
||||
| ------------------------- | --------------- | ----------- |
|
||||
| `title` | String | The title of the incident. |
|
||||
| `description` | String | A high-level summary of the problem. |
|
||||
| `start_time` | DateTime | The time of the incident. If none is provided, a timestamp of the issue is used. |
|
||||
| `end_time` | DateTime | For existing alerts only. When provided, the alert is resolved and the associated incident is closed. |
|
||||
| `service` | String | The affected service. |
|
||||
| `monitoring_tool` | String | The name of the associated monitoring tool. |
|
||||
| `hosts` | String or Array | One or more hosts, as to where this incident occurred. |
|
||||
| `severity` | String | The severity of the alert. Must be one of `critical`, `high`, `medium`, `low`, `info`, `unknown`. Default is `critical`. |
|
||||
| `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. |
|
||||
| `gitlab_environment_name` | String | The name of the associated GitLab [environment](../../ci/environments/index.md). Required to [display alerts on a dashboard](../../user/operations_dashboard/index.md#adding-a-project-to-the-dashboard). |
|
||||
|
||||
You can also add custom fields to the alert's payload. The values of extra
|
||||
parameters aren't limited to primitive types (such as strings or numbers), but
|
||||
can be a nested JSON object. For example:
|
||||
|
||||
```json
|
||||
{ "foo": { "bar": { "baz": 42 } } }
|
||||
```
|
||||
|
||||
NOTE:
|
||||
Ensure your requests are smaller than the
|
||||
[payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads).
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request POST \
|
||||
--data '{"title": "Incident title"}' \
|
||||
--header "Authorization: Bearer <authorization_key>" \
|
||||
--header "Content-Type: application/json" \
|
||||
<url>
|
||||
```
|
||||
|
||||
The `<authorization_key>` and `<url>` values can be found when configuring an alert integration.
|
||||
|
||||
Example payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Incident title",
|
||||
"description": "Short description of the incident",
|
||||
"start_time": "2019-09-12T06:00:55Z",
|
||||
"service": "service affected",
|
||||
"monitoring_tool": "value",
|
||||
"hosts": "value",
|
||||
"severity": "high",
|
||||
"fingerprint": "d19381d4e8ebca87b55cda6e8eee7385",
|
||||
"foo": {
|
||||
"bar": {
|
||||
"baz": 42
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Triggering test alerts
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab Core in 13.2.
|
||||
|
||||
After a [project maintainer or owner](../../user/permissions.md)
|
||||
configures an integration, you can trigger a test
|
||||
alert to confirm your integration works properly.
|
||||
|
||||
1. Sign in as a user with Developer or greater [permissions](../../user/permissions.md).
|
||||
1. Navigate to **Settings > Operations** in your project.
|
||||
1. Click **Alerts endpoint** to expand the section.
|
||||
1. Enter a sample payload in **Alert test payload** (valid JSON is required).
|
||||
1. Click **Test alert payload**.
|
||||
|
||||
GitLab displays an error or success message, depending on the outcome of your test.
|
||||
|
||||
## Automatic grouping of identical alerts **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214557) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
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)
|
||||
and details pages.
|
||||
|
||||
If the existing alert is already `resolved`, GitLab creates a new alert instead.
|
||||
|
||||
![Alert Management List](img/alert_list_v13_1.png)
|
||||
|
||||
## Link to your Opsgenie Alerts
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
WARNING:
|
||||
We are building deeper integration with Opsgenie and other alerting tools through
|
||||
[HTTP endpoint integrations](#single-http-endpoint) so you can see alerts in
|
||||
the GitLab interface. As a result, the previous direct link to Opsgenie Alerts from
|
||||
the GitLab alerts list is deprecated in
|
||||
GitLab versions [13.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/273657).
|
||||
|
||||
You can monitor alerts using a GitLab integration with [Opsgenie](https://www.atlassian.com/software/opsgenie).
|
||||
|
||||
If you enable the Opsgenie integration, you can't have other GitLab alert
|
||||
services
|
||||
active at the same time.
|
||||
|
||||
To enable Opsgenie integration:
|
||||
|
||||
1. Sign in as a user with Maintainer or Owner [permissions](../../user/permissions.md).
|
||||
1. Navigate to **Operations > Alerts**.
|
||||
1. In the **Integrations** select box, select **Opsgenie**.
|
||||
1. Select the **Active** toggle.
|
||||
1. In the **API URL** field, enter the base URL for your Opsgenie integration,
|
||||
such as `https://app.opsgenie.com/alert/list`.
|
||||
1. Select **Save changes**.
|
||||
|
||||
After you enable the integration, navigate to the Alerts list page at
|
||||
**Operations > Alerts**, and then select **View alerts in Opsgenie**.
|
||||
<!-- This redirect file can be deleted after <2021-05-03>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -12,7 +12,7 @@ Incident Management enables developers to easily triage and view the alerts and
|
|||
generated by their application. By surfacing alerts and incidents where the code is
|
||||
being developed, efficiency and awareness can be increased. Check out the following sections for more information:
|
||||
|
||||
- [Integrate your monitoring tools](alert_integrations.md).
|
||||
- [Integrate your monitoring tools](integrations.md).
|
||||
- Receive [notifications](paging.md) for triggered alerts.
|
||||
- Triage [Alerts](alerts.md) and [Incidents](incidents.md).
|
||||
- Inform stakeholders with [Status Page](status_page.md).
|
||||
|
|
|
@ -4,9 +4,19 @@ group: Health
|
|||
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/#assignments
|
||||
---
|
||||
|
||||
# Integrations **(FREE)**
|
||||
# Alert integrations **(FREE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/245331) in GitLab Free 13.5.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
|
||||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/42640) to [GitLab Core](https://about.gitlab.com/pricing/) in 12.8.
|
||||
|
||||
GitLab can accept alerts from any source via a webhook receiver. This can be configured
|
||||
generically or, in GitLab versions 13.1 and greater, you can configure
|
||||
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
|
||||
to use this endpoint.
|
||||
|
||||
## Integrations list
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/245331) in [GitLab Core](https://about.gitlab.com/pricing/) 13.5.
|
||||
|
||||
With Maintainer or higher [permissions](../../user/permissions.md), you can view
|
||||
the list of configured alerts integrations by navigating to
|
||||
|
@ -14,3 +24,176 @@ the list of configured alerts integrations by navigating to
|
|||
The list displays the integration name, type, and status (enabled or disabled):
|
||||
|
||||
![Current Integrations](img/integrations_list_v13_5.png)
|
||||
|
||||
## Configuration
|
||||
|
||||
GitLab can receive alerts via a HTTP endpoint that you configure,
|
||||
or the [Prometheus integration](#external-prometheus-integration).
|
||||
|
||||
### Single HTTP Endpoint **(FREE)**
|
||||
|
||||
Enabling the HTTP Endpoint in a GitLab projects activates it to
|
||||
receive alert payloads in JSON format. You can always
|
||||
[customize the payload](#customize-the-alert-payload-outside-of-gitlab) to your liking.
|
||||
|
||||
1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
|
||||
for a project.
|
||||
1. Navigate to **Settings > Operations** in your project.
|
||||
1. Expand the **Alerts** section, and in the **Integration** dropdown menu, select **Generic**.
|
||||
1. Toggle the **Active** alert setting to display the **URL** and **Authorization Key**
|
||||
for the webhook configuration.
|
||||
|
||||
### HTTP Endpoints **PREMIUM**
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4442) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.6.
|
||||
|
||||
In [GitLab Premium](https://about.gitlab.com/pricing/), you can create multiple
|
||||
unique HTTP endpoints to receive alerts from any external source in JSON format,
|
||||
and you can [customize the payload](#customize-the-alert-payload-outside-of-gitlab).
|
||||
|
||||
1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
|
||||
for a project.
|
||||
1. Navigate to **Settings > Operations** in your project.
|
||||
1. Expand the **Alerts** section.
|
||||
1. For each endpoint you want to create:
|
||||
|
||||
1. In the **Integration** dropdown menu, select **HTTP Endpoint**.
|
||||
1. Name the integration.
|
||||
1. Toggle the **Active** alert setting to display the **URL** and **Authorization Key**
|
||||
for the webhook configuration. You must also input the URL and Authorization Key
|
||||
in your external service.
|
||||
1. _(Optional)_ To generate a test alert to test the new integration, enter a
|
||||
sample payload, then click **Save and test alert payload**. Valid JSON is required.
|
||||
1. Click **Save Integration**.
|
||||
|
||||
The new HTTP Endpoint displays in the [integrations list](#integrations-list).
|
||||
You can edit the integration by selecting the **{pencil}** pencil icon on the right
|
||||
side of the integrations list.
|
||||
|
||||
### External Prometheus integration
|
||||
|
||||
For GitLab versions 13.1 and greater, please read
|
||||
[External Prometheus Instances](../metrics/alerts.md#external-prometheus-instances)
|
||||
to configure alerts for this integration.
|
||||
|
||||
## Customize the alert payload outside of GitLab
|
||||
|
||||
For all integration types, you can customize the payload by sending the following
|
||||
parameters. All fields are optional. If the incoming alert does not contain a value for the `Title` field, a default value of `New: Incident` will be applied.
|
||||
|
||||
| Property | Type | Description |
|
||||
| ------------------------- | --------------- | ----------- |
|
||||
| `title` | String | The title of the incident. |
|
||||
| `description` | String | A high-level summary of the problem. |
|
||||
| `start_time` | DateTime | The time of the incident. If none is provided, a timestamp of the issue is used. |
|
||||
| `end_time` | DateTime | For existing alerts only. When provided, the alert is resolved and the associated incident is closed. |
|
||||
| `service` | String | The affected service. |
|
||||
| `monitoring_tool` | String | The name of the associated monitoring tool. |
|
||||
| `hosts` | String or Array | One or more hosts, as to where this incident occurred. |
|
||||
| `severity` | String | The severity of the alert. Must be one of `critical`, `high`, `medium`, `low`, `info`, `unknown`. Default is `critical`. |
|
||||
| `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. |
|
||||
| `gitlab_environment_name` | String | The name of the associated GitLab [environment](../../ci/environments/index.md). Required to [display alerts on a dashboard](../../user/operations_dashboard/index.md#adding-a-project-to-the-dashboard). |
|
||||
|
||||
You can also add custom fields to the alert's payload. The values of extra
|
||||
parameters aren't limited to primitive types (such as strings or numbers), but
|
||||
can be a nested JSON object. For example:
|
||||
|
||||
```json
|
||||
{ "foo": { "bar": { "baz": 42 } } }
|
||||
```
|
||||
|
||||
NOTE:
|
||||
Ensure your requests are smaller than the
|
||||
[payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads).
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request POST \
|
||||
--data '{"title": "Incident title"}' \
|
||||
--header "Authorization: Bearer <authorization_key>" \
|
||||
--header "Content-Type: application/json" \
|
||||
<url>
|
||||
```
|
||||
|
||||
The `<authorization_key>` and `<url>` values can be found when configuring an alert integration.
|
||||
|
||||
Example payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Incident title",
|
||||
"description": "Short description of the incident",
|
||||
"start_time": "2019-09-12T06:00:55Z",
|
||||
"service": "service affected",
|
||||
"monitoring_tool": "value",
|
||||
"hosts": "value",
|
||||
"severity": "high",
|
||||
"fingerprint": "d19381d4e8ebca87b55cda6e8eee7385",
|
||||
"foo": {
|
||||
"bar": {
|
||||
"baz": 42
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Triggering test alerts
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab Core in 13.2.
|
||||
|
||||
After a [project maintainer or owner](../../user/permissions.md)
|
||||
configures an integration, you can trigger a test
|
||||
alert to confirm your integration works properly.
|
||||
|
||||
1. Sign in as a user with Developer or greater [permissions](../../user/permissions.md).
|
||||
1. Navigate to **Settings > Operations** in your project.
|
||||
1. Click **Alerts endpoint** to expand the section.
|
||||
1. Enter a sample payload in **Alert test payload** (valid JSON is required).
|
||||
1. Click **Test alert payload**.
|
||||
|
||||
GitLab displays an error or success message, depending on the outcome of your test.
|
||||
|
||||
## Automatic grouping of identical alerts **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214557) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
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)
|
||||
and details pages.
|
||||
|
||||
If the existing alert is already `resolved`, GitLab creates a new alert instead.
|
||||
|
||||
![Alert Management List](img/alert_list_v13_1.png)
|
||||
|
||||
## Link to your Opsgenie Alerts
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
WARNING:
|
||||
We are building deeper integration with Opsgenie and other alerting tools through
|
||||
[HTTP endpoint integrations](#single-http-endpoint) so you can see alerts in
|
||||
the GitLab interface. As a result, the previous direct link to Opsgenie Alerts from
|
||||
the GitLab alerts list is deprecated in
|
||||
GitLab versions [13.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/273657).
|
||||
|
||||
You can monitor alerts using a GitLab integration with [Opsgenie](https://www.atlassian.com/software/opsgenie).
|
||||
|
||||
If you enable the Opsgenie integration, you can't have other GitLab alert
|
||||
services
|
||||
active at the same time.
|
||||
|
||||
To enable Opsgenie integration:
|
||||
|
||||
1. Sign in as a user with Maintainer or Owner [permissions](../../user/permissions.md).
|
||||
1. Navigate to **Operations > Alerts**.
|
||||
1. In the **Integrations** select box, select **Opsgenie**.
|
||||
1. Select the **Active** toggle.
|
||||
1. In the **API URL** field, enter the base URL for your Opsgenie integration,
|
||||
such as `https://app.opsgenie.com/alert/list`.
|
||||
1. Select **Save changes**.
|
||||
|
||||
After you enable the integration, navigate to the Alerts list page at
|
||||
**Operations > Alerts**, and then select **View alerts in Opsgenie**.
|
||||
|
|
|
@ -83,7 +83,7 @@ You can display alerts with a `gitlab_environment_name` of `production`
|
|||
|
||||
In GitLab versions 13.1 and greater, you can configure your manually configured
|
||||
Prometheus server to use the
|
||||
[Generic alerts integration](../incident_management/alert_integrations.md).
|
||||
[Generic alerts integration](../incident_management/integrations.md).
|
||||
|
||||
## Trigger actions from alerts **(ULTIMATE)**
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
redirect_to: '../offline/index.md'
|
||||
---
|
|
@ -3,3 +3,6 @@ redirect_to: 'usage_trends.md'
|
|||
---
|
||||
|
||||
This document was moved to [another location](usage_trends.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2022-03-20>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -4,5 +4,5 @@ redirect_to: 'https://docs.gitlab.com/runner/install/kubernetes-agent.html'
|
|||
|
||||
This document was moved to [another location](https://docs.gitlab.com/runner/install/kubernetes-agent.html).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-04-22>. -->
|
||||
<!-- This redirect file can be deleted after <2022-02-01>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -39,7 +39,7 @@ Click on the service links to see further configuration instructions and details
|
|||
| [Emails on push](emails_on_push.md) | Email the commits and diff of each push to a list of recipients | No |
|
||||
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki | No |
|
||||
| Flowdock | Flowdock is a collaboration web app for technical teams | No |
|
||||
| [Generic alerts](../../../operations/incident_management/alert_integrations.md) **(ULTIMATE)** | Receive alerts on GitLab from any source | No |
|
||||
| [Generic alerts](../../../operations/incident_management/integrations.md) **(ULTIMATE)** | Receive alerts on GitLab from any source | No |
|
||||
| [GitHub](github.md) **(PREMIUM)** | Sends pipeline notifications to GitHub | No |
|
||||
| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat | No |
|
||||
| [HipChat](hipchat.md) | Private group chat and IM | No |
|
||||
|
|
|
@ -361,7 +361,7 @@ module API
|
|||
with: Entities::MergeRequestChanges,
|
||||
current_user: current_user,
|
||||
project: user_project,
|
||||
access_raw_diffs: params.fetch(:access_raw_diffs, false)
|
||||
access_raw_diffs: to_boolean(params.fetch(:access_raw_diffs, false))
|
||||
end
|
||||
|
||||
desc 'Get the merge request pipelines' do
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* eslint-disable max-classes-per-file */
|
||||
import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor';
|
||||
import { editor as monacoEditor, languages as monacoLanguages } from 'monaco-editor';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import Editor from '~/editor/editor_lite';
|
||||
import { joinPaths } from '~/lib/utils/url_utility';
|
||||
import EditorLite from '~/editor/editor_lite';
|
||||
import { EditorLiteExtension } from '~/editor/extensions/editor_lite_extension_base';
|
||||
import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
|
||||
import {
|
||||
|
@ -13,6 +14,8 @@ import {
|
|||
describe('Base editor', () => {
|
||||
let editorEl;
|
||||
let editor;
|
||||
let defaultArguments;
|
||||
const blobOriginalContent = 'Foo Foo';
|
||||
const blobContent = 'Foo Bar';
|
||||
const blobPath = 'test.md';
|
||||
const blobGlobalId = 'snippet_777';
|
||||
|
@ -21,15 +24,19 @@ describe('Base editor', () => {
|
|||
beforeEach(() => {
|
||||
setFixtures('<div id="editor" data-editor-loading></div>');
|
||||
editorEl = document.getElementById('editor');
|
||||
editor = new Editor();
|
||||
defaultArguments = { el: editorEl, blobPath, blobContent, blobGlobalId };
|
||||
editor = new EditorLite();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
editor.dispose();
|
||||
editorEl.remove();
|
||||
monacoEditor.getModels().forEach((model) => {
|
||||
model.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
const createUri = (...paths) => Uri.file([URI_PREFIX, ...paths].join('/'));
|
||||
const uriFilePath = joinPaths('/', URI_PREFIX, blobGlobalId, blobPath);
|
||||
|
||||
it('initializes Editor with basic properties', () => {
|
||||
expect(editor).toBeDefined();
|
||||
|
@ -42,93 +49,192 @@ describe('Base editor', () => {
|
|||
expect(editorEl.dataset.editorLoading).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('instance of the Editor', () => {
|
||||
describe('instance of the Editor Lite', () => {
|
||||
let modelSpy;
|
||||
let instanceSpy;
|
||||
let setModel;
|
||||
let dispose;
|
||||
let modelsStorage;
|
||||
const setModel = jest.fn();
|
||||
const dispose = jest.fn();
|
||||
const mockModelReturn = (res = fakeModel) => {
|
||||
modelSpy = jest.spyOn(monacoEditor, 'createModel').mockImplementation(() => res);
|
||||
};
|
||||
const mockDecorateInstance = (decorations = {}) => {
|
||||
jest.spyOn(EditorLite, 'convertMonacoToELInstance').mockImplementation((inst) => {
|
||||
return Object.assign(inst, decorations);
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
setModel = jest.fn();
|
||||
dispose = jest.fn();
|
||||
modelsStorage = new Map();
|
||||
modelSpy = jest.spyOn(monacoEditor, 'createModel').mockImplementation(() => fakeModel);
|
||||
instanceSpy = jest.spyOn(monacoEditor, 'create').mockImplementation(() => ({
|
||||
setModel,
|
||||
dispose,
|
||||
onDidDispose: jest.fn(),
|
||||
}));
|
||||
jest.spyOn(monacoEditor, 'getModel').mockImplementation((uri) => {
|
||||
return modelsStorage.get(uri.path);
|
||||
modelSpy = jest.spyOn(monacoEditor, 'createModel');
|
||||
});
|
||||
|
||||
describe('instance of the Code Editor', () => {
|
||||
beforeEach(() => {
|
||||
instanceSpy = jest.spyOn(monacoEditor, 'create');
|
||||
});
|
||||
|
||||
it('throws an error if no dom element is supplied', () => {
|
||||
mockDecorateInstance();
|
||||
expect(() => {
|
||||
editor.createInstance();
|
||||
}).toThrow(EDITOR_LITE_INSTANCE_ERROR_NO_EL);
|
||||
|
||||
expect(modelSpy).not.toHaveBeenCalled();
|
||||
expect(instanceSpy).not.toHaveBeenCalled();
|
||||
expect(EditorLite.convertMonacoToELInstance).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates model to be supplied to Monaco editor', () => {
|
||||
mockModelReturn();
|
||||
mockDecorateInstance({
|
||||
setModel,
|
||||
});
|
||||
editor.createInstance(defaultArguments);
|
||||
|
||||
expect(modelSpy).toHaveBeenCalledWith(
|
||||
blobContent,
|
||||
undefined,
|
||||
expect.objectContaining({
|
||||
path: uriFilePath,
|
||||
}),
|
||||
);
|
||||
expect(setModel).toHaveBeenCalledWith(fakeModel);
|
||||
});
|
||||
|
||||
it('does not create a model automatically if model is passed as `null`', () => {
|
||||
mockDecorateInstance({
|
||||
setModel,
|
||||
});
|
||||
editor.createInstance({ ...defaultArguments, model: null });
|
||||
expect(modelSpy).not.toHaveBeenCalled();
|
||||
expect(setModel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('initializes the instance on a supplied DOM node', () => {
|
||||
editor.createInstance({ el: editorEl });
|
||||
|
||||
expect(editor.editorEl).not.toBe(null);
|
||||
expect(instanceSpy).toHaveBeenCalledWith(editorEl, expect.anything());
|
||||
});
|
||||
|
||||
it('with blobGlobalId, creates model with the id in uri', () => {
|
||||
editor.createInstance(defaultArguments);
|
||||
|
||||
expect(modelSpy).toHaveBeenCalledWith(
|
||||
blobContent,
|
||||
undefined,
|
||||
expect.objectContaining({
|
||||
path: uriFilePath,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('initializes instance with passed properties', () => {
|
||||
const instanceOptions = {
|
||||
foo: 'bar',
|
||||
};
|
||||
editor.createInstance({
|
||||
el: editorEl,
|
||||
...instanceOptions,
|
||||
});
|
||||
expect(instanceSpy).toHaveBeenCalledWith(
|
||||
editorEl,
|
||||
expect.objectContaining(instanceOptions),
|
||||
);
|
||||
});
|
||||
|
||||
it('disposes instance when the global editor is disposed', () => {
|
||||
mockDecorateInstance({
|
||||
dispose,
|
||||
});
|
||||
editor.createInstance(defaultArguments);
|
||||
|
||||
expect(dispose).not.toHaveBeenCalled();
|
||||
|
||||
editor.dispose();
|
||||
|
||||
expect(dispose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("removes the disposed instance from the global editor's storage and disposes the associated model", () => {
|
||||
mockModelReturn();
|
||||
mockDecorateInstance({
|
||||
setModel,
|
||||
});
|
||||
const instance = editor.createInstance(defaultArguments);
|
||||
|
||||
expect(editor.instances).toHaveLength(1);
|
||||
expect(fakeModel.dispose).not.toHaveBeenCalled();
|
||||
|
||||
instance.dispose();
|
||||
|
||||
expect(editor.instances).toHaveLength(0);
|
||||
expect(fakeModel.dispose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('throws an error if no dom element is supplied', () => {
|
||||
expect(() => {
|
||||
editor.createInstance();
|
||||
}).toThrow(EDITOR_LITE_INSTANCE_ERROR_NO_EL);
|
||||
|
||||
expect(modelSpy).not.toHaveBeenCalled();
|
||||
expect(instanceSpy).not.toHaveBeenCalled();
|
||||
expect(setModel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates model to be supplied to Monaco editor', () => {
|
||||
editor.createInstance({ el: editorEl, blobPath, blobContent, blobGlobalId: '' });
|
||||
|
||||
expect(modelSpy).toHaveBeenCalledWith(blobContent, undefined, createUri(blobPath));
|
||||
expect(setModel).toHaveBeenCalledWith(fakeModel);
|
||||
});
|
||||
|
||||
it('does not create a new model if a model for the path already exists', () => {
|
||||
modelSpy = jest
|
||||
.spyOn(monacoEditor, 'createModel')
|
||||
.mockImplementation((content, lang, uri) => modelsStorage.set(uri.path, content));
|
||||
const instanceOptions = { el: editorEl, blobPath, blobContent, blobGlobalId: '' };
|
||||
const a = editor.createInstance(instanceOptions);
|
||||
const b = editor.createInstance(instanceOptions);
|
||||
|
||||
expect(a === b).toBe(false);
|
||||
expect(modelSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('initializes the instance on a supplied DOM node', () => {
|
||||
editor.createInstance({ el: editorEl });
|
||||
|
||||
expect(editor.editorEl).not.toBe(null);
|
||||
expect(instanceSpy).toHaveBeenCalledWith(editorEl, expect.anything());
|
||||
});
|
||||
|
||||
it('with blobGlobalId, creates model with id in uri', () => {
|
||||
editor.createInstance({ el: editorEl, blobPath, blobContent, blobGlobalId });
|
||||
|
||||
expect(modelSpy).toHaveBeenCalledWith(
|
||||
blobContent,
|
||||
undefined,
|
||||
createUri(blobGlobalId, blobPath),
|
||||
);
|
||||
});
|
||||
|
||||
it('initializes instance with passed properties', () => {
|
||||
const instanceOptions = {
|
||||
foo: 'bar',
|
||||
};
|
||||
editor.createInstance({
|
||||
el: editorEl,
|
||||
...instanceOptions,
|
||||
describe('instance of the Diff Editor', () => {
|
||||
beforeEach(() => {
|
||||
instanceSpy = jest.spyOn(monacoEditor, 'createDiffEditor');
|
||||
});
|
||||
expect(instanceSpy).toHaveBeenCalledWith(editorEl, expect.objectContaining(instanceOptions));
|
||||
});
|
||||
|
||||
it('disposes instance when the editor is disposed', () => {
|
||||
editor.createInstance({ el: editorEl, blobPath, blobContent, blobGlobalId });
|
||||
it('Diff Editor goes through the normal path of Code Editor just with the flag ON', () => {
|
||||
const spy = jest.spyOn(editor, 'createInstance').mockImplementation(() => {});
|
||||
editor.createDiffInstance();
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
isDiff: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
expect(dispose).not.toHaveBeenCalled();
|
||||
it('initializes the instance on a supplied DOM node', () => {
|
||||
const wrongInstanceSpy = jest.spyOn(monacoEditor, 'create').mockImplementation(() => ({}));
|
||||
editor.createDiffInstance({ ...defaultArguments, blobOriginalContent });
|
||||
|
||||
editor.dispose();
|
||||
expect(editor.editorEl).not.toBe(null);
|
||||
expect(wrongInstanceSpy).not.toHaveBeenCalled();
|
||||
expect(instanceSpy).toHaveBeenCalledWith(editorEl, expect.anything());
|
||||
});
|
||||
|
||||
expect(dispose).toHaveBeenCalled();
|
||||
it('creates correct model for the Diff Editor', () => {
|
||||
const instance = editor.createDiffInstance({ ...defaultArguments, blobOriginalContent });
|
||||
const getDiffModelValue = (model) => instance.getModel()[model].getValue();
|
||||
|
||||
expect(modelSpy).toHaveBeenCalledTimes(2);
|
||||
expect(modelSpy.mock.calls[0]).toEqual([
|
||||
blobContent,
|
||||
undefined,
|
||||
expect.objectContaining({
|
||||
path: uriFilePath,
|
||||
}),
|
||||
]);
|
||||
expect(modelSpy.mock.calls[1]).toEqual([blobOriginalContent, 'markdown']);
|
||||
expect(getDiffModelValue('original')).toBe(blobOriginalContent);
|
||||
expect(getDiffModelValue('modified')).toBe(blobContent);
|
||||
});
|
||||
|
||||
it('correctly disposes the diff editor model', () => {
|
||||
const modifiedModel = fakeModel;
|
||||
const originalModel = { ...fakeModel };
|
||||
mockDecorateInstance({
|
||||
getModel: jest.fn().mockReturnValue({
|
||||
original: originalModel,
|
||||
modified: modifiedModel,
|
||||
}),
|
||||
});
|
||||
|
||||
const instance = editor.createDiffInstance({ ...defaultArguments, blobOriginalContent });
|
||||
|
||||
expect(editor.instances).toHaveLength(1);
|
||||
expect(originalModel.dispose).not.toHaveBeenCalled();
|
||||
expect(modifiedModel.dispose).not.toHaveBeenCalled();
|
||||
|
||||
instance.dispose();
|
||||
|
||||
expect(editor.instances).toHaveLength(0);
|
||||
expect(originalModel.dispose).toHaveBeenCalled();
|
||||
expect(modifiedModel.dispose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -148,16 +254,14 @@ describe('Base editor', () => {
|
|||
editorEl2 = document.getElementById('editor2');
|
||||
inst1Args = {
|
||||
el: editorEl1,
|
||||
blobGlobalId,
|
||||
};
|
||||
inst2Args = {
|
||||
el: editorEl2,
|
||||
blobContent,
|
||||
blobPath,
|
||||
blobGlobalId,
|
||||
};
|
||||
|
||||
editor = new Editor();
|
||||
editor = new EditorLite();
|
||||
instanceSpy = jest.spyOn(monacoEditor, 'create');
|
||||
});
|
||||
|
||||
|
@ -187,8 +291,20 @@ describe('Base editor', () => {
|
|||
expect(model1).not.toEqual(model2);
|
||||
});
|
||||
|
||||
it('does not create a new model if a model for the path & globalId combo already exists', () => {
|
||||
const modelSpy = jest.spyOn(monacoEditor, 'createModel');
|
||||
inst1 = editor.createInstance({ ...inst2Args, blobGlobalId });
|
||||
inst2 = editor.createInstance({ ...inst2Args, el: editorEl1, blobGlobalId });
|
||||
|
||||
const model1 = inst1.getModel();
|
||||
const model2 = inst2.getModel();
|
||||
|
||||
expect(modelSpy).toHaveBeenCalledTimes(1);
|
||||
expect(model1).toBe(model2);
|
||||
});
|
||||
|
||||
it('shares global editor options among all instances', () => {
|
||||
editor = new Editor({
|
||||
editor = new EditorLite({
|
||||
readOnly: true,
|
||||
});
|
||||
|
||||
|
@ -200,7 +316,7 @@ describe('Base editor', () => {
|
|||
});
|
||||
|
||||
it('allows overriding editor options on the instance level', () => {
|
||||
editor = new Editor({
|
||||
editor = new EditorLite({
|
||||
readOnly: true,
|
||||
});
|
||||
inst1 = editor.createInstance({
|
||||
|
@ -221,6 +337,7 @@ describe('Base editor', () => {
|
|||
expect(monacoEditor.getModels()).toHaveLength(2);
|
||||
|
||||
inst1.dispose();
|
||||
|
||||
expect(inst1.getModel()).toBe(null);
|
||||
expect(inst2.getModel()).not.toBe(null);
|
||||
expect(editor.instances).toHaveLength(1);
|
||||
|
@ -423,19 +540,20 @@ describe('Base editor', () => {
|
|||
el: editorEl,
|
||||
blobPath,
|
||||
blobContent,
|
||||
blobGlobalId,
|
||||
extensions,
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
editorExtensionSpy = jest.spyOn(Editor, 'pushToImportsArray').mockImplementation((arr) => {
|
||||
arr.push(
|
||||
Promise.resolve({
|
||||
default: {},
|
||||
}),
|
||||
);
|
||||
});
|
||||
editorExtensionSpy = jest
|
||||
.spyOn(EditorLite, 'pushToImportsArray')
|
||||
.mockImplementation((arr) => {
|
||||
arr.push(
|
||||
Promise.resolve({
|
||||
default: {},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it.each([undefined, [], [''], ''])(
|
||||
|
@ -472,9 +590,14 @@ describe('Base editor', () => {
|
|||
const eventSpy = jest.fn().mockImplementation(() => {
|
||||
calls.push('event');
|
||||
});
|
||||
const useSpy = jest.spyOn(editor, 'use').mockImplementation(() => {
|
||||
const useSpy = jest.fn().mockImplementation(() => {
|
||||
calls.push('use');
|
||||
});
|
||||
jest.spyOn(EditorLite, 'convertMonacoToELInstance').mockImplementation((inst) => {
|
||||
const decoratedInstance = inst;
|
||||
decoratedInstance.use = useSpy;
|
||||
return decoratedInstance;
|
||||
});
|
||||
editorEl.addEventListener(EDITOR_READY_EVENT, eventSpy);
|
||||
instance = instanceConstructor('foo, bar');
|
||||
await waitForPromises();
|
||||
|
@ -508,12 +631,6 @@ describe('Base editor', () => {
|
|||
expect(inst1.alpha()).toEqual(alphaRes);
|
||||
expect(inst2.alpha()).toEqual(alphaRes);
|
||||
});
|
||||
|
||||
it('extends specific instance if it has been passed', () => {
|
||||
editor.use(AlphaExt, inst2);
|
||||
expect(inst1.alpha).toBeUndefined();
|
||||
expect(inst2.alpha()).toEqual(alphaRes);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -547,7 +664,7 @@ describe('Base editor', () => {
|
|||
it('sets default syntax highlighting theme', () => {
|
||||
const expectedTheme = themes.find((t) => t.name === DEFAULT_THEME);
|
||||
|
||||
editor = new Editor();
|
||||
editor = new EditorLite();
|
||||
|
||||
expect(themeDefineSpy).toHaveBeenCalledWith(DEFAULT_THEME, expectedTheme.data);
|
||||
expect(themeSetSpy).toHaveBeenCalledWith(DEFAULT_THEME);
|
||||
|
@ -559,7 +676,7 @@ describe('Base editor', () => {
|
|||
expect(expectedTheme.name).not.toBe(DEFAULT_THEME);
|
||||
|
||||
window.gon.user_color_scheme = expectedTheme.name;
|
||||
editor = new Editor();
|
||||
editor = new EditorLite();
|
||||
|
||||
expect(themeDefineSpy).toHaveBeenCalledWith(expectedTheme.name, expectedTheme.data);
|
||||
expect(themeSetSpy).toHaveBeenCalledWith(expectedTheme.name);
|
||||
|
@ -570,7 +687,7 @@ describe('Base editor', () => {
|
|||
const nonExistentTheme = { name };
|
||||
|
||||
window.gon.user_color_scheme = nonExistentTheme.name;
|
||||
editor = new Editor();
|
||||
editor = new EditorLite();
|
||||
|
||||
expect(themeDefineSpy).not.toHaveBeenCalled();
|
||||
expect(themeSetSpy).toHaveBeenCalledWith(DEFAULT_THEME);
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
import Editor from '~/ide/lib/editor';
|
||||
import { createStore } from '~/ide/stores';
|
||||
import { defaultEditorOptions } from '~/ide/lib/editor_options';
|
||||
import { EDITOR_TYPE_DIFF } from '~/editor/constants';
|
||||
import { file } from '../helpers';
|
||||
|
||||
describe('Multi-file editor library', () => {
|
||||
|
@ -125,7 +126,7 @@ describe('Multi-file editor library', () => {
|
|||
});
|
||||
|
||||
it('sets original & modified when diff editor', () => {
|
||||
jest.spyOn(instance.instance, 'getEditorType').mockReturnValue('vs.editor.IDiffEditor');
|
||||
jest.spyOn(instance.instance, 'getEditorType').mockReturnValue(EDITOR_TYPE_DIFF);
|
||||
jest.spyOn(instance.instance, 'setModel').mockImplementation(() => {});
|
||||
|
||||
instance.attachModel(model);
|
||||
|
|
|
@ -30,7 +30,7 @@ RSpec.describe OperationsHelper do
|
|||
|
||||
it 'returns the correct values' do
|
||||
expect(subject).to eq(
|
||||
'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'),
|
||||
'alerts_setup_url' => help_page_path('operations/incident_management/integrations.md', anchor: 'configuration'),
|
||||
'alerts_usage_url' => project_alert_management_index_path(project),
|
||||
'prometheus_form_path' => project_service_path(project, prometheus_service),
|
||||
'prometheus_reset_key_path' => reset_alerting_token_project_settings_operations_path(project),
|
||||
|
|
|
@ -1894,8 +1894,11 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
|||
it 'removes the remote' do
|
||||
repository_rugged.remotes.create(remote_name, url)
|
||||
|
||||
repository.remove_remote(remote_name)
|
||||
expect(repository.remove_remote(remote_name)).to be true
|
||||
|
||||
# Since we deleted the remote via Gitaly, Rugged doesn't know
|
||||
# this changed underneath it. Let's refresh the Rugged repo.
|
||||
repository_rugged = Rugged::Repository.new(repository_path)
|
||||
expect(repository_rugged.remotes[remote_name]).to be_nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -715,6 +715,10 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
context 'when external issue tracker is enabled' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
subject { create(:merge_request, source_project: project) }
|
||||
|
||||
before do
|
||||
subject.project.has_external_issue_tracker = true
|
||||
subject.project.save!
|
||||
|
@ -788,6 +792,10 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
context 'when only external issue tracker enabled' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
subject { create(:merge_request, source_project: project) }
|
||||
|
||||
before do
|
||||
subject.project.has_external_issue_tracker = true
|
||||
subject.project.issues_enabled = false
|
||||
|
@ -1274,8 +1282,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
let(:mentioned_issue) { create :issue, project: subject.project }
|
||||
let(:commit) { double('commit', safe_message: "Fixes #{closing_issue.to_reference}") }
|
||||
|
||||
subject { create(:merge_request, source_project: create(:project)) }
|
||||
|
||||
it 'detects issues mentioned in description but not closed' do
|
||||
subject.project.add_developer(subject.author)
|
||||
subject.description = "Is related to #{mentioned_issue.to_reference} and #{closing_issue.to_reference}"
|
||||
|
@ -1478,8 +1484,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
describe '#default_merge_commit_message' do
|
||||
subject { create(:merge_request, source_project: create(:project)) }
|
||||
|
||||
it 'includes merge information as the title' do
|
||||
request = build(:merge_request, source_branch: 'source', target_branch: 'target')
|
||||
|
||||
|
@ -3424,6 +3428,10 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
context 'when resolve_outdated_diff_discussions is set' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
subject { create(:merge_request, source_project: project) }
|
||||
|
||||
before do
|
||||
discussion
|
||||
|
||||
|
@ -3444,7 +3452,7 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
describe '#branch_merge_base_commit' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
subject { create(:merge_request, :with_diffs, source_project: project) }
|
||||
subject { create(:merge_request, source_project: project) }
|
||||
|
||||
context 'source and target branch exist' do
|
||||
it { expect(subject.branch_merge_base_commit.sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') }
|
||||
|
@ -3467,7 +3475,7 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
context "with diffs" do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
subject { create(:merge_request, :with_diffs, source_project: project) }
|
||||
subject { create(:merge_request, source_project: project) }
|
||||
|
||||
let(:expected_diff_refs) do
|
||||
Gitlab::Diff::DiffRefs.new(
|
||||
|
@ -3871,7 +3879,7 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
describe '#fetch_ref!' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
subject { create(:merge_request, :with_diffs, source_project: project) }
|
||||
subject { create(:merge_request, source_project: project) }
|
||||
|
||||
it 'fetches the ref correctly' do
|
||||
expect { subject.target_project.repository.delete_refs(subject.ref_path) }.not_to raise_error
|
||||
|
|
|
@ -1136,11 +1136,11 @@ RSpec.describe Repository do
|
|||
expect(repository.license_key).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when the content is not recognizable' do
|
||||
it 'returns other when the content is not recognizable' do
|
||||
repository.create_file(user, 'LICENSE', 'Gitlab B.V.',
|
||||
message: 'Add LICENSE', branch_name: 'master')
|
||||
|
||||
expect(repository.license_key).to be_nil
|
||||
expect(repository.license_key).to eq('other')
|
||||
end
|
||||
|
||||
it 'returns nil when the commit SHA does not exist' do
|
||||
|
@ -1180,11 +1180,12 @@ RSpec.describe Repository do
|
|||
expect(repository.license).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when the content is not recognizable' do
|
||||
it 'returns other when the content is not recognizable' do
|
||||
license = Licensee::License.new('other')
|
||||
repository.create_file(user, 'LICENSE', 'Gitlab B.V.',
|
||||
message: 'Add LICENSE', branch_name: 'master')
|
||||
|
||||
expect(repository.license).to be_nil
|
||||
expect(repository.license).to eq(license)
|
||||
end
|
||||
|
||||
it 'returns the license' do
|
||||
|
|
|
@ -1542,9 +1542,9 @@ RSpec.describe API::MergeRequests do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when access_raw_diffs is passed as an option' do
|
||||
context 'when access_raw_diffs is true' do
|
||||
it_behaves_like 'accesses diffs via raw_diffs' do
|
||||
let(:params) { { access_raw_diffs: true } }
|
||||
let(:params) { { access_raw_diffs: "true" } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,7 +65,9 @@ RSpec.describe API::Templates do
|
|||
expect(json_response['nickname']).to be_nil
|
||||
expect(json_response['popular']).to be true
|
||||
expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/')
|
||||
expect(json_response['source_url']).to eq('https://opensource.org/licenses/MIT')
|
||||
# This was dropped:
|
||||
# https://github.com/github/choosealicense.com/commit/325806b42aa3d5b78e84120327ec877bc936dbdd#diff-66df8f1997786f7052d29010f2cbb4c66391d60d24ca624c356acc0ab986f139
|
||||
expect(json_response['source_url']).to be_nil
|
||||
expect(json_response['description']).to include('A short and simple permissive license with conditions')
|
||||
expect(json_response['conditions']).to eq(%w[include-copyright])
|
||||
expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use])
|
||||
|
@ -81,7 +83,7 @@ RSpec.describe API::Templates do
|
|||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to include_pagination_headers
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.size).to eq(12)
|
||||
expect(json_response.size).to eq(13)
|
||||
expect(json_response.map { |l| l['key'] }).to include('agpl-3.0')
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue