Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
22391da126
commit
a8281ac434
|
@ -463,7 +463,7 @@ db:backup_and_restore:
|
|||
script:
|
||||
- . scripts/prepare_build.sh
|
||||
- bundle exec rake db:drop db:create db:structure:load db:seed_fu
|
||||
- mkdir -p tmp/tests/public/uploads tmp/tests/{artifacts,pages,lfs-objects,terraform_state,registry}
|
||||
- mkdir -p tmp/tests/public/uploads tmp/tests/{artifacts,pages,lfs-objects,terraform_state,registry,packages}
|
||||
- bundle exec rake gitlab:backup:create
|
||||
- date
|
||||
- bundle exec rake gitlab:backup:restore
|
||||
|
|
|
@ -4,6 +4,7 @@ import initUserPopovers from '../../user_popovers';
|
|||
import highlightCurrentUser from './highlight_current_user';
|
||||
import renderMath from './render_math';
|
||||
import renderMermaid from './render_mermaid';
|
||||
import renderSandboxedMermaid from './render_sandboxed_mermaid';
|
||||
import renderMetrics from './render_metrics';
|
||||
|
||||
// Render GitLab flavoured Markdown
|
||||
|
@ -13,7 +14,11 @@ import renderMetrics from './render_metrics';
|
|||
$.fn.renderGFM = function renderGFM() {
|
||||
syntaxHighlight(this.find('.js-syntax-highlight').get());
|
||||
renderMath(this.find('.js-render-math'));
|
||||
renderMermaid(this.find('.js-render-mermaid'));
|
||||
if (gon.features?.sandboxedMermaid) {
|
||||
renderSandboxedMermaid(this.find('.js-render-mermaid'));
|
||||
} else {
|
||||
renderMermaid(this.find('.js-render-mermaid'));
|
||||
}
|
||||
highlightCurrentUser(this.find('.gfm-project_member').get());
|
||||
initUserPopovers(this.find('.js-user-link').get());
|
||||
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
import $ from 'jquery';
|
||||
import { once, countBy } from 'lodash';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
getBaseURL,
|
||||
relativePathToAbsolute,
|
||||
setUrlParams,
|
||||
joinPaths,
|
||||
} from '~/lib/utils/url_utility';
|
||||
import { darkModeEnabled } from '~/lib/utils/color_utils';
|
||||
import { setAttributes } from '~/lib/utils/dom_utils';
|
||||
|
||||
// Renders diagrams and flowcharts from text using Mermaid in any element with the
|
||||
// `js-render-mermaid` class.
|
||||
//
|
||||
// Example markup:
|
||||
//
|
||||
// <pre class="js-render-mermaid">
|
||||
// graph TD;
|
||||
// A-- > B;
|
||||
// A-- > C;
|
||||
// B-- > D;
|
||||
// C-- > D;
|
||||
// </pre>
|
||||
//
|
||||
|
||||
const SANDBOX_FRAME_PATH = '/-/sandbox/mermaid';
|
||||
// This is an arbitrary number; Can be iterated upon when suitable.
|
||||
const MAX_CHAR_LIMIT = 2000;
|
||||
// Max # of mermaid blocks that can be rendered in a page.
|
||||
const MAX_MERMAID_BLOCK_LIMIT = 50;
|
||||
// Max # of `&` allowed in Chaining of links syntax
|
||||
const MAX_CHAINING_OF_LINKS_LIMIT = 30;
|
||||
// Keep a map of mermaid blocks we've already rendered.
|
||||
const elsProcessingMap = new WeakMap();
|
||||
let renderedMermaidBlocks = 0;
|
||||
|
||||
// Pages without any restrictions on mermaid rendering
|
||||
const PAGES_WITHOUT_RESTRICTIONS = [
|
||||
// Group wiki
|
||||
'groups:wikis:show',
|
||||
'groups:wikis:edit',
|
||||
'groups:wikis:create',
|
||||
|
||||
// Project wiki
|
||||
'projects:wikis:show',
|
||||
'projects:wikis:edit',
|
||||
'projects:wikis:create',
|
||||
|
||||
// Project files
|
||||
'projects:show',
|
||||
'projects:blob:show',
|
||||
];
|
||||
|
||||
function shouldLazyLoadMermaidBlock(source) {
|
||||
/**
|
||||
* If source contains `&`, which means that it might
|
||||
* contain Chaining of links a new syntax in Mermaid.
|
||||
*/
|
||||
if (countBy(source)['&'] > MAX_CHAINING_OF_LINKS_LIMIT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function fixElementSource(el) {
|
||||
// Mermaid doesn't like `<br />` tags, so collapse all like tags into `<br>`, which is parsed correctly.
|
||||
const source = el.textContent?.replace(/<br\s*\/>/g, '<br>');
|
||||
|
||||
// Remove any extra spans added by the backend syntax highlighting.
|
||||
Object.assign(el, { textContent: source });
|
||||
|
||||
return { source };
|
||||
}
|
||||
|
||||
function getSandboxFrameSrc() {
|
||||
const path = joinPaths(gon.relative_url_root || '', SANDBOX_FRAME_PATH);
|
||||
if (!darkModeEnabled()) {
|
||||
return path;
|
||||
}
|
||||
const absoluteUrl = relativePathToAbsolute(path, getBaseURL());
|
||||
return setUrlParams({ darkMode: darkModeEnabled() }, absoluteUrl);
|
||||
}
|
||||
|
||||
function renderMermaidEl(el, source) {
|
||||
const iframeEl = document.createElement('iframe');
|
||||
setAttributes(iframeEl, {
|
||||
src: getSandboxFrameSrc(),
|
||||
sandbox: 'allow-scripts',
|
||||
frameBorder: 0,
|
||||
scrolling: 'no',
|
||||
});
|
||||
|
||||
// Add the original source into the DOM
|
||||
// to allow Copy-as-GFM to access it.
|
||||
const sourceEl = document.createElement('text');
|
||||
sourceEl.textContent = source;
|
||||
sourceEl.classList.add('gl-display-none');
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.appendChild(iframeEl);
|
||||
wrapper.appendChild(sourceEl);
|
||||
|
||||
el.closest('pre').replaceWith(wrapper);
|
||||
|
||||
// Event Listeners
|
||||
iframeEl.addEventListener('load', () => {
|
||||
// Potential risk associated with '*' discussed in below thread
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74414#note_735183398
|
||||
iframeEl.contentWindow.postMessage(source, '*');
|
||||
});
|
||||
|
||||
window.addEventListener(
|
||||
'message',
|
||||
(event) => {
|
||||
if (event.origin !== 'null' || event.source !== iframeEl.contentWindow) {
|
||||
return;
|
||||
}
|
||||
const { h, w } = event.data;
|
||||
iframeEl.width = w;
|
||||
iframeEl.height = h;
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
function renderMermaids($els) {
|
||||
if (!$els.length) return;
|
||||
|
||||
const pageName = document.querySelector('body').dataset.page;
|
||||
|
||||
// A diagram may have been truncated in search results which will cause errors, so abort the render.
|
||||
if (pageName === 'search:show') return;
|
||||
|
||||
let renderedChars = 0;
|
||||
|
||||
$els.each((i, el) => {
|
||||
// Skipping all the elements which we've already queued in requestIdleCallback
|
||||
if (elsProcessingMap.has(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { source } = fixElementSource(el);
|
||||
/**
|
||||
* Restrict the rendering to a certain amount of character
|
||||
* and mermaid blocks to prevent mermaidjs from hanging
|
||||
* up the entire thread and causing a DoS.
|
||||
*/
|
||||
if (
|
||||
!PAGES_WITHOUT_RESTRICTIONS.includes(pageName) &&
|
||||
((source && source.length > MAX_CHAR_LIMIT) ||
|
||||
renderedChars > MAX_CHAR_LIMIT ||
|
||||
renderedMermaidBlocks >= MAX_MERMAID_BLOCK_LIMIT ||
|
||||
shouldLazyLoadMermaidBlock(source))
|
||||
) {
|
||||
const html = `
|
||||
<div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-mermaid-container js-lazy-render-mermaid-container fade show" role="alert">
|
||||
<div>
|
||||
<div>
|
||||
<div class="js-warning-text"></div>
|
||||
<div class="gl-alert-actions">
|
||||
<button type="button" class="js-lazy-render-mermaid btn gl-alert-action btn-warning btn-md gl-button">Display</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const $parent = $(el).parent();
|
||||
|
||||
if (!$parent.hasClass('lazy-alert-shown')) {
|
||||
$parent.after(html);
|
||||
$parent
|
||||
.siblings()
|
||||
.find('.js-warning-text')
|
||||
.text(
|
||||
__('Warning: Displaying this diagram might cause performance issues on this page.'),
|
||||
);
|
||||
$parent.addClass('lazy-alert-shown');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
renderedChars += source.length;
|
||||
renderedMermaidBlocks += 1;
|
||||
|
||||
const requestId = window.requestIdleCallback(() => {
|
||||
renderMermaidEl(el, source);
|
||||
});
|
||||
|
||||
elsProcessingMap.set(el, requestId);
|
||||
});
|
||||
}
|
||||
|
||||
const hookLazyRenderMermaidEvent = once(() => {
|
||||
$(document.body).on('click', '.js-lazy-render-mermaid', function eventHandler() {
|
||||
const parent = $(this).closest('.js-lazy-render-mermaid-container');
|
||||
const pre = parent.prev();
|
||||
|
||||
const el = pre.find('.js-render-mermaid');
|
||||
|
||||
parent.remove();
|
||||
|
||||
// sandbox update
|
||||
const element = el.get(0);
|
||||
const { source } = fixElementSource(element);
|
||||
|
||||
renderMermaidEl(element, source);
|
||||
});
|
||||
});
|
||||
|
||||
export default function renderMermaid($els) {
|
||||
if (!$els.length) return;
|
||||
|
||||
const visibleMermaids = $els.filter(function filter() {
|
||||
return $(this).closest('details').length === 0 && $(this).is(':visible');
|
||||
});
|
||||
|
||||
renderMermaids(visibleMermaids);
|
||||
|
||||
$els.closest('details').one('toggle', function toggle() {
|
||||
if (this.open) {
|
||||
renderMermaids($(this).find('.js-render-mermaid'));
|
||||
}
|
||||
});
|
||||
|
||||
hookLazyRenderMermaidEvent();
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import mermaid from 'mermaid';
|
||||
import { getParameterByName } from '~/lib/utils/url_utility';
|
||||
|
||||
const setIframeRenderedSize = (h, w) => {
|
||||
const { origin } = window.location;
|
||||
window.parent.postMessage({ h, w }, origin);
|
||||
};
|
||||
|
||||
const drawDiagram = (source) => {
|
||||
const element = document.getElementById('app');
|
||||
const insertSvg = (svgCode) => {
|
||||
element.innerHTML = svgCode;
|
||||
|
||||
const height = parseInt(element.firstElementChild.getAttribute('height'), 10);
|
||||
const width = parseInt(element.firstElementChild.style.maxWidth, 10);
|
||||
setIframeRenderedSize(height, width);
|
||||
};
|
||||
mermaid.mermaidAPI.render('mermaid', source, insertSvg);
|
||||
};
|
||||
|
||||
const darkModeEnabled = () => getParameterByName('darkMode') === 'true';
|
||||
|
||||
const initMermaid = () => {
|
||||
let theme = 'neutral';
|
||||
|
||||
if (darkModeEnabled()) {
|
||||
theme = 'dark';
|
||||
}
|
||||
|
||||
mermaid.initialize({
|
||||
// mermaid core options
|
||||
mermaid: {
|
||||
startOnLoad: false,
|
||||
},
|
||||
// mermaidAPI options
|
||||
theme,
|
||||
flowchart: {
|
||||
useMaxWidth: true,
|
||||
htmlLabels: true,
|
||||
},
|
||||
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize', 'htmlLabels'],
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
};
|
||||
|
||||
const addListener = () => {
|
||||
window.addEventListener(
|
||||
'message',
|
||||
(event) => {
|
||||
if (event.origin !== window.location.origin) {
|
||||
return;
|
||||
}
|
||||
drawDiagram(event.data);
|
||||
},
|
||||
false,
|
||||
);
|
||||
};
|
||||
|
||||
addListener();
|
||||
initMermaid();
|
||||
export default {};
|
|
@ -212,7 +212,9 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div class="js-pipeline-header-container">
|
||||
<gl-alert v-if="hasError" :variant="failure.variant">{{ failure.text }}</gl-alert>
|
||||
<gl-alert v-if="hasError" :variant="failure.variant" :dismissible="false">{{
|
||||
failure.text
|
||||
}}</gl-alert>
|
||||
<ci-header
|
||||
v-if="shouldRenderContent"
|
||||
:status="pipeline.detailedStatus"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlIcon, GlPopover, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { __, n__, sprintf } from '~/locale';
|
||||
import createFlash from '~/flash';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
|
@ -10,6 +10,7 @@ import issueCrmContactsSubscription from './queries/issue_crm_contacts.subscript
|
|||
export default {
|
||||
components: {
|
||||
GlIcon,
|
||||
GlLink,
|
||||
GlPopover,
|
||||
},
|
||||
directives: {
|
||||
|
@ -85,9 +86,6 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
help: __('Work in progress- click here to find out more'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -97,11 +95,10 @@ export default {
|
|||
<gl-icon name="users" />
|
||||
<span> {{ contactCount }} </span>
|
||||
</div>
|
||||
<div
|
||||
v-gl-tooltip.left.viewport="$options.i18n.help"
|
||||
class="hide-collapsed help-button float-right"
|
||||
>
|
||||
<a href="https://gitlab.com/gitlab-org/gitlab/-/issues/2256"><gl-icon name="question-o" /></a>
|
||||
<div class="hide-collapsed help-button gl-float-right">
|
||||
<gl-link href="https://docs.gitlab.com/ee/user/crm/" target="_blank"
|
||||
><gl-icon name="question-o"
|
||||
/></gl-link>
|
||||
</div>
|
||||
<div class="title hide-collapsed gl-mb-2 gl-line-height-20">
|
||||
{{ contactsLabel }}
|
||||
|
|
|
@ -247,16 +247,6 @@ $gl-line-height-42: px-to-rem(42px);
|
|||
max-width: 50%;
|
||||
}
|
||||
|
||||
// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1465
|
||||
.gl-popover {
|
||||
.popover-header {
|
||||
.gl-button.close {
|
||||
margin-top: -$gl-spacing-scale-3;
|
||||
margin-right: -$gl-spacing-scale-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Will be moved to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1490
|
||||
.gl-w-grid-size-28 {
|
||||
width: $grid-size * 28;
|
||||
|
|
|
@ -13,7 +13,7 @@ class Oauth::TokenInfoController < Doorkeeper::TokenInfoController
|
|||
'expires_in_seconds' => token_json[:expires_in]
|
||||
), status: :ok
|
||||
else
|
||||
error = Doorkeeper::OAuth::ErrorResponse.new(name: :invalid_request)
|
||||
error = Doorkeeper::OAuth::InvalidTokenResponse.new
|
||||
response.headers.merge!(error.headers)
|
||||
render json: error.body, status: error.status
|
||||
end
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SandboxController < ApplicationController # rubocop:disable Gitlab/NamespacedClass
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
feature_category :not_owned
|
||||
|
||||
def mermaid
|
||||
render layout: false
|
||||
end
|
||||
end
|
|
@ -9,10 +9,17 @@ module Resolvers
|
|||
|
||||
delegate :project, to: :agent
|
||||
|
||||
argument :status, Types::Clusters::AgentTokenStatusEnum,
|
||||
required: false,
|
||||
description: 'Status of the token.'
|
||||
|
||||
def resolve(**args)
|
||||
return ::Clusters::AgentToken.none unless can_read_agent_tokens?
|
||||
|
||||
agent.last_used_agent_tokens
|
||||
tokens = agent.last_used_agent_tokens
|
||||
tokens = tokens.with_status(args[:status]) if args[:status].present?
|
||||
|
||||
tokens
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -24,7 +24,7 @@ module ResolvesPipelines
|
|||
argument :source,
|
||||
GraphQL::Types::String,
|
||||
required: false,
|
||||
description: "Filter pipelines by their source. Will be ignored if `dast_view_scans` feature flag is disabled."
|
||||
description: "Filter pipelines by their source."
|
||||
end
|
||||
|
||||
class_methods do
|
||||
|
@ -38,8 +38,6 @@ module ResolvesPipelines
|
|||
end
|
||||
|
||||
def resolve_pipelines(project, params = {})
|
||||
params.delete(:source) unless Feature.enabled?(:dast_view_scans, project, default_enabled: :yaml)
|
||||
|
||||
Ci::PipelinesFinder.new(project, context[:current_user], params).execute
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module Clusters
|
||||
class AgentTokenStatusEnum < BaseEnum
|
||||
graphql_name 'AgentTokenStatus'
|
||||
description 'Agent token statuses'
|
||||
|
||||
::Clusters::AgentToken.statuses.keys.each do |status|
|
||||
value status.upcase, value: status, description: "#{status.titleize} agent token."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -45,7 +45,7 @@ module Types
|
|||
description: 'Name given to the token.'
|
||||
|
||||
field :status,
|
||||
GraphQL::Types::String,
|
||||
Types::Clusters::AgentTokenStatusEnum,
|
||||
null: true,
|
||||
description: 'Current status of the token.'
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ module Clusters
|
|||
validates :name, presence: true, length: { maximum: 255 }
|
||||
|
||||
scope :order_last_used_at_desc, -> { order(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) }
|
||||
scope :with_status, -> (status) { where(status: status) }
|
||||
|
||||
enum status: {
|
||||
active: 0,
|
||||
|
|
|
@ -12,9 +12,6 @@ class NamespaceSetting < ApplicationRecord
|
|||
validate :allow_mfa_for_group
|
||||
validate :allow_resource_access_token_creation_for_group
|
||||
|
||||
before_save :set_prevent_sharing_groups_outside_hierarchy, if: -> { user_cap_enabled? }
|
||||
after_save :disable_project_sharing!, if: -> { user_cap_enabled? }
|
||||
|
||||
before_validation :normalize_default_branch_name
|
||||
|
||||
enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true
|
||||
|
@ -59,18 +56,6 @@ class NamespaceSetting < ApplicationRecord
|
|||
errors.add(:resource_access_token_creation_allowed, _('is not allowed since the group is not top-level group.'))
|
||||
end
|
||||
end
|
||||
|
||||
def set_prevent_sharing_groups_outside_hierarchy
|
||||
self.prevent_sharing_groups_outside_hierarchy = true
|
||||
end
|
||||
|
||||
def disable_project_sharing!
|
||||
namespace.update_attribute(:share_with_group_lock, true)
|
||||
end
|
||||
|
||||
def user_cap_enabled?
|
||||
new_user_signups_cap.present? && namespace.root?
|
||||
end
|
||||
end
|
||||
|
||||
NamespaceSetting.prepend_mod_with('NamespaceSetting')
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%= webpack_bundle_tag("sandboxed_mermaid") %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: dast_view_scans
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69571
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340388
|
||||
milestone: '14.3'
|
||||
name: sandboxed_mermaid
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74414
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/349755
|
||||
milestone: '14.7'
|
||||
type: development
|
||||
group: group::dynamic analysis
|
||||
default_enabled: true
|
||||
group: group::analyzer frontend
|
||||
default_enabled: false
|
|
@ -8,7 +8,7 @@ product_stage: create
|
|||
product_group: group::code review
|
||||
product_category: code_review
|
||||
value_type: number
|
||||
status: active
|
||||
status: removed
|
||||
time_frame: 28d
|
||||
data_source: database
|
||||
distribution:
|
||||
|
@ -20,3 +20,4 @@ tier:
|
|||
- ultimate
|
||||
performance_indicator_type: []
|
||||
milestone: "<13.9"
|
||||
milestone_removed: '14.7'
|
||||
|
|
|
@ -7,7 +7,7 @@ product_stage: create
|
|||
product_group: group::code review
|
||||
product_category: code_review
|
||||
value_type: number
|
||||
status: active
|
||||
status: removed
|
||||
time_frame: all
|
||||
data_source: database
|
||||
distribution:
|
||||
|
@ -18,3 +18,4 @@ tier:
|
|||
- premium
|
||||
- ultimate
|
||||
milestone: "<13.9"
|
||||
milestone_removed: '14.7'
|
||||
|
|
|
@ -108,6 +108,9 @@ Rails.application.routes.draw do
|
|||
get '/autocomplete/namespace_routes' => 'autocomplete#namespace_routes'
|
||||
end
|
||||
|
||||
# sandbox
|
||||
get '/sandbox/mermaid' => 'sandbox#mermaid'
|
||||
|
||||
get '/whats_new' => 'whats_new#index'
|
||||
|
||||
# '/-/health' implemented by BasicHealthCheck middleware
|
||||
|
|
|
@ -141,6 +141,7 @@ function generateEntries() {
|
|||
sentry: './sentry/index.js',
|
||||
performance_bar: './performance_bar/index.js',
|
||||
jira_connect_app: './jira_connect/subscriptions/index.js',
|
||||
sandboxed_mermaid: './lib/mermaid.js',
|
||||
};
|
||||
|
||||
return Object.assign(manualEntries, incrementalCompiler.filterEntryPoints(autoEntries));
|
||||
|
|
|
@ -9027,10 +9027,27 @@ GitLab CI/CD configuration template.
|
|||
| <a id="clusteragentid"></a>`id` | [`ID!`](#id) | ID of the cluster agent. |
|
||||
| <a id="clusteragentname"></a>`name` | [`String`](#string) | Name of the cluster agent. |
|
||||
| <a id="clusteragentproject"></a>`project` | [`Project`](#project) | Project this cluster agent is associated with. |
|
||||
| <a id="clusteragenttokens"></a>`tokens` | [`ClusterAgentTokenConnection`](#clusteragenttokenconnection) | Tokens associated with the cluster agent. (see [Connections](#connections)) |
|
||||
| <a id="clusteragentupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp the cluster agent was updated. |
|
||||
| <a id="clusteragentwebpath"></a>`webPath` | [`String`](#string) | Web path of the cluster agent. |
|
||||
|
||||
#### Fields with arguments
|
||||
|
||||
##### `ClusterAgent.tokens`
|
||||
|
||||
Tokens associated with the cluster agent.
|
||||
|
||||
Returns [`ClusterAgentTokenConnection`](#clusteragenttokenconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="clusteragenttokensstatus"></a>`status` | [`AgentTokenStatus`](#agenttokenstatus) | Status of the token. |
|
||||
|
||||
### `ClusterAgentActivityEvent`
|
||||
|
||||
#### Fields
|
||||
|
@ -9056,7 +9073,7 @@ GitLab CI/CD configuration template.
|
|||
| <a id="clusteragenttokenid"></a>`id` | [`ClustersAgentTokenID!`](#clustersagenttokenid) | Global ID of the token. |
|
||||
| <a id="clusteragenttokenlastusedat"></a>`lastUsedAt` | [`Time`](#time) | Timestamp the token was last used. |
|
||||
| <a id="clusteragenttokenname"></a>`name` | [`String`](#string) | Name given to the token. |
|
||||
| <a id="clusteragenttokenstatus"></a>`status` | [`String`](#string) | Current status of the token. |
|
||||
| <a id="clusteragenttokenstatus"></a>`status` | [`AgentTokenStatus`](#agenttokenstatus) | Current status of the token. |
|
||||
|
||||
### `CodeCoverageActivity`
|
||||
|
||||
|
@ -9141,7 +9158,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| <a id="commitpipelinesref"></a>`ref` | [`String`](#string) | Filter pipelines by the ref they are run for. |
|
||||
| <a id="commitpipelinesscope"></a>`scope` | [`PipelineScopeEnum`](#pipelinescopeenum) | Filter pipelines by scope. |
|
||||
| <a id="commitpipelinessha"></a>`sha` | [`String`](#string) | Filter pipelines by the sha of the commit they are run for. |
|
||||
| <a id="commitpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. Will be ignored if `dast_view_scans` feature flag is disabled. |
|
||||
| <a id="commitpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. |
|
||||
| <a id="commitpipelinesstatus"></a>`status` | [`PipelineStatusEnum`](#pipelinestatusenum) | Filter pipelines by their status. |
|
||||
|
||||
### `ComplianceFramework`
|
||||
|
@ -11894,7 +11911,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| <a id="mergerequestpipelinesref"></a>`ref` | [`String`](#string) | Filter pipelines by the ref they are run for. |
|
||||
| <a id="mergerequestpipelinesscope"></a>`scope` | [`PipelineScopeEnum`](#pipelinescopeenum) | Filter pipelines by scope. |
|
||||
| <a id="mergerequestpipelinessha"></a>`sha` | [`String`](#string) | Filter pipelines by the sha of the commit they are run for. |
|
||||
| <a id="mergerequestpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. Will be ignored if `dast_view_scans` feature flag is disabled. |
|
||||
| <a id="mergerequestpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. |
|
||||
| <a id="mergerequestpipelinesstatus"></a>`status` | [`PipelineStatusEnum`](#pipelinestatusenum) | Filter pipelines by their status. |
|
||||
|
||||
##### `MergeRequest.reference`
|
||||
|
@ -12928,7 +12945,7 @@ Represents a file or directory in the project repository that has been locked.
|
|||
| <a id="pipelineconfigsource"></a>`configSource` | [`PipelineConfigSourceEnum`](#pipelineconfigsourceenum) | Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE). |
|
||||
| <a id="pipelinecoverage"></a>`coverage` | [`Float`](#float) | Coverage percentage. |
|
||||
| <a id="pipelinecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of the pipeline's creation. |
|
||||
| <a id="pipelinedastprofile"></a>`dastProfile` | [`DastProfile`](#dastprofile) | DAST profile associated with the pipeline. Returns `null`if `dast_view_scans` feature flag is disabled. |
|
||||
| <a id="pipelinedastprofile"></a>`dastProfile` | [`DastProfile`](#dastprofile) | DAST profile associated with the pipeline. |
|
||||
| <a id="pipelinedetailedstatus"></a>`detailedStatus` | [`DetailedStatus!`](#detailedstatus) | Detailed status of the pipeline. |
|
||||
| <a id="pipelinedownstream"></a>`downstream` | [`PipelineConnection`](#pipelineconnection) | Pipelines this pipeline will trigger. (see [Connections](#connections)) |
|
||||
| <a id="pipelineduration"></a>`duration` | [`Int`](#int) | Duration of the pipeline in seconds. |
|
||||
|
@ -13360,7 +13377,7 @@ Returns [`DastProfile`](#dastprofile).
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="projectdastprofilehasdastprofileschedule"></a>`hasDastProfileSchedule` | [`Boolean`](#boolean) | Filter DAST Profiles by whether or not they have a schedule. Will be ignored if `dast_view_scans` feature flag is disabled. |
|
||||
| <a id="projectdastprofilehasdastprofileschedule"></a>`hasDastProfileSchedule` | [`Boolean`](#boolean) | Filter DAST Profiles by whether or not they have a schedule. |
|
||||
| <a id="projectdastprofileid"></a>`id` | [`DastProfileID!`](#dastprofileid) | ID of the DAST Profile. |
|
||||
|
||||
##### `Project.dastProfiles`
|
||||
|
@ -13377,7 +13394,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="projectdastprofileshasdastprofileschedule"></a>`hasDastProfileSchedule` | [`Boolean`](#boolean) | Filter DAST Profiles by whether or not they have a schedule. Will be ignored if `dast_view_scans` feature flag is disabled. |
|
||||
| <a id="projectdastprofileshasdastprofileschedule"></a>`hasDastProfileSchedule` | [`Boolean`](#boolean) | Filter DAST Profiles by whether or not they have a schedule. |
|
||||
|
||||
##### `Project.dastSiteProfile`
|
||||
|
||||
|
@ -13837,7 +13854,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| <a id="projectpipelinesref"></a>`ref` | [`String`](#string) | Filter pipelines by the ref they are run for. |
|
||||
| <a id="projectpipelinesscope"></a>`scope` | [`PipelineScopeEnum`](#pipelinescopeenum) | Filter pipelines by scope. |
|
||||
| <a id="projectpipelinessha"></a>`sha` | [`String`](#string) | Filter pipelines by the sha of the commit they are run for. |
|
||||
| <a id="projectpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. Will be ignored if `dast_view_scans` feature flag is disabled. |
|
||||
| <a id="projectpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. |
|
||||
| <a id="projectpipelinesstatus"></a>`status` | [`PipelineStatusEnum`](#pipelinestatusenum) | Filter pipelines by their status. |
|
||||
|
||||
##### `Project.projectMembers`
|
||||
|
@ -16150,6 +16167,15 @@ Access level to a resource.
|
|||
| <a id="accesslevelenumowner"></a>`OWNER` | Owner access. |
|
||||
| <a id="accesslevelenumreporter"></a>`REPORTER` | Reporter access. |
|
||||
|
||||
### `AgentTokenStatus`
|
||||
|
||||
Agent token statuses.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="agenttokenstatusactive"></a>`ACTIVE` | Active agent token. |
|
||||
| <a id="agenttokenstatusrevoked"></a>`REVOKED` | Revoked agent token. |
|
||||
|
||||
### `AlertManagementAlertSort`
|
||||
|
||||
Values for sorting alerts.
|
||||
|
|
|
@ -61,12 +61,12 @@ including:
|
|||
- Terraform states ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331806) in GitLab 14.7)
|
||||
- Container Registry images
|
||||
- GitLab Pages content
|
||||
- Packages ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332006) in GitLab 14.7)
|
||||
- Snippets
|
||||
- [Group wikis](../user/project/wiki/group.md)
|
||||
|
||||
Backups do not include:
|
||||
|
||||
- [Package registry files](../administration/packages/index.md)
|
||||
- [Mattermost data](https://docs.mattermost.com/administration/config-settings.html#file-storage)
|
||||
|
||||
WARNING:
|
||||
|
@ -276,6 +276,7 @@ You can exclude specific directories from the backup by adding the environment v
|
|||
- `registry` (Container Registry images)
|
||||
- `pages` (Pages content)
|
||||
- `repositories` (Git repositories data)
|
||||
- `packages` (Packages)
|
||||
|
||||
All wikis are backed up as part of the `repositories` group. Non-existent wikis are skipped during a backup.
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ a license, upload the license in the **Admin Area** in the web user interface.
|
|||
|
||||
## What happens when your license expires
|
||||
|
||||
Fifteen days before the license expires, a message with the upcoming expiration
|
||||
One month before the license expires, a message with the upcoming expiration
|
||||
date displays to GitLab administrators.
|
||||
|
||||
When your license expires, GitLab locks features, like Git pushes
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Backup
|
||||
class Manager
|
||||
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs terraform_state registry].freeze
|
||||
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs terraform_state registry packages].freeze
|
||||
FOLDERS_TO_BACKUP = %w[repositories db].freeze
|
||||
FILE_NAME_SUFFIX = '_gitlab_backup.tar'
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Backup
|
||||
class Packages < Backup::Files
|
||||
attr_reader :progress
|
||||
|
||||
def initialize(progress)
|
||||
@progress = progress
|
||||
|
||||
super('packages', Settings.packages.storage_path, excludes: ['tmp'])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -29,8 +29,16 @@ secret_detection:
|
|||
script:
|
||||
- if [ -n "$CI_COMMIT_TAG" ]; then echo "Skipping Secret Detection for tags. No code changes have occurred."; exit 0; fi
|
||||
- if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then echo "Running Secret Detection on default branch."; /analyzer run; exit 0; fi
|
||||
- git fetch origin $CI_DEFAULT_BRANCH $CI_COMMIT_REF_NAME
|
||||
- git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/$CI_DEFAULT_BRANCH...refs/remotes/origin/$CI_COMMIT_REF_NAME > "$CI_COMMIT_SHA"_commit_list.txt
|
||||
- export SECRET_DETECTION_COMMITS_FILE="$CI_COMMIT_SHA"_commit_list.txt
|
||||
- |
|
||||
git fetch origin $CI_DEFAULT_BRANCH $CI_COMMIT_REF_NAME
|
||||
git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/${CI_DEFAULT_BRANCH}..refs/remotes/origin/${CI_COMMIT_REF_NAME} >${CI_COMMIT_SHA}_commit_list.txt
|
||||
if [[ $(wc -l <${CI_COMMIT_SHA}_commit_list.txt) -eq "0" ]]; then
|
||||
# if git log produces 0 or 1 commits we should scan $CI_COMMIT_SHA only
|
||||
export SECRET_DETECTION_COMMITS=$CI_COMMIT_SHA
|
||||
else
|
||||
# +1 because busybox wc only counts \n and there is no trailing \n
|
||||
echo "scanning $(($(wc -l <${CI_COMMIT_SHA}_commit_list.txt) + 1)) commits"
|
||||
export SECRET_DETECTION_COMMITS_FILE=${CI_COMMIT_SHA}_commit_list.txt
|
||||
fi
|
||||
- /analyzer run
|
||||
- rm "$CI_COMMIT_SHA"_commit_list.txt
|
||||
|
|
|
@ -147,7 +147,7 @@ module Gitlab
|
|||
# Using 'self' in the CSP introduces several CSP bypass opportunities
|
||||
# for this reason we list the URLs where GitLab frames itself instead
|
||||
def self.allow_framed_gitlab_paths(directives)
|
||||
['/admin/', '/assets/', '/-/speedscope/index.html'].map do |path|
|
||||
['/admin/', '/assets/', '/-/speedscope/index.html', '/-/sandbox/mermaid'].map do |path|
|
||||
append_to_directive(directives, 'frame_src', Gitlab::Utils.append_path(Gitlab.config.gitlab.url, path))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,6 +57,7 @@ module Gitlab
|
|||
push_frontend_feature_flag(:improved_emoji_picker, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:new_header_search, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:bootstrap_confirmation_modals, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:sandboxed_mermaid, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
# Exposes the state of a feature flag to the frontend code.
|
||||
|
|
|
@ -522,11 +522,7 @@ module Gitlab
|
|||
projects_with_disable_overriding_approvers_per_merge_request: count(::Project.where(time_period.merge(disable_overriding_approvers_per_merge_request: true))),
|
||||
projects_without_disable_overriding_approvers_per_merge_request: count(::Project.where(time_period.merge(disable_overriding_approvers_per_merge_request: [false, nil]))),
|
||||
remote_mirrors: distinct_count(::Project.with_remote_mirrors.where(time_period), :creator_id),
|
||||
snippets: distinct_count(::Snippet.where(time_period), :author_id),
|
||||
suggestions: distinct_count(::Note.with_suggestions.where(time_period),
|
||||
:author_id,
|
||||
start: minimum_id(::User),
|
||||
finish: maximum_id(::User))
|
||||
snippets: distinct_count(::Snippet.where(time_period), :author_id)
|
||||
}.tap do |h|
|
||||
if time_period.present?
|
||||
h[:merge_requests_users] = merge_requests_users(time_period)
|
||||
|
|
|
@ -9,15 +9,9 @@ namespace :gitlab do
|
|||
task create: :gitlab_environment do
|
||||
warn_user_is_not_gitlab
|
||||
|
||||
Rake::Task['gitlab:backup:db:create'].invoke
|
||||
Rake::Task['gitlab:backup:repo:create'].invoke
|
||||
Rake::Task['gitlab:backup:uploads:create'].invoke
|
||||
Rake::Task['gitlab:backup:builds:create'].invoke
|
||||
Rake::Task['gitlab:backup:artifacts:create'].invoke
|
||||
Rake::Task['gitlab:backup:pages:create'].invoke
|
||||
Rake::Task['gitlab:backup:lfs:create'].invoke
|
||||
Rake::Task['gitlab:backup:terraform_state:create'].invoke
|
||||
Rake::Task['gitlab:backup:registry:create'].invoke
|
||||
%w(db repo uploads builds artifacts pages lfs terraform_state registry packages).each do |type|
|
||||
Rake::Task["gitlab:backup:#{type}:create"].invoke
|
||||
end
|
||||
|
||||
backup = Backup::Manager.new(progress)
|
||||
backup.write_info
|
||||
|
@ -86,6 +80,7 @@ namespace :gitlab do
|
|||
Rake::Task['gitlab:backup:lfs:restore'].invoke unless backup.skipped?('lfs')
|
||||
Rake::Task['gitlab:backup:terraform_state:restore'].invoke unless backup.skipped?('terraform_state')
|
||||
Rake::Task['gitlab:backup:registry:restore'].invoke unless backup.skipped?('registry')
|
||||
Rake::Task['gitlab:backup:packages:restore'].invoke unless backup.skipped?('packages')
|
||||
Rake::Task['gitlab:shell:setup'].invoke
|
||||
Rake::Task['cache:clear'].invoke
|
||||
|
||||
|
@ -331,6 +326,25 @@ namespace :gitlab do
|
|||
end
|
||||
end
|
||||
|
||||
namespace :packages do
|
||||
task create: :gitlab_environment do
|
||||
puts_time "Dumping packages ... ".color(:blue)
|
||||
|
||||
if ENV['SKIP'] && ENV['SKIP'].include?('packages')
|
||||
puts_time "[SKIPPED]".color(:cyan)
|
||||
else
|
||||
Backup::Packages.new(progress).dump
|
||||
puts_time "done".color(:green)
|
||||
end
|
||||
end
|
||||
|
||||
task restore: :gitlab_environment do
|
||||
puts_time "Restoring packages ...".color(:blue)
|
||||
Backup::Packages.new(progress).restore
|
||||
puts_time "done".color(:green)
|
||||
end
|
||||
end
|
||||
|
||||
def puts_time(msg)
|
||||
progress.puts "#{Time.now} -- #{msg}"
|
||||
Gitlab::BackupLogger.info(message: "#{Rainbow.uncolor(msg)}")
|
||||
|
|
|
@ -40360,9 +40360,6 @@ msgstr ""
|
|||
msgid "Work in progress Limit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Work in progress- click here to find out more"
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Work Items"
|
||||
msgstr ""
|
||||
|
||||
|
@ -41541,6 +41538,9 @@ msgstr ""
|
|||
msgid "cannot be changed if shared runners are enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot be enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot be enabled because parent group does not allow it"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@
|
|||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "2.0.0",
|
||||
"@gitlab/svgs": "2.2.0",
|
||||
"@gitlab/tributejs": "1.0.0",
|
||||
"@gitlab/ui": "32.51.3",
|
||||
"@gitlab/ui": "32.54.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "6.1.4-1",
|
||||
"@rails/ujs": "6.1.4-1",
|
||||
|
|
|
@ -5,11 +5,11 @@ require 'spec_helper'
|
|||
RSpec.describe Oauth::TokenInfoController do
|
||||
describe '#show' do
|
||||
context 'when the user is not authenticated' do
|
||||
it 'responds with a 400' do
|
||||
it 'responds with a 401' do
|
||||
get :show
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request')
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_token')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -36,11 +36,11 @@ RSpec.describe Oauth::TokenInfoController do
|
|||
end
|
||||
|
||||
context 'when the doorkeeper_token is not recognised' do
|
||||
it 'responds with a 400' do
|
||||
it 'responds with a 401' do
|
||||
get :show, params: { access_token: 'unknown_token' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request')
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_token')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -49,22 +49,22 @@ RSpec.describe Oauth::TokenInfoController do
|
|||
create(:oauth_access_token, created_at: 2.days.ago, expires_in: 10.minutes)
|
||||
end
|
||||
|
||||
it 'responds with a 400' do
|
||||
it 'responds with a 401' do
|
||||
get :show, params: { access_token: access_token.token }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request')
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_token')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the token is revoked' do
|
||||
let(:access_token) { create(:oauth_access_token, revoked_at: 2.days.ago) }
|
||||
|
||||
it 'responds with a 400' do
|
||||
it 'responds with a 401' do
|
||||
get :show, params: { access_token: access_token.token }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_request')
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(Gitlab::Json.parse(response.body)).to include('error' => 'invalid_token')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,5 +7,9 @@ FactoryBot.define do
|
|||
token_encrypted { Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) }
|
||||
|
||||
sequence(:name) { |n| "agent-token-#{n}" }
|
||||
|
||||
trait :revoked do
|
||||
status { :revoked }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ RSpec.describe "User comments on issue", :js do
|
|||
|
||||
before do
|
||||
stub_feature_flags(tribute_autocomplete: false)
|
||||
stub_feature_flags(sandboxed_mermaid: false)
|
||||
project.add_guest(user)
|
||||
sign_in(user)
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@ require 'spec_helper'
|
|||
RSpec.describe 'Mermaid rendering', :js do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(sandboxed_mermaid: false)
|
||||
end
|
||||
|
||||
it 'renders Mermaid diagrams correctly' do
|
||||
description = <<~MERMAID
|
||||
```mermaid
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Sandboxed Mermaid rendering', :js do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(sandboxed_mermaid: true)
|
||||
end
|
||||
|
||||
it 'includes mermaid frame correctly' do
|
||||
description = <<~MERMAID
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;
|
||||
```
|
||||
MERMAID
|
||||
|
||||
issue = create(:issue, project: project, description: description)
|
||||
|
||||
visit project_issue_path(project, issue)
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expected = %(<iframe src="/-/sandbox/mermaid" sandbox="allow-scripts" frameborder="0" scrolling="no")
|
||||
expect(page.html).to include(expected)
|
||||
end
|
||||
end
|
|
@ -7,6 +7,7 @@ RSpec.describe Resolvers::Clusters::AgentTokensResolver do
|
|||
|
||||
it { expect(described_class.type).to eq(Types::Clusters::AgentTokenType) }
|
||||
it { expect(described_class.null).to be_truthy }
|
||||
it { expect(described_class.arguments.keys).to contain_exactly('status') }
|
||||
|
||||
describe '#resolve' do
|
||||
let(:agent) { create(:cluster_agent) }
|
||||
|
@ -23,6 +24,14 @@ RSpec.describe Resolvers::Clusters::AgentTokensResolver do
|
|||
expect(subject).to eq([matching_token2, matching_token1])
|
||||
end
|
||||
|
||||
context 'token status is specified' do
|
||||
let!(:revoked_token) { create(:cluster_agent_token, :revoked, agent: agent) }
|
||||
|
||||
subject { resolve(described_class, obj: agent, ctx: ctx, args: { status: 'revoked' }) }
|
||||
|
||||
it { is_expected.to contain_exactly(revoked_token) }
|
||||
end
|
||||
|
||||
context 'user does not have permission' do
|
||||
let(:user) { create(:user, developer_projects: [agent.project]) }
|
||||
|
||||
|
|
|
@ -62,24 +62,12 @@ RSpec.describe ResolvesPipelines do
|
|||
context 'filtering by source' do
|
||||
let_it_be(:source_pipeline) { create(:ci_pipeline, project: project, source: 'web') }
|
||||
|
||||
context 'when `dast_view_scans` feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(dast_view_scans: false)
|
||||
end
|
||||
|
||||
it 'does not filter by source' do
|
||||
expect(resolve_pipelines(source: 'web')).to contain_exactly(*all_pipelines, source_pipeline)
|
||||
end
|
||||
it 'does filter by source' do
|
||||
expect(resolve_pipelines(source: 'web')).to contain_exactly(source_pipeline)
|
||||
end
|
||||
|
||||
context 'when `dast_view_scans` feature flag is enabled' do
|
||||
it 'does filter by source' do
|
||||
expect(resolve_pipelines(source: 'web')).to contain_exactly(source_pipeline)
|
||||
end
|
||||
|
||||
it 'returns all the pipelines' do
|
||||
expect(resolve_pipelines).to contain_exactly(*all_pipelines, source_pipeline)
|
||||
end
|
||||
it 'returns all the pipelines' do
|
||||
expect(resolve_pipelines).to contain_exactly(*all_pipelines, source_pipeline)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Types::Clusters::AgentTokenStatusEnum do
|
||||
it { expect(described_class.graphql_name).to eq('AgentTokenStatus') }
|
||||
it { expect(described_class.values.keys).to match_array(Clusters::AgentToken.statuses.keys.map(&:upcase)) }
|
||||
end
|
|
@ -15,7 +15,7 @@ RSpec.describe Backup::Manager do
|
|||
end
|
||||
|
||||
describe '#pack' do
|
||||
let(:expected_backup_contents) { %w(repositories db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz backup_information.yml) }
|
||||
let(:expected_backup_contents) { %w(repositories db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz packages.tar.gz backup_information.yml) }
|
||||
let(:tar_file) { '1546300800_2019_01_01_12.3_gitlab_backup.tar' }
|
||||
let(:tar_system_options) { { out: [tar_file, 'w', Gitlab.config.backup.archive_permissions] } }
|
||||
let(:tar_cmdline) { ['tar', '-cf', '-', *expected_backup_contents, tar_system_options] }
|
||||
|
@ -57,7 +57,7 @@ RSpec.describe Backup::Manager do
|
|||
end
|
||||
|
||||
context 'when skipped is set in backup_information.yml' do
|
||||
let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz backup_information.yml} }
|
||||
let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz packages.tar.gz backup_information.yml} }
|
||||
let(:backup_information) do
|
||||
{
|
||||
backup_created_at: Time.zone.parse('2019-01-01'),
|
||||
|
@ -74,7 +74,7 @@ RSpec.describe Backup::Manager do
|
|||
end
|
||||
|
||||
context 'when a directory does not exist' do
|
||||
let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz backup_information.yml} }
|
||||
let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz packages.tar.gz backup_information.yml} }
|
||||
|
||||
before do
|
||||
expect(Dir).to receive(:exist?).with(File.join(Gitlab.config.backup.path, 'repositories')).and_return(false)
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.shared_examples 'backup object' do |setting|
|
||||
let(:progress) { StringIO.new }
|
||||
let(:backup_path) { "/var/#{setting}" }
|
||||
|
||||
subject(:backup) { described_class.new(progress) }
|
||||
|
||||
describe '#dump' do
|
||||
before do
|
||||
allow(File).to receive(:realpath).and_call_original
|
||||
allow(File).to receive(:realpath).with(backup_path).and_return(backup_path)
|
||||
allow(File).to receive(:realpath).with("#{backup_path}/..").and_return('/var')
|
||||
allow(Settings.send(setting)).to receive(:storage_path).and_return(backup_path)
|
||||
end
|
||||
|
||||
it 'uses the correct storage dir in tar command and excludes tmp', :aggregate_failures do
|
||||
expect(backup.app_files_dir).to eq(backup_path)
|
||||
expect(backup).to receive(:tar).and_return('blabla-tar')
|
||||
expect(backup).to receive(:run_pipeline!).with([%W(blabla-tar --exclude=lost+found --exclude=./tmp -C #{backup_path} -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], ''])
|
||||
expect(backup).to receive(:pipeline_succeeded?).and_return(true)
|
||||
|
||||
backup.dump
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.describe Backup::Packages do
|
||||
it_behaves_like 'backup object', 'packages'
|
||||
end
|
||||
|
||||
RSpec.describe Backup::TerraformState do
|
||||
it_behaves_like 'backup object', 'terraform_state'
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Backup::TerraformState do
|
||||
let(:progress) { StringIO.new }
|
||||
|
||||
subject(:backup) { described_class.new(progress) }
|
||||
|
||||
describe '#dump' do
|
||||
before do
|
||||
allow(File).to receive(:realpath).and_call_original
|
||||
allow(File).to receive(:realpath).with('/var/terraform_state').and_return('/var/terraform_state')
|
||||
allow(File).to receive(:realpath).with('/var/terraform_state/..').and_return('/var')
|
||||
allow(Settings.terraform_state).to receive(:storage_path).and_return('/var/terraform_state')
|
||||
end
|
||||
|
||||
it 'uses the correct storage dir in tar command and excludes tmp', :aggregate_failures do
|
||||
expect(backup.app_files_dir).to eq('/var/terraform_state')
|
||||
expect(backup).to receive(:tar).and_return('blabla-tar')
|
||||
expect(backup).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found --exclude=./tmp -C /var/terraform_state -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], ''])
|
||||
expect(backup).to receive(:pipeline_succeeded?).and_return(true)
|
||||
|
||||
backup.dump
|
||||
end
|
||||
end
|
||||
end
|
|
@ -85,7 +85,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
|
|||
expect(directives['style_src']).to eq("'self' 'unsafe-inline' https://cdn.example.com")
|
||||
expect(directives['font_src']).to eq("'self' https://cdn.example.com")
|
||||
expect(directives['worker_src']).to eq('http://localhost/assets/ blob: data: https://cdn.example.com')
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " https://cdn.example.com http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html")
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " https://cdn.example.com http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html http://localhost/-/sandbox/mermaid")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -113,7 +113,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
|
|||
end
|
||||
|
||||
it 'does not add CUSTOMER_PORTAL_URL to CSP' do
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html")
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html http://localhost/-/sandbox/mermaid")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -123,7 +123,7 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
|
|||
end
|
||||
|
||||
it 'adds CUSTOMER_PORTAL_URL to CSP' do
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/rails/letter_opener/ https://customers.example.com http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html")
|
||||
expect(directives['frame_src']).to eq(::Gitlab::ContentSecurityPolicy::Directives.frame_src + " http://localhost/rails/letter_opener/ https://customers.example.com http://localhost/admin/ http://localhost/assets/ http://localhost/-/speedscope/index.html http://localhost/-/sandbox/mermaid")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -161,7 +161,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
another_project = create(:project, :repository, creator: another_user)
|
||||
create(:remote_mirror, project: another_project, enabled: false)
|
||||
create(:snippet, author: user)
|
||||
create(:suggestion, note: create(:note, project: project))
|
||||
end
|
||||
|
||||
expect(described_class.usage_activity_by_stage_create({})).to include(
|
||||
|
@ -171,8 +170,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
projects_with_disable_overriding_approvers_per_merge_request: 2,
|
||||
projects_without_disable_overriding_approvers_per_merge_request: 6,
|
||||
remote_mirrors: 2,
|
||||
snippets: 2,
|
||||
suggestions: 2
|
||||
snippets: 2
|
||||
)
|
||||
expect(described_class.usage_activity_by_stage_create(described_class.monthly_time_range_db_params)).to include(
|
||||
deploy_keys: 1,
|
||||
|
@ -181,8 +179,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
|
|||
projects_with_disable_overriding_approvers_per_merge_request: 1,
|
||||
projects_without_disable_overriding_approvers_per_merge_request: 3,
|
||||
remote_mirrors: 1,
|
||||
snippets: 1,
|
||||
suggestions: 1
|
||||
snippets: 1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,7 +48,7 @@ RSpec.describe Ci::Runner do
|
|||
let(:runner) { create(:ci_runner, :group, groups: [group]) }
|
||||
|
||||
it 'disallows assigning group if already assigned to a group' do
|
||||
runner.runner_namespaces << build(:ci_runner_namespace)
|
||||
runner.runner_namespaces << create(:ci_runner_namespace)
|
||||
|
||||
expect(runner).not_to be_valid
|
||||
expect(runner.errors.full_messages).to include('Runner needs to be assigned to exactly one group')
|
||||
|
|
|
@ -13,15 +13,25 @@ RSpec.describe Clusters::AgentToken do
|
|||
|
||||
describe 'scopes' do
|
||||
describe '.order_last_used_at_desc' do
|
||||
let_it_be(:token_1) { create(:cluster_agent_token, last_used_at: 7.days.ago) }
|
||||
let_it_be(:token_2) { create(:cluster_agent_token, last_used_at: nil) }
|
||||
let_it_be(:token_3) { create(:cluster_agent_token, last_used_at: 2.days.ago) }
|
||||
let_it_be(:agent) { create(:cluster_agent) }
|
||||
let_it_be(:token_1) { create(:cluster_agent_token, agent: agent, last_used_at: 7.days.ago) }
|
||||
let_it_be(:token_2) { create(:cluster_agent_token, agent: agent, last_used_at: nil) }
|
||||
let_it_be(:token_3) { create(:cluster_agent_token, agent: agent, last_used_at: 2.days.ago) }
|
||||
|
||||
it 'sorts by last_used_at descending, with null values at last' do
|
||||
expect(described_class.order_last_used_at_desc)
|
||||
.to eq([token_3, token_1, token_2])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.with_status' do
|
||||
let!(:active_token) { create(:cluster_agent_token) }
|
||||
let!(:revoked_token) { create(:cluster_agent_token, :revoked) }
|
||||
|
||||
subject { described_class.with_status(:active) }
|
||||
|
||||
it { is_expected.to contain_exactly(active_token) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#token' do
|
||||
|
|
|
@ -126,57 +126,4 @@ RSpec.describe NamespaceSetting, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'hooks related to group user cap update' do
|
||||
let(:settings) { create(:namespace_settings, new_user_signups_cap: user_cap) }
|
||||
let(:group) { create(:group, namespace_settings: settings) }
|
||||
|
||||
before do
|
||||
allow(group).to receive(:root?).and_return(true)
|
||||
end
|
||||
|
||||
context 'when updating a group with a user cap' do
|
||||
let(:user_cap) { nil }
|
||||
|
||||
it 'also sets share_with_group_lock and prevent_sharing_groups_outside_hierarchy to true' do
|
||||
expect(group.new_user_signups_cap).to be_nil
|
||||
expect(group.share_with_group_lock).to be_falsey
|
||||
expect(settings.prevent_sharing_groups_outside_hierarchy).to be_falsey
|
||||
|
||||
settings.update!(new_user_signups_cap: 10)
|
||||
group.reload
|
||||
|
||||
expect(group.new_user_signups_cap).to eq(10)
|
||||
expect(group.share_with_group_lock).to be_truthy
|
||||
expect(settings.reload.prevent_sharing_groups_outside_hierarchy).to be_truthy
|
||||
end
|
||||
|
||||
it 'has share_with_group_lock and prevent_sharing_groups_outside_hierarchy returning true for descendent groups' do
|
||||
descendent = create(:group, parent: group)
|
||||
desc_settings = descendent.namespace_settings
|
||||
|
||||
expect(descendent.share_with_group_lock).to be_falsey
|
||||
expect(desc_settings.prevent_sharing_groups_outside_hierarchy).to be_falsey
|
||||
|
||||
settings.update!(new_user_signups_cap: 10)
|
||||
|
||||
expect(descendent.reload.share_with_group_lock).to be_truthy
|
||||
expect(desc_settings.reload.prevent_sharing_groups_outside_hierarchy).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when removing a user cap from namespace settings' do
|
||||
let(:user_cap) { 10 }
|
||||
|
||||
it 'leaves share_with_group_lock and prevent_sharing_groups_outside_hierarchy set to true to the related group' do
|
||||
expect(group.share_with_group_lock).to be_truthy
|
||||
expect(settings.prevent_sharing_groups_outside_hierarchy).to be_truthy
|
||||
|
||||
settings.update!(new_user_signups_cap: nil)
|
||||
|
||||
expect(group.reload.share_with_group_lock).to be_truthy
|
||||
expect(settings.reload.prevent_sharing_groups_outside_hierarchy).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe SandboxController do
|
||||
describe 'GET #mermaid' do
|
||||
it 'renders page without template' do
|
||||
get sandbox_mermaid_path
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to render_template(layout: nil)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -364,6 +364,12 @@ RSpec.describe AutocompleteController, 'routing' do
|
|||
end
|
||||
end
|
||||
|
||||
RSpec.describe SandboxController, 'routing' do
|
||||
it 'to #mermaid' do
|
||||
expect(get("/-/sandbox/mermaid")).to route_to('sandbox#mermaid')
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.describe Snippets::BlobsController, "routing" do
|
||||
it "to #raw" do
|
||||
expect(get('/-/snippets/1/raw/master/lib/version.rb'))
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
- "./spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb"
|
||||
- "./spec/models/ci/build_trace_chunk_spec.rb"
|
||||
- "./spec/models/ci/job_artifact_spec.rb"
|
||||
- "./spec/models/ci/runner_spec.rb"
|
||||
- "./spec/models/clusters/applications/runner_spec.rb"
|
||||
- "./spec/models/design_management/version_spec.rb"
|
||||
- "./spec/models/hooks/system_hook_spec.rb"
|
||||
|
|
|
@ -150,6 +150,7 @@ module TestEnv
|
|||
FileUtils.mkdir_p(artifacts_path)
|
||||
FileUtils.mkdir_p(lfs_path)
|
||||
FileUtils.mkdir_p(terraform_state_path)
|
||||
FileUtils.mkdir_p(packages_path)
|
||||
end
|
||||
|
||||
def setup_gitlab_shell
|
||||
|
@ -424,6 +425,10 @@ module TestEnv
|
|||
Gitlab.config.terraform_state.storage_path
|
||||
end
|
||||
|
||||
def packages_path
|
||||
Gitlab.config.packages.storage_path
|
||||
end
|
||||
|
||||
# When no cached assets exist, manually hit the root path to create them
|
||||
#
|
||||
# Otherwise they'd be created by the first test, often timing out and
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'rake_helper'
|
|||
|
||||
RSpec.describe 'gitlab:app namespace rake task', :delete do
|
||||
let(:enable_registry) { true }
|
||||
let(:backup_types) { %w{db repo uploads builds artifacts pages lfs terraform_state registry} }
|
||||
let(:backup_types) { %w{db repo uploads builds artifacts pages lfs terraform_state registry packages} }
|
||||
|
||||
def tars_glob
|
||||
Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar'))
|
||||
|
@ -15,7 +15,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
end
|
||||
|
||||
def backup_files
|
||||
%w(backup_information.yml artifacts.tar.gz builds.tar.gz lfs.tar.gz terraform_state.tar.gz pages.tar.gz)
|
||||
%w(backup_information.yml artifacts.tar.gz builds.tar.gz lfs.tar.gz terraform_state.tar.gz pages.tar.gz packages.tar.gz)
|
||||
end
|
||||
|
||||
def backup_directories
|
||||
|
@ -137,6 +137,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:terraform_state:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:registry:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:packages:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:shell:setup']).to receive(:invoke)
|
||||
end
|
||||
|
||||
|
@ -213,7 +214,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... ")
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... ")
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... ")
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "done").exactly(8).times
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping packages ... ")
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "done").exactly(9).times
|
||||
|
||||
backup_types.each do |task|
|
||||
run_rake_task("gitlab:backup:#{task}:create")
|
||||
|
@ -279,9 +281,11 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
|
||||
|
||||
tar_contents, exit_status = Gitlab::Popen.popen(
|
||||
%W{tar -tvf #{backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz registry.tar.gz}
|
||||
%W{tar -tvf #{backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz registry.tar.gz packages.tar.gz}
|
||||
)
|
||||
|
||||
puts "CONTENT: #{tar_contents}"
|
||||
|
||||
expect(exit_status).to eq(0)
|
||||
expect(tar_contents).to match('db')
|
||||
expect(tar_contents).to match('uploads.tar.gz')
|
||||
|
@ -292,6 +296,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(tar_contents).to match('lfs.tar.gz')
|
||||
expect(tar_contents).to match('terraform_state.tar.gz')
|
||||
expect(tar_contents).to match('registry.tar.gz')
|
||||
expect(tar_contents).to match('packages.tar.gz')
|
||||
expect(tar_contents).not_to match(%r{^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|pages.tar.gz|artifacts.tar.gz|registry.tar.gz)/$})
|
||||
end
|
||||
|
||||
|
@ -299,7 +304,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
|
||||
|
||||
temp_dirs = Dir.glob(
|
||||
File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry}')
|
||||
File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry,packages}')
|
||||
)
|
||||
|
||||
expect(temp_dirs).to be_empty
|
||||
|
@ -461,7 +466,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
|
||||
|
||||
tar_contents, _exit_status = Gitlab::Popen.popen(
|
||||
%W{tar -tvf #{backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz registry.tar.gz}
|
||||
%W{tar -tvf #{backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz registry.tar.gz packages.tar.gz}
|
||||
)
|
||||
|
||||
expect(tar_contents).to match('db/')
|
||||
|
@ -472,6 +477,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(tar_contents).to match('terraform_state.tar.gz')
|
||||
expect(tar_contents).to match('pages.tar.gz')
|
||||
expect(tar_contents).to match('registry.tar.gz')
|
||||
expect(tar_contents).to match('packages.tar.gz')
|
||||
expect(tar_contents).not_to match('repositories/')
|
||||
expect(tar_contents).to match('repositories: Not found in archive')
|
||||
end
|
||||
|
@ -492,6 +498,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:terraform_state:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:registry:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:packages:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:shell:setup']).to receive :invoke
|
||||
expect { run_rake_task('gitlab:backup:restore') }.to output.to_stdout_from_any_process
|
||||
end
|
||||
|
@ -519,6 +526,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
'terraform_state.tar.gz',
|
||||
'pages.tar.gz',
|
||||
'registry.tar.gz',
|
||||
'packages.tar.gz',
|
||||
'repositories'
|
||||
)
|
||||
end
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -914,20 +914,20 @@
|
|||
stylelint-declaration-strict-value "1.7.7"
|
||||
stylelint-scss "3.18.0"
|
||||
|
||||
"@gitlab/svgs@2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.0.0.tgz#06af5e91c36498ccf7e3e30e432eefcb3b1276c2"
|
||||
integrity sha512-kBq7RZ0N+h41b4JbPOmwzx1X++fD+tz8HhaBmHTkOmRFY/7Ygvt2A8GodUUtpFK/NxRxy8O+knZvLNdfMLAIoQ==
|
||||
"@gitlab/svgs@2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.2.0.tgz#95cf58d6ae634d535145159f08f5cff6241d4013"
|
||||
integrity sha512-mCwR3KfNPsxRoojtTjMIZwdd4FFlBh5DlR9AeodP+7+k8rILdWGYxTZbJMPNXoPbZx16R94nG8c5bR7toD4QBw==
|
||||
|
||||
"@gitlab/tributejs@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
|
||||
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
|
||||
|
||||
"@gitlab/ui@32.51.3":
|
||||
version "32.51.3"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.51.3.tgz#1ba4802a16ecf5465774f4083e5ec1ed6adc4579"
|
||||
integrity sha512-PWC0FtpsW9SM3O935XPU2el/JtLtvHQCL9qblKCeR98eJNYmIpjrw45ow+01jsqpjufcUI49n4id/sYHq8b6og==
|
||||
"@gitlab/ui@32.54.0":
|
||||
version "32.54.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.54.0.tgz#86002a6796bdd68fd54cd01e11292d2b29f361f7"
|
||||
integrity sha512-a1QUbQ3KQtmmenOaSGMp8clwi0o8H/u2c8Q1s9EbWHuXN3UwVnhxP+0ncNUpdTlHyEPn4UbYpAZOowtnikXn8Q==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
|
Loading…
Reference in New Issue