summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/milestone_select.js8
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment.js6
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js4
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment_storage.js8
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/login.js4
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/mr_id.js4
-rw-r--r--app/assets/javascripts/visual_review_toolbar/shared/constants.js9
-rw-r--r--app/assets/javascripts/visual_review_toolbar/shared/index.js6
-rw-r--r--app/assets/javascripts/visual_review_toolbar/store/state.js6
-rw-r--r--app/assets/javascripts/visual_review_toolbar/styles/toolbar.css2
-rw-r--r--app/assets/stylesheets/pages/notes.scss2
-rw-r--r--app/assets/stylesheets/pages/settings.scss13
-rw-r--r--app/controllers/projects/environments_controller.rb2
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/finders/issuable_finder.rb27
-rw-r--r--app/helpers/services_helper.rb2
-rw-r--r--app/models/ci/variable.rb1
-rw-r--r--app/models/concerns/has_environment_scope.rb78
-rw-r--r--app/models/milestone.rb4
-rw-r--r--app/models/project.rb14
-rw-r--r--app/models/project_services/kubernetes_service.rb133
-rw-r--r--app/models/service.rb1
-rw-r--r--app/serializers/variable_entity.rb1
-rw-r--r--app/services/create_snippet_service.rb1
-rw-r--r--app/services/notes/base_service.rb4
-rw-r--r--app/services/notes/create_service.rb1
-rw-r--r--app/services/update_snippet_service.rb4
-rw-r--r--app/views/admin/services/_form.html.haml5
-rw-r--r--app/views/ci/variables/_environment_scope.html.haml21
-rw-r--r--app/views/ci/variables/_environment_scope_header.html.haml2
-rw-r--r--app/views/projects/forks/_fork_button.html.haml8
-rw-r--r--app/views/projects/services/prometheus/_metrics.html.haml7
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--app/views/shared/issuable/form/_metadata.html.haml1
-rw-r--r--changelogs/unreleased/39217-remove-kubernetes-service-integration.yml5
-rw-r--r--changelogs/unreleased/4221-board-milestone-should-persist-any-none-properly.yml5
-rw-r--r--changelogs/unreleased/63671-remove-extra-padding-from-the-disabled-comment-area.yml5
-rw-r--r--changelogs/unreleased/63888-snippets-usage-ping-for-create-smau.yml5
-rw-r--r--changelogs/unreleased/65700-document-max-replication-slots-pg-ha.yml5
-rw-r--r--changelogs/unreleased/add-release-to-github-importer.yml5
-rw-r--r--changelogs/unreleased/bring-scoped-environment-variables-to-core.yml5
-rw-r--r--changelogs/unreleased/filter-title-description-and-body-from-logs.yml5
-rw-r--r--changelogs/unreleased/rails-template-update.yml5
-rw-r--r--changelogs/unreleased/sh-add-gitaly-and-rugged-data-sidekiq.yml5
-rw-r--r--changelogs/unreleased/sh-rename-githost-to-gitjson.yml5
-rw-r--r--changelogs/unreleased/speed-up-labels-api.yml5
-rw-r--r--changelogs/unreleased/visual-review-tools-constant-storage-keys.yml5
-rw-r--r--config/application.rb19
-rw-r--r--config/initializers/lograge.rb14
-rw-r--r--config/initializers/sidekiq.rb1
-rw-r--r--db/migrate/20190703001120_default_milestone_to_nil.rb24
-rw-r--r--db/migrate/20190801060809_delete_kubernetes_services.rb13
-rw-r--r--db/migrate/20190802195602_add_timestamps_columns_to_geo_nodes.rb10
-rw-r--r--db/schema.rb2
-rw-r--r--doc/README.md90
-rw-r--r--doc/administration/geo/replication/troubleshooting.md16
-rw-r--r--doc/administration/high_availability/database.md1
-rw-r--r--doc/administration/index.md2
-rw-r--r--doc/administration/logs.md9
-rw-r--r--doc/administration/troubleshooting/kubernetes_cheat_sheet.md251
-rw-r--r--doc/api/group_labels.md9
-rw-r--r--doc/api/labels.md9
-rw-r--r--doc/api/project_level_variables.md4
-rw-r--r--doc/api/services.md38
-rw-r--r--doc/ci/environments.md2
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/development/architecture.md2
-rw-r--r--doc/development/database_review.md28
-rw-r--r--doc/development/i18n/proofreader.md1
-rw-r--r--doc/development/migration_style_guide.md11
-rw-r--r--doc/install/aws/index.md4
-rw-r--r--doc/install/requirements.md3
-rw-r--r--doc/legal/corporate_contributor_license_agreement.md26
-rw-r--r--doc/legal/individual_contributor_license_agreement.md26
-rw-r--r--doc/migrate_ci_to_ce/README.md2
-rw-r--r--doc/public_access/public_access.md2
-rw-r--r--doc/raketasks/backup_restore.md24
-rw-r--r--doc/raketasks/web_hooks.md5
-rw-r--r--doc/security/img/whitelist.pngbin0 -> 10650 bytes
-rw-r--r--doc/security/webhooks.md30
-rw-r--r--doc/subscriptions/billing_table.pngbin28321 -> 0 bytes
-rw-r--r--doc/subscriptions/index.md268
-rw-r--r--doc/system_hooks/system_hooks.md5
-rw-r--r--doc/topics/autodevops/index.md6
-rw-r--r--doc/user/admin_area/index.md2
-rw-r--r--doc/user/admin_area/settings/email.md10
-rw-r--r--doc/user/application_security/sast/analyzers.md26
-rw-r--r--doc/user/group/clusters/index.md2
-rw-r--r--doc/user/project/clusters/index.md7
-rw-r--r--doc/user/project/merge_requests/blocking_merge_requests.md133
-rw-r--r--doc/user/project/merge_requests/img/cross-project-dependencies-edit-inaccessible.pngbin0 -> 19461 bytes
-rw-r--r--doc/user/project/merge_requests/img/cross-project-dependencies-edit.pngbin0 -> 19302 bytes
-rw-r--r--doc/user/project/merge_requests/img/cross-project-dependencies-view.pngbin0 -> 37528 bytes
-rw-r--r--doc/user/project/merge_requests/img/edit_blocking_merge_requests.pngbin4369 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.pngbin4749 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.pngbin9999 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/index.md18
-rw-r--r--doc/user/project/merge_requests/merge_request_dependencies.md143
-rw-r--r--lib/api/entities.rb19
-rw-r--r--lib/api/group_labels.rb2
-rw-r--r--lib/api/helpers/label_helpers.rb6
-rw-r--r--lib/api/helpers/notes_helpers.rb12
-rw-r--r--lib/api/helpers/services_helpers.rb27
-rw-r--r--lib/api/helpers/variables_helpers.rb13
-rw-r--r--lib/api/labels.rb2
-rw-r--r--lib/api/project_import.rb1
-rw-r--r--lib/api/variables.rb8
-rw-r--r--lib/gitlab/git_logger.rb2
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--lib/gitlab/github_import/importer/releases_importer.rb1
-rw-r--r--lib/gitlab/instrumentation_helper.rb25
-rw-r--r--lib/gitlab/project_search_results.rb4
-rw-r--r--lib/gitlab/regex.rb12
-rw-r--r--lib/gitlab/sidekiq_logging/structured_logger.rb17
-rw-r--r--lib/gitlab/sidekiq_middleware/instrumentation_logger.rb21
-rw-r--r--lib/gitlab/usage_data.rb2
-rw-r--r--lib/gitlab/usage_data_counters/base_counter.rb39
-rw-r--r--lib/gitlab/usage_data_counters/note_counter.rb39
-rw-r--r--lib/gitlab/usage_data_counters/snippet_counter.rb8
-rw-r--r--lib/gitlab/usage_data_counters/wiki_page_counter.rb30
-rw-r--r--locale/gitlab.pot18
-rwxr-xr-xscripts/lint-rugged1
-rw-r--r--spec/controllers/projects/variables_controller_spec.rb65
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/factories/services.rb12
-rw-r--r--spec/features/admin/admin_browses_logs_spec.rb2
-rw-r--r--spec/features/project_variables_spec.rb23
-rw-r--r--spec/finders/issues_finder_spec.rb4
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/group_labels.json19
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/labels/label.json11
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/labels/label_with_counts.json16
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/labels/project_label.json15
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/labels/project_label_with_counts.json9
-rw-r--r--spec/frontend/fixtures/projects.rb2
-rw-r--r--spec/frontend/tracking_spec.js7
-rw-r--r--spec/lib/gitlab/ci/build/policy/variables_spec.rb33
-rw-r--r--spec/lib/gitlab/github_import/importer/releases_importer_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/regex_spec.rb8
-rw-r--r--spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb28
-rw-r--r--spec/lib/gitlab/usage_data_counters/note_counter_spec.rb78
-rw-r--r--spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb12
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb3
-rw-r--r--spec/models/ci/build_spec.rb26
-rw-r--r--spec/models/ci/variable_spec.rb1
-rw-r--r--spec/models/concerns/has_environment_scope_spec.rb66
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb167
-rw-r--r--spec/models/project_spec.rb93
-rw-r--r--spec/requests/api/group_labels_spec.rb15
-rw-r--r--spec/requests/api/issues/get_project_issues_spec.rb2
-rw-r--r--spec/requests/api/labels_spec.rb111
-rw-r--r--spec/requests/api/services_spec.rb10
-rw-r--r--spec/requests/api/variables_spec.rb24
-rw-r--r--spec/serializers/variable_entity_spec.rb2
-rw-r--r--spec/services/create_snippet_service_spec.rb16
-rw-r--r--spec/services/notes/create_service_spec.rb38
-rw-r--r--spec/services/update_snippet_service_spec.rb17
-rw-r--r--vendor/project_templates/rails.tar.gzbin25490 -> 25668 bytes
158 files changed, 1965 insertions, 1051 deletions
diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js
index 01ed27c49fb..43949d5cc86 100644
--- a/app/assets/javascripts/milestone_select.js
+++ b/app/assets/javascripts/milestone_select.js
@@ -55,7 +55,7 @@ export default class MilestoneSelect {
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
const $value = $block.find('.value');
const $loading = $block.find('.block-loading').fadeOut();
- selectedMilestoneDefault = showAny ? __('Any Milestone') : null;
+ selectedMilestoneDefault = showAny ? '' : null;
selectedMilestoneDefault =
showNo && defaultNo ? __('No Milestone') : selectedMilestoneDefault;
selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault;
@@ -74,16 +74,14 @@ export default class MilestoneSelect {
if (showAny) {
extraOptions.push({
id: null,
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
- name: 'Any',
+ name: null,
title: __('Any Milestone'),
});
}
if (showNo) {
extraOptions.push({
id: -1,
- // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
- name: 'None',
+ name: __('No Milestone'),
title: __('No Milestone'),
});
}
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment.js b/app/assets/javascripts/visual_review_toolbar/components/comment.js
index 20effc1751d..a03dc14b319 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/comment.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/comment.js
@@ -1,5 +1,5 @@
import { nextView } from '../store';
-import { localStorage, COMMENT_BOX, LOGOUT } from '../shared';
+import { localStorage, COMMENT_BOX, LOGOUT, STORAGE_MR_ID, STORAGE_TOKEN } from '../shared';
import { clearNote } from './note';
import { buttonClearStyles } from './utils';
import { addForm } from './wrapper';
@@ -27,8 +27,8 @@ const comment = state => {
// If we reach a design where we can logout from multiple views, promote this
// to it's own package
const logoutUser = state => {
- localStorage.removeItem('token');
- localStorage.removeItem('mergeRequestId');
+ localStorage.removeItem(STORAGE_TOKEN);
+ localStorage.removeItem(STORAGE_MR_ID);
state.token = '';
state.mergeRequestId = '';
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js b/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js
index f71ffbf4f20..da67763261c 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js
@@ -1,5 +1,5 @@
import { nextView } from '../store';
-import { localStorage, CHANGE_MR_ID_BUTTON, COMMENT_BOX } from '../shared';
+import { localStorage, CHANGE_MR_ID_BUTTON, COMMENT_BOX, STORAGE_MR_ID } from '../shared';
import { clearNote } from './note';
import { buttonClearStyles } from './utils';
import { addForm } from './wrapper';
@@ -18,7 +18,7 @@ const selectedMrNote = state => {
};
const clearMrId = state => {
- localStorage.removeItem('mergeRequestId');
+ localStorage.removeItem(STORAGE_MR_ID);
state.mergeRequestId = '';
};
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js b/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js
index 32a9e7e2f05..49c9400437e 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js
@@ -1,7 +1,7 @@
import { selectCommentBox } from './utils';
-import { sessionStorage } from '../shared';
+import { sessionStorage, STORAGE_COMMENT } from '../shared';
-const getSavedComment = () => sessionStorage.getItem('comment') || '';
+const getSavedComment = () => sessionStorage.getItem(STORAGE_COMMENT) || '';
const saveComment = () => {
const currentComment = selectCommentBox();
@@ -9,12 +9,12 @@ const saveComment = () => {
// This may be added to any view via top-level beforeunload listener
// so let's skip if it does not apply
if (currentComment && currentComment.value) {
- sessionStorage.setItem('comment', currentComment.value);
+ sessionStorage.setItem(STORAGE_COMMENT, currentComment.value);
}
};
const clearSavedComment = () => {
- sessionStorage.removeItem('comment');
+ sessionStorage.removeItem(STORAGE_COMMENT);
};
export { getSavedComment, saveComment, clearSavedComment };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/login.js b/app/assets/javascripts/visual_review_toolbar/components/login.js
index 4a6976ef2fd..20ab01bc690 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/login.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/login.js
@@ -1,5 +1,5 @@
import { nextView } from '../store';
-import { localStorage, LOGIN, TOKEN_BOX } from '../shared';
+import { localStorage, LOGIN, TOKEN_BOX, STORAGE_TOKEN } from '../shared';
import { clearNote, postError } from './note';
import { rememberBox, submitButton } from './form_elements';
import { selectRemember, selectToken } from './utils';
@@ -22,7 +22,7 @@ const storeToken = (token, state) => {
const rememberMe = selectRemember().checked;
if (rememberMe) {
- localStorage.setItem('token', token);
+ localStorage.setItem(STORAGE_TOKEN, token);
}
state.token = token;
diff --git a/app/assets/javascripts/visual_review_toolbar/components/mr_id.js b/app/assets/javascripts/visual_review_toolbar/components/mr_id.js
index f51e9631dd2..695b3af8aa0 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/mr_id.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/mr_id.js
@@ -1,5 +1,5 @@
import { nextView } from '../store';
-import { MR_ID, MR_ID_BUTTON, localStorage } from '../shared';
+import { MR_ID, MR_ID_BUTTON, STORAGE_MR_ID, localStorage } from '../shared';
import { clearNote, postError } from './note';
import { rememberBox, submitButton } from './form_elements';
import { selectForm, selectMrBox, selectRemember } from './utils';
@@ -23,7 +23,7 @@ const storeMR = (id, state) => {
const rememberMe = selectRemember().checked;
if (rememberMe) {
- localStorage.setItem('mergeRequestId', id);
+ localStorage.setItem(STORAGE_MR_ID, id);
}
state.mergeRequestId = id;
diff --git a/app/assets/javascripts/visual_review_toolbar/shared/constants.js b/app/assets/javascripts/visual_review_toolbar/shared/constants.js
index a56ea378b14..0d5b666ab0a 100644
--- a/app/assets/javascripts/visual_review_toolbar/shared/constants.js
+++ b/app/assets/javascripts/visual_review_toolbar/shared/constants.js
@@ -15,6 +15,12 @@ const REMEMBER_ITEM = 'gitlab-remember-item';
const REVIEW_CONTAINER = 'gitlab-review-container';
const TOKEN_BOX = 'gitlab-token';
+// Storage keys
+const STORAGE_PREFIX = '--gitlab'; // Using `--` to make the prefix more unique
+const STORAGE_MR_ID = `${STORAGE_PREFIX}-merge-request-id`;
+const STORAGE_TOKEN = `${STORAGE_PREFIX}-token`;
+const STORAGE_COMMENT = `${STORAGE_PREFIX}-comment`;
+
// colors — these are applied programmatically
// rest of styles belong in ./styles
const BLACK = 'rgba(46, 46, 46, 1)';
@@ -39,6 +45,9 @@ export {
REMEMBER_ITEM,
REVIEW_CONTAINER,
TOKEN_BOX,
+ STORAGE_MR_ID,
+ STORAGE_TOKEN,
+ STORAGE_COMMENT,
BLACK,
CLEAR,
MUTED,
diff --git a/app/assets/javascripts/visual_review_toolbar/shared/index.js b/app/assets/javascripts/visual_review_toolbar/shared/index.js
index 751eae74dde..d8ccb170592 100644
--- a/app/assets/javascripts/visual_review_toolbar/shared/index.js
+++ b/app/assets/javascripts/visual_review_toolbar/shared/index.js
@@ -14,6 +14,9 @@ import {
REMEMBER_ITEM,
REVIEW_CONTAINER,
TOKEN_BOX,
+ STORAGE_MR_ID,
+ STORAGE_TOKEN,
+ STORAGE_COMMENT,
BLACK,
CLEAR,
MUTED,
@@ -41,6 +44,9 @@ export {
REMEMBER_ITEM,
REVIEW_CONTAINER,
TOKEN_BOX,
+ STORAGE_MR_ID,
+ STORAGE_TOKEN,
+ STORAGE_COMMENT,
BLACK,
CLEAR,
MUTED,
diff --git a/app/assets/javascripts/visual_review_toolbar/store/state.js b/app/assets/javascripts/visual_review_toolbar/store/state.js
index 741a5c7d99c..b7853bb0723 100644
--- a/app/assets/javascripts/visual_review_toolbar/store/state.js
+++ b/app/assets/javascripts/visual_review_toolbar/store/state.js
@@ -1,5 +1,5 @@
import { comment, login, mrForm } from '../components';
-import { localStorage, COMMENT_BOX, LOGIN, MR_ID } from '../shared';
+import { localStorage, COMMENT_BOX, LOGIN, MR_ID, STORAGE_MR_ID, STORAGE_TOKEN } from '../shared';
const state = {
browser: '',
@@ -74,8 +74,8 @@ const initializeState = (wind, doc) => {
};
const getInitialView = () => {
- const token = localStorage.getItem('token');
- const mrId = localStorage.getItem('mergeRequestId');
+ const token = localStorage.getItem(STORAGE_TOKEN);
+ const mrId = localStorage.getItem(STORAGE_MR_ID);
if (token) {
state.token = token;
diff --git a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
index e5732fd5d93..d1a8d66ef40 100644
--- a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
+++ b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
@@ -42,7 +42,7 @@
position: fixed;
bottom: 1rem;
right: 1rem;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell,
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, Cantarell,
'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
font-size: .8rem;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index b9b8eabf909..6c03dbb56a7 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -806,7 +806,7 @@ $note-form-margin-left: 72px;
border-radius: $border-radius-base;
border: 1px solid $border-gray-normal;
color: $note-disabled-comment-color;
- padding: 90px 0;
+ padding: $gl-padding-8 0;
&.discussion-locked {
border: 0;
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 3b62121eb0d..79de1d78a6e 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -272,7 +272,7 @@
}
.custom-monitored-metrics {
- .card-title {
+ .card-header {
display: flex;
align-items: center;
@@ -292,17 +292,6 @@
}
}
- .loading-metrics,
- .empty-metrics {
- padding: 30px 10px;
-
- p,
- .btn {
- margin-top: 10px;
- margin-bottom: 0;
- }
- }
-
.loading-metrics .metrics-load-spinner {
color: $gl-gray-700;
}
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 07eb689d031..b709ac85e39 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -11,7 +11,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
before_action :verify_api_request!, only: :terminal_websocket_authorize
before_action :expire_etag_cache, only: [:index]
before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do
- push_frontend_feature_flag(:environment_metrics_use_prometheus_endpoint)
+ push_frontend_feature_flag(:environment_metrics_use_prometheus_endpoint, default_enabled: true)
push_frontend_feature_flag(:environment_metrics_show_multiple_dashboards)
push_frontend_feature_flag(:environment_metrics_additional_panel_types)
push_frontend_feature_flag(:prometheus_computed_alerts)
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 646728e8167..1dffc57fcf0 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -38,6 +38,6 @@ class Projects::VariablesController < Projects::ApplicationController
end
def variable_params_attributes
- %i[id variable_type key secret_value protected masked _destroy]
+ %i[id variable_type key secret_value protected masked environment_scope _destroy]
end
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 86970ae3219..1773ac2d508 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -484,19 +484,22 @@ class IssuableFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_milestone(items)
- return items unless milestones?
- return items if filter_by_any_milestone?
-
- if filter_by_no_milestone?
- items.left_joins_milestones.where(milestone_id: nil)
- elsif filter_by_upcoming_milestone?
- upcoming_ids = Milestone.upcoming_ids(projects, related_groups)
- items.left_joins_milestones.where(milestone_id: upcoming_ids)
- elsif filter_by_started_milestone?
- items.left_joins_milestones.merge(Milestone.started)
- else
- items.with_milestone(params[:milestone_title])
+ if milestones?
+ if filter_by_no_milestone?
+ items = items.left_joins_milestones.where(milestone_id: [-1, nil])
+ elsif filter_by_any_milestone?
+ items = items.any_milestone
+ elsif filter_by_upcoming_milestone?
+ upcoming_ids = Milestone.upcoming_ids(projects, related_groups)
+ items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
+ elsif filter_by_started_milestone?
+ items = items.left_joins_milestones.merge(Milestone.started)
+ else
+ items = items.with_milestone(params[:milestone_title])
+ end
end
+
+ items
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index 01ccf163b45..d4b50b7ecfb 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -39,7 +39,7 @@ module ServicesHelper
end
def disable_fields_service?(service)
- service.is_a?(KubernetesService) || (!current_controller?("admin/services") && service.deprecated?)
+ !current_controller?("admin/services") && service.deprecated?
end
extend self
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index a77bbef0fca..760872d3e6b 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -6,6 +6,7 @@ module Ci
include HasVariable
include Presentable
include Maskable
+ prepend HasEnvironmentScope
belongs_to :project
diff --git a/app/models/concerns/has_environment_scope.rb b/app/models/concerns/has_environment_scope.rb
new file mode 100644
index 00000000000..9553abe4dd3
--- /dev/null
+++ b/app/models/concerns/has_environment_scope.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+module HasEnvironmentScope
+ extend ActiveSupport::Concern
+
+ prepended do
+ validates(
+ :environment_scope,
+ presence: true,
+ format: { with: ::Gitlab::Regex.environment_scope_regex,
+ message: ::Gitlab::Regex.environment_scope_regex_message }
+ )
+
+ ##
+ # Select rows which have a scope that matches the given environment name.
+ # Rows are ordered by relevance, by default. The most relevant row is
+ # placed at the end of a list.
+ #
+ # options:
+ # - relevant_only: (boolean)
+ # You can get the most relevant row only. Other rows are not be
+ # selected even if its scope matches the environment name.
+ # This is equivalent to using `#last` from SQL standpoint.
+ #
+ scope :on_environment, -> (environment_name, relevant_only: false) do
+ order_direction = relevant_only ? 'DESC' : 'ASC'
+
+ where = <<~SQL
+ environment_scope IN (:wildcard, :environment_name) OR
+ :environment_name LIKE
+ #{::Gitlab::SQL::Glob.to_like('environment_scope')}
+ SQL
+
+ order = <<~SQL
+ CASE environment_scope
+ WHEN :wildcard THEN 0
+ WHEN :environment_name THEN 2
+ ELSE 1
+ END #{order_direction}
+ SQL
+
+ values = {
+ wildcard: '*',
+ environment_name: environment_name
+ }
+
+ sanitized_order_sql = sanitize_sql_array([order, values])
+
+ # The query is trying to find variables with scopes matching the
+ # current environment name. Suppose the environment name is
+ # 'review/app', and we have variables with environment scopes like:
+ # * variable A: review
+ # * variable B: review/app
+ # * variable C: review/*
+ # * variable D: *
+ # And the query should find variable B, C, and D, because it would
+ # try to convert the scope into a LIKE pattern for each variable:
+ # * A: review
+ # * B: review/app
+ # * C: review/%
+ # * D: %
+ # Note that we'll match % and _ literally therefore we'll escape them.
+ # In this case, B, C, and D would match. We also want to prioritize
+ # the exact matched name, and put * last, and everything else in the
+ # middle. So the order should be: D < C < B
+ relation = where(where, values)
+ .order(Arel.sql(sanitized_order_sql)) # `order` cannot escape for us!
+
+ relation = relation.limit(1) if relevant_only
+
+ relation
+ end
+ end
+
+ def environment_scope=(new_environment_scope)
+ super(new_environment_scope.to_s.strip)
+ end
+end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 60266992ee1..2ad2838111e 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -4,8 +4,8 @@ class Milestone < ApplicationRecord
# Represents a "No Milestone" state used for filtering Issues and Merge
# Requests that have no milestone assigned.
MilestoneStruct = Struct.new(:title, :name, :id)
- None = MilestoneStruct.new('No Milestone', 'No Milestone', -1)
- Any = MilestoneStruct.new('Any Milestone', '', nil)
+ None = MilestoneStruct.new('No Milestone', 'No Milestone', 0)
+ Any = MilestoneStruct.new('Any Milestone', '', -1)
Upcoming = MilestoneStruct.new('Upcoming', '#upcoming', -2)
Started = MilestoneStruct.new('Started', '#started', -3)
diff --git a/app/models/project.rb b/app/models/project.rb
index 960795b73cb..a6e43efa1f3 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -162,7 +162,6 @@ class Project < ApplicationRecord
has_one :bugzilla_service
has_one :gitlab_issue_tracker_service, inverse_of: :project
has_one :external_wiki_service
- has_one :kubernetes_service, inverse_of: :project
has_one :prometheus_service, inverse_of: :project
has_one :mock_ci_service
has_one :mock_deployment_service
@@ -1828,11 +1827,16 @@ class Project < ApplicationRecord
end
def ci_variables_for(ref:, environment: nil)
- # EE would use the environment
- if protected_for?(ref)
- variables
+ result = if protected_for?(ref)
+ variables
+ else
+ variables.unprotected
+ end
+
+ if environment
+ result.on_environment(environment)
else
- variables.unprotected
+ result.where(environment_scope: '*')
end
end
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
deleted file mode 100644
index 9f5c226f4c9..00000000000
--- a/app/models/project_services/kubernetes_service.rb
+++ /dev/null
@@ -1,133 +0,0 @@
-# frozen_string_literal: true
-
-class KubernetesService < Service
- default_value_for :category, 'deployment'
-
- # Namespace defaults to the project path, but can be overridden in case that
- # is an invalid or inappropriate name
- prop_accessor :namespace
-
- # Access to kubernetes is directly through the API
- prop_accessor :api_url
-
- # Bearer authentication
- # TODO: user/password auth, client certificates
- prop_accessor :token
-
- # Provide a custom CA bundle for self-signed deployments
- prop_accessor :ca_pem
-
- with_options presence: true, if: :activated? do
- validates :api_url, public_url: true
- validates :token
- end
-
- before_validation :enforce_namespace_to_lower_case
-
- attr_accessor :skip_deprecation_validation
-
- validate :deprecation_validation, unless: :skip_deprecation_validation
-
- validates :namespace,
- allow_blank: true,
- length: 1..63,
- if: :activated?,
- format: {
- with: Gitlab::Regex.kubernetes_namespace_regex,
- message: Gitlab::Regex.kubernetes_namespace_regex_message
- }
-
- def self.supported_events
- %w()
- end
-
- def can_test?
- false
- end
-
- def initialize_properties
- self.properties = {} if properties.nil?
- end
-
- def title
- 'Kubernetes'
- end
-
- def description
- 'Kubernetes / OpenShift integration'
- end
-
- def self.to_param
- 'kubernetes'
- end
-
- def fields
- [
- { type: 'text',
- name: 'api_url',
- title: 'API URL',
- placeholder: 'Kubernetes API URL, like https://kube.example.com/' },
- { type: 'textarea',
- name: 'ca_pem',
- title: 'CA Certificate',
- placeholder: 'Certificate Authority bundle (PEM format)' },
- { type: 'text',
- name: 'namespace',
- title: 'Project namespace (optional/unique)',
- placeholder: namespace_placeholder },
- { type: 'text',
- name: 'token',
- title: 'Token',
- placeholder: 'Service token' }
- ]
- end
-
- def deprecated?
- true
- end
-
- def editable?
- false
- end
-
- def deprecation_message
- content = if project
- _("Kubernetes service integration has been disabled. Fields on this page are not used by GitLab, you can configure your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page") % {
- url: Gitlab::Routing.url_helpers.project_clusters_path(project)
- }
- else
- _("The instance-level Kubernetes service integration is disabled. Your data has been migrated to an <a href=\"%{url}\"/>instance-level cluster</a>.") % {
- url: Gitlab::Routing.url_helpers.admin_clusters_path
- }
- end
-
- content.html_safe
- end
-
- TEMPLATE_PLACEHOLDER = 'Kubernetes namespace'.freeze
-
- private
-
- def namespace_placeholder
- default_namespace || TEMPLATE_PLACEHOLDER
- end
-
- def default_namespace
- return unless project
-
- slug = "#{project.path}-#{project.id}".downcase
- slug.gsub(/[^-a-z0-9]/, '-').gsub(/^-+/, '')
- end
-
- def enforce_namespace_to_lower_case
- self.namespace = self.namespace&.downcase
- end
-
- def deprecation_validation
- return if active_changed?(from: true, to: false) || (new_record? && !active?)
-
- if deprecated?
- errors[:base] << deprecation_message
- end
- end
-end
diff --git a/app/models/service.rb b/app/models/service.rb
index 752467622f2..f6d8fb1fb46 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -260,7 +260,6 @@ class Service < ApplicationRecord
hipchat
irker
jira
- kubernetes
mattermost_slash_commands
mattermost
packagist
diff --git a/app/serializers/variable_entity.rb b/app/serializers/variable_entity.rb
index 4d48e13cfca..8b19925f153 100644
--- a/app/serializers/variable_entity.rb
+++ b/app/serializers/variable_entity.rb
@@ -7,4 +7,5 @@ class VariableEntity < Grape::Entity
expose :protected?, as: :protected
expose :masked?, as: :masked
+ expose :environment_scope
end
diff --git a/app/services/create_snippet_service.rb b/app/services/create_snippet_service.rb
index 6f1fce4989e..6e5bf823cc7 100644
--- a/app/services/create_snippet_service.rb
+++ b/app/services/create_snippet_service.rb
@@ -23,6 +23,7 @@ class CreateSnippetService < BaseService
if snippet.save
UserAgentDetailService.new(snippet, @request).create
+ Gitlab::UsageDataCounters::SnippetCounter.count(:create)
end
snippet
diff --git a/app/services/notes/base_service.rb b/app/services/notes/base_service.rb
index c1260837c12..b4d04c47cc0 100644
--- a/app/services/notes/base_service.rb
+++ b/app/services/notes/base_service.rb
@@ -9,5 +9,9 @@ module Notes
note.noteable.diffs.clear_cache
end
end
+
+ def increment_usage_counter(note)
+ Gitlab::UsageDataCounters::NoteCounter.count(:create, note.noteable_type)
+ end
end
end
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 194c4a43dbc..a09272f0d83 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -41,6 +41,7 @@ module Notes
todo_service.new_note(note, current_user)
clear_noteable_diffs_cache(note)
Suggestions::CreateService.new(note).execute
+ increment_usage_counter(note)
end
if quick_actions_service.commands_executed_count.to_i > 0
diff --git a/app/services/update_snippet_service.rb b/app/services/update_snippet_service.rb
index 15bc1046a4e..2969c360de5 100644
--- a/app/services/update_snippet_service.rb
+++ b/app/services/update_snippet_service.rb
@@ -25,6 +25,8 @@ class UpdateSnippetService < BaseService
snippet.assign_attributes(params)
spam_check(snippet, current_user)
- snippet.save
+ snippet.save.tap do |succeeded|
+ Gitlab::UsageDataCounters::SnippetCounter.count(:update) if succeeded
+ end
end
end
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
index ab08d5c4906..495ee6a04ea 100644
--- a/app/views/admin/services/_form.html.haml
+++ b/app/views/admin/services/_form.html.haml
@@ -6,6 +6,5 @@
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'fieldset-form' } do |form|
= render 'shared/service_settings', form: form, subject: @service
- - unless @service.is_a?(KubernetesService)
- .footer-block.row-content-block
- = form.submit 'Save', class: 'btn btn-success'
+ .footer-block.row-content-block
+ = form.submit 'Save', class: 'btn btn-success'
diff --git a/app/views/ci/variables/_environment_scope.html.haml b/app/views/ci/variables/_environment_scope.html.haml
new file mode 100644
index 00000000000..15e61d85881
--- /dev/null
+++ b/app/views/ci/variables/_environment_scope.html.haml
@@ -0,0 +1,21 @@
+- form_field = local_assigns.fetch(:form_field, nil)
+- variable = local_assigns.fetch(:variable, nil)
+
+- if @project
+ - environment_scope = variable&.environment_scope || '*'
+ - environment_scope_label = environment_scope == '*' ? s_('CiVariable|All environments') : environment_scope
+
+ %input{ type: "hidden", name: "#{form_field}[variables_attributes][][environment_scope]", value: environment_scope }
+ = dropdown_tag(environment_scope_label,
+ options: { wrapper_class: 'ci-variable-body-item js-variable-environment-dropdown-wrapper',
+ toggle_class: 'js-variable-environment-toggle wide',
+ filter: true,
+ dropdown_class: "dropdown-menu-selectable",
+ placeholder: s_('CiVariable|Search environments'),
+ footer_content: true,
+ data: { selected: environment_scope } }) do
+ %ul.dropdown-footer-list
+ %li
+ %button{ class: "dropdown-create-new-item-button js-dropdown-create-new-item", title: s_('CiVariable|New environment') }
+ = s_('CiVariable|Create wildcard')
+ %code
diff --git a/app/views/ci/variables/_environment_scope_header.html.haml b/app/views/ci/variables/_environment_scope_header.html.haml
new file mode 100644
index 00000000000..4ba4ceec16c
--- /dev/null
+++ b/app/views/ci/variables/_environment_scope_header.html.haml
@@ -0,0 +1,2 @@
+.bold.table-section.section-15.append-right-10
+ = s_('CiVariables|Scope')
diff --git a/app/views/projects/forks/_fork_button.html.haml b/app/views/projects/forks/_fork_button.html.haml
index 3f0798a898d..c7ed6a5094d 100644
--- a/app/views/projects/forks/_fork_button.html.haml
+++ b/app/views/projects/forks/_fork_button.html.haml
@@ -5,9 +5,9 @@
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default.forked
= link_to project_path(forked_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
- = group_icon(namespace, class: "avatar rect-avatar s100 identicon")
+ = group_icon(namespace, class: "avatar rect-avatar s100 identicon mx-auto")
- else
- .avatar-container.s100
+ .avatar-container.s100.mx-auto
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
@@ -18,9 +18,9 @@
class: ("disabled has-tooltip" unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
- = group_icon(namespace, class: "avatar rect-avatar s100 identicon")
+ = group_icon(namespace, class: "avatar rect-avatar s100 identicon mx-auto")
- else
- .avatar-container.s100
+ .avatar-container.s100.mx-auto
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
diff --git a/app/views/projects/services/prometheus/_metrics.html.haml b/app/views/projects/services/prometheus/_metrics.html.haml
index 3aefb3fdbb9..7685dee08fc 100644
--- a/app/views/projects/services/prometheus/_metrics.html.haml
+++ b/app/views/projects/services/prometheus/_metrics.html.haml
@@ -8,15 +8,16 @@
.col-lg-9
.card.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/index') } }
.card-header
- = s_('PrometheusService|Common metrics')
+ %strong
+ = s_('PrometheusService|Common metrics')
%span.badge.badge-pill.js-monitored-count 0
.card-body
.loading-metrics.js-loading-metrics
- %p.prepend-top-10.prepend-left-10
+ %p.m-3
= icon('spinner spin', class: 'metrics-load-spinner')
= s_('PrometheusService|Finding and configuring metrics...')
.empty-metrics.hidden.js-empty-metrics
- %p.text-tertiary.prepend-top-10.prepend-left-10
+ %p.text-tertiary.m-3
= s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics')
%ul.list-unstyled.metrics-list.hidden.js-metrics-list
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 07a7b5ce9de..214e87052da 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -33,8 +33,6 @@
= render_if_exists 'shared/issuable/approvals', issuable: issuable, presenter: presenter, form: form
-= render_if_exists "shared/issuable/form/merge_request_blocks", issuable: issuable, form: form
-
= render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form
= render 'shared/issuable/form/merge_params', issuable: issuable
diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml
index 1e03440a5dc..90a6a98235d 100644
--- a/app/views/shared/issuable/form/_metadata.html.haml
+++ b/app/views/shared/issuable/form/_metadata.html.haml
@@ -23,6 +23,7 @@
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label"
= render_if_exists "shared/issuable/form/weight", issuable: issuable, form: form
+ = render_if_exists "shared/issuable/form/merge_request_blocks", issuable: issuable, form: form
- if has_due_date
.col-lg-6
diff --git a/changelogs/unreleased/39217-remove-kubernetes-service-integration.yml b/changelogs/unreleased/39217-remove-kubernetes-service-integration.yml
new file mode 100644
index 00000000000..e13e3e86a37
--- /dev/null
+++ b/changelogs/unreleased/39217-remove-kubernetes-service-integration.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Kubernetes service integration page
+merge_request: 31365
+author:
+type: removed
diff --git a/changelogs/unreleased/4221-board-milestone-should-persist-any-none-properly.yml b/changelogs/unreleased/4221-board-milestone-should-persist-any-none-properly.yml
deleted file mode 100644
index d50c59bf607..00000000000
--- a/changelogs/unreleased/4221-board-milestone-should-persist-any-none-properly.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: For milestone filters, treat Any as No Filter (using null). Use -1 for No Milestone
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/63671-remove-extra-padding-from-the-disabled-comment-area.yml b/changelogs/unreleased/63671-remove-extra-padding-from-the-disabled-comment-area.yml
new file mode 100644
index 00000000000..ab116674ced
--- /dev/null
+++ b/changelogs/unreleased/63671-remove-extra-padding-from-the-disabled-comment-area.yml
@@ -0,0 +1,5 @@
+---
+title: Remove extra padding from disabled comment box
+merge_request: 31603
+author:
+type: fixed
diff --git a/changelogs/unreleased/63888-snippets-usage-ping-for-create-smau.yml b/changelogs/unreleased/63888-snippets-usage-ping-for-create-smau.yml
new file mode 100644
index 00000000000..1a5a552b120
--- /dev/null
+++ b/changelogs/unreleased/63888-snippets-usage-ping-for-create-smau.yml
@@ -0,0 +1,5 @@
+---
+title: Count snippet creation, update and comment events
+merge_request: 30930
+author:
+type: added
diff --git a/changelogs/unreleased/65700-document-max-replication-slots-pg-ha.yml b/changelogs/unreleased/65700-document-max-replication-slots-pg-ha.yml
new file mode 100644
index 00000000000..bacc3f5fc11
--- /dev/null
+++ b/changelogs/unreleased/65700-document-max-replication-slots-pg-ha.yml
@@ -0,0 +1,5 @@
+---
+title: Add max_replication_slots to PG HA documentation
+merge_request: 31534
+author:
+type: other
diff --git a/changelogs/unreleased/add-release-to-github-importer.yml b/changelogs/unreleased/add-release-to-github-importer.yml
new file mode 100644
index 00000000000..d11e7c725f7
--- /dev/null
+++ b/changelogs/unreleased/add-release-to-github-importer.yml
@@ -0,0 +1,5 @@
+---
+title: Add a field for released_at to GH importer
+merge_request: 31496
+author:
+type: fixed
diff --git a/changelogs/unreleased/bring-scoped-environment-variables-to-core.yml b/changelogs/unreleased/bring-scoped-environment-variables-to-core.yml
new file mode 100644
index 00000000000..48dfe662206
--- /dev/null
+++ b/changelogs/unreleased/bring-scoped-environment-variables-to-core.yml
@@ -0,0 +1,5 @@
+---
+title: Bring scoped environment variables to core
+merge_request: 30779
+author:
+type: changed
diff --git a/changelogs/unreleased/filter-title-description-and-body-from-logs.yml b/changelogs/unreleased/filter-title-description-and-body-from-logs.yml
new file mode 100644
index 00000000000..8b592790629
--- /dev/null
+++ b/changelogs/unreleased/filter-title-description-and-body-from-logs.yml
@@ -0,0 +1,5 @@
+---
+title: Filter title, description, and body parameters from logs
+merge_request:
+author:
+type: changed
diff --git a/changelogs/unreleased/rails-template-update.yml b/changelogs/unreleased/rails-template-update.yml
new file mode 100644
index 00000000000..53eb57c84ff
--- /dev/null
+++ b/changelogs/unreleased/rails-template-update.yml
@@ -0,0 +1,5 @@
+---
+title: Update 'Ruby on Rails' project template
+merge_request: 31310
+author:
+type: other
diff --git a/changelogs/unreleased/sh-add-gitaly-and-rugged-data-sidekiq.yml b/changelogs/unreleased/sh-add-gitaly-and-rugged-data-sidekiq.yml
new file mode 100644
index 00000000000..d2143e83045
--- /dev/null
+++ b/changelogs/unreleased/sh-add-gitaly-and-rugged-data-sidekiq.yml
@@ -0,0 +1,5 @@
+---
+title: Add Gitaly and Rugged call timing in Sidekiq logs
+merge_request: 31651
+author:
+type: other
diff --git a/changelogs/unreleased/sh-rename-githost-to-gitjson.yml b/changelogs/unreleased/sh-rename-githost-to-gitjson.yml
new file mode 100644
index 00000000000..24fcd1e9781
--- /dev/null
+++ b/changelogs/unreleased/sh-rename-githost-to-gitjson.yml
@@ -0,0 +1,5 @@
+---
+title: Rename githost.log -> git_json.log
+merge_request: 31634
+author:
+type: changed
diff --git a/changelogs/unreleased/speed-up-labels-api.yml b/changelogs/unreleased/speed-up-labels-api.yml
new file mode 100644
index 00000000000..d5ac4313414
--- /dev/null
+++ b/changelogs/unreleased/speed-up-labels-api.yml
@@ -0,0 +1,5 @@
+---
+title: Remove counts from default labels API responses
+merge_request: 31543
+author:
+type: changed
diff --git a/changelogs/unreleased/visual-review-tools-constant-storage-keys.yml b/changelogs/unreleased/visual-review-tools-constant-storage-keys.yml
new file mode 100644
index 00000000000..4c9b048aaa3
--- /dev/null
+++ b/changelogs/unreleased/visual-review-tools-constant-storage-keys.yml
@@ -0,0 +1,5 @@
+---
+title: Fix visual review app storage keys
+merge_request: 31427
+author:
+type: fixed
diff --git a/config/application.rb b/config/application.rb
index 21cb79f7851..47c5ab71285 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -105,10 +105,23 @@ module Gitlab
# - Sentry DSN (:sentry_dsn)
# - File content from Web Editor (:content)
# - Jira shared secret (:sharedSecret)
+ # - Titles, bodies, and descriptions for notes, issues, etc.
#
- # NOTE: It is **IMPORTANT** to also update gitlab-workhorse's filter when adding parameters here to not
- # introduce another security vulnerability: https://gitlab.com/gitlab-org/gitlab-workhorse/issues/182
- config.filter_parameters += [/token$/, /password/, /secret/, /key$/, /^note$/, /^text$/]
+ # NOTE: It is **IMPORTANT** to also update labkit's filter when
+ # adding parameters here to not introduce another security
+ # vulnerability:
+ # https://gitlab.com/gitlab-org/labkit/blob/master/mask/matchers.go
+ config.filter_parameters += [
+ /token$/,
+ /password/,
+ /secret/,
+ /key$/,
+ /^body$/,
+ /^description$/,
+ /^note$/,
+ /^text$/,
+ /^title$/
+ ]
config.filter_parameters += %i(
certificate
encrypted_key
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
index 3d84b4e44ce..346725e4080 100644
--- a/config/initializers/lograge.rb
+++ b/config/initializers/lograge.rb
@@ -27,19 +27,7 @@ unless Sidekiq.server?
queue_duration: event.payload[:queue_duration]
}
- gitaly_calls = Gitlab::GitalyClient.get_request_count
-
- if gitaly_calls > 0
- payload[:gitaly_calls] = gitaly_calls
- payload[:gitaly_duration] = Gitlab::GitalyClient.query_time_ms
- end
-
- rugged_calls = Gitlab::RuggedInstrumentation.query_count
-
- if rugged_calls > 0
- payload[:rugged_calls] = rugged_calls
- payload[:rugged_duration_ms] = Gitlab::RuggedInstrumentation.query_time_ms
- end
+ ::Gitlab::InstrumentationHelper.add_instrumentation_data(payload)
payload[:response] = event.payload[:response] if event.payload[:response]
payload[Labkit::Correlation::CorrelationId::LOG_KEY] = Labkit::Correlation::CorrelationId.current_id
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 9f88fb9895b..7217f098fd9 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -39,6 +39,7 @@ Sidekiq.configure_server do |config|
chain.add Gitlab::SidekiqMiddleware::RequestStoreMiddleware unless ENV['SIDEKIQ_REQUEST_STORE'] == '0'
chain.add Gitlab::SidekiqMiddleware::BatchLoader
chain.add Gitlab::SidekiqMiddleware::CorrelationLogger
+ chain.add Gitlab::SidekiqMiddleware::InstrumentationLogger
chain.add Gitlab::SidekiqStatus::ServerMiddleware
end
diff --git a/db/migrate/20190703001120_default_milestone_to_nil.rb b/db/migrate/20190703001120_default_milestone_to_nil.rb
deleted file mode 100644
index 6a1c3603d9d..00000000000
--- a/db/migrate/20190703001120_default_milestone_to_nil.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-class DefaultMilestoneToNil < ActiveRecord::Migration[5.1]
- DOWNTIME = false
-
- def up
- execute(update_board_milestones_query)
- end
-
- def down
- # no-op
- end
-
- private
-
- # Only 105 records to update, as of 2019/07/18
- def update_board_milestones_query
- <<~HEREDOC
- UPDATE boards
- SET milestone_id = NULL
- WHERE boards.milestone_id = -1
- HEREDOC
- end
-end
diff --git a/db/migrate/20190801060809_delete_kubernetes_services.rb b/db/migrate/20190801060809_delete_kubernetes_services.rb
new file mode 100644
index 00000000000..018976584d4
--- /dev/null
+++ b/db/migrate/20190801060809_delete_kubernetes_services.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class DeleteKubernetesServices < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def up
+ Service.where(type: "KubernetesService").delete_all
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/migrate/20190802195602_add_timestamps_columns_to_geo_nodes.rb b/db/migrate/20190802195602_add_timestamps_columns_to_geo_nodes.rb
new file mode 100644
index 00000000000..b95d9037afe
--- /dev/null
+++ b/db/migrate/20190802195602_add_timestamps_columns_to_geo_nodes.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddTimestampsColumnsToGeoNodes < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ def change
+ add_column(:geo_nodes, :created_at, :datetime_with_timezone, null: true)
+ add_column(:geo_nodes, :updated_at, :datetime_with_timezone, null: true)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 890f4ab4d8a..0e4a3d07fdd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1450,6 +1450,8 @@ ActiveRecord::Schema.define(version: 2019_08_02_235445) do
t.string "internal_url"
t.string "name", null: false
t.integer "container_repositories_max_capacity", default: 10, null: false
+ t.datetime_with_timezone "created_at"
+ t.datetime_with_timezone "updated_at"
t.index ["access_key"], name: "index_geo_nodes_on_access_key"
t.index ["name"], name: "index_geo_nodes_on_name", unique: true
t.index ["primary"], name: "index_geo_nodes_on_primary"
diff --git a/doc/README.md b/doc/README.md
index af675582a99..edce03baec9 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -25,7 +25,7 @@ No matter how you use GitLab, we have documentation for you.
| [**User Documentation**](user/index.md)<br/>Discover features and concepts for GitLab users. | [**Administrator documentation**](administration/index.md)<br/>Everything GitLab self-managed administrators need to know. |
| [**Contributing to GitLab**](#contributing-to-gitlab)<br/>At GitLab, everyone can contribute! | [**New to Git and GitLab?**](#new-to-git-and-gitlab)<br/>We have resources to get you started. |
| [**Building an integration with GitLab?**](#building-an-integration-with-gitlab)<br/>Consult our automation and integration documentation. | [**Coming to GitLab from another platform?**](#coming-to-gitlab-from-another-platform)<br/>Consult our handy guides. |
-| [**Install GitLab**](https://about.gitlab.com/install/)<br/>Installation options for different platforms. | [**Subscribe to GitLab**](#subscribe-to-gitlab)<br/>Get access to more features. |
+| [**Install GitLab**](https://about.gitlab.com/install/)<br/>Installation options for different platforms. | [**Customers**](subscriptions/index.md)<br/>Information for new and existing customers. |
| [**Update GitLab**](update/README.md)<br/>Update your GitLab self-managed instance to the latest version. | [**GitLab Releases**](https://about.gitlab.com/releases/)<br/>What's new in GitLab. |
## Popular Documentation
@@ -38,7 +38,7 @@ Have a look at some of our most popular documentation resources:
| [GitLab CI/CD examples](ci/examples/README.md) | Get up to speed quickly with common CI/CD scenarios. |
| [GitLab Container Registry](user/project/container_registry.md) | Host containers within GitLab. |
| [GitLab Pages](user/project/pages/index.md) | Host static websites for your projects with GitLab. |
-| [GitLab.com settings](user/gitlab_com/index.md) | Settings for [GitLab.com](#gitlabcom). |
+| [GitLab.com settings](user/gitlab_com/index.md) | Settings for GitLab.com. |
| [Kubernetes integration](user/project/clusters/index.md) | Use GitLab with Kubernetes. |
| [SSH authentication](ssh/README.md) | Secure your network communications. |
| [Using Docker images](ci/docker/using_docker_images.md) | Build and test your applications with Docker. |
@@ -279,7 +279,7 @@ The following documentation relates to the DevOps **Release** stage:
| [Canary Deployments](user/project/canary_deployments.md) **(PREMIUM)** | Employ a popular CI strategy where a small portion of the fleet is updated to the new version first. |
| [Deploy Boards](user/project/deploy_boards.md) **(PREMIUM)** | View the current health and status of each CI environment running on Kubernetes, displaying the status of the pods in the deployment. |
| [Environments and deployments](ci/environments.md) | With environments, you can control the continuous deployment of your software within GitLab. |
-| [Environment-specific variables](ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium) **(PREMIUM)** | Limit scope of variables to specific environments. |
+| [Environment-specific variables](ci/variables/README.md#limiting-environment-scopes-of-environment-variables) | Limit scope of variables to specific environments. |
| [GitLab CI/CD](ci/README.md) | Explore the features and capabilities of Continuous Deployment and Delivery with GitLab. |
| [GitLab Pages](user/project/pages/index.md) | Build, test, and deploy a static site directly from GitLab. |
| [Protected Runners](ci/runners/README.md#protected-runners) | Select Runners to only pick jobs for protected branches and tags. |
@@ -361,90 +361,6 @@ The following documentation relates to the DevOps **Secure** stage:
| [Project Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View the latest security reports for your project. |
| [Static Application Security Testing (SAST)](user/application_security/sast/index.md) **(ULTIMATE)** | Analyze source code for known vulnerabilities. |
-## Subscribe to GitLab
-
-There are two ways to use GitLab:
-
-- [GitLab self-managed](#gitlab-self-managed): Install, administer, and maintain your own GitLab instance.
-- [GitLab.com](#gitlabcom): GitLab's SaaS offering. You don't need to install anything to use GitLab.com,
- you only need to [sign up](https://gitlab.com/users/sign_in) and start using GitLab straight away.
-
-For more information on managing your subscription and [Customers Portal](https://customers.gitlab.com) account, please see [Getting Started with Subscriptions](getting-started/subscription.md).
-
-The following sections outline tiers and features within GitLab self-managed and GitLab.com.
-
-<div align="right">
- <a type="button" class="btn btn-default" href="#overview">
- Back to Overview <i class="fa fa-angle-double-up" aria-hidden="true"></i>
- </a>
-</div>
-
-### GitLab self-managed
-
-With GitLab self-managed, you deploy your own GitLab instance on-premises or on a cloud of your choice.
-GitLab self-managed is available for [free and with paid subscriptions](https://about.gitlab.com/pricing/#self-managed) in the following tiers:
-
-| Tier | Includes |
-|:---------|:-----------------------------------------------|
-| Core | Core features. |
-| Starter | Core and Starter features. |
-| Premium | Core, Starter, and Premium features. |
-| Ultimate | Core, Starter, Premium, and Ultimate features. |
-
-The following resources are available for more information on GitLab self-managed:
-
-- [Feature comparison](https://about.gitlab.com/pricing/self-managed/feature-comparison/), for information on what features are available at each tier.
-- [GitLab pricing page](https://about.gitlab.com/pricing/#self-managed), for subscription information and a free trial.
-- Our [product marketing page](https://about.gitlab.com/handbook/marketing/product-marketing/), for additional information including:
- - How [different tiers are licensed](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers).
- - The different [GitLab distributions](https://about.gitlab.com/handbook/marketing/product-marketing/#distributions).
-
-<div align="right">
- <a type="button" class="btn btn-default" href="#overview">
- Back to Overview <i class="fa fa-angle-double-up" aria-hidden="true"></i>
- </a>
-</div>
-
-### GitLab.com
-
-GitLab.com is hosted, managed, and administered by GitLab, Inc., with
-[free and paid subscriptions](https://about.gitlab.com/pricing/) for individuals
-and teams in the following tiers:
-
-| Tier | Includes same features available in |
-|:-------|:----------------------------------------------------|
-| Free | [Core](#gitlab-self-managed) self-managed tier. |
-| Bronze | [Starter](#gitlab-self-managed) self-managed tier. |
-| Silver | [Premium](#gitlab-self-managed) self-managed tier. |
-| Gold | [Ultimate](#gitlab-self-managed) self-managed tier. |
-
-GitLab.com subscriptions grant access
-to the same features available in GitLab self-managed, **except
-[administration](administration/index.md) tools and settings**.
-
-GitLab.com allows you to apply your subscription to a group or your personal user.
-
-When applied to a **group**, the group, all subgroups, and all projects under the selected group on GitLab.com will have the features of the associated plan. It is recommended to go with a group plan when managing projects and users of an organization.
-
-When associated with a **personal userspace** instead, all projects will have features with the subscription applied, but as it is not a group, group features will not be available.
-
-TIP: **Tip:**
-To support the open source community and encourage the development of open source projects, GitLab grants access to **Gold** features for all GitLab.com **public** projects, regardless of the subscription.
-
-The following resources are available for more information on GitLab.com:
-
-- [Feature comparison](https://about.gitlab.com/pricing/gitlab-com/feature-comparison/), for information on what features are available at each tier.
-- [GitLab pricing page](https://about.gitlab.com/pricing/), for subscription information and a free trial.
-- Our [product marketing page](https://about.gitlab.com/handbook/marketing/product-marketing/), for additional information including:
- - How [different tiers are licensed](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers).
- - The different [GitLab distributions](https://about.gitlab.com/handbook/marketing/product-marketing/#distributions).
-
-<div align="right">
- <a type="button" class="btn btn-default" href="#overview">
- Back to Overview <i class="fa fa-angle-double-up" aria-hidden="true"></i>
- </a>
-</div>
-
## New to Git and GitLab?
Working with new systems can be daunting.
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 28abfff973d..fe1557fd8b5 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -230,7 +230,7 @@ sudo gitlab-ctl reconfigure
This will increase the timeout to three hours (10800 seconds). Choose a time
long enough to accommodate a full clone of your largest repositories.
-### Reseting Geo **secondary** node replication
+### Resetting Geo **secondary** node replication
If you get a **secondary** node in a broken state and want to reset the replication state,
to start again from scratch, there are a few steps that can help you:
@@ -524,6 +524,20 @@ If it doesn't exist or inadvertent changes have been made to it, run `sudo gitla
If this path is mounted on a remote volume, please check your volume configuration and that it has correct permissions.
+### An existing tracking database cannot be reused
+
+Geo cannot reuse an existing tracking database.
+
+It is safest to use a fresh secondary, or reset the whole secondary by following
+[Resetting Geo secondary node replication](#resetting-geo-secondary-node-replication).
+
+If you are not concerned about possible orphaned directories and files, then you
+can simply reset the existing tracking database with:
+
+```sh
+sudo gitlab-rake geo:db:reset
+```
+
### Geo node has a database that is writable which is an indication it is not configured for replication with the primary node.
This error refers to a problem with the database replica on a **secondary** node,
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
index f7a1f425b40..7c9e02d889e 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -327,6 +327,7 @@ When installing the GitLab package, do not supply `EXTERNAL_URL` value.
postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
# Replace X with value of number of db nodes + 1
postgresql['max_wal_senders'] = X
+ postgresql['max_replication_slots'] = X
# Replace XXX.XXX.XXX.XXX/YY with Network Address
postgresql['trust_auth_cidr_addresses'] = %w(XXX.XXX.XXX.XXX/YY)
diff --git a/doc/administration/index.md b/doc/administration/index.md
index f7f9d753e58..91a4d5097f2 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -188,3 +188,5 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- Useful [diagnostics tools](troubleshooting/diagnostics_tools.md) that are sometimes used by the GitLab
Support team.
- [Troubleshooting ElasticSearch](troubleshooting/elasticsearch.md): Tips to troubleshoot ElasticSearch.
+- [Kubernetes troubleshooting](troubleshooting/kubernetes_cheat_sheet.md): Commands and tips useful
+ for troubleshooting Kubernetes-related issues.
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 31876dd178a..47abbc512e0 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -151,14 +151,15 @@ etc. For example:
{"severity":"ERROR","time":"2018-11-23T15:42:11.647Z","exception":"Kubeclient::HttpError","error_code":null,"service":"Clusters::Applications::InstallService","app_id":2,"project_ids":[19],"group_ids":[],"message":"SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate)"}
```
-## `githost.log`
+## `git_json.log`
-This file lives in `/var/log/gitlab/gitlab-rails/githost.log` for
-Omnibus GitLab packages or in `/home/git/gitlab/log/githost.log` for
+This file lives in `/var/log/gitlab/gitlab-rails/git_json.log` for
+Omnibus GitLab packages or in `/home/git/gitlab/log/git_json.log` for
installations from source.
NOTE: **Note:**
-After 12.2, this file will be stored in JSON format.
+After 12.2, this file was renamed from `githost.log` to
+`git_json.log` and stored in JSON format.
GitLab has to interact with Git repositories but in some rare cases
something can go wrong and in this case you will know what exactly
diff --git a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
new file mode 100644
index 00000000000..95cdb1508fa
--- /dev/null
+++ b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
@@ -0,0 +1,251 @@
+---
+type: reference
+---
+
+# Kubernetes, GitLab and You
+
+This is a list of useful information regarding Kubernetes that the GitLab Support
+Team sometimes uses while troubleshooting. GitLab is making this public, so that anyone
+can make use of the Support team's collected knowledge
+
+CAUTION: **Caution:**
+These commands **can alter or break** your Kubernetes components so use these at your own risk.
+
+If you are on a [paid tier](https://about.gitlab.com/pricing/) and are not sure how
+to use these commands, it is best to [contact Support](https://about.gitlab.com/support/)
+and they will assist you with any issues you are having.
+
+## Generic kubernetes commands
+
+- How to authorize to your GCP project (can be especially useful if you have projects
+ under different GCP accounts):
+
+ ```bash
+ gcloud auth login
+ ```
+
+- How to access Kubernetes dashboard:
+
+ ```bash
+ # for minikube:
+ minikube dashboard —url
+ # for non-local installations if access via kubectl is configured:
+ kubectl proxy
+ ```
+
+- How to ssh to a Kubernetes node and enter the container as root
+ <https://github.com/kubernetes/kubernetes/issues/30656>:
+
+ - For GCP, you may find the node name and run `gcloud compute ssh node-name`.
+ - List containers using `docker ps`.
+ - Enter container using `docker exec --user root -ti container-id bash`.
+
+- How to copy a file from local machine to a pod:
+
+ ```bash
+ kubectl cp file-name pod-name:./destination-path
+ ```
+
+- What to do with pods in `CrashLoopBackoff` status:
+
+ - Check logs via Kubernetes dashboard.
+ - Check logs via `kubectl`:
+
+ ```bash
+ kubectl logs <unicorn pod> -c dependencies
+ ```
+
+- How to tail all Kubernetes cluster events in real time:
+
+ ```bash
+ kubectl get events -w --all-namespaces
+ ```
+
+- How to get logs of the previously terminated pod instance:
+
+ ```bash
+ kubectl logs <pod-name> --previous
+ ```
+
+ NOTE: **Note:**
+ No logs are kept in the containers/pods themselves, everything is written to stdout.
+ This is the principle of Kubernetes, read [Twelve-factor app](https://12factor.net/)
+ for details.
+
+## Gitlab-specific kubernetes information
+
+- Minimal config that can be used to test a Kubernetes helm chart can be found
+ [here](https://gitlab.com/charts/gitlab/issues/620).
+
+- Tailing logs of a separate pod. An example for a unicorn pod:
+
+ ```bash
+ kubectl logs gitlab-unicorn-7656fdd6bf-jqzfs -c unicorn
+ ```
+
+- It is not possible to get all the logs via `kubectl` at once, like with `gitlab-ctl tail`,
+ but a number of third-party tools can be used to do it:
+
+ - [Kubetail](https://github.com/johanhaleby/kubetail)
+ - [kail: kubernetes tail](https://github.com/boz/kail)
+ - [stern](https://github.com/wercker/stern)
+
+- Check all events in the `gitlab` namespace (the namespace name can be different if you
+ specified a different one when deploying the helm chart):
+
+ ```bash
+ kubectl get events -w --namespace=gitlab
+ ```
+
+- Most of the useful GitLab tools (console, rake tasks, etc) are found in the task-runner
+ pod. You may enter it and run commands inside or run them from the outside:
+
+ ```bash
+ # find the pod
+ kubectl get pods | grep task-runner
+
+ # enter it
+ kubectl exec -it <task-runner-pod-name> bash
+
+ # open rails console
+ # rails console can be also called from other GitLab pods
+ /srv/gitlab/bin/rails console
+
+ # source-style commands should also work
+ /srv/gitlab && bundle exec rake gitlab:check RAILS_ENV=production
+
+ # run GitLab check. Note that the output can be confusing and invalid because of the specific structure of GitLab installed via helm chart
+ /usr/local/bin/gitlab-rake gitlab:check
+
+ # open console without entering pod
+ kubectl exec -it <task-runner-pod-name> /srv/gitlab/bin/rails console
+
+ # check the status of DB migrations
+ kubectl exec -it <task-runner-pod-name> /usr/local/bin/gitlab-rake db:migrate:status
+ ```
+
+ You can also use `gitlab-rake`, instead of `/usr/local/bin/gitlab-rake`.
+
+- Troubleshooting **Operations > Kubernetes** integration:
+
+ - Check the output of `kubectl get events -w --all-namespaces`.
+ - Check the logs of pods within `gitlab-managed-apps` namespace.
+ - On the side of GitLab check sidekiq log and kubernetes log. When GitLab is installed
+ via helm chart, kubernetes.log can be found inside the sidekiq pod.
+
+- How to get your initial admin password <https://docs.gitlab.com/charts/installation/deployment.html#initial-login>:
+
+ ```bash
+ # find the name of the secret containing the password
+ kubectl get secrets | grep initial-root
+ # decode it
+ kubectl get secret <secret-name> -ojsonpath={.data.password} | base64 --decode ; echo
+ ```
+
+- How to connect to a GitLab postgres database:
+
+ ```bash
+ kubectl exec -it <task-runner-pod-name> -- /srv/gitlab/bin/rails dbconsole -p
+ ```
+
+- How to get info about helm installation status:
+
+ ```bash
+ helm status name-of-installation
+ ```
+
+- How to update GitLab installed using helm chart:
+
+ ```bash
+ helm repo upgrade
+
+ # get current values and redirect them to yaml file (analogue of gitlab.rb values)
+ helm get values <release name> > gitlab.yaml
+
+ # run upgrade itself
+ helm upgrade <release name> <chart path> -f gitlab.yaml
+ ```
+
+ After <https://canary.gitlab.com/charts/gitlab/issues/780> is fixed, it should
+ be possible to use [Updating GitLab using the Helm Chart](https://docs.gitlab.com/ee/install/kubernetes/gitlab_chart.html#updating-gitlab-using-the-helm-chart)
+ for upgrades.
+
+- How to apply changes to GitLab config:
+
+ - Modify the `gitlab.yaml` file.
+ - Run the following command to apply changes:
+
+ ```bash
+ helm upgrade <release name> <chart path> -f gitlab.yaml
+ ```
+
+## Installation of minimal GitLab config via minukube on macOS
+
+This section is based on [Developing for Kubernetes with Minikube](https://gitlab.com/charts/gitlab/blob/master/doc/minikube/index.md)
+and [Helm](https://gitlab.com/charts/gitlab/blob/master/doc/helm/index.md). Refer
+to those documents for details.
+
+- Install kubectl via Homebrew:
+
+ ```bash
+ brew install kubernetes-cli
+ ```
+
+- Install minikube via Homebrew:
+
+ ```bash
+ brew cask install minikube
+ ```
+
+- Start minikube and configure it. If minikube cannot start, try running `minikube delete && minikube start`
+ and repeat the steps:
+
+ ```bash
+ minikube start --cpus 3 --memory 8192 # minimum amount for GitLab to work
+ minikube addons enable ingress
+ minikube addons enable kube-dns
+ ```
+
+- Install helm via Homebrew and initialize it:
+
+ ```bash
+ brew install kubernetes-helm
+ helm init --service-account tiller
+ ```
+
+- Copy the file <https://gitlab.com/charts/gitlab/raw/master/examples/values-minikube-minimum.yaml>
+ to your workstation.
+
+- Find the IP address in the output of `minikube ip` and update the yaml file with
+ this IP address.
+
+- Install the GitLab helm chart:
+
+ ```bash
+ helm repo add gitlab https://charts.gitlab.io
+ helm install --name gitlab -f <path-to-yaml-file> gitlab/gitlab
+ ```
+
+ If you want to modify some GitLab settings, you can use the above-mentioned config
+ as a base and create your own yaml file.
+
+- Monitor the installation progress via `helm status gitlab` and `minikube dashboard`.
+ The installation could take up to 20-30 minutes depending on the amount of resources
+ on your workstation.
+
+- When all the pods show either a `Running` or `Completed` status, get the GitLab password as
+ described in [Initial login](https://docs.gitlab.com/ee/install/kubernetes/gitlab_chart.html#initial-login),
+ and log in to GitLab via the UI. It will be accessible via `https://gitlab.domain`
+ where `domain` is the value provided in the yaml file.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/api/group_labels.md b/doc/api/group_labels.md
index 3d4b099b49e..e2ba0dea642 100644
--- a/doc/api/group_labels.md
+++ b/doc/api/group_labels.md
@@ -12,12 +12,13 @@ Get all labels for a given group.
GET /groups/:id/labels
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `with_counts` | boolean | no | Whether or not to include issue and merge request counts. Defaults to `false`. _([Introduced in GitLab 12.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31543))_ |
```bash
-curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/labels
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/labels?with_counts=true
```
Example response:
diff --git a/doc/api/labels.md b/doc/api/labels.md
index 9d10d383bf9..5db0edcf14d 100644
--- a/doc/api/labels.md
+++ b/doc/api/labels.md
@@ -8,12 +8,13 @@ Get all labels for a given project.
GET /projects/:id/labels
```
-| 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 |
+| 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 |
+| `with_counts` | boolean | no | Whether or not to include issue and merge request counts. Defaults to `false`. _([Introduced in GitLab 12.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31543))_ |
```bash
-curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/labels
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/labels?with_counts=true
```
Example response:
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index eab905bbc5f..591911bb8ec 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -74,7 +74,7 @@ POST /projects/:id/variables
| `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 |
-| `environment_scope` | string | no | The `environment_scope` of the variable **(PREMIUM)** |
+| `environment_scope` | string | no | The `environment_scope` of the variable |
```
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
@@ -108,7 +108,7 @@ PUT /projects/:id/variables/:key
| `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 |
-| `environment_scope` | string | no | The `environment_scope` of the variable **(PREMIUM)** |
+| `environment_scope` | string | no | The `environment_scope` of the variable |
```
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
diff --git a/doc/api/services.md b/doc/api/services.md
index 45b49d7eb92..7d025cd3bdf 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -595,44 +595,6 @@ Remove all previously Jira settings from a project.
DELETE /projects/:id/services/jira
```
-## Kubernetes
-
-Kubernetes / OpenShift integration
-
-CAUTION: **Warning:**
-Kubernetes service integration has been deprecated in GitLab 10.3. API service endpoints will continue to work as long as the Kubernetes service is active, however if the service is inactive API endpoints will automatically return a `400 Bad Request`. Read [GitLab 10.3 release post](https://about.gitlab.com/2017/12/22/gitlab-10-3-released/#kubernetes-integration-service) for more information.
-
-### Create/Edit Kubernetes service
-
-Set Kubernetes service for a project.
-
-```
-PUT /projects/:id/services/kubernetes
-```
-
-Parameters:
-
-- `namespace` (**required**) - The Kubernetes namespace to use
-- `api_url` (**required**) - The URL to the Kubernetes cluster API. For example, `https://kubernetes.example.com`
-- `token` (**required**) - The service token to authenticate against the Kubernetes cluster with
-- `ca_pem` (optional) - A custom certificate authority bundle to verify the Kubernetes cluster with (PEM format)
-
-### Delete Kubernetes service
-
-Delete Kubernetes service for a project.
-
-```
-DELETE /projects/:id/services/kubernetes
-```
-
-### Get Kubernetes service settings
-
-Get Kubernetes service settings for a project.
-
-```
-GET /projects/:id/services/kubernetes
-```
-
## Slack slash commands
Ability to receive slash commands from a Slack chat instance.
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index f86ca8f74f2..61559e69182 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -692,7 +692,7 @@ with `review/` would have that particular variable.
Some GitLab features can behave differently for each environment.
For example, you can
-[create a secret variable to be injected only into a production environment](variables/README.md#limiting-environment-scopes-of-environment-variables-premium). **(PREMIUM)**
+[create a secret variable to be injected only into a production environment](variables/README.md#limiting-environment-scopes-of-environment-variables).
In most cases, these features use the _environment specs_ mechanism, which offers
an efficient way to implement scoping within each environment group.
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 01edd873a8d..d741482b662 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -393,7 +393,7 @@ Protected variables can be added by going to your project's
Once you set them, they will be available for all subsequent pipelines.
-### Limiting environment scopes of environment variables **(PREMIUM)**
+### Limiting environment scopes of environment variables
You can limit the environment scope of a variable by
[defining which environments][envs] it can be available for.
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 091edb6ac40..87405bc2fec 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -568,7 +568,7 @@ Usage: /etc/init.d/postgresql {start|stop|restart|reload|force-reload|status} [v
gitlabhq (includes Unicorn and Sidekiq logs)
-- `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `unicorn.stdout.log`, `githost.log` and `unicorn.stderr.log` normally.
+- `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `unicorn.stdout.log`, `git_json.log` and `unicorn.stderr.log` normally.
gitlab-shell
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 3d10a0c84e5..3f1b359cb0b 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -90,12 +90,20 @@ and details for a database reviewer:
- Ensure that migrations execute in a transaction or only contain
concurrent index/foreign key helpers (with transactions disabled)
- Check consistency with `db/schema.rb` and that migrations are [reversible](migration_style_guide.md#reversibility)
+ - Check queries timing (If any): Queries executed in a migration
+ need to fit comfortable within `15s` - preferably much less than that - on GitLab.com.
+- Check [background migrations](background_migrations.md):
- For data migrations, establish a time estimate for execution
-- Check post deploy migration
- - Make sure we can expect post deploy migrations to finish within 1 hour max.
-- Check background migrations
+ - They should only be used when migrating data in larger tables.
+ - If a single `update` is below than `1s` the query can be placed
+ directly in a regular migration (inside `db/migrate`).
- Review queries (for example, make sure batch sizes are fine)
- Establish a time estimate for execution
+ - Because execution time can be longer than for a regular migration,
+ it's suggested to treat background migrations as post migrations:
+ place them in `db/post_migrate` instead of `db/migrate`. Keep in mind
+ that post migrations are executed post-deployment in production.
+- Check [timing guidelines for migrations](#timing-guidelines-for-migrations)
- Query performance
- Check for any obviously complex queries and queries the author specifically
points out for review (if any)
@@ -110,3 +118,17 @@ and details for a database reviewer:
(eg indexes, columns), you can use a [one-off instance from the restore
pipeline](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd)
in order to establish a proper testing environment.
+
+### Timing guidelines for migrations
+
+In general, migrations for a single deploy shouldn't take longer than
+1 hour for GitLab.com. The following guidelines are not hard rules, they were
+estimated to keep migration timing to a minimum.
+
+NOTE: **Note:** Keep in mind that all runtimes should be measured against GitLab.com.
+
+| Migration Type | Execution Time Recommended | Notes |
+|----|----|---|
+| Regular migrations on `db/migrate` | `3 minutes` | A valid exception are index creation as this can take a long time. |
+| Post migrations on `db/post_migrate` | `10 minutes` | |
+| Background migrations | --- | Since these are suitable for larger tables, it's not possible to set a precise timing guideline, however, any query must stay well below `10s` of execution time. |
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index 910d7296057..492e3d48164 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -80,6 +80,7 @@ are very appreciative of the work done by translators and proofreaders!
- Russian
- Nikita Grylov - [GitLab](https://gitlab.com/nixel2007), [Crowdin](https://crowdin.com/profile/nixel2007)
- Alexy Lustin - [GitLab](https://gitlab.com/allustin), [Crowdin](https://crowdin.com/profile/lustin)
+ - Mark Minakou - [GitLab](https://gitlab.com/sandzhaj), [Crowdin](https://crowdin.com/profile/sandzhaj)
- NickVolynkin - [Crowdin](https://crowdin.com/profile/NickVolynkin)
- Serbian (Cyrillic)
- Proofreaders needed.
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 0c7601b415e..3181b3a88cc 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -10,9 +10,7 @@ migrations are written carefully, can be applied online and adhere to the style
guide below.
Migrations are **not** allowed to require GitLab installations to be taken
-offline unless _absolutely necessary_. Downtime assumptions should be based on
-the behaviour of a migration when performed using PostgreSQL, as various
-operations in MySQL may require downtime without there being alternatives.
+offline unless _absolutely necessary_.
When downtime is necessary the migration has to be approved by:
@@ -343,10 +341,7 @@ class AddOptionsToBuildMetadata < ActiveRecord::Migration[5.0]
end
```
-On MySQL the `JSON` and `JSONB` is translated to `TEXT 1MB`, as `JSONB` is PostgreSQL only feature.
-
-For above reason you have to use a serializer to provide a translation layer
-in order to support PostgreSQL and MySQL seamlessly:
+You have to use a serializer to provide a translation layer:
```ruby
class BuildMetadata
@@ -356,7 +351,7 @@ end
## Testing
-Make sure that your migration works with MySQL and PostgreSQL with data. An
+Make sure that your migration works for databases with data. An
empty database does not guarantee that your migration is correct.
Make sure your migration can be reversed.
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index fed3b1ca595..358ba971049 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -610,7 +610,7 @@ To back up GitLab:
1. Take a backup:
```sh
- sudo gitlab-rake gitlab:backup:create
+ sudo gitlab-backup create
```
### Restoring GitLab from a backup
@@ -628,7 +628,7 @@ released, you can update your GitLab instance:
1. Take a backup:
```sh
- sudo gitlab-rake gitlab:backup:create
+ sudo gitlab-backup create
```
1. Update the repositories and install GitLab:
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index cfabc09646d..086f3b1b843 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -92,7 +92,8 @@ We recommend having at least [2GB of swap on your server](https://askubuntu.com/
enough available RAM. Having swap will help reduce the chance of errors occurring
if your available memory changes. We also recommend [configuring the kernel's swappiness setting](https://askubuntu.com/a/103916)
to a low value like `10` to make the most of your RAM while still having the swap
-available when needed.
+available when needed.
+Our [Memory Team](https://about.gitlab.com/handbook/engineering/development/enablement/memory/) is actively working to reduce this requirement.
NOTE: **Note:** The 25 workers of Sidekiq will show up as separate processes in your process overview (such as `top` or `htop`) but they share the same RAM allocation since Sidekiq is a multithreaded application. Please see the section below about Unicorn workers for information about how many you need of those.
diff --git a/doc/legal/corporate_contributor_license_agreement.md b/doc/legal/corporate_contributor_license_agreement.md
index 7f08188bd65..8c1f4a126b1 100644
--- a/doc/legal/corporate_contributor_license_agreement.md
+++ b/doc/legal/corporate_contributor_license_agreement.md
@@ -2,28 +2,28 @@
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
-1. Definitions.
+- **Definitions:**
- "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+ "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
- "Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
+ "Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-2. Grant of Copyright License.
+- **Grant of Copyright License:**
-Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
+ Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-3. Grant of Patent License.
+- **Grant of Patent License:**
-Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
+ Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
-4. You represent that You are legally entitled to grant the above license. You represent further that each of Your employees is authorized to submit Contributions on Your behalf, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of [name of Your corporation here]." Such designations of exclusion for unauthorized employees are to be submitted via email to legal@gitlab.com.
+ You represent that You are legally entitled to grant the above license. You represent further that each of Your employees is authorized to submit Contributions on Your behalf, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of (name of Your corporation here)." Such designations of exclusion for unauthorized employees are to be submitted via email to legal@gitlab.com. It is Your responsibility to notify GitLab B.V. when any change is required to the list of designated employees excluded from submitting Contributions on Your behalf. Such notification should also be sent via email to legal@gitlab.com.
-5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).
+- **Contributions:**
-6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
+ You represent that each of Your Contributions is Your original creation.
+
+ Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: (named here)".
-7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
-
-8. It is Your responsibility to notify GitLab.com when any change is required to the list of designated employees excluded from submitting Contributions on Your behalf per Section 4. Such notification should be sent via email to legal@gitlab.com.
+ You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office.
diff --git a/doc/legal/individual_contributor_license_agreement.md b/doc/legal/individual_contributor_license_agreement.md
index 59803aea080..7a071414629 100644
--- a/doc/legal/individual_contributor_license_agreement.md
+++ b/doc/legal/individual_contributor_license_agreement.md
@@ -2,24 +2,30 @@
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
-1. Definitions.
+- **Definitions:**
- "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+ "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
- "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
+ "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
+- **Grant of Copyright License:**
-3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
+ Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab B.V., or that your employer has executed a separate Corporate CLA with GitLab B.V..
+- **Grant of Patent License:**
-5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
+ Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
-6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
+ You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab B.V., or that your employer has executed a separate Corporate CLA with GitLab B.V..
-7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [insert_name_here]".
+- **Contributions:**
-8. You agree to notify GitLab B.V. of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
+ You represent that each of Your Contributions is Your original creation. You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
+
+ Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: (insert_name_here)".
+
+ You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
+
+You agree to notify GitLab B.V. of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office.
diff --git a/doc/migrate_ci_to_ce/README.md b/doc/migrate_ci_to_ce/README.md
index 51ff56b3541..9947c19a667 100644
--- a/doc/migrate_ci_to_ce/README.md
+++ b/doc/migrate_ci_to_ce/README.md
@@ -67,7 +67,7 @@ Also check on your GitLab server.
```
# On your GitLab server:
# Omnibus
-sudo gitlab-rake gitlab:backup:create SKIP=repositories,uploads
+sudo gitlab-backup create SKIP=repositories,uploads
# Source
cd /home/git/gitlab
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index ea4702acc41..0142e5075cc 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -12,7 +12,7 @@ public access directory (`/public` under your GitLab instance), like at [https:/
### Public projects
-Public projects can be cloned **without any** authentication.
+Public projects can be cloned **without any** authentication over https.
They will be listed in the public access directory (`/public`) for all users.
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index f8da09e5fe1..51f04df27c7 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -77,7 +77,7 @@ You are highly advised to [read about storing configuration files](#storing-conf
Use this command if you've installed GitLab with the Omnibus package:
```sh
-sudo gitlab-rake gitlab:backup:create
+sudo gitlab-backup create
```
Use this if you've installed GitLab from source:
@@ -89,7 +89,7 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
If you are running GitLab within a Docker container, you can run the backup from the host:
```sh
-docker exec -t <container name> gitlab-rake gitlab:backup:create
+docker exec -t <container name> gitlab-backup create
```
If you are using the [GitLab helm chart](https://gitlab.com/charts/gitlab) on a
@@ -199,7 +199,7 @@ To use the `copy` strategy instead of the default streaming strategy, specify
`STRATEGY=copy` in the Rake task command. For example:
```sh
-sudo gitlab-rake gitlab:backup:create STRATEGY=copy
+sudo gitlab-backup create STRATEGY=copy
```
### Backup filename
@@ -207,7 +207,7 @@ sudo gitlab-rake gitlab:backup:create STRATEGY=copy
By default a backup file is created according to the specification in [the Backup timestamp](#backup-timestamp) section above. You can however override the `[TIMESTAMP]` part of the filename by setting the `BACKUP` environment variable. For example:
```sh
-sudo gitlab-rake gitlab:backup:create BACKUP=dump
+sudo gitlab-backup create BACKUP=dump
```
The resulting file will then be `dump_gitlab_backup.tar`. This is useful for systems that make use of rsync and incremental backups, and will result in considerably faster transfer speeds.
@@ -219,7 +219,7 @@ To make sure the generated archive is intelligently transferable by rsync, the `
Note that the `--rsyncable` option in `gzip` is not guaranteed to be available on all distributions. To verify that it is available in your distribution you can run `gzip --help` or consult the man pages.
```sh
-sudo gitlab-rake gitlab:backup:create BACKUP=dump GZIP_RSYNCABLE=yes
+sudo gitlab-backup create BACKUP=dump GZIP_RSYNCABLE=yes
```
### Excluding specific directories from the backup
@@ -244,7 +244,7 @@ will be skipped during a backup.
For Omnibus GitLab packages:
```sh
-sudo gitlab-rake gitlab:backup:create SKIP=db,uploads
+sudo gitlab-backup create SKIP=db,uploads
```
For installations from source:
@@ -448,8 +448,8 @@ Note: This option only works for remote storage. If you want to group your backu
you can pass a `DIRECTORY` environment variable:
```
-sudo gitlab-rake gitlab:backup:create DIRECTORY=daily
-sudo gitlab-rake gitlab:backup:create DIRECTORY=weekly
+sudo gitlab-backup create DIRECTORY=daily
+sudo gitlab-backup create DIRECTORY=weekly
```
### Uploading to locally mounted shares
@@ -566,7 +566,7 @@ crontab -e
There, add the following line to schedule the backup for everyday at 2 AM:
```
-0 2 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create CRON=1
+0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1
```
You may also want to set a limited lifetime for backups to prevent regular
@@ -726,7 +726,7 @@ restore:
```shell
# This command will overwrite the contents of your GitLab database!
-sudo gitlab-rake gitlab:backup:restore BACKUP=1493107454_2018_04_25_10.6.4-ce
+sudo gitlab-backup restore BACKUP=1493107454_2018_04_25_10.6.4-ce
```
Next, restore `/etc/gitlab/gitlab-secrets.json` if necessary as mentioned above.
@@ -760,7 +760,7 @@ backup location (default location is `/var/opt/gitlab/backups`).
For docker installations, the restore task can be run from host:
```sh
-docker exec -it <name of container> gitlab-rake gitlab:backup:restore
+docker exec -it <name of container> gitlab-backup restore
```
The GitLab helm chart uses a different process, documented in
@@ -966,7 +966,7 @@ want to run the chown against your custom location instead of
While running the backup, you may receive a gzip error:
```sh
-sudo /opt/gitlab/bin/gitlab-rake gitlab:backup:create
+sudo /opt/gitlab/bin/gitlab-backup create
Dumping ...
...
gzip: stdout: Input/output error
diff --git a/doc/raketasks/web_hooks.md b/doc/raketasks/web_hooks.md
index a498e9793c1..cc1166a04cc 100644
--- a/doc/raketasks/web_hooks.md
+++ b/doc/raketasks/web_hooks.md
@@ -53,3 +53,8 @@ sudo gitlab-rake gitlab:web_hook:list NAMESPACE=acme
# source installations
bundle exec rake gitlab:web_hook:list NAMESPACE=acme RAILS_ENV=production
```
+
+## Local requests in webhooks
+
+[Requests to local network by webhooks](../security/webhooks.md) can be allowed
+or blocked by an administrator.
diff --git a/doc/security/img/whitelist.png b/doc/security/img/whitelist.png
new file mode 100644
index 00000000000..897000e804d
--- /dev/null
+++ b/doc/security/img/whitelist.png
Binary files differ
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index 7ece9407ac0..e39bc9a9626 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -45,6 +45,36 @@ NOTE: **Note:**
set up by administrators. However, you can turn this off by disabling the
**Allow requests to the local network from system hooks** option.
+## Whitelist for local requests
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/44496) in GitLab 12.2
+
+You can allow certain domains and IP addresses to be accessible to both *system hooks*
+and *webhooks* even when local requests are not allowed by adding them to the
+whitelist. Navigate to **Admin Area > Settings > Network** (`/admin/application_settings/network`)
+and expand **Outbound requests**:
+
+![Outbound local requests whitelist](img/whitelist.png)
+
+The whilelist entries can be separated by semicolons, commas or whitespaces
+(including newlines) and be in different formats like hostnames, IP addresses and/or
+IP ranges. IPv6 is supported. Hostnames that contain unicode characters should
+use IDNA encoding.
+
+The whitelist can hold a maximum of 1000 entries. Each entry can be a maximum of
+255 characters.
+
+Example:
+
+```text
+example.com;gitlab.example.com
+127.0.0.1,1:0:0:0:0:0:0:1
+127.0.0.0/8 1:0:0:0:0:0:0:0/124
+```
+
+NOTE: **Note:**
+Wildcards (`*.example.com`) and ports (`127.0.0.1:3000`) are not currently supported.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/subscriptions/billing_table.png b/doc/subscriptions/billing_table.png
deleted file mode 100644
index acd1b6193ec..00000000000
--- a/doc/subscriptions/billing_table.png
+++ /dev/null
Binary files differ
diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md
index 68e62fff106..fc36b961b3f 100644
--- a/doc/subscriptions/index.md
+++ b/doc/subscriptions/index.md
@@ -2,126 +2,268 @@
type: index, reference
---
-# Subscription setup and management
+# Customers
-This page will help get you started with your new subscription or manage an existing one, whether you have subscribed to GitLab.com or self-managed GitLab.
+This section contains information for:
-To subscribe, upgrade, or read more about the types of subscriptions, please see [Subscribe to GitLab](../README.md#subscribe-to-gitlab) on the GitLab Documentation landing page.
+- New customers about choosing [which GitLab](#which-gitlab) is right for you.
+- Existing customers about [managing subscriptions](#managing-subscriptions).
-## Set up GitLab
+Also see our [subscription FAQ](https://about.gitlab.com/pricing/licensing-faq/).
-Learn how GitLab helps you in the stages of the DevOps lifecycle by learning more [about the GitLab product](https://about.gitlab.com/product/), [GitLab features](https://about.gitlab.com/features/), and [GitLab Documentation](../README.md).
+## Which GitLab?
-### Self-managed: Install GitLab
+There are two ways to use GitLab:
-Take a look at [installing GitLab](https://about.gitlab.com/install/) and our [administrator documentation](../administration/index.md). Then, follow the instructions below under [Your subscription](#your-subscription) to apply your license file.
+- [GitLab.com](#gitlabcom): GitLab's SaaS offering. You don't need to install
+ anything to use GitLab.com, you only need to
+ [sign up](https://gitlab.com/users/sign_in) and start using GitLab straight away.
+- [GitLab self-managed](#gitlab-self-managed): Install, administer, and maintain
+ your own GitLab instance.
-### GitLab.com: Create a user and group
+The following sections outline tiers and features within GitLab.com
+and GitLab self-managed.
-Start with creating a user account for yourself using our [sign up page](https://gitlab.com/users/sign_in#register-pane).
+### GitLab.com
+
+GitLab.com is hosted, managed, and administered by GitLab, Inc., with
+[free and paid subscriptions](https://about.gitlab.com/pricing/) for individuals
+and teams in the following tiers:
-[GitLab groups](../user/group/index.md) help assemble related projects together allowing you to grant members access to several projects at once. A group is not required if you plan on having [projects](../user/project/) inside a personal namespace.
+| Tier | Includes same features available in |
+|:-------|:----------------------------------------------------|
+| Free | [Core](#gitlab-self-managed) self-managed tier. |
+| Bronze | [Starter](#gitlab-self-managed) self-managed tier. |
+| Silver | [Premium](#gitlab-self-managed) self-managed tier. |
+| Gold | [Ultimate](#gitlab-self-managed) self-managed tier. |
-## Your subscription
+GitLab.com subscriptions grant access
+to the same features available in GitLab self-managed, **except
+[administration](../administration/index.md) tools and settings**.
-You can view and manage subscriptions through our [Customers portal](https://customers.gitlab.com/). Information on applying your subscription is below.
+GitLab.com allows you to apply your subscription to a group or your personal user.
-Please also see our [subscription FAQ](https://about.gitlab.com/pricing/licensing-faq/)
+When applied to:
-### View subscription and seats
+- A **group**, the group, all subgroups, and all projects under the selected
+ group on GitLab.com will have the features of the associated plan. It is
+ recommended to go with a group plan when managing projects and users of an
+ organization.
+- A **personal userspace** instead, all projects will have features with the
+ subscription applied, but as it is not a group, group features will not be available.
-To view and manage the subscriptions you have purchased and the number of seats associated with the subscription, please visit and log into the [Customers’ Portal](https://customers.gitlab.com/subscriptions). For more information, please see our [subscription FAQ](https://about.gitlab.com/pricing/licensing-faq/) and [pricing page](https://about.gitlab.com/pricing/), which includes information on our [true-up pricing policy](https://about.gitlab.com/handbook/product/pricing/#true-up-pricing) when adding more users than at the time of purchase.
+TIP: **Tip:**
+To support the open source community and encourage the development of open
+source projects, GitLab grants access to **Gold** features for all GitLab.com
+**public** projects, regardless of the subscription.
-Please note that this account may have the same email, but is a _separate_ login from your GitLab.com account. If the two accounts are linked together, then you can use the "sign in with GitLab.com account" link underneath the `Sign In` button.
+The following resources are available for more information on GitLab.com:
-### Change billing information
+- [Feature comparison](https://about.gitlab.com/pricing/gitlab-com/feature-comparison/), for information on what features are available at each tier.
+- [GitLab pricing page](https://about.gitlab.com/pricing/), for subscription information and a free trial.
+- Our [product marketing page](https://about.gitlab.com/handbook/marketing/product-marketing/), for additional information including:
+ - How [different tiers are licensed](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers).
+ - The different [GitLab distributions](https://about.gitlab.com/handbook/marketing/product-marketing/#distributions).
+
+#### Subscribing to GitLab.com
+
+To subscribe to GitLab.com:
+
+1. Create a user account for yourself using our
+ [sign up page](https://gitlab.com/users/sign_in#register-pane).
+1. Create a [group](../user/group/index.md). GitLab groups help assemble related
+ projects together allowing you to grant members access to several projects
+ at once. A group is not required if you plan on having projects inside a personal
+ namespace.
+1. Create additional users and
+ [add them to the group](../user/group/index.md#add-users-to-a-group).
+1. Select the **Bronze**, **Silver**, or **Gold** GitLab.com plan through the
+ [GitLab Subscription Manager](https://customers.gitlab.com/).
+1. Link your GitLab.com account with your GitLab Subscription Manager account.
+ Once signed into the GitLab Subscription Manager, if your account is not
+ already linked, you will prompted to link your account with a
+ **Link my GitLab Account** button.
+1. Associate the group with the subscription.
+
+TIP: **Tip:**
+You can also go to the [**My Account**](https://customers.gitlab.com/customers/edit)
+page to add or change the GitLab.com account link.
+
+### GitLab self-managed
+
+With GitLab self-managed, you deploy your own GitLab instance on-premises or on a cloud of your choice.
+GitLab self-managed is available for [free and with paid subscriptions](https://about.gitlab.com/pricing/#self-managed) in the following tiers:
+
+| Tier | Includes |
+|:---------|:-----------------------------------------------|
+| Core | Core features. |
+| Starter | Core and Starter features. |
+| Premium | Core, Starter, and Premium features. |
+| Ultimate | Core, Starter, Premium, and Ultimate features. |
+
+The following resources are available for more information on GitLab self-managed:
+
+- [Feature comparison](https://about.gitlab.com/pricing/self-managed/feature-comparison/), for information on what features are available at each tier.
+- [GitLab pricing page](https://about.gitlab.com/pricing/#self-managed), for subscription information and a free trial.
+- Our [product marketing page](https://about.gitlab.com/handbook/marketing/product-marketing/), for additional information including:
+ - How [different tiers are licensed](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers).
+ - The different [GitLab distributions](https://about.gitlab.com/handbook/marketing/product-marketing/#distributions).
-In the customers portal, go to the `My Account` page, then revise the `Account Details` information and click on the `Update Account` button.
+#### Subscribing through GitLab self-managed
-Future purchases will use the information in this section. The email listed in this section is used for the Customers Portal login and for license related email communication.
+To subscribe to GitLab through a self-managed installation:
+
+1. [Install](https://about.gitlab.com/install/) GitLab.
+1. Complete the installation with
+ [administration tasks](https://docs.gitlab.com/ee/administration/).
+1. Select the **Starter**, **Premium**, or **Ultimate** self-managed plan
+ through the [GitLab Subscription Manager](https://customers.gitlab.com/).
+1. Apply your license file. After purchase, a license file is sent to the email
+ address associated to the GitLab Subscription Manager account,
+ which needs to be
+ [uploaded to your GitLab instance](../user/admin_area/license.md#uploading-your-license).
+
+TIP: **Tip:**
+If you are purchasing a subscription for an existing **Core** self-managed
+instance, ensure you are purchasing enough seats to
+[cover your users](../user/admin_area/index.md#administering-users).
+
+## Managing subscriptions
+
+You can view and manage subscriptions through our
+[GitLab Subscription Manager](https://customers.gitlab.com/).
-### Self-managed: Apply your license file
+### View subscription and seats
+
+Visit the
+[GitLab Subscription Manager](https://customers.gitlab.com/subscriptions) to
+view and manage:
+
+- The subscriptions you have purchased.
+- The number of seats associated with the subscription.
+- Retrieve copies of invoices.
+- Change the credit card on file.
-After purchase, the license file is sent to the email address tied to the Customers portal account, which needs to be [uploaded to the GitLab instance](../user/admin_area/license.md#uploading-your-license).
+For more information, please see our:
-### Link your GitLab.com account with your Customers Portal account
+- [Subscription FAQ](https://about.gitlab.com/pricing/licensing-faq/).
+- [Pricing page](https://about.gitlab.com/pricing/), which includes information
+ on our [true-up pricing policy](https://about.gitlab.com/handbook/product/pricing/#true-up-pricing)
+ when adding more users other than at the time of purchase.
NOTE: **Note:**
-This is *required* for GitLab.com subscriptions.
+The GitLab Subscription Manager account can have the same email address as your
+GitLab.com account, but is a _separate_ login. If the two accounts are
+linked together, you can use the **Or sign in with GitLab.com**
+link underneath the **Sign In** button.
-Once signed into the customers portal, if your account is not already linked, you should be prompted to link your account with a "Link my GitLab Account" button.
+### Change billing information
-You can also go to the [My Account](https://customers.gitlab.com/customers/edit) page to add or change the GitLab.com account link.
+To change billing information:
-### Change the linked GitLab.com account for your Customers Portal account
+1. Log in to [GitLab Subscription Manager](https://customers.gitlab.com/customers/sign_in).
+1. Go to the **My Account** page.
+1. Make the required changes to the **Account Details** information.
+1. Click **Update Account**.
-To change which GitLab.com account is associated with a Customers Portal account, please follow these steps:
+NOTE: **Note:**
+Future purchases will use the information in this section.
+The email listed in this section is used for the GitLab Subscription Manager
+login and for license-related email communication.
-1. Log into the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
-1. In a separate browser tab, visit [GitLab.com](https://gitlab.com) to ensure you are not logged in, or if you are, log out.
-1. Back on the Customers Portal page, click [My Account](https://customers.gitlab.com/customers/edit) in the top menu.
-1. Under `Your GitLab.com account`, click the `Change linked account` button.
-1. Have the user you want associated log in to their [GitLab.com](https://gitlab.com) account.
+### Manage GitLab.com account
-### GitLab.com: Associate your namespace with your subscription
+This section provided information specific to managing subscriptions with a
+GitLab.com account.
-Once your GitLab.com account is linked, you can go to your [Subscriptions](https://customers.gitlab.com/subscriptions) page to choose or change the namespace your subscription applies to.
+#### Change linked account
-Please note that you need to be a group owner to associate a group to your subscription.
+To change the GitLab.com account associated with a GitLab Subscription Manager
+account:
-### GitLab.com: Upgrade your subscription plan
+1. Log in to the
+ [GitLab Subscription Manager](https://customers.gitlab.com/customers/sign_in).
+1. Go to [GitLab.com](https://gitlab.com) in a separate browser tab. Ensure you
+ are not logged in.
+1. On the GitLab Subscription Manager page, click
+ [**My Account**](https://customers.gitlab.com/customers/edit) in the top menu.
+1. Under **Your GitLab.com account**, click **Change linked account** button.
+1. Log in to [GitLab.com](https://gitlab.com) account to link to.
-GitLab.com subscriptions can be upgraded directly through the [Subscriptions portal](https://customers.gitlab.com/subscriptions).
+#### Change associated namespace
-The Subscriptions portal provides an **Upgrade** button below each GitLab.com
-subscription, which will lead you to a simple
-checkout process.
+With a linked GitLab.com account, go to the
+[**Subscriptions**](https://customers.gitlab.com/subscriptions) page to choose
+or change the namespace your subscription applies to.
-### Confirm or upgrade your GitLab.com subscription details within GitLab
+NOTE: **Note:**
+Please note that you need to be a group owner to associate a group to your
+subscription.
-To see the status of your GitLab.com subscription, you can click on the Billings
-section of the relevant namespace:
+### Confirm or upgrade your subscription
-- For individuals, this is located at <https://gitlab.com/profile/billings> under
- in your Settings,
-- For groups, this is located under the group's Settings dropdown, under Billing.
+To see the status of your GitLab.com subscription, you can click on the
+**Billings** section of the relevant namespace:
-For groups, you can see details of your subscription - including your current
-plan - in the included table:
+- For individuals:
+ 1. Go to **User Avatar > Settings**.
+ 1. Click **Billing**.
+- For groups, go to the group's **Settings** dropdown, under **Billing**.
-![Billing table](billing_table.png)
+The following table describes details of your subscription for groups:
| Field | Description |
| ------ | ------ |
-| Seats in subscription | If this is a paid plan, this represents the number of seats you've paid to support in your group. |
-| Seats currently in use | The number of active seats currently in use. |
-| Max seats used | The highest number of seats you've used. If this exceeds the seats in subscription, you may owe an additional fee for the additional users. |
+| Seats in subscription | If this is a paid plan, represents the number of seats you've paid to support in your group. |
+| Seats currently in use | Number of active seats currently in use. |
+| Max seats used | Highest number of seats you've used. If this exceeds the seats in subscription, you may owe an additional fee for the additional users. |
| Seats owed | If your max seats used exceeds the seats in your subscription, you'll owe an additional fee for the users you've added. |
-| Subscription start date | The date your subscription started. If this is for a Free plan, this is the date you transitioned off your group's paid plan. |
-| Subscription end date | The date your current subscription will end. This does not apply to Free plans. |
+| Subscription start date | Date your subscription started. If this is for a Free plan, is the date you transitioned off your group's paid plan. |
+| Subscription end date | Date your current subscription will end. Does not apply to Free plans. |
-### Subscription changes and your data
+## Subscription changes and your data
-When your subscription or trial expires, GitLab does not delete your data, however, depending on the tier and feature, it may become inaccessible. Please note that some features may not behave as expected if a graceful fallback is not currently implemented, such as [environment specific variables not being passed](https://gitlab.com/gitlab-org/gitlab-ce/issues/52825).
+When your subscription or trial expires, GitLab does not delete your data.
+
+However, depending on the tier and feature, your data may become inaccessible.
+
+Please note that some features may not behave as expected if a graceful
+fallback is not currently implemented. For example,
+[environment specific variables not being passed](https://gitlab.com/gitlab-org/gitlab-ce/issues/52825).
If you renew or upgrade, your data will again be accessible.
-For self-managed customers, there is a two-week grace period when your features will continue to work as-is, after which the entire instance will become read only. However, if you remove the license, you will immediately revert to Core features.
+### Self-managed data
+
+For self-managed customers, there is a two-week grace period when your features
+will continue to work as-is, after which the entire instance will become read
+only.
+
+However, if you remove the license, you will immediately revert to Core
+features.
## Need help?
-[GitLab's Documentation](https://docs.gitlab.com/) offers a wide range of topics covering the use and administration of GitLab.
+[GitLab's Documentation](https://docs.gitlab.com/) offers a wide range of
+topics covering the use and administration of GitLab.
-We also encourage all users to search our project trackers for known issues and existing feature requests in:
+We also encourage all users to search our project trackers for known issues and
+existing feature requests in:
-- [GitLab CE](https://gitlab.com/gitlab-org/gitlab-ce/issues/) for features included in all tiers, and
-- [GitLab EE](https://gitlab.com/gitlab-org/gitlab-ee/issues/) for paid-tier features.
+- [GitLab CE](https://gitlab.com/gitlab-org/gitlab-ce/issues/) for features
+ included in all tiers.
+- [GitLab EE](https://gitlab.com/gitlab-org/gitlab-ee/issues/) for paid-tier
+ features.
-These issues are the best avenue for getting updates on specific product plans and for communicating directly with the relevant GitLab team members.
+These issues are the best avenue for getting updates on specific product plans
+and for communicating directly with the relevant GitLab team members.
### Contacting Support
-Learn more about the tiers of [GitLab Support](https://about.gitlab.com/support/) or [submit a request via the Support Portal](https://support.gitlab.com/hc/en-us/requests/new).
+Learn more about:
+
+- The tiers of [GitLab Support](https://about.gitlab.com/support/).
+- [Submit a request via the Support Portal](https://support.gitlab.com/hc/en-us/requests/new).
<!-- ## Troubleshooting
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index e8bd35fba5c..1e9eb15533a 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -644,6 +644,11 @@ X-Gitlab-Event: System Hook
}
```
+## Local requests in system hooks
+
+[Requests to local network by system hooks](../security/webhooks.md) can be allowed
+or blocked by an administrator.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 63a72f8f193..95220d6364c 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -190,7 +190,7 @@ Those environments are tied to jobs that use [Auto Deploy](#auto-deploy), so
except for the environment scope, they would also need to have a different
domain they would be deployed to. This is why you need to define a separate
`KUBE_INGRESS_BASE_DOMAIN` variable for all the above
-[based on the environment](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium).
+[based on the environment](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables).
The following table is an example of how the three different clusters would
be configured.
@@ -662,10 +662,10 @@ repo or by specifying a project variable:
You can also make use of the `HELM_UPGRADE_EXTRA_ARGS` environment variable to override the default values in the `values.yaml` file in the [default Helm chart](https://gitlab.com/gitlab-org/charts/auto-deploy-app).
To apply your own `values.yaml` file to all Helm upgrade commands in Auto Deploy set `HELM_UPGRADE_EXTRA_ARGS` to `--values my-values.yaml`.
-### Custom Helm chart per environment **(PREMIUM)**
+### Custom Helm chart per environment
You can specify the use of a custom Helm chart per environment by scoping the environment variable
-to the desired environment. See [Limiting environment scopes of variables](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium).
+to the desired environment. See [Limiting environment scopes of variables](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables).
### Customizing `.gitlab-ci.yml`
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index f5e6bff67c5..9bc0f64b68d 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -272,7 +272,7 @@ The **Logs** page provides access to the following log files:
| Log file | Contents |
| :---------------------- | :------- |
| `application.log` | GitLab user activity |
-| `githost.log` | Failed GitLab interaction with Git repositories |
+| `git_json.log` | Failed GitLab interaction with Git repositories |
| `production.log` | Requests received from Unicorn, and the actions taken to serve those requests |
| `sidekiq.log` | Background jobs |
| `repocheck.log` | Repository activity |
diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md
index 77c9d097283..490163c1816 100644
--- a/doc/user/admin_area/settings/email.md
+++ b/doc/user/admin_area/settings/email.md
@@ -34,11 +34,13 @@ This configuration option sets the email hostname for [private commit emails](..
In order to change this option:
-1. Go to **Admin area > Settings** (`/admin/application_settings`).
-1. Under the **Email** section, change the **Custom hostname (for private commit emails)** field.
-1. Hit **Save** for the changes to take effect.
+1. Go to **Admin Area > Settings > Preferences** (`/admin/application_settings/preferences`).
+1. Expand the **Email** section.
+1. Enter the desire hostname in the **Custom hostname (for private commit emails)** field.
+1. Click **Save changes**.
-NOTE: **Note**: Once the hostname gets configured, every private commit email using the previous hostname, will not get
+NOTE: **Note:**
+Once the hostname gets configured, every private commit email using the previous hostname, will not get
recognized by GitLab. This can directly conflict with certain [Push rules](../../../push_rules/push_rules.md) such as
`Check whether author is a GitLab user` and `Check whether committer is the current authenticated user`.
diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md
index cb533538047..f730a25a9fc 100644
--- a/doc/user/application_security/sast/analyzers.md
+++ b/doc/user/application_security/sast/analyzers.md
@@ -17,19 +17,19 @@ This is achieved by implementing the [common API](https://gitlab.com/gitlab-org/
SAST supports the following official analyzers:
-- [Bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit)
-- [Brakeman](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman)
-- [ESLint (Javascript)](https://gitlab.com/gitlab-org/security-products/analyzers/eslint)
-- [SpotBugs with the Find Sec Bugs plugin (Ant, Gradle and wrapper, Grails, Maven and wrapper, SBT)](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs)
-- [Flawfinder](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder)
-- [Gosec](https://gitlab.com/gitlab-org/security-products/analyzers/gosec)
-- [NodeJsScan](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan)
-- [PHP CS security-audit](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit)
-- [Secrets (Gitleaks, TruffleHog & Diffence secret detectors)](https://gitlab.com/gitlab-org/security-products/analyzers/secrets)
-- [Security Code Scan (.NET)](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan)
-- [TSLint (Typescript)](https://gitlab.com/gitlab-org/security-products/analyzers/tslint)
-- [Sobelow (Elixir Phoenix)](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow)
-- [PMD (Apex only)](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex)
+- [`bandit`](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) (Bandit)
+- [`brakeman`](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman) (Brakeman)
+- [`eslint`](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) (ESLint (Javascript))
+- [`flawfinder`](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder) (Flawfinder)
+- [`gosec`](https://gitlab.com/gitlab-org/security-products/analyzers/gosec) (Gosec)
+- [`nodejs-scan`](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan) (NodeJsScan)
+- [`phpcs-security-audit`](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) (PHP CS security-audit)
+- [`pmd-apex`](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex) (PMD (Apex only))
+- [`secrets`](https://gitlab.com/gitlab-org/security-products/analyzers/secrets) (Secrets (Gitleaks, TruffleHog & Diffence secret detectors))
+- [`security-code-scan`](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) (Security Code Scan (.NET))
+- [`sobelow`](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow) (Sobelow (Elixir Phoenix))
+- [`spotbugs`](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) (SpotBugs with the Find Sec Bugs plugin (Ant, Gradle and wrapper, Grails, Maven and wrapper, SBT))
+- [`tslint`](https://gitlab.com/gitlab-org/security-products/analyzers/tslint) (TSLint (Typescript))
The analyzers are published as Docker images that SAST will use to launch
dedicated containers for each analysis.
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index 625c5440ec0..d41f44f85cc 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -86,7 +86,7 @@ The domain should have a wildcard DNS configured to the Ingress IP address.
When adding more than one Kubernetes cluster to your project, you need to differentiate
them with an environment scope. The environment scope associates clusters with
[environments](../../../ci/environments.md) similar to how the
-[environment-specific variables](../../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium)
+[environment-specific variables](../../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables)
work.
While evaluating which environment matches the environment scope of a
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 7dfd0d04637..ffaa07cb3a4 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -438,7 +438,7 @@ NOTE: **Note:**
Environment-specific resources are only created if your cluster is [managed by GitLab](#gitlab-managed-clusters).
NOTE: **Note:**
-If your project was created before GitLab 12.2 it will use a single namespace for all project environments.
+If your cluster was created before GitLab 12.2, it will use a single namespace for all project environments.
#### Security of GitLab Runners
@@ -468,7 +468,7 @@ If you don't want to use GitLab Runner in privileged mode, either:
When adding more than one Kubernetes cluster to your project, you need to differentiate
them with an environment scope. The environment scope associates clusters with [environments](../../../ci/environments.md) similar to how the
-[environment-specific variables](../../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium) work.
+[environment-specific variables](../../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables) work.
The default environment scope is `*`, which means all jobs, regardless of their
environment, will use that cluster. Each scope can only be used by a single
@@ -652,6 +652,9 @@ NOTE: **NOTE:**
Prior to GitLab 11.5, `KUBE_TOKEN` was the Kubernetes token of the main
service account of the cluster integration.
+NOTE: **Note:**
+If your cluster was created before GitLab 12.2, default `KUBE_NAMESPACE` will be set to `<project_name>-<project_id>`.
+
### Troubleshooting
Before the deployment jobs starts, GitLab creates the following specifically for
diff --git a/doc/user/project/merge_requests/blocking_merge_requests.md b/doc/user/project/merge_requests/blocking_merge_requests.md
deleted file mode 100644
index 0506a7cb4a5..00000000000
--- a/doc/user/project/merge_requests/blocking_merge_requests.md
+++ /dev/null
@@ -1,133 +0,0 @@
----
-type: reference, concepts
----
-
-# Blocking merge requests **(PREMIUM)**
-
-> Introduced in GitLab Premium 12.2
-
-Blocking merge requests allow dependencies between MRs to be expressed. If a
-merge request is blocked by another MR, it cannot be merged until that blocking
-MR is itself merged.
-
-NOTE: **Note:**
-Blocking merge requests are a **PREMIUM** feature, but this restriction is only
-enforced for the blocked merge request. A merge request in a **CORE** or
-**STARTER** project can block a **PREMIUM** merge request, but not vice-versa.
-
-## Use cases
-
-* Ensure changes to a library are merged before changes to a project that
- imports the library
-* Prevent a documentation-only merge request from being merged before the MR
- implementing the feature to be documented
-* Require an MR updating a permissions matrix to be merged before merging an
- MR from someone who hasn't yet been granted permissions
-
-It is common for a single logical change to span several merge requests. These
-MRs may all be in a single project, or they may be spread out across multiple
-projects, and the order in which they are merged can be significant.
-
-For example, given a project `mycorp/awesome-project` that imports a library
-at `myfriend/awesome-lib`, adding a feature in `awesome-project` may **also**
-require changes to `awesome-lib`, and so necessitate two merge requests. Merging
-the `awesome-project` MR before the `awesome-lib` one would break the `master`
-branch.
-
-The `awesome-project` MR could be [marked as WIP](work_in_progress_merge_requests.md),
-and the reason for the WIP stated included in the comments. However, this
-requires the state of the `awesome-lib` MR to be manually tracked, and doesn't
-scale well if the `awesome-project` MR depends on changes to **several** other
-projects.
-
-By marking the `awesome-project` MR as blocked on the `awesome-lib` MR instead,
-the status of the dependency is automatically tracked by GitLab, and the WIP
-state can be used to communicate the readiness of the code in each individual
-MR instead.
-
-## Configuration
-
-To continue the above example, you can configure a block when creating the
-new MR in `awesome-project` (or by editing it, if it already exists). The block
-needs to be configured on the MR that will be **blocked**, rather than on the
-**blocking** MR. There is a "Blocking merge requests" section in the form:
-
-![Blocking merge requests form control](img/edit_blocking_merge_requests.png)
-
-Anyone who can edit a merge request can change the list of blocking merge
-requests.
-
-New blocks can be added by reference, by URL, or by using autcompletion. To
-remove a block, press the "X" by its reference.
-
-As blocks can be specified across projects, it's possible that someone else has
-added a block for a merge request in a project you don't have access to. These
-are shown as a simple count:
-
-![Blocking merge requests form control with inaccessible MRs](img/edit_blocking_merge_requests_inaccessible.png)
-
-If necessary, you can remove all the blocks like this by pressing the "X", just
-as you would for a single, visible block.
-
-Once you're finished, press the "Save changes" button to submit the request, or
-"Cancel" to return without making any changes.
-
-The list of configured blocks, and the status of each one, is shown in the merge
-request widget:
-
-![Blocking merge requests in merge request widget](img/show_blocking_merge_requests_in_mr_widget.png)
-
-Until all blocking merge requests have, themselves, been merged, the "Merge"
-button will be disabled. In particular, note that **closed** merge requests
-still block their dependents - it is impossible to automatically determine if
-merge requests that were blocked by that MR when it was open, are still blocked
-when it is closed.
-
-If a merge request has been closed **and** the block is no longer relevant, it
-must be removed as a blocking MR, following the instructions above, before
-merge.
-
-## Limitations
-
-* API support: [gitlab-ee#12551](https://gitlab.com/gitlab-org/gitlab-ee/issues/12551)
-* Blocking relationships are not preserved across project export/import: [gitlab-ee#12549](https://gitlab.com/gitlab-org/gitlab-ee/issues/12549)
-* Complex merge order dependencies are not supported: [gitlab-ee#11393](https://gitlab.com/gitlab-org/gitlab-ee/issues/11393)
-
-The last item merits a little more explanation. Blocking merge requests can be
-described as a graph of dependencies. The simplest possible graph has one
-merge request blocking another:
-
-```mermaid
-graph LR;
- myfriend/awesome-lib!10-->mycorp/awesome-project!100;
-```
-
-A more complex (and still supported) graph might have several MRs blocking
-another from being merged:
-
-```mermaid
-graph LR;
- myfriend/awesome-lib!10-->mycorp/awesome-project!100;
- herfriend/another-lib!1-->mycorp/awesome-project!100;
-```
-
-We also support one MR blocking several others from being merged:
-
-```mermaid
-graph LR;
- herfriend/another-lib!1-->myfriend/awesome-lib!10;
- herfriend/another-lib!1-->mycorp/awesome-project!100;
-```
-
-What is **not** supported is a "deep", or "nested" graph of dependencies, e.g.:
-
-```mermaid
-graph LR;
- herfriend/another-lib!1-->myfriend/awesome-lib!10;
- myfriend/awesome-lib!10-->mycorp/awesome-project!100;
-```
-
-In this example, `myfriend/awesome-lib!10` would be blocked from being merged by
-`herfriend/another-lib!1`, and would also block `mycorp/awesome-project!100`
-from being merged. This is **not** yet supported.
-
diff --git a/doc/user/project/merge_requests/img/cross-project-dependencies-edit-inaccessible.png b/doc/user/project/merge_requests/img/cross-project-dependencies-edit-inaccessible.png
new file mode 100644
index 00000000000..2dc02634fd8
--- /dev/null
+++ b/doc/user/project/merge_requests/img/cross-project-dependencies-edit-inaccessible.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cross-project-dependencies-edit.png b/doc/user/project/merge_requests/img/cross-project-dependencies-edit.png
new file mode 100644
index 00000000000..362e7e0ead2
--- /dev/null
+++ b/doc/user/project/merge_requests/img/cross-project-dependencies-edit.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/cross-project-dependencies-view.png b/doc/user/project/merge_requests/img/cross-project-dependencies-view.png
new file mode 100644
index 00000000000..e00231c839b
--- /dev/null
+++ b/doc/user/project/merge_requests/img/cross-project-dependencies-view.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png b/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png
deleted file mode 100644
index 98345f2f0d1..00000000000
--- a/doc/user/project/merge_requests/img/edit_blocking_merge_requests.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png b/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png
deleted file mode 100644
index b19cf1db94b..00000000000
--- a/doc/user/project/merge_requests/img/edit_blocking_merge_requests_inaccessible.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png b/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png
deleted file mode 100644
index 3f4fcc5781d..00000000000
--- a/doc/user/project/merge_requests/img/show_blocking_merge_requests_in_mr_widget.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index f78ec9d96e6..7ff30d1b813 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -47,7 +47,7 @@ With **[GitLab Enterprise Edition][ee]**, you can also:
- Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **(ULTIMATE)**
- Analyze your Docker images for vulnerabilities with [Container Scanning](../../application_security/container_scanning/index.md) **(ULTIMATE)**
- Determine the performance impact of changes with [Browser Performance Testing](#browser-performance-testing-premium) **(PREMIUM)**
-- Specify merge order dependencies with [Blocking Merge Requests](#blocking-merge-requests-premium) **(PREMIUM)**
+- Specify merge order dependencies with [Cross-project Merge Request Dependencies](#cross-project-merge-request-dependencies-premium) **(PREMIUM)**
## Use cases
@@ -451,20 +451,20 @@ GitLab runs the [Sitespeed.io container][sitespeed-container] and displays the d
[Read more about Browser Performance Testing.](browser_performance_testing.md)
-## Blocking Merge Requests **(PREMIUM)**
+## Cross-project Merge Request Dependencies **(PREMIUM)**
> Introduced in [GitLab Premium][products] 12.2.
-A single logical change may be split across several merge requests, and perhaps
-even across several projects. When this happens, the order in which MRs are
-merged is important.
+A single logical change may be split across several merge requests, across
+several projects. When this happens, the order in which MRs are merged is
+important.
-GitLab allows you to specify that a merge request is blocked by other MRs. With
+GitLab allows you to specify that a merge request depends on other MRs. With
this relationship in place, the merge request cannot be merged until all of its
-blockers have also been merged, helping to maintain the consistency of a single
-logical change.
+dependencies have also been merged, helping to maintain the consistency of a
+single logical change.
-[Read more about Blocking Merge Requests.](blocking_merge_requests.md)
+[Read more about cross-project merge request dependencies.](merge_request_dependencies.md)
## Security reports **(ULTIMATE)**
diff --git a/doc/user/project/merge_requests/merge_request_dependencies.md b/doc/user/project/merge_requests/merge_request_dependencies.md
new file mode 100644
index 00000000000..45cb56dfb6b
--- /dev/null
+++ b/doc/user/project/merge_requests/merge_request_dependencies.md
@@ -0,0 +1,143 @@
+---
+type: reference, concepts
+---
+
+# Cross-project merge request dependencies **(PREMIUM)**
+
+> Introduced in GitLab Premium 12.2
+
+Cross-project merge request dependencies allows a required order of merging
+between merge requests in different projects to be expressed. If a
+merge request "depends on" another, then it cannot be merged until its
+dependency is itself merged.
+
+NOTE: **Note:**
+Merge requests dependencies are a **PREMIUM** feature, but this restriction is
+only enforced for the dependent merge request. A merge request in a **CORE** or
+**STARTER** project can be a dependency of a **PREMIUM** merge request, but not
+vice-versa.
+
+NOTE: **Note:**
+A merge request can only depend on merge requests in a different project. Two
+merge requests in the same project cannot depend on each other.
+
+## Use cases
+
+* Ensure changes to a library are merged before changes to a project that
+ imports the library
+* Prevent a documentation-only merge request from being merged before the merge request
+ implementing the feature to be documented
+* Require an merge request updating a permissions matrix to be merged before merging an
+ merge request from someone who hasn't yet been granted permissions
+
+It is common for a single logical change to span several merge requests, spread
+out across multiple projects, and the order in which they are merged can be
+significant.
+
+For example, given a project `mycorp/awesome-project` that imports a library
+at `myfriend/awesome-lib`, adding a feature in `awesome-project` may **also**
+require changes to `awesome-lib`, and so necessitate two merge requests. Merging
+the `awesome-project` merge request before the `awesome-lib` one would
+break the `master`branch.
+
+The `awesome-project` merge request could be [marked as
+WIP](work_in_progress_merge_requests.md),
+and the reason for the WIP stated included in the comments. However, this
+requires the state of the `awesome-lib` merge request to be manually
+tracked, and doesn't scale well if the `awesome-project` merge request
+depends on changes to **several** other projects.
+
+By making the `awesome-project` merge request depend on the
+`awesome-lib` merge request instead, this relationship is
+automatically tracked by GitLab, and the WIP state can be used to
+communicate the readiness of the code in each individual merge request
+instead.
+
+## Configuration
+
+To continue the above example, you can configure a dependency when creating the
+new merge request in `awesome-project` (or by editing it, if it already exists).
+The dependency needs to be configured on the **dependent** merge
+request. There is a "Cross-project dependencies" section in the form:
+
+![Cross-project dependencies form control](img/cross-project-dependencies-edit.png)
+
+Anyone who can edit a merge request can change the list of dependencies.
+
+New dependencies can be added by reference, or by URL. To remove a dependency,
+press the "X" by its reference.
+
+As dependencies are specified across projects, it's possible that someone else
+has added a dependency for a merge request in a project you don't have access to.
+These are shown as a simple count:
+
+![Cross-project dependencies form control with inaccessible merge requests](img/cross-project-dependencies-edit-inaccessible.png)
+
+If necessary, you can remove all the dependencies like this by pressing the "X",
+just as you would for a single, visible dependency.
+
+Once you're finished, press the "Save changes" button to submit the request, or
+"Cancel" to return without making any changes.
+
+The list of configured dependencies, and the status of each one, is shown in the
+merge request widget:
+
+![Cross-project dependencies in merge request widget](img/cross-project-dependencies-view.png)
+
+Until all dependencies have, themselves, been merged, the "Merge"
+button will be disabled for the dependent merge request. In
+particular, note that **closed** merge request still prevent their
+dependents from being merged - it is impossible to automatically
+determine whether the dependency expressed by a closed merge request
+has been satisfied in some other way or not.
+
+If a merge request has been closed **and** the dependency is no longer relevant,
+it must be removed as a dependency, following the instructions above, before
+merge.
+
+## Limitations
+
+* API support: [gitlab-ee#12551](https://gitlab.com/gitlab-org/gitlab-ee/issues/12551)
+* Dependencies are not preserved across project export/import: [gitlab-ee#12549](https://gitlab.com/gitlab-org/gitlab-ee/issues/12549)
+* Complex merge order dependencies are not supported: [gitlab-ee#11393](https://gitlab.com/gitlab-org/gitlab-ee/issues/11393)
+
+The last item merits a little more explanation. Dependencies between merge
+requests can be described as a graph of relationships. The simplest possible
+graph has one merge request that depends upon another:
+
+```mermaid
+graph LR;
+ myfriend/awesome-lib!10-->mycorp/awesome-project!100;
+```
+
+A more complex (and still supported) graph might have one merge request that
+directly depends upon several others:
+
+```mermaid
+graph LR;
+ myfriend/awesome-lib!10-->mycorp/awesome-project!100;
+ herfriend/another-lib!1-->mycorp/awesome-project!100;
+```
+
+Several different merge requests can also directly depend upon the
+same merge request:
+
+
+```mermaid
+graph LR;
+ herfriend/another-lib!1-->myfriend/awesome-lib!10;
+ herfriend/another-lib!1-->mycorp/awesome-project!100;
+```
+
+What is **not** supported is a "deep", or "nested" graph of dependencies, e.g.:
+
+```mermaid
+graph LR;
+ herfriend/another-lib!1-->myfriend/awesome-lib!10;
+ myfriend/awesome-lib!10-->mycorp/awesome-project!100;
+```
+
+In this example, `myfriend/awesome-lib!10` depends on `herfriend/another-lib!1`,
+and is itself a dependent of `mycorp/awesome-project!100`. This means that
+`myfriend/awesome-lib!10` becomes an **indirect** dependency of
+`mycorp/awesome-project!100`, which is not yet supported.
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 643b53f5e63..09253ab6b0e 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1090,16 +1090,18 @@ module API
end
class Label < LabelBasic
- expose :open_issues_count do |label, options|
- label.open_issues_count(options[:current_user])
- end
+ with_options if: lambda { |_, options| options[:with_counts] } do
+ expose :open_issues_count do |label, options|
+ label.open_issues_count(options[:current_user])
+ end
- expose :closed_issues_count do |label, options|
- label.closed_issues_count(options[:current_user])
- end
+ expose :closed_issues_count do |label, options|
+ label.closed_issues_count(options[:current_user])
+ end
- expose :open_merge_requests_count do |label, options|
- label.open_merge_requests_count(options[:current_user])
+ expose :open_merge_requests_count do |label, options|
+ label.open_merge_requests_count(options[:current_user])
+ end
end
expose :subscribed do |label, options|
@@ -1346,6 +1348,7 @@ module API
expose :variable_type, :key, :value
expose :protected?, as: :protected, if: -> (entity, _) { entity.respond_to?(:protected?) }
expose :masked?, as: :masked, if: -> (entity, _) { entity.respond_to?(:masked?) }
+ expose :environment_scope, if: -> (entity, _) { entity.respond_to?(:environment_scope) }
end
class Pipeline < PipelineBasic
diff --git a/lib/api/group_labels.rb b/lib/api/group_labels.rb
index 0dbc5f45a68..79a44941c81 100644
--- a/lib/api/group_labels.rb
+++ b/lib/api/group_labels.rb
@@ -16,6 +16,8 @@ module API
success Entities::GroupLabel
end
params do
+ optional :with_counts, type: Boolean, default: false,
+ desc: 'Include issue and merge request counts'
use :pagination
end
get ':id/labels' do
diff --git a/lib/api/helpers/label_helpers.rb b/lib/api/helpers/label_helpers.rb
index c11e7d614ab..896b0aba52b 100644
--- a/lib/api/helpers/label_helpers.rb
+++ b/lib/api/helpers/label_helpers.rb
@@ -19,7 +19,11 @@ module API
end
def get_labels(parent, entity)
- present paginate(available_labels_for(parent)), with: entity, current_user: current_user, parent: parent
+ present paginate(available_labels_for(parent)),
+ with: entity,
+ current_user: current_user,
+ parent: parent,
+ with_counts: params[:with_counts]
end
def create_label(parent, entity)
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index 7124ac0c5c3..6bf9057fad7 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -74,14 +74,14 @@ module API
end
def find_noteable(parent_type, parent_id, noteable_type, noteable_id)
- params = params_by_noteable_type_and_id(noteable_type, noteable_id)
+ params = finder_params_by_noteable_type_and_id(noteable_type, noteable_id, parent_id)
- noteable = NotesFinder.new(current_user, params.merge(project: user_project)).target
+ noteable = NotesFinder.new(current_user, params).target
noteable = nil unless can?(current_user, noteable_read_ability_name(noteable), noteable)
noteable || not_found!(noteable_type)
end
- def params_by_noteable_type_and_id(type, id)
+ def finder_params_by_noteable_type_and_id(type, id, parent_id)
target_type = type.name.underscore
{ target_type: target_type }.tap do |h|
if %w(issue merge_request).include?(target_type)
@@ -89,9 +89,15 @@ module API
else
h[:target_id] = id
end
+
+ add_parent_to_finder_params(h, type, parent_id)
end
end
+ def add_parent_to_finder_params(finder_params, noteable_type, parent_id)
+ finder_params[:project] = user_project
+ end
+
def noteable_parent(noteable)
public_send("user_#{noteable.class.parent_class.to_s.underscore}") # rubocop:disable GitlabSecurity/PublicSend
end
diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb
index c4ecf55969c..422db5c7a50 100644
--- a/lib/api/helpers/services_helpers.rb
+++ b/lib/api/helpers/services_helpers.rb
@@ -489,32 +489,6 @@ module API
desc: 'The ID of a transition that moves issues to a closed state. You can find this number under the Jira workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`'
}
],
- 'kubernetes' => [
- {
- required: true,
- name: :namespace,
- type: String,
- desc: 'The Kubernetes namespace to use'
- },
- {
- required: true,
- name: :api_url,
- type: String,
- desc: 'The URL to the Kubernetes cluster API, e.g., https://kubernetes.example.com'
- },
- {
- required: true,
- name: :token,
- type: String,
- desc: 'The service token to authenticate against the Kubernetes cluster with'
- },
- {
- required: false,
- name: :ca_pem,
- type: String,
- desc: 'A custom certificate authority bundle to verify the Kubernetes cluster with (PEM format)'
- }
- ],
'mattermost-slash-commands' => [
{
required: true,
@@ -739,7 +713,6 @@ module API
::HipchatService,
::IrkerService,
::JiraService,
- ::KubernetesService,
::MattermostSlashCommandsService,
::SlackSlashCommandsService,
::PackagistService,
diff --git a/lib/api/helpers/variables_helpers.rb b/lib/api/helpers/variables_helpers.rb
deleted file mode 100644
index 78a92d0f5a6..00000000000
--- a/lib/api/helpers/variables_helpers.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module API
- module Helpers
- module VariablesHelpers
- extend ActiveSupport::Concern
- extend Grape::API::Helpers
-
- params :optional_params_ee do
- end
- end
- end
-end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index d729d3ee625..c183198d3c6 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -15,6 +15,8 @@ module API
success Entities::ProjectLabel
end
params do
+ optional :with_counts, type: Boolean, default: false,
+ desc: 'Include issue and merge request counts'
use :pagination
end
get ':id/labels' do
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index 71891e43dcc..bb1b037c08f 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -59,6 +59,7 @@ module API
}
override_params = import_params.delete(:override_params)
+ filter_attributes_using_license!(override_params) if override_params
project = ::Projects::GitlabProjectsImportService.new(
current_user, project_params, override_params
diff --git a/lib/api/variables.rb b/lib/api/variables.rb
index af1d7936556..f022b9e665a 100644
--- a/lib/api/variables.rb
+++ b/lib/api/variables.rb
@@ -7,8 +7,6 @@ module API
before { authenticate! }
before { authorize! :admin_build, user_project }
- helpers Helpers::VariablesHelpers
-
helpers do
def filter_variable_parameters(params)
# This method exists so that EE can more easily filter out certain
@@ -59,8 +57,7 @@ module API
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
optional :variable_type, type: String, values: Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
-
- use :optional_params_ee
+ optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
end
post ':id/variables' do
variable_params = declared_params(include_missing: false)
@@ -84,8 +81,7 @@ module API
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
optional :variable_type, type: String, values: Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
-
- use :optional_params_ee
+ optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
end
# rubocop: disable CodeReuse/ActiveRecord
put ':id/variables/:key' do
diff --git a/lib/gitlab/git_logger.rb b/lib/gitlab/git_logger.rb
index ded5349be01..545451f0dc9 100644
--- a/lib/gitlab/git_logger.rb
+++ b/lib/gitlab/git_logger.rb
@@ -3,7 +3,7 @@
module Gitlab
class GitLogger < JsonLogger
def self.file_name_noext
- 'githost'
+ 'git_json'
end
end
end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 4783832961d..e6cbfb00f60 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -240,7 +240,7 @@ module Gitlab
# Ensures that Gitaly is not being abuse through n+1 misuse etc
def self.enforce_gitaly_request_limits(call_site)
- # Only count limits in request-response environments (not sidekiq for example)
+ # Only count limits in request-response environments
return unless Gitlab::SafeRequestStore.active?
# This is this actual number of times this call was made. Used for information purposes only
diff --git a/lib/gitlab/github_import/importer/releases_importer.rb b/lib/gitlab/github_import/importer/releases_importer.rb
index 0e7c9ee0d00..9d925581441 100644
--- a/lib/gitlab/github_import/importer/releases_importer.rb
+++ b/lib/gitlab/github_import/importer/releases_importer.rb
@@ -36,6 +36,7 @@ module Gitlab
description: description_for(release),
created_at: release.created_at,
updated_at: release.updated_at,
+ released_at: release.published_at,
project_id: project.id
}
end
diff --git a/lib/gitlab/instrumentation_helper.rb b/lib/gitlab/instrumentation_helper.rb
new file mode 100644
index 00000000000..e6a5facb2a5
--- /dev/null
+++ b/lib/gitlab/instrumentation_helper.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module InstrumentationHelper
+ extend self
+
+ KEYS = %i(gitaly_calls gitaly_duration rugged_calls rugged_duration_ms).freeze
+
+ def add_instrumentation_data(payload)
+ gitaly_calls = Gitlab::GitalyClient.get_request_count
+
+ if gitaly_calls > 0
+ payload[:gitaly_calls] = gitaly_calls
+ payload[:gitaly_duration] = Gitlab::GitalyClient.query_time_ms
+ end
+
+ rugged_calls = Gitlab::RuggedInstrumentation.query_count
+
+ if rugged_calls > 0
+ payload[:rugged_calls] = rugged_calls
+ payload[:rugged_duration_ms] = Gitlab::RuggedInstrumentation.query_time_ms
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 827f4f77f36..5e77d31760d 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -134,9 +134,11 @@ module Gitlab
project.repository.commit(key) if Commit.valid_hash?(key)
end
+ # rubocop: disable CodeReuse/ActiveRecord
def project_ids_relation
- project
+ Project.where(id: project).select(:id).reorder(nil)
end
+ # rubocop: enabled CodeReuse/ActiveRecord
def filter_milestones_by_project(milestones)
return Milestone.none unless Ability.allowed?(@current_user, :read_milestone, @project)
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 21614ea003e..e6372a42dda 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -46,6 +46,18 @@ module Gitlab
"can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', and spaces, but it cannot start or end with '/'"
end
+ def environment_scope_regex_chars
+ "#{environment_name_regex_chars}\\*"
+ end
+
+ def environment_scope_regex
+ @environment_scope_regex ||= /\A[#{environment_scope_regex_chars}]+\z/.freeze
+ end
+
+ def environment_scope_regex_message
+ "can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', '*' and spaces"
+ end
+
def kubernetes_namespace_regex
/\A[a-z0-9]([-a-z0-9]*[a-z0-9])?\z/
end
diff --git a/lib/gitlab/sidekiq_logging/structured_logger.rb b/lib/gitlab/sidekiq_logging/structured_logger.rb
index d556d5ef129..60782306ade 100644
--- a/lib/gitlab/sidekiq_logging/structured_logger.rb
+++ b/lib/gitlab/sidekiq_logging/structured_logger.rb
@@ -15,9 +15,9 @@ module Gitlab
yield
- Sidekiq.logger.info log_job_done(started_at, base_payload)
+ Sidekiq.logger.info log_job_done(job, started_at, base_payload)
rescue => job_exception
- Sidekiq.logger.warn log_job_done(started_at, base_payload, job_exception)
+ Sidekiq.logger.warn log_job_done(job, started_at, base_payload, job_exception)
raise
end
@@ -28,6 +28,10 @@ module Gitlab
"#{payload['class']} JID-#{payload['jid']}"
end
+ def add_instrumentation_keys!(job, output_payload)
+ output_payload.merge!(job.slice(*::Gitlab::InstrumentationHelper::KEYS))
+ end
+
def log_job_start(started_at, payload)
payload['message'] = "#{base_message(payload)}: start"
payload['job_status'] = 'start'
@@ -35,14 +39,15 @@ module Gitlab
# Old gitlab-shell messages don't provide enqueued_at/created_at attributes
enqueued_at = payload['enqueued_at'] || payload['created_at']
if enqueued_at
- payload['scheduling_latency_s'] = elapsed(Time.iso8601(enqueued_at).to_f)
+ payload['scheduling_latency_s'] = elapsed_by_absolute_time(Time.iso8601(enqueued_at))
end
payload
end
- def log_job_done(started_at, payload, job_exception = nil)
+ def log_job_done(job, started_at, payload, job_exception = nil)
payload = payload.dup
+ add_instrumentation_keys!(job, payload)
payload['duration'] = elapsed(started_at)
payload['completed_at'] = Time.now.utc
@@ -84,6 +89,10 @@ module Gitlab
end
end
+ def elapsed_by_absolute_time(start)
+ (Time.now.utc - start).to_f.round(3)
+ end
+
def elapsed(start)
(current_time - start).round(3)
end
diff --git a/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb b/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb
new file mode 100644
index 00000000000..979a3fce7e6
--- /dev/null
+++ b/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SidekiqMiddleware
+ class InstrumentationLogger
+ def call(worker, job, queue)
+ yield
+
+ # The Sidekiq logger is called outside the middleware block, so
+ # we need to modify the job hash to pass along this information
+ # since RequestStore is only active in the Sidekiq middleware.
+ #
+ # Modifying the job hash in a middleware is permitted by Sidekiq
+ # because Sidekiq keeps a pristine copy of the original hash
+ # before sending it to the middleware:
+ # https://github.com/mperham/sidekiq/blob/53bd529a0c3f901879925b8390353129c465b1f2/lib/sidekiq/processor.rb#L115-L118
+ ::Gitlab::InstrumentationHelper.add_instrumentation_data(job)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index d5657c474c8..7e3a695e52a 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -140,6 +140,8 @@ module Gitlab
[
Gitlab::UsageDataCounters::WikiPageCounter,
Gitlab::UsageDataCounters::WebIdeCounter,
+ Gitlab::UsageDataCounters::NoteCounter,
+ Gitlab::UsageDataCounters::SnippetCounter,
Gitlab::UsageDataCounters::SearchCounter
]
end
diff --git a/lib/gitlab/usage_data_counters/base_counter.rb b/lib/gitlab/usage_data_counters/base_counter.rb
new file mode 100644
index 00000000000..2b52571c3cc
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/base_counter.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab::UsageDataCounters
+ class BaseCounter
+ extend RedisCounter
+
+ UnknownEvent = Class.new(StandardError)
+
+ class << self
+ def redis_key(event)
+ Gitlab::Sentry.track_exception(UnknownEvent, extra: { event: event }) unless known_events.include?(event.to_s)
+
+ "USAGE_#{prefix}_#{event}".upcase
+ end
+
+ def count(event)
+ increment(redis_key event)
+ end
+
+ def read(event)
+ total_count(redis_key event)
+ end
+
+ def totals
+ known_events.map { |e| ["#{prefix}_#{e}".to_sym, read(e)] }.to_h
+ end
+
+ private
+
+ def known_events
+ self::KNOWN_EVENTS
+ end
+
+ def prefix
+ self::PREFIX
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_counters/note_counter.rb b/lib/gitlab/usage_data_counters/note_counter.rb
new file mode 100644
index 00000000000..e93a0bcfa27
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/note_counter.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab::UsageDataCounters
+ class NoteCounter < BaseCounter
+ KNOWN_EVENTS = %w[create].freeze
+ PREFIX = 'note'
+ COUNTABLE_TYPES = %w[Snippet].freeze
+
+ class << self
+ def redis_key(event, noteable_type)
+ "#{super(event)}_#{noteable_type}".upcase
+ end
+
+ def count(event, noteable_type)
+ return unless countable?(noteable_type)
+
+ increment(redis_key(event, noteable_type))
+ end
+
+ def read(event, noteable_type)
+ return 0 unless countable?(noteable_type)
+
+ total_count(redis_key(event, noteable_type))
+ end
+
+ def totals
+ {
+ snippet_comment: read(:create, 'Snippet')
+ }
+ end
+
+ private
+
+ def countable?(noteable_type)
+ COUNTABLE_TYPES.include?(noteable_type.to_s)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_counters/snippet_counter.rb b/lib/gitlab/usage_data_counters/snippet_counter.rb
new file mode 100644
index 00000000000..e4d234ce4d9
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/snippet_counter.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module Gitlab::UsageDataCounters
+ class SnippetCounter < BaseCounter
+ KNOWN_EVENTS = %w[create update].freeze
+ PREFIX = 'snippet'
+ end
+end
diff --git a/lib/gitlab/usage_data_counters/wiki_page_counter.rb b/lib/gitlab/usage_data_counters/wiki_page_counter.rb
index c8b59a3160c..9cfe0be5bab 100644
--- a/lib/gitlab/usage_data_counters/wiki_page_counter.rb
+++ b/lib/gitlab/usage_data_counters/wiki_page_counter.rb
@@ -1,32 +1,8 @@
# frozen_string_literal: true
module Gitlab::UsageDataCounters
- class WikiPageCounter
- extend RedisCounter
-
- KNOWN_EVENTS = %w[create update delete].map(&:freeze).freeze
-
- UnknownEvent = Class.new(StandardError)
-
- class << self
- # Each event gets a unique Redis key
- def redis_key(event)
- raise UnknownEvent, event unless KNOWN_EVENTS.include?(event.to_s)
-
- "USAGE_WIKI_PAGES_#{event}".upcase
- end
-
- def count(event)
- increment(redis_key event)
- end
-
- def read(event)
- total_count(redis_key event)
- end
-
- def totals
- KNOWN_EVENTS.map { |e| ["wiki_pages_#{e}".to_sym, read(e)] }.to_h
- end
- end
+ class WikiPageCounter < BaseCounter
+ KNOWN_EVENTS = %w[create update delete].freeze
+ PREFIX = 'wiki_pages'
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f0254be2044..9bc2fd1b8f4 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2263,6 +2263,9 @@ msgstr ""
msgid "CiVariables|Remove variable row"
msgstr ""
+msgid "CiVariables|Scope"
+msgstr ""
+
msgid "CiVariables|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used as default"
msgstr ""
@@ -2284,15 +2287,24 @@ msgstr ""
msgid "CiVariable|All environments"
msgstr ""
+msgid "CiVariable|Create wildcard"
+msgstr ""
+
msgid "CiVariable|Error occurred while saving variables"
msgstr ""
msgid "CiVariable|Masked"
msgstr ""
+msgid "CiVariable|New environment"
+msgstr ""
+
msgid "CiVariable|Protected"
msgstr ""
+msgid "CiVariable|Search environments"
+msgstr ""
+
msgid "CiVariable|Toggle masked"
msgstr ""
@@ -6159,9 +6171,6 @@ msgstr ""
msgid "Kubernetes error: %{error_code}"
msgstr ""
-msgid "Kubernetes service integration has been disabled. Fields on this page are not used by GitLab, you can configure your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
-msgstr ""
-
msgid "LDAP"
msgstr ""
@@ -10930,9 +10939,6 @@ msgstr ""
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
-msgid "The instance-level Kubernetes service integration is disabled. Your data has been migrated to an <a href=\"%{url}\"/>instance-level cluster</a>."
-msgstr ""
-
msgid "The invitation could not be accepted."
msgstr ""
diff --git a/scripts/lint-rugged b/scripts/lint-rugged
index d862571c1c5..1b3fb54f70b 100755
--- a/scripts/lint-rugged
+++ b/scripts/lint-rugged
@@ -19,6 +19,7 @@ ALLOWED = [
'config/initializers/peek.rb',
'config/initializers/lograge.rb',
'lib/gitlab/grape_logging/loggers/perf_logger.rb',
+ 'lib/gitlab/instrumentation_helper.rb',
'lib/gitlab/rugged_instrumentation.rb',
'lib/peek/views/rugged.rb'
].freeze
diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb
index a2a09e2580f..21e106660d0 100644
--- a/spec/controllers/projects/variables_controller_spec.rb
+++ b/spec/controllers/projects/variables_controller_spec.rb
@@ -36,5 +36,70 @@ describe Projects::VariablesController do
end
include_examples 'PATCH #update updates variables'
+
+ context 'with environment scope' do
+ let!(:variable) { create(:ci_variable, project: project, environment_scope: 'custom_scope') }
+
+ let(:variable_attributes) do
+ { id: variable.id,
+ key: variable.key,
+ secret_value: variable.value,
+ protected: variable.protected?.to_s,
+ environment_scope: variable.environment_scope }
+ end
+ let(:new_variable_attributes) do
+ { key: 'new_key',
+ secret_value: 'dummy_value',
+ protected: 'false',
+ environment_scope: 'new_scope' }
+ end
+
+ context 'with same key and different environment scope' do
+ let(:variables_attributes) do
+ [
+ variable_attributes,
+ new_variable_attributes.merge(key: variable.key)
+ ]
+ end
+
+ it 'does not update the existing variable' do
+ expect { subject }.not_to change { variable.reload.value }
+ end
+
+ it 'creates the new variable' do
+ expect { subject }.to change { owner.variables.count }.by(1)
+ end
+
+ it 'returns a successful response including all variables' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('variables')
+ end
+ end
+
+ context 'with same key and same environment scope' do
+ let(:variables_attributes) do
+ [
+ variable_attributes,
+ new_variable_attributes.merge(key: variable.key, environment_scope: variable.environment_scope)
+ ]
+ end
+
+ it 'does not update the existing variable' do
+ expect { subject }.not_to change { variable.reload.value }
+ end
+
+ it 'does not create the new variable' do
+ expect { subject }.not_to change { owner.variables.count }
+ end
+
+ it 'returns a bad request response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+ end
end
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index afe27aaf1fb..ea89555b0d5 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -325,10 +325,6 @@ FactoryBot.define do
jira_service
end
- factory :kubernetes_project, parent: :project do
- kubernetes_service
- end
-
factory :mock_deployment_project, parent: :project do
mock_deployment_service
end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 5ef39b3e818..f3e662ad4f5 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -16,18 +16,6 @@ FactoryBot.define do
)
end
- factory :kubernetes_service do
- project
- type 'KubernetesService'
- active true
- properties({
- api_url: 'https://kubernetes.example.com',
- token: 'a' * 40
- })
-
- skip_deprecation_validation true
- end
-
factory :mock_deployment_service do
project
type 'MockDeploymentService'
diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb
index 5a2df89aeb7..2b97362c8e9 100644
--- a/spec/features/admin/admin_browses_logs_spec.rb
+++ b/spec/features/admin/admin_browses_logs_spec.rb
@@ -11,7 +11,7 @@ describe 'Admin browses logs' do
visit admin_logs_path
expect(page).to have_link 'application.log'
- expect(page).to have_link 'githost.log'
+ expect(page).to have_link 'git_json.log'
expect(page).to have_link 'test.log'
expect(page).to have_link 'sidekiq.log'
expect(page).to have_link 'repocheck.log'
diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb
index 95685a3c7ff..9e3f8a843a1 100644
--- a/spec/features/project_variables_spec.rb
+++ b/spec/features/project_variables_spec.rb
@@ -17,4 +17,27 @@ describe 'Project variables', :js do
end
it_behaves_like 'variable list'
+
+ it 'adds new variable with a special environment scope' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('somekey')
+ find('.js-ci-variable-input-value').set('somevalue')
+
+ find('.js-variable-environment-toggle').click
+ find('.js-variable-environment-dropdown-wrapper .dropdown-input-field').set('review/*')
+ find('.js-variable-environment-dropdown-wrapper .js-dropdown-create-new-item').click
+
+ expect(find('input[name="variables[variables_attributes][][environment_scope]"]', visible: false).value).to eq('review/*')
+ end
+
+ click_button('Save variables')
+ wait_for_requests
+
+ visit page_path
+
+ page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
+ expect(find('.js-ci-variable-input-key').value).to eq('somekey')
+ expect(page).to have_content('review/*')
+ end
+ end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index bcde730c40b..879ff01f294 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -113,13 +113,13 @@ describe IssuesFinder do
let(:params) { { milestone_title: 'Any' } }
it 'returns issues with any assigned milestone' do
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4)
+ expect(issues).to contain_exactly(issue1)
end
it 'returns issues with any assigned milestone (deprecated)' do
params[:milestone_title] = Milestone::Any.title
- expect(issues).to contain_exactly(issue1, issue2, issue3, issue4)
+ expect(issues).to contain_exactly(issue1)
end
end
diff --git a/spec/fixtures/api/schemas/public_api/v4/group_labels.json b/spec/fixtures/api/schemas/public_api/v4/group_labels.json
deleted file mode 100644
index fbde45f2904..00000000000
--- a/spec/fixtures/api/schemas/public_api/v4/group_labels.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "type": "array",
- "items": {
- "type": "object",
- "properties" : {
- "id" : { "type": "integer" },
- "name" : { "type": "string "},
- "color" : { "type": "string "},
- "text_color" : { "type": "string "},
- "description" : { "type": "string "},
- "open_issues_count" : { "type": "integer "},
- "closed_issues_count" : { "type": "integer "},
- "open_merge_requests_count" : { "type": "integer "},
- "subscribed" : { "type": "boolean" },
- "priority" : { "type": "null" }
- },
- "additionalProperties": false
- }
-}
diff --git a/spec/fixtures/api/schemas/public_api/v4/labels/label.json b/spec/fixtures/api/schemas/public_api/v4/labels/label.json
new file mode 100644
index 00000000000..a116b33572d
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/labels/label.json
@@ -0,0 +1,11 @@
+{
+ "type": "object",
+ "properties": {
+ "id": { "type": "integer" },
+ "name": { "type": "string" },
+ "color": { "type": "string" },
+ "text_color": { "type": "string" },
+ "description": { "type": ["string", "null"] },
+ "subscribed": { "type": "boolean" }
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/labels/label_with_counts.json b/spec/fixtures/api/schemas/public_api/v4/labels/label_with_counts.json
new file mode 100644
index 00000000000..2331932e07d
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/labels/label_with_counts.json
@@ -0,0 +1,16 @@
+{
+ "type": "object",
+ "properties": {
+ "allOf": [
+ { "$ref": "label.json" },
+ {
+ "type": "object",
+ "properties": {
+ "open_issues_count": { "type": "integer" },
+ "closed_issues_count": { "type": "integer" },
+ "open_merge_requests_count": { "type": "integer" }
+ }
+ }
+ ]
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/labels/project_label.json b/spec/fixtures/api/schemas/public_api/v4/labels/project_label.json
new file mode 100644
index 00000000000..a9a065ee71f
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/labels/project_label.json
@@ -0,0 +1,15 @@
+{
+ "type": "object",
+ "properties": {
+ "allOf": [
+ { "$ref": "label.json" },
+ {
+ "type": "object",
+ "properties": {
+ "priority": { "type": ["integer", "null"] },
+ "is_project_label": { "type": "boolean" }
+ }
+ }
+ ]
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/labels/project_label_with_counts.json b/spec/fixtures/api/schemas/public_api/v4/labels/project_label_with_counts.json
new file mode 100644
index 00000000000..87b90b2b3b5
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/labels/project_label_with_counts.json
@@ -0,0 +1,9 @@
+{
+ "type": "object",
+ "properties": {
+ "allOf": [
+ { "$ref": "project_label.json" },
+ { "$ref": "label_with_counts.json" }
+ ]
+ }
+}
diff --git a/spec/frontend/fixtures/projects.rb b/spec/frontend/fixtures/projects.rb
index b6c29003e57..91e3b65215a 100644
--- a/spec/frontend/fixtures/projects.rb
+++ b/spec/frontend/fixtures/projects.rb
@@ -18,8 +18,6 @@ describe 'Projects (JavaScript fixtures)', type: :controller do
end
before do
- stub_licensed_features(variable_environment_scope: true)
-
project.add_maintainer(admin)
sign_in(admin)
allow(SecureRandom).to receive(:hex).and_return('securerandomhex:thereisnospoon')
diff --git a/spec/frontend/tracking_spec.js b/spec/frontend/tracking_spec.js
index 7e462e9a6ce..cd0bf50f8e9 100644
--- a/spec/frontend/tracking_spec.js
+++ b/spec/frontend/tracking_spec.js
@@ -31,13 +31,6 @@ describe('Tracking', () => {
expect(snowplowSpy).not.toHaveBeenCalled();
});
-
- it('skips tracking if ', () => {
- window.snowplow = false;
- Tracking.event('_category_', '_eventName_');
-
- expect(snowplowSpy).not.toHaveBeenCalled();
- });
});
describe('tracking interface events', () => {
diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
index 42a2a9fda2e..f712f47a558 100644
--- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
@@ -91,5 +91,38 @@ describe Gitlab::Ci::Build::Policy::Variables do
expect(policy).to be_satisfied_by(pipeline, seed)
end
end
+
+ context 'when using project ci variables in environment scope' do
+ let(:ci_build) do
+ build(:ci_build, pipeline: pipeline,
+ project: project,
+ ref: 'master',
+ stage: 'review',
+ environment: 'test/$CI_JOB_STAGE/1')
+ end
+
+ before do
+ create(:ci_variable, project: project,
+ key: 'SCOPED_VARIABLE',
+ value: 'my-value-1')
+
+ create(:ci_variable, project: project,
+ key: 'SCOPED_VARIABLE',
+ value: 'my-value-2',
+ environment_scope: 'test/review/*')
+ end
+
+ it 'is satisfied by scoped variable match' do
+ policy = described_class.new(['$SCOPED_VARIABLE == "my-value-2"'])
+
+ expect(policy).to be_satisfied_by(pipeline, seed)
+ end
+
+ it 'is not satisfied when matching against overridden variable' do
+ policy = described_class.new(['$SCOPED_VARIABLE == "my-value-1"'])
+
+ expect(policy).not_to be_satisfied_by(pipeline, seed)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb b/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb
index 23ae026fb14..0e5419e6c5e 100644
--- a/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb
@@ -6,6 +6,7 @@ describe Gitlab::GithubImport::Importer::ReleasesImporter do
let(:importer) { described_class.new(project, client) }
let(:created_at) { Time.new(2017, 1, 1, 12, 00) }
let(:updated_at) { Time.new(2017, 1, 1, 12, 15) }
+ let(:released_at) { Time.new(2017, 1, 1, 12, 00) }
let(:release) do
double(
@@ -13,7 +14,8 @@ describe Gitlab::GithubImport::Importer::ReleasesImporter do
tag_name: '1.0',
body: 'This is my release',
created_at: created_at,
- updated_at: updated_at
+ updated_at: updated_at,
+ published_at: released_at
)
end
@@ -23,7 +25,8 @@ describe Gitlab::GithubImport::Importer::ReleasesImporter do
tag_name: '1.0',
description: 'This is my release',
created_at: created_at,
- updated_at: updated_at
+ updated_at: updated_at,
+ released_at: released_at
}
expect(importer).to receive(:build_releases).and_return([release_hash])
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index ada8c649ff6..fddb5066d6f 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -277,7 +277,6 @@ project:
- bugzilla_service
- gitlab_issue_tracker_service
- external_wiki_service
-- kubernetes_service
- mock_ci_service
- mock_deployment_service
- mock_monitoring_service
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index a1079e54975..ba295386a55 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -32,6 +32,14 @@ describe Gitlab::Regex do
it { is_expected.not_to match('/') }
end
+ describe '.environment_scope_regex' do
+ subject { described_class.environment_scope_regex }
+
+ it { is_expected.to match('foo') }
+ it { is_expected.to match('foo*Z') }
+ it { is_expected.not_to match('!!()()') }
+ end
+
describe '.environment_slug_regex' do
subject { described_class.environment_slug_regex }
diff --git a/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb b/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb
index 98286eb432d..5621d3d17d1 100644
--- a/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb
+++ b/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe Gitlab::SidekiqLogging::StructuredLogger do
describe '#call' do
let(:timestamp) { Time.iso8601('2018-01-01T12:00:00Z') }
- let(:created_at) { timestamp }
- let(:scheduling_latency_s) { 0.0 }
+ let(:created_at) { timestamp - 1.second }
+ let(:scheduling_latency_s) { 1.0 }
let(:job) do
{
@@ -153,5 +153,29 @@ describe Gitlab::SidekiqLogging::StructuredLogger do
end
end
end
+
+ context 'with Gitaly and Rugged calls' do
+ let(:timing_data) do
+ {
+ gitaly_calls: 10,
+ gitaly_duration: 10000,
+ rugged_calls: 1,
+ rugged_duration_ms: 5000
+ }
+ end
+
+ before do
+ job.merge!(timing_data)
+ end
+
+ it 'logs with Gitaly and Rugged timing data' do
+ Timecop.freeze(timestamp) do
+ expect(logger).to receive(:info).with(start_payload.except('args')).ordered
+ expect(logger).to receive(:info).with(end_payload.except('args')).ordered
+
+ subject.call(job, 'test_queue') { }
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb
new file mode 100644
index 00000000000..1669a22879f
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/note_counter_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::UsageDataCounters::NoteCounter, :clean_gitlab_redis_shared_state do
+ shared_examples 'a note usage counter' do |event, noteable_type|
+ describe ".count(#{event})" do
+ it "increments the Note #{event} counter by 1" do
+ expect do
+ described_class.count(event, noteable_type)
+ end.to change { described_class.read(event, noteable_type) }.by 1
+ end
+ end
+
+ describe ".read(#{event})" do
+ event_count = 5
+
+ it "returns the total number of #{event} events" do
+ event_count.times do
+ described_class.count(event, noteable_type)
+ end
+
+ expect(described_class.read(event, noteable_type)).to eq(event_count)
+ end
+ end
+ end
+
+ it_behaves_like 'a note usage counter', :create, 'Snippet'
+
+ describe '.totals' do
+ let(:combinations) do
+ [
+ [:create, 'Snippet', 3]
+ ]
+ end
+
+ let(:expected_totals) do
+ { snippet_comment: 3 }
+ end
+
+ before do
+ combinations.each do |event, noteable_type, n|
+ n.times do
+ described_class.count(event, noteable_type)
+ end
+ end
+ end
+
+ it 'can report all totals' do
+ expect(described_class.totals).to include(expected_totals)
+ end
+ end
+
+ describe 'unknown events or noteable_type' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:unknown_event_error) { Gitlab::UsageDataCounters::BaseCounter::UnknownEvent }
+
+ where(:event, :noteable_type, :expected_count, :should_raise) do
+ :create | 'Snippet' | 1 | false
+ :wibble | 'Snippet' | 0 | true
+ :create | 'Issue' | 0 | false
+ :wibble | 'Issue' | 0 | false
+ end
+
+ with_them do
+ it "handles event" do
+ if should_raise
+ expect { described_class.count(event, noteable_type) }.to raise_error(unknown_event_error)
+ else
+ described_class.count(event, noteable_type)
+
+ expect(described_class.read(event, noteable_type)).to eq(expected_count)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb
new file mode 100644
index 00000000000..65381ed36d1
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::UsageDataCounters::SnippetCounter do
+ it_behaves_like 'a redis usage counter', 'Snippet', :create
+ it_behaves_like 'a redis usage counter', 'Snippet', :update
+
+ it_behaves_like 'a redis usage counter with totals', :snippet,
+ create: 3,
+ update: 2
+end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 297c4f0b683..bf36273251b 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -62,6 +62,9 @@ describe Gitlab::UsageData do
))
expect(subject).to include(
+ snippet_create: a_kind_of(Integer),
+ snippet_update: a_kind_of(Integer),
+ snippet_comment: a_kind_of(Integer),
wiki_pages_create: a_kind_of(Integer),
wiki_pages_update: a_kind_of(Integer),
wiki_pages_delete: a_kind_of(Integer),
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index b7e005e3883..4aac4b640f4 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -2340,6 +2340,32 @@ describe Ci::Build do
it_behaves_like 'containing environment variables'
end
end
+
+ context 'when project has an environment specific variable' do
+ let(:environment_specific_variable) do
+ { key: 'MY_STAGING_ONLY_VARIABLE', value: 'environment_specific_variable', public: false, masked: false }
+ end
+
+ before do
+ create(:ci_variable, environment_specific_variable.slice(:key, :value)
+ .merge(project: project, environment_scope: 'stag*'))
+ end
+
+ it_behaves_like 'containing environment variables'
+
+ context 'when environment scope does not match build environment' do
+ it { is_expected.not_to include(environment_specific_variable) }
+ end
+
+ context 'when environment scope matches build environment' do
+ before do
+ create(:environment, name: 'staging', project: project)
+ build.update!(environment: 'staging')
+ end
+
+ it { is_expected.to include(environment_specific_variable) }
+ end
+ end
end
context 'when build started manually' do
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index a231c7eaed8..3ff547456c6 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -10,6 +10,7 @@ describe Ci::Variable do
describe 'validations' do
it { is_expected.to include_module(Presentable) }
it { is_expected.to include_module(Maskable) }
+ it { is_expected.to include_module(HasEnvironmentScope) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope).with_message(/\(\w+\) has already been taken/) }
end
diff --git a/spec/models/concerns/has_environment_scope_spec.rb b/spec/models/concerns/has_environment_scope_spec.rb
new file mode 100644
index 00000000000..a6e1ba59263
--- /dev/null
+++ b/spec/models/concerns/has_environment_scope_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe HasEnvironmentScope do
+ subject { build(:ci_variable) }
+
+ it { is_expected.to allow_value('*').for(:environment_scope) }
+ it { is_expected.to allow_value('review/*').for(:environment_scope) }
+ it { is_expected.not_to allow_value('').for(:environment_scope) }
+ it { is_expected.not_to allow_value('!!()()').for(:environment_scope) }
+
+ it do
+ is_expected.to validate_uniqueness_of(:key)
+ .scoped_to(:project_id, :environment_scope)
+ .with_message(/\(\w+\) has already been taken/)
+ end
+
+ describe '.on_environment' do
+ let(:project) { create(:project) }
+
+ it 'returns scoped objects' do
+ variable1 = create(:ci_variable, project: project, environment_scope: '*')
+ variable2 = create(:ci_variable, project: project, environment_scope: 'product/*')
+ create(:ci_variable, project: project, environment_scope: 'staging/*')
+
+ expect(project.variables.on_environment('product/canary-1')).to eq([variable1, variable2])
+ end
+
+ it 'returns only the most relevant object if relevant_only is true' do
+ create(:ci_variable, project: project, environment_scope: '*')
+ variable2 = create(:ci_variable, project: project, environment_scope: 'product/*')
+ create(:ci_variable, project: project, environment_scope: 'staging/*')
+
+ expect(project.variables.on_environment('product/canary-1', relevant_only: true)).to eq([variable2])
+ end
+
+ it 'returns scopes ordered by lowest precedence first' do
+ create(:ci_variable, project: project, environment_scope: '*')
+ create(:ci_variable, project: project, environment_scope: 'production*')
+ create(:ci_variable, project: project, environment_scope: 'production')
+
+ result = project.variables.on_environment('production').map(&:environment_scope)
+
+ expect(result).to eq(['*', 'production*', 'production'])
+ end
+ end
+
+ describe '#environment_scope=' do
+ context 'when the new environment_scope is nil' do
+ it 'strips leading and trailing whitespaces' do
+ subject.environment_scope = nil
+
+ expect(subject.environment_scope).to eq('')
+ end
+ end
+
+ context 'when the new environment_scope has leadind and trailing whitespaces' do
+ it 'strips leading and trailing whitespaces' do
+ subject.environment_scope = ' * '
+
+ expect(subject.environment_scope).to eq('*')
+ end
+ end
+ end
+end
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
deleted file mode 100644
index d33bbb0470f..00000000000
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe KubernetesService, :use_clean_rails_memory_store_caching do
- include KubernetesHelpers
- include ReactiveCachingHelpers
-
- let(:project) { create(:kubernetes_project) }
- let(:service) { create(:kubernetes_service, project: project) }
-
- describe 'Associations' do
- it { is_expected.to belong_to :project }
- end
-
- describe 'Validations' do
- context 'when service is active' do
- before do
- subject.active = true
- subject.skip_deprecation_validation = true
- end
-
- it { is_expected.not_to validate_presence_of(:namespace) }
- it { is_expected.to validate_presence_of(:api_url) }
- it { is_expected.to validate_presence_of(:token) }
-
- context 'namespace format' do
- before do
- subject.project = project
- subject.api_url = "http://example.com"
- subject.token = "test"
- end
-
- {
- 'foo' => true,
- '1foo' => true,
- 'foo1' => true,
- 'foo-bar' => true,
- '-foo' => false,
- 'foo-' => false,
- 'a' * 63 => true,
- 'a' * 64 => false,
- 'a.b' => false,
- 'a*b' => false,
- 'FOO' => true
- }.each do |namespace, validity|
- it "validates #{namespace} as #{validity ? 'valid' : 'invalid'}" do
- subject.namespace = namespace
-
- expect(subject.valid?).to eq(validity)
- end
- end
- end
- end
-
- context 'when service is inactive' do
- before do
- subject.project = project
- subject.active = false
- end
-
- it { is_expected.not_to validate_presence_of(:api_url) }
- it { is_expected.not_to validate_presence_of(:token) }
- end
-
- context 'with a deprecated service' do
- let(:kubernetes_service) { create(:kubernetes_service) }
-
- before do
- kubernetes_service.update_attribute(:active, false)
- kubernetes_service.skip_deprecation_validation = false
- kubernetes_service.properties['namespace'] = "foo"
- end
-
- it 'does not update attributes' do
- expect(kubernetes_service.save).to be_falsy
- end
-
- it 'includes an error with a deprecation message' do
- kubernetes_service.valid?
- expect(kubernetes_service.errors[:base].first).to match(/Kubernetes service integration has been disabled/)
- end
- end
-
- context 'with an active and deprecated service' do
- let(:kubernetes_service) { create(:kubernetes_service) }
-
- before do
- kubernetes_service.skip_deprecation_validation = false
- kubernetes_service.active = false
- kubernetes_service.properties['namespace'] = 'foo'
- kubernetes_service.save
- end
-
- it 'deactivates the service' do
- expect(kubernetes_service.active?).to be_falsy
- end
-
- it 'does not include a deprecation message as error' do
- expect(kubernetes_service.errors.messages.count).to eq(0)
- end
-
- it 'updates attributes' do
- expect(kubernetes_service.properties['namespace']).to eq("foo")
- end
- end
- end
-
- describe '#initialize_properties' do
- context 'without a project' do
- it 'leaves the namespace unset' do
- expect(described_class.new.namespace).to be_nil
- end
- end
- end
-
- describe '#fields' do
- let(:kube_namespace) do
- subject.fields.find { |h| h[:name] == 'namespace' }
- end
-
- context 'as template' do
- before do
- subject.template = true
- end
-
- it 'sets the namespace to the default' do
- expect(kube_namespace).not_to be_nil
- expect(kube_namespace[:placeholder]).to eq(subject.class::TEMPLATE_PLACEHOLDER)
- end
- end
-
- context 'with associated project' do
- before do
- subject.project = project
- end
-
- it 'sets the namespace to the default' do
- expect(kube_namespace).not_to be_nil
- expect(kube_namespace[:placeholder]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/)
- end
- end
- end
-
- describe "#deprecated?" do
- let(:kubernetes_service) { create(:kubernetes_service) }
-
- it 'returns true' do
- expect(kubernetes_service.deprecated?).to be_truthy
- end
- end
-
- describe "#deprecation_message" do
- let(:kubernetes_service) { create(:kubernetes_service) }
-
- it 'indicates the service is deprecated' do
- expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been disabled/)
- end
-
- context 'if the service is not active' do
- it 'returns a message' do
- kubernetes_service.update_attribute(:active, false)
- expect(kubernetes_service.deprecation_message).to match(/Fields on this page are not used by GitLab/)
- end
- end
- end
-end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index dde766c3813..29a589eba20 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2648,9 +2648,10 @@ describe Project do
describe '#ci_variables_for' do
let(:project) { create(:project) }
+ let(:environment_scope) { '*' }
let!(:ci_variable) do
- create(:ci_variable, value: 'secret', project: project)
+ create(:ci_variable, value: 'secret', project: project, environment_scope: environment_scope)
end
let!(:protected_variable) do
@@ -2695,6 +2696,96 @@ describe Project do
it_behaves_like 'ref is protected'
end
+
+ context 'when environment name is specified' do
+ let(:environment) { 'review/name' }
+
+ subject do
+ project.ci_variables_for(ref: 'ref', environment: environment)
+ end
+
+ context 'when environment scope is exactly matched' do
+ let(:environment_scope) { 'review/name' }
+
+ it { is_expected.to contain_exactly(ci_variable) }
+ end
+
+ context 'when environment scope is matched by wildcard' do
+ let(:environment_scope) { 'review/*' }
+
+ it { is_expected.to contain_exactly(ci_variable) }
+ end
+
+ context 'when environment scope does not match' do
+ let(:environment_scope) { 'review/*/special' }
+
+ it { is_expected.not_to contain_exactly(ci_variable) }
+ end
+
+ context 'when environment scope has _' do
+ let(:environment_scope) { '*_*' }
+
+ it 'does not treat it as wildcard' do
+ is_expected.not_to contain_exactly(ci_variable)
+ end
+
+ context 'when environment name contains underscore' do
+ let(:environment) { 'foo_bar/test' }
+ let(:environment_scope) { 'foo_bar/*' }
+
+ it 'matches literally for _' do
+ is_expected.to contain_exactly(ci_variable)
+ end
+ end
+ end
+
+ # The environment name and scope cannot have % at the moment,
+ # but we're considering relaxing it and we should also make sure
+ # it doesn't break in case some data sneaked in somehow as we're
+ # not checking this integrity in database level.
+ context 'when environment scope has %' do
+ it 'does not treat it as wildcard' do
+ ci_variable.update_attribute(:environment_scope, '*%*')
+
+ is_expected.not_to contain_exactly(ci_variable)
+ end
+
+ context 'when environment name contains a percent' do
+ let(:environment) { 'foo%bar/test' }
+
+ it 'matches literally for _' do
+ ci_variable.update(environment_scope: 'foo%bar/*')
+
+ is_expected.to contain_exactly(ci_variable)
+ end
+ end
+ end
+
+ context 'when variables with the same name have different environment scopes' do
+ let!(:partially_matched_variable) do
+ create(:ci_variable,
+ key: ci_variable.key,
+ value: 'partial',
+ environment_scope: 'review/*',
+ project: project)
+ end
+
+ let!(:perfectly_matched_variable) do
+ create(:ci_variable,
+ key: ci_variable.key,
+ value: 'prefect',
+ environment_scope: 'review/name',
+ project: project)
+ end
+
+ it 'puts variables matching environment scope more in the end' do
+ is_expected.to eq(
+ [ci_variable,
+ partially_matched_variable,
+ perfectly_matched_variable])
+ end
+ end
+ end
end
describe '#any_lfs_file_locks?', :request_store do
diff --git a/spec/requests/api/group_labels_spec.rb b/spec/requests/api/group_labels_spec.rb
index fcea57d9df7..0be4e2e9121 100644
--- a/spec/requests/api/group_labels_spec.rb
+++ b/spec/requests/api/group_labels_spec.rb
@@ -14,12 +14,25 @@ describe API::GroupLabels do
get api("/groups/#{group.id}/labels", user)
expect(response).to have_gitlab_http_status(200)
- expect(response).to match_response_schema('public_api/v4/group_labels')
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
+ expect(json_response).to all(match_schema('public_api/v4/labels/label'))
expect(json_response.size).to eq(2)
expect(json_response.map {|r| r['name'] }).to contain_exactly('feature', 'bug')
end
+
+ context 'when the with_counts parameter is set' do
+ it 'includes counts in the response' do
+ get api("/groups/#{group.id}/labels", user), params: { with_counts: true }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response).to all(match_schema('public_api/v4/labels/label_with_counts'))
+ expect(json_response.size).to eq(2)
+ expect(json_response.map { |r| r['open_issues_count'] }).to contain_exactly(0, 0)
+ end
+ end
end
describe 'POST /groups/:id/labels' do
diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb
index f11d8259d4a..f7ca6fd1e0a 100644
--- a/spec/requests/api/issues/get_project_issues_spec.rb
+++ b/spec/requests/api/issues/get_project_issues_spec.rb
@@ -389,7 +389,7 @@ describe API::Issues do
it 'returns an array of issues with any milestone' do
get api("#{base_url}/issues", user), params: { milestone: any_milestone_title }
- expect_paginated_array_response([issue.id, confidential_issue.id, closed_issue.id])
+ expect_paginated_array_response([issue.id, closed_issue.id])
end
context 'without sort params' do
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index 518181e4d93..ad0974f55a3 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -11,65 +11,76 @@ describe API::Labels do
end
describe 'GET /projects/:id/labels' do
- it 'returns all available labels to the project' do
- group = create(:group)
- group_label = create(:group_label, title: 'feature', group: group)
- project.update(group: group)
- create(:labeled_issue, project: project, labels: [group_label], author: user)
- create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed)
- create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project )
+ let(:group) { create(:group) }
+ let!(:group_label) { create(:group_label, title: 'feature', group: group) }
- expected_keys = %w(
- id name color text_color description
- open_issues_count closed_issues_count open_merge_requests_count
- subscribed priority is_project_label
- )
+ before do
+ project.update!(group: group)
+ end
+ it 'returns all available labels to the project' do
get api("/projects/#{project.id}/labels", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
+ expect(json_response).to all(match_schema('public_api/v4/labels/project_label'))
expect(json_response.size).to eq(3)
- expect(json_response.first.keys).to match_array expected_keys
expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, priority_label.name, label1.name])
+ end
- label1_response = json_response.find { |l| l['name'] == label1.title }
- group_label_response = json_response.find { |l| l['name'] == group_label.title }
- priority_label_response = json_response.find { |l| l['name'] == priority_label.title }
-
- expect(label1_response['open_issues_count']).to eq(0)
- expect(label1_response['closed_issues_count']).to eq(1)
- expect(label1_response['open_merge_requests_count']).to eq(0)
- expect(label1_response['name']).to eq(label1.name)
- expect(label1_response['color']).to be_present
- expect(label1_response['text_color']).to be_present
- expect(label1_response['description']).to be_nil
- expect(label1_response['priority']).to be_nil
- expect(label1_response['subscribed']).to be_falsey
- expect(label1_response['is_project_label']).to be_truthy
-
- expect(group_label_response['open_issues_count']).to eq(1)
- expect(group_label_response['closed_issues_count']).to eq(0)
- expect(group_label_response['open_merge_requests_count']).to eq(0)
- expect(group_label_response['name']).to eq(group_label.name)
- expect(group_label_response['color']).to be_present
- expect(group_label_response['text_color']).to be_present
- expect(group_label_response['description']).to be_nil
- expect(group_label_response['priority']).to be_nil
- expect(group_label_response['subscribed']).to be_falsey
- expect(group_label_response['is_project_label']).to be_falsey
-
- expect(priority_label_response['open_issues_count']).to eq(0)
- expect(priority_label_response['closed_issues_count']).to eq(0)
- expect(priority_label_response['open_merge_requests_count']).to eq(1)
- expect(priority_label_response['name']).to eq(priority_label.name)
- expect(priority_label_response['color']).to be_present
- expect(priority_label_response['text_color']).to be_present
- expect(priority_label_response['description']).to be_nil
- expect(priority_label_response['priority']).to eq(3)
- expect(priority_label_response['subscribed']).to be_falsey
- expect(priority_label_response['is_project_label']).to be_truthy
+ context 'when the with_counts parameter is set' do
+ before do
+ create(:labeled_issue, project: project, labels: [group_label], author: user)
+ create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed)
+ create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project )
+ end
+
+ it 'includes counts in the response' do
+ get api("/projects/#{project.id}/labels", user), params: { with_counts: true }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to all(match_schema('public_api/v4/labels/project_label_with_counts'))
+ expect(json_response.size).to eq(3)
+ expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, priority_label.name, label1.name])
+
+ label1_response = json_response.find { |l| l['name'] == label1.title }
+ group_label_response = json_response.find { |l| l['name'] == group_label.title }
+ priority_label_response = json_response.find { |l| l['name'] == priority_label.title }
+
+ expect(label1_response).to include('open_issues_count' => 0,
+ 'closed_issues_count' => 1,
+ 'open_merge_requests_count' => 0,
+ 'name' => label1.name,
+ 'description' => nil,
+ 'color' => a_string_matching(/^#\h{6}$/),
+ 'text_color' => a_string_matching(/^#\h{6}$/),
+ 'priority' => nil,
+ 'subscribed' => false,
+ 'is_project_label' => true)
+
+ expect(group_label_response).to include('open_issues_count' => 1,
+ 'closed_issues_count' => 0,
+ 'open_merge_requests_count' => 0,
+ 'name' => group_label.name,
+ 'description' => nil,
+ 'color' => a_string_matching(/^#\h{6}$/),
+ 'text_color' => a_string_matching(/^#\h{6}$/),
+ 'priority' => nil,
+ 'subscribed' => false,
+ 'is_project_label' => false)
+
+ expect(priority_label_response).to include('open_issues_count' => 0,
+ 'closed_issues_count' => 0,
+ 'open_merge_requests_count' => 1,
+ 'name' => priority_label.name,
+ 'description' => nil,
+ 'color' => a_string_matching(/^#\h{6}$/),
+ 'text_color' => a_string_matching(/^#\h{6}$/),
+ 'priority' => 3,
+ 'subscribed' => false,
+ 'is_project_label' => true)
+ end
end
end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 91cb8760a04..76a70ab6e9e 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -10,10 +10,7 @@ describe API::Services do
end
Service.available_services_names.each do |service|
- # TODO: Remove below `if: (service != "kubernetes")` in the next release
- # KubernetesService was deprecated and it can't be updated. Right now it's
- # only readable. It should be completely removed in the next iteration.
- describe "PUT /projects/:id/services/#{service.dasherize}", if: (service != "kubernetes") do
+ describe "PUT /projects/:id/services/#{service.dasherize}" do
include_context service
it "updates #{service} settings" do
@@ -62,10 +59,7 @@ describe API::Services do
end
end
- # TODO: Remove below `if: (service != "kubernetes")` in the next release
- # KubernetesService was deprecated and it can't be updated. Right now it's
- # only readable. It should be completely removed in the next iteration.
- describe "DELETE /projects/:id/services/#{service.dasherize}", if: (service != "kubernetes") do
+ describe "DELETE /projects/:id/services/#{service.dasherize}" do
include_context service
before do
diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb
index 55b1419a004..69f105b71a8 100644
--- a/spec/requests/api/variables_spec.rb
+++ b/spec/requests/api/variables_spec.rb
@@ -106,6 +106,30 @@ describe API::Variables do
expect(response).to have_gitlab_http_status(400)
end
+
+ it 'creates variable with a specific environment scope' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'VALUE_2', environment_scope: 'review/*' }
+ end.to change { project.variables.reload.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['environment_scope']).to eq('review/*')
+ end
+
+ it 'allows duplicated variable key given different environment scopes' do
+ variable = create(:ci_variable, project: project)
+
+ expect do
+ post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2', environment_scope: 'review/*' }
+ end.to change { project.variables.reload.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['key']).to eq(variable.key)
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['environment_scope']).to eq('review/*')
+ end
end
context 'authorized user with invalid permissions' do
diff --git a/spec/serializers/variable_entity_spec.rb b/spec/serializers/variable_entity_spec.rb
index effc0022633..10664ff66ec 100644
--- a/spec/serializers/variable_entity_spec.rb
+++ b/spec/serializers/variable_entity_spec.rb
@@ -8,7 +8,7 @@ describe VariableEntity do
subject { entity.as_json }
it 'contains required fields' do
- expect(subject).to include(:id, :key, :value, :protected)
+ expect(subject).to include(:id, :key, :value, :protected, :environment_scope)
end
end
end
diff --git a/spec/services/create_snippet_service_spec.rb b/spec/services/create_snippet_service_spec.rb
index f6b6989b955..9b83f65a17e 100644
--- a/spec/services/create_snippet_service_spec.rb
+++ b/spec/services/create_snippet_service_spec.rb
@@ -36,6 +36,22 @@ describe CreateSnippetService do
end
end
+ describe 'usage counter' do
+ let(:counter) { Gitlab::UsageDataCounters::SnippetCounter }
+
+ it 'increments count' do
+ expect do
+ create_snippet(nil, @admin, @opts)
+ end.to change { counter.read(:create) }.by 1
+ end
+
+ it 'does not increment count if create fails' do
+ expect do
+ create_snippet(nil, @admin, {})
+ end.not_to change { counter.read(:create) }
+ end
+ end
+
def create_snippet(project, user, opts)
CreateSnippetService.new(project, user, opts).execute
end
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 46abd8f356a..cd4ea9c401d 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -365,5 +365,43 @@ describe Notes::CreateService do
.and change { existing_note.updated_at }
end
end
+
+ describe "usage counter" do
+ let(:counter) { Gitlab::UsageDataCounters::NoteCounter }
+
+ context 'snippet note' do
+ let(:snippet) { create(:project_snippet, project: project) }
+ let(:opts) { { note: 'reply', noteable_type: 'Snippet', noteable_id: snippet.id, project: project } }
+
+ it 'increments usage counter' do
+ expect do
+ note = described_class.new(project, user, opts).execute
+
+ expect(note).to be_valid
+ end.to change { counter.read(:create, opts[:noteable_type]) }.by 1
+ end
+
+ it 'does not increment usage counter when creation fails' do
+ expect do
+ note = described_class.new(project, user, { note: '' }).execute
+
+ expect(note).to be_invalid
+ end.not_to change { counter.read(:create, opts[:noteable_type]) }
+ end
+ end
+
+ context 'issue note' do
+ let(:issue) { create(:issue, project: project) }
+ let(:opts) { { note: 'reply', noteable_type: 'Issue', noteable_id: issue.id, project: project } }
+
+ it 'does not increment usage counter' do
+ expect do
+ note = described_class.new(project, user, opts).execute
+
+ expect(note).to be_valid
+ end.not_to change { counter.read(:create, opts[:noteable_type]) }
+ end
+ end
+ end
end
end
diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb
index 23ea4e003f8..0678f54c195 100644
--- a/spec/services/update_snippet_service_spec.rb
+++ b/spec/services/update_snippet_service_spec.rb
@@ -40,6 +40,23 @@ describe UpdateSnippetService do
end
end
+ describe 'usage counter' do
+ let(:counter) { Gitlab::UsageDataCounters::SnippetCounter }
+ let(:snippet) { create_snippet(nil, @user, @opts) }
+
+ it 'increments count' do
+ expect do
+ update_snippet(nil, @admin, snippet, @opts)
+ end.to change { counter.read(:update) }.by 1
+ end
+
+ it 'does not increment count if create fails' do
+ expect do
+ update_snippet(nil, @admin, snippet, { title: '' })
+ end.not_to change { counter.read(:update) }
+ end
+ end
+
def create_snippet(project, user, opts)
CreateSnippetService.new(project, user, opts).execute
end
diff --git a/vendor/project_templates/rails.tar.gz b/vendor/project_templates/rails.tar.gz
index c1f90c3f8f7..6bb51bcd7a1 100644
--- a/vendor/project_templates/rails.tar.gz
+++ b/vendor/project_templates/rails.tar.gz
Binary files differ