summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-13 21:08:55 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-13 21:08:55 +0000
commita5650b86b5a809d3b7c754afd5ff5671e9bcc584 (patch)
tree6a53414f01dae4b5716a94c8d33136616c8b3eb1
parente689e858ede41a34b1e9132eba6a602632e6885e (diff)
downloadgitlab-ce-a5650b86b5a809d3b7c754afd5ff5671e9bcc584.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_mermaid.js2
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue5
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/variables_section.vue4
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js2
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js6
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js4
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js11
-rw-r--r--app/assets/javascripts/monitoring/stores/utils.js5
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue5
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue5
-rw-r--r--app/assets/javascripts/repository/queries/commit.fragment.graphql1
-rw-r--r--app/assets/javascripts/repository/queries/pathLastCommit.query.graphql1
-rw-r--r--app/assets/javascripts/repository/utils/commit.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js48
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue20
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_service.js32
-rw-r--r--app/assets/stylesheets/components/rich_content_editor.scss11
-rw-r--r--app/assets/stylesheets/framework/common.scss11
-rw-r--r--app/controllers/concerns/preview_markdown.rb2
-rw-r--r--app/controllers/concerns/record_user_last_activity.rb1
-rw-r--r--app/controllers/concerns/snippets_actions.rb9
-rw-r--r--app/controllers/projects/refs_controller.rb15
-rw-r--r--app/controllers/projects/snippets_controller.rb11
-rw-r--r--app/controllers/snippets_controller.rb9
-rw-r--r--app/graphql/types/commit_type.rb1
-rw-r--r--app/helpers/application_settings_helper.rb7
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/models/snippet_repository.rb5
-rw-r--r--app/models/user.rb3
-rw-r--r--app/services/snippets/base_service.rb17
-rw-r--r--app/services/snippets/create_service.rb2
-rw-r--r--app/services/snippets/update_service.rb3
-rw-r--r--app/views/admin/application_settings/_influx.html.haml60
-rw-r--r--app/views/admin/application_settings/_prometheus.html.haml6
-rw-r--r--app/views/admin/application_settings/metrics_and_profiling.html.haml11
-rw-r--r--app/views/projects/services/prometheus/_custom_metrics.html.haml4
-rw-r--r--changelogs/unreleased/14108-instance-level-ci-variables-api.yml5
-rw-r--r--changelogs/unreleased/208897-remove-bot-type-column.yml5
-rw-r--r--changelogs/unreleased/214382-remove-project_list_show_issue_count-feature-flag.yml5
-rw-r--r--changelogs/unreleased/214382-remove-project_list_show_mr_count-feature-flag.yml5
-rw-r--r--changelogs/unreleased/214382-remove-set_user_last_activity-feature-flag.yml5
-rw-r--r--changelogs/unreleased/25375-webide-markdown-broken-images.yml5
-rw-r--r--changelogs/unreleased/dblessing-scim-identitites-new-user-flow.yml5
-rw-r--r--changelogs/unreleased/dbodicherla-update-urls-params-only-update-existing-variables.yml6
-rw-r--r--changelogs/unreleased/fix-broken-heading-of-vue-3-migration-guide-doc.yml5
-rw-r--r--changelogs/unreleased/ph-212669-commitTypeMarkdownHTML.yml5
-rw-r--r--changelogs/unreleased/rc-remove_influx_views_docs.yml5
-rw-r--r--changelogs/unreleased/vij-snippet-create-update-errors.yml5
-rw-r--r--config/pseudonymizer.yml1
-rw-r--r--db/post_migrate/20200506154421_migrate_scim_identities_to_saml_for_new_users.rb37
-rw-r--r--db/post_migrate/20200508091106_remove_bot_type.rb29
-rw-r--r--db/structure.sql5
-rw-r--r--doc/administration/index.md2
-rw-r--r--doc/administration/logs.md2
-rw-r--r--doc/administration/monitoring/performance/gitlab_configuration.md10
-rw-r--r--doc/administration/monitoring/performance/grafana_configuration.md54
-rw-r--r--doc/administration/monitoring/performance/index.md18
-rw-r--r--doc/administration/monitoring/performance/influxdb_configuration.md192
-rw-r--r--doc/administration/monitoring/performance/influxdb_schema.md102
-rw-r--r--doc/api/admin_ci_instance_level_variables.md136
-rw-r--r--doc/api/api_resources.md3
-rw-r--r--doc/api/commits.md56
-rw-r--r--doc/api/container_registry.md2
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json14
-rw-r--r--doc/api/graphql/reference/index.md1
-rw-r--r--doc/api/settings.md9
-rw-r--r--doc/development/fe_guide/vue3_migration.md2
-rw-r--r--doc/development/performance.md2
-rw-r--r--doc/development/policies.md2
-rw-r--r--doc/development/testing_guide/best_practices.md2
-rw-r--r--doc/monitoring/performance/influxdb_configuration.md4
-rw-r--r--doc/monitoring/performance/influxdb_schema.md4
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/index.md10
-rw-r--r--doc/user/admin_area/settings/index.md1
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md1
-rw-r--r--doc/user/analytics/value_stream_analytics.md15
-rw-r--r--doc/user/application_security/img/adding_a_dismissal_reason_v13_0.pngbin0 -> 109979 bytes
-rw-r--r--doc/user/application_security/img/dismissed_info_v12_3.pngbin35439 -> 0 bytes
-rw-r--r--doc/user/application_security/img/interacting_with_vulnerability_v13_0.pngbin0 -> 90299 bytes
-rw-r--r--doc/user/application_security/img/interactive_reports.pngbin29814 -> 0 bytes
-rw-r--r--doc/user/application_security/index.md22
-rw-r--r--doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_6.pngbin69145 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/group_security_dashboard_v13_0.pngbin0 -> 212401 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/instance_security_dashboard_export_csv_v13_0.pngbin91436 -> 5563 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v12_8.pngbin87617 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v13_0.pngbin0 -> 58505 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.pngbin48767 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.pngbin0 -> 199457 bytes
-rw-r--r--doc/user/application_security/security_dashboard/index.md30
-rw-r--r--doc/user/packages/container_registry/img/container_registry_group_repositories_v13_0.pngbin41940 -> 41813 bytes
-rw-r--r--doc/user/packages/container_registry/img/container_registry_repositories_v13_0.pngbin43833 -> 44925 bytes
-rw-r--r--doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_0.pngbin48529 -> 48708 bytes
-rw-r--r--doc/user/packages/container_registry/img/expiration_policy_app_v13_0.pngbin106289 -> 61601 bytes
-rw-r--r--doc/user/packages/container_registry/index.md2
-rw-r--r--doc/user/search/img/filter_approved_by_merge_requests_v13_0.pngbin0 -> 46764 bytes
-rw-r--r--doc/user/search/index.md11
-rw-r--r--lib/api/admin/ci/variables.rb137
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/settings.rb11
-rw-r--r--lib/gitlab/alert_management/alert_params.rb3
-rw-r--r--lib/gitlab/alerting/notification_payload_parser.rb10
-rw-r--r--lib/gitlab/background_migration/populate_user_highest_roles_table.rb2
-rw-r--r--lib/gitlab/cycle_analytics/summary/value.rb2
-rw-r--r--lib/gitlab/graphql/query_analyzers/logger_analyzer.rb4
-rw-r--r--lib/gitlab/middleware/multipart.rb1
-rw-r--r--lib/gitlab/tree_summary.rb16
-rw-r--r--locale/gitlab.pot42
-rw-r--r--qa/qa.rb6
-rw-r--r--qa/qa/page/component/custom_metric.rb45
-rw-r--r--qa/qa/page/project/operations/metrics/show.rb18
-rw-r--r--qa/qa/page/project/settings/integrations.rb19
-rw-r--r--qa/qa/page/project/settings/services/prometheus.rb36
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb155
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/apm/dashboards_spec.rb97
-rw-r--r--spec/controllers/projects_controller_spec.rb26
-rw-r--r--spec/factories/alert_management/alerts.rb7
-rw-r--r--spec/features/admin/admin_settings_spec.rb10
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb12
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb2
-rw-r--r--spec/features/projects/snippets/user_updates_snippet_spec.rb4
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb2
-rw-r--r--spec/features/snippets/user_edits_snippet_spec.rb4
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/project.json20
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/protected_environments.ndjson1
-rw-r--r--spec/fixtures/lib/gitlab/import_export/designs/project.json17
-rw-r--r--spec/frontend/__mocks__/@toast-ui/vue-editor/index.js3
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap2
-rw-r--r--spec/frontend/monitoring/components/variables_section_spec.js15
-rw-r--r--spec/frontend/monitoring/store/actions_spec.js10
-rw-r--r--spec/frontend/monitoring/store/getters_spec.js4
-rw-r--r--spec/frontend/monitoring/store/mutations_spec.js24
-rw-r--r--spec/frontend/monitoring/store/utils_spec.js22
-rw-r--r--spec/frontend/monitoring/store_utils.js2
-rw-r--r--spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap8
-rw-r--r--spec/frontend/repository/components/last_commit_spec.js1
-rw-r--r--spec/frontend/repository/utils/commit_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js37
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js44
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/toolbar_service_spec.js29
-rw-r--r--spec/graphql/types/commit_type_spec.rb2
-rw-r--r--spec/helpers/markup_helper_spec.rb39
-rw-r--r--spec/helpers/projects_helper_spec.rb42
-rw-r--r--spec/javascripts/ide/components/repo_editor_spec.js16
-rw-r--r--spec/lib/gitlab/alert_management/alert_params_spec.rb12
-rw-r--r--spec/lib/gitlab/alerting/notification_payload_parser_spec.rb29
-rw-r--r--spec/lib/gitlab/cycle_analytics/summary/value_spec.rb4
-rw-r--r--spec/lib/gitlab/graphql_logger_spec.rb4
-rw-r--r--spec/lib/gitlab/middleware/multipart_spec.rb11
-rw-r--r--spec/lib/gitlab/tree_summary_spec.rb16
-rw-r--r--spec/requests/api/admin/ci/variables_spec.rb210
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb2
-rw-r--r--spec/requests/api/graphql_spec.rb2
-rw-r--r--spec/services/projects/alerting/notify_service_spec.rb84
-rw-r--r--spec/services/snippets/create_service_spec.rb16
-rw-r--r--spec/services/snippets/update_service_spec.rb2
161 files changed, 1724 insertions, 896 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
index e42f6e5ba48..057cdb6cc4c 100644
--- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
@@ -82,7 +82,7 @@ function renderMermaidEl(el) {
return;
}
- svg.classList.add('mermaid', 'mw-100');
+ svg.classList.add('mermaid');
// pre > code > svg
svg.closest('pre').replaceWith(svg);
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 08850679152..559731dd248 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -44,6 +44,7 @@ export default {
'isEditModeActive',
'isCommitModeActive',
'isReviewModeActive',
+ 'currentBranch',
]),
...mapGetters('fileTemplates', ['showFileTemplatesBar']),
shouldHideEditor() {
@@ -87,6 +88,9 @@ export default {
theme: this.editorTheme,
};
},
+ currentBranchCommit() {
+ return this.currentBranch?.commit.id;
+ },
},
watch: {
file(newVal, oldVal) {
@@ -315,6 +319,7 @@ export default {
:file-path="file.path"
:file-size="file.size"
:project-path="file.projectId"
+ :commit-sha="currentBranchCommit"
:type="fileType"
/>
<diff-viewer
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 0a6329fbdfb..27ef0b0999e 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -494,7 +494,7 @@ export default {
<date-time-picker
ref="dateTimePicker"
class="flex-grow-1 show-last-dropdown"
- data-qa-selector="show_last_dropdown"
+ data-qa-selector="range_picker_dropdown"
:value="selectedTimeRange"
:options="timeRanges"
@input="onDateTimePickerInput"
diff --git a/app/assets/javascripts/monitoring/components/variables_section.vue b/app/assets/javascripts/monitoring/components/variables_section.vue
index a67bc62e196..6d08bb4f219 100644
--- a/app/assets/javascripts/monitoring/components/variables_section.vue
+++ b/app/assets/javascripts/monitoring/components/variables_section.vue
@@ -12,14 +12,14 @@ export default {
...mapState('monitoringDashboard', ['promVariables']),
},
methods: {
- ...mapActions('monitoringDashboard', ['fetchDashboardData', 'setVariableData']),
+ ...mapActions('monitoringDashboard', ['fetchDashboardData', 'setVariableValues']),
refreshDashboard(event) {
const { name, value } = event.target;
if (this.promVariables[name] !== value) {
const changedVariable = { [name]: value };
- this.setVariableData(changedVariable);
+ this.setVariableValues(changedVariable);
updateHistory({
url: mergeUrlParams(this.promVariables, window.location.href),
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index c2c1ceab312..3d2cabfd978 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -14,7 +14,7 @@ export default (props = {}) => {
if (el && el.dataset) {
const [currentDashboard] = getParameterValues('dashboard');
- store.dispatch('monitoringDashboard/setVariables', promCustomVariablesFromUrl());
+ store.dispatch('monitoringDashboard/setVariableValues', promCustomVariablesFromUrl());
// eslint-disable-next-line no-new
new Vue({
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 4481395cbbd..7df18f5d6d7 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -77,7 +77,7 @@ export const setTimeRange = ({ commit }, timeRange) => {
};
export const setVariables = ({ commit }, variables) => {
- commit(types.SET_PROM_QUERY_VARIABLES, variables);
+ commit(types.SET_VARIABLES, variables);
};
export const filterEnvironments = ({ commit, dispatch }, searchTerm) => {
@@ -413,8 +413,8 @@ export const duplicateSystemDashboard = ({ state }, payload) => {
// Variables manipulation
-export const setVariableData = ({ commit }, updatedVariable) => {
- commit(types.UPDATE_VARIABLE_DATA, updatedVariable);
+export const setVariableValues = ({ commit }, updatedVariable) => {
+ commit(types.UPDATE_VARIABLE_VALUES, updatedVariable);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index dc78e50476e..d60334609fd 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -2,8 +2,8 @@
export const REQUEST_METRICS_DASHBOARD = 'REQUEST_METRICS_DASHBOARD';
export const RECEIVE_METRICS_DASHBOARD_SUCCESS = 'RECEIVE_METRICS_DASHBOARD_SUCCESS';
export const RECEIVE_METRICS_DASHBOARD_FAILURE = 'RECEIVE_METRICS_DASHBOARD_FAILURE';
-export const SET_PROM_QUERY_VARIABLES = 'SET_PROM_QUERY_VARIABLES';
-export const UPDATE_VARIABLE_DATA = 'UPDATE_VARIABLE_DATA';
+export const SET_VARIABLES = 'SET_VARIABLES';
+export const UPDATE_VARIABLE_VALUES = 'UPDATE_VARIABLE_VALUES';
export const REQUEST_DASHBOARD_STARRING = 'REQUEST_DASHBOARD_STARRING';
export const RECEIVE_DASHBOARD_STARRING_SUCCESS = 'RECEIVE_DASHBOARD_STARRING_SUCCESS';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index ec519ee4576..c5db94cb267 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -188,13 +188,14 @@ export default {
state.expandedPanel.group = group;
state.expandedPanel.panel = panel;
},
- [types.SET_PROM_QUERY_VARIABLES](state, variables) {
+ [types.SET_VARIABLES](state, variables) {
state.promVariables = variables;
},
- [types.UPDATE_VARIABLE_DATA](state, newVariable) {
- Object.assign(state.promVariables, {
- ...state.promVariables,
- ...newVariable,
+ [types.UPDATE_VARIABLE_VALUES](state, newVariable) {
+ Object.keys(newVariable).forEach(key => {
+ if (Object.prototype.hasOwnProperty.call(state.promVariables, key)) {
+ state.promVariables[key] = newVariable[key];
+ }
});
},
};
diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js
index 3dc88fa56fc..c92b42fefad 100644
--- a/app/assets/javascripts/monitoring/stores/utils.js
+++ b/app/assets/javascripts/monitoring/stores/utils.js
@@ -244,7 +244,10 @@ export const addPrefixToLabels = label => `${VARIABLE_PREFIX}${label}`;
* Before the templating variables are passed to the backend the
* prefix needs to be removed.
*
+ * This method removes the prefix at the beginning of the string.
+ *
* @param {String} label label to remove prefix from
* @returns {String}
*/
-export const removePrefixFromLabels = label => label.replace(VARIABLE_PREFIX, '');
+export const removePrefixFromLabels = label =>
+ (label || '').replace(new RegExp(`^${VARIABLE_PREFIX}`), '');
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index a13f8ac65cf..010fc9a5d1a 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -121,9 +121,8 @@ export default {
:href="commit.webUrl"
:class="{ 'font-italic': !commit.message }"
class="commit-row-message item-title"
- >
- {{ commit.title }}
- </gl-link>
+ v-html="commit.titleHtml"
+ />
<gl-deprecated-button
v-if="commit.description"
:class="{ open: showDescription }"
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index f741a6df5d9..34424121390 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -167,9 +167,8 @@ export default {
:href="commit.commitPath"
:title="commit.message"
class="str-truncated-100 tree-commit-link"
- >
- {{ commit.message }}
- </gl-link>
+ v-html="commit.titleHtml"
+ />
<gl-skeleton-loading v-else :lines="1" class="h-auto" />
</td>
<td class="tree-time-ago text-right cursor-default">
diff --git a/app/assets/javascripts/repository/queries/commit.fragment.graphql b/app/assets/javascripts/repository/queries/commit.fragment.graphql
index 9bb13c475c7..be6897b9a16 100644
--- a/app/assets/javascripts/repository/queries/commit.fragment.graphql
+++ b/app/assets/javascripts/repository/queries/commit.fragment.graphql
@@ -1,6 +1,7 @@
fragment TreeEntryCommit on LogTreeCommit {
sha
message
+ titleHtml
committedDate
commitPath
fileName
diff --git a/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
index a22cadf0e8d..f54f09fd647 100644
--- a/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
+++ b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
@@ -5,6 +5,7 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
lastCommit {
sha
title
+ titleHtml
description
message
webUrl
diff --git a/app/assets/javascripts/repository/utils/commit.js b/app/assets/javascripts/repository/utils/commit.js
index 3973798605d..90ac01c5874 100644
--- a/app/assets/javascripts/repository/utils/commit.js
+++ b/app/assets/javascripts/repository/utils/commit.js
@@ -3,6 +3,7 @@ export function normalizeData(data, path, extra = () => {}) {
return data.map(d => ({
sha: d.commit.id,
message: d.commit.message,
+ titleHtml: d.commit_title_html,
committedDate: d.commit.committed_date,
commitPath: d.commit_path,
fileName: d.file_name,
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
index 2f5e5f35064..3f8b8cea256 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
@@ -24,6 +24,11 @@ export default {
required: false,
default: '',
},
+ commitSha: {
+ type: String,
+ required: false,
+ default: '',
+ },
projectPath: {
type: String,
required: false,
@@ -62,6 +67,7 @@ export default {
:file-size="fileSize"
:project-path="projectPath"
:content="content"
+ :commit-sha="commitSha"
/>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
index eb3e489fb8c..cc45ad0e5ca 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
@@ -16,6 +16,11 @@ export default {
type: String,
required: true,
},
+ commitSha: {
+ type: String,
+ required: false,
+ default: '',
+ },
filePath: {
type: String,
required: false,
@@ -55,6 +60,9 @@ export default {
text: this.content,
path: this.filePath,
};
+ if (this.commitSha) {
+ postBody.ref = this.commitSha;
+ }
const postOptions = {
cancelToken: axiosSource.token,
};
diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
index 37998f8aa97..07748482204 100644
--- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
@@ -209,6 +209,7 @@ export default {
<gl-dropdown-item
v-for="(option, index) in options"
:key="index"
+ data-qa-selector="quick_range_item"
:active="isOptionActive(option)"
active-class="active"
@click="setQuickRange(option)"
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js
index 3e8f3dd548f..457f1806452 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js
@@ -1,23 +1,31 @@
+import { __ } from '~/locale';
+import { generateToolbarItem } from './toolbar_service';
+
+/* eslint-disable @gitlab/require-i18n-strings */
+const TOOLBAR_ITEM_CONFIGS = [
+ { icon: 'heading', event: 'openHeadingSelect', classes: 'tui-heading', tooltip: __('Headings') },
+ { icon: 'bold', command: 'Bold', tooltip: __('Add bold text') },
+ { icon: 'italic', command: 'Italic', tooltip: __('Add italic text') },
+ { icon: 'strikethrough', command: 'Strike', tooltip: __('Add strikethrough text') },
+ { isDivider: true },
+ { icon: 'quote', command: 'Blockquote', tooltip: __('Insert a quote') },
+ { icon: 'link', event: 'openPopupAddLink', tooltip: __('Add a link') },
+ { icon: 'doc-code', command: 'CodeBlock', tooltip: __('Insert a code block') },
+ { isDivider: true },
+ { icon: 'list-bulleted', command: 'UL', tooltip: __('Add a bullet list') },
+ { icon: 'list-numbered', command: 'OL', tooltip: __('Add a numbered list') },
+ { icon: 'list-task', command: 'Task', tooltip: __('Add a task list') },
+ { icon: 'list-indent', command: 'Indent', tooltip: __('Indent') },
+ { icon: 'list-outdent', command: 'Outdent', tooltip: __('Outdent') },
+ { isDivider: true },
+ { icon: 'dash', command: 'HR', tooltip: __('Add a line') },
+ { icon: 'table', event: 'openPopupAddTable', classes: 'tui-table', tooltip: __('Add a table') },
+ { isDivider: true },
+ { icon: 'code', command: 'Code', tooltip: __('Insert inline code') },
+];
+
export const EDITOR_OPTIONS = {
- toolbarItems: [
- 'heading',
- 'bold',
- 'italic',
- 'strike',
- 'divider',
- 'quote',
- 'link',
- 'codeblock',
- 'divider',
- 'ul',
- 'ol',
- 'task',
- 'divider',
- 'hr',
- 'table',
- 'divider',
- 'code',
- ],
+ toolbarItems: TOOLBAR_ITEM_CONFIGS.map(config => generateToolbarItem(config)),
};
export const EDITOR_TYPES = {
@@ -25,3 +33,5 @@ export const EDITOR_TYPES = {
};
export const EDITOR_HEIGHT = '100%';
+
+export const EDITOR_PREVIEW_STYLE = 'horizontal';
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue b/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue
index 0b10424ad1e..ba3696c8ad1 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue
@@ -2,7 +2,7 @@
import 'codemirror/lib/codemirror.css';
import '@toast-ui/editor/dist/toastui-editor.css';
-import { EDITOR_OPTIONS, EDITOR_TYPES, EDITOR_HEIGHT } from './constants';
+import { EDITOR_OPTIONS, EDITOR_TYPES, EDITOR_HEIGHT, EDITOR_PREVIEW_STYLE } from './constants';
export default {
components: {
@@ -31,6 +31,11 @@ export default {
required: false,
default: EDITOR_HEIGHT,
},
+ previewStyle: {
+ type: String,
+ required: false,
+ default: EDITOR_PREVIEW_STYLE,
+ },
},
computed: {
editorOptions() {
@@ -52,6 +57,7 @@ export default {
ref="editor"
:initial-value="value"
:options="editorOptions"
+ :preview-style="previewStyle"
:initial-edit-type="initialEditType"
:height="height"
@change="onContentChanged"
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue b/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue
new file mode 100644
index 00000000000..58aaeef45f2
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue
@@ -0,0 +1,20 @@
+<script>
+import { GlIcon } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlIcon,
+ },
+ props: {
+ icon: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+<template>
+ <button class="p-0 gl-display-flex toolbar-button">
+ <gl-icon class="gl-mx-auto" :name="icon" />
+ </button>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_service.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_service.js
new file mode 100644
index 00000000000..fff90f3e3fb
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_service.js
@@ -0,0 +1,32 @@
+import Vue from 'vue';
+import ToolbarItem from './toolbar_item.vue';
+
+const buildWrapper = propsData => {
+ const instance = new Vue({
+ render(createElement) {
+ return createElement(ToolbarItem, propsData);
+ },
+ });
+
+ instance.$mount();
+ return instance.$el;
+};
+
+// eslint-disable-next-line import/prefer-default-export
+export const generateToolbarItem = config => {
+ const { icon, classes, event, command, tooltip, isDivider } = config;
+
+ if (isDivider) {
+ return 'divider';
+ }
+
+ return {
+ type: 'button',
+ options: {
+ el: buildWrapper({ props: { icon }, class: classes }),
+ event,
+ command,
+ tooltip,
+ },
+ };
+};
diff --git a/app/assets/stylesheets/components/rich_content_editor.scss b/app/assets/stylesheets/components/rich_content_editor.scss
new file mode 100644
index 00000000000..eca0f1114af
--- /dev/null
+++ b/app/assets/stylesheets/components/rich_content_editor.scss
@@ -0,0 +1,11 @@
+// Overrides styles from ToastUI editor
+.tui-editor-defaultUI-toolbar .toolbar-button {
+ color: $gl-gray-600;
+ border: 0;
+
+ &:hover,
+ &:active {
+ color: $blue-500;
+ border: 0;
+ }
+}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 1422959a10a..93361c21642 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -495,7 +495,8 @@ img.emoji {
🚨 Do not use these classes — they are deprecated and being removed. 🚨
See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details.
- Instead, if you need a spacing class, add it below using the following values.
+ Instead, if you need a spacing class, please use one from Gitlab UI —
+ https://unpkg.com/browse/@gitlab/ui/src/scss/utilities.scss — which uses the following scale.
$gl-spacing-scale-0: 0;
$gl-spacing-scale-1: 2px;
$gl-spacing-scale-2: 4px;
@@ -510,14 +511,6 @@ img.emoji {
$gl-spacing-scale-11: 64px;
$gl-spacing-scale-12: 80px;
$gl-spacing-scale-13: 96px;
-
- E.g., a padding top of 96px can be added using:
- .gl-shim-pt-13 {
- padding-top: 96px;
- }
-
- Please use -shim- so it can be differentiated from the old scale classes.
- These will be replaced when the Gitlab UI utilities are included.
**/
@each $index, $padding in $spacing-scale {
#{'.gl-p-#{$index}-deprecated-no-really-do-not-use-me'} { padding: $padding; }
diff --git a/app/controllers/concerns/preview_markdown.rb b/app/controllers/concerns/preview_markdown.rb
index c7c9f2e9b70..ba15d611c0d 100644
--- a/app/controllers/concerns/preview_markdown.rb
+++ b/app/controllers/concerns/preview_markdown.rb
@@ -37,7 +37,7 @@ module PreviewMarkdown
when 'groups' then { group: group }
when 'projects' then projects_filter_params
else {}
- end.merge(requested_path: params[:path])
+ end.merge(requested_path: params[:path], ref: params[:ref])
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/record_user_last_activity.rb b/app/controllers/concerns/record_user_last_activity.rb
index 4013596ba12..29164df4516 100644
--- a/app/controllers/concerns/record_user_last_activity.rb
+++ b/app/controllers/concerns/record_user_last_activity.rb
@@ -17,7 +17,6 @@ module RecordUserLastActivity
def set_user_last_activity
return unless request.get?
- return unless Feature.enabled?(:set_user_last_activity, default_enabled: true)
return if Gitlab::Database.read_only?
if current_user && current_user.last_activity_on != Date.today
diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb
index d8113c39351..e78723bdda2 100644
--- a/app/controllers/concerns/snippets_actions.rb
+++ b/app/controllers/concerns/snippets_actions.rb
@@ -65,11 +65,12 @@ module SnippetsActions
params[:line_ending] == 'raw' ? content : content.gsub(/\r\n/, "\n")
end
- def check_repository_error
- repository_errors = Array(snippet.errors.delete(:repository))
+ def handle_repository_error(action)
+ errors = Array(snippet.errors.delete(:repository))
- flash.now[:alert] = repository_errors.first if repository_errors.present?
- recaptcha_check_with_fallback(repository_errors.empty?) { render :edit }
+ flash.now[:alert] = errors.first if errors.present?
+
+ recaptcha_check_with_fallback(errors.empty?) { render action }
end
def redirect_if_binary
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 69253b55188..fcbeb5c840c 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -45,7 +45,8 @@ class Projects::RefsController < Projects::ApplicationController
def logs_tree
tree_summary = ::Gitlab::TreeSummary.new(
- @commit, @project, path: @path, offset: params[:offset], limit: 25)
+ @commit, @project, current_user,
+ path: @path, offset: params[:offset], limit: 25)
respond_to do |format|
format.html { render_404 }
@@ -60,10 +61,8 @@ class Projects::RefsController < Projects::ApplicationController
# Deprecated due to https://gitlab.com/gitlab-org/gitlab/-/issues/36863
# Will be removed soon https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29895
format.js do
- @logs, commits = tree_summary.summarize
+ @logs, _ = tree_summary.summarize
@more_log_url = more_url(tree_summary.next_offset) if tree_summary.more?
-
- prerender_commit_full_titles!(commits)
end
end
end
@@ -74,14 +73,6 @@ class Projects::RefsController < Projects::ApplicationController
logs_file_project_ref_path(@project, @ref, @path, offset: offset)
end
- def prerender_commit_full_titles!(commits)
- # Preload commit authors as they are used in rendering
- commits.each(&:lazy_author)
-
- renderer = Banzai::ObjectRenderer.new(user: current_user, default_project: @project)
- renderer.render(commits, :full_title)
- end
-
def validate_ref_id
return not_found! if params[:id].present? && params[:id] !~ Gitlab::PathRegex.git_reference_regex
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index da0e3a44f05..9233f063f55 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -52,15 +52,8 @@ class Projects::SnippetsController < Projects::ApplicationController
create_params = snippet_params.merge(spammable_params)
service_response = Snippets::CreateService.new(project, current_user, create_params).execute
@snippet = service_response.payload[:snippet]
- repository_operation_error = service_response.error? && !@snippet.persisted? && @snippet.valid?
- if repository_operation_error
- flash.now[:alert] = service_response.message
-
- render :new
- else
- recaptcha_check_with_fallback { render :new }
- end
+ handle_repository_error(:new)
end
def update
@@ -69,7 +62,7 @@ class Projects::SnippetsController < Projects::ApplicationController
service_response = Snippets::UpdateService.new(project, current_user, update_params).execute(@snippet)
@snippet = service_response.payload[:snippet]
- check_repository_error
+ handle_repository_error(:edit)
end
def show
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index a07baa1a045..e877f3c7a54 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -52,12 +52,9 @@ class SnippetsController < ApplicationController
create_params = snippet_params.merge(spammable_params)
service_response = Snippets::CreateService.new(nil, current_user, create_params).execute
@snippet = service_response.payload[:snippet]
- repository_operation_error = service_response.error? && !@snippet.persisted? && @snippet.valid?
- if repository_operation_error
- flash.now[:alert] = service_response.message
-
- render :new
+ if service_response.error? && @snippet.errors[:repository].present?
+ handle_repository_error(:new)
else
move_temporary_files if @snippet.valid? && params[:files]
@@ -71,7 +68,7 @@ class SnippetsController < ApplicationController
service_response = Snippets::UpdateService.new(nil, current_user, update_params).execute(@snippet)
@snippet = service_response.payload[:snippet]
- check_repository_error
+ handle_repository_error(:edit)
end
def show
diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb
index aaf2dfd8488..be5165da545 100644
--- a/app/graphql/types/commit_type.rb
+++ b/app/graphql/types/commit_type.rb
@@ -14,6 +14,7 @@ module Types
description: 'SHA1 ID of the commit'
field :title, type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true,
description: 'Title of the commit message'
+ markdown_field :title_html, null: true
field :description, type: GraphQL::STRING_TYPE, null: true,
description: 'Description of the commit message'
field :message, type: GraphQL::STRING_TYPE, null: true,
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index df8009c3d00..b9f0e3582df 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -229,14 +229,7 @@ module ApplicationSettingsHelper
:max_artifacts_size,
:max_attachment_size,
:max_pages_size,
- :metrics_enabled,
- :metrics_host,
:metrics_method_call_threshold,
- :metrics_packet_size,
- :metrics_pool_size,
- :metrics_port,
- :metrics_sample_interval,
- :metrics_timeout,
:minimum_password_length,
:mirror_available,
:pages_domain_verification_enabled,
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 5c7c128da90..d677e770b67 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -295,11 +295,11 @@ module ProjectsHelper
end
def show_merge_request_count?(disabled: false, compact_mode: false)
- !disabled && !compact_mode && Feature.enabled?(:project_list_show_mr_count, default_enabled: true)
+ !disabled && !compact_mode
end
def show_issue_count?(disabled: false, compact_mode: false)
- !disabled && !compact_mode && Feature.enabled?(:project_list_show_issue_count, default_enabled: true)
+ !disabled && !compact_mode
end
# overridden in EE
diff --git a/app/models/snippet_repository.rb b/app/models/snippet_repository.rb
index 4fc6e72948a..2276851b7a1 100644
--- a/app/models/snippet_repository.rb
+++ b/app/models/snippet_repository.rb
@@ -44,6 +44,9 @@ class SnippetRepository < ApplicationRecord
Gitlab::Git::PreReceiveError,
Gitlab::Git::CommandError,
ArgumentError => error
+
+ logger.error(message: "Snippet git error. Reason: #{error.message}", snippet: snippet.id)
+
raise commit_error_exception(error)
end
@@ -91,7 +94,7 @@ class SnippetRepository < ApplicationRecord
def commit_error_exception(err)
if invalid_path_error?(err)
- InvalidPathError.new('Invalid Path') # To avoid returning the message with the path included
+ InvalidPathError.new('Invalid file name') # To avoid returning the message with the path included
elsif invalid_signature_error?(err)
InvalidSignatureError.new(err.message)
else
diff --git a/app/models/user.rb b/app/models/user.rb
index 365e3cd713d..a469beaaed2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -65,8 +65,7 @@ class User < ApplicationRecord
MINIMUM_INACTIVE_DAYS = 180
- ignore_column :bot_type, remove_with: '12.11', remove_after: '2020-04-22'
-
+ ignore_column :bot_type, remove_with: '13.1', remove_after: '2020-05-22'
ignore_column :ghost, remove_with: '13.2', remove_after: '2020-06-22'
# Override Devise::Models::Trackable#update_tracked_fields!
diff --git a/app/services/snippets/base_service.rb b/app/services/snippets/base_service.rb
index 2b450db0b83..c8215e79c56 100644
--- a/app/services/snippets/base_service.rb
+++ b/app/services/snippets/base_service.rb
@@ -11,5 +11,22 @@ module Snippets
payload: { snippet: snippet }
)
end
+
+ def add_snippet_repository_error(snippet:, error:)
+ message = repository_error_message(error)
+
+ snippet.errors.add(:repository, message)
+ end
+
+ def repository_error_message(error)
+ message = self.is_a?(Snippets::CreateService) ? _("Error creating the snippet") : _("Error updating the snippet")
+
+ # We only want to include additional error detail in the message
+ # if the error is not a CommitError because we cannot guarantee the message
+ # will be user-friendly
+ message += " - #{error.message}" unless error.instance_of?(SnippetRepository::CommitError)
+
+ message
+ end
end
end
diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb
index 8d5568e1b1e..2e2fdd5993f 100644
--- a/app/services/snippets/create_service.rb
+++ b/app/services/snippets/create_service.rb
@@ -60,7 +60,7 @@ module Snippets
@snippet = @snippet.dup
end
- @snippet.errors.add(:base, e.message)
+ add_snippet_repository_error(snippet: @snippet, error: e)
false
end
diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb
index af46f965c7b..259fe09b02f 100644
--- a/app/services/snippets/update_service.rb
+++ b/app/services/snippets/update_service.rb
@@ -54,7 +54,8 @@ module Snippets
snippet.save
end
- snippet.errors.add(:repository, 'Error updating the snippet')
+ add_snippet_repository_error(snippet: snippet, error: e)
+
log_error(e.message)
# If the commit action failed we remove it because
diff --git a/app/views/admin/application_settings/_influx.html.haml b/app/views/admin/application_settings/_influx.html.haml
deleted file mode 100644
index 300b01c6777..00000000000
--- a/app/views/admin/application_settings/_influx.html.haml
+++ /dev/null
@@ -1,60 +0,0 @@
-= form_for @application_setting, url: metrics_and_profiling_admin_application_settings_path(anchor: 'js-influx-settings'), html: { class: 'fieldset-form' } do |f|
- = form_errors(@application_setting)
-
- %fieldset
- %p
- Set up InfluxDB to measure a wide variety of statistics like the time spent
- in running SQL queries. These settings require a
- = link_to 'restart', help_page_path('administration/restart_gitlab')
- to take effect.
- = link_to icon('question-circle'), help_page_path('administration/monitoring/performance/index')
- .form-group
- .form-check
- = f.check_box :metrics_enabled, class: 'form-check-input'
- = f.label :metrics_enabled, class: 'form-check-label' do
- Enable InfluxDB Metrics
- .form-group
- = f.label :metrics_host, 'InfluxDB host', class: 'label-bold'
- = f.text_field :metrics_host, class: 'form-control', placeholder: 'influxdb.example.com'
- .form-group
- = f.label :metrics_port, 'InfluxDB port', class: 'label-bold'
- = f.text_field :metrics_port, class: 'form-control', placeholder: '8089'
- .form-text.text-muted
- The UDP port to use for connecting to InfluxDB. InfluxDB requires that
- your server configuration specifies a database to store data in when
- sending messages to this port, without it metrics data will not be
- saved.
- .form-group
- = f.label :metrics_pool_size, 'Connection pool size', class: 'label-bold'
- = f.number_field :metrics_pool_size, class: 'form-control'
- .form-text.text-muted
- The amount of InfluxDB connections to open. Connections are opened
- lazily. Users using multi-threaded application servers should ensure
- enough connections are available (at minimum the amount of application
- server threads).
- .form-group
- = f.label :metrics_timeout, 'Connection timeout', class: 'label-bold'
- = f.number_field :metrics_timeout, class: 'form-control'
- .form-text.text-muted
- The amount of seconds after which an InfluxDB connection will time
- out.
- .form-group
- = f.label :metrics_method_call_threshold, 'Method Call Threshold (ms)', class: 'label-bold'
- = f.number_field :metrics_method_call_threshold, class: 'form-control'
- .form-text.text-muted
- A method call is only tracked when it takes longer to complete than
- the given amount of milliseconds.
- .form-group
- = f.label :metrics_sample_interval, 'Sampler Interval (sec)', class: 'label-bold'
- = f.number_field :metrics_sample_interval, class: 'form-control'
- .form-text.text-muted
- The sampling interval in seconds. Sampled data includes memory usage,
- retained Ruby objects, file descriptors and so on.
- .form-group
- = f.label :metrics_packet_size, 'Metrics per packet', class: 'label-bold'
- = f.number_field :metrics_packet_size, class: 'form-control'
- .form-text.text-muted
- The amount of points to store in a single UDP packet. More points
- results in fewer but larger UDP packets being sent.
-
- = f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/admin/application_settings/_prometheus.html.haml b/app/views/admin/application_settings/_prometheus.html.haml
index 4c0ff3a18e8..b2ec25cdf8d 100644
--- a/app/views/admin/application_settings/_prometheus.html.haml
+++ b/app/views/admin/application_settings/_prometheus.html.haml
@@ -23,5 +23,11 @@
%code prometheus_multiproc_dir
does not exist or is not pointing to a valid directory.
= link_to icon('question-circle'), help_page_path('administration/monitoring/prometheus/gitlab_metrics', anchor: 'metrics-shared-directory')
+ .form-group
+ = f.label :metrics_method_call_threshold, 'Method Call Threshold (ms)', class: 'label-bold'
+ = f.number_field :metrics_method_call_threshold, class: 'form-control'
+ .form-text.text-muted
+ A method call is only tracked when it takes longer to complete than
+ the given amount of milliseconds.
= f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml
index 6a703d0b70c..befe10ea510 100644
--- a/app/views/admin/application_settings/metrics_and_profiling.html.haml
+++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml
@@ -2,17 +2,6 @@
- page_title _("Metrics and profiling")
- @content_class = "limit-container-width" unless fluid_layout
-%section.settings.as-influx.no-animate#js-influx-settings{ class: ('expanded' if expanded_by_default?) }
- .settings-header
- %h4
- = _('Metrics - Influx')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded_by_default? ? _('Collapse') : _('Expand')
- %p
- = _('Enable and configure InfluxDB metrics.')
- .settings-content
- = render 'influx'
-
%section.settings.as-prometheus.no-animate#js-prometheus-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
diff --git a/app/views/projects/services/prometheus/_custom_metrics.html.haml b/app/views/projects/services/prometheus/_custom_metrics.html.haml
index 21f9d1125e0..210d0f37d65 100644
--- a/app/views/projects/services/prometheus/_custom_metrics.html.haml
+++ b/app/views/projects/services/prometheus/_custom_metrics.html.haml
@@ -6,14 +6,14 @@
= link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus', anchor: 'adding-custom-metrics'), target: '_blank', rel: "noopener noreferrer"
.col-lg-9
- .card.custom-monitored-metrics.js-panel-custom-monitored-metrics{ data: { active_custom_metrics: project_prometheus_metrics_path(project), environments_data: environments_list_data, service_active: "#{@service.active}" } }
+ .card.custom-monitored-metrics.js-panel-custom-monitored-metrics{ data: { qa_selector: 'custom_metrics_container', active_custom_metrics: project_prometheus_metrics_path(project), environments_data: environments_list_data, service_active: "#{@service.active}" } }
.card-header
%strong
= s_('PrometheusService|Custom metrics')
-# haml-lint:disable NoPlainNodes
%span.badge.badge-pill.js-custom-monitored-count 0
-# haml-lint:enable NoPlainNodes
- = link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn btn-success js-new-metric-button hidden'
+ = link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn btn-success js-new-metric-button hidden', data: { qa_selector: 'new_metric_button' }
.card-body
.flash-container.hidden
.flash-warning
diff --git a/changelogs/unreleased/14108-instance-level-ci-variables-api.yml b/changelogs/unreleased/14108-instance-level-ci-variables-api.yml
new file mode 100644
index 00000000000..3c4288d2a5d
--- /dev/null
+++ b/changelogs/unreleased/14108-instance-level-ci-variables-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add API CRUD actions for instance-level CI/CD variables
+merge_request: 31342
+author:
+type: added
diff --git a/changelogs/unreleased/208897-remove-bot-type-column.yml b/changelogs/unreleased/208897-remove-bot-type-column.yml
new file mode 100644
index 00000000000..109fedca0e0
--- /dev/null
+++ b/changelogs/unreleased/208897-remove-bot-type-column.yml
@@ -0,0 +1,5 @@
+---
+title: Remove obsolete bot_type column
+merge_request: 27076
+author:
+type: other
diff --git a/changelogs/unreleased/214382-remove-project_list_show_issue_count-feature-flag.yml b/changelogs/unreleased/214382-remove-project_list_show_issue_count-feature-flag.yml
new file mode 100644
index 00000000000..463e697d344
--- /dev/null
+++ b/changelogs/unreleased/214382-remove-project_list_show_issue_count-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove project_list_show_issue_count feature flag.
+merge_request: 31793
+author: Gilang Gumilar
+type: removed
diff --git a/changelogs/unreleased/214382-remove-project_list_show_mr_count-feature-flag.yml b/changelogs/unreleased/214382-remove-project_list_show_mr_count-feature-flag.yml
new file mode 100644
index 00000000000..459d6342680
--- /dev/null
+++ b/changelogs/unreleased/214382-remove-project_list_show_mr_count-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove project_list_show_mr_count feature flag.
+merge_request: 31789
+author: Gilang Gumilar
+type: removed
diff --git a/changelogs/unreleased/214382-remove-set_user_last_activity-feature-flag.yml b/changelogs/unreleased/214382-remove-set_user_last_activity-feature-flag.yml
new file mode 100644
index 00000000000..1d3b40fe227
--- /dev/null
+++ b/changelogs/unreleased/214382-remove-set_user_last_activity-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove set_user_last_activity feature flag.
+merge_request: 31795
+author: Gilang Gumilar
+type: removed
diff --git a/changelogs/unreleased/25375-webide-markdown-broken-images.yml b/changelogs/unreleased/25375-webide-markdown-broken-images.yml
new file mode 100644
index 00000000000..6ec333116e8
--- /dev/null
+++ b/changelogs/unreleased/25375-webide-markdown-broken-images.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issue with broken images in Web IDE markdown
+merge_request: 31638
+author:
+type: fixed
diff --git a/changelogs/unreleased/dblessing-scim-identitites-new-user-flow.yml b/changelogs/unreleased/dblessing-scim-identitites-new-user-flow.yml
new file mode 100644
index 00000000000..49e92dd85d0
--- /dev/null
+++ b/changelogs/unreleased/dblessing-scim-identitites-new-user-flow.yml
@@ -0,0 +1,5 @@
+---
+title: Fix regression and allow SCIM to create SAML identity
+merge_request: 31238
+author:
+type: fixed
diff --git a/changelogs/unreleased/dbodicherla-update-urls-params-only-update-existing-variables.yml b/changelogs/unreleased/dbodicherla-update-urls-params-only-update-existing-variables.yml
new file mode 100644
index 00000000000..78f6e6df8e6
--- /dev/null
+++ b/changelogs/unreleased/dbodicherla-update-urls-params-only-update-existing-variables.yml
@@ -0,0 +1,6 @@
+---
+title: URL params in the monitoring dashboard update variable values defined in yml
+ file
+merge_request: 31662
+author:
+type: changed
diff --git a/changelogs/unreleased/fix-broken-heading-of-vue-3-migration-guide-doc.yml b/changelogs/unreleased/fix-broken-heading-of-vue-3-migration-guide-doc.yml
new file mode 100644
index 00000000000..4e8fc37bea0
--- /dev/null
+++ b/changelogs/unreleased/fix-broken-heading-of-vue-3-migration-guide-doc.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken heading of Vue 3 migration guide doc
+merge_request: 31951
+author: Gilang Gumilar
+type: fixed
diff --git a/changelogs/unreleased/ph-212669-commitTypeMarkdownHTML.yml b/changelogs/unreleased/ph-212669-commitTypeMarkdownHTML.yml
new file mode 100644
index 00000000000..e60bbc0a3e6
--- /dev/null
+++ b/changelogs/unreleased/ph-212669-commitTypeMarkdownHTML.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes commit message emojis not rendering in Vue file list
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/rc-remove_influx_views_docs.yml b/changelogs/unreleased/rc-remove_influx_views_docs.yml
new file mode 100644
index 00000000000..233ea92ad5d
--- /dev/null
+++ b/changelogs/unreleased/rc-remove_influx_views_docs.yml
@@ -0,0 +1,5 @@
+---
+title: Remove deprecated InfluxDB
+merge_request: 30786
+author:
+type: removed
diff --git a/changelogs/unreleased/vij-snippet-create-update-errors.yml b/changelogs/unreleased/vij-snippet-create-update-errors.yml
new file mode 100644
index 00000000000..36714435da3
--- /dev/null
+++ b/changelogs/unreleased/vij-snippet-create-update-errors.yml
@@ -0,0 +1,5 @@
+---
+title: Modify Snippet git path errors to be more helpful
+merge_request: 31333
+author:
+type: changed
diff --git a/config/pseudonymizer.yml b/config/pseudonymizer.yml
index 195506ac4a1..e9d5fd5623f 100644
--- a/config/pseudonymizer.yml
+++ b/config/pseudonymizer.yml
@@ -469,7 +469,6 @@ tables:
- last_activity_on
- notified_of_own_activity
- user_type
- - bot_type
- preferred_language
- theme_id
diff --git a/db/post_migrate/20200506154421_migrate_scim_identities_to_saml_for_new_users.rb b/db/post_migrate/20200506154421_migrate_scim_identities_to_saml_for_new_users.rb
new file mode 100644
index 00000000000..718e788aad7
--- /dev/null
+++ b/db/post_migrate/20200506154421_migrate_scim_identities_to_saml_for_new_users.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+class MigrateScimIdentitiesToSamlForNewUsers < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ class ScimIdentity < ActiveRecord::Base
+ self.table_name = 'scim_identities'
+
+ belongs_to :user
+
+ include ::EachBatch
+ end
+
+ class Identity < ActiveRecord::Base
+ self.table_name = 'identities'
+
+ belongs_to :saml_provider
+ end
+
+ def up
+ users_with_saml_provider = Identity.select('user_id').joins(:saml_provider)
+
+ ScimIdentity.each_batch do |relation|
+ identity_records = relation
+ .select("scim_identities.extern_uid, 'group_saml', scim_identities.user_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, saml_providers.id")
+ .joins(:user)
+ .joins('inner join saml_providers on saml_providers.group_id=scim_identities.group_id')
+ .where("date_trunc('second',scim_identities.created_at) at time zone 'UTC' = date_trunc('second',users.created_at)")
+ .where.not(user_id: users_with_saml_provider)
+
+ execute "insert into identities (extern_uid, provider, user_id, created_at, updated_at, saml_provider_id) #{identity_records.to_sql} on conflict do nothing"
+ end
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20200508091106_remove_bot_type.rb b/db/post_migrate/20200508091106_remove_bot_type.rb
new file mode 100644
index 00000000000..2afcf5308e7
--- /dev/null
+++ b/db/post_migrate/20200508091106_remove_bot_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class RemoveBotType < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :users, 'index_users_on_bot_type'
+
+ with_lock_retries do
+ remove_column :users, :bot_type
+ end
+ end
+
+ def down
+ unless column_exists?(:users, :bot_type)
+ with_lock_retries do
+ add_column :users, :bot_type, :integer, limit: 2 # rubocop:disable Migration/AddColumnsToWideTables
+ end
+ end
+
+ execute 'UPDATE users set bot_type = user_type WHERE user_type IN(1,2,3,6)'
+
+ add_concurrent_index :users, :bot_type
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index ebaec8eee10..9406b024eee 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -6778,7 +6778,6 @@ CREATE TABLE public.users (
commit_email character varying,
group_view integer,
managing_group_id integer,
- bot_type smallint,
first_name character varying(255),
last_name character varying(255),
static_object_token character varying(255),
@@ -10732,8 +10731,6 @@ CREATE INDEX index_users_on_accepted_term_id ON public.users USING btree (accept
CREATE INDEX index_users_on_admin ON public.users USING btree (admin);
-CREATE INDEX index_users_on_bot_type ON public.users USING btree (bot_type);
-
CREATE UNIQUE INDEX index_users_on_confirmation_token ON public.users USING btree (confirmation_token);
CREATE INDEX index_users_on_created_at ON public.users USING btree (created_at);
@@ -13764,7 +13761,9 @@ COPY "schema_migrations" (version) FROM STDIN;
20200505172405
20200506085748
20200506125731
+20200506154421
20200507221434
+20200508091106
20200511145545
\.
diff --git a/doc/administration/index.md b/doc/administration/index.md
index fdae970a716..cda2852b43b 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -184,8 +184,6 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [GitLab Performance Monitoring](monitoring/performance/index.md):
- [Enable Performance Monitoring](monitoring/performance/gitlab_configuration.md): Enable GitLab Performance Monitoring.
- - [GitLab performance monitoring with InfluxDB](monitoring/performance/influxdb_configuration.md): Configure GitLab and InfluxDB for measuring performance metrics.
- - [InfluxDB Schema](monitoring/performance/influxdb_schema.md): Measurements stored in InfluxDB.
- [GitLab performance monitoring with Prometheus](monitoring/prometheus/index.md): Configure GitLab and Prometheus for measuring performance metrics.
- [GitLab performance monitoring with Grafana](monitoring/performance/grafana_configuration.md): Configure GitLab to visualize time series metrics through graphs and dashboards.
- [Request Profiling](monitoring/performance/request_profiling.md): Get a detailed profile on slow requests.
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index d6b4bdeb50e..d8ec588a37d 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -618,7 +618,7 @@ installations from source.
GraphQL queries are recorded in that file. For example:
```json
-{"query_string":"query IntrospectionQuery{__schema {queryType { name },mutationType { name }}}...(etc)","variables":{"a":1,"b":2},"complexity":181,"depth":1,"duration":7}
+{"query_string":"query IntrospectionQuery{__schema {queryType { name },mutationType { name }}}...(etc)","variables":{"a":1,"b":2},"complexity":181,"depth":1,"duration_s":7}
```
## `migrations.log`
diff --git a/doc/administration/monitoring/performance/gitlab_configuration.md b/doc/administration/monitoring/performance/gitlab_configuration.md
index e8a6c661464..14119a5d8f3 100644
--- a/doc/administration/monitoring/performance/gitlab_configuration.md
+++ b/doc/administration/monitoring/performance/gitlab_configuration.md
@@ -1,17 +1,9 @@
# GitLab Configuration
-CAUTION: **InfluxDB is deprecated in favor of Prometheus:**
-InfluxDB support is scheduled to be removed in GitLab 13.0.
-You are advised to use [Prometheus](../prometheus/index.md) instead.
-
GitLab Performance Monitoring is disabled by default. To enable it and change any of its
settings, navigate to **Admin Area > Settings > Metrics and profiling**
(`/admin/application_settings/metrics_and_profiling`).
-The minimum required settings you need to set are the InfluxDB host and port.
-Make sure _Enable InfluxDB Metrics_ is checked and hit **Save** to save the
-changes.
-
![GitLab Performance Monitoring Admin Settings](img/metrics_gitlab_configuration_settings.png)
Finally, a restart of all GitLab processes is required for the changes to take
@@ -33,6 +25,4 @@ have been performed.
Read more on:
- [Introduction to GitLab Performance Monitoring](index.md)
-- [InfluxDB Configuration](influxdb_configuration.md)
-- [InfluxDB Schema](influxdb_schema.md)
- [Grafana Install/Configuration](grafana_configuration.md)
diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md
index b705e00bc35..3438a564d2f 100644
--- a/doc/administration/monitoring/performance/grafana_configuration.md
+++ b/doc/administration/monitoring/performance/grafana_configuration.md
@@ -1,18 +1,9 @@
# Grafana Configuration
-CAUTION: **InfluxDB is deprecated in favor of Prometheus:**
-InfluxDB support is scheduled to be removed in GitLab 13.0.
-You are advised to use [Prometheus](../prometheus/index.md) instead.
-
[Grafana](https://grafana.com/) is a tool that allows you to visualize time
-series metrics through graphs and dashboards. It supports several backend
-data stores, including InfluxDB. GitLab writes performance data to InfluxDB
+series metrics through graphs and dashboards. GitLab writes performance data to Prometheus
and Grafana will allow you to query to display useful graphs.
-For the easiest installation and configuration, install Grafana on the same
-server as InfluxDB. For larger installations, you may want to split out these
-services.
-
## Installation
[Omnibus GitLab can help you install Grafana (recommended)](https://docs.gitlab.com/omnibus/settings/grafana.html)
@@ -33,49 +24,8 @@ in the top bar.
![Grafana empty data source page](img/grafana_data_source_empty.png)
-Fill in the configuration details for the InfluxDB data source. Save and
-Test Connection to ensure the configuration is correct.
-
-- **Name**: `InfluxDB`
-- **Default**: Checked
-- **Type**: `InfluxDB 0.9.x` (Even if you're using InfluxDB 0.10.x)
-- For the URL, use `https://localhost:8086`, or provide the remote URL if you've installed InfluxDB
- on a separate server
-- **Access**: `proxy`
-- **Database**: `gitlab`
-- **User**: `admin` (Or the username configured when setting up InfluxDB)
-- **Password**: The password configured when you set up InfluxDB
-
![Grafana data source configurations](img/grafana_data_source_configuration.png)
-## Apply retention policies and create continuous queries
-
-If you intend to import the GitLab provided Grafana dashboards, you will need to
-set up the right retention policies and continuous queries. The easiest way of
-doing this is by using the [InfluxDB Management](https://gitlab.com/gitlab-org/influxdb-management)
-repository.
-
-To use this repository you must first clone it:
-
-```shell
-git clone https://gitlab.com/gitlab-org/influxdb-management.git
-cd influxdb-management
-```
-
-Next you must install the required dependencies:
-
-```shell
-gem install bundler
-bundle install
-```
-
-Now you must configure the repository by first copying `.env.example` to `.env`
-and then editing the `.env` file to contain the correct InfluxDB settings. Once
-configured you can simply run `bundle exec rake` and the InfluxDB database will
-be configured for you.
-
-For more information see the [InfluxDB Management README](https://gitlab.com/gitlab-org/influxdb-management/blob/master/README.md).
-
## Import Dashboards
You can now import a set of default dashboards that will give you a good
@@ -164,5 +114,3 @@ Read more on:
- [Introduction to GitLab Performance Monitoring](index.md)
- [GitLab Configuration](gitlab_configuration.md)
-- [InfluxDB Installation/Configuration](influxdb_configuration.md)
-- [InfluxDB Schema](influxdb_schema.md)
diff --git a/doc/administration/monitoring/performance/index.md b/doc/administration/monitoring/performance/index.md
index 3305ea33f2e..02070287611 100644
--- a/doc/administration/monitoring/performance/index.md
+++ b/doc/administration/monitoring/performance/index.md
@@ -1,9 +1,5 @@
# GitLab Performance Monitoring
-CAUTION: **InfluxDB is deprecated in favor of Prometheus:**
-InfluxDB support is scheduled to be removed in GitLab 13.0.
-You are advised to use [Prometheus](../prometheus/index.md) instead.
-
GitLab comes with its own application performance measuring system as of GitLab
8.4, simply called "GitLab Performance Monitoring". GitLab Performance Monitoring is available in both the
Community and Enterprise editions.
@@ -12,17 +8,11 @@ Apart from this introduction, you are advised to read through the following
documents in order to understand and properly configure GitLab Performance Monitoring:
- [GitLab Configuration](gitlab_configuration.md)
-- [InfluxDB Install/Configuration](influxdb_configuration.md)
-- [InfluxDB Schema](influxdb_schema.md)
+- [Prometheus documentation](../prometheus/index.md)
- [Grafana Install/Configuration](grafana_configuration.md)
- [Performance bar](performance_bar.md)
- [Request profiling](request_profiling.md)
-NOTE: **Note:**
-Omnibus GitLab 8.16 includes Prometheus as an additional tool to collect
-metrics. It will eventually replace InfluxDB when their metrics collection is
-on par. Read more in the [Prometheus documentation](../prometheus/index.md).
-
## Introduction to GitLab Performance Monitoring
GitLab Performance Monitoring makes it possible to measure a wide variety of statistics
@@ -35,12 +25,6 @@ including (but not limited to):
- System statistics such as the process' memory usage and open file descriptors.
- Ruby garbage collection statistics.
-Metrics data is written to [InfluxDB](https://www.influxdata.com/products/influxdb-overview/)
-over [UDP](https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/).
-Stored data can be visualized using [Grafana](https://grafana.com) or any other application that
-supports reading data from InfluxDB. Alternatively data can be queried using the
-InfluxDB CLI.
-
## Metric Types
Two types of metrics are collected:
diff --git a/doc/administration/monitoring/performance/influxdb_configuration.md b/doc/administration/monitoring/performance/influxdb_configuration.md
index 8478272897b..d793e014a18 100644
--- a/doc/administration/monitoring/performance/influxdb_configuration.md
+++ b/doc/administration/monitoring/performance/influxdb_configuration.md
@@ -1,191 +1,5 @@
-# InfluxDB Configuration
-
-CAUTION: **InfluxDB is deprecated in favor of Prometheus:**
-InfluxDB support is scheduled to be removed in GitLab 13.0.
-You are advised to use [Prometheus](../prometheus/index.md) instead.
-
-The default settings provided by [InfluxDB](https://www.influxdata.com/products/influxdb-overview/)
-are not sufficient for a high traffic GitLab environment. The settings discussed in
-this document are based on the settings GitLab uses for GitLab.com. Depending on
-your own needs, you may need to further adjust them.
-
-If you are intending to run InfluxDB on the same server as GitLab, make sure
-you have plenty of RAM since InfluxDB can use quite a bit depending on traffic.
-
-Unless you are going with a budget setup, it's advised to run it separately.
-
-## Requirements
-
-- InfluxDB 0.9.5 or newer
-- A fairly modern version of Linux
-- At least 4GB of RAM
-- At least 10GB of storage for InfluxDB data
-
-Note that the RAM and storage requirements can differ greatly depending on the
-amount of data received/stored. To limit the amount of stored data users can
-look into
-[InfluxDB Retention Policies](https://docs.influxdata.com/influxdb/v0.9/query_language/database_management/#retention-policy-management).
-
-## Installation
-
-Installing InfluxDB is out of the scope of this document. Please refer to the
-[InfluxDB documentation](https://docs.influxdata.com/influxdb/v0.9/).
-
-## InfluxDB Server Settings
-
-Since InfluxDB has many settings that users may wish to customize themselves
-(e.g. what port to run InfluxDB on), we'll only cover the essentials.
-
-The configuration file in question is usually located at
-`/etc/influxdb/influxdb.conf`. Whenever you make a change in this file,
-InfluxDB needs to be restarted.
-
-### Storage Engine
-
-InfluxDB comes with different storage engines and as of InfluxDB 0.9.5 a new
-storage engine is available, called [TSM Tree](https://www.influxdata.com/blog/new-storage-engine-time-structured-merge-tree/).
-All users **must** use the new `tsm1` storage engine as this
-[will be the default engine](https://github.com/influxdata/influxdb/commit/15d723dc77651bac83e09e2b1c94be480966cb0d) in
-upcoming InfluxDB releases.
-
-Make sure you have the following in your configuration file:
-
-```toml
-[data]
- dir = "/var/lib/influxdb/data"
- engine = "tsm1"
-```
-
-### Admin Panel
-
-Production environments should have the InfluxDB admin panel **disabled**. This
-feature can be disabled by adding the following to your InfluxDB configuration
-file:
-
-```toml
-[admin]
- enabled = false
-```
-
-### HTTP
-
-HTTP is required when using the [InfluxDB CLI](https://docs.influxdata.com/influxdb/v0.9/tools/shell/)
-or other tools such as Grafana, thus it should be enabled. When enabling
-make sure to _also_ enable authentication:
-
-```toml
-[http]
- enabled = true
- auth-enabled = true
-```
-
-_**Note:** Before you enable authentication, you might want to [create an
-admin user](#create-a-new-admin-user)._
-
-### UDP
-
-GitLab writes data to InfluxDB via UDP and thus this must be enabled. Enabling
-UDP can be done using the following settings:
-
-```toml
-[[udp]]
- enabled = true
- bind-address = ":8089"
- database = "gitlab"
- batch-size = 1000
- batch-pending = 5
- batch-timeout = "1s"
- read-buffer = 209715200
-```
-
-This does the following:
-
-1. Enable UDP and bind it to port 8089 for all addresses.
-1. Store any data received in the `gitlab` database.
-1. Define a batch of points to be 1000 points in size and allow a maximum of
- 5 batches _or_ flush them automatically after 1 second.
-1. Define a UDP read buffer size of 200 MB.
-
-One of the most important settings here is the UDP read buffer size as if this
-value is set too low, packets will be dropped. You must also make sure the OS
-buffer size is set to the same value, the default value is almost never enough.
-
-To set the OS buffer size to 200 MB, on Linux you can run the following command:
-
-```shell
-sysctl -w net.core.rmem_max=209715200
-```
-
-To make this permanent, add the following to `/etc/sysctl.conf` and restart the
-server:
-
-```shell
-net.core.rmem_max=209715200
-```
-
-It is **very important** to make sure the buffer sizes are large enough to
-handle all data sent to InfluxDB as otherwise you _will_ lose data. The above
-buffer sizes are based on the traffic for GitLab.com. Depending on the amount of
-traffic, users may be able to use a smaller buffer size, but we highly recommend
-using _at least_ 100 MB.
-
-When enabling UDP, users should take care to not expose the port to the public,
-as doing so will allow anybody to write data into your InfluxDB database (as
-[InfluxDB's UDP protocol](https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/)
-doesn't support authentication). We recommend either
-whitelisting the allowed IP addresses/ranges, or setting up a VLAN and only
-allowing traffic from members of said VLAN.
-
-## Create a new admin user
-
-If you want to [enable authentication](#http), you might want to [create an
-admin user](https://docs.influxdata.com/influxdb/v0.9/administration/authentication_and_authorization/#create-a-new-admin-user):
-
-```shell
-influx -execute "CREATE USER jeff WITH PASSWORD '1234' WITH ALL PRIVILEGES"
-```
-
-## Create the `gitlab` database
-
-Once you get InfluxDB up and running, you need to create a database for GitLab.
-Make sure you have changed the [storage engine](#storage-engine) to `tsm1`
-before creating a database.
-
-_**Note:** If you [created an admin user](#create-a-new-admin-user) and enabled
-[HTTP authentication](#http), remember to append the username (`-username <username>`)
-and password (`-password <password>`) you set earlier to the commands below._
-
-Run the following command to create a database named `gitlab`:
-
-```shell
-influx -execute 'CREATE DATABASE gitlab'
-```
-
-The name **must** be `gitlab`, do not use any other name.
-
-Next, make sure that the database was successfully created:
-
-```shell
-influx -execute 'SHOW DATABASES'
-```
-
-The output should be similar to:
-
-```plaintext
-name: databases
----------------
-name
-_internal
-gitlab
-```
-
-That's it! Now your GitLab instance should send data to InfluxDB.
-
+---
+redirect_to: 'prometheus.md'
---
-Read more on:
-
-- [Introduction to GitLab Performance Monitoring](index.md)
-- [GitLab Configuration](gitlab_configuration.md)
-- [InfluxDB Schema](influxdb_schema.md)
-- [Grafana Install/Configuration](grafana_configuration.md)
+Support for InfluxDB was removed in GitLab 13.0. Use [Prometheus](prometheus.md) for performance monitoring.
diff --git a/doc/administration/monitoring/performance/influxdb_schema.md b/doc/administration/monitoring/performance/influxdb_schema.md
index adbccdaaeb8..d793e014a18 100644
--- a/doc/administration/monitoring/performance/influxdb_schema.md
+++ b/doc/administration/monitoring/performance/influxdb_schema.md
@@ -1,101 +1,5 @@
-# InfluxDB Schema
-
-CAUTION: **InfluxDB is deprecated in favor of Prometheus:**
-InfluxDB support is scheduled to be removed in GitLab 13.0.
-You are advised to use [Prometheus](../prometheus/index.md) instead.
-
-The following measurements are currently stored in InfluxDB:
-
-- `PROCESS_file_descriptors`
-- `PROCESS_gc_statistics`
-- `PROCESS_memory_usage`
-- `PROCESS_method_calls`
-- `PROCESS_object_counts`
-- `PROCESS_transactions`
-- `PROCESS_views`
-- `events`
-
-Here, `PROCESS` is replaced with either `rails` or `sidekiq` depending on the
-process type. In all series, any form of duration is stored in milliseconds.
-
-## PROCESS_file_descriptors
-
-This measurement contains the number of open file descriptors over time. The
-value field `value` contains the number of descriptors.
-
-## PROCESS_gc_statistics
-
-This measurement contains Ruby garbage collection statistics such as the amount
-of minor/major GC runs (relative to the last sampling interval), the time spent
-in garbage collection cycles, and all fields/values returned by `GC.stat`.
-
-## PROCESS_memory_usage
-
-This measurement contains the process' memory usage (in bytes) over time. The
-value field `value` contains the number of bytes.
-
-## PROCESS_method_calls
-
-This measurement contains the methods called during a transaction along with
-their duration, and a name of the transaction action that invoked the method (if
-available). The method call duration is stored in the value field `duration`,
-while the method name is stored in the tag `method`. The tag `action` contains
-the full name of the transaction action. Both the `method` and `action` fields
-are in the following format:
-
-```plaintext
-ClassName#method_name
-```
-
-For example, a method called by the `show` method in the `UsersController` class
-would have `action` set to `UsersController#show`.
-
-## PROCESS_object_counts
-
-This measurement is used to store retained Ruby objects (per class) and the
-amount of retained objects. The number of objects is stored in the `count` value
-field while the class name is stored in the `type` tag.
-
-## PROCESS_transactions
-
-This measurement is used to store basic transaction details such as the time it
-took to complete a transaction, how much time was spent in SQL queries, etc. The
-following value fields are available:
-
-| Value | Description |
-| ----- | ----------- |
-| `duration` | The total duration of the transaction |
-| `allocated_memory` | The amount of bytes allocated while the transaction was running. This value is only reliable when using single-threaded application servers |
-| `method_duration` | The total time spent in method calls |
-| `sql_duration` | The total time spent in SQL queries |
-| `view_duration` | The total time spent in views |
-
-## PROCESS_views
-
-This measurement is used to store view rendering timings for a transaction. The
-following value fields are available:
-
-| Value | Description |
-| ----- | ----------- |
-| `duration` | The rendering time of the view |
-| `view` | The path of the view, relative to the application's root directory |
-
-The `action` tag contains the action name of the transaction that rendered the
-view.
-
-## events
-
-This measurement is used to store generic events such as the number of Git
-pushes, Emails sent, etc. Each point in this measurement has a single value
-field called `count`. The value of this field is simply set to `1`. Each point
-also has at least one tag: `event`. This tag's value is set to the event name.
-Depending on the event type additional tags may be available as well.
-
+---
+redirect_to: 'prometheus.md'
---
-Read more on:
-
-- [Introduction to GitLab Performance Monitoring](index.md)
-- [GitLab Configuration](gitlab_configuration.md)
-- [InfluxDB Configuration](influxdb_configuration.md)
-- [Grafana Install/Configuration](grafana_configuration.md)
+Support for InfluxDB was removed in GitLab 13.0. Use [Prometheus](prometheus.md) for performance monitoring.
diff --git a/doc/api/admin_ci_instance_level_variables.md b/doc/api/admin_ci_instance_level_variables.md
new file mode 100644
index 00000000000..d7e14fe0019
--- /dev/null
+++ b/doc/api/admin_ci_instance_level_variables.md
@@ -0,0 +1,136 @@
+# Instance-level CI/CD variables API
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14108) in GitLab 13.0
+
+## List all instance variables
+
+Get the list of all instance-level variables.
+
+```plaintext
+GET /admin/ci/variables
+```
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/admin/ci/variables"
+```
+
+```json
+[
+ {
+ "key": "TEST_VARIABLE_1",
+ "variable_type": "env_var",
+ "value": "TEST_1",
+ "protected": false,
+ "masked": false
+ },
+ {
+ "key": "TEST_VARIABLE_2",
+ "variable_type": "env_var",
+ "value": "TEST_2",
+ "protected": false,
+ "masked": false
+ }
+]
+```
+
+## Show instance variable details
+
+Get the details of a specific instance-level variable.
+
+```plaintext
+GET /admin/ci/variables/:key
+```
+
+| Attribute | Type | required | Description |
+|-----------|---------|----------|-----------------------|
+| `key` | string | yes | The `key` of a variable |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/admin/ci/variables/TEST_VARIABLE_1"
+```
+
+```json
+{
+ "key": "TEST_VARIABLE_1",
+ "variable_type": "env_var",
+ "value": "TEST_1",
+ "protected": false,
+ "masked": false
+}
+```
+
+## Create instance variable
+
+Create a new instance-level variable.
+
+```plaintext
+POST /admin/ci/variables
+```
+
+| Attribute | Type | required | Description |
+|-----------------|---------|----------|-----------------------|
+| `key` | string | yes | The `key` of a variable. Max 255 characters, only `A-Z`, `a-z`, `0-9`, and `_` are allowed. |
+| `value` | string | yes | The `value` of a variable. |
+| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file`. |
+| `protected` | boolean | no | Whether the variable is protected. |
+| `masked` | boolean | no | Whether the variable is masked. |
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/admin/ci/variables" --form "key=NEW_VARIABLE" --form "value=new value"
+```
+
+```json
+{
+ "key": "NEW_VARIABLE",
+ "value": "new value",
+ "variable_type": "env_var",
+ "protected": false,
+ "masked": false
+}
+```
+
+## Update instance variable
+
+Update an instance-level variable.
+
+```plaintext
+PUT /admin/ci/variables/:key
+```
+
+| Attribute | Type | required | Description |
+|-----------------|---------|----------|-------------------------|
+| `key` | string | yes | The `key` of a variable. |
+| `value` | string | yes | The `value` of a variable. |
+| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file`. |
+| `protected` | boolean | no | Whether the variable is protected. |
+| `masked` | boolean | no | Whether the variable is masked. |
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/admin/ci/variables/NEW_VARIABLE" --form "value=updated value"
+```
+
+```json
+{
+ "key": "NEW_VARIABLE",
+ "value": "updated value",
+ "variable_type": "env_var",
+ "protected": true,
+ "masked": true
+}
+```
+
+## Remove instance variable
+
+Remove an instance-level variable.
+
+```plaintext
+DELETE /admin/ci/variables/:key
+```
+
+| Attribute | Type | required | Description |
+|-----------|---------|----------|-------------------------|
+| `key` | string | yes | The `key` of a variable |
+
+```shell
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/admin/ci/variables/VARIABLE_1"
+```
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index f0f3e58c61f..4c34d23dcd6 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -113,7 +113,8 @@ The following API resources are available outside of project and group contexts
| Resource | Available endpoints |
|:---------------------------------------------------|:------------------------------------------------------------------------|
-| [Admin Sidekiq queues](admin_sidekiq_queues.md) | `/admin/sidekiq/queues/:queue_name` |
+| [Instance-level CI/CD variables](admin_ci_instance_level_variables.md) | `/admin/ci/variables` |
+| [Admin Sidekiq queues](admin_sidekiq_queues.md) | `/admin/sidekiq/queues/:queue_name` |
| [Appearance](appearance.md) **(CORE ONLY)** | `/application/appearance` |
| [Applications](applications.md) | `/applications` |
| [Audit Events](audit_events.md) **(PREMIUM ONLY)** | `/audit_events` |
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 87fb60a7573..98a8e4ea2ce 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -521,6 +521,62 @@ Example response:
}
```
+## Get the discussions of a commit
+
+Get the discussions of a commit in a project.
+
+```plaintext
+GET /projects/:id/repository/commits/:sha/discussions
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+| `sha` | string | yes | The commit hash or name of a repository branch or tag |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/4604744a1c64de00ff62e1e8a6766919923d2b41/discussions"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": "4604744a1c64de00ff62e1e8a6766919923d2b41",
+ "individual_note": true,
+ "notes": [
+ {
+ "id": 334686748,
+ "type": null,
+ "body": "I'm the Dude, so that's what you call me.",
+ "attachment": null,
+ "author" : {
+ "id" : 28,
+ "name" : "Jeff Lebowski",
+ "username" : "thedude",
+ "web_url" : "https://gitlab.example.com/thedude",
+ "state" : "active",
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png"
+ },
+ "created_at": "2020-04-30T18:48:11.432Z",
+ "updated_at": "2020-04-30T18:48:11.432Z",
+ "system": false,
+ "noteable_id": null,
+ "noteable_type": "Commit",
+ "resolvable": false,
+ "confidential": null,
+ "noteable_iid": null,
+ "commands_changes": {}
+ }
+ ]
+ }
+]
+
+```
+
## Commit status
Since GitLab 8.1, this is the new commit status API.
diff --git a/doc/api/container_registry.md b/doc/api/container_registry.md
index 2e8656fef60..9ec4373c92c 100644
--- a/doc/api/container_registry.md
+++ b/doc/api/container_registry.md
@@ -18,6 +18,7 @@ GET /projects/:id/registry/repositories
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
+| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories"
@@ -58,6 +59,7 @@ GET /groups/:id/registry/repositories
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
+| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/2/registry/repositories?tags=1"
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 044bbe6a9d4..860a32349f1 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -890,6 +890,11 @@ type Commit {
title: String
"""
+ The GitLab Flavored Markdown rendering of `title`
+ """
+ titleHtml: String
+
+ """
Web URL of the commit
"""
webUrl: String!
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index a471e591bd7..17b5730e899 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -2379,6 +2379,20 @@
"deprecationReason": null
},
{
+ "name": "titleHtml",
+ "description": "The GitLab Flavored Markdown rendering of `title`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "webUrl",
"description": "Web URL of the commit",
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 1da2e7ee2ae..6a036239c65 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -161,6 +161,7 @@ Autogenerated return type of BoardListUpdateLimitMetrics
| `sha` | String! | SHA1 ID of the commit |
| `signatureHtml` | String | Rendered HTML of the commit signature |
| `title` | String | Title of the commit message |
+| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
| `webUrl` | String! | Web URL of the commit |
## CreateBranchPayload
diff --git a/doc/api/settings.md b/doc/api/settings.md
index f8749940cdd..d63e109cfe8 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -282,14 +282,7 @@ are listed in the descriptions of the relevant settings.
| `max_attachment_size` | integer | no | Limit attachment size in MB |
| `max_pages_size` | integer | no | Maximum size of pages repositories in MB |
| `max_personal_access_token_lifetime` | integer | no | **(ULTIMATE ONLY)** Maximum allowable lifetime for personal access tokens in days |
-| `metrics_enabled` | boolean | no | (**If enabled, requires:** `metrics_host`, `metrics_method_call_threshold`, `metrics_packet_size`, `metrics_pool_size`, `metrics_port`, `metrics_sample_interval` and `metrics_timeout`) Enable influxDB metrics. |
-| `metrics_host` | string | required by: `metrics_enabled` | InfluxDB host. |
-| `metrics_method_call_threshold` | integer | required by: `metrics_enabled` | A method call is only tracked when it takes longer than the given amount of milliseconds. |
-| `metrics_packet_size` | integer | required by: `metrics_enabled` | The amount of data points to send in a single UDP packet. |
-| `metrics_pool_size` | integer | required by: `metrics_enabled` | The amount of InfluxDB connections to keep open. |
-| `metrics_port` | integer | required by: `metrics_enabled` | The UDP port to use for connecting to InfluxDB. |
-| `metrics_sample_interval` | integer | required by: `metrics_enabled` | The sampling interval in seconds. |
-| `metrics_timeout` | integer | required by: `metrics_enabled` | The amount of seconds after which InfluxDB will time out. |
+| `metrics_method_call_threshold` | integer | no | A method call is only tracked when it takes longer than the given amount of milliseconds. |
| `mirror_available` | boolean | no | Allow repository mirroring to configured by project Maintainers. If disabled, only Admins will be able to configure repository mirroring. |
| `mirror_capacity_threshold` | integer | no | **(PREMIUM)** Minimum capacity to be available before scheduling more mirrors preemptively |
| `mirror_max_capacity` | integer | no | **(PREMIUM)** Maximum number of mirrors that can be synchronizing at the same time. |
diff --git a/doc/development/fe_guide/vue3_migration.md b/doc/development/fe_guide/vue3_migration.md
index 7bbd5f6340a..e9f1a702fdf 100644
--- a/doc/development/fe_guide/vue3_migration.md
+++ b/doc/development/fe_guide/vue3_migration.md
@@ -58,7 +58,7 @@ export default createEventHub();
Event hubs created with the factory expose the same methods as Vue 2 event hubs (`$on`, `$once`, `$off` and
`$emit`), making them backward compatible with our previous approach.
-## <template functional>
+## \<template functional>
**Why?**
diff --git a/doc/development/performance.md b/doc/development/performance.md
index 8eb8c4eada9..2e73161a11f 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -46,7 +46,7 @@ GitLab provides built-in tools to help improve performance and availability:
GitLab team members can use [GitLab.com's performance monitoring systems](https://about.gitlab.com/handbook/engineering/monitoring/) located at
<https://dashboards.gitlab.net>, this requires you to log in using your
`@gitlab.com` email address. Non-GitLab team-members are advised to set up their
-own InfluxDB and Grafana stack.
+own Prometheus and Grafana stack.
## Benchmarks
diff --git a/doc/development/policies.md b/doc/development/policies.md
index 4d045411156..36793ea081e 100644
--- a/doc/development/policies.md
+++ b/doc/development/policies.md
@@ -95,7 +95,7 @@ Each line represents a rule that was evaluated. There are a few things to note:
Here you can see that the first four rules were evaluated `false` for
which user and subject. For example, you can see in the last line that
-the rule was activated because the user `root` had Reporter access to
+the rule was activated because the user `john` had Reporter access to
`Project/4`.
When a policy is asked whether a particular ability is allowed
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 510aecfc6d3..f610e9a1f77 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -69,6 +69,8 @@ FDOC=1 bin/rspec spec/[path]/[to]/[spec].rb
- Use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'`
- Don't assert against the absolute value of a sequence-generated attribute (see
[Gotchas](../gotchas.md#do-not-assert-against-the-absolute-value-of-a-sequence-generated-attribute)).
+- Avoid using `expect_any_instance_of` or `allow_any_instance_of` (see
+ [Gotchas](../gotchas.md#do-not-assert-against-the-absolute-value-of-a-sequence-generated-attribute)).
- Don't supply the `:each` argument to hooks since it's the default.
- On `before` and `after` hooks, prefer it scoped to `:context` over `:all`
- When using `evaluate_script("$('.js-foo').testSomething()")` (or `execute_script`) which acts on a given element,
diff --git a/doc/monitoring/performance/influxdb_configuration.md b/doc/monitoring/performance/influxdb_configuration.md
index ae5f4c7e9df..0bcb18bdfe7 100644
--- a/doc/monitoring/performance/influxdb_configuration.md
+++ b/doc/monitoring/performance/influxdb_configuration.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../../administration/monitoring/performance/influxdb_configuration.md'
+redirect_to: '../../administration/monitoring/performance/prometheus.md'
---
-This document was moved to [administration/monitoring/performance/influxdb_configuration](../../administration/monitoring/performance/influxdb_configuration.md).
+Support for InfluxDB was removed in GitLab 13.0. Use [Prometheus](../../administration/monitoring/performance/prometheus.md) for performance monitoring.
diff --git a/doc/monitoring/performance/influxdb_schema.md b/doc/monitoring/performance/influxdb_schema.md
index 57fb74cb6cd..0bcb18bdfe7 100644
--- a/doc/monitoring/performance/influxdb_schema.md
+++ b/doc/monitoring/performance/influxdb_schema.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../../administration/monitoring/performance/influxdb_schema.md'
+redirect_to: '../../administration/monitoring/performance/prometheus.md'
---
-This document was moved to [administration/monitoring/performance/influxdb_schema](../../administration/monitoring/performance/influxdb_schema.md).
+Support for InfluxDB was removed in GitLab 13.0. Use [Prometheus](../../administration/monitoring/performance/prometheus.md) for performance monitoring.
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/index.md b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
index 7fc10cb27e6..8597325db7b 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/index.md
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
@@ -24,7 +24,7 @@ Git is really deleted](https://git-scm.com/book/en/v2/Git-Internals-Maintenance-
This means that until Git automatically cleans detached commits (which cannot be
accessed by branch or tag) it will be possible to view them with `git reflog` command
-and access them with direct commit ID. Read more about _[redoing the undo](#redoing-the-undo)_ on the section below.
+and access them with direct commit ID. Read more about _[redoing the undo](#redoing-the-undo)_ in the section below.
## Introduction
@@ -36,12 +36,12 @@ a file into the **staged** state, which is then committed (`git commit`) to your
local repository. After that, file can be shared with other developers (`git push`).
Here's what we'll cover in this tutorial:
-- [Undo local changes](#undo-local-changes) which were not pushed to remote repository:
+- [Undo local changes](#undo-local-changes) which were not pushed to a remote repository:
- Before you commit, in both unstaged and staged state.
- After you committed.
-- Undo changes after they are pushed to remote repository:
+- Undo changes after they are pushed to a remote repository:
- [Without history modification](#undo-remote-changes-without-changing-history) (preferred way).
- [With history modification](#undo-remote-changes-with-modifying-history) (requires
@@ -68,7 +68,7 @@ joined development of the same feature by multiple developers by default.
When multiple developers develop the same feature on the same branch, clashing
with every synchronization is unavoidable, but a proper or chosen Git Workflow will
-prevent that anything is lost or out of sync when feature is complete.
+prevent that anything is lost or out of sync when the feature is complete.
You can also
read through this blog post on [Git Tips & Tricks](https://about.gitlab.com/blog/2016/12/08/git-tips-and-tricks/)
@@ -83,7 +83,7 @@ can be on various stages and each stage has a different approach on how to tackl
### Unstaged local changes (before you commit)
When a change is made, but it is not added to the staged tree, Git itself
-proposes a solution to discard changes to certain file.
+proposes a solution to discard changes to a certain file.
Suppose you edited a file to change the content using your favorite editor:
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index d3f3012e9b0..0dc9afb1c2a 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -74,7 +74,6 @@ Access the default page for admin area settings by navigating to
| Option | Description |
| ------ | ----------- |
-| [Metrics - Influx](../../../administration/monitoring/performance/gitlab_configuration.md) | Enable and configure InfluxDB metrics. |
| [Metrics - Prometheus](../../../administration/monitoring/prometheus/gitlab_metrics.md) | Enable and configure Prometheus metrics. |
| [Metrics - Grafana](../../../administration/monitoring/performance/grafana_configuration.md#integration-with-gitlab-ui) | Enable and configure Grafana. |
| [Profiling - Performance bar](../../../administration/monitoring/performance/performance_bar.md#enable-the-performance-bar-via-the-admin-panel) | Enable access to the Performance Bar for a given group. |
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index 5a685678934..7ded404f877 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -339,7 +339,6 @@ but commented out to help encourage others to add to it in the future. -->
|dependency_proxy_enabled|||
|gitlab_shared_runners_enabled|||
|gravatar_enabled|||
-|influxdb_metrics_enabled|||
|ldap_enabled|||
|mattermost_enabled|||
|omniauth_enabled|||
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index a544de60413..90a4f96f00b 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -169,6 +169,21 @@ development workflow.
NOTE: **Note:**
Customizability is [only available for group-level](https://gitlab.com/gitlab-org/gitlab/-/issues/35823#note_272558950) Value Stream Analytics.
+### Stage path
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/210315) in GitLab 13.0.
+
+Stages are visually depicted as a horizontal process flow. Selecting a stage will update the
+the content below the value stream.
+
+This is disabled by default. If you have a self-managed instance, an
+administrator can [open a Rails console](../../administration/troubleshooting/navigating_gitlab_via_rails_console.md)
+and enable it with the following command:
+
+```ruby
+Feature.enable(:value_stream_analytics_path_navigation)
+```
+
### Adding a stage
In the following example we're creating a new stage that measures and tracks issues from creation
diff --git a/doc/user/application_security/img/adding_a_dismissal_reason_v13_0.png b/doc/user/application_security/img/adding_a_dismissal_reason_v13_0.png
new file mode 100644
index 00000000000..385236d08f2
--- /dev/null
+++ b/doc/user/application_security/img/adding_a_dismissal_reason_v13_0.png
Binary files differ
diff --git a/doc/user/application_security/img/dismissed_info_v12_3.png b/doc/user/application_security/img/dismissed_info_v12_3.png
deleted file mode 100644
index 92037493eaa..00000000000
--- a/doc/user/application_security/img/dismissed_info_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/img/interacting_with_vulnerability_v13_0.png b/doc/user/application_security/img/interacting_with_vulnerability_v13_0.png
new file mode 100644
index 00000000000..866ad74d42c
--- /dev/null
+++ b/doc/user/application_security/img/interacting_with_vulnerability_v13_0.png
Binary files differ
diff --git a/doc/user/application_security/img/interactive_reports.png b/doc/user/application_security/img/interactive_reports.png
deleted file mode 100644
index 1b2ef0d3da9..00000000000
--- a/doc/user/application_security/img/interactive_reports.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index ceae827fb75..ee69aa0cd39 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -101,25 +101,27 @@ information with several options:
- [Solution](#solutions-for-vulnerabilities-auto-remediation): For some vulnerabilities,
a solution is provided for how to fix the vulnerability.
-![Interacting with security reports](img/interactive_reports.png)
+![Interacting with security reports](img/interacting_with_vulnerability_v13_0.png)
### Dismissing a vulnerability
-You can dismiss vulnerabilities by clicking the **Dismiss vulnerability** button.
-This will dismiss the vulnerability and re-render it to reflect its dismissed state.
-If you wish to undo this dismissal, you can click the **Undo dismiss** button.
+To dismiss a vulnerability, you must set its status to Dismissed. Follow these steps to do so:
+
+1. Select the vulnerability in the Security Dashboard.
+1. Select **Dismissed** from the **Status** selector menu at the top-right.
+
+You can undo this action by selecting a different status from the same menu.
#### Adding a dismissal reason
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
-When dismissing a vulnerability, it's often helpful to provide a reason for doing so.
-If you press the comment button next to **Dismiss vulnerability** in the modal,
-a text box appears for you to add a comment with your dismissal.
-Once added, you can edit or delete it. This allows you to add and update
-context for a vulnerability as you learn more over time.
+When dismissing a vulnerability, it's often helpful to provide a reason for doing so. Upon setting a
+vulnerability's status to Dismissed, a text box appears for you to add a comment with your
+dismissal. Once added, you can edit or delete it. This allows you to add and update context for a
+vulnerability as you learn more over time.
-![Dismissed vulnerability comment](img/dismissed_info_v12_3.png)
+![Dismissed vulnerability comment](img/adding_a_dismissal_reason_v13_0.png)
#### Dismissing multiple vulnerabilities
diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_6.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_6.png
deleted file mode 100644
index c93a3ce8c35..00000000000
--- a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v13_0.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v13_0.png
new file mode 100644
index 00000000000..c788e2165ad
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v13_0.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_export_csv_v13_0.png b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_export_csv_v13_0.png
index d767c159e8d..77e75551bd9 100644
--- a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_export_csv_v13_0.png
+++ b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_export_csv_v13_0.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v12_8.png b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v12_8.png
deleted file mode 100644
index fd0548d0b34..00000000000
--- a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v12_8.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v13_0.png b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v13_0.png
new file mode 100644
index 00000000000..a500f186c2b
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_with_projects_v13_0.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.png
deleted file mode 100644
index 51e80bdb50d..00000000000
--- a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.png
new file mode 100644
index 00000000000..bb88b7f371c
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index 8776b626bec..2988b3642ef 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -51,11 +51,10 @@ A pipeline consists of multiple jobs, including SAST and DAST scanning. If any j
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/6165) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.1.
-At the project level, the Security Dashboard displays the latest security reports
-for your project from the last successful pipeline. Use it to find and fix vulnerabilities affecting the
-[default branch](../../project/repository/branches/index.md#default-branch).
+At the project level, the Security Dashboard displays the latest security reports for your project.
+Use it to find and fix vulnerabilities.
-![Project Security Dashboard](img/project_security_dashboard_v12_3.png)
+![Project Security Dashboard](img/project_security_dashboard_v13_0.png)
### Export vulnerabilities
@@ -81,32 +80,27 @@ First, navigate to the Security Dashboard found under your group's
Once you're on the dashboard, at the top you should see a series of filters for:
+- Status
- Severity
-- Confidence
- Report type
-- Project
-
-To the right of the filters, you should see a **Hide dismissed** toggle button.
NOTE: **Note:**
-The dashboard only shows projects with [security reports](#supported-reports) enabled in a group
-according to the last successful projects' pipelines.
+The dashboard only shows projects with [security reports](#supported-reports) enabled in a group.
-![dashboard with action buttons and metrics](img/group_security_dashboard_v12_6.png)
+![Dashboard with action buttons and metrics](img/group_security_dashboard_v13_0.png)
-Selecting one or more filters will filter the results in this page. Disabling the **Hide dismissed**
-toggle button will let you also see vulnerabilities that have been dismissed.
+Selecting one or more filters will filter the results in this page.
The main section is a list of all the vulnerabilities in the group, sorted by severity.
In that list, you can see the severity of the vulnerability, its name, its
confidence (likelihood of the vulnerability to be a positive one), and the project
it's from.
-If you hover over a row, there will appear some actions you can take:
+If you hover over a row, the following actions appear:
-- "More info"
-- "Create issue"
-- "Dismiss vulnerability"
+- More info
+- Create issue
+- Dismiss vulnerability
Next to the list is a timeline chart that shows how many open
vulnerabilities your projects had at various points in time. You can filter among 30, 60, and
@@ -150,7 +144,7 @@ To add projects to the dashboard:
Once added, the dashboard will display the vulnerabilities found in your chosen
projects.
-![Instance Security Dashboard with projects](img/instance_security_dashboard_with_projects_v12_8.png)
+![Instance Security Dashboard with projects](img/instance_security_dashboard_with_projects_v13_0.png)
### Export vulnerabilities
diff --git a/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_0.png b/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_0.png
index 0295eb25de0..14119abd56a 100644
--- a/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_0.png
+++ b/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_0.png
Binary files differ
diff --git a/doc/user/packages/container_registry/img/container_registry_repositories_v13_0.png b/doc/user/packages/container_registry/img/container_registry_repositories_v13_0.png
index 48af857be2b..7286007b953 100644
--- a/doc/user/packages/container_registry/img/container_registry_repositories_v13_0.png
+++ b/doc/user/packages/container_registry/img/container_registry_repositories_v13_0.png
Binary files differ
diff --git a/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_0.png b/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_0.png
index a09b911944c..f7c3aafcc8e 100644
--- a/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_0.png
+++ b/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_0.png
Binary files differ
diff --git a/doc/user/packages/container_registry/img/expiration_policy_app_v13_0.png b/doc/user/packages/container_registry/img/expiration_policy_app_v13_0.png
index 81e516e833b..93c9e00a8f5 100644
--- a/doc/user/packages/container_registry/img/expiration_policy_app_v13_0.png
+++ b/doc/user/packages/container_registry/img/expiration_policy_app_v13_0.png
Binary files differ
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index 941e099d9ba..55dc048222e 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -8,6 +8,7 @@
> login to GitLab's Container Registry.
> - Multiple level image names support was added in GitLab 9.1.
> - The group level Container Registry was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23315) in GitLab 12.10.
+> - Searching by image repository name was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31322) in GitLab 13.0.
NOTE: **Note:**
This document is the user guide. To learn how to enable GitLab Container
@@ -60,6 +61,7 @@ Navigate to your project's **{package}** **Packages & Registries > Container Reg
This view will:
- Show all the image repositories that belong to the project.
+- Allow you to filter image repositories by their name.
- Allow you to [delete](#delete-images-from-within-gitlab) one or more image repository.
- Allow you to navigate to the image repository details page.
- Show a **Quick start** dropdown with the most common commands to log in, build and push
diff --git a/doc/user/search/img/filter_approved_by_merge_requests_v13_0.png b/doc/user/search/img/filter_approved_by_merge_requests_v13_0.png
new file mode 100644
index 00000000000..ef4c65aea4b
--- /dev/null
+++ b/doc/user/search/img/filter_approved_by_merge_requests_v13_0.png
Binary files differ
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index eac3d714831..f5efa3519d9 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -97,10 +97,19 @@ You can filter the **Issues** list to individual instances by their ID. For exam
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9468) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.9.
To filter merge requests by an individual approver, you can type (or select from
-the dropdown) `approver` and select the user.
+the dropdown) **Approver** and select the user.
![Filter MRs by an approver](img/filter_approver_merge_requests.png)
+### Filtering merge requests by "approved by" **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30335) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.0.
+
+To filter merge requests already approved by a specific individual, you can type (or select from
+the dropdown) **Approved-By** and select the user.
+
+![Filter MRs by approved by](img/filter_approved_by_merge_requests_v13_0.png)
+
## Search history
You can view recent searches by clicking on the little arrow-clock icon, which is to the left of the search input. Click the search entry to run that search again. This feature is available for issues and merge requests. Searches are stored locally in your browser.
diff --git a/lib/api/admin/ci/variables.rb b/lib/api/admin/ci/variables.rb
new file mode 100644
index 00000000000..df731148bac
--- /dev/null
+++ b/lib/api/admin/ci/variables.rb
@@ -0,0 +1,137 @@
+# frozen_string_literal: true
+
+module API
+ module Admin
+ module Ci
+ class Variables < Grape::API
+ include PaginationParams
+
+ before { authenticated_as_admin! }
+
+ namespace 'admin' do
+ namespace 'ci' do
+ namespace 'variables' do
+ desc 'Get instance-level variables' do
+ success Entities::Variable
+ end
+ params do
+ use :pagination
+ end
+ get '/' do
+ variables = ::Ci::InstanceVariable.all
+
+ present paginate(variables), with: Entities::Variable
+ end
+
+ desc 'Get a specific variable from a group' do
+ success Entities::Variable
+ end
+ params do
+ requires :key, type: String, desc: 'The key of the variable'
+ end
+ get ':key' do
+ key = params[:key]
+ variable = ::Ci::InstanceVariable.find_by_key(key)
+
+ break not_found!('InstanceVariable') unless variable
+
+ present variable, with: Entities::Variable
+ end
+
+ desc 'Create a new instance-level variable' do
+ success Entities::Variable
+ end
+ params do
+ requires :key,
+ type: String,
+ desc: 'The key of the variable'
+
+ requires :value,
+ type: String,
+ desc: 'The value of the variable'
+
+ optional :protected,
+ type: String,
+ desc: 'Whether the variable is protected'
+
+ optional :masked,
+ type: String,
+ desc: 'Whether the variable is masked'
+
+ optional :variable_type,
+ type: String,
+ values: ::Ci::InstanceVariable.variable_types.keys,
+ desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ end
+ post '/' do
+ variable_params = declared_params(include_missing: false)
+
+ variable = ::Ci::InstanceVariable.new(variable_params)
+
+ if variable.save
+ present variable, with: Entities::Variable
+ else
+ render_validation_error!(variable)
+ end
+ end
+
+ desc 'Update an existing instance-variable' do
+ success Entities::Variable
+ end
+ params do
+ optional :key,
+ type: String,
+ desc: 'The key of the variable'
+
+ optional :value,
+ type: String,
+ desc: 'The value of the variable'
+
+ optional :protected,
+ type: String,
+ desc: 'Whether the variable is protected'
+
+ optional :masked,
+ type: String,
+ desc: 'Whether the variable is masked'
+
+ optional :variable_type,
+ type: String,
+ values: ::Ci::InstanceVariable.variable_types.keys,
+ desc: 'The type of variable, must be one of env_var or file'
+ end
+ put ':key' do
+ variable = ::Ci::InstanceVariable.find_by_key(params[:key])
+
+ break not_found!('InstanceVariable') unless variable
+
+ variable_params = declared_params(include_missing: false).except(:key)
+
+ if variable.update(variable_params)
+ present variable, with: Entities::Variable
+ else
+ render_validation_error!(variable)
+ end
+ end
+
+ desc 'Delete an existing instance-level variable' do
+ success Entities::Variable
+ end
+ params do
+ requires :key, type: String, desc: 'The key of the variable'
+ end
+ delete ':key' do
+ variable = ::Ci::InstanceVariable.find_by_key(params[:key])
+ not_found!('InstanceVariable') unless variable
+
+ variable.destroy
+
+ no_content!
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 433edc1daba..fe8f101e7b5 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -120,6 +120,7 @@ module API
# Keep in alphabetical order
mount ::API::AccessRequests
+ mount ::API::Admin::Ci::Variables
mount ::API::Admin::Sidekiq
mount ::API::Appearance
mount ::API::Applications
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 304baa6aa0b..baae9513c98 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -84,16 +84,7 @@ module API
optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts"
optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB'
optional :max_pages_size, type: Integer, desc: 'Maximum size of pages in MB'
- optional :metrics_enabled, type: Boolean, desc: 'Enable the InfluxDB metrics'
- given metrics_enabled: ->(val) { val } do
- requires :metrics_host, type: String, desc: 'The InfluxDB host'
- requires :metrics_method_call_threshold, type: Integer, desc: 'A method call is only tracked when it takes longer to complete than the given amount of milliseconds.'
- requires :metrics_packet_size, type: Integer, desc: 'The amount of points to store in a single UDP packet'
- requires :metrics_pool_size, type: Integer, desc: 'The amount of InfluxDB connections to open'
- requires :metrics_port, type: Integer, desc: 'The UDP port to use for connecting to InfluxDB'
- requires :metrics_sample_interval, type: Integer, desc: 'The sampling interval in seconds'
- requires :metrics_timeout, type: Integer, desc: 'The amount of seconds after which an InfluxDB connection will time out'
- end
+ optional :metrics_method_call_threshold, type: Integer, desc: 'A method call is only tracked when it takes longer to complete than the given amount of milliseconds.'
optional :password_authentication_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface' # support legacy names, can be removed in v5
optional :password_authentication_enabled_for_web, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface'
mutually_exclusive :password_authentication_enabled_for_web, :password_authentication_enabled, :signin_enabled
diff --git a/lib/gitlab/alert_management/alert_params.rb b/lib/gitlab/alert_management/alert_params.rb
index 876eff6d91e..982479784a9 100644
--- a/lib/gitlab/alert_management/alert_params.rb
+++ b/lib/gitlab/alert_management/alert_params.rb
@@ -19,7 +19,8 @@ module Gitlab
service: annotations[:service],
hosts: Array(annotations[:hosts]),
payload: payload,
- started_at: parsed_payload['startsAt']
+ started_at: parsed_payload['startsAt'],
+ severity: annotations[:severity]
}
end
diff --git a/lib/gitlab/alerting/notification_payload_parser.rb b/lib/gitlab/alerting/notification_payload_parser.rb
index a54bb44d66a..1237c575eac 100644
--- a/lib/gitlab/alerting/notification_payload_parser.rb
+++ b/lib/gitlab/alerting/notification_payload_parser.rb
@@ -5,7 +5,8 @@ module Gitlab
class NotificationPayloadParser
BadPayloadError = Class.new(StandardError)
- DEFAULT_TITLE = 'New: Incident'
+ DEFAULT_TITLE = 'New: Incident'.freeze
+ DEFAULT_SEVERITY = 'critical'.freeze
def initialize(payload)
@payload = payload.to_h.with_indifferent_access
@@ -30,6 +31,10 @@ module Gitlab
payload[:title].presence || DEFAULT_TITLE
end
+ def severity
+ payload[:severity].presence || DEFAULT_SEVERITY
+ end
+
def annotations
primary_params
.reverse_merge(flatten_secondary_params)
@@ -43,7 +48,8 @@ module Gitlab
'description' => payload[:description],
'monitoring_tool' => payload[:monitoring_tool],
'service' => payload[:service],
- 'hosts' => hosts.presence
+ 'hosts' => hosts.presence,
+ 'severity' => severity
}
end
diff --git a/lib/gitlab/background_migration/populate_user_highest_roles_table.rb b/lib/gitlab/background_migration/populate_user_highest_roles_table.rb
index 0c9e15b5a80..16386ebf9c3 100644
--- a/lib/gitlab/background_migration/populate_user_highest_roles_table.rb
+++ b/lib/gitlab/background_migration/populate_user_highest_roles_table.rb
@@ -20,6 +20,8 @@ module Gitlab
end
def perform(from_id, to_id)
+ return unless User.column_names.include?('bot_type')
+
(from_id..to_id).each_slice(BATCH_SIZE) do |ids|
execute(
<<-EOF
diff --git a/lib/gitlab/cycle_analytics/summary/value.rb b/lib/gitlab/cycle_analytics/summary/value.rb
index 9516f9ec974..ce32132e048 100644
--- a/lib/gitlab/cycle_analytics/summary/value.rb
+++ b/lib/gitlab/cycle_analytics/summary/value.rb
@@ -33,7 +33,7 @@ module Gitlab
class PrettyNumeric < Numeric
def to_s
# 0 is shown as -
- value.nonzero? ? super : None.new.to_s
+ (value || 0).nonzero? ? super : None.new.to_s
end
end
end
diff --git a/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb b/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
index 327a9c549d5..6f705239fa3 100644
--- a/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
+++ b/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
@@ -34,7 +34,7 @@ module Gitlab
memo[:depth] = depth
memo[:complexity] = complexity
- memo[:duration] = duration(memo[:time_started]).round(1)
+ memo[:duration_s] = duration(memo[:time_started]).round(1)
GraphqlLogger.info(memo.except!(:time_started, :query))
rescue => e
@@ -62,7 +62,7 @@ module Gitlab
query_string: nil,
query: query,
variables: nil,
- duration: nil
+ duration_s: nil
}
end
end
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 7d0de3aee1c..3c45f841653 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -110,6 +110,7 @@ module Gitlab
::FileUploader.root,
Gitlab.config.uploads.storage_path,
JobArtifactUploader.workhorse_upload_path,
+ LfsObjectUploader.workhorse_upload_path,
File.join(Rails.root, 'public/uploads/tmp')
]
end
diff --git a/lib/gitlab/tree_summary.rb b/lib/gitlab/tree_summary.rb
index 9861ea7d322..4ec43e62c19 100644
--- a/lib/gitlab/tree_summary.rb
+++ b/lib/gitlab/tree_summary.rb
@@ -3,18 +3,20 @@
module Gitlab
class TreeSummary
include ::Gitlab::Utils::StrongMemoize
+ include ::MarkupHelper
CACHE_EXPIRE_IN = 1.hour
MAX_OFFSET = 2**31
- attr_reader :commit, :project, :path, :offset, :limit
+ attr_reader :commit, :project, :path, :offset, :limit, :user
attr_reader :resolved_commits
private :resolved_commits
- def initialize(commit, project, params = {})
+ def initialize(commit, project, user, params = {})
@commit = commit
@project = project
+ @user = user
@path = params.fetch(:path, nil).presence
@offset = [params.fetch(:offset, 0).to_i, MAX_OFFSET].min
@@ -96,6 +98,7 @@ module Gitlab
end
commits_hsh = repository.list_last_commits_for_tree(commit.id, ensured_path, offset: offset, limit: limit)
+ prerender_commit_full_titles!(commits_hsh.values)
entries.each do |entry|
path_key = entry_path(entry)
@@ -104,6 +107,7 @@ module Gitlab
if commit
entry[:commit] = commit
entry[:commit_path] = commit_path(commit)
+ entry[:commit_title_html] = markdown_field(commit, :full_title)
end
end
end
@@ -131,6 +135,14 @@ module Gitlab
def tree
strong_memoize(:tree) { repository.tree(commit.id, path) }
end
+
+ def prerender_commit_full_titles!(commits)
+ # Preload commit authors as they are used in rendering
+ commits.each(&:lazy_author)
+
+ renderer = Banzai::ObjectRenderer.new(user: user, default_project: project)
+ renderer.render(commits, :full_title)
+ end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 981fc6f2b1f..f55f06153fc 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1188,6 +1188,9 @@ msgstr ""
msgid "Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message."
msgstr ""
+msgid "Add a line"
+msgstr ""
+
msgid "Add a link"
msgstr ""
@@ -1275,6 +1278,9 @@ msgstr ""
msgid "Add request manually"
msgstr ""
+msgid "Add strikethrough text"
+msgstr ""
+
msgid "Add system hook"
msgstr ""
@@ -2297,6 +2303,9 @@ msgstr ""
msgid "An issue can be a bug, a todo or a feature request that needs to be discussed in a project. Besides, issues are searchable and filterable."
msgstr ""
+msgid "An unauthenticated user"
+msgstr ""
+
msgid "An unexpected error occurred while checking the project environment."
msgstr ""
@@ -6519,6 +6528,9 @@ msgstr ""
msgid "Customize your pipeline configuration."
msgstr ""
+msgid "Cycle Time"
+msgstr ""
+
msgid "CycleAnalyticsEvent|Issue closed"
msgstr ""
@@ -7916,9 +7928,6 @@ msgstr ""
msgid "Enable and configure Grafana."
msgstr ""
-msgid "Enable and configure InfluxDB metrics."
-msgstr ""
-
msgid "Enable and configure Prometheus metrics."
msgstr ""
@@ -8453,6 +8462,9 @@ msgstr ""
msgid "Error creating new iteration"
msgstr ""
+msgid "Error creating the snippet"
+msgstr ""
+
msgid "Error deleting %{issuableType}"
msgstr ""
@@ -8573,6 +8585,9 @@ msgstr ""
msgid "Error updating status of to-do item."
msgstr ""
+msgid "Error updating the snippet"
+msgstr ""
+
msgid "Error uploading file"
msgstr ""
@@ -10943,6 +10958,9 @@ msgstr ""
msgid "Header message"
msgstr ""
+msgid "Headings"
+msgstr ""
+
msgid "Health"
msgstr ""
@@ -11463,6 +11481,9 @@ msgstr ""
msgid "Incompatible options set!"
msgstr ""
+msgid "Indent"
+msgstr ""
+
msgid "Index all projects"
msgstr ""
@@ -11487,12 +11508,18 @@ msgstr ""
msgid "Input your repository URL"
msgstr ""
+msgid "Insert a code block"
+msgstr ""
+
msgid "Insert a quote"
msgstr ""
msgid "Insert code"
msgstr ""
+msgid "Insert inline code"
+msgstr ""
+
msgid "Insert suggestion"
msgstr ""
@@ -13292,9 +13319,6 @@ msgstr ""
msgid "Metrics - Grafana"
msgstr ""
-msgid "Metrics - Influx"
-msgstr ""
-
msgid "Metrics - Prometheus"
msgstr ""
@@ -14653,6 +14677,9 @@ msgstr ""
msgid "OutdatedBrowser|You can provide feedback %{feedback_link_start}on this issue%{feedback_link_end} or via your usual support channels."
msgstr ""
+msgid "Outdent"
+msgstr ""
+
msgid "Overridden"
msgstr ""
@@ -23496,6 +23523,9 @@ msgstr ""
msgid "Value Stream Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
+msgid "ValueStreamAnalytics|%{days}d"
+msgstr ""
+
msgid "Variable"
msgstr ""
diff --git a/qa/qa.rb b/qa/qa.rb
index ed4ad868451..9a7d2cb0f2a 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -265,6 +265,11 @@ module QA
autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions'
autoload :Operations, 'qa/page/project/settings/operations'
autoload :Incidents, 'qa/page/project/settings/incidents'
+ autoload :Integrations, 'qa/page/project/settings/integrations'
+
+ module Services
+ autoload :Prometheus, 'qa/page/project/settings/services/prometheus'
+ end
end
module SubMenus
@@ -412,6 +417,7 @@ module QA
autoload :UsersSelect, 'qa/page/component/users_select'
autoload :Note, 'qa/page/component/note'
autoload :ConfirmModal, 'qa/page/component/confirm_modal'
+ autoload :CustomMetric, 'qa/page/component/custom_metric'
module Issuable
autoload :Common, 'qa/page/component/issuable/common'
diff --git a/qa/qa/page/component/custom_metric.rb b/qa/qa/page/component/custom_metric.rb
new file mode 100644
index 00000000000..9c402855709
--- /dev/null
+++ b/qa/qa/page/component/custom_metric.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module CustomMetric
+ def self.included(base)
+ base.view 'app/assets/javascripts/custom_metrics/components/custom_metrics_form_fields.vue' do
+ element :custom_metric_prometheus_title_field
+ element :custom_metric_prometheus_query_field
+ element :custom_metric_prometheus_y_label_field
+ element :custom_metric_prometheus_unit_label_field
+ element :custom_metric_prometheus_legend_label_field
+ end
+ end
+
+ def add_custom_metric
+ fill_element :custom_metric_prometheus_title_field, 'HTTP Requests Total'
+ fill_element :custom_metric_prometheus_query_field, 'rate(http_requests_total[5m])'
+ fill_element :custom_metric_prometheus_y_label_field, 'Requests/second'
+ fill_element :custom_metric_prometheus_unit_label_field, 'req/sec'
+ fill_element :custom_metric_prometheus_legend_label_field, 'HTTP requests'
+
+ save_changes
+ end
+
+ def save_changes
+ click_button(class: 'btn-success')
+ end
+
+ def delete_custom_metric
+ click_button(class: 'btn-danger')
+ within('.modal-content') { click_button(class: 'btn-danger') }
+ end
+
+ def edit_custom_metric
+ fill_element :custom_metric_prometheus_title_field, ''
+ fill_element :custom_metric_prometheus_title_field, 'Throughput'
+
+ save_changes
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/operations/metrics/show.rb b/qa/qa/page/project/operations/metrics/show.rb
index 90137e379c5..2228cca1d3d 100644
--- a/qa/qa/page/project/operations/metrics/show.rb
+++ b/qa/qa/page/project/operations/metrics/show.rb
@@ -14,7 +14,7 @@ module QA
element :dashboards_filter_dropdown
element :environments_dropdown
element :edit_dashboard_button
- element :show_last_dropdown
+ element :range_picker_dropdown
end
view 'app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue' do
@@ -28,6 +28,10 @@ module QA
element :generate_chart_link_menu_item
end
+ view 'app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue' do
+ element :quick_range_item
+ end
+
def wait_for_metrics
wait_for_data
return if has_metrics?
@@ -67,10 +71,8 @@ module QA
end
def show_last(range = '8 hours')
- click_element :show_last_dropdown
- within_element :show_last_dropdown do
- click_on range
- end
+ all_elements(:range_picker_dropdown, minimum: 1).first.click
+ click_element :quick_range_item, text: range
end
def copy_link_to_first_chart
@@ -78,6 +80,12 @@ module QA
find_element(:generate_chart_link_menu_item)['data-clipboard-text']
end
+ def has_custom_metric?(metric)
+ within_element :prometheus_graphs do
+ has_text?(metric)
+ end
+ end
+
private
def wait_for_data
diff --git a/qa/qa/page/project/settings/integrations.rb b/qa/qa/page/project/settings/integrations.rb
new file mode 100644
index 00000000000..436a42fb093
--- /dev/null
+++ b/qa/qa/page/project/settings/integrations.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ class Integrations < QA::Page::Base
+ view 'app/views/shared/integrations/_index.html.haml' do
+ element :prometheus_link, '{ data: { qa_selector: "#{integration.to_param' # rubocop:disable QA/ElementWithPattern
+ end
+
+ def click_on_prometheus_integration
+ click_element :prometheus_link
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/settings/services/prometheus.rb b/qa/qa/page/project/settings/services/prometheus.rb
new file mode 100644
index 00000000000..8ae4ded535e
--- /dev/null
+++ b/qa/qa/page/project/settings/services/prometheus.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Settings
+ module Services
+ class Prometheus < Page::Base
+ include Page::Component::CustomMetric
+
+ view 'app/views/projects/services/prometheus/_custom_metrics.html.haml' do
+ element :custom_metrics_container
+ element :new_metric_button
+ end
+
+ def click_on_custom_metric(custom_metric)
+ within_element :custom_metrics_container do
+ click_on custom_metric
+ end
+ end
+
+ def click_on_new_metric
+ click_element :new_metric_button
+ end
+
+ def has_custom_metric?(custom_metric)
+ within_element :custom_metrics_container do
+ has_text? custom_metric
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
new file mode 100644
index 00000000000..eda509641e3
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
@@ -0,0 +1,155 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Monitor' do
+ describe 'with Prometheus Gitlab-managed cluster', :orchestrated, :kubernetes, :docker, :runner do
+ before :all do
+ Flow::Login.sign_in
+ @project, @runner = deploy_project_with_prometheus
+ end
+
+ before do
+ Flow::Login.sign_in_unless_signed_in
+ @project.visit!
+ end
+
+ after :all do
+ @runner.remove_via_api!
+ @cluster.remove!
+ end
+
+ it 'configures custom metrics' do
+ verify_add_custom_metric
+ verify_edit_custom_metric
+ verify_delete_custom_metric
+ end
+
+ it 'duplicates to create dashboard to custom' do
+ Page::Project::Menu.perform(&:go_to_operations_metrics)
+
+ Page::Project::Operations::Metrics::Show.perform do |dashboard|
+ dashboard.duplicate_dashboard
+
+ expect(dashboard).to have_metrics
+ expect(dashboard).to have_edit_dashboard_enabled
+ end
+ end
+
+ it 'verifies data on filtered deployed environment' do
+ Page::Project::Menu.perform(&:go_to_operations_metrics)
+
+ Page::Project::Operations::Metrics::Show.perform do |dashboard|
+ dashboard.filter_environment
+
+ expect(dashboard).to have_metrics
+ end
+ end
+
+ it 'filters using the quick range' do
+ Page::Project::Menu.perform(&:go_to_operations_metrics)
+
+ Page::Project::Operations::Metrics::Show.perform do |dashboard|
+ dashboard.show_last('30 minutes')
+ expect(dashboard).to have_metrics
+
+ dashboard.show_last('3 hours')
+ expect(dashboard).to have_metrics
+
+ dashboard.show_last('1 day')
+ expect(dashboard).to have_metrics
+ end
+ end
+
+ private
+
+ def deploy_project_with_prometheus
+ project = Resource::Project.fabricate_via_api! do |project|
+ project.name = 'cluster-with-prometheus'
+ project.description = 'Cluster with Prometheus'
+ end
+
+ runner = Resource::Runner.fabricate_via_api! do |runner|
+ runner.project = project
+ runner.name = project.name
+ end
+
+ @cluster = Service::KubernetesCluster.new.create!
+
+ cluster_props = Resource::KubernetesCluster::ProjectCluster.fabricate! do |cluster_settings|
+ cluster_settings.project = project
+ cluster_settings.cluster = @cluster
+ cluster_settings.install_helm_tiller = true
+ cluster_settings.install_ingress = true
+ cluster_settings.install_prometheus = true
+ end
+
+ Resource::CiVariable.fabricate_via_api! do |ci_variable|
+ ci_variable.project = project
+ ci_variable.key = 'AUTO_DEVOPS_DOMAIN'
+ ci_variable.value = cluster_props.ingress_ip
+ ci_variable.masked = false
+ end
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.directory = Pathname
+ .new(__dir__)
+ .join('../../../../fixtures/monitored_auto_devops')
+ push.commit_message = 'Create AutoDevOps compatible Project for Monitoring'
+ end
+
+ Page::Project::Menu.perform(&:click_ci_cd_pipelines)
+ Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success_or_retry)
+
+ [project, runner]
+ end
+
+ def verify_add_custom_metric
+ Page::Project::Menu.perform(&:go_to_integrations_settings)
+ Page::Project::Settings::Integrations.perform(&:click_on_prometheus_integration)
+
+ Page::Project::Settings::Services::Prometheus.perform do |metrics_panel|
+ metrics_panel.click_on_new_metric
+ metrics_panel.add_custom_metric
+ end
+
+ Page::Project::Menu.perform(&:go_to_operations_metrics)
+
+ Page::Project::Operations::Metrics::Show.perform do |dashboard|
+ expect(dashboard).to have_custom_metric('HTTP Requests Total')
+ end
+ end
+
+ def verify_edit_custom_metric
+ Page::Project::Menu.perform(&:go_to_integrations_settings)
+ Page::Project::Settings::Integrations.perform(&:click_on_prometheus_integration)
+ Page::Project::Settings::Services::Prometheus.perform do |metrics_panel|
+ metrics_panel.click_on_custom_metric('Business / HTTP Requests Total (req/sec)')
+ metrics_panel.edit_custom_metric
+ end
+
+ Page::Project::Menu.perform(&:go_to_operations_metrics)
+
+ Page::Project::Operations::Metrics::Show.perform do |dashboard|
+ expect(dashboard).to have_custom_metric('Throughput')
+ end
+ end
+
+ def verify_delete_custom_metric
+ Page::Project::Menu.perform(&:go_to_integrations_settings)
+ Page::Project::Settings::Integrations.perform(&:click_on_prometheus_integration)
+
+ Page::Project::Settings::Services::Prometheus.perform do |metrics_panel|
+ metrics_panel.click_on_custom_metric('Business / Throughput (req/sec)')
+ metrics_panel.delete_custom_metric
+ end
+
+ Page::Project::Menu.perform(&:go_to_operations_metrics)
+
+ Page::Project::Operations::Metrics::Show.perform do |dashboard|
+ expect(dashboard).not_to have_custom_metric('Throughput')
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/apm/dashboards_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/apm/dashboards_spec.rb
deleted file mode 100644
index da63b1ac7c8..00000000000
--- a/qa/qa/specs/features/browser_ui/8_monitor/apm/dashboards_spec.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- context 'Monitor' do
- describe 'Dashboards', :orchestrated, :kubernetes, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29262', type: :waiting_on } do
- before(:all) do
- @cluster = Service::KubernetesCluster.new.create!
- Flow::Login.sign_in
- create_project_to_monitor
- wait_for_deployment
- end
-
- before do
- Flow::Login.sign_in_unless_signed_in
- @project.visit!
- end
-
- after(:all) do
- @cluster&.remove!
- end
-
- it 'duplicates to create dashboard to custom' do
- Page::Project::Menu.perform(&:go_to_operations_metrics)
-
- Page::Project::Operations::Metrics::Show.perform do |dashboard|
- dashboard.duplicate_dashboard
-
- expect(dashboard).to have_metrics
- expect(dashboard).to have_edit_dashboard_enabled
- end
- end
-
- it 'verifies data on filtered deployed environment' do
- Page::Project::Menu.perform(&:go_to_operations_metrics)
-
- Page::Project::Operations::Metrics::Show.perform do |dashboard|
- dashboard.filter_environment
-
- expect(dashboard).to have_metrics
- end
- end
-
- it 'filters using the quick range' do
- Page::Project::Menu.perform(&:go_to_operations_metrics)
-
- Page::Project::Operations::Metrics::Show.perform do |dashboard|
- dashboard.show_last('30 minutes')
- expect(dashboard).to have_metrics
-
- dashboard.show_last('3 hours')
- expect(dashboard).to have_metrics
-
- dashboard.show_last('1 day')
- expect(dashboard).to have_metrics
- end
- end
-
- private
-
- def wait_for_deployment
- Page::Project::Menu.perform(&:click_ci_cd_pipelines)
- Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success_or_retry)
- Page::Project::Menu.perform(&:go_to_operations_metrics)
- end
-
- def create_project_to_monitor
- @project = Resource::Project.fabricate_via_api! do |project|
- project.name = 'cluster-with-prometheus'
- project.description = 'Cluster with Prometheus'
- end
-
- @cluster_props = Resource::KubernetesCluster::ProjectCluster.fabricate_via_browser_ui! do |cluster_settings|
- cluster_settings.project = @project
- cluster_settings.cluster = @cluster
- cluster_settings.install_helm_tiller = true
- cluster_settings.install_ingress = true
- cluster_settings.install_prometheus = true
- end
-
- Resource::CiVariable.fabricate_via_api! do |ci_variable|
- ci_variable.project = @project
- ci_variable.key = 'AUTO_DEVOPS_DOMAIN'
- ci_variable.value = @cluster_props.ingress_ip
- ci_variable.masked = false
- end
-
- Resource::Repository::ProjectPush.fabricate! do |push|
- push.project = @project
- push.directory = Pathname
- .new(__dir__)
- .join('../../../../../fixtures/monitored_auto_devops')
- push.commit_message = 'Create AutoDevOps compatible Project for Monitoring'
- end
- end
- end
- end
-end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index fc3efc8e805..6c00dad8bb7 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -1020,6 +1020,32 @@ describe ProjectsController do
expect(json_response['body']).to include(expanded_path)
end
end
+
+ context 'when path and ref parameters are provided' do
+ let(:project_with_repo) { create(:project, :repository) }
+ let(:preview_markdown_params) do
+ {
+ namespace_id: project_with_repo.namespace,
+ id: project_with_repo,
+ text: "![](./logo-white.png)\n",
+ ref: 'other_branch',
+ path: 'files/images/README.md'
+ }
+ end
+
+ before do
+ project_with_repo.add_maintainer(user)
+ project_with_repo.repository.create_branch('other_branch')
+ end
+
+ it 'renders JSON body with image links expanded' do
+ expanded_path = "/#{project_with_repo.full_path}/-/raw/other_branch/files/images/logo-white.png"
+
+ post :preview_markdown, params: preview_markdown_params
+
+ expect(json_response['body']).to include(expanded_path)
+ end
+ end
end
describe '#ensure_canonical_path' do
diff --git a/spec/factories/alert_management/alerts.rb b/spec/factories/alert_management/alerts.rb
index d98fed4a6b1..a86dc63dc17 100644
--- a/spec/factories/alert_management/alerts.rb
+++ b/spec/factories/alert_management/alerts.rb
@@ -25,7 +25,7 @@ FactoryBot.define do
end
trait :with_host do
- hosts { FFaker::Internet.ip_v4_address }
+ hosts { [FFaker::Internet.ip_v4_address] }
end
trait :with_ended_at do
@@ -56,12 +56,17 @@ FactoryBot.define do
without_ended_at
end
+ trait :low_severity do
+ severity { 'low' }
+ end
+
trait :all_fields do
with_issue
with_fingerprint
with_service
with_monitoring_tool
with_host
+ low_severity
end
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 236a6c4cfeb..a18721170f8 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -302,16 +302,6 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
visit metrics_and_profiling_admin_application_settings_path
end
- it 'Change Influx settings' do
- page.within('.as-influx') do
- check 'Enable InfluxDB Metrics'
- click_button 'Save changes'
- end
-
- expect(current_settings.metrics_enabled?).to be true
- expect(page).to have_content "Application settings saved successfully"
- end
-
it 'Change Prometheus settings' do
page.within('.as-prometheus') do
check 'Enable Prometheus Metrics'
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index 5c52abaeb62..4f7eab2a6dc 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -171,6 +171,18 @@ describe "User browses files" do
end
end
+ context 'when commit message has markdown', :js do
+ before do
+ project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master')
+
+ visit(project_tree_path(project, "master"))
+ end
+
+ it 'renders emojis' do
+ expect(page).to have_selector('gl-emoji', count: 2)
+ end
+ end
+
context "when browsing a `improve/awesome` branch", :js do
before do
visit(project_tree_path(project, "improve/awesome"))
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 794b1fdb97c..1e8f9fa0875 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -99,7 +99,7 @@ shared_examples_for 'snippet editor' do
end
context 'when the git operation fails' do
- let(:error) { 'This is a git error' }
+ let(:error) { 'Error creating the snippet' }
before do
allow_next_instance_of(Snippets::CreateService) do |instance|
diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb
index 6d30a6696c6..d19fe9e8d38 100644
--- a/spec/features/projects/snippets/user_updates_snippet_spec.rb
+++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb
@@ -42,7 +42,7 @@ describe 'Projects > Snippets > User updates a snippet', :js do
context 'when the git operation fails' do
before do
allow_next_instance_of(Snippets::UpdateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError)
+ allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end
fill_in('project_snippet_title', with: 'Snippet new title')
@@ -52,7 +52,7 @@ describe 'Projects > Snippets > User updates a snippet', :js do
end
it 'renders edit page and displays the error' do
- expect(page.find('.flash-container span').text).to eq('Error updating the snippet')
+ expect(page.find('.flash-container span').text).to eq('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet')
end
end
diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index c4279bdb212..62054c1f491 100644
--- a/spec/features/snippets/user_creates_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -79,7 +79,7 @@ shared_examples_for 'snippet editor' do
end
context 'when the git operation fails' do
- let(:error) { 'This is a git error' }
+ let(:error) { 'Error creating the snippet' }
before do
allow_next_instance_of(Snippets::CreateService) do |instance|
diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb
index 98f0f75c818..40b0113cf39 100644
--- a/spec/features/snippets/user_edits_snippet_spec.rb
+++ b/spec/features/snippets/user_edits_snippet_spec.rb
@@ -73,7 +73,7 @@ describe 'User edits snippet', :js do
context 'when the git operation fails' do
before do
allow_next_instance_of(Snippets::UpdateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError)
+ allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end
fill_in 'personal_snippet_title', with: 'New Snippet Title'
@@ -83,7 +83,7 @@ describe 'User edits snippet', :js do
end
it 'renders edit page and displays the error' do
- expect(page.find('.flash-container span').text).to eq('Error updating the snippet')
+ expect(page.find('.flash-container span').text).to eq('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet')
end
end
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json
index 4bf72fe6912..6abd76b5138 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/complex/project.json
@@ -7444,6 +7444,26 @@
]
}
],
+ "protected_environments": [
+ {
+ "id": 1,
+ "project_id": 9,
+ "created_at": "2017-10-19T15:36:23.466Z",
+ "updated_at": "2017-10-19T15:36:23.466Z",
+ "name": "production",
+ "deploy_access_levels": [
+ {
+ "id": 1,
+ "protected_environment_id": 1,
+ "created_at": "2017-10-19T15:36:23.466Z",
+ "updated_at": "2017-10-19T15:36:23.466Z",
+ "access_level": 40,
+ "user_id": 1,
+ "group_id": null
+ }
+ ]
+ }
+ ],
"protected_tags": [
{
"id": 1,
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/protected_environments.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/protected_environments.ndjson
new file mode 100644
index 00000000000..55afaa8bcf6
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/protected_environments.ndjson
@@ -0,0 +1 @@
+{ "id": 1, "project_id": 9, "created_at": "2017-10-19T15:36:23.466Z", "updated_at": "2017-10-19T15:36:23.466Z", "name": "production", "deploy_access_levels": [ { "id": 1, "protected_environment_id": 1, "created_at": "2017-10-19T15:36:23.466Z", "updated_at": "2017-10-19T15:36:23.466Z", "access_level": 40, "user_id": 1, "group_id": null } ] }
diff --git a/spec/fixtures/lib/gitlab/import_export/designs/project.json b/spec/fixtures/lib/gitlab/import_export/designs/project.json
index a466529c09d..28eaa38d387 100644
--- a/spec/fixtures/lib/gitlab/import_export/designs/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/designs/project.json
@@ -463,22 +463,7 @@
],
"protected_environments": [
- {
- "id": 14,
- "created_at": "2017-10-19T15:36:23.466Z",
- "updated_at": "2017-10-19T15:36:23.466Z",
- "name": "production",
- "deploy_access_levels": [
- {
- "id": 21,
- "created_at": "2017-10-19T15:36:23.466Z",
- "updated_at": "2017-10-19T15:36:23.466Z",
- "access_level": 40,
- "user_id": 1,
- "group_id": null
- }
- ]
- }
+
],
"protected_tags":[
diff --git a/spec/frontend/__mocks__/@toast-ui/vue-editor/index.js b/spec/frontend/__mocks__/@toast-ui/vue-editor/index.js
index 91bcef5cb62..726ed0fa030 100644
--- a/spec/frontend/__mocks__/@toast-ui/vue-editor/index.js
+++ b/spec/frontend/__mocks__/@toast-ui/vue-editor/index.js
@@ -13,6 +13,9 @@ export const Editor = {
height: {
type: String,
},
+ previewStyle: {
+ type: String,
+ },
},
render(h) {
return h('div');
diff --git a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
index 5770778d8ee..d41fda1040b 100644
--- a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
+++ b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
@@ -71,7 +71,7 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<date-time-picker-stub
class="flex-grow-1 show-last-dropdown"
customenabled="true"
- data-qa-selector="show_last_dropdown"
+ data-qa-selector="range_picker_dropdown"
options="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"
value="[object Object]"
/>
diff --git a/spec/frontend/monitoring/components/variables_section_spec.js b/spec/frontend/monitoring/components/variables_section_spec.js
index 51c0e192c58..6bd8b18881b 100644
--- a/spec/frontend/monitoring/components/variables_section_spec.js
+++ b/spec/frontend/monitoring/components/variables_section_spec.js
@@ -43,10 +43,7 @@ describe('Metrics dashboard/variables section component', () => {
it('shows the variables section', () => {
createShallowWrapper();
- wrapper.vm.$store.commit(
- `monitoringDashboard/${types.SET_PROM_QUERY_VARIABLES}`,
- sampleVariables,
- );
+ wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_VARIABLES}`, sampleVariables);
return wrapper.vm.$nextTick(() => {
const allInputs = findAllFormInputs();
@@ -57,7 +54,7 @@ describe('Metrics dashboard/variables section component', () => {
describe('when changing the variable inputs', () => {
const fetchDashboardData = jest.fn();
- const setVariableData = jest.fn();
+ const setVariableValues = jest.fn();
beforeEach(() => {
store = new Vuex.Store({
@@ -70,7 +67,7 @@ describe('Metrics dashboard/variables section component', () => {
},
actions: {
fetchDashboardData,
- setVariableData,
+ setVariableValues,
},
},
},
@@ -86,7 +83,7 @@ describe('Metrics dashboard/variables section component', () => {
firstInput.vm.$emit('input');
firstInput.trigger('blur');
- expect(setVariableData).toHaveBeenCalled();
+ expect(setVariableValues).toHaveBeenCalled();
expect(mergeUrlParams).toHaveBeenCalledWith(sampleVariables, window.location.href);
expect(updateHistory).toHaveBeenCalled();
expect(fetchDashboardData).toHaveBeenCalled();
@@ -99,7 +96,7 @@ describe('Metrics dashboard/variables section component', () => {
firstInput.vm.$emit('input');
firstInput.trigger('keyup.enter');
- expect(setVariableData).toHaveBeenCalled();
+ expect(setVariableValues).toHaveBeenCalled();
expect(mergeUrlParams).toHaveBeenCalledWith(sampleVariables, window.location.href);
expect(updateHistory).toHaveBeenCalled();
expect(fetchDashboardData).toHaveBeenCalled();
@@ -111,7 +108,7 @@ describe('Metrics dashboard/variables section component', () => {
firstInput.vm.$emit('input');
firstInput.trigger('keyup.enter');
- expect(setVariableData).not.toHaveBeenCalled();
+ expect(setVariableValues).not.toHaveBeenCalled();
expect(mergeUrlParams).not.toHaveBeenCalled();
expect(updateHistory).not.toHaveBeenCalled();
expect(fetchDashboardData).not.toHaveBeenCalled();
diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js
index 44626bfcc57..32ff03a53d7 100644
--- a/spec/frontend/monitoring/store/actions_spec.js
+++ b/spec/frontend/monitoring/store/actions_spec.js
@@ -26,7 +26,7 @@ import {
clearExpandedPanel,
setGettingStartedEmptyState,
duplicateSystemDashboard,
- setVariables,
+ setVariableValues,
} from '~/monitoring/stores/actions';
import {
gqClient,
@@ -442,19 +442,19 @@ describe('Monitoring store actions', () => {
});
});
- describe('setVariables', () => {
+ describe('setVariableValues', () => {
let mockedState;
beforeEach(() => {
mockedState = storeState();
});
- it('should commit SET_PROM_QUERY_VARIABLES mutation', done => {
+ it('should commit UPDATE_VARIABLE_VALUES mutation', done => {
testAction(
- setVariables,
+ setVariableValues,
{ pod: 'POD' },
mockedState,
[
{
- type: types.SET_PROM_QUERY_VARIABLES,
+ type: types.UPDATE_VARIABLE_VALUES,
payload: { pod: 'POD' },
},
],
diff --git a/spec/frontend/monitoring/store/getters_spec.js b/spec/frontend/monitoring/store/getters_spec.js
index e3ee9ffb2bc..3577bebb336 100644
--- a/spec/frontend/monitoring/store/getters_spec.js
+++ b/spec/frontend/monitoring/store/getters_spec.js
@@ -338,14 +338,14 @@ describe('Monitoring store Getters', () => {
});
it('transforms the promVariables object to an array in the [variable, variable_value] format', () => {
- mutations[types.SET_PROM_QUERY_VARIABLES](state, sampleVariables);
+ mutations[types.SET_VARIABLES](state, sampleVariables);
const variablesArray = getters.getCustomVariablesArray(state);
expect(variablesArray).toEqual(['label1', 'pod', 'label2', 'env']);
});
it('transforms the promVariables object to an empty array when no keys are present', () => {
- mutations[types.SET_PROM_QUERY_VARIABLES](state, {});
+ mutations[types.SET_VARIABLES](state, {});
const variablesArray = getters.getCustomVariablesArray(state);
expect(variablesArray).toEqual([]);
diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js
index 29628c99256..6c9b0726c93 100644
--- a/spec/frontend/monitoring/store/mutations_spec.js
+++ b/spec/frontend/monitoring/store/mutations_spec.js
@@ -408,27 +408,35 @@ describe('Monitoring mutations', () => {
});
});
- describe('SET_PROM_QUERY_VARIABLES', () => {
+ describe('SET_VARIABLES', () => {
it('stores an empty variables array when no custom variables are given', () => {
- mutations[types.SET_PROM_QUERY_VARIABLES](stateCopy, {});
+ mutations[types.SET_VARIABLES](stateCopy, {});
expect(stateCopy.promVariables).toEqual({});
});
it('stores variables in the key key_value format in the array', () => {
- mutations[types.SET_PROM_QUERY_VARIABLES](stateCopy, { pod: 'POD', stage: 'main ops' });
+ mutations[types.SET_VARIABLES](stateCopy, { pod: 'POD', stage: 'main ops' });
expect(stateCopy.promVariables).toEqual({ pod: 'POD', stage: 'main ops' });
});
});
- describe('UPDATE_VARIABLE_DATA', () => {
- beforeEach(() => {
- mutations[types.SET_PROM_QUERY_VARIABLES](stateCopy, { pod: 'POD' });
+ describe('UPDATE_VARIABLE_VALUES', () => {
+ afterEach(() => {
+ mutations[types.SET_VARIABLES](stateCopy, {});
+ });
+
+ it('ignores updates that are not already in promVariables', () => {
+ mutations[types.SET_VARIABLES](stateCopy, { environment: 'prod' });
+ mutations[types.UPDATE_VARIABLE_VALUES](stateCopy, { pod: 'new pod' });
+
+ expect(stateCopy.promVariables).toEqual({ environment: 'prod' });
});
- it('sets a new value for an existing key', () => {
- mutations[types.UPDATE_VARIABLE_DATA](stateCopy, { pod: 'new pod' });
+ it('only updates existing variables', () => {
+ mutations[types.SET_VARIABLES](stateCopy, { pod: 'POD' });
+ mutations[types.UPDATE_VARIABLE_VALUES](stateCopy, { pod: 'new pod' });
expect(stateCopy.promVariables).toEqual({ pod: 'new pod' });
});
diff --git a/spec/frontend/monitoring/store/utils_spec.js b/spec/frontend/monitoring/store/utils_spec.js
index fe5754e1216..af040743ebb 100644
--- a/spec/frontend/monitoring/store/utils_spec.js
+++ b/spec/frontend/monitoring/store/utils_spec.js
@@ -5,6 +5,7 @@ import {
parseAnnotationsResponse,
removeLeadingSlash,
mapToDashboardViewModel,
+ removePrefixFromLabels,
} from '~/monitoring/stores/utils';
import { annotationsData } from '../mock_data';
import { NOT_IN_DB_PREFIX } from '~/monitoring/constants';
@@ -419,3 +420,24 @@ describe('removeLeadingSlash', () => {
});
});
});
+
+describe('removePrefixFromLabels', () => {
+ it.each`
+ input | expected
+ ${undefined} | ${''}
+ ${null} | ${''}
+ ${''} | ${''}
+ ${' '} | ${' '}
+ ${'pod-1'} | ${'pod-1'}
+ ${'pod-var-1'} | ${'pod-var-1'}
+ ${'pod-1-var'} | ${'pod-1-var'}
+ ${'podvar--1'} | ${'podvar--1'}
+ ${'povar-d-1'} | ${'povar-d-1'}
+ ${'var-pod-1'} | ${'pod-1'}
+ ${'var-var-pod-1'} | ${'var-pod-1'}
+ ${'varvar-pod-1'} | ${'varvar-pod-1'}
+ ${'var-pod-1-var-'} | ${'pod-1-var-'}
+ `('removePrefixFromLabels returns $expected with input $input', ({ input, expected }) => {
+ expect(removePrefixFromLabels(input)).toEqual(expected);
+ });
+});
diff --git a/spec/frontend/monitoring/store_utils.js b/spec/frontend/monitoring/store_utils.js
index e5b36bf5ad4..b3f87fb7abf 100644
--- a/spec/frontend/monitoring/store_utils.js
+++ b/spec/frontend/monitoring/store_utils.js
@@ -24,7 +24,7 @@ export const setupStoreWithDashboard = $store => {
};
export const setupStoreWithVariable = $store => {
- $store.commit(`monitoringDashboard/${types.SET_PROM_QUERY_VARIABLES}`, {
+ $store.commit(`monitoringDashboard/${types.SET_VARIABLES}`, {
label1: 'pod',
});
};
diff --git a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
index 491fc20c40e..1dca65dd862 100644
--- a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -26,9 +26,7 @@ exports[`Repository last commit component renders commit widget 1`] = `
class="commit-row-message item-title"
href="https://test.com/commit/123"
>
-
- Commit title
-
+ Commit title
</gl-link-stub>
<!---->
@@ -128,9 +126,7 @@ exports[`Repository last commit component renders the signature HTML as returned
class="commit-row-message item-title"
href="https://test.com/commit/123"
>
-
- Commit title
-
+ Commit title
</gl-link-stub>
<!---->
diff --git a/spec/frontend/repository/components/last_commit_spec.js b/spec/frontend/repository/components/last_commit_spec.js
index d2576ec26b7..a5bfeb08fe4 100644
--- a/spec/frontend/repository/components/last_commit_spec.js
+++ b/spec/frontend/repository/components/last_commit_spec.js
@@ -9,6 +9,7 @@ function createCommitData(data = {}) {
const defaultData = {
sha: '123456789',
title: 'Commit title',
+ titleHtml: 'Commit title',
message: 'Commit message',
webUrl: 'https://test.com/commit/123',
authoredDate: '2019-01-01',
diff --git a/spec/frontend/repository/utils/commit_spec.js b/spec/frontend/repository/utils/commit_spec.js
index e7cc28178bf..aaaa39f739f 100644
--- a/spec/frontend/repository/utils/commit_spec.js
+++ b/spec/frontend/repository/utils/commit_spec.js
@@ -8,6 +8,7 @@ const mockData = [
committed_date: '2019-01-01',
},
commit_path: `https://test.com`,
+ commit_title_html: 'testing message',
file_name: 'index.js',
type: 'blob',
},
@@ -24,6 +25,7 @@ describe('normalizeData', () => {
fileName: 'index.js',
filePath: '/index.js',
type: 'blob',
+ titleHtml: 'testing message',
__typename: 'LogTreeCommit',
},
]);
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
index 774fe25387a..549d89171c6 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
@@ -1,30 +1,15 @@
import { shallowMount } from '@vue/test-utils';
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
+import {
+ EDITOR_OPTIONS,
+ EDITOR_TYPES,
+ EDITOR_HEIGHT,
+ EDITOR_PREVIEW_STYLE,
+} from '~/vue_shared/components/rich_content_editor/constants';
describe('Rich Content Editor', () => {
let wrapper;
- const editorOptions = {
- toolbarItems: [
- 'heading',
- 'bold',
- 'italic',
- 'strike',
- 'divider',
- 'quote',
- 'link',
- 'codeblock',
- 'divider',
- 'ul',
- 'ol',
- 'task',
- 'divider',
- 'hr',
- 'table',
- 'divider',
- 'code',
- ],
- };
const value = '## Some Markdown';
const findEditor = () => wrapper.find({ ref: 'editor' });
@@ -44,15 +29,19 @@ describe('Rich Content Editor', () => {
});
it('provides the correct editor options', () => {
- expect(findEditor().props().options).toEqual(editorOptions);
+ expect(findEditor().props().options).toEqual(EDITOR_OPTIONS);
+ });
+
+ it('has the correct preview style', () => {
+ expect(findEditor().props().previewStyle).toBe(EDITOR_PREVIEW_STYLE);
});
it('has the correct initial edit type', () => {
- expect(findEditor().props().initialEditType).toBe('wysiwyg');
+ expect(findEditor().props().initialEditType).toBe(EDITOR_TYPES.wysiwyg);
});
it('has the correct height', () => {
- expect(findEditor().props().height).toBe('100%');
+ expect(findEditor().props().height).toBe(EDITOR_HEIGHT);
});
});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
new file mode 100644
index 00000000000..8545c43dc1e
--- /dev/null
+++ b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
@@ -0,0 +1,44 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import ToolbarItem from '~/vue_shared/components/rich_content_editor/toolbar_item.vue';
+
+describe('Toolbar Item', () => {
+ let wrapper;
+
+ const findIcon = () => wrapper.find(GlIcon);
+ const findButton = () => wrapper.find('button');
+
+ const buildWrapper = propsData => {
+ wrapper = shallowMount(ToolbarItem, { propsData });
+ };
+
+ describe.each`
+ icon
+ ${'heading'}
+ ${'bold'}
+ ${'italic'}
+ ${'strikethrough'}
+ ${'quote'}
+ ${'link'}
+ ${'doc-code'}
+ ${'list-bulleted'}
+ ${'list-numbered'}
+ ${'list-task'}
+ ${'list-indent'}
+ ${'list-outdent'}
+ ${'dash'}
+ ${'table'}
+ ${'code'}
+ `('toolbar item component', ({ icon }) => {
+ beforeEach(() => buildWrapper({ icon }));
+
+ it('renders a toolbar button', () => {
+ expect(findButton().exists()).toBe(true);
+ });
+
+ it(`renders the ${icon} icon`, () => {
+ expect(findIcon().exists()).toBe(true);
+ expect(findIcon().props().name).toBe(icon);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_service_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_service_spec.js
new file mode 100644
index 00000000000..7605cc6a22c
--- /dev/null
+++ b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_service_spec.js
@@ -0,0 +1,29 @@
+import { generateToolbarItem } from '~/vue_shared/components/rich_content_editor/toolbar_service';
+
+describe('Toolbar Service', () => {
+ const config = {
+ icon: 'bold',
+ command: 'some-command',
+ tooltip: 'Some Tooltip',
+ event: 'some-event',
+ };
+ const generatedItem = generateToolbarItem(config);
+
+ it('generates the correct command', () => {
+ expect(generatedItem.options.command).toBe(config.command);
+ });
+
+ it('generates the correct tooltip', () => {
+ expect(generatedItem.options.tooltip).toBe(config.tooltip);
+ });
+
+ it('generates the correct event', () => {
+ expect(generatedItem.options.event).toBe(config.event);
+ });
+
+ it('generates a divider when isDivider is set to true', () => {
+ const isDivider = true;
+
+ expect(generateToolbarItem({ isDivider })).toBe('divider');
+ });
+});
diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb
index adc86321bb1..88b450e3924 100644
--- a/spec/graphql/types/commit_type_spec.rb
+++ b/spec/graphql/types/commit_type_spec.rb
@@ -9,7 +9,7 @@ describe GitlabSchema.types['Commit'] do
it 'contains attributes related to commit' do
expect(described_class).to have_graphql_fields(
- :id, :sha, :title, :description, :message, :authored_date,
+ :id, :sha, :title, :description, :message, :title_html, :authored_date,
:author_name, :author_gravatar, :author, :web_url, :latest_pipeline,
:pipelines, :signature_html
)
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 33347f20de8..b2df543d651 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -95,12 +95,13 @@ describe MarkupHelper do
context 'when text contains a relative link to an image in the repository' do
let(:image_file) { "logo-white.png" }
let(:text_with_relative_path) { "![](./#{image_file})\n" }
- let(:generated_html) { helper.markdown(text_with_relative_path, requested_path: requested_path) }
+ let(:generated_html) { helper.markdown(text_with_relative_path, requested_path: requested_path, ref: ref) }
subject { Nokogiri::HTML.parse(generated_html) }
- context 'when requested_path is provided in the context' do
+ context 'when requested_path is provided, but ref isn\'t' do
let(:requested_path) { 'files/images/README.md' }
+ let(:ref) { nil }
it 'returns the correct HTML for the image' do
expanded_path = "/#{project.full_path}/-/raw/master/files/images/#{image_file}"
@@ -110,13 +111,43 @@ describe MarkupHelper do
end
end
- context 'when requested_path parameter is not provided' do
+ context 'when requested_path and ref parameters are both provided' do
+ let(:requested_path) { 'files/images/README.md' }
+ let(:ref) { 'other_branch' }
+
+ it 'returns the correct HTML for the image' do
+ project.repository.create_branch('other_branch')
+
+ expanded_path = "/#{project.full_path}/-/raw/#{ref}/files/images/#{image_file}"
+
+ expect(subject.css('a')[0].attr('href')).to eq(expanded_path)
+ expect(subject.css('img')[0].attr('data-src')).to eq(expanded_path)
+ end
+ end
+
+ context 'when ref is provided, but requested_path isn\'t' do
+ let(:ref) { 'other_branch' }
+ let(:requested_path) { nil }
+
+ it 'returns the correct HTML for the image' do
+ project.repository.create_branch('other_branch')
+
+ expanded_path = "/#{project.full_path}/-/blob/#{ref}/./#{image_file}"
+
+ expect(subject.css('a')[0].attr('href')).to eq(expanded_path)
+ expect(subject.css('img')[0].attr('data-src')).to eq(expanded_path)
+ end
+ end
+
+ context 'when neither requested_path, nor ref parameter is provided' do
+ let(:ref) { nil }
let(:requested_path) { nil }
- it 'returns the link to the image path as a relative path' do
+ it 'returns the correct HTML for the image' do
expanded_path = "/#{project.full_path}/-/blob/master/./#{image_file}"
expect(subject.css('a')[0].attr('href')).to eq(expanded_path)
+ expect(subject.css('img')[0].attr('data-src')).to eq(expanded_path)
end
end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 17e3f8f9c06..189ab1a8354 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -719,11 +719,7 @@ describe ProjectsHelper do
end
describe '#show_merge_request_count' do
- context 'when the feature flag is enabled' do
- before do
- stub_feature_flags(project_list_show_mr_count: true)
- end
-
+ context 'enabled flag' do
it 'returns true if compact mode is disabled' do
expect(helper.show_merge_request_count?).to be_truthy
end
@@ -733,22 +729,7 @@ describe ProjectsHelper do
end
end
- context 'when the feature flag is disabled' do
- before do
- stub_feature_flags(project_list_show_mr_count: false)
- end
-
- it 'always returns false' do
- expect(helper.show_merge_request_count?(disabled: false)).to be_falsy
- expect(helper.show_merge_request_count?(disabled: true)).to be_falsy
- end
- end
-
context 'disabled flag' do
- before do
- stub_feature_flags(project_list_show_mr_count: true)
- end
-
it 'returns false if disabled flag is true' do
expect(helper.show_merge_request_count?(disabled: true)).to be_falsey
end
@@ -760,11 +741,7 @@ describe ProjectsHelper do
end
describe '#show_issue_count?' do
- context 'when the feature flag is enabled' do
- before do
- stub_feature_flags(project_list_show_issue_count: true)
- end
-
+ context 'enabled flag' do
it 'returns true if compact mode is disabled' do
expect(helper.show_issue_count?).to be_truthy
end
@@ -774,22 +751,7 @@ describe ProjectsHelper do
end
end
- context 'when the feature flag is disabled' do
- before do
- stub_feature_flags(project_list_show_issue_count: false)
- end
-
- it 'always returns false' do
- expect(helper.show_issue_count?(disabled: false)).to be_falsy
- expect(helper.show_issue_count?(disabled: true)).to be_falsy
- end
- end
-
context 'disabled flag' do
- before do
- stub_feature_flags(project_list_show_issue_count: true)
- end
-
it 'returns false if disabled flag is true' do
expect(helper.show_issue_count?(disabled: true)).to be_falsey
end
diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js
index ef0299f0d56..44a75de4be2 100644
--- a/spec/javascripts/ide/components/repo_editor_spec.js
+++ b/spec/javascripts/ide/components/repo_editor_spec.js
@@ -26,7 +26,23 @@ describe('RepoEditor', () => {
f.active = true;
f.tempFile = true;
+
vm.$store.state.openFiles.push(f);
+ vm.$store.state.projects = {
+ 'gitlab-org/gitlab': {
+ branches: {
+ master: {
+ name: 'master',
+ commit: {
+ id: 'abcdefgh',
+ },
+ },
+ },
+ },
+ };
+ vm.$store.state.currentProjectId = 'gitlab-org/gitlab';
+ vm.$store.state.currentBranchId = 'master';
+
Vue.set(vm.$store.state.entries, f.path, f);
spyOn(vm, 'getFileData').and.returnValue(Promise.resolve());
diff --git a/spec/lib/gitlab/alert_management/alert_params_spec.rb b/spec/lib/gitlab/alert_management/alert_params_spec.rb
index 601be961c2e..5cf34038f68 100644
--- a/spec/lib/gitlab/alert_management/alert_params_spec.rb
+++ b/spec/lib/gitlab/alert_management/alert_params_spec.rb
@@ -7,7 +7,7 @@ describe Gitlab::AlertManagement::AlertParams do
describe '.from_generic_alert' do
let(:started_at) { Time.current.change(usec: 0).rfc3339 }
- let(:payload) do
+ let(:default_payload) do
{
'title' => 'Alert title',
'description' => 'Description',
@@ -18,6 +18,7 @@ describe Gitlab::AlertManagement::AlertParams do
'some' => { 'extra' => { 'payload' => 'here' } }
}
end
+ let(:payload) { default_payload }
subject { described_class.from_generic_alert(project: project, payload: payload) }
@@ -28,12 +29,21 @@ describe Gitlab::AlertManagement::AlertParams do
description: 'Description',
monitoring_tool: 'Monitoring tool name',
service: 'Service',
+ severity: 'critical',
hosts: ['gitlab.com'],
payload: payload,
started_at: started_at
)
end
+ context 'when severity given' do
+ let(:payload) { default_payload.merge(severity: 'low') }
+
+ it 'returns Alert compatible parameters' do
+ expect(subject[:severity]).to eq('low')
+ end
+ end
+
context 'when there are no hosts in the payload' do
let(:payload) { {} }
diff --git a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
index a38aea7b972..f32095b3c86 100644
--- a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
+++ b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
@@ -12,7 +12,8 @@ describe Gitlab::Alerting::NotificationPayloadParser do
'description' => 'Description',
'monitoring_tool' => 'Monitoring tool name',
'service' => 'Service',
- 'hosts' => ['gitlab.com']
+ 'hosts' => ['gitlab.com'],
+ 'severity' => 'low'
}
end
@@ -26,7 +27,8 @@ describe Gitlab::Alerting::NotificationPayloadParser do
'description' => 'Description',
'monitoring_tool' => 'Monitoring tool name',
'service' => 'Service',
- 'hosts' => ['gitlab.com']
+ 'hosts' => ['gitlab.com'],
+ 'severity' => 'low'
},
'startsAt' => starts_at.rfc3339
}
@@ -67,11 +69,24 @@ describe Gitlab::Alerting::NotificationPayloadParser do
let(:payload) { {} }
it 'returns default parameters' do
- is_expected.to eq(
- 'annotations' => { 'title' => 'New: Incident' },
+ is_expected.to match(
+ 'annotations' => {
+ 'title' => described_class::DEFAULT_TITLE,
+ 'severity' => described_class::DEFAULT_SEVERITY
+ },
'startsAt' => starts_at.rfc3339
)
end
+
+ context 'when severity is blank' do
+ before do
+ payload[:severity] = ''
+ end
+
+ it 'sets severity to the default ' do
+ expect(subject.dig('annotations', 'severity')).to eq(described_class::DEFAULT_SEVERITY)
+ end
+ end
end
context 'when payload attributes have blank lines' do
@@ -88,7 +103,10 @@ describe Gitlab::Alerting::NotificationPayloadParser do
it 'returns default parameters' do
is_expected.to eq(
- 'annotations' => { 'title' => 'New: Incident' },
+ 'annotations' => {
+ 'title' => 'New: Incident',
+ 'severity' => described_class::DEFAULT_SEVERITY
+ },
'startsAt' => starts_at.rfc3339
)
end
@@ -112,6 +130,7 @@ describe Gitlab::Alerting::NotificationPayloadParser do
is_expected.to eq(
'annotations' => {
'title' => 'New: Incident',
+ 'severity' => described_class::DEFAULT_SEVERITY,
'description' => 'Description',
'additional.params.1' => 'Some value 1',
'additional.params.2' => 'Some value 2'
diff --git a/spec/lib/gitlab/cycle_analytics/summary/value_spec.rb b/spec/lib/gitlab/cycle_analytics/summary/value_spec.rb
index 21ee42295cd..d9bdfa92a04 100644
--- a/spec/lib/gitlab/cycle_analytics/summary/value_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/summary/value_spec.rb
@@ -21,6 +21,10 @@ describe Gitlab::CycleAnalytics::Summary::Value do
expect(described_class.new(0).to_s).to eq('-')
end
+ it 'returns `-` when the number is nil' do
+ expect(described_class.new(nil).to_s).to eq('-')
+ end
+
it 'returns the string representation of the number' do
expect(described_class.new(100).to_s).to eq('100')
end
diff --git a/spec/lib/gitlab/graphql_logger_spec.rb b/spec/lib/gitlab/graphql_logger_spec.rb
index 86cb8cbedad..12cb56c78c1 100644
--- a/spec/lib/gitlab/graphql_logger_spec.rb
+++ b/spec/lib/gitlab/graphql_logger_spec.rb
@@ -23,7 +23,7 @@ describe Gitlab::GraphqlLogger do
variables: {},
complexity: 181,
depth: 0,
- duration: 7
+ duration_s: 7
}
output = subject.format_message('INFO', now, 'test', analyzer_memo)
@@ -34,7 +34,7 @@ describe Gitlab::GraphqlLogger do
expect(data['complexity']).to eq(181)
expect(data['variables']).to eq({})
expect(data['depth']).to eq(0)
- expect(data['duration']).to eq(7)
+ expect(data['duration_s']).to eq(7)
end
end
end
diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb
index c99281ee12c..705164d5445 100644
--- a/spec/lib/gitlab/middleware/multipart_spec.rb
+++ b/spec/lib/gitlab/middleware/multipart_spec.rb
@@ -195,6 +195,17 @@ describe Gitlab::Middleware::Multipart do
end
end
+ it 'allows files in the lfs upload path' do
+ with_tmp_dir('lfs-objects') do |dir, env|
+ expect(LfsObjectUploader).to receive(:workhorse_upload_path).and_return(File.join(dir, 'lfs-objects'))
+ expect(app).to receive(:call) do |env|
+ expect(get_params(env)['file']).to be_a(::UploadedFile)
+ end
+
+ middleware.call(env)
+ end
+ end
+
it 'allows symlinks for uploads dir' do
Tempfile.open('two-levels') do |tempfile|
symlinked_dir = '/some/dir/uploads'
diff --git a/spec/lib/gitlab/tree_summary_spec.rb b/spec/lib/gitlab/tree_summary_spec.rb
index d64b826ba9b..593b8655e80 100644
--- a/spec/lib/gitlab/tree_summary_spec.rb
+++ b/spec/lib/gitlab/tree_summary_spec.rb
@@ -8,12 +8,13 @@ describe Gitlab::TreeSummary do
let(:project) { create(:project, :empty_repo) }
let(:repo) { project.repository }
let(:commit) { repo.head_commit }
+ let_it_be(:user) { create(:user) }
let(:path) { nil }
let(:offset) { nil }
let(:limit) { nil }
- subject(:summary) { described_class.new(commit, project, path: path, offset: offset, limit: limit) }
+ subject(:summary) { described_class.new(commit, project, user, path: path, offset: offset, limit: limit) }
describe '#initialize' do
it 'defaults offset to 0' do
@@ -72,7 +73,8 @@ describe Gitlab::TreeSummary do
expected_commit_path = Gitlab::Routing.url_helpers.project_commit_path(project, commit)
expect(entry[:commit]).to be_a(::Commit)
- expect(entry[:commit_path]).to eq expected_commit_path
+ expect(entry[:commit_path]).to eq(expected_commit_path)
+ expect(entry[:commit_title_html]).to eq(commit.message)
end
context 'in a good subdirectory' do
@@ -140,6 +142,16 @@ describe Gitlab::TreeSummary do
expect(entry).to include(:commit)
end
end
+
+ context 'rendering commits' do
+ it 'does not perform N + 1 request' do
+ summary
+
+ queries = ActiveRecord::QueryRecorder.new { summary.summarize }
+
+ expect(queries.count).to be <= 3
+ end
+ end
end
describe '#more?' do
diff --git a/spec/requests/api/admin/ci/variables_spec.rb b/spec/requests/api/admin/ci/variables_spec.rb
new file mode 100644
index 00000000000..bc2f0ba50a2
--- /dev/null
+++ b/spec/requests/api/admin/ci/variables_spec.rb
@@ -0,0 +1,210 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ::API::Admin::Ci::Variables do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user) { create(:user) }
+
+ describe 'GET /admin/ci/variables' do
+ let!(:variable) { create(:ci_instance_variable) }
+
+ it 'returns instance-level variables for admins', :aggregate_failures do
+ get api('/admin/ci/variables', admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_a(Array)
+ end
+
+ it 'does not return instance-level variables for regular users' do
+ get api('/admin/ci/variables', user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'does not return instance-level variables for unauthorized users' do
+ get api('/admin/ci/variables')
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ describe 'GET /admin/ci/variables/:key' do
+ let!(:variable) { create(:ci_instance_variable) }
+
+ it 'returns instance-level variable details for admins', :aggregate_failures do
+ get api("/admin/ci/variables/#{variable.key}", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['value']).to eq(variable.value)
+ expect(json_response['protected']).to eq(variable.protected?)
+ expect(json_response['variable_type']).to eq(variable.variable_type)
+ end
+
+ it 'responds with 404 Not Found if requesting non-existing variable' do
+ get api('/admin/ci/variables/non_existing_variable', admin)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'does not return instance-level variable details for regular users' do
+ get api("/admin/ci/variables/#{variable.key}", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'does not return instance-level variable details for unauthorized users' do
+ get api("/admin/ci/variables/#{variable.key}")
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ describe 'POST /admin/ci/variables' do
+ context 'authorized user with proper permissions' do
+ let!(:variable) { create(:ci_instance_variable) }
+
+ it 'creates variable for admins', :aggregate_failures do
+ expect do
+ post api('/admin/ci/variables', admin),
+ params: {
+ key: 'TEST_VARIABLE_2',
+ value: 'PROTECTED_VALUE_2',
+ protected: true,
+ masked: true
+ }
+ end.to change { ::Ci::InstanceVariable.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('PROTECTED_VALUE_2')
+ expect(json_response['protected']).to be_truthy
+ expect(json_response['masked']).to be_truthy
+ expect(json_response['variable_type']).to eq('env_var')
+ end
+
+ it 'creates variable with optional attributes', :aggregate_failures do
+ expect do
+ post api('/admin/ci/variables', admin),
+ params: {
+ variable_type: 'file',
+ key: 'TEST_VARIABLE_2',
+ value: 'VALUE_2'
+ }
+ end.to change { ::Ci::InstanceVariable.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['protected']).to be_falsey
+ expect(json_response['masked']).to be_falsey
+ expect(json_response['variable_type']).to eq('file')
+ end
+
+ it 'does not allow to duplicate variable key' do
+ expect do
+ post api('/admin/ci/variables', admin),
+ params: { key: variable.key, value: 'VALUE_2' }
+ end.not_to change { ::Ci::InstanceVariable.count }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not create variable' do
+ post api('/admin/ci/variables', user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not create variable' do
+ post api('/admin/ci/variables')
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+ end
+
+ describe 'PUT /admin/ci/variables/:key' do
+ let!(:variable) { create(:ci_instance_variable) }
+
+ context 'authorized user with proper permissions' do
+ it 'updates variable data', :aggregate_failures do
+ put api("/admin/ci/variables/#{variable.key}", admin),
+ params: {
+ variable_type: 'file',
+ value: 'VALUE_1_UP',
+ protected: true,
+ masked: true
+ }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(variable.reload.value).to eq('VALUE_1_UP')
+ expect(variable.reload).to be_protected
+ expect(json_response['variable_type']).to eq('file')
+ expect(json_response['masked']).to be_truthy
+ end
+
+ it 'responds with 404 Not Found if requesting non-existing variable' do
+ put api('/admin/ci/variables/non_existing_variable', admin)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not update variable' do
+ put api("/admin/ci/variables/#{variable.key}", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not update variable' do
+ put api("/admin/ci/variables/#{variable.key}")
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+ end
+
+ describe 'DELETE /admin/ci/variables/:key' do
+ let!(:variable) { create(:ci_instance_variable) }
+
+ context 'authorized user with proper permissions' do
+ it 'deletes variable' do
+ expect do
+ delete api("/admin/ci/variables/#{variable.key}", admin)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end.to change { ::Ci::InstanceVariable.count }.by(-1)
+ end
+
+ it 'responds with 404 Not Found if requesting non-existing variable' do
+ delete api('/admin/ci/variables/non_existing_variable', admin)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'authorized user with invalid permissions' do
+ it 'does not delete variable' do
+ delete api("/admin/ci/variables/#{variable.key}", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not delete variable' do
+ delete api("/admin/ci/variables/#{variable.key}")
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index cf409ea6c2d..266c98d6f08 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -190,7 +190,7 @@ describe 'GitlabSchema configurations' do
variables: {}.to_s,
complexity: 181,
depth: 13,
- duration: 7
+ duration_s: 7
}
expect_any_instance_of(Gitlab::Graphql::QueryAnalyzers::LoggerAnalyzer).to receive(:duration).and_return(7)
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index 783dd730dd9..f5c7a820abe 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -9,7 +9,7 @@ describe 'GraphQL' do
context 'logging' do
shared_examples 'logging a graphql query' do
let(:expected_params) do
- { query_string: query, variables: variables.to_s, duration: anything, depth: 1, complexity: 1 }
+ { query_string: query, variables: variables.to_s, duration_s: anything, depth: 1, complexity: 1 }
end
it 'logs a query with the expected params' do
diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb
index bfd51874549..5ef276e1f02 100644
--- a/spec/services/projects/alerting/notify_service_spec.rb
+++ b/spec/services/projects/alerting/notify_service_spec.rb
@@ -76,9 +76,14 @@ describe Projects::Alerting::NotifyService do
let(:service) { described_class.new(project, nil, payload) }
let(:payload_raw) do
{
- 'title' => 'alert title',
- 'start_time' => starts_at.rfc3339
- }
+ title: 'alert title',
+ start_time: starts_at.rfc3339,
+ severity: 'low',
+ monitoring_tool: 'GitLab RSpec',
+ service: 'GitLab Test Suite',
+ description: 'Very detailed description',
+ hosts: ['1.1.1.1', '2.2.2.2']
+ }.with_indifferent_access
end
let(:payload) { ActionController::Parameters.new(payload_raw).permit! }
@@ -100,6 +105,12 @@ describe Projects::Alerting::NotifyService do
end
context 'with valid payload' do
+ let(:last_alert_attributes) do
+ AlertManagement::Alert.last.attributes
+ .except('id', 'iid', 'created_at', 'updated_at')
+ .with_indifferent_access
+ end
+
it 'creates AlertManagement::Alert' do
expect { subject }.to change(AlertManagement::Alert, :count).by(1)
end
@@ -107,26 +118,57 @@ describe Projects::Alerting::NotifyService do
it 'created alert has all data properly assigned' do
subject
- alert = AlertManagement::Alert.last
- alert_attributes = alert.attributes.except('id', 'iid', 'created_at', 'updated_at')
-
- expect(alert_attributes).to eq(
- 'project_id' => project.id,
- 'issue_id' => nil,
- 'fingerprint' => nil,
- 'title' => 'alert title',
- 'description' => nil,
- 'monitoring_tool' => nil,
- 'service' => nil,
- 'hosts' => [],
- 'payload' => payload_raw,
- 'severity' => 'critical',
- 'status' => AlertManagement::Alert::STATUSES[:triggered],
- 'events' => 1,
- 'started_at' => alert.started_at,
- 'ended_at' => nil
+ expect(last_alert_attributes).to match(
+ project_id: project.id,
+ title: payload_raw.fetch(:title),
+ started_at: Time.parse(payload_raw.fetch(:start_time)),
+ severity: payload_raw.fetch(:severity),
+ status: AlertManagement::Alert::STATUSES[:triggered],
+ events: 1,
+ hosts: payload_raw.fetch(:hosts),
+ payload: payload_raw.with_indifferent_access,
+ issue_id: nil,
+ description: payload_raw.fetch(:description),
+ monitoring_tool: payload_raw.fetch(:monitoring_tool),
+ service: payload_raw.fetch(:service),
+ fingerprint: nil,
+ ended_at: nil
)
end
+
+ context 'with a minimal payload' do
+ let(:payload_raw) do
+ {
+ title: 'alert title',
+ start_time: starts_at.rfc3339
+ }
+ end
+
+ it 'creates AlertManagement::Alert' do
+ expect { subject }.to change(AlertManagement::Alert, :count).by(1)
+ end
+
+ it 'created alert has all data properly assigned' do
+ subject
+
+ expect(last_alert_attributes).to match(
+ project_id: project.id,
+ title: payload_raw.fetch(:title),
+ started_at: Time.parse(payload_raw.fetch(:start_time)),
+ severity: 'critical',
+ status: AlertManagement::Alert::STATUSES[:triggered],
+ events: 1,
+ hosts: [],
+ payload: payload_raw.with_indifferent_access,
+ issue_id: nil,
+ description: nil,
+ monitoring_tool: nil,
+ service: nil,
+ fingerprint: nil,
+ ended_at: nil
+ )
+ end
+ end
end
it_behaves_like 'does not process incident issues'
diff --git a/spec/services/snippets/create_service_spec.rb b/spec/services/snippets/create_service_spec.rb
index b3f536a896a..b545d7a8aa8 100644
--- a/spec/services/snippets/create_service_spec.rb
+++ b/spec/services/snippets/create_service_spec.rb
@@ -169,8 +169,8 @@ describe Snippets::CreateService do
expect { subject }.not_to change { Snippet.count }
end
- it 'returns the error' do
- expect(snippet.errors.full_messages).to include('Repository could not be created')
+ it 'returns a generic creation error' do
+ expect(snippet.errors[:repository]).to eq ['Error creating the snippet - Repository could not be created']
end
it 'does not return a snippet with an id' do
@@ -178,6 +178,14 @@ describe Snippets::CreateService do
end
end
+ context 'when repository creation fails with invalid file name' do
+ let(:extra_opts) { { file_name: 'invalid://file/name/here' } }
+
+ it 'returns an appropriate error' do
+ expect(snippet.errors[:repository]).to eq ['Error creating the snippet - Invalid file name']
+ end
+ end
+
context 'when the commit action fails' do
before do
allow_next_instance_of(SnippetRepository) do |instance|
@@ -209,11 +217,11 @@ describe Snippets::CreateService do
subject
end
- it 'returns the error' do
+ it 'returns a generic error' do
response = subject
expect(response).to be_error
- expect(response.payload[:snippet].errors.full_messages).to eq ['foobar']
+ expect(response.payload[:snippet].errors[:repository]).to eq ['Error creating the snippet']
end
end
diff --git a/spec/services/snippets/update_service_spec.rb b/spec/services/snippets/update_service_spec.rb
index 7cfb919e021..9f0cb0df474 100644
--- a/spec/services/snippets/update_service_spec.rb
+++ b/spec/services/snippets/update_service_spec.rb
@@ -121,7 +121,7 @@ describe Snippets::UpdateService do
response = subject
expect(response).to be_error
- expect(response.payload[:snippet].errors[:repository].to_sentence).to eq 'Error updating the snippet'
+ expect(response.payload[:snippet].errors[:repository].to_sentence).to eq 'Error updating the snippet - Repository could not be created'
end
it 'does not try to commit file' do