summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-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
34 files changed, 189 insertions, 204 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