Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-10-29 15:09:12 +00:00
parent 5a7d44a955
commit 4dfd78cb55
84 changed files with 1067 additions and 59 deletions

View File

@ -207,6 +207,35 @@ Dangerfile @gl-quality/eng-prod
/ee/lib/gitlab/ci/reports/license_scanning/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/reports/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
[Container Security]
/ee/app/views/projects/threat_monitoring/** @gitlab-org/threat-management/defend/container-security/frontend
/ee/app/assets/javascripts/pages/projects/threat_monitoring/** @gitlab-org/threat-management/defend/container-security/frontend
/ee/app/assets/javascripts/threat_monitoring/** @gitlab-org/threat-management/defend/container-security/frontend
/ee/spec/frontend/threat_monitoring/** @gitlab-org/threat-management/defend/container-security/frontend
/ee/app/controllers/projects/threat_monitoring_controller.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/controllers/projects/threat_monitoring_controller_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/lib/gitlab/kubernetes/cilium_network_policy.rb @gitlab-org/threat-management/defend/container-security/backend
/spec/lib/gitlab/kubernetes/cilium_network_policy_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/lib/gitlab/kubernetes/network_policy_common.rb @gitlab-org/threat-management/defend/container-security/backend
/spec/support/shared_examples/lib/gitlab/kubernetes/network_policy_common_shared_examples.rb @gitlab-org/threat-management/defend/container-security/backend
/lib/gitlab/kubernetes/network_policy.rb @gitlab-org/threat-management/defend/container-security/backend
/spec/lib/gitlab/kubernetes/network_policy_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/app/services/network_policies/** @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/services/network_policies/** @gitlab-org/threat-management/defend/container-security/backend
/ee/app/controllers/projects/security/waf_anomalies_controller.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/controllers/projects/security/waf_anomalies_controller_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/app/models/clusters/applications/cilium.rb @gitlab-org/threat-management/defend/container-security/backend
/spec/models/clusters/applications/cilium_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/app/controllers/projects/security/network_policies_controller.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/controllers/projects/security/network_policies_controller_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/app/workers/network_policy_metrics_worker.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/workers/network_policy_metrics_worker_spec.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/app/services/network_policies/** @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/services/network_policies/** @gitlab-org/threat-management/defend/container-security/backend
/ee/lib/gitlab/usage_data_counters/network_policy_counter.rb @gitlab-org/threat-management/defend/container-security/backend
/ee/spec/lib/gitlab/usage_data_counters/network_policy_counter_spec.rb @gitlab-org/threat-management/defend/container-security/backend
[Code Owners]
/ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh
/ee/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh

View File

@ -1,5 +1,6 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { once } from 'lodash';
import { GlButton } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import { componentNames } from './issue_body';
@ -8,6 +9,7 @@ import SummaryRow from './summary_row.vue';
import IssuesList from './issues_list.vue';
import Modal from './modal.vue';
import createStore from '../store';
import Tracking from '~/tracking';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { summaryTextBuilder, reportTextBuilder, statusIcon } from '../store/utils';
@ -21,7 +23,7 @@ export default {
Modal,
GlButton,
},
mixins: [glFeatureFlagsMixin()],
mixins: [glFeatureFlagsMixin(), Tracking.mixin()],
props: {
endpoint: {
type: String,
@ -58,6 +60,11 @@ export default {
showViewFullReport() {
return this.pipelinePath.length;
},
handleToggleEvent() {
return once(() => {
this.track(this.$options.expandEvent);
});
},
},
created() {
this.setEndpoint(this.endpoint);
@ -102,6 +109,7 @@ export default {
return report.resolved_failures.concat(report.resolved_errors);
},
},
expandEvent: 'expand_test_report_widget',
};
</script>
<template>
@ -111,7 +119,9 @@ export default {
:loading-text="groupedSummaryText"
:error-text="groupedSummaryText"
:has-issues="reports.length > 0"
:should-emit-toggle-event="true"
class="mr-widget-section grouped-security-reports mr-report"
@toggleEvent="handleToggleEvent"
>
<template v-if="showViewFullReport" #actionButtons>
<gl-button

View File

@ -189,6 +189,7 @@ export default {
<button
v-if="isCollapsible"
type="button"
data-testid="report-section-expand-button"
class="js-collapse-btn btn float-right btn-sm align-self-center qa-expand-report-button"
@click="toggleCollapsed"
>

View File

@ -7,11 +7,14 @@ import { deprecatedCreateFlash as createFlash } from './flash';
import FilesCommentButton from './files_comment_button';
import initImageDiffHelper from './image_diff/helpers/init_image_diff';
import syntaxHighlight from './syntax_highlight';
import { spriteIcon } from '~/lib/utils/common_utils';
const WRAPPER = '<div class="diff-content"></div>';
const LOADING_HTML = '<span class="spinner"></span>';
const ERROR_HTML =
'<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
const ERROR_HTML = `<div class="nothing-here-block">${spriteIcon(
'warning-solid',
's16',
)} Could not load diff</div>`;
const COLLAPSED_HTML =
'<div class="nothing-here-block diff-collapsed">This diff is collapsed. <button class="click-to-expand btn btn-link">Click to expand it.</button></div>';

View File

@ -2,13 +2,15 @@
module Ci
module RunnersHelper
include IconsHelper
def runner_status_icon(runner)
status = runner.status
case status
when :not_connected
content_tag :i, nil,
class: "fa fa-warning",
title: "New runner. Has not connected yet"
content_tag(:span, title: "New runner. Has not connected yet") do
sprite_icon("warning-solid", size: 24, css_class: "gl-vertical-align-bottom!")
end
when :online, :offline, :paused
content_tag :i, nil,

View File

@ -4,6 +4,7 @@ module Ci
class DailyBuildGroupReportResult < ApplicationRecord
extend Gitlab::Ci::Model
REPORT_WINDOW = 90.days
PARAM_TYPES = %w[coverage].freeze
belongs_to :last_pipeline, class_name: 'Ci::Pipeline', foreign_key: :last_pipeline_id
@ -15,6 +16,7 @@ module Ci
scope :by_projects, -> (ids) { where(project_id: ids) }
scope :with_coverage, -> { where("(data->'coverage') IS NOT NULL") }
scope :with_default_branch, -> { where(default_branch: true) }
scope :by_date, -> (start_date) { where(date: report_window(start_date)..Date.current) }
store_accessor :data, :coverage
@ -26,6 +28,13 @@ module Ci
def recent_results(attrs, limit: nil)
where(attrs).order(date: :desc, group_name: :asc).limit(limit)
end
def report_window(start_date)
default_date = REPORT_WINDOW.ago.to_date
date = Date.parse(start_date) rescue default_date
[date, default_date].max
end
end
end
end

View File

@ -7,6 +7,8 @@ class PagesDeployment < ApplicationRecord
belongs_to :project, optional: false
belongs_to :ci_build, class_name: 'Ci::Build', optional: true
scope :older_than, -> (id) { where('id < ?', id) }
validates :file, presence: true
validates :file_store, presence: true, inclusion: { in: ObjectStorage::SUPPORTED_STORES }
validates :size, presence: true, numericality: { greater_than: 0, only_integer: true }

View File

@ -346,7 +346,8 @@ class Project < ApplicationRecord
# GitLab Pages
has_many :pages_domains
has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', inverse_of: :project
has_many :pages_deployments
# we need to clean up files, not only remove records
has_many :pages_deployments, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# Can be too many records. We need to implement delete_all in batches.
# Issue https://gitlab.com/gitlab-org/gitlab/-/issues/228637
@ -1801,6 +1802,8 @@ class Project < ApplicationRecord
mark_pages_as_not_deployed unless destroyed?
DestroyPagesDeploymentsWorker.perform_async(id)
# 1. We rename pages to temporary directory
# 2. We wait 5 minutes, due to NFS caching
# 3. We asynchronously remove pages with force
@ -1817,7 +1820,7 @@ class Project < ApplicationRecord
end
def mark_pages_as_not_deployed
ensure_pages_metadatum.update!(deployed: false, artifacts_archive: nil)
ensure_pages_metadatum.update!(deployed: false, artifacts_archive: nil, pages_deployment: nil)
end
def write_repository_config(gl_full_path: full_path)

View File

@ -0,0 +1,65 @@
# frozen_string_literal: true
module Ci
class AppendBuildTraceService
Result = Struct.new(:status, :stream_size, keyword_init: true)
TraceRangeError = Class.new(StandardError)
attr_reader :build, :params
def initialize(build, params)
@build = build
@params = params
end
def execute(body_data)
# TODO:
# it seems that `Content-Range` as formatted by runner is wrong,
# the `byte_end` should point to final byte, but it points byte+1
# that means that we have to calculate end of body,
# as we cannot use `content_length[1]`
# Issue: https://gitlab.com/gitlab-org/gitlab-runner/issues/3275
content_range = stream_range.split('-')
body_start = content_range[0].to_i
body_end = body_start + body_data.bytesize
stream_size = build.trace.append(body_data, body_start)
unless stream_size == body_end
log_range_error(stream_size, body_end)
return Result.new(status: 416, stream_size: stream_size)
end
Result.new(status: 202, stream_size: stream_size)
end
private
def stream_range
params.fetch(:content_range)
end
def log_range_error(stream_size, body_end)
extra = {
build_id: build.id,
body_end: body_end,
stream_size: stream_size,
stream_class: stream_size.class,
stream_range: stream_range
}
build.trace_chunks.last.try do |chunk|
extra.merge!(
chunk_index: chunk.chunk_index,
chunk_store: chunk.data_store,
chunks_count: build.trace_chunks.count
)
end
::Gitlab::ErrorTracking
.log_exception(TraceRangeError.new, extra)
end
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
module Pages
class DestroyDeploymentsService
def initialize(project, last_deployment_id = nil)
@project = project
@last_deployment_id = last_deployment_id
end
def execute
deployments_to_destroy = @project.pages_deployments
deployments_to_destroy = deployments_to_destroy.older_than(@last_deployment_id) if @last_deployment_id
deployments_to_destroy.find_each(&:destroy) # rubocop: disable CodeReuse/ActiveRecord
end
end
end

View File

@ -12,6 +12,11 @@ module Projects
# as it shares the namespace with groups
TMP_EXTRACT_PATH = '@pages.tmp'
# old deployment can be cached by pages daemon
# so we need to give pages daemon some time update cache
# 10 minutes is enough, but 30 feels safer
OLD_DEPLOYMENTS_DESTRUCTION_DELAY = 30.minutes.freeze
attr_reader :build
def initialize(project, build)
@ -128,6 +133,7 @@ module Projects
entries_count = build.artifacts_metadata_entry("", recursive: true).entries.count
sha256 = build.job_artifacts_archive.file_sha256
deployment = nil
File.open(artifacts_path) do |file|
deployment = project.pages_deployments.create!(file: file,
file_count: entries_count,
@ -135,7 +141,11 @@ module Projects
project.pages_metadatum.update!(pages_deployment: deployment)
end
# TODO: schedule old deployment removal https://gitlab.com/gitlab-org/gitlab/-/issues/235730
DestroyPagesDeploymentsWorker.perform_in(
OLD_DEPLOYMENTS_DESTRUCTION_DELAY,
project.id,
deployment.id
)
rescue => e
# we don't want to break current pages deployment process if something goes wrong
# TODO: remove this rescue as part of https://gitlab.com/gitlab-org/gitlab/-/issues/245308

View File

@ -54,7 +54,7 @@ module Projects
end
def mirror_repositories
mirror_repository
mirror_repository if project.repository_exists?
if project.wiki.repository_exists?
mirror_repository(type: Gitlab::GlRepository::WIKI)
@ -92,12 +92,14 @@ module Projects
end
def remove_old_paths
Gitlab::Git::Repository.new(
source_storage_name,
"#{project.disk_path}.git",
nil,
nil
).remove
if project.repository_exists?
Gitlab::Git::Repository.new(
source_storage_name,
"#{project.disk_path}.git",
nil,
nil
).remove
end
if project.wiki.repository_exists?
Gitlab::Git::Repository.new(

View File

@ -30,7 +30,7 @@
= sprite_icon('check', css_class: 'cgreen')
#{ s_('HealthCheck|Healthy') }
- else
= icon('warning', class: 'cred')
= sprite_icon('warning-solid', css_class: 'cred')
#{ s_('HealthCheck|Unhealthy') }
.card-body
- if no_errors

View File

@ -9,7 +9,7 @@
- if @cpus
%h2= _('%{cores} cores') % { cores: @cpus.length }
- else
= icon('warning', class: 'text-warning')
= sprite_icon('warning-solid', css_class: 'text-warning')
= _('Unable to collect CPU info')
.bg-light.light-well.gl-mt-3
%h4= _('Memory Usage')
@ -17,7 +17,7 @@
- if @memory
%h2 #{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}
- else
= icon('warning', class: 'text-warning')
= sprite_icon('warning-solid', css_class: 'text-warning')
= _('Unable to collect memory info')
.bg-light.light-well.gl-mt-3
%h4= _('Uptime')

View File

@ -3,6 +3,7 @@
- page_title _("Environments")
- add_page_specific_style 'page_bundles/xterm'
- add_page_specific_style 'page_bundles/environments'
- add_page_specific_style 'page_bundles/ci_status'
#environments-detail-view{ data: { name: @environment.name, id: @environment.id, delete_path: environment_delete_path(@environment)} }
- if @environment.available? && can?(current_user, :stop_environment, @environment)

View File

@ -19,7 +19,7 @@
- if ref
- if generic_commit_status.ref
.icon-container
= generic_commit_status.tags.any? ? icon('tag') : sprite_icon('fork', size: 10)
= generic_commit_status.tags.any? ? sprite_icon('tag', size: 10) : sprite_icon('fork', size: 10)
= link_to generic_commit_status.ref, project_commits_path(generic_commit_status.project, generic_commit_status.ref)
- else
.light none
@ -30,7 +30,8 @@
= link_to generic_commit_status.short_sha, project_commit_path(generic_commit_status.project, generic_commit_status.sha), class: "commit-sha"
- if retried
= icon('warning', class: 'text-warning has-tooltip', title: 'Status was retried.')
%span.has-tooltip{ title: _('Status was retried.') }
= sprite_icon('warning-solid', class: 'text-warning')
.label-container
- if generic_commit_status.tags.any?

View File

@ -1,9 +1,10 @@
- breadcrumb_title _("Details")
- page_title _("Details")
%h2
%i.fa.fa-warning
#{ _('No repository') }
%h2.gl-display-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('warning-solid', size: 24, css_class: 'gl-mr-2')
= _('No repository')
%p.slead
#{ _('The repository for this project does not exist.') }

View File

@ -1,5 +1,5 @@
.bs-callout.bs-callout-warning
%i.fa.fa-warning
= sprite_icon("warning-solid", css_class: "gl-text-orange-600")
%strong= _("Warning:")
- pages_host = Gitlab.config.pages.host
= s_("GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with sub-subdomains. This means that if your username/groupname contains a dot it will not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages will continue to work provided you don't redirect HTTP to HTTPS.").html_safe % { pages_host: pages_host }

View File

@ -6,7 +6,7 @@
.col-sm-10.offset-sm-2
.bs-callout.bs-callout-warning.mt-0
.row.align-items-center.mx-2
= icon('warning', class: 'mr-2')
= sprite_icon('warning-solid', css_class: ' mr-2 gl-text-orange-600')
= _("Something went wrong while obtaining the Let's Encrypt certificate.")
.row.mx-0.mt-3
= link_to s_('GitLabPagesDomains|Retry'), retry_auto_ssl_project_pages_domain_path(@project, domain_presenter), class: "btn btn-sm btn-grouped btn-warning", method: :post

View File

@ -23,7 +23,7 @@
%button.dropdown-menu-toggle.js-user-search.js-author-search.js-multiselect.js-save-user-data.js-issue-board-sidebar{ type: 'button', ref: 'assigneeDropdown', data: board_sidebar_user_data,
":data-issuable-id" => "issue.iid" }
= dropdown_options[:title]
= icon("chevron-down")
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
.dropdown-menu.dropdown-select.dropdown-menu-user.dropdown-menu-selectable.dropdown-menu-author
= dropdown_title("Assign to")
= dropdown_filter("Search users")

View File

@ -24,7 +24,7 @@
%button.dropdown-menu-toggle.js-due-date-select.js-issue-boards-due-date{ type: 'button',
data: { toggle: 'dropdown', field_name: "issue[due_date]", ability_name: "issue" } }
%span.dropdown-toggle-text= _("Due date")
= icon('chevron-down')
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
.dropdown-menu.dropdown-menu-due-date
= dropdown_title(_('Due date'))
= dropdown_content do

View File

@ -27,7 +27,7 @@
data: label_dropdown_data(@project, namespace_path: @namespace_path, field_name: "issue[label_names][]") }
%span.dropdown-toggle-text
{{ labelDropdownTitle }}
= icon('chevron-down')
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable.dropdown-extended-height
= render partial: "shared/issuable/label_page_default"
- if can?(current_user, :admin_label, current_board_parent)

View File

@ -21,7 +21,7 @@
":data-issuable-id" => "issue.iid",
":data-project-id" => "issue.project_id" }
= _("Milestone")
= icon("chevron-down")
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
.dropdown-menu.dropdown-select.dropdown-menu-selectable
= dropdown_title(_("Assign milestone"))
= dropdown_filter(_("Search milestones"))

View File

@ -1425,6 +1425,14 @@
:weight: 1
:idempotent:
:tags: []
- :name: destroy_pages_deployments
:feature_category: :pages
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
- :name: detect_repository_languages
:feature_category: :source_code_management
:has_external_dependencies:

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class DestroyPagesDeploymentsWorker
include ApplicationWorker
idempotent!
loggable_arguments 0, 1
sidekiq_options retry: 3
feature_category :pages
def perform(project_id, last_deployment_id = nil)
project = Project.find_by_id(project_id)
return unless project
::Pages::DestroyDeploymentsService.new(project, last_deployment_id).execute
end
end

View File

@ -9,7 +9,8 @@ mail_room_config="$app_root/config/mail_room.yml"
get_mail_room_pid()
{
local pid=$(cat $mail_room_pidfile)
local pid
pid=$(cat $mail_room_pidfile)
if [ -z "$pid" ] ; then
echo "Could not find a PID in $mail_room_pidfile"
exit 1

View File

@ -9,7 +9,8 @@ unicorn_cmd="bundle exec unicorn_rails -c $unicorn_config -E $RAILS_ENV"
get_unicorn_pid()
{
local pid=$(cat $unicorn_pidfile)
local pid
pid=$(cat $unicorn_pidfile)
if [ -z "$pid" ] ; then
echo "Could not find a PID in $unicorn_pidfile"
exit 1

View File

@ -0,0 +1,5 @@
---
title: Replace chevron-down fa-icon in board sidebar
merge_request: 46075
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Replace fa-warning icons with GitLab SVG warning-solid icon
merge_request: 46214
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Declare and assign variable separately in Shell Script
merge_request: 46121
author: Peter Dave Hello @PeterDaveHello
type: other

View File

@ -0,0 +1,5 @@
---
title: Add CI Status CSS to the Environments Page
merge_request: 46382
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Allow project storage to be updated when no repositories exist
merge_request: 46385
author:
type: fixed

View File

@ -86,6 +86,8 @@
- 1
- - design_management_new_version
- 1
- - destroy_pages_deployments
- 1
- - detect_repository_languages
- 1
- - disallow_two_factor_for_group

View File

@ -2682,6 +2682,66 @@ Identifier of Clusters::Cluster
"""
scalar ClustersClusterID
"""
Represents the code coverage activity for a group
"""
type CodeCoverageActivity {
"""
Average percentage of the different code coverage results available for the group.
"""
averageCoverage: Float
"""
Number of different code coverage results available for the group.
"""
coverageCount: Int
"""
Date when the code coverage was created.
"""
date: Date!
"""
Number of projects with code coverage results for the group.
"""
projectCount: Int
}
"""
The connection type for CodeCoverageActivity.
"""
type CodeCoverageActivityConnection {
"""
A list of edges.
"""
edges: [CodeCoverageActivityEdge]
"""
A list of nodes.
"""
nodes: [CodeCoverageActivity]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type CodeCoverageActivityEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: CodeCoverageActivity
}
"""
Represents the code coverage summary for a project
"""
@ -7965,6 +8025,37 @@ type Group {
last: Int
): BoardConnection
"""
Represents the code coverage activity for this group. Available only when
feature flag `group_coverage_data_report` is enabled
"""
codeCoverageActivities(
"""
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
"""
First day for which to fetch code coverage activity (maximum time window is set to 90 days)
"""
startDate: Date!
): CodeCoverageActivityConnection
"""
Container repositories of the project
"""

View File

@ -7328,6 +7328,191 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "CodeCoverageActivity",
"description": "Represents the code coverage activity for a group",
"fields": [
{
"name": "averageCoverage",
"description": "Average percentage of the different code coverage results available for the group.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "coverageCount",
"description": "Number of different code coverage results available for the group.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "date",
"description": "Date when the code coverage was created.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Date",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "projectCount",
"description": "Number of projects with code coverage results for the group.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "CodeCoverageActivityConnection",
"description": "The connection type for CodeCoverageActivity.",
"fields": [
{
"name": "edges",
"description": "A list of edges.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "CodeCoverageActivityEdge",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "nodes",
"description": "A list of nodes.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "CodeCoverageActivity",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pageInfo",
"description": "Information to aid in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PageInfo",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "CodeCoverageActivityEdge",
"description": "An edge in a connection.",
"fields": [
{
"name": "cursor",
"description": "A cursor for use in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "node",
"description": "The item at the end of the edge.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "CodeCoverageActivity",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "CodeCoverageSummary",
@ -22008,6 +22193,73 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "codeCoverageActivities",
"description": "Represents the code coverage activity for this group. Available only when feature flag `group_coverage_data_report` is enabled",
"args": [
{
"name": "startDate",
"description": "First day for which to fetch code coverage activity (maximum time window is set to 90 days)",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Date",
"ofType": null
}
},
"defaultValue": null
},
{
"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": "CodeCoverageActivityConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "containerRepositories",
"description": "Container repositories of the project",

View File

@ -418,6 +418,17 @@ Autogenerated return type of ClusterAgentTokenDelete.
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
### CodeCoverageActivity
Represents the code coverage activity for a group.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `averageCoverage` | Float | Average percentage of the different code coverage results available for the group. |
| `coverageCount` | Int | Number of different code coverage results available for the group. |
| `date` | Date! | Date when the code coverage was created. |
| `projectCount` | Int | Number of projects with code coverage results for the group. |
### CodeCoverageSummary
Represents the code coverage summary for a project.

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
description: 'Next iteration of build logs architecture at GitLab'
---

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
description: 'Making GitLab Pages a Cloud Native application - architecture blueprint.'
---

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
description: 'Internal usage of Feature Flags for GitLab development'
---

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
description: 'Image Resizing'
---

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
description: 'Architecture Practice at GitLab'
---

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# CI Lint
If you want to test the validity of your GitLab CI/CD configuration before committing

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Downgrading from EE to CE
If you ever decide to downgrade your Enterprise Edition back to the Community

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
type: howto
---

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# GitLab Pivotal Tile **(PREMIUM ONLY)**
CAUTION: **Discontinued:**

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Managing PostgreSQL extensions
This guide documents how to manage PostgreSQL extensions for installations with an external

View File

@ -1,4 +1,7 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
---

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Akismet
GitLab leverages [Akismet](https://akismet.com/) to protect against spam. Currently

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Auth0 OmniAuth Provider
To enable the Auth0 OmniAuth provider, you must create an Auth0 account, and an

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Microsoft Azure OAuth2 OmniAuth Provider
To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your application with Azure. Azure will generate a client ID and secret key for you to use.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Integrate your GitLab server with Bitbucket Cloud
NOTE: **Note:**

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# CAS OmniAuth Provider
To enable the CAS OmniAuth provider you must register your application with your CAS instance. This requires the service URL GitLab will supply to CAS. It should be something like: `https://gitlab.example.com:443/users/auth/cas3/callback?url`. By default handling for SLO is enabled, you only need to configure CAS for backchannel logout.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# External issue tracker
GitLab has a great [issue tracker](../user/project/issues/index.md) but you can also use an external

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Facebook OAuth2 OmniAuth Provider
To enable the Facebook OmniAuth provider you must register your application with Facebook. Facebook will generate an app ID and secret key for you to use.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Integrate your GitLab instance with GitHub
You can integrate your GitLab instance with GitHub.com as well as GitHub Enterprise to enable users to import projects from GitHub and/or to login to your GitLab instance with your GitHub account.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Integrate your server with GitLab.com
Import projects from GitLab.com and login to your GitLab instance with your GitLab.com account.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Gmail actions buttons for GitLab
GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview).

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Google OAuth2 OmniAuth Provider
To enable the Google OAuth2 OmniAuth provider you must register your application

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Jenkins CI service **(STARTER)**
NOTE: **Note:**

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Jenkins CI (deprecated) service
NOTE: **Note:**

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Sign into GitLab with (almost) any OAuth2 provider
The `omniauth-oauth2-generic` gem allows Single Sign On between GitLab and your own OAuth2 provider

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# GitLab as OAuth2 authentication service provider
This document is about using GitLab as an OAuth authentication service provider

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# OmniAuth
GitLab leverages OmniAuth to allow users to sign in using Twitter, GitHub, and

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# GitLab as OpenID Connect identity provider
This document is about using GitLab as an OpenID Connect identity provider

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# reCAPTCHA
GitLab leverages [Google's reCAPTCHA](https://www.google.com/recaptcha/about/)

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Salesforce OmniAuth Provider
You can integrate your GitLab instance with [Salesforce](https://www.salesforce.com/) to enable users to log in to your GitLab instance with their Salesforce account.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Shibboleth OmniAuth Provider
NOTE: **Note:**

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Slash Commands
> The `run` command was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4466) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.6. [Moved](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24780) to [GitLab Core](https://about.gitlab.com/pricing/) in 11.9.

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Trello Power-Up
GitLab's Trello Power-Up enables you to seamlessly attach

View File

@ -1,3 +1,9 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Twitter OAuth2 OmniAuth Provider
To enable the Twitter OmniAuth provider you must register your application with Twitter. Twitter will generate a client ID and secret key for you to use.

View File

@ -57,9 +57,11 @@ Data table displaying a maximum of the 100 most recent merge requests merged for
You can filter the data that is presented on the page based on the following parameters:
- Author
- Assignees
- Labels
- Milestones
- Assignee
- Label
- Milestone
- Source branch
- Target branch
To filter results:

View File

@ -88,8 +88,6 @@ We intend to add a similar SSO requirement for [Git and API activity](https://gi
When SSO enforcement is enabled for a group, users cannot share a project in the group outside the top-level group, even if the project is forked.
To disallow users to contribute outside of the top-level group, please see [Group Managed Accounts](group_managed_accounts.md).
## Providers
NOTE: **Note:**

View File

@ -207,27 +207,18 @@ module API
error!('400 Missing header Content-Range', 400) unless request.headers.key?('Content-Range')
content_range = request.headers['Content-Range']
content_range = content_range.split('-')
# TODO:
# it seems that `Content-Range` as formatted by runner is wrong,
# the `byte_end` should point to final byte, but it points byte+1
# that means that we have to calculate end of body,
# as we cannot use `content_length[1]`
# Issue: https://gitlab.com/gitlab-org/gitlab-runner/issues/3275
result = ::Ci::AppendBuildTraceService
.new(job, content_range: content_range)
.execute(request.body.read)
body_data = request.body.read
body_start = content_range[0].to_i
body_end = body_start + body_data.bytesize
stream_size = job.trace.append(body_data, body_start)
unless stream_size == body_end
break error!('416 Range Not Satisfiable', 416, { 'Range' => "0-#{stream_size}" })
if result.status == 416
break error!('416 Range Not Satisfiable', 416, { 'Range' => "0-#{result.stream_size}" })
end
status 202
status result.status
header 'Job-Status', job.status
header 'Range', "0-#{stream_size}"
header 'Range', "0-#{result.stream_size}"
header 'X-GitLab-Trace-Update-Interval', job.trace.update_interval.to_s
end

View File

@ -17,8 +17,6 @@ module Gitlab
key_width: opts[:key_width].to_i,
key_text: opts[:key_text]
}
@pipeline = @project.ci_pipelines.latest_successful_for_ref(@ref)
end
def entity
@ -42,14 +40,18 @@ module Gitlab
private
def pipeline
@pipeline ||= @project.ci_pipelines.latest_successful_for_ref(@ref)
end
# rubocop: disable CodeReuse/ActiveRecord
def raw_coverage
return unless @pipeline
return unless pipeline
if @job.blank?
@pipeline.coverage
pipeline.coverage
else
@pipeline.builds
pipeline.builds
.find_by(name: @job)
.try(:coverage)
end

View File

@ -25420,6 +25420,9 @@ msgstr ""
msgid "Status"
msgstr ""
msgid "Status was retried."
msgstr ""
msgid "Status:"
msgstr ""

View File

@ -1,5 +1,6 @@
import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { mockTracking } from 'helpers/tracking_helper';
import GroupedTestReportsApp from '~/reports/components/grouped_test_reports_app.vue';
import { getStoreConfig } from '~/reports/store';
@ -39,6 +40,7 @@ describe('Grouped test reports app', () => {
};
const findHeader = () => wrapper.find('[data-testid="report-section-code-text"]');
const findExpandButton = () => wrapper.find('[data-testid="report-section-expand-button"]');
const findFullTestReportLink = () => wrapper.find('[data-testid="group-test-reports-full-link"]');
const findSummaryDescription = () => wrapper.find('[data-testid="test-summary-row-description"]');
const findIssueDescription = () => wrapper.find('[data-testid="test-issue-body-description"]');
@ -96,6 +98,35 @@ describe('Grouped test reports app', () => {
});
});
describe('`Expand` button', () => {
let trackingSpy;
beforeEach(() => {
setReports(newFailedTestReports);
mountComponent();
document.body.dataset.page = 'projects:merge_requests:show';
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
});
it('tracks an event on click', () => {
findExpandButton().trigger('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'expand_test_report_widget', {});
});
it('only tracks the first expansion', () => {
expect(trackingSpy).not.toHaveBeenCalled();
const button = findExpandButton();
button.trigger('click');
button.trigger('click');
button.trigger('click');
expect(trackingSpy).toHaveBeenCalledTimes(1);
});
});
describe('with new failed result', () => {
beforeEach(() => {
setReports(newFailedTestReports);

View File

@ -123,5 +123,39 @@ RSpec.describe Ci::DailyBuildGroupReportResult do
end
end
end
describe '.by_date' do
subject(:coverages) { described_class.by_date(start_date) }
let!(:coverage_1) { create(:ci_daily_build_group_report_result, date: 1.week.ago) }
context 'when project has several coverage' do
let!(:coverage_2) { create(:ci_daily_build_group_report_result, date: 2.weeks.ago) }
let(:start_date) { 1.week.ago.to_date.to_s }
it 'returns the coverage from the start_date' do
expect(coverages).to contain_exactly(coverage_1)
end
end
context 'when start_date is over 90 days' do
let!(:coverage_2) { create(:ci_daily_build_group_report_result, date: 90.days.ago) }
let!(:coverage_3) { create(:ci_daily_build_group_report_result, date: 91.days.ago) }
let(:start_date) { 1.year.ago.to_date.to_s }
it 'returns the coverage in the last 90 days' do
expect(coverages).to contain_exactly(coverage_1, coverage_2)
end
end
context 'when start_date is not a string' do
let!(:coverage_2) { create(:ci_daily_build_group_report_result, date: 90.days.ago) }
let(:start_date) { 1.week.ago }
it 'returns the coverage in the last 90 days' do
expect(coverages).to contain_exactly(coverage_1, coverage_2)
end
end
end
end
end

View File

@ -42,4 +42,17 @@ RSpec.describe PagesDeployment do
deployment = create(:pages_deployment)
expect(deployment.size).to eq(deployment.file.size)
end
describe '.older_than' do
it 'returns deployments with lower id' do
old_deployments = create_list(:pages_deployment, 2)
deployment = create(:pages_deployment)
# new deployment
create(:pages_deployment)
expect(PagesDeployment.older_than(deployment.id)).to eq(old_deployments)
end
end
end

View File

@ -3668,7 +3668,7 @@ RSpec.describe Project, factory_default: :keep do
let(:project) { create(:project) }
before do
project.namespace_id = 7
project.namespace_id = project.namespace_id + 1
end
it { expect(project.parent_changed?).to be_truthy }
@ -4219,6 +4219,27 @@ RSpec.describe Project, factory_default: :keep do
expect { project.destroy }.not_to raise_error
end
context 'when there is an old pages deployment' do
let!(:old_deployment_from_another_project) { create(:pages_deployment) }
let!(:old_deployment) { create(:pages_deployment, project: project) }
it 'schedules a destruction of pages deployments' do
expect(DestroyPagesDeploymentsWorker).to(
receive(:perform_async).with(project.id)
)
project.remove_pages
end
it 'removes pages deployments', :sidekiq_inline do
expect do
project.remove_pages
end.to change { PagesDeployment.count }.by(-1)
expect(PagesDeployment.find_by_id(old_deployment.id)).to be_nil
end
end
end
describe '#remove_export' do

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::AppendBuildTraceService do
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, :running, pipeline: pipeline) }
before do
stub_feature_flags(ci_enable_live_trace: true)
end
context 'build trace append is successful' do
it 'returns a correct stream size and status code' do
stream_size = 192.kilobytes
body_data = 'x' * stream_size
content_range = "0-#{stream_size}"
result = described_class
.new(build, content_range: content_range)
.execute(body_data)
expect(result.status).to eq 202
expect(result.stream_size).to eq stream_size
expect(build.trace_chunks.count).to eq 2
end
end
context 'when could not correctly append to a trace' do
it 'responds with content range violation and data stored' do
allow(build).to receive_message_chain(:trace, :append) { 16 }
result = described_class
.new(build, content_range: '0-128')
.execute('x' * 128)
expect(result.status).to eq 416
expect(result.stream_size).to eq 16
end
it 'logs exception if build has live trace' do
build.trace.append('abcd', 0)
expect(::Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(anything, hash_including(chunk_index: 0, chunk_store: 'redis'))
result = described_class
.new(build, content_range: '0-128')
.execute('x' * 128)
expect(result.status).to eq 416
expect(result.stream_size).to eq 4
end
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Pages::DestroyDeploymentsService do
let(:project) { create(:project) }
let!(:old_deployments) { create_list(:pages_deployment, 2, project: project) }
let!(:last_deployment) { create(:pages_deployment, project: project) }
let!(:newer_deployment) { create(:pages_deployment, project: project) }
let!(:deployment_from_another_project) { create(:pages_deployment) }
it 'destroys all deployments of the project' do
expect do
described_class.new(project).execute
end.to change { PagesDeployment.count }.by(-4)
expect(deployment_from_another_project.reload).to be
end
it 'destroy only deployments older than last deployment if it is provided' do
expect do
described_class.new(project, last_deployment.id).execute
end.to change { PagesDeployment.count }.by(-2)
expect(last_deployment.reload).to be
expect(newer_deployment.reload).to be
expect(deployment_from_another_project.reload).to be
end
end

View File

@ -71,6 +71,29 @@ RSpec.describe Projects::UpdatePagesService do
expect(project.pages_metadatum.reload.pages_deployment_id).to eq(deployment.id)
end
context 'when there is an old pages deployment' do
let!(:old_deployment_from_another_project) { create(:pages_deployment) }
let!(:old_deployment) { create(:pages_deployment, project: project) }
it 'schedules a destruction of older deployments' do
expect(DestroyPagesDeploymentsWorker).to(
receive(:perform_in).with(described_class::OLD_DEPLOYMENTS_DESTRUCTION_DELAY,
project.id,
instance_of(Integer))
)
execute
end
it 'removes older deployments', :sidekiq_inline do
expect do
execute
end.not_to change { PagesDeployment.count } # it creates one and deletes one
expect(PagesDeployment.find_by_id(old_deployment.id)).to be_nil
end
end
it 'does not create deployment when zip_pages_deployments feature flag is disabled' do
stub_feature_flags(zip_pages_deployments: false)

View File

@ -168,6 +168,24 @@ RSpec.describe Projects::UpdateRepositoryStorageService do
end
end
context 'project with no repositories' do
let(:project) { create(:project) }
let(:repository_storage_move) { create(:project_repository_storage_move, :scheduled, project: project, destination_storage_name: 'test_second_storage') }
it 'updates the database' do
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original
allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid)
result = subject.execute
project.reload
expect(result).to be_success
expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('test_second_storage')
expect(project.project_repository.shard_name).to eq('test_second_storage')
end
end
context 'with wiki repository' do
include_examples 'moves repository to another storage', 'wiki' do
let(:project) { create(:project, :repository, wiki_enabled: true) }

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe DestroyPagesDeploymentsWorker do
subject(:worker) { described_class.new }
let(:project) { create(:project) }
let!(:old_deployment) { create(:pages_deployment, project: project) }
let!(:last_deployment) { create(:pages_deployment, project: project) }
let!(:another_deployment) { create(:pages_deployment) }
it "doesn't fail if project is already removed" do
expect do
worker.perform(-1)
end.not_to raise_error
end
it 'can be called without last_deployment_id' do
expect_next_instance_of(::Pages::DestroyDeploymentsService, project, nil) do |service|
expect(service).to receive(:execute).and_call_original
end
expect do
worker.perform(project.id)
end.to change { PagesDeployment.count }.by(-2)
end
it 'calls destroy service' do
expect_next_instance_of(::Pages::DestroyDeploymentsService, project, last_deployment.id) do |service|
expect(service).to receive(:execute).and_call_original
end
expect do
worker.perform(project.id, last_deployment.id)
end.to change { PagesDeployment.count }.by(-1)
end
end