Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
277fdda606
commit
5958e399de
|
@ -1 +1 @@
|
|||
d6ded95a76876ff182d37cb33ed9515ed29d5c23
|
||||
300980719a82ec3b40c5d938310cebd6fc3d3c37
|
||||
|
|
|
@ -659,9 +659,9 @@ GEM
|
|||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
memory_profiler (0.9.14)
|
||||
method_source (0.9.2)
|
||||
mime-types (3.2.2)
|
||||
mime-types (3.3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2019.0331)
|
||||
mime-types-data (3.2020.0512)
|
||||
mimemagic (0.3.5)
|
||||
mini_histogram (0.1.3)
|
||||
mini_magick (4.9.5)
|
||||
|
|
|
@ -282,7 +282,7 @@ export default {
|
|||
@sort-changed="fetchSortedData"
|
||||
>
|
||||
<template #cell(title)="{ item }">
|
||||
<div class="incident-management-list-title gl-display-flex gl-align-items-center">
|
||||
<div :class="{ 'gl-display-flex gl-align-items-center': item.state === 'closed' }">
|
||||
<div class="gl-max-w-full text-truncate" :title="item.title">{{ item.title }}</div>
|
||||
<gl-icon
|
||||
v-if="item.state === 'closed'"
|
||||
|
|
|
@ -19,10 +19,6 @@
|
|||
@include gl-relative;
|
||||
}
|
||||
|
||||
.sortable-cell {
|
||||
padding-left: calc(0.75rem + 0.65em);
|
||||
}
|
||||
|
||||
th {
|
||||
@include gl-bg-transparent;
|
||||
@include gl-font-weight-bold;
|
||||
|
@ -42,6 +38,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sortable-cell {
|
||||
padding-left: calc(0.75rem + 0.65em);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,11 @@
|
|||
@include gl-bg-white;
|
||||
@include gl-border-none;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
@include gl-pt-6;
|
||||
}
|
||||
}
|
||||
|
||||
&.alert-management-table {
|
||||
|
@ -77,8 +82,24 @@
|
|||
}
|
||||
}
|
||||
|
||||
.incident-management-list-title {
|
||||
@include gl-flex-direction-row-reverse;
|
||||
.b-table-empty-row {
|
||||
td {
|
||||
@include gl-border-b-0;
|
||||
|
||||
div {
|
||||
text-align: unset !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.b-table-busy-slot {
|
||||
td {
|
||||
@include gl-border-b-0;
|
||||
|
||||
div {
|
||||
text-align: center !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
class BoardListIssuesResolver < BaseResolver
|
||||
type Types::IssueType, null: true
|
||||
|
||||
alias_method :list, :object
|
||||
|
||||
def resolve(**args)
|
||||
service = Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], { board_id: list.board.id, id: list.id })
|
||||
Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection.new(service.execute)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -94,8 +94,12 @@ module Types
|
|||
field :metrics_dashboard_url,
|
||||
GraphQL::STRING_TYPE,
|
||||
null: true,
|
||||
description: 'URL for metrics embed for the alert',
|
||||
resolve: -> (alert, _args, _context) { alert.present.metrics_dashboard_url }
|
||||
description: 'URL for metrics embed for the alert'
|
||||
|
||||
field :runbook,
|
||||
GraphQL::STRING_TYPE,
|
||||
null: true,
|
||||
description: 'Runbook for the alert as defined in alert details'
|
||||
|
||||
field :todos,
|
||||
Types::TodoType.connection_type,
|
||||
|
|
|
@ -19,6 +19,10 @@ module Types
|
|||
field :collapsed, GraphQL::BOOLEAN_TYPE, null: true,
|
||||
description: 'Indicates if list is collapsed for this user',
|
||||
resolve: -> (list, _args, ctx) { list.collapsed?(ctx[:current_user]) }
|
||||
|
||||
field :issues, ::Types::IssueType.connection_type, null: true,
|
||||
description: 'Board issues',
|
||||
resolver: ::Resolvers::BoardListIssuesResolver
|
||||
end
|
||||
# rubocop: enable Graphql/AuthorizeTypes
|
||||
end
|
||||
|
|
|
@ -7,7 +7,17 @@ module Types
|
|||
description: 'Total count of collection'
|
||||
|
||||
def count
|
||||
object.items.size
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
relation = object.items
|
||||
# sometimes relation is an Array
|
||||
relation = relation.reorder(nil) if relation.respond_to?(:reorder)
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
if relation.try(:group_values)&.present?
|
||||
relation.size.keys.size
|
||||
else
|
||||
relation.size
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -118,6 +118,7 @@ module AlertManagement
|
|||
end
|
||||
|
||||
delegate :iid, to: :issue, prefix: true, allow_nil: true
|
||||
delegate :metrics_dashboard_url, :runbook, to: :present
|
||||
|
||||
scope :for_iid, -> (iid) { where(iid: iid) }
|
||||
scope :for_status, -> (status) { where(status: status) }
|
||||
|
|
|
@ -857,8 +857,7 @@ module Ci
|
|||
end
|
||||
|
||||
def multi_build_steps?
|
||||
options.dig(:release)&.any? &&
|
||||
Gitlab::Ci::Features.release_generation_enabled?
|
||||
options.dig(:release)&.any?
|
||||
end
|
||||
|
||||
def hide_secrets(trace)
|
||||
|
|
|
@ -37,6 +37,12 @@ module AlertManagement
|
|||
MARKDOWN
|
||||
end
|
||||
|
||||
def runbook
|
||||
strong_memoize(:runbook) do
|
||||
payload&.dig('runbook')
|
||||
end
|
||||
end
|
||||
|
||||
def metrics_dashboard_url; end
|
||||
|
||||
private
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
module AlertManagement
|
||||
class PrometheusAlertPresenter < AlertManagement::AlertPresenter
|
||||
def runbook
|
||||
strong_memoize(:runbook) do
|
||||
payload&.dig('annotations', 'runbook')
|
||||
end
|
||||
end
|
||||
|
||||
def metrics_dashboard_url
|
||||
alerting_alert.metrics_dashboard_url
|
||||
end
|
||||
|
|
|
@ -34,7 +34,7 @@ module Metrics
|
|||
|
||||
# Returns an un-processed dashboard from the cache.
|
||||
def raw_dashboard
|
||||
Gitlab::Metrics::Dashboard::Cache.fetch(cache_key) { get_raw_dashboard }
|
||||
Gitlab::Metrics::Dashboard::Cache.for(project).fetch(cache_key) { get_raw_dashboard }
|
||||
end
|
||||
|
||||
# Should return true if this dashboard service is for an out-of-the-box
|
||||
|
|
|
@ -30,6 +30,11 @@ module Metrics
|
|||
end
|
||||
end
|
||||
|
||||
# Returns an un-processed dashboard from the cache.
|
||||
def raw_dashboard
|
||||
Gitlab::Metrics::Dashboard::Cache.fetch(cache_key) { get_raw_dashboard }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def dashboard_version
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Incident and Alert mobile CSS and alignment
|
||||
merge_request: 38577
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Expose board list issues via GraphQL
|
||||
merge_request: 36259
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Expose runbook field in alert_management_alert GraphQL API
|
||||
merge_request: 38510
|
||||
author:
|
||||
type: added
|
|
@ -294,6 +294,11 @@ type AlertManagementAlert implements Noteable {
|
|||
last: Int
|
||||
): NoteConnection!
|
||||
|
||||
"""
|
||||
Runbook for the alert as defined in alert details
|
||||
"""
|
||||
runbook: String
|
||||
|
||||
"""
|
||||
Service the alert came from
|
||||
"""
|
||||
|
@ -1087,6 +1092,31 @@ type BoardList {
|
|||
"""
|
||||
id: ID!
|
||||
|
||||
"""
|
||||
Board issues
|
||||
"""
|
||||
issues(
|
||||
"""
|
||||
Returns the elements in the list that come after the specified cursor.
|
||||
"""
|
||||
after: String
|
||||
|
||||
"""
|
||||
Returns the elements in the list that come before the specified cursor.
|
||||
"""
|
||||
before: String
|
||||
|
||||
"""
|
||||
Returns the first _n_ elements from the list.
|
||||
"""
|
||||
first: Int
|
||||
|
||||
"""
|
||||
Returns the last _n_ elements from the list.
|
||||
"""
|
||||
last: Int
|
||||
): IssueConnection
|
||||
|
||||
"""
|
||||
Label of the list
|
||||
"""
|
||||
|
|
|
@ -801,6 +801,20 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "runbook",
|
||||
"description": "Runbook for the alert as defined in alert details",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "service",
|
||||
"description": "Service the alert came from",
|
||||
|
@ -2927,6 +2941,59 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "issues",
|
||||
"description": "Board issues",
|
||||
"args": [
|
||||
{
|
||||
"name": "after",
|
||||
"description": "Returns the elements in the list that come after the specified cursor.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "before",
|
||||
"description": "Returns the elements in the list that come before the specified cursor.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "first",
|
||||
"description": "Returns the first _n_ elements from the list.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Int",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "last",
|
||||
"description": "Returns the last _n_ elements from the list.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Int",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "IssueConnection",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"description": "Label of the list",
|
||||
|
|
|
@ -71,6 +71,7 @@ Describes an alert from the project's Alert Management
|
|||
| `issueIid` | ID | Internal ID of the GitLab issue attached to the alert |
|
||||
| `metricsDashboardUrl` | String | URL for metrics embed for the alert |
|
||||
| `monitoringTool` | String | Monitoring tool the alert came from |
|
||||
| `runbook` | String | Runbook for the alert as defined in alert details |
|
||||
| `service` | String | Service the alert came from |
|
||||
| `severity` | AlertManagementSeverity | Severity of the alert |
|
||||
| `startedAt` | Time | Timestamp the alert was raised |
|
||||
|
|
|
@ -82,7 +82,7 @@ path to point to your ECR image.
|
|||
### Deploy your application to the AWS Elastic Container Service (ECS)
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207962) in GitLab 12.9.
|
||||
> - The `Deploy-ECS.gitlab-ci.yml` template was deprecated in favor of `AWS/Deploy-ECS.gitlab-ci.yml` template in GitLab 13.2.
|
||||
> - The `Deploy-ECS.gitlab-ci.yml` template was [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/220821) to `AWS/Deploy-ECS.gitlab-ci.yml` in GitLab 13.2.
|
||||
|
||||
GitLab provides a series of [CI templates that you can include in your project](../yaml/README.md#include).
|
||||
To automate deployments of your application to your [Amazon Elastic Container Service](https://aws.amazon.com/ecs/) (AWS ECS)
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
|
@ -90,15 +90,20 @@ When a link of a commit reference is found in a thread inside a merge
|
|||
request, it will be automatically converted to a link in the context of the
|
||||
current merge request.
|
||||
|
||||
### Jumping between unresolved threads
|
||||
### Jumping between unresolved threads (deprecated)
|
||||
|
||||
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/199718) in GitLab 13.3.
|
||||
> - This button's removal is behind a feature flag enabled by default.
|
||||
> - For GitLab self-managed instances, GitLab administrators with access to the
|
||||
[GitLab Rails console](../../administration/feature_flags.md) can opt to disable it by running
|
||||
`Feature.disable(:hide_jump_to_next_unresolved_in_threads)` (for the instance) or
|
||||
`Feature.disable(:hide_jump_to_next_unresolved_in_threads, Project.find(<project id>))`
|
||||
(per project.) **(CORE ONLY)**
|
||||
|
||||
When a merge request has a large number of comments it can be difficult to track
|
||||
what remains unresolved. You can jump between unresolved threads with the
|
||||
Jump button next to the Reply field on a thread.
|
||||
|
||||
You can also jump to the next unresolved thread from the button next to the
|
||||
resolved threads tracker.
|
||||
|
||||
You can also use keyboard shortcuts to navigate among threads:
|
||||
|
||||
- Use <kbd>n</kbd> to jump to the next unresolved thread.
|
||||
|
@ -111,7 +116,7 @@ You can also use keyboard shortcuts to navigate among threads:
|
|||
You can mark a thread as resolved by clicking the **Resolve thread**
|
||||
button at the bottom of the thread.
|
||||
|
||||
!["Resolve thread" button](img/resolve_thread_button.png)
|
||||
!["Resolve thread" button](img/resolve_thread_button_v13_3.png)
|
||||
|
||||
Alternatively, you can mark each comment as resolved individually.
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@ module Gitlab
|
|||
end
|
||||
|
||||
def from_release(job)
|
||||
return unless Gitlab::Ci::Features.release_generation_enabled?
|
||||
|
||||
release = job.options[:release]
|
||||
return unless release
|
||||
|
||||
|
|
|
@ -22,12 +22,6 @@ module Gitlab
|
|||
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
|
||||
validates :config, required_keys: REQUIRED_BY_NEEDS, if: :has_needs?
|
||||
validates :script, presence: true
|
||||
validates :config,
|
||||
disallowed_keys: {
|
||||
in: %i[release],
|
||||
message: 'release features are not enabled'
|
||||
},
|
||||
unless: -> { Gitlab::Ci::Features.release_generation_enabled? }
|
||||
|
||||
with_options allow_nil: true do
|
||||
validates :allow_failure, boolean: true
|
||||
|
|
|
@ -34,10 +34,6 @@ module Gitlab
|
|||
Feature.enabled?(:ci_pipeline_status_omit_commit_sha_in_cache_key, project, default_enabled: true)
|
||||
end
|
||||
|
||||
def self.release_generation_enabled?
|
||||
::Feature.enabled?(:ci_release_generation, default_enabled: true)
|
||||
end
|
||||
|
||||
# Remove in https://gitlab.com/gitlab-org/gitlab/-/issues/224199
|
||||
def self.store_pipeline_messages?(project)
|
||||
::Feature.enabled?(:ci_store_pipeline_messages, project, default_enabled: true)
|
||||
|
|
|
@ -115,7 +115,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def release(job)
|
||||
job[:release] if Gitlab::Ci::Features.release_generation_enabled?
|
||||
job[:release]
|
||||
end
|
||||
|
||||
def stage_builds_attributes(stage)
|
||||
|
|
|
@ -9,34 +9,53 @@ module Gitlab
|
|||
CACHE_KEYS = 'all_cached_metric_dashboards'
|
||||
|
||||
class << self
|
||||
# Stores a dashboard in the cache, documenting the key
|
||||
# so the cached can be cleared in bulk at another time.
|
||||
def fetch(key)
|
||||
register_key(key)
|
||||
# This class method (Gitlab::Metrics::Dashboard::Cache.fetch) can be used
|
||||
# when the key does not need to be deleted by `delete_all!`.
|
||||
# For example, out of the box dashboard caches do not need to be deleted.
|
||||
delegate :fetch, to: :"Rails.cache"
|
||||
|
||||
Rails.cache.fetch(key) { yield }
|
||||
end
|
||||
alias_method :for, :new
|
||||
end
|
||||
|
||||
# Resets all dashboard caches, such that all
|
||||
# dashboard content will be loaded from source on
|
||||
# subsequent dashboard calls.
|
||||
def delete_all!
|
||||
all_keys.each { |key| Rails.cache.delete(key) }
|
||||
def initialize(project)
|
||||
@project = project
|
||||
end
|
||||
|
||||
Rails.cache.delete(CACHE_KEYS)
|
||||
end
|
||||
# Stores a dashboard in the cache, documenting the key
|
||||
# so the cache can be cleared in bulk at another time.
|
||||
def fetch(key)
|
||||
register_key(key)
|
||||
|
||||
private
|
||||
Rails.cache.fetch(key) { yield }
|
||||
end
|
||||
|
||||
def register_key(key)
|
||||
new_keys = all_keys.add(key).to_a.join('|')
|
||||
# Resets all dashboard caches, such that all
|
||||
# dashboard content will be loaded from source on
|
||||
# subsequent dashboard calls.
|
||||
def delete_all!
|
||||
all_keys.each { |key| Rails.cache.delete(key) }
|
||||
|
||||
Rails.cache.write(CACHE_KEYS, new_keys)
|
||||
end
|
||||
Rails.cache.delete(catalog_key)
|
||||
end
|
||||
|
||||
def all_keys
|
||||
Set.new(Rails.cache.read(CACHE_KEYS)&.split('|'))
|
||||
end
|
||||
private
|
||||
|
||||
def register_key(key)
|
||||
new_keys = all_keys.add(key).to_a.join('|')
|
||||
|
||||
Rails.cache.write(catalog_key, new_keys)
|
||||
end
|
||||
|
||||
def all_keys
|
||||
keys = Rails.cache.read(catalog_key)&.split('|')
|
||||
Set.new(keys)
|
||||
end
|
||||
|
||||
# One key to store them all...
|
||||
# This key is used to store the names of all the keys that contain this
|
||||
# project's dashboards.
|
||||
def catalog_key
|
||||
"#{CACHE_KEYS}_#{@project.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ module Gitlab
|
|||
# Also deletes all dashboard cache entries.
|
||||
# @return [Array] ex) ['.gitlab/dashboards/dashboard1.yml']
|
||||
def list_dashboards(project)
|
||||
Gitlab::Metrics::Dashboard::Cache.delete_all!
|
||||
Gitlab::Metrics::Dashboard::Cache.for(project).delete_all!
|
||||
|
||||
file_finder(project).list_files_for(DASHBOARD_ROOT)
|
||||
end
|
||||
|
|
|
@ -10369,12 +10369,18 @@ msgstr ""
|
|||
msgid "FeatureFlags|Flag becomes read only soon"
|
||||
msgstr ""
|
||||
|
||||
msgid "FeatureFlags|Flag is read-only"
|
||||
msgstr ""
|
||||
|
||||
msgid "FeatureFlags|Get started with feature flags"
|
||||
msgstr ""
|
||||
|
||||
msgid "FeatureFlags|GitLab is moving to a new way of managing feature flags, and in 13.4, this feature flag will become read-only. Please create a new feature flag."
|
||||
msgstr ""
|
||||
|
||||
msgid "FeatureFlags|GitLab is moving to a new way of managing feature flags. This feature flag is read-only, and it will be removed in 14.0. Please create a new feature flag."
|
||||
msgstr ""
|
||||
|
||||
msgid "FeatureFlags|ID"
|
||||
msgstr ""
|
||||
|
||||
|
@ -21294,7 +21300,10 @@ msgstr ""
|
|||
msgid "SecurityConfiguration|Configure"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|Customize common SAST settings to suit your requirements. More advanced configuration options exist, which you can add to the configuration file this tool generates. It's important to note that if you make any configurations, they will be saved as overrides and will be excluded from automatic updates. We've provided guidance for some easily configurable variables below, but our docs go into even more depth. %{linkStart}Read more%{linkEnd}"
|
||||
msgid "SecurityConfiguration|Could not retrieve configuration data. Please refresh the page, or try again later."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|Customize common SAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{linkStart}GitLab SAST documentation%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|Enable via Merge Request"
|
||||
|
@ -21330,9 +21339,6 @@ msgstr ""
|
|||
msgid "SecurityConfiguration|Testing & Compliance"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|There was an error loading the configuration. Please reload the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Resolvers::BoardListIssuesResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:unauth_user) { create(:user) }
|
||||
let_it_be(:user_project) { create(:project, creator_id: user.id, namespace: user.namespace ) }
|
||||
let_it_be(:group) { create(:group, :private) }
|
||||
|
||||
shared_examples_for 'group and project board list issues resolver' do
|
||||
let!(:board) { create(:board, resource_parent: board_parent) }
|
||||
|
||||
before do
|
||||
board_parent.add_developer(user)
|
||||
end
|
||||
|
||||
# auth is handled by the parent object
|
||||
context 'when authorized' do
|
||||
let!(:list) { create(:list, board: board, label: label) }
|
||||
|
||||
it 'returns the issues in the correct order' do
|
||||
issue1 = create(:issue, project: project, labels: [label], relative_position: 10)
|
||||
issue2 = create(:issue, project: project, labels: [label], relative_position: 12)
|
||||
issue3 = create(:issue, project: project, labels: [label], relative_position: 10)
|
||||
|
||||
# by relative_position and then ID
|
||||
issues = resolve_board_list_issues.items
|
||||
|
||||
expect(issues.map(&:id)).to eq [issue3.id, issue1.id, issue2.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#resolve' do
|
||||
context 'when project boards' do
|
||||
let(:board_parent) { user_project }
|
||||
let!(:label) { create(:label, project: project, name: 'project label') }
|
||||
let(:project) { user_project }
|
||||
|
||||
it_behaves_like 'group and project board list issues resolver'
|
||||
end
|
||||
|
||||
context 'when group boards' do
|
||||
let(:board_parent) { group }
|
||||
let!(:label) { create(:group_label, group: group, name: 'group label') }
|
||||
let!(:project) { create(:project, :private, group: group) }
|
||||
|
||||
it_behaves_like 'group and project board list issues resolver'
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_board_list_issues(args: {}, current_user: user)
|
||||
resolve(described_class, obj: list, args: args, ctx: { current_user: current_user })
|
||||
end
|
||||
end
|
|
@ -28,6 +28,7 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
|
|||
notes
|
||||
discussions
|
||||
metrics_dashboard_url
|
||||
runbook
|
||||
todos
|
||||
]
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe GitlabSchema.types['BoardList'] do
|
|||
specify { expect(described_class.graphql_name).to eq('BoardList') }
|
||||
|
||||
it 'has specific fields' do
|
||||
expected_fields = %w[id list_type position label]
|
||||
expected_fields = %w[id list_type position label issues]
|
||||
|
||||
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||
end
|
||||
|
|
|
@ -1641,26 +1641,9 @@ module Gitlab
|
|||
}
|
||||
end
|
||||
|
||||
context 'with feature flag active' do
|
||||
before do
|
||||
stub_feature_flags(ci_release_generation: true)
|
||||
end
|
||||
|
||||
it "returns release info" do
|
||||
expect(processor.stage_builds_attributes('release').first[:options])
|
||||
.to eq(config[:release].except(:stage, :only))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with feature flag inactive' do
|
||||
before do
|
||||
stub_feature_flags(ci_release_generation: false)
|
||||
end
|
||||
|
||||
it 'raises error' do
|
||||
expect { processor }.to raise_error(
|
||||
'jobs:release config release features are not enabled: release')
|
||||
end
|
||||
it "returns release info" do
|
||||
expect(processor.stage_builds_attributes('release').first[:options])
|
||||
.to eq(config[:release].except(:stage, :only))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Metrics::Dashboard::Cache, :use_clean_rails_memory_store_caching do
|
||||
let_it_be(:project1) { build_stubbed(:project) }
|
||||
let_it_be(:project2) { build_stubbed(:project) }
|
||||
|
||||
let(:project1_key1) { "#{project1.id}_key1" }
|
||||
let(:project1_key2) { "#{project1.id}_key2" }
|
||||
let(:project2_key1) { "#{project2.id}_key1" }
|
||||
|
||||
let(:cache1) { described_class.for(project1) }
|
||||
let(:cache2) { described_class.for(project2) }
|
||||
|
||||
before do
|
||||
cache1.fetch(project1_key1) { 'data1' }
|
||||
cache1.fetch(project1_key2) { 'data2' }
|
||||
cache2.fetch(project2_key1) { 'data3' }
|
||||
end
|
||||
|
||||
describe '.fetch' do
|
||||
it 'stores data correctly' do
|
||||
described_class.fetch('key1') { 'data1' }
|
||||
described_class.fetch('key2') { 'data2' }
|
||||
|
||||
expect(described_class.fetch('key1')).to eq('data1')
|
||||
expect(described_class.fetch('key2')).to eq('data2')
|
||||
end
|
||||
end
|
||||
|
||||
describe '.for' do
|
||||
it 'returns a new instance' do
|
||||
expect(described_class.for(project1)).to be_instance_of(described_class)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fetch' do
|
||||
it 'stores data correctly' do
|
||||
expect(cache1.fetch(project1_key1)).to eq('data1')
|
||||
expect(cache1.fetch(project1_key2)).to eq('data2')
|
||||
expect(cache2.fetch(project2_key1)).to eq('data3')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete_all!' do
|
||||
it 'deletes keys of the given project', :aggregate_failures do
|
||||
cache1.delete_all!
|
||||
|
||||
expect(Rails.cache.exist?(project1_key1)).to be(false)
|
||||
expect(Rails.cache.exist?(project1_key2)).to be(false)
|
||||
expect(cache2.fetch(project2_key1)).to eq('data3')
|
||||
|
||||
cache2.delete_all!
|
||||
|
||||
expect(Rails.cache.exist?(project2_key1)).to be(false)
|
||||
end
|
||||
|
||||
it 'does not fail when nothing to delete' do
|
||||
project3 = build_stubbed(:project)
|
||||
cache3 = described_class.for(project3)
|
||||
|
||||
expect { cache3.delete_all! }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'multiple fetches and deletes' do
|
||||
specify :aggregate_failures do
|
||||
cache1.delete_all!
|
||||
|
||||
expect(Rails.cache.exist?(project1_key1)).to be(false)
|
||||
expect(Rails.cache.exist?(project1_key2)).to be(false)
|
||||
|
||||
cache1.fetch("#{project1.id}_key3") { 'data1' }
|
||||
cache1.fetch("#{project1.id}_key4") { 'data2' }
|
||||
|
||||
expect(cache1.fetch("#{project1.id}_key3")).to eq('data1')
|
||||
expect(cache1.fetch("#{project1.id}_key4")).to eq('data2')
|
||||
|
||||
cache1.delete_all!
|
||||
|
||||
expect(Rails.cache.exist?("#{project1.id}_key3")).to be(false)
|
||||
expect(Rails.cache.exist?("#{project1.id}_key4")).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,7 +9,10 @@ RSpec.describe Gitlab::Metrics::Dashboard::RepoDashboardFinder do
|
|||
|
||||
describe '.list_dashboards' do
|
||||
it 'deletes dashboard cache entries' do
|
||||
expect(Gitlab::Metrics::Dashboard::Cache).to receive(:delete_all!).and_call_original
|
||||
cache = instance_double(Gitlab::Metrics::Dashboard::Cache)
|
||||
allow(Gitlab::Metrics::Dashboard::Cache).to receive(:for).and_return(cache)
|
||||
|
||||
expect(cache).to receive(:delete_all!)
|
||||
|
||||
described_class.list_dashboards(project)
|
||||
end
|
||||
|
|
|
@ -8,11 +8,12 @@ RSpec.describe AlertManagement::AlertPresenter do
|
|||
{
|
||||
'title' => 'Alert title',
|
||||
'start_time' => '2020-04-27T10:10:22.265949279Z',
|
||||
'custom' => { 'param' => 73 }
|
||||
'custom' => { 'param' => 73 },
|
||||
'runbook' => 'https://runbook.com'
|
||||
}
|
||||
end
|
||||
let_it_be(:alert) do
|
||||
create(:alert_management_alert, :with_description, :with_host, :with_service, :with_monitoring_tool, project: project, payload: generic_payload)
|
||||
build(:alert_management_alert, :with_description, :with_host, :with_service, :with_monitoring_tool, project: project, payload: generic_payload)
|
||||
end
|
||||
|
||||
subject(:presenter) { described_class.new(alert) }
|
||||
|
@ -34,7 +35,8 @@ RSpec.describe AlertManagement::AlertPresenter do
|
|||
|
||||
#### Alert Details
|
||||
|
||||
**custom.param:** 73
|
||||
**custom.param:** 73#{markdown_line_break}
|
||||
**runbook:** https://runbook.com
|
||||
MARKDOWN
|
||||
)
|
||||
end
|
||||
|
@ -45,4 +47,10 @@ RSpec.describe AlertManagement::AlertPresenter do
|
|||
expect(presenter.metrics_dashboard_url).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#runbook' do
|
||||
it 'shows the runbook from the payload' do
|
||||
expect(presenter.runbook).to eq('https://runbook.com')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe AlertManagement::PrometheusAlertPresenter do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:payload) do
|
||||
let(:payload) do
|
||||
{
|
||||
'annotations' => {
|
||||
'title' => 'Alert title',
|
||||
|
@ -15,6 +15,7 @@ RSpec.describe AlertManagement::PrometheusAlertPresenter do
|
|||
'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1'
|
||||
}
|
||||
end
|
||||
|
||||
let(:alert) do
|
||||
create(:alert_management_alert, :prometheus, project: project, payload: payload)
|
||||
end
|
||||
|
@ -65,4 +66,17 @@ RSpec.describe AlertManagement::PrometheusAlertPresenter do
|
|||
it { is_expected.to eq(dashboard_url_for_alert) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#runbook' do
|
||||
subject { presenter.runbook }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
|
||||
context 'with runbook in payload' do
|
||||
let(:expected_runbook) { 'https://awesome-runbook.com' }
|
||||
let(:payload) { { 'annotations' => { 'runbook' => expected_runbook } } }
|
||||
|
||||
it { is_expected.to eq(expected_runbook) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'get board lists' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:unauth_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace ) }
|
||||
let_it_be(:group) { create(:group, :private) }
|
||||
let_it_be(:project_label) { create(:label, project: project, name: 'Development') }
|
||||
let_it_be(:project_label2) { create(:label, project: project, name: 'Testing') }
|
||||
let_it_be(:group_label) { create(:group_label, group: group, name: 'Development') }
|
||||
let_it_be(:group_label2) { create(:group_label, group: group, name: 'Testing') }
|
||||
|
||||
let(:params) { '' }
|
||||
let(:board) { }
|
||||
let(:board_parent_type) { board_parent.class.to_s.downcase }
|
||||
let(:board_data) { graphql_data[board_parent_type]['boards']['nodes'][0] }
|
||||
let(:lists_data) { board_data['lists']['nodes'][0] }
|
||||
let(:issues_data) { lists_data['issues']['nodes'] }
|
||||
|
||||
def query(list_params = params)
|
||||
graphql_query_for(
|
||||
board_parent_type,
|
||||
{ 'fullPath' => board_parent.full_path },
|
||||
<<~BOARDS
|
||||
boards(first: 1) {
|
||||
nodes {
|
||||
lists {
|
||||
nodes {
|
||||
issues {
|
||||
count
|
||||
nodes {
|
||||
#{all_graphql_fields_for('issues'.classify)}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BOARDS
|
||||
)
|
||||
end
|
||||
|
||||
def issue_titles
|
||||
issues_data.map { |i| i['title'] }
|
||||
end
|
||||
|
||||
shared_examples 'group and project board list issues query' do
|
||||
let!(:board) { create(:board, resource_parent: board_parent) }
|
||||
let!(:label_list) { create(:list, board: board, label: label, position: 10) }
|
||||
let!(:issue1) { create(:issue, project: issue_project, labels: [label], relative_position: 9) }
|
||||
let!(:issue2) { create(:issue, project: issue_project, labels: [label], relative_position: 2) }
|
||||
let!(:issue3) { create(:issue, project: issue_project, labels: [label], relative_position: 9) }
|
||||
let!(:issue4) { create(:issue, project: issue_project, labels: [label2], relative_position: 432) }
|
||||
|
||||
context 'when the user does not have access to the board' do
|
||||
it 'returns nil' do
|
||||
post_graphql(query, current_user: unauth_user)
|
||||
|
||||
expect(graphql_data[board_parent_type]).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user can read the board' do
|
||||
before do
|
||||
board_parent.add_reporter(user)
|
||||
end
|
||||
|
||||
it 'can access the issues' do
|
||||
post_graphql(query("id: \"#{global_id_of(label_list)}\""), current_user: user)
|
||||
|
||||
expect(issue_titles).to eq([issue2.title, issue3.title, issue1.title])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'for a project' do
|
||||
let(:board_parent) { project }
|
||||
let(:label) { project_label }
|
||||
let(:label2) { project_label2 }
|
||||
let(:issue_project) { project }
|
||||
|
||||
it_behaves_like 'group and project board list issues query'
|
||||
end
|
||||
|
||||
describe 'for a group' do
|
||||
let(:board_parent) { group }
|
||||
let(:label) { group_label }
|
||||
let(:label2) { group_label2 }
|
||||
let(:issue_project) { create(:project, :private, group: group) }
|
||||
|
||||
before do
|
||||
allow(board_parent).to receive(:multiple_issue_boards_available?).and_return(false)
|
||||
end
|
||||
|
||||
it_behaves_like 'group and project board list issues query'
|
||||
end
|
||||
end
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
RSpec.describe 'getting Alert Management Alerts' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:payload) { { 'custom' => { 'alert' => 'payload' } } }
|
||||
let_it_be(:payload) { { 'custom' => { 'alert' => 'payload' }, 'runbook' => 'runbook' } }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:resolved_alert) { create(:alert_management_alert, :all_fields, :resolved, project: project, issue: nil, severity: :low) }
|
||||
|
@ -71,10 +71,11 @@ RSpec.describe 'getting Alert Management Alerts' do
|
|||
'eventCount' => triggered_alert.events,
|
||||
'startedAt' => triggered_alert.started_at.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
||||
'endedAt' => nil,
|
||||
'details' => { 'custom.alert' => 'payload' },
|
||||
'details' => { 'custom.alert' => 'payload', 'runbook' => 'runbook' },
|
||||
'createdAt' => triggered_alert.created_at.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
||||
'updatedAt' => triggered_alert.updated_at.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
||||
'metricsDashboardUrl' => nil
|
||||
'metricsDashboardUrl' => nil,
|
||||
'runbook' => 'runbook'
|
||||
)
|
||||
|
||||
expect(second_alert).to include(
|
||||
|
|
|
@ -982,7 +982,6 @@ RSpec.describe Ci::CreatePipelineService do
|
|||
context 'with release' do
|
||||
shared_examples_for 'a successful release pipeline' do
|
||||
before do
|
||||
stub_feature_flags(ci_release_generation: true)
|
||||
stub_ci_pipeline_yaml_file(YAML.dump(config))
|
||||
end
|
||||
|
||||
|
|
|
@ -111,7 +111,8 @@ RSpec.describe Metrics::Dashboard::CustomMetricEmbedService do
|
|||
it_behaves_like 'valid embedded dashboard service response'
|
||||
|
||||
it 'does not cache the unprocessed dashboard' do
|
||||
expect(Gitlab::Metrics::Dashboard::Cache).not_to receive(:fetch)
|
||||
# Fail spec if any method of Cache class is called.
|
||||
stub_const('Gitlab::Metrics::Dashboard::Cache', double)
|
||||
|
||||
described_class.new(*service_params).get_dashboard
|
||||
end
|
||||
|
|
|
@ -87,7 +87,8 @@ RSpec.describe Metrics::Dashboard::GitlabAlertEmbedService do
|
|||
end
|
||||
|
||||
it 'does not cache the unprocessed dashboard' do
|
||||
expect(Gitlab::Metrics::Dashboard::Cache).not_to receive(:fetch)
|
||||
# Fail spec if any method of Cache class is called.
|
||||
stub_const('Gitlab::Metrics::Dashboard::Cache', double)
|
||||
|
||||
described_class.new(*service_params).get_dashboard
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue