Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5a7d44a955
commit
4dfd78cb55
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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>';
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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.') }
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace chevron-down fa-icon in board sidebar
|
||||
merge_request: 46075
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace fa-warning icons with GitLab SVG warning-solid icon
|
||||
merge_request: 46214
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Declare and assign variable separately in Shell Script
|
||||
merge_request: 46121
|
||||
author: Peter Dave Hello @PeterDaveHello
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add CI Status CSS to the Environments Page
|
||||
merge_request: 46382
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow project storage to be updated when no repositories exist
|
||||
merge_request: 46385
|
||||
author:
|
||||
type: fixed
|
|
@ -86,6 +86,8 @@
|
|||
- 1
|
||||
- - design_management_new_version
|
||||
- 1
|
||||
- - destroy_pages_deployments
|
||||
- 1
|
||||
- - detect_repository_languages
|
||||
- 1
|
||||
- - disallow_two_factor_for_group
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'
|
||||
---
|
||||
|
|
|
@ -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.'
|
||||
---
|
||||
|
|
|
@ -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'
|
||||
---
|
||||
|
|
|
@ -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'
|
||||
---
|
||||
|
|
|
@ -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'
|
||||
---
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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:**
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25420,6 +25420,9 @@ msgstr ""
|
|||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Status was retried."
|
||||
msgstr ""
|
||||
|
||||
msgid "Status:"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue