Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c64b892786
commit
325318e2dd
|
@ -324,6 +324,12 @@ export default {
|
|||
</div>
|
||||
<div class="gl-pl-2" data-testid="service">{{ alert.service }}</div>
|
||||
</div>
|
||||
<div v-if="alert.runbook" class="gl-my-5 gl-display-flex">
|
||||
<div class="bold gl-w-13 gl-text-right gl-pr-3">
|
||||
{{ s__('AlertManagement|Runbook') }}:
|
||||
</div>
|
||||
<div class="gl-pl-2" data-testid="runbook">{{ alert.runbook }}</div>
|
||||
</div>
|
||||
<template>
|
||||
<div v-if="alert.notes.nodes" class="issuable-discussion py-5">
|
||||
<ul class="notes main-notes-list timeline">
|
||||
|
|
|
@ -11,6 +11,7 @@ fragment AlertDetailItem on AlertManagementAlert {
|
|||
updatedAt
|
||||
endedAt
|
||||
details
|
||||
runbook
|
||||
todos {
|
||||
nodes {
|
||||
id
|
||||
|
|
|
@ -93,10 +93,6 @@ const createPipelineHeaderApp = mediator => {
|
|||
};
|
||||
|
||||
const createTestDetails = () => {
|
||||
if (!window.gon?.features?.junitPipelineView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const el = document.querySelector('#js-pipeline-tests-detail');
|
||||
const { summaryEndpoint, suiteEndpoint } = el?.dataset || {};
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ export default {
|
|||
return `${this.pipelinePath}/test_report`;
|
||||
},
|
||||
showViewFullReport() {
|
||||
return Boolean(this.glFeatures.junitPipelineView) && this.pipelinePath.length;
|
||||
return this.pipelinePath.length;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
@ -116,6 +116,7 @@ export default {
|
|||
<template v-if="showViewFullReport" #actionButtons>
|
||||
<gl-button
|
||||
:href="testTabURL"
|
||||
target="_blank"
|
||||
icon="external-link"
|
||||
data-testid="group-test-reports-full-link"
|
||||
class="gl-mr-3"
|
||||
|
|
|
@ -43,7 +43,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:vue_issuable_sidebar, @project.group)
|
||||
push_frontend_feature_flag(:junit_pipeline_view, @project.group)
|
||||
end
|
||||
|
||||
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions]
|
||||
|
|
|
@ -12,7 +12,6 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
before_action :authorize_create_pipeline!, only: [:new, :create]
|
||||
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
|
||||
before_action do
|
||||
push_frontend_feature_flag(:junit_pipeline_view, project)
|
||||
push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true)
|
||||
push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true)
|
||||
push_frontend_feature_flag(:pipelines_security_report_summary, project)
|
||||
|
@ -177,8 +176,6 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def test_report
|
||||
return unless Feature.enabled?(:junit_pipeline_view, project)
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render 'show'
|
||||
|
|
|
@ -17,7 +17,7 @@ module HasWiki
|
|||
|
||||
def wiki
|
||||
strong_memoize(:wiki) do
|
||||
Wiki.for_container(self, self.owner)
|
||||
Wiki.for_container(self, self.default_owner)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -563,6 +563,10 @@ class Group < Namespace
|
|||
all_projects.update_all(shared_runners_enabled: false)
|
||||
end
|
||||
|
||||
def default_owner
|
||||
owners.first || parent&.default_owner || owner
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_two_factor_requirement
|
||||
|
|
|
@ -1395,6 +1395,16 @@ class Project < ApplicationRecord
|
|||
group || namespace.try(:owner)
|
||||
end
|
||||
|
||||
def default_owner
|
||||
obj = owner
|
||||
|
||||
if obj.respond_to?(:default_owner)
|
||||
obj.default_owner
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
def to_ability_name
|
||||
model_name.singular
|
||||
end
|
||||
|
|
|
@ -35,6 +35,7 @@ class Wiki
|
|||
def initialize(container, user = nil)
|
||||
@container = container
|
||||
@user = user
|
||||
raise ArgumentError, "user must be a User, got #{user.class}" if user && !user.is_a?(User)
|
||||
end
|
||||
|
||||
def path
|
||||
|
|
|
@ -96,12 +96,12 @@ module AlertManagement
|
|||
end
|
||||
|
||||
def handle_assignement(old_assignees)
|
||||
assign_todo
|
||||
assign_todo(old_assignees)
|
||||
add_assignee_system_note(old_assignees)
|
||||
end
|
||||
|
||||
def assign_todo
|
||||
todo_service.assign_alert(alert, current_user)
|
||||
def assign_todo(old_assignees)
|
||||
todo_service.reassigned_assignable(alert, current_user, old_assignees)
|
||||
end
|
||||
|
||||
def add_assignee_system_note(old_assignees)
|
||||
|
|
|
@ -109,7 +109,7 @@ class EventCreateService
|
|||
def wiki_event(wiki_page_meta, author, action, fingerprint)
|
||||
raise IllegalActionError, action unless Event::WIKI_ACTIONS.include?(action)
|
||||
|
||||
Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: action, event_target: wiki_page_meta.class, author_id: author.id)
|
||||
Gitlab::UsageDataCounters::TrackUniqueActions.track_event(event_action: action, event_target: wiki_page_meta.class, author_id: author.id)
|
||||
|
||||
duplicate = Event.for_wiki_meta(wiki_page_meta).for_fingerprint(fingerprint).first
|
||||
return duplicate if duplicate.present?
|
||||
|
@ -154,7 +154,7 @@ class EventCreateService
|
|||
result = Event.insert_all(attribute_sets, returning: %w[id])
|
||||
|
||||
tuples.each do |record, status, _|
|
||||
Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: status, event_target: record.class, author_id: current_user.id)
|
||||
Gitlab::UsageDataCounters::TrackUniqueActions.track_event(event_action: status, event_target: record.class, author_id: current_user.id)
|
||||
end
|
||||
|
||||
result
|
||||
|
@ -172,7 +172,7 @@ class EventCreateService
|
|||
new_event
|
||||
end
|
||||
|
||||
Gitlab::UsageDataCounters::TrackUniqueActions.track_action(event_action: :pushed, event_target: Project, author_id: current_user.id)
|
||||
Gitlab::UsageDataCounters::TrackUniqueActions.track_event(event_action: :pushed, event_target: Project, author_id: current_user.id)
|
||||
|
||||
Users::LastPushEventService.new(current_user)
|
||||
.cache_last_push_event(event)
|
||||
|
|
|
@ -43,7 +43,7 @@ module Issues
|
|||
if issue.assignees != old_assignees
|
||||
create_assignee_note(issue, old_assignees)
|
||||
notification_service.async.reassigned_issue(issue, current_user, old_assignees)
|
||||
todo_service.reassigned_issuable(issue, current_user, old_assignees)
|
||||
todo_service.reassigned_assignable(issue, current_user, old_assignees)
|
||||
end
|
||||
|
||||
if issue.previous_changes.include?('confidential')
|
||||
|
|
|
@ -105,7 +105,7 @@ module MergeRequests
|
|||
def handle_assignees_change(merge_request, old_assignees)
|
||||
create_assignee_note(merge_request, old_assignees)
|
||||
notification_service.async.reassigned_merge_request(merge_request, current_user, old_assignees)
|
||||
todo_service.reassigned_issuable(merge_request, current_user, old_assignees)
|
||||
todo_service.reassigned_assignable(merge_request, current_user, old_assignees)
|
||||
end
|
||||
|
||||
def create_branch_change_note(issuable, branch_type, old_branch, new_branch)
|
||||
|
|
|
@ -32,6 +32,8 @@ module ResourceAccessTokens
|
|||
attr_reader :resource_type, :resource
|
||||
|
||||
def feature_enabled?
|
||||
return false if ::Gitlab.com?
|
||||
|
||||
::Feature.enabled?(:resource_access_token, resource, default_enabled: true)
|
||||
end
|
||||
|
||||
|
|
|
@ -49,11 +49,11 @@ class TodoService
|
|||
todo_users.each(&:update_todos_count_cache)
|
||||
end
|
||||
|
||||
# When we reassign an issuable we should:
|
||||
# When we reassign an assignable object (issuable, alert) we should:
|
||||
#
|
||||
# * create a pending todo for new assignee if issuable is assigned
|
||||
# * create a pending todo for new assignee if object is assigned
|
||||
#
|
||||
def reassigned_issuable(issuable, current_user, old_assignees = [])
|
||||
def reassigned_assignable(issuable, current_user, old_assignees = [])
|
||||
create_assignment_todo(issuable, current_user, old_assignees)
|
||||
end
|
||||
|
||||
|
@ -154,14 +154,6 @@ class TodoService
|
|||
resolve_todos_for_target(awardable, current_user)
|
||||
end
|
||||
|
||||
# When assigning an alert we should:
|
||||
#
|
||||
# * create a pending todo for new assignee if alert is assigned
|
||||
#
|
||||
def assign_alert(alert, current_user)
|
||||
create_assignment_todo(alert, current_user, [])
|
||||
end
|
||||
|
||||
# When user marks a target as todo
|
||||
def mark_todo(target, current_user)
|
||||
attributes = attributes_for_todo(target.project, target, current_user, Todo::MARKED)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
- return if pipeline_has_errors
|
||||
- test_reports_enabled = Feature.enabled?(:junit_pipeline_view, @project)
|
||||
- dag_pipeline_tab_enabled = Feature.enabled?(:dag_pipeline_tab, @project, default_enabled: true)
|
||||
|
||||
.tabs-holder
|
||||
|
@ -20,11 +19,10 @@
|
|||
= link_to failures_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-failures', action: 'failures', toggle: 'tab' }, class: 'failures-tab' do
|
||||
= _('Failed Jobs')
|
||||
%span.badge.badge-pill.js-failures-counter= @pipeline.failed_builds.count
|
||||
- if test_reports_enabled
|
||||
%li.js-tests-tab-link
|
||||
= link_to test_report_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-tests', action: 'test_report', toggle: 'tab' }, class: 'test-tab' do
|
||||
= s_('TestReports|Tests')
|
||||
%span.badge.badge-pill.js-test-report-badge-counter= @pipeline.test_report_summary.total[:count]
|
||||
%li.js-tests-tab-link
|
||||
= link_to test_report_project_pipeline_path(@project, @pipeline), data: { target: '#js-tab-tests', action: 'test_report', toggle: 'tab' }, class: 'test-tab' do
|
||||
= s_('TestReports|Tests')
|
||||
%span.badge.badge-pill.js-test-report-badge-counter= @pipeline.test_report_summary.total[:count]
|
||||
= render_if_exists "projects/pipelines/tabs_holder", pipeline: @pipeline, project: @project
|
||||
|
||||
.tab-content
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
= page_title
|
||||
%p
|
||||
= _('You can generate an access token scoped to this project for each application to use the GitLab API.')
|
||||
%p
|
||||
= _('You can also use project access tokens to authenticate against Git over HTTP.')
|
||||
-# Commented out until https://gitlab.com/gitlab-org/gitlab/-/issues/219551 is fixed
|
||||
-# %p
|
||||
-# = _('You can also use project access tokens to authenticate against Git over HTTP.')
|
||||
|
||||
.col-lg-8
|
||||
- if @new_project_access_token
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: JUnit test report on pipeline detail page
|
||||
merge_request: 39260
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Make View full report button open link in new tab
|
||||
merge_request: 39501
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Show runbook for alert in detail view
|
||||
merge_request: 39477
|
||||
author:
|
||||
type: added
|
|
@ -575,6 +575,9 @@ Gitlab.ee do
|
|||
Settings.cron_jobs['elastic_cluster_reindexing_cron_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['elastic_cluster_reindexing_cron_worker']['cron'] ||= '*/10 * * * *'
|
||||
Settings.cron_jobs['elastic_cluster_reindexing_cron_worker']['job_class'] ||= 'ElasticClusterReindexingCronWorker'
|
||||
Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker']['cron'] ||= '10 3 * * *'
|
||||
Settings.cron_jobs['elastic_remove_expired_namespace_subscriptions_from_index_cron_worker']['job_class'] ||= 'ElasticRemoveExpiredNamespaceSubscriptionsFromIndexCronWorker'
|
||||
Settings.cron_jobs['sync_seat_link_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 0 * * *"
|
||||
Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker'
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexOnEndDateAndNamespaceIdToGitlabSubscriptions < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index :gitlab_subscriptions, [:end_date, :namespace_id]
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index :gitlab_subscriptions, [:end_date, :namespace_id]
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
432ef9d45c8242ab8db954ceeb6a68a75ef46181dd868a30d68fef0ed6058caf
|
|
@ -19710,6 +19710,8 @@ CREATE INDEX index_geo_upload_deleted_events_on_upload_id ON public.geo_upload_d
|
|||
|
||||
CREATE INDEX index_gitlab_subscription_histories_on_gitlab_subscription_id ON public.gitlab_subscription_histories USING btree (gitlab_subscription_id);
|
||||
|
||||
CREATE INDEX index_gitlab_subscriptions_on_end_date_and_namespace_id ON public.gitlab_subscriptions USING btree (end_date, namespace_id);
|
||||
|
||||
CREATE INDEX index_gitlab_subscriptions_on_hosted_plan_id ON public.gitlab_subscriptions USING btree (hosted_plan_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_gitlab_subscriptions_on_namespace_id ON public.gitlab_subscriptions USING btree (namespace_id);
|
||||
|
|
|
@ -103,10 +103,10 @@ Some feature flags can be enabled or disabled on a per project basis:
|
|||
Feature.enable(:<feature flag>, Project.find(<project id>))
|
||||
```
|
||||
|
||||
For example, to enable the [`:junit_pipeline_view`](../ci/junit_test_reports.md#enabling-the-junit-test-reports-feature-core-only) feature flag for project `1234`:
|
||||
For example, to enable the [`:product_analytics`](../operations/product_analytics.md#enable-or-disable-product-analytics) feature flag for project `1234`:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:junit_pipeline_view, Project.find(1234))
|
||||
Feature.enable(:product_analytics, Project.find(1234))
|
||||
```
|
||||
|
||||
`Feature.enable` and `Feature.disable` always return `nil`, this is not an indication that the command failed:
|
||||
|
|
|
@ -1135,42 +1135,47 @@ type BoardEdge {
|
|||
|
||||
input BoardEpicIssueInput {
|
||||
"""
|
||||
Username of a user assigned to issues
|
||||
Filter by assignee username
|
||||
"""
|
||||
assigneeUsername: [String]
|
||||
|
||||
"""
|
||||
Username of the issues author
|
||||
Filter by author username
|
||||
"""
|
||||
authorUsername: String
|
||||
|
||||
"""
|
||||
Epic ID applied to issues
|
||||
Filter by epic ID
|
||||
"""
|
||||
epicId: String
|
||||
|
||||
"""
|
||||
Label applied to issues
|
||||
Filter by label name
|
||||
"""
|
||||
labelName: [String]
|
||||
|
||||
"""
|
||||
Milestone applied to issues
|
||||
Filter by milestone title
|
||||
"""
|
||||
milestoneTitle: String
|
||||
|
||||
"""
|
||||
Reaction emoji applied to issues
|
||||
Filter by reaction emoji
|
||||
"""
|
||||
myReactionEmoji: String
|
||||
|
||||
"""
|
||||
Release applied to issues
|
||||
List of negated params. Warning: this argument is experimental and a subject to change in future
|
||||
"""
|
||||
not: NegatedBoardEpicIssueInput
|
||||
|
||||
"""
|
||||
Filter by release tag
|
||||
"""
|
||||
releaseTag: String
|
||||
|
||||
"""
|
||||
Weight applied to issues
|
||||
Filter by weight
|
||||
"""
|
||||
weight: String
|
||||
}
|
||||
|
@ -9795,6 +9800,48 @@ type NamespaceIncreaseStorageTemporarilyPayload {
|
|||
namespace: Namespace
|
||||
}
|
||||
|
||||
input NegatedBoardEpicIssueInput {
|
||||
"""
|
||||
Filter by assignee username
|
||||
"""
|
||||
assigneeUsername: [String]
|
||||
|
||||
"""
|
||||
Filter by author username
|
||||
"""
|
||||
authorUsername: String
|
||||
|
||||
"""
|
||||
Filter by epic ID
|
||||
"""
|
||||
epicId: String
|
||||
|
||||
"""
|
||||
Filter by label name
|
||||
"""
|
||||
labelName: [String]
|
||||
|
||||
"""
|
||||
Filter by milestone title
|
||||
"""
|
||||
milestoneTitle: String
|
||||
|
||||
"""
|
||||
Filter by reaction emoji
|
||||
"""
|
||||
myReactionEmoji: String
|
||||
|
||||
"""
|
||||
Filter by release tag
|
||||
"""
|
||||
releaseTag: String
|
||||
|
||||
"""
|
||||
Filter by weight
|
||||
"""
|
||||
weight: String
|
||||
}
|
||||
|
||||
type Note implements ResolvableInterface {
|
||||
"""
|
||||
User who wrote this note
|
||||
|
|
|
@ -3049,7 +3049,7 @@
|
|||
"inputFields": [
|
||||
{
|
||||
"name": "labelName",
|
||||
"description": "Label applied to issues",
|
||||
"description": "Filter by label name",
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
|
@ -3063,7 +3063,7 @@
|
|||
},
|
||||
{
|
||||
"name": "milestoneTitle",
|
||||
"description": "Milestone applied to issues",
|
||||
"description": "Filter by milestone title",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
|
@ -3073,7 +3073,7 @@
|
|||
},
|
||||
{
|
||||
"name": "assigneeUsername",
|
||||
"description": "Username of a user assigned to issues",
|
||||
"description": "Filter by assignee username",
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
|
@ -3087,7 +3087,7 @@
|
|||
},
|
||||
{
|
||||
"name": "authorUsername",
|
||||
"description": "Username of the issues author",
|
||||
"description": "Filter by author username",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
|
@ -3097,7 +3097,7 @@
|
|||
},
|
||||
{
|
||||
"name": "releaseTag",
|
||||
"description": "Release applied to issues",
|
||||
"description": "Filter by release tag",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
|
@ -3107,7 +3107,7 @@
|
|||
},
|
||||
{
|
||||
"name": "epicId",
|
||||
"description": "Epic ID applied to issues",
|
||||
"description": "Filter by epic ID",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
|
@ -3117,7 +3117,7 @@
|
|||
},
|
||||
{
|
||||
"name": "myReactionEmoji",
|
||||
"description": "Reaction emoji applied to issues",
|
||||
"description": "Filter by reaction emoji",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
|
@ -3127,13 +3127,23 @@
|
|||
},
|
||||
{
|
||||
"name": "weight",
|
||||
"description": "Weight applied to issues",
|
||||
"description": "Filter by weight",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "not",
|
||||
"description": "List of negated params. Warning: this argument is experimental and a subject to change in future",
|
||||
"type": {
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "NegatedBoardEpicIssueInput",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
|
@ -29245,6 +29255,105 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "NegatedBoardEpicIssueInput",
|
||||
"description": null,
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "labelName",
|
||||
"description": "Filter by label name",
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "milestoneTitle",
|
||||
"description": "Filter by milestone title",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "assigneeUsername",
|
||||
"description": "Filter by assignee username",
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "authorUsername",
|
||||
"description": "Filter by author username",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "releaseTag",
|
||||
"description": "Filter by release tag",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "epicId",
|
||||
"description": "Filter by epic ID",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "myReactionEmoji",
|
||||
"description": "Filter by reaction emoji",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "weight",
|
||||
"description": "Filter by weight",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "Note",
|
||||
|
|
|
@ -239,9 +239,8 @@ Test:
|
|||
|
||||
## Viewing JUnit test reports on GitLab
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24792) in GitLab 12.5.
|
||||
> - It's deployed behind a feature flag, disabled by default.
|
||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enabling-the-junit-test-reports-feature-core-only). **(CORE ONLY)**
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24792) in GitLab 12.5 behind a feature flag (`junit_pipeline_view`), disabled by default.
|
||||
> - The feature flag was removed and the feature was [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/216478) in GitLab 13.3.
|
||||
|
||||
If JUnit XML files are generated and uploaded as part of a pipeline, these reports
|
||||
can be viewed inside the pipelines details page. The **Tests** tab on this page will
|
||||
|
@ -254,22 +253,6 @@ details, including the cases that make up the suite.
|
|||
|
||||
You can also retrieve the reports via the [GitLab API](../api/pipelines.md#get-a-pipelines-test-report).
|
||||
|
||||
### Enabling the JUnit test reports feature **(CORE ONLY)**
|
||||
|
||||
This feature comes with the `:junit_pipeline_view` feature flag disabled by default. This
|
||||
feature is disabled due to some performance issues with very large data sets.
|
||||
When [the performance is improved](https://gitlab.com/groups/gitlab-org/-/epics/2854), the feature will be enabled by default.
|
||||
|
||||
To enable this feature, ask a GitLab administrator with [Rails console access](../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags) to run the
|
||||
following command:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:junit_pipeline_view)
|
||||
|
||||
# Enable the feature for a specific project, GitLab 13.0 and above only.
|
||||
Feature.enable(:junit_pipeline_view, Project.find(<your-project-id-here>))
|
||||
```
|
||||
|
||||
## Viewing JUnit screenshots on GitLab
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202114) in GitLab 13.0.
|
||||
|
|
|
@ -5,20 +5,20 @@ info: "To determine the technical writer assigned to the Stage/Group associated
|
|||
type: reference, howto
|
||||
---
|
||||
|
||||
# Project access tokens (Alpha) **(CORE ONLY)**
|
||||
|
||||
CAUTION: **Warning:**
|
||||
This is an [Alpha](https://about.gitlab.com/handbook/product/#alpha) feature, and it is subject to change at any time without
|
||||
prior notice.
|
||||
# Project access tokens **(CORE ONLY)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2587) in GitLab 13.0.
|
||||
> - It's deployed behind a feature flag, disabled by default.
|
||||
> - It was [deployed](https://gitlab.com/groups/gitlab-org/-/epics/2587) behind a feature flag, disabled by default.
|
||||
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/218722) in GitLab 13.3.
|
||||
> - It's disabled on GitLab.com.
|
||||
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-project-access-tokens).
|
||||
> - It can be enabled or disabled by project.
|
||||
> - It's recommended for production use.
|
||||
> - For GitLab self-managed instances, GitLab administrators can [disable it](#enable-or-disable-project-access-tokens).
|
||||
|
||||
Project access tokens are scoped to a project and can be used to authenticate with the [GitLab API](../../../api/README.md#personalproject-access-tokens).
|
||||
|
||||
You can also use project access tokens with Git to authenticate over HTTP or SSH.
|
||||
<!-- Commented out until https://gitlab.com/gitlab-org/gitlab/-/issues/219551 is fixed -->
|
||||
<!-- You can also use project access tokens with Git to authenticate over HTTP or SSH. -->
|
||||
|
||||
Project access tokens expire on the date you define, at midnight UTC.
|
||||
|
||||
|
@ -78,19 +78,30 @@ the following table.
|
|||
|
||||
### Enable or disable project access tokens
|
||||
|
||||
Project access tokens is an [Alpha](https://about.gitlab.com/handbook/product/#alpha) feature and is not recommended for production use.
|
||||
It is deployed behind a feature flag that is **disabled by default**.
|
||||
Project access tokens are deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||
can enable it for your instance.
|
||||
can disable it for your instance, globally or by project.
|
||||
|
||||
To enable it:
|
||||
To disable it globally:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:resource_access_token)
|
||||
```
|
||||
|
||||
To disable it for a specific project:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:resource_access_token, project)
|
||||
```
|
||||
|
||||
To enable it globally:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:resource_access_token)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
To enable it for a specific project:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:resource_access_token)
|
||||
Feature.enable(:resource_access_token, project)
|
||||
```
|
||||
|
|
|
@ -110,15 +110,13 @@ module API
|
|||
end
|
||||
|
||||
desc 'Gets the test report for a given pipeline' do
|
||||
detail 'This feature was introduced in GitLab 13.0. Disabled by default behind feature flag `junit_pipeline_view`'
|
||||
detail 'This feature was introduced in GitLab 13.0.'
|
||||
success TestReportEntity
|
||||
end
|
||||
params do
|
||||
requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
|
||||
end
|
||||
get ':id/pipelines/:pipeline_id/test_report' do
|
||||
not_found! unless Feature.enabled?(:junit_pipeline_view, user_project)
|
||||
|
||||
authorize! :read_build, pipeline
|
||||
|
||||
present pipeline.test_reports, with: TestReportEntity, details: true
|
||||
|
|
|
@ -607,7 +607,7 @@ module Gitlab
|
|||
counter = Gitlab::UsageDataCounters::TrackUniqueActions
|
||||
|
||||
project_count = redis_usage_data do
|
||||
counter.count_unique_events(
|
||||
counter.count_unique(
|
||||
event_action: Gitlab::UsageDataCounters::TrackUniqueActions::PUSH_ACTION,
|
||||
date_from: time_period[:created_at].first,
|
||||
date_to: time_period[:created_at].last
|
||||
|
@ -615,7 +615,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
design_count = redis_usage_data do
|
||||
counter.count_unique_events(
|
||||
counter.count_unique(
|
||||
event_action: Gitlab::UsageDataCounters::TrackUniqueActions::DESIGN_ACTION,
|
||||
date_from: time_period[:created_at].first,
|
||||
date_to: time_period[:created_at].last
|
||||
|
@ -623,7 +623,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
wiki_count = redis_usage_data do
|
||||
counter.count_unique_events(
|
||||
counter.count_unique(
|
||||
event_action: Gitlab::UsageDataCounters::TrackUniqueActions::WIKI_ACTION,
|
||||
date_from: time_period[:created_at].first,
|
||||
date_to: time_period[:created_at].last
|
||||
|
|
|
@ -27,7 +27,7 @@ module Gitlab
|
|||
}).freeze
|
||||
|
||||
class << self
|
||||
def track_action(event_action:, event_target:, author_id:, time: Time.zone.now)
|
||||
def track_event(event_action:, event_target:, author_id:, time: Time.zone.now)
|
||||
return unless Gitlab::CurrentSettings.usage_ping_enabled
|
||||
return unless Feature.enabled?(FEATURE_FLAG)
|
||||
return unless valid_target?(event_target)
|
||||
|
@ -40,7 +40,7 @@ module Gitlab
|
|||
Gitlab::Redis::HLL.add(key: target_key, value: author_id, expiry: KEY_EXPIRY_LENGTH)
|
||||
end
|
||||
|
||||
def count_unique_events(event_action:, date_from:, date_to:)
|
||||
def count_unique(event_action:, date_from:, date_to:)
|
||||
keys = (date_from.to_date..date_to.to_date).map { |date| key(event_action, date) }
|
||||
|
||||
Gitlab::Redis::HLL.count(keys: keys)
|
||||
|
|
|
@ -2180,6 +2180,9 @@ msgstr ""
|
|||
msgid "AlertManagement|Resolved"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|Runbook"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|Service"
|
||||
msgstr ""
|
||||
|
||||
|
@ -27831,9 +27834,6 @@ msgstr ""
|
|||
msgid "You can also upload existing files from your computer using the instructions below."
|
||||
msgstr ""
|
||||
|
||||
msgid "You can also use project access tokens to authenticate against Git over HTTP."
|
||||
msgstr ""
|
||||
|
||||
msgid "You can always edit this later"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -859,113 +859,88 @@ RSpec.describe Projects::PipelinesController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when feature is enabled' do
|
||||
context 'when pipeline does not have a test report' do
|
||||
it 'renders an empty test report' do
|
||||
get_test_report_json
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has a test report' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_view: project)
|
||||
create(:ci_build, :test_reports, name: 'rspec', pipeline: pipeline)
|
||||
end
|
||||
|
||||
context 'when pipeline does not have a test report' do
|
||||
it 'renders an empty test report' do
|
||||
get_test_report_json
|
||||
it 'renders the test report' do
|
||||
get_test_report_json
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has a corrupt test report artifact' do
|
||||
before do
|
||||
create(:ci_build, :broken_test_reports, name: 'rspec', pipeline: pipeline)
|
||||
|
||||
get_test_report_json
|
||||
end
|
||||
|
||||
it 'renders the test reports' do
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['test_suites'].count).to eq(1)
|
||||
end
|
||||
|
||||
it 'returns a suite_error on the suite with corrupted XML' do
|
||||
expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when junit_pipeline_screenshots_view is enabled' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_screenshots_view: project)
|
||||
end
|
||||
|
||||
context 'when test_report contains attachment and scope is with_attachment as a URL param' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) }
|
||||
|
||||
it 'returns a test reports with attachment' do
|
||||
get_test_report_json(scope: 'with_attachment')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(0)
|
||||
expect(json_response["test_suites"]).to be_present
|
||||
expect(json_response["test_suites"].first["test_cases"].first).to include("attachment_url")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has a test report' do
|
||||
before do
|
||||
create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build|
|
||||
create(:ci_job_artifact, :junit, job: build)
|
||||
end
|
||||
end
|
||||
context 'when test_report does not contain attachment and scope is with_attachment as a URL param' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) }
|
||||
|
||||
it 'renders the test report' do
|
||||
get_test_report_json
|
||||
it 'returns a test reports with empty values' do
|
||||
get_test_report_json(scope: 'with_attachment')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has a corrupt test report artifact' do
|
||||
before do
|
||||
create(:ci_build, name: 'rspec', pipeline: pipeline).tap do |build|
|
||||
create(:ci_job_artifact, :junit_with_corrupted_data, job: build)
|
||||
end
|
||||
|
||||
get_test_report_json
|
||||
end
|
||||
|
||||
it 'renders the test reports' do
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['test_suites'].count).to eq(1)
|
||||
end
|
||||
|
||||
it 'returns a suite_error on the suite with corrupted XML' do
|
||||
expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when junit_pipeline_screenshots_view is enabled' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_screenshots_view: project)
|
||||
end
|
||||
|
||||
context 'when test_report contains attachment and scope is with_attachment as a URL param' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) }
|
||||
|
||||
it 'returns a test reports with attachment' do
|
||||
get_test_report_json(scope: 'with_attachment')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response["test_suites"]).to be_present
|
||||
expect(json_response["test_suites"].first["test_cases"].first).to include("attachment_url")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when test_report does not contain attachment and scope is with_attachment as a URL param' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) }
|
||||
|
||||
it 'returns a test reports with empty values' do
|
||||
get_test_report_json(scope: 'with_attachment')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response["test_suites"]).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when junit_pipeline_screenshots_view is disabled' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_screenshots_view: false)
|
||||
end
|
||||
|
||||
context 'when test_report contains attachment and scope is with_attachment as a URL param' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) }
|
||||
|
||||
it 'returns a test reports without attachment_url' do
|
||||
get_test_report_json(scope: 'with_attachment')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response["test_suites"].first["test_cases"].first).not_to include("attachment_url")
|
||||
end
|
||||
expect(json_response["test_suites"]).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature is disabled' do
|
||||
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
|
||||
|
||||
context 'when junit_pipeline_screenshots_view is disabled' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_view: false)
|
||||
stub_feature_flags(junit_pipeline_screenshots_view: false)
|
||||
end
|
||||
|
||||
it 'renders empty response' do
|
||||
get_test_report_json
|
||||
context 'when test_report contains attachment and scope is with_attachment as a URL param' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports_attachment, project: project) }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
expect(response.body).to be_empty
|
||||
it 'returns a test reports without attachment_url' do
|
||||
get_test_report_json(scope: 'with_attachment')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response["test_suites"].first["test_cases"].first).not_to include("attachment_url")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ describe('AlertDetails', () => {
|
|||
${'monitoringTool'} | ${undefined} | ${false}
|
||||
${'service'} | ${'Prometheus'} | ${true}
|
||||
${'service'} | ${undefined} | ${false}
|
||||
${'runbook'} | ${undefined} | ${false}
|
||||
${'runbook'} | ${'run.com'} | ${true}
|
||||
`(`$desc`, ({ field, data, isShown }) => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ data: { alert: { ...mockAlert, [field]: data } } });
|
||||
|
|
|
@ -15,7 +15,6 @@ RSpec.describe Projects::PipelinesController, "(JavaScript fixtures)", type: :co
|
|||
|
||||
before do
|
||||
sign_in(user)
|
||||
stub_feature_flags(junit_pipeline_view: project)
|
||||
end
|
||||
|
||||
it "pipelines/test_report.json" do
|
||||
|
|
|
@ -20,10 +20,7 @@ describe('Grouped test reports app', () => {
|
|||
let wrapper;
|
||||
let mockStore;
|
||||
|
||||
const mountComponent = ({
|
||||
glFeatures = { junitPipelineView: false },
|
||||
props = { pipelinePath },
|
||||
} = {}) => {
|
||||
const mountComponent = ({ props = { pipelinePath } } = {}) => {
|
||||
wrapper = mount(Component, {
|
||||
store: mockStore,
|
||||
localVue,
|
||||
|
@ -35,9 +32,6 @@ describe('Grouped test reports app', () => {
|
|||
methods: {
|
||||
fetchReports: () => {},
|
||||
},
|
||||
provide: {
|
||||
glFeatures,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -78,28 +72,17 @@ describe('Grouped test reports app', () => {
|
|||
});
|
||||
|
||||
describe('`View full report` button', () => {
|
||||
it('should not render the full test report link', () => {
|
||||
expect(findFullTestReportLink().exists()).toBe(false);
|
||||
});
|
||||
it('should render the full test report link', () => {
|
||||
const fullTestReportLink = findFullTestReportLink();
|
||||
|
||||
describe('With junitPipelineView feature flag enabled', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ glFeatures: { junitPipelineView: true } });
|
||||
});
|
||||
|
||||
it('should render the full test report link', () => {
|
||||
const fullTestReportLink = findFullTestReportLink();
|
||||
|
||||
expect(fullTestReportLink.exists()).toBe(true);
|
||||
expect(pipelinePath).not.toBe('');
|
||||
expect(fullTestReportLink.attributes('href')).toBe(`${pipelinePath}/test_report`);
|
||||
});
|
||||
expect(fullTestReportLink.exists()).toBe(true);
|
||||
expect(pipelinePath).not.toBe('');
|
||||
expect(fullTestReportLink.attributes('href')).toBe(`${pipelinePath}/test_report`);
|
||||
});
|
||||
|
||||
describe('Without a pipelinePath', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({
|
||||
glFeatures: { junitPipelineView: true },
|
||||
props: { pipelinePath: '' },
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,8 +6,7 @@ RSpec.describe Banzai::Filter::GollumTagsFilter do
|
|||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { double }
|
||||
let(:wiki) { ProjectWiki.new(project, user) }
|
||||
let(:wiki) { ProjectWiki.new(project, nil) }
|
||||
|
||||
describe 'validation' do
|
||||
it 'ensure that a :wiki key exists in context' do
|
||||
|
|
|
@ -7,8 +7,7 @@ RSpec.describe Banzai::Filter::WikiLinkFilter do
|
|||
|
||||
let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") }
|
||||
let(:project) { build_stubbed(:project, :public, name: "wiki_link_project", namespace: namespace) }
|
||||
let(:user) { double }
|
||||
let(:wiki) { ProjectWiki.new(project, user) }
|
||||
let(:wiki) { ProjectWiki.new(project, nil) }
|
||||
let(:repository_upload_folder) { Wikis::CreateAttachmentService::ATTACHMENT_PATH }
|
||||
|
||||
it "doesn't rewrite absolute links" do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe Banzai::Pipeline::WikiPipeline do
|
||||
let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
|
||||
let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
|
||||
let_it_be(:wiki) { ProjectWiki.new(project, double(:user)) }
|
||||
let_it_be(:wiki) { ProjectWiki.new(project, nil) }
|
||||
let_it_be(:page) { build(:wiki_page, wiki: wiki, title: 'nested/twice/start-page') }
|
||||
|
||||
describe 'TableOfContents' do
|
||||
|
|
|
@ -7,12 +7,12 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueActions, :clean_gitlab_redi
|
|||
|
||||
let(:time) { Time.zone.now }
|
||||
|
||||
def track_action(params)
|
||||
track_unique_events.track_action(params)
|
||||
def track_event(params)
|
||||
track_unique_events.track_event(params)
|
||||
end
|
||||
|
||||
def count_unique_events(params)
|
||||
track_unique_events.count_unique_events(params)
|
||||
def count_unique(params)
|
||||
track_unique_events.count_unique(params)
|
||||
end
|
||||
|
||||
context 'tracking an event' do
|
||||
|
@ -29,28 +29,28 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueActions, :clean_gitlab_redi
|
|||
design = Event::TARGET_TYPES[:design]
|
||||
wiki = Event::TARGET_TYPES[:wiki]
|
||||
|
||||
expect(track_action(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy
|
||||
expect(track_action(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy
|
||||
expect(track_action(event_action: :pushed, event_target: project, author_id: 2)).to be_truthy
|
||||
expect(track_action(event_action: :pushed, event_target: project, author_id: 3)).to be_truthy
|
||||
expect(track_action(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)).to be_truthy
|
||||
expect(track_action(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: project, author_id: 1)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: project, author_id: 2)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: project, author_id: 3)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)).to be_truthy
|
||||
expect(track_event(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)).to be_truthy
|
||||
|
||||
expect(track_action(event_action: :destroyed, event_target: design, author_id: 3)).to be_truthy
|
||||
expect(track_action(event_action: :created, event_target: design, author_id: 4)).to be_truthy
|
||||
expect(track_action(event_action: :updated, event_target: design, author_id: 5)).to be_truthy
|
||||
expect(track_action(event_action: :pushed, event_target: design, author_id: 6)).to be_truthy
|
||||
expect(track_event(event_action: :destroyed, event_target: design, author_id: 3)).to be_truthy
|
||||
expect(track_event(event_action: :created, event_target: design, author_id: 4)).to be_truthy
|
||||
expect(track_event(event_action: :updated, event_target: design, author_id: 5)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: design, author_id: 6)).to be_truthy
|
||||
|
||||
expect(track_action(event_action: :destroyed, event_target: wiki, author_id: 5)).to be_truthy
|
||||
expect(track_action(event_action: :created, event_target: wiki, author_id: 3)).to be_truthy
|
||||
expect(track_action(event_action: :updated, event_target: wiki, author_id: 4)).to be_truthy
|
||||
expect(track_action(event_action: :pushed, event_target: wiki, author_id: 6)).to be_truthy
|
||||
expect(track_event(event_action: :destroyed, event_target: wiki, author_id: 5)).to be_truthy
|
||||
expect(track_event(event_action: :created, event_target: wiki, author_id: 3)).to be_truthy
|
||||
expect(track_event(event_action: :updated, event_target: wiki, author_id: 4)).to be_truthy
|
||||
expect(track_event(event_action: :pushed, event_target: wiki, author_id: 6)).to be_truthy
|
||||
|
||||
expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(3)
|
||||
expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: Date.tomorrow)).to eq(4)
|
||||
expect(count_unique_events(event_action: described_class::DESIGN_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3)
|
||||
expect(count_unique_events(event_action: described_class::WIKI_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3)
|
||||
expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: time - 2.days)).to eq(1)
|
||||
expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(3)
|
||||
expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: Date.tomorrow)).to eq(4)
|
||||
expect(count_unique(event_action: described_class::DESIGN_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3)
|
||||
expect(count_unique(event_action: described_class::WIKI_ACTION, date_from: time - 5.days, date_to: Date.today)).to eq(3)
|
||||
expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time - 5.days, date_to: time - 2.days)).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -73,8 +73,8 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueActions, :clean_gitlab_redi
|
|||
end
|
||||
|
||||
it 'returns the expected values' do
|
||||
expect(track_action(event_action: action, event_target: target, author_id: 2)).to be_nil
|
||||
expect(count_unique_events(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(0)
|
||||
expect(track_event(event_action: action, event_target: target, author_id: 2)).to be_nil
|
||||
expect(count_unique(event_action: described_class::PUSH_ACTION, date_from: time, date_to: Date.today)).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -924,14 +924,14 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
wiki = Event::TARGET_TYPES[:wiki]
|
||||
design = Event::TARGET_TYPES[:design]
|
||||
|
||||
counter.track_action(event_action: :pushed, event_target: project, author_id: 1)
|
||||
counter.track_action(event_action: :pushed, event_target: project, author_id: 1)
|
||||
counter.track_action(event_action: :pushed, event_target: project, author_id: 2)
|
||||
counter.track_action(event_action: :pushed, event_target: project, author_id: 3)
|
||||
counter.track_action(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)
|
||||
counter.track_action(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)
|
||||
counter.track_action(event_action: :created, event_target: wiki, author_id: 3)
|
||||
counter.track_action(event_action: :created, event_target: design, author_id: 3)
|
||||
counter.track_event(event_action: :pushed, event_target: project, author_id: 1)
|
||||
counter.track_event(event_action: :pushed, event_target: project, author_id: 1)
|
||||
counter.track_event(event_action: :pushed, event_target: project, author_id: 2)
|
||||
counter.track_event(event_action: :pushed, event_target: project, author_id: 3)
|
||||
counter.track_event(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)
|
||||
counter.track_event(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)
|
||||
counter.track_event(event_action: :created, event_target: wiki, author_id: 3)
|
||||
counter.track_event(event_action: :created, event_target: design, author_id: 3)
|
||||
end
|
||||
|
||||
it 'returns the distinct count of user actions within the specified time period' do
|
||||
|
|
|
@ -1541,4 +1541,48 @@ RSpec.describe Group do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#default_owner' do
|
||||
let(:group) { build(:group) }
|
||||
|
||||
context 'the group has owners' do
|
||||
before do
|
||||
group.add_owner(create(:user))
|
||||
group.add_owner(create(:user))
|
||||
end
|
||||
|
||||
it 'is the first owner' do
|
||||
expect(group.default_owner)
|
||||
.to eq(group.owners.first)
|
||||
.and be_a(User)
|
||||
end
|
||||
end
|
||||
|
||||
context 'the group has a parent' do
|
||||
let(:parent) { build(:group) }
|
||||
|
||||
before do
|
||||
group.parent = parent
|
||||
parent.add_owner(create(:user))
|
||||
end
|
||||
|
||||
it 'is the first owner of the parent' do
|
||||
expect(group.default_owner)
|
||||
.to eq(parent.default_owner)
|
||||
.and be_a(User)
|
||||
end
|
||||
end
|
||||
|
||||
context 'we fallback to group.owner' do
|
||||
before do
|
||||
group.owner = build(:user)
|
||||
end
|
||||
|
||||
it 'is the group.owner' do
|
||||
expect(group.default_owner)
|
||||
.to eq(group.owner)
|
||||
.and be_a(User)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1090,6 +1090,30 @@ RSpec.describe Project do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#default_owner' do
|
||||
let_it_be(:owner) { create(:user) }
|
||||
let_it_be(:namespace) { create(:namespace, owner: owner) }
|
||||
|
||||
context 'the project does not have a group' do
|
||||
let(:project) { build(:project, namespace: namespace) }
|
||||
|
||||
it 'is the namespace owner' do
|
||||
expect(project.default_owner).to eq(owner)
|
||||
end
|
||||
end
|
||||
|
||||
context 'the project is in a group' do
|
||||
let(:group) { build(:group) }
|
||||
let(:project) { build(:project, group: group, namespace: namespace) }
|
||||
|
||||
it 'is the group owner' do
|
||||
allow(group).to receive(:default_owner).and_return(Object.new)
|
||||
|
||||
expect(project.default_owner).to eq(group.default_owner)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#external_wiki' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Wiki do
|
||||
describe '.new' do
|
||||
it 'verifies that the user is a User' do
|
||||
expect { described_class.new(double, 1) }.to raise_error(ArgumentError)
|
||||
expect { described_class.new(double, build(:group)) }.to raise_error(ArgumentError)
|
||||
expect { described_class.new(double, build(:user)) }.not_to raise_error
|
||||
expect { described_class.new(double, nil) }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -735,55 +735,36 @@ RSpec.describe API::Ci::Pipelines do
|
|||
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
||||
context 'when feature is enabled' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_view: true)
|
||||
end
|
||||
context 'when pipeline does not have a test report' do
|
||||
it 'returns an empty test report' do
|
||||
subject
|
||||
|
||||
context 'when pipeline does not have a test report' do
|
||||
it 'returns an empty test report' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has a test report' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) }
|
||||
|
||||
it 'returns the test report' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has corrupt test reports' do
|
||||
before do
|
||||
job = create(:ci_build, pipeline: pipeline)
|
||||
create(:ci_job_artifact, :junit_with_corrupted_data, job: job, project: project)
|
||||
end
|
||||
|
||||
it 'returns a suite_error' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty')
|
||||
end
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature is disabled' do
|
||||
before do
|
||||
stub_feature_flags(junit_pipeline_view: false)
|
||||
end
|
||||
context 'when pipeline has a test report' do
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project) }
|
||||
|
||||
it 'renders empty response' do
|
||||
it 'returns the test report' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['total_count']).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline has corrupt test reports' do
|
||||
before do
|
||||
create(:ci_build, :broken_test_reports, name: 'rspec', pipeline: pipeline)
|
||||
end
|
||||
|
||||
it 'returns a suite_error' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['test_suites'].first['suite_error']).to eq('JUnit XML parsing failed: 1:1: FATAL: Document is empty')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -147,8 +147,7 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
|
|||
end
|
||||
|
||||
it_behaves_like 'does not add a system note'
|
||||
# TODO: We should not add another todo in this scenario
|
||||
it_behaves_like 'adds a todo'
|
||||
it_behaves_like 'does not add a todo'
|
||||
end
|
||||
|
||||
context 'with multiple users included' do
|
||||
|
|
|
@ -207,7 +207,7 @@ RSpec.describe EventCreateService do
|
|||
tracking_params = { event_action: counter_class::WIKI_ACTION, date_from: Date.yesterday, date_to: Date.today }
|
||||
|
||||
expect { create_event }
|
||||
.to change { counter_class.count_unique_events(tracking_params) }
|
||||
.to change { counter_class.count_unique(tracking_params) }
|
||||
.by(1)
|
||||
end
|
||||
end
|
||||
|
@ -249,7 +249,7 @@ RSpec.describe EventCreateService do
|
|||
tracking_params = { event_action: counter_class::PUSH_ACTION, date_from: Date.yesterday, date_to: Date.today }
|
||||
|
||||
expect { subject }
|
||||
.to change { counter_class.count_unique_events(tracking_params) }
|
||||
.to change { counter_class.count_unique(tracking_params) }
|
||||
.from(0).to(1)
|
||||
end
|
||||
end
|
||||
|
@ -273,7 +273,7 @@ RSpec.describe EventCreateService do
|
|||
tracking_params = { event_action: counter_class::PUSH_ACTION, date_from: Date.yesterday, date_to: Date.today }
|
||||
|
||||
expect { subject }
|
||||
.to change { counter_class.count_unique_events(tracking_params) }
|
||||
.to change { counter_class.count_unique(tracking_params) }
|
||||
.from(0).to(1)
|
||||
end
|
||||
end
|
||||
|
@ -328,7 +328,7 @@ RSpec.describe EventCreateService do
|
|||
tracking_params = { event_action: counter_class::DESIGN_ACTION, date_from: Date.yesterday, date_to: Date.today }
|
||||
|
||||
expect { result }
|
||||
.to change { counter_class.count_unique_events(tracking_params) }
|
||||
.to change { counter_class.count_unique(tracking_params) }
|
||||
.from(0).to(1)
|
||||
end
|
||||
end
|
||||
|
@ -356,7 +356,7 @@ RSpec.describe EventCreateService do
|
|||
tracking_params = { event_action: counter_class::DESIGN_ACTION, date_from: Date.yesterday, date_to: Date.today }
|
||||
|
||||
expect { result }
|
||||
.to change { counter_class.count_unique_events(tracking_params) }
|
||||
.to change { counter_class.count_unique(tracking_params) }
|
||||
.from(0).to(1)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,6 +34,16 @@ RSpec.describe ResourceAccessTokens::CreateService do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'fails on gitlab.com' do
|
||||
before do
|
||||
allow(Gitlab).to receive(:com?) { true }
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
expect(subject).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'allows creation of bot with valid params' do
|
||||
it { expect { subject }.to change { User.count }.by(1) }
|
||||
|
||||
|
@ -171,6 +181,7 @@ RSpec.describe ResourceAccessTokens::CreateService do
|
|||
|
||||
it_behaves_like 'fails when user does not have the permission to create a Resource Bot'
|
||||
it_behaves_like 'fails when flag is disabled'
|
||||
it_behaves_like 'fails on gitlab.com'
|
||||
|
||||
context 'user with valid permission' do
|
||||
before_all do
|
||||
|
|
|
@ -59,6 +59,10 @@ RSpec.describe TodoService do
|
|||
|
||||
should_not_create_todo(user: guest, target: addressed_target_assigned, action: Todo::DIRECTLY_ADDRESSED)
|
||||
end
|
||||
|
||||
it 'does not create a todo if already assigned' do
|
||||
should_not_create_any_todo { service.send(described_method, target_assigned, author, [john_doe]) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Issues' do
|
||||
|
@ -573,10 +577,10 @@ RSpec.describe TodoService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#reassigned_issuable' do
|
||||
let(:described_method) { :reassigned_issuable }
|
||||
describe '#reassigned_assignable' do
|
||||
let(:described_method) { :reassigned_assignable }
|
||||
|
||||
context 'issuable is a merge request' do
|
||||
context 'assignable is a merge request' do
|
||||
it_behaves_like 'reassigned target' do
|
||||
let(:target_assigned) { create(:merge_request, source_project: project, author: author, assignees: [john_doe], description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
|
||||
let(:addressed_target_assigned) { create(:merge_request, source_project: project, author: author, assignees: [john_doe], description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") }
|
||||
|
@ -584,13 +588,21 @@ RSpec.describe TodoService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'issuable is an issue' do
|
||||
context 'assignable is an issue' do
|
||||
it_behaves_like 'reassigned target' do
|
||||
let(:target_assigned) { create(:issue, project: project, author: author, assignees: [john_doe], description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
|
||||
let(:addressed_target_assigned) { create(:issue, project: project, author: author, assignees: [john_doe], description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") }
|
||||
let(:target_unassigned) { create(:issue, project: project, author: author, assignees: []) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'assignable is an alert' do
|
||||
it_behaves_like 'reassigned target' do
|
||||
let(:target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) }
|
||||
let(:addressed_target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) }
|
||||
let(:target_unassigned) { create(:alert_management_alert, project: project, assignees: []) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Merge Requests' do
|
||||
|
@ -778,16 +790,6 @@ RSpec.describe TodoService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#assign_alert' do
|
||||
let(:described_method) { :assign_alert }
|
||||
|
||||
it_behaves_like 'reassigned target' do
|
||||
let(:target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) }
|
||||
let(:addressed_target_assigned) { create(:alert_management_alert, project: project, assignees: [john_doe]) }
|
||||
let(:target_unassigned) { create(:alert_management_alert, project: project, assignees: []) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#merge_request_build_failed' do
|
||||
let(:merge_participants) { [mr_unassigned.author, admin] }
|
||||
|
||||
|
|
Loading…
Reference in New Issue