Commit 808671d8 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 702f9f2a7ca7
......@@ -6,6 +6,14 @@
.if-canonical-gitlab-merge-request: &if-canonical-gitlab-merge-request
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_MERGE_REQUEST_IID'
# Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-not-ee: &if-not-ee
if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/'
# Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-default-refs: &if-default-refs
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG'
# Make sure to update all the similar patterns in other CI config files if you modify these patterns
.code-patterns: &code-patterns
- ".gitlab/ci/**/*"
......@@ -27,12 +35,43 @@
- ".dockerignore"
- "qa/**/*"
# Make sure to update all the similar patterns in other CI config files if you modify these patterns
.code-qa-patterns: &code-qa-patterns
- ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
- ".csscomb.json"
- "Dockerfile.assets"
- "*_VERSION"
- "Gemfile{,.lock}"
- "Rakefile"
- "{babel.config,jest.config}.js"
- "config.ru"
- "{package.json,yarn.lock}"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# QA changes
- ".dockerignore"
- "qa/**/*"
.qa:rules:ee-and-foss:
rules:
- <<: *if-default-refs
changes: *code-qa-patterns
when: on_success
.qa:rules:ee-only:
rules:
- <<: *if-not-ee
when: never
- <<: *if-default-refs
changes: *code-qa-patterns
when: on_success
.qa-job-base:
extends:
- .default-tags
- .default-retry
- .default-only
- .only:changes-code-qa
stage: test
dependencies: []
cache:
......@@ -46,26 +85,32 @@
- bundle check
qa:internal:
extends: .qa-job-base
extends:
- .qa-job-base
- .qa:rules:ee-and-foss
script:
- bundle exec rspec
qa:internal-foss:
extends:
- .qa-job-base
- .only-ee-as-if-foss
- .qa:rules:ee-only
- .as-if-foss
script:
- bundle exec rspec
qa:selectors:
extends: .qa-job-base
extends:
- .qa-job-base
- .qa:rules:ee-and-foss
script:
- bundle exec bin/qa Test::Sanity::Selectors
qa:selectors-foss:
extends:
- qa:selectors
- .only-ee-as-if-foss
- .qa:rules:ee-only
- .as-if-foss
.package-and-qa-base:
image: ruby:2.6-alpine
......
......@@ -334,17 +334,15 @@ RSpec/UnspecifiedException:
# Work in progress. See https://gitlab.com/gitlab-org/gitlab/issues/196163
RSpec/HaveGitlabHttpStatus:
Enabled: true
Exclude:
- 'spec/support/matchers/have_gitlab_http_status.rb'
Include:
- 'spec/support/shared_examples/**/*'
- 'ee/spec/support/shared_examples/**/*'
- 'spec/support/**/*'
- 'ee/spec/support/**/*'
- 'spec/features/**/*'
- 'ee/spec/features/**/*'
- 'spec/controllers/*.rb'
- 'ee/spec/controllers/*.rb'
- 'spec/controllers/projects/**/*.rb'
- 'ee/spec/controllers/projects/**/*.rb'
- 'spec/controllers/groups/**/*.rb'
- 'ee/spec/controllers/groups/**/*.rb'
- 'spec/controllers/**/*'
- 'ee/spec/controllers/**/*'
- 'spec/requests/*.rb'
- 'ee/spec/requests/*.rb'
......
......@@ -36,6 +36,7 @@ import initSearchAutocomplete from './search_autocomplete';
import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers';
import initBroadcastNotifications from './broadcast_notification';
import PersistentUserCallout from './persistent_user_callout';
import { initUserTracking } from './tracking';
import { __ } from './locale';
......@@ -108,6 +109,9 @@ function deferredInitialisation() {
initUserTracking();
initBroadcastNotifications();
const recoverySettingsCallout = document.querySelector('.js-recovery-settings-callout');
PersistentUserCallout.factory(recoverySettingsCallout);
if (document.querySelector('.search')) initSearchAutocomplete();
addSelectOnFocusBehaviour('.js-select-on-focus');
......
......@@ -2,7 +2,10 @@
class UserCalloutsController < ApplicationController
def create
if ensure_callout.persisted?
callout = ensure_callout
if callout.persisted?
callout.update(dismissed_at: Time.now)
respond_to do |format|
format.json { head :ok }
end
......
......@@ -16,7 +16,8 @@ class Project < BasePermissionType
:create_deployment, :push_to_delete_protected_branch,
:admin_wiki, :admin_project, :update_pages,
:admin_remote_mirror, :create_label, :update_wiki, :destroy_wiki,
:create_pages, :destroy_pages, :read_pages_content, :admin_operations
:create_pages, :destroy_pages, :read_pages_content, :admin_operations,
:read_merge_request
permission_field :create_snippet
......
......@@ -153,7 +153,7 @@ def markup_unsafe(file_name, text, context = {})
other_markup_unsafe(file_name, text, context)
end
rescue StandardError => e
Gitlab::ErrorTracking.track_exception(e, project_id: @project&.id, file_name: file_name, context: context)
Gitlab::ErrorTracking.track_exception(e, project_id: @project&.id, file_name: file_name)
simple_format(text)
end
......
......@@ -22,6 +22,9 @@ def render_flash_user_callout(flash_type, message, feature_name)
def render_dashboard_gold_trial(user)
end
def render_account_recovery_regular_check
end
def show_suggest_popover?
!user_dismissed?(SUGGEST_POPOVER_DISMISSED)
end
......@@ -32,8 +35,10 @@ def show_tabs_feature_highlight?
private
def user_dismissed?(feature_name)
current_user&.callouts&.find_by(feature_name: UserCallout.feature_names[feature_name])
def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil)
return false unless current_user
current_user.dismissed_callout?(feature_name: feature_name, ignore_dismissal_earlier_than: ignore_dismissal_earlier_than)
end
end
......
......@@ -4,19 +4,78 @@ module Ci
class Bridge < Ci::Processable
include Ci::Contextable
include Ci::PipelineDelegator
include Ci::Metadatable
include Importable
include AfterCommitQueue
include HasRef
include Gitlab::Utils::StrongMemoize
InvalidBridgeTypeError = Class.new(StandardError)
belongs_to :project
belongs_to :trigger_request
has_many :sourced_pipelines, class_name: "::Ci::Sources::Pipeline",
foreign_key: :source_job_id
validates :ref, presence: true
# rubocop:disable Cop/ActiveRecordSerialize
serialize :options
serialize :yaml_variables, ::Gitlab::Serializer::Ci::Variables
# rubocop:enable Cop/ActiveRecordSerialize
state_machine :status do
event :manual do
transition all => :manual
end
event :scheduled do
transition all => :scheduled
end
end
def self.retry(bridge, current_user)
raise NotImplementedError
end
def inherit_status_from_downstream!(pipeline)
case pipeline.status
when 'success'
self.success!
when 'failed', 'canceled', 'skipped'
self.drop!
else
false
end
end
def downstream_pipeline_params
return child_params if triggers_child_pipeline?
return cross_project_params if downstream_project.present?
{}
end
def downstream_project
strong_memoize(:downstream_project) do
if downstream_project_path
::Project.find_by_full_path(downstream_project_path)
elsif triggers_child_pipeline?
project
end
end
end
def downstream_project_path
strong_memoize(:downstream_project_path) do
options&.dig(:trigger, :project)
end
end
def triggers_child_pipeline?
yaml_for_downstream.present?
end
def tags
[:bridge]
end
......@@ -55,7 +114,68 @@ def to_partial_path
end
def yaml_for_downstream
nil
strong_memoize(:yaml_for_downstream) do
includes = options&.dig(:trigger, :include)
YAML.dump('include' => includes) if includes
end
end
def target_ref
branch = options&.dig(:trigger, :branch)
return unless branch
scoped_variables.to_runner_variables.yield_self do |all_variables|
::ExpandVariables.expand(branch, all_variables)
end
end
def dependent?
strong_memoize(:dependent) do
options&.dig(:trigger, :strategy) == 'depend'
end
end
def downstream_variables
variables = scoped_variables.concat(pipeline.persisted_variables)
variables.to_runner_variables.yield_self do |all_variables|
yaml_variables.to_a.map do |hash|
{ key: hash[:key], value: ::ExpandVariables.expand(hash[:value], all_variables) }
end
end
end
private
def cross_project_params
{
project: downstream_project,
source: :pipeline,
target_revision: {
ref: target_ref || downstream_project.default_branch
},
execute_params: { ignore_skip_ci: true }
}
end
def child_params
parent_pipeline = pipeline
{
project: project,
source: :parent_pipeline,
target_revision: {
ref: parent_pipeline.ref,
checkout_sha: parent_pipeline.sha,
before: parent_pipeline.before_sha,
source_sha: parent_pipeline.source_sha,
target_sha: parent_pipeline.target_sha
},
execute_params: {
ignore_skip_ci: true,
bridge: self
}
}
end
end
end
......
......@@ -58,5 +58,12 @@ def query_klass_for(query_name)
def build_query_args(*args)
args.map { |arg| arg.respond_to?(:id) ? arg.id : arg }
end
def clear_prometheus_reactive_cache!(query_name, *args)
query_class = query_klass_for(query_name)
query_args = build_query_args(*args)
clear_reactive_cache!(query_class.name, *query_args)
end
end
end
......@@ -11,6 +11,7 @@ class Environment < ApplicationRecord
has_many :deployments, -> { visible }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :successful_deployments, -> { success }, class_name: 'Deployment'
has_many :prometheus_alerts, inverse_of: :environment
has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
has_one :last_deployable, through: :last_deployment, source: 'deployable', source_type: 'CommitStatus'
......@@ -105,6 +106,14 @@ def self.find_or_create_by_name(name)
find_or_create_by(name: name)
end
def clear_prometheus_reactive_cache!(query_name)
cluster_prometheus_adapter&.clear_prometheus_reactive_cache!(query_name, self)
end
def cluster_prometheus_adapter
@cluster_prometheus_adapter ||= ::Gitlab::Prometheus::Adapter.new(project, deployment_platform&.cluster).cluster_prometheus_adapter
end
def predefined_variables
Gitlab::Ci::Variables::Collection.new
.append(key: 'CI_ENVIRONMENT_NAME', value: name)
......
......@@ -244,6 +244,7 @@ class Project < ApplicationRecord
has_many :management_clusters, class_name: 'Clusters::Cluster', foreign_key: :management_project_id, inverse_of: :management_project
has_many :prometheus_metrics
has_many :prometheus_alerts, inverse_of: :project
# Container repositories need to remove data from the container registry,
# which is not managed by the DB. Hence we're still using dependent: :destroy
......
# frozen_string_literal: true
class PrometheusAlert < ApplicationRecord
include Sortable
OPERATORS_MAP = {
lt: "<",
eq: "==",
gt: ">"
}.freeze
belongs_to :environment, validate: true, inverse_of: :prometheus_alerts
belongs_to :project, validate: true, inverse_of: :prometheus_alerts
belongs_to :prometheus_metric, validate: true, inverse_of: :prometheus_alerts
has_many :prometheus_alert_events, inverse_of: :prometheus_alert
has_many :related_issues, through: :prometheus_alert_events
after_save :clear_prometheus_adapter_cache!
after_destroy :clear_prometheus_adapter_cache!
validates :environment, :project, :prometheus_metric, presence: true
validate :require_valid_environment_project!
validate :require_valid_metric_project!
enum operator: { lt: 0, eq: 1, gt: 2 }
delegate :title, :query, to: :prometheus_metric
scope :for_metric, -> (metric) { where(prometheus_metric: metric) }
scope :for_project, -> (project) { where(project_id: project) }
scope :for_environment, -> (environment) { where(environment_id: environment) }
def self.distinct_projects
sub_query = self.group(:project_id).select(1)
self.from(sub_query)
end
def self.operator_to_enum(op)
OPERATORS_MAP.invert.fetch(op)
end
def full_query
"#{query} #{computed_operator} #{threshold}"
end
def computed_operator
OPERATORS_MAP.fetch(operator.to_sym)
end
def to_param
{
"alert" => title,
"expr" => full_query,
"for" => "5m",
"labels" => {
"gitlab" => "hook",
"gitlab_alert_id" => prometheus_metric_id
}
}
end
private
def clear_prometheus_adapter_cache!
environment.clear_prometheus_reactive_cache!(:additional_metrics_environment)
end
def require_valid_environment_project!
return if project == environment&.project
errors.add(:environment, "invalid project")
end
def require_valid_metric_project!
return if prometheus_metric&.common?
return if project == prometheus_metric&.project
errors.add(:prometheus_metric, "invalid project")
end
end
......@@ -1644,6 +1644,13 @@ def set_role_required!
end
# End of signup_flow experiment methods
def dismissed_callout?(feature_name:, ignore_dismissal_earlier_than: nil)
callouts = self.callouts.with_feature_name(feature_name)
callouts = callouts.with_dismissed_after(ignore_dismissal_earlier_than) if ignore_dismissal_earlier_than
callouts.any?
end
# @deprecated
alias_method :owned_or_masters_groups, :owned_or_maintainers_groups
......
......@@ -12,4 +12,7 @@ class UserCallout < ApplicationRecord
presence: true,
uniqueness: { scope: :user_id },
inclusion: { in: UserCallout.feature_names.keys }
scope :with_feature_name, -> (feature_name) { where(feature_name: UserCallout.feature_names[feature_name]) }
scope :with_dismissed_after, -> (dismissed_after) { where('dismissed_at > ?', dismissed_after) }
end
......@@ -4,6 +4,8 @@
.table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Kubernetes cluster")
.table-mobile-content
= cluster.item_link(clusterable, html_options: { data: { qa_selector: 'cluster', qa_cluster_name: cluster.name } })
- if cluster.status_name == :creating
.spinner.ml-2.align-middle.has-tooltip{ title: s_("ClusterIntegration|Cluster being created") }
- unless cluster.enabled?
%span.badge.badge-danger Connection disabled
.table-section.section-25
......
......@@ -11,6 +11,7 @@
= render "layouts/nav/classification_level_banner"
= yield :flash_message
= render "shared/ping_consent"
= render_account_recovery_regular_check
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
.d-flex
......
.gl-alert.gl-alert-warning.js-recovery-settings-callout{ role: 'alert', data: { feature_id: "account_recovery_regular_check", dismiss_endpoint: user_callouts_path, defer_links: "true" } }
%button.js-close.gl-alert-dismiss.gl-cursor-pointer{ type: 'button', 'aria-label' => _('Dismiss') }
= sprite_icon('close', size: 16, css_class: 'gl-icon')
.gl-alert-body
- account_link_start = '<a class="deferred-link" href="%{url}">'.html_safe % { url: profile_account_path }
= _("Please ensure your account's %{account_link_start}recovery settings%{account_link_end} are up to date.").html_safe % { account_link_start: account_link_start, account_link_end: '</a>'.html_safe }
---
title: Add loading icon to clusters being created
merge_request: 24370
author:
type: added
---
title: Don't leak entire objects into the error log when rendering markup fails
merge_request: 24599
author:
type: fixed
---
title: Remove username lookup when mapping users when importing projects using Project
Import/Export and rely on email only
merge_request: 24464
author:
type: changed
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment