Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2fe341d705
commit
5460c19548
|
|
@ -72,7 +72,7 @@ review-deploy:
|
|||
- download_chart
|
||||
- date
|
||||
- deploy || (display_deployment_debug && exit 1)
|
||||
- disable_sign_ups
|
||||
- disable_sign_ups || (delete_release && exit 1)
|
||||
# When the job is manual, review-qa-smoke is also manual and we don't want people
|
||||
# to have to manually start the jobs in sequence, so we do it for them.
|
||||
- '[ -z $CI_JOB_MANUAL ] || play_job "review-qa-smoke"'
|
||||
|
|
|
|||
|
|
@ -17,19 +17,11 @@ export default {
|
|||
required: false,
|
||||
default: null,
|
||||
},
|
||||
repositioning: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isNewNote() {
|
||||
return this.label === null;
|
||||
},
|
||||
pinStyle() {
|
||||
return this.repositioning ? { ...this.position, cursor: 'move' } : this.position;
|
||||
},
|
||||
pinLabel() {
|
||||
return this.isNewNote
|
||||
? __('Comment form position')
|
||||
|
|
@ -41,13 +33,13 @@ export default {
|
|||
|
||||
<template>
|
||||
<button
|
||||
:style="pinStyle"
|
||||
:style="position"
|
||||
:aria-label="pinLabel"
|
||||
:class="{
|
||||
'btn-transparent comment-indicator': isNewNote,
|
||||
'btn-transparent comment-indicator gl-p-0': isNewNote,
|
||||
'js-image-badge badge badge-pill': !isNewNote,
|
||||
}"
|
||||
class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0"
|
||||
class="gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-font-lg gl-outline-0!"
|
||||
type="button"
|
||||
@mousedown="$emit('mousedown', $event)"
|
||||
@mouseup="$emit('mouseup', $event)"
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ export default {
|
|||
type="button"
|
||||
role="button"
|
||||
:aria-label="$options.i18n.newCommentButtonLabel"
|
||||
class="gl-absolute gl-w-full gl-h-full gl-p-0 gl-top-0 gl-left-0 gl-outline-0! btn-transparent design-detail-overlay-add-comment"
|
||||
class="gl-absolute gl-w-full gl-h-full gl-p-0 gl-top-0 gl-left-0 gl-outline-0! btn-transparent gl-hover-cursor-crosshair"
|
||||
data-qa-selector="design_image_button"
|
||||
@mouseup="onAddCommentMouseup"
|
||||
></button>
|
||||
|
|
@ -276,7 +276,6 @@ export default {
|
|||
v-if="resolvedDiscussionsExpanded || !note.resolved"
|
||||
:key="note.id"
|
||||
:label="note.index"
|
||||
:repositioning="isMovingNote(note.id)"
|
||||
:position="
|
||||
isMovingNote(note.id) && movingNoteNewPosition
|
||||
? getNotePositionStyle(movingNoteNewPosition)
|
||||
|
|
@ -290,7 +289,6 @@ export default {
|
|||
<design-note-pin
|
||||
v-if="currentCommentForm"
|
||||
:position="currentCommentPositionStyle"
|
||||
:repositioning="isMovingCurrentComment"
|
||||
@mousedown.stop="onNoteMousedown"
|
||||
@mouseup.stop="onNoteMouseup"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
export function loadCSSFile(path) {
|
||||
return new Promise(resolve => {
|
||||
if (document.querySelector(`link[href="${path}"]`)) {
|
||||
resolve();
|
||||
} else {
|
||||
const linkElement = document.createElement('link');
|
||||
linkElement.type = 'text/css';
|
||||
linkElement.rel = 'stylesheet';
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
linkElement.media = 'screen,print';
|
||||
linkElement.onload = () => {
|
||||
resolve();
|
||||
};
|
||||
linkElement.href = path;
|
||||
|
||||
document.head.appendChild(linkElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ export const PACKAGE_REGISTRY_TABS = [
|
|||
type: PackageType.NUGET,
|
||||
},
|
||||
{
|
||||
title: s__('PackageRegistry|PyPi'),
|
||||
title: s__('PackageRegistry|PyPI'),
|
||||
type: PackageType.PYPI,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const getPackageTypeLabel = packageType => {
|
|||
case PackageType.NUGET:
|
||||
return s__('PackageType|NuGet');
|
||||
case PackageType.PYPI:
|
||||
return s__('PackageType|PyPi');
|
||||
return s__('PackageType|PyPI');
|
||||
case PackageType.COMPOSER:
|
||||
return s__('PackageType|Composer');
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import $ from 'jquery';
|
||||
import 'cropper';
|
||||
import { isString } from 'lodash';
|
||||
import { loadCSSFile } from '../lib/utils/css_utils';
|
||||
|
||||
(() => {
|
||||
// Matches everything but the file name
|
||||
|
|
@ -180,6 +181,9 @@ import { isString } from 'lodash';
|
|||
}
|
||||
}
|
||||
|
||||
const cropModal = document.querySelector('.modal-profile-crop');
|
||||
if (cropModal) loadCSSFile(cropModal.dataset.cropperCssPath);
|
||||
|
||||
$.fn.glCrop = function(opts) {
|
||||
return this.each(function() {
|
||||
return $(this).data('glcrop', new GitLabCrop(this, opts));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
@import '@gitlab/at.js/dist/css/jquery.atwho';
|
||||
@import 'dropzone/dist/basic';
|
||||
@import 'select2';
|
||||
@import 'cropper';
|
||||
|
||||
// GitLab UI framework
|
||||
@import 'framework';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
$design-pin-diameter: 28px;
|
||||
$t-gray-a-16-design-pin: rgba($black, 0.16);
|
||||
|
||||
.layout-page.design-detail-layout {
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
|
@ -9,8 +12,53 @@
|
|||
top: 35px;
|
||||
}
|
||||
|
||||
.design-pin {
|
||||
transition: opacity $gl-transition-duration-medium $general-hover-transition-curve;
|
||||
.badge.badge-pill {
|
||||
display: flex;
|
||||
height: $design-pin-diameter;
|
||||
width: $design-pin-diameter;
|
||||
box-sizing: content-box;
|
||||
background-color: $purple-500;
|
||||
color: $white;
|
||||
font-weight: $gl-font-weight-bold;
|
||||
border-radius: 50%;
|
||||
z-index: 1;
|
||||
padding: 0;
|
||||
|
||||
&.resolved {
|
||||
background-color: $gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-indicator {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.comment-indicator,
|
||||
.frame .badge.badge-pill {
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Design pin that overlays the design
|
||||
*/
|
||||
.frame .badge.badge-pill {
|
||||
box-shadow: 0 2px 4px $t-gray-a-08, 0 0 1px $t-gray-a-24;
|
||||
border: $white 2px solid;
|
||||
will-change: transform, box-shadow, opacity;
|
||||
// NOTE: verbose transition property required for Safari
|
||||
transition: transform $general-hover-transition-duration linear, box-shadow $general-hover-transition-duration linear, opacity $general-hover-transition-duration linear;
|
||||
transform-origin: 0 0;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2) translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: 0 0 4px $t-gray-a-16-design-pin, 0 4px 12px $t-gray-a-16-design-pin;
|
||||
}
|
||||
|
||||
&.inactive {
|
||||
@include gl-opacity-5;
|
||||
|
|
@ -20,24 +68,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.badge.badge-pill {
|
||||
display: flex;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
background-color: $blue-400;
|
||||
color: $white;
|
||||
border: $white 1px solid;
|
||||
border-radius: 50%;
|
||||
|
||||
&.resolved {
|
||||
background-color: $gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
.design-detail-overlay-add-comment {
|
||||
cursor: crosshair;
|
||||
}
|
||||
}
|
||||
|
||||
.design-presentation-wrapper {
|
||||
|
|
@ -105,8 +135,8 @@
|
|||
border-left: 1px solid $gray-100;
|
||||
position: absolute;
|
||||
left: 28px;
|
||||
top: -18px;
|
||||
height: 18px;
|
||||
top: -17px;
|
||||
height: 17px;
|
||||
}
|
||||
|
||||
.design-note {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,378 @@
|
|||
/*!
|
||||
* Cropper v2.3.0
|
||||
* https://github.com/fengyuanchen/cropper
|
||||
*
|
||||
* Copyright (c) 2014-2016 Fengyuan Chen and contributors
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2016-02-22T02:13:13.332Z
|
||||
*/
|
||||
.cropper-container {
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
|
||||
position: relative;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
direction: ltr !important;
|
||||
touch-action: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
|
||||
.cropper-container img {
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
min-width: 0 !important;
|
||||
max-width: none !important;
|
||||
height: 100%;
|
||||
min-height: 0 !important;
|
||||
max-height: none !important;
|
||||
|
||||
image-orientation: 0deg !important;
|
||||
}
|
||||
|
||||
.cropper-wrap-box,
|
||||
.cropper-canvas,
|
||||
.cropper-drag-box,
|
||||
.cropper-crop-box,
|
||||
.cropper-modal {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.cropper-wrap-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cropper-drag-box {
|
||||
opacity: 0;
|
||||
background-color: #fff;
|
||||
|
||||
filter: alpha(opacity=0);
|
||||
}
|
||||
|
||||
.cropper-modal {
|
||||
opacity: 0.5;
|
||||
background-color: #000;
|
||||
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
||||
.cropper-view-box {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
outline: 1px solid #39f;
|
||||
outline-color: rgba(51, 153, 255, 0.75);
|
||||
}
|
||||
|
||||
.cropper-dashed {
|
||||
position: absolute;
|
||||
|
||||
display: block;
|
||||
|
||||
opacity: 0.5;
|
||||
border: 0 dashed #eee;
|
||||
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
||||
.cropper-dashed.dashed-h {
|
||||
top: 33.33333%;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 33.33333%;
|
||||
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.cropper-dashed.dashed-v {
|
||||
top: 0;
|
||||
left: 33.33333%;
|
||||
|
||||
width: 33.33333%;
|
||||
height: 100%;
|
||||
|
||||
border-right-width: 1px;
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.cropper-center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
opacity: 0.75;
|
||||
|
||||
filter: alpha(opacity=75);
|
||||
}
|
||||
|
||||
.cropper-center::before,
|
||||
.cropper-center::after {
|
||||
position: absolute;
|
||||
|
||||
display: block;
|
||||
|
||||
content: ' ';
|
||||
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.cropper-center::before {
|
||||
top: 0;
|
||||
left: -3px;
|
||||
|
||||
width: 7px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.cropper-center::after {
|
||||
top: -3px;
|
||||
left: 0;
|
||||
|
||||
width: 1px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.cropper-face,
|
||||
.cropper-line,
|
||||
.cropper-point {
|
||||
position: absolute;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
opacity: 0.1;
|
||||
|
||||
filter: alpha(opacity=10);
|
||||
}
|
||||
|
||||
.cropper-face {
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.cropper-line {
|
||||
background-color: #39f;
|
||||
}
|
||||
|
||||
.cropper-line.line-e {
|
||||
top: 0;
|
||||
right: -3px;
|
||||
|
||||
width: 5px;
|
||||
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.cropper-line.line-n {
|
||||
top: -3px;
|
||||
left: 0;
|
||||
|
||||
height: 5px;
|
||||
|
||||
cursor: n-resize;
|
||||
}
|
||||
|
||||
.cropper-line.line-w {
|
||||
top: 0;
|
||||
left: -3px;
|
||||
|
||||
width: 5px;
|
||||
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.cropper-line.line-s {
|
||||
bottom: -3px;
|
||||
left: 0;
|
||||
|
||||
height: 5px;
|
||||
|
||||
cursor: s-resize;
|
||||
}
|
||||
|
||||
.cropper-point {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
|
||||
opacity: 0.75;
|
||||
background-color: #39f;
|
||||
|
||||
filter: alpha(opacity=75);
|
||||
}
|
||||
|
||||
.cropper-point.point-e {
|
||||
top: 50%;
|
||||
right: -3px;
|
||||
|
||||
margin-top: -3px;
|
||||
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-n {
|
||||
top: -3px;
|
||||
left: 50%;
|
||||
|
||||
margin-left: -3px;
|
||||
|
||||
cursor: n-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-w {
|
||||
top: 50%;
|
||||
left: -3px;
|
||||
|
||||
margin-top: -3px;
|
||||
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-s {
|
||||
bottom: -3px;
|
||||
left: 50%;
|
||||
|
||||
margin-left: -3px;
|
||||
|
||||
cursor: s-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-ne {
|
||||
top: -3px;
|
||||
right: -3px;
|
||||
|
||||
cursor: ne-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-nw {
|
||||
top: -3px;
|
||||
left: -3px;
|
||||
|
||||
cursor: nw-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-sw {
|
||||
bottom: -3px;
|
||||
left: -3px;
|
||||
|
||||
cursor: sw-resize;
|
||||
}
|
||||
|
||||
.cropper-point.point-se {
|
||||
right: -3px;
|
||||
bottom: -3px;
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
cursor: se-resize;
|
||||
|
||||
opacity: 1;
|
||||
|
||||
filter: alpha(opacity=100);
|
||||
}
|
||||
|
||||
.cropper-point.point-se::before {
|
||||
position: absolute;
|
||||
right: -50%;
|
||||
bottom: -50%;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
|
||||
content: ' ';
|
||||
|
||||
opacity: 0;
|
||||
background-color: #39f;
|
||||
|
||||
filter: alpha(opacity=0);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.cropper-point.point-se {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.cropper-point.point-se {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.cropper-point.point-se {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
|
||||
opacity: 0.75;
|
||||
|
||||
filter: alpha(opacity=75);
|
||||
}
|
||||
}
|
||||
|
||||
.cropper-invisible {
|
||||
opacity: 0;
|
||||
|
||||
filter: alpha(opacity=0);
|
||||
}
|
||||
|
||||
.cropper-bg {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
.cropper-hide {
|
||||
position: absolute;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.cropper-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cropper-move {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.cropper-crop {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.cropper-disabled .cropper-drag-box,
|
||||
.cropper-disabled .cropper-face,
|
||||
.cropper-disabled .cropper-line,
|
||||
.cropper-disabled .cropper-point {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class HelpController < ApplicationController
|
||||
skip_before_action :authenticate_user!, unless: :public_visibility_restricted?
|
||||
feature_category :not_owned
|
||||
|
||||
layout 'help'
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ class IdeController < ApplicationController
|
|||
push_frontend_feature_flag(:schema_linting)
|
||||
end
|
||||
|
||||
feature_category :web_ide
|
||||
|
||||
def index
|
||||
Gitlab::UsageDataCounters::WebIdeCounter.increment_views_count
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Import::AvailableNamespacesController < ApplicationController
|
||||
feature_category :importers
|
||||
|
||||
def index
|
||||
render json: NamespaceSerializer.new.represent(current_user.manageable_groups_with_routes)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ class Import::BaseController < ApplicationController
|
|||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
before_action :import_rate_limit, only: [:create]
|
||||
feature_category :importers
|
||||
|
||||
def status
|
||||
respond_to do |format|
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ class Import::BulkImportsController < ApplicationController
|
|||
before_action :ensure_group_import_enabled
|
||||
before_action :verify_blocked_uri, only: :status
|
||||
|
||||
feature_category :importers
|
||||
|
||||
def configure
|
||||
session[access_token_key] = params[access_token_key]&.strip
|
||||
session[url_key] = params[url_key]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ class Import::GitlabGroupsController < ApplicationController
|
|||
before_action :ensure_group_import_enabled
|
||||
before_action :import_rate_limit, only: %i[create]
|
||||
|
||||
feature_category :importers
|
||||
|
||||
def create
|
||||
unless file_is_valid?(group_params[:file])
|
||||
return redirect_back_or_default(options: { alert: s_('GroupImport|Unable to process group import file') })
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ class InvitesController < ApplicationController
|
|||
|
||||
respond_to :html
|
||||
|
||||
feature_category :authentication_and_authorization
|
||||
|
||||
def show
|
||||
track_new_user_invite_experiment('opened')
|
||||
accept if skip_invitation_prompt?
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ class JiraConnect::ApplicationController < ApplicationController
|
|||
skip_before_action :verify_authenticity_token
|
||||
before_action :verify_atlassian_jwt!
|
||||
|
||||
feature_category :integrations
|
||||
|
||||
attr_reader :current_jira_installation
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ class JwtController < ApplicationController
|
|||
# Add this before other actions, since we want to have the user or project
|
||||
prepend_before_action :auth_user, :authenticate_project_or_user
|
||||
|
||||
feature_category :authentication_and_authorization
|
||||
|
||||
SERVICES = {
|
||||
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService
|
||||
}.freeze
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
class NotificationSettingsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
feature_category :users
|
||||
|
||||
def create
|
||||
return render_404 unless can_read?(resource)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ class Oauth::Jira::AuthorizationsController < ApplicationController
|
|||
skip_before_action :authenticate_user!
|
||||
skip_before_action :verify_authenticity_token
|
||||
|
||||
feature_category :integrations
|
||||
|
||||
# 1. Rewire Jira OAuth initial request to our stablished OAuth authorization URL.
|
||||
def new
|
||||
session[:redirect_uri] = params['redirect_uri']
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||
|
||||
protect_from_forgery except: [:kerberos, :saml, :cas3, :failure], with: :exception, prepend: true
|
||||
|
||||
feature_category :authentication_and_authorization
|
||||
|
||||
def handle_omniauth
|
||||
omniauth_flow(Gitlab::Auth::OAuth)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ module Registrations
|
|||
before_action :check_experiment_enabled
|
||||
before_action :ensure_namespace_path_param
|
||||
|
||||
feature_category :navigation
|
||||
|
||||
def update
|
||||
current_user.experience_level = params[:experience_level]
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
|
||||
before_action :load_recaptcha, only: :new
|
||||
|
||||
feature_category :authentication_and_authorization
|
||||
|
||||
def new
|
||||
if experiment_enabled?(:signup_flow)
|
||||
track_experiment_event(:terms_opt_in, 'start')
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ module Repositories
|
|||
|
||||
prepend_before_action :authenticate_user, :parse_repo_path
|
||||
|
||||
feature_category :source_code_management
|
||||
|
||||
private
|
||||
|
||||
def download_request?
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RunnerSetupController < ApplicationController
|
||||
feature_category :continuous_integration
|
||||
|
||||
def platforms
|
||||
render json: Gitlab::Ci::RunnerInstructions::OS.merge(Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ class SearchController < ApplicationController
|
|||
|
||||
layout 'search'
|
||||
|
||||
feature_category :global_search
|
||||
|
||||
def show
|
||||
@project = search_service.project
|
||||
@group = search_service.group
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
class SentNotificationsController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
feature_category :users
|
||||
|
||||
def unsubscribe
|
||||
@sent_notification = SentNotification.for(params[:id])
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ class SessionsController < Devise::SessionsController
|
|||
# token mismatch.
|
||||
protect_from_forgery with: :exception, prepend: true, except: :destroy
|
||||
|
||||
feature_category :authentication_and_authorization
|
||||
|
||||
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'
|
||||
MAX_FAILED_LOGIN_ATTEMPTS = 5
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ class Snippets::ApplicationController < ApplicationController
|
|||
include FindSnippet
|
||||
include SnippetAuthorizations
|
||||
|
||||
feature_category :snippets
|
||||
|
||||
private
|
||||
|
||||
def authorize_read_snippet!
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ class Snippets::NotesController < ApplicationController
|
|||
before_action :authorize_read_snippet!, only: [:show, :index]
|
||||
before_action :authorize_create_note!, only: [:create]
|
||||
|
||||
feature_category :snippets
|
||||
|
||||
private
|
||||
|
||||
def note
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ class UploadsController < ApplicationController
|
|||
before_action :authorize_create_access!, only: [:create, :authorize]
|
||||
before_action :verify_workhorse_api!, only: [:authorize]
|
||||
|
||||
feature_category :not_owned
|
||||
|
||||
def uploader_class
|
||||
PersonalFileUploader
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UserCalloutsController < ApplicationController
|
||||
feature_category :navigation
|
||||
|
||||
def create
|
||||
callout = ensure_callout
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ module Users
|
|||
|
||||
layout 'terms'
|
||||
|
||||
feature_category :users
|
||||
|
||||
def index
|
||||
@redirect = redirect_path
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ class UsersController < ApplicationController
|
|||
before_action :authorize_read_user_profile!,
|
||||
only: [:calendar, :calendar_activities, :groups, :projects, :contributed_projects, :starred_projects, :snippets]
|
||||
|
||||
feature_category :users
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
|
|
|||
|
|
@ -152,6 +152,13 @@ module Types
|
|||
field :auto_merge_enabled, GraphQL::BOOLEAN_TYPE, null: false,
|
||||
description: 'Indicates if auto merge is enabled for the merge request'
|
||||
|
||||
field :approved_by, Types::UserType.connection_type, null: true,
|
||||
description: 'Users who approved the merge request'
|
||||
|
||||
def approved_by
|
||||
object.approved_by_users
|
||||
end
|
||||
|
||||
def diff_stats(path: nil)
|
||||
stats = Array.wrap(object.diff_stats&.to_a)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
module Types
|
||||
class PackageTypeEnum < BaseEnum
|
||||
::Packages::Package.package_types.keys.each do |package_type|
|
||||
value package_type.to_s.upcase, "Packages from the #{package_type} package manager", value: package_type.to_s
|
||||
value package_type.to_s.upcase, "Packages from the #{package_type.capitalize} package manager", value: package_type.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -782,6 +782,11 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def has_expired_locked_archive_artifacts?
|
||||
locked_artifacts? &&
|
||||
artifacts_expire_at.present? && artifacts_expire_at < Time.current
|
||||
end
|
||||
|
||||
def has_expiring_archive_artifacts?
|
||||
has_expiring_artifacts? && job_artifacts_archive.present?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,6 +27,13 @@ module Ci
|
|||
sha_attribute :source_sha
|
||||
sha_attribute :target_sha
|
||||
|
||||
# Ci::CreatePipelineService returns Ci::Pipeline so this is the only place
|
||||
# where we can pass additional information from the service. This accessor
|
||||
# is used for storing the processed CI YAML contents for linting purposes.
|
||||
# There is an open issue to address this:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/259010
|
||||
attr_accessor :merged_yaml
|
||||
|
||||
belongs_to :project, inverse_of: :all_pipelines
|
||||
belongs_to :user
|
||||
belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ class Packages::Event < ApplicationRecord
|
|||
belongs_to :package, optional: true
|
||||
|
||||
# FIXME: Remove debian: 9 from here when it's added to the types in package.rb model
|
||||
EVENT_SCOPES = ::Packages::Package.package_types.merge(debian: 9, container: 1000, tag: 1001).freeze
|
||||
EVENT_SCOPES = ::Packages::Package.package_types.merge(container: 1000, tag: 1001).freeze
|
||||
|
||||
enum event_scope: EVENT_SCOPES
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class Packages::Package < ApplicationRecord
|
|||
format: { with: Gitlab::Regex.generic_package_version_regex },
|
||||
if: :generic?
|
||||
|
||||
enum package_type: { maven: 1, npm: 2, conan: 3, nuget: 4, pypi: 5, composer: 6, generic: 7, golang: 8 }
|
||||
enum package_type: { maven: 1, npm: 2, conan: 3, nuget: 4, pypi: 5, composer: 6, generic: 7, golang: 8, debian: 9 }
|
||||
|
||||
scope :with_name, ->(name) { where(name: name) }
|
||||
scope :with_name_like, ->(name) { where(arel_table[:name].matches(name)) }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Display package version data acording to PyPi
|
||||
# Display package version data acording to PyPI
|
||||
# Simple API: https://warehouse.pypa.io/api-reference/legacy/#simple-project-api
|
||||
module Packages
|
||||
module Pypi
|
||||
|
|
@ -12,7 +12,7 @@ module Packages
|
|||
@project = project
|
||||
end
|
||||
|
||||
# Returns the HTML body for PyPi simple API.
|
||||
# Returns the HTML body for PyPI simple API.
|
||||
# Basically a list of package download links for a specific
|
||||
# package
|
||||
def body
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class BuildDetailsEntity < JobEntity
|
|||
browse_project_job_artifacts_path(project, build)
|
||||
end
|
||||
|
||||
expose :keep_path, if: -> (*) { (build.locked_artifacts? || build.has_expiring_archive_artifacts?) && can?(current_user, :update_build, build) } do |build|
|
||||
expose :keep_path, if: -> (*) { (build.has_expired_locked_archive_artifacts? || build.has_expiring_archive_artifacts?) && can?(current_user, :update_build, build) } do |build|
|
||||
keep_project_job_artifacts_path(project, build)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,9 @@ class PipelineEntity < Grape::Entity
|
|||
end
|
||||
|
||||
expose :failed_builds, if: -> (*) { can_retry? }, using: JobEntity do |pipeline|
|
||||
pipeline.failed_builds
|
||||
pipeline.failed_builds.each do |build|
|
||||
build.project = pipeline.project
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -2,12 +2,20 @@
|
|||
|
||||
module Ci
|
||||
class BuildReportResultService
|
||||
include Gitlab::Utils::UsageData
|
||||
|
||||
EVENT_NAME = 'i_testing_test_case_parsed'
|
||||
|
||||
def execute(build)
|
||||
return unless build.has_test_reports?
|
||||
|
||||
test_suite = generate_test_suite_report(build)
|
||||
|
||||
track_test_cases(build, test_suite)
|
||||
|
||||
build.report_results.create!(
|
||||
project_id: build.project_id,
|
||||
data: tests_params(build)
|
||||
data: tests_params(test_suite)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -17,9 +25,7 @@ module Ci
|
|||
build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new)
|
||||
end
|
||||
|
||||
def tests_params(build)
|
||||
test_suite = generate_test_suite_report(build)
|
||||
|
||||
def tests_params(test_suite)
|
||||
{
|
||||
tests: {
|
||||
name: test_suite.name,
|
||||
|
|
@ -31,5 +37,20 @@ module Ci
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
def track_test_cases(build, test_suite)
|
||||
return if Feature.disabled?(:track_unique_test_cases_parsed, build.project)
|
||||
|
||||
track_usage_event(EVENT_NAME, test_case_hashes(build, test_suite))
|
||||
end
|
||||
|
||||
def test_case_hashes(build, test_suite)
|
||||
[].tap do |hashes|
|
||||
test_suite.each_test_case do |test_case|
|
||||
key = "#{build.project_id}-#{test_suite.name}-#{test_case.key}"
|
||||
hashes << Digest::SHA256.hexdigest(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ module SystemNotes
|
|||
def relate_issue(noteable_ref)
|
||||
body = "marked this issue as related to #{noteable_ref.to_reference(noteable.project)}"
|
||||
|
||||
issue_activity_counter.track_issue_related_action(author: author) if noteable.is_a?(Issue)
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: 'relate'))
|
||||
end
|
||||
|
||||
|
|
@ -27,6 +29,8 @@ module SystemNotes
|
|||
def unrelate_issue(noteable_ref)
|
||||
body = "removed the relation with #{noteable_ref.to_reference(noteable.project)}"
|
||||
|
||||
issue_activity_counter.track_issue_unrelated_action(author: author) if noteable.is_a?(Issue)
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: 'unrelate'))
|
||||
end
|
||||
|
||||
|
|
@ -174,6 +178,8 @@ module SystemNotes
|
|||
if noteable.is_a?(ExternalIssue)
|
||||
noteable.project.external_issue_tracker.create_cross_reference_note(noteable, mentioner, author)
|
||||
else
|
||||
issue_activity_counter.track_issue_cross_referenced_action(author: author) if noteable.is_a?(Issue)
|
||||
|
||||
create_note(NoteSummary.new(noteable, noteable.project, author, body, action: 'cross_reference'))
|
||||
end
|
||||
end
|
||||
|
|
@ -208,6 +214,8 @@ module SystemNotes
|
|||
status_label = new_task.complete? ? Taskable::COMPLETED : Taskable::INCOMPLETE
|
||||
body = "marked the task **#{new_task.source}** as #{status_label}"
|
||||
|
||||
issue_activity_counter.track_issue_description_changed_action(author: author) if noteable.is_a?(Issue)
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: 'task'))
|
||||
end
|
||||
|
||||
|
|
@ -229,6 +237,8 @@ module SystemNotes
|
|||
cross_reference = noteable_ref.to_reference(project)
|
||||
body = "moved #{direction} #{cross_reference}"
|
||||
|
||||
issue_activity_counter.track_issue_moved_action(author: author) if noteable.is_a?(Issue)
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: 'moved'))
|
||||
end
|
||||
|
||||
|
|
@ -299,6 +309,9 @@ module SystemNotes
|
|||
# Returns the created Note object
|
||||
def mark_duplicate_issue(canonical_issue)
|
||||
body = "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}"
|
||||
|
||||
issue_activity_counter.track_issue_marked_as_duplicate_action(author: author) if noteable.is_a?(Issue)
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate'))
|
||||
end
|
||||
|
||||
|
|
@ -322,6 +335,14 @@ module SystemNotes
|
|||
action = noteable.discussion_locked? ? 'locked' : 'unlocked'
|
||||
body = "#{action} this #{noteable.class.to_s.titleize.downcase}"
|
||||
|
||||
if noteable.is_a?(Issue)
|
||||
if action == 'locked'
|
||||
issue_activity_counter.track_issue_locked_action(author: author)
|
||||
else
|
||||
issue_activity_counter.track_issue_unlocked_action(author: author)
|
||||
end
|
||||
end
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: action))
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@
|
|||
= f.submit s_("Profiles|Update profile settings"), class: 'btn btn-success'
|
||||
= link_to _("Cancel"), user_path(current_user), class: 'btn btn-cancel'
|
||||
|
||||
.modal.modal-profile-crop
|
||||
.modal.modal-profile-crop{ data: { cropper_css_path: ActionController::Base.helpers.stylesheet_path('lazy_bundles/cropper.css') } }
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update styling of design comment pins
|
||||
merge_request: 39797
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add more issue change events to usage ping
|
||||
merge_request: 43828
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Reduce cached SQL for JobsController#show
|
||||
merge_request: 43559
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow get approvals on merge request by GraphQL in CE
|
||||
author: Pavel Kuznetsov
|
||||
merge_request: 43325
|
||||
type: add
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Create ComplianceManagement::Framework Model
|
||||
merge_request: 43301
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add :default_branch_name column to namespace_settings
|
||||
merge_request: 42778
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Track unique number of test cases parsed
|
||||
merge_request: 41918
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix spelling of PyPI
|
||||
merge_request: 44058
|
||||
author: Peter Bittner (@bittner)
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Show keep path for expired locked artifacts.
|
||||
merge_request: 43866
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add project scoped CI lint API endpoint.
|
||||
merge_request: 42998
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Loads cropper css only when needed
|
||||
merge_request: 44137
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -194,6 +194,7 @@ module Gitlab
|
|||
config.assets.precompile << "page_bundles/milestone.css"
|
||||
config.assets.precompile << "page_bundles/todos.css"
|
||||
config.assets.precompile << "page_bundles/xterm.css"
|
||||
config.assets.precompile << "lazy_bundles/cropper.css"
|
||||
config.assets.precompile << "performance_bar.css"
|
||||
config.assets.precompile << "lib/ace.js"
|
||||
config.assets.precompile << "disable_animations.css"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: track_unique_test_cases_parsed
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41918
|
||||
rollout_issue_url:
|
||||
group: group::testing
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: usage_data_i_testing_test_case_parsed
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41918
|
||||
rollout_issue_url:
|
||||
group: group::testing
|
||||
type: development
|
||||
default_enabled: true
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddDefaultBranchNameToNamespaceSettings < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
# rubocop:disable Migration/AddLimitToTextColumns
|
||||
|
||||
# limit is added in 20200919204155_add_text_limit_to_namespace_settings_default_branch_name
|
||||
#
|
||||
def change
|
||||
add_column :namespace_settings, :default_branch_name, :text
|
||||
end
|
||||
|
||||
# rubocop:enable Migration/AddLimitToTextColumns
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTextLimitToNamespaceSettingsDefaultBranchName < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_text_limit :namespace_settings, :default_branch_name, 255
|
||||
end
|
||||
|
||||
def down
|
||||
# Down is required as `add_text_limit` is not reversible
|
||||
#
|
||||
remove_text_limit :namespace_settings, :default_branch_name
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddComplianceFrameworkModel < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
unless table_exists?(:compliance_management_frameworks)
|
||||
with_lock_retries do
|
||||
create_table :compliance_management_frameworks do |t|
|
||||
t.references :group, foreign_key: { to_table: :namespaces, on_delete: :cascade }, null: false, index: false
|
||||
t.text :name, null: false
|
||||
t.text :description, null: false
|
||||
t.text :color, null: false
|
||||
t.index [:group_id, :name], unique: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
add_text_limit :compliance_management_frameworks, :name, 255
|
||||
add_text_limit :compliance_management_frameworks, :description, 255
|
||||
add_text_limit :compliance_management_frameworks, :color, 10
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
drop_table :compliance_management_frameworks
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
f33c66297ca7848c576778dc275e42801f5f9d7cdcf8c4d2fb205d4eb9770937
|
||||
|
|
@ -0,0 +1 @@
|
|||
097cb7a36fdc831045f3a33a047f8bda6474b8165ef5fc95dbdeea45d0ac04a3
|
||||
|
|
@ -0,0 +1 @@
|
|||
a8450c6c21b1182afd06c88af18c0d9be92b0e7fdc73505c07d4ab3fddd39abf
|
||||
|
|
@ -11087,6 +11087,26 @@ CREATE SEQUENCE commit_user_mentions_id_seq
|
|||
|
||||
ALTER SEQUENCE commit_user_mentions_id_seq OWNED BY commit_user_mentions.id;
|
||||
|
||||
CREATE TABLE compliance_management_frameworks (
|
||||
id bigint NOT NULL,
|
||||
group_id bigint NOT NULL,
|
||||
name text NOT NULL,
|
||||
description text NOT NULL,
|
||||
color text NOT NULL,
|
||||
CONSTRAINT check_08cd34b2c2 CHECK ((char_length(color) <= 10)),
|
||||
CONSTRAINT check_1617e0b87e CHECK ((char_length(description) <= 255)),
|
||||
CONSTRAINT check_ab00bc2193 CHECK ((char_length(name) <= 255))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE compliance_management_frameworks_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE compliance_management_frameworks_id_seq OWNED BY compliance_management_frameworks.id;
|
||||
|
||||
CREATE TABLE container_expiration_policies (
|
||||
project_id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
|
|
@ -13609,7 +13629,9 @@ CREATE TABLE namespace_settings (
|
|||
updated_at timestamp with time zone NOT NULL,
|
||||
namespace_id integer NOT NULL,
|
||||
prevent_forking_outside_group boolean DEFAULT false NOT NULL,
|
||||
allow_mfa_for_subgroups boolean DEFAULT true NOT NULL
|
||||
allow_mfa_for_subgroups boolean DEFAULT true NOT NULL,
|
||||
default_branch_name text,
|
||||
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255))
|
||||
);
|
||||
|
||||
CREATE TABLE namespace_statistics (
|
||||
|
|
@ -17344,6 +17366,8 @@ ALTER TABLE ONLY clusters_kubernetes_namespaces ALTER COLUMN id SET DEFAULT next
|
|||
|
||||
ALTER TABLE ONLY commit_user_mentions ALTER COLUMN id SET DEFAULT nextval('commit_user_mentions_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY compliance_management_frameworks ALTER COLUMN id SET DEFAULT nextval('compliance_management_frameworks_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY container_repositories ALTER COLUMN id SET DEFAULT nextval('container_repositories_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY conversational_development_index_metrics ALTER COLUMN id SET DEFAULT nextval('conversational_development_index_metrics_id_seq'::regclass);
|
||||
|
|
@ -18377,6 +18401,9 @@ ALTER TABLE ONLY clusters
|
|||
ALTER TABLE ONLY commit_user_mentions
|
||||
ADD CONSTRAINT commit_user_mentions_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY compliance_management_frameworks
|
||||
ADD CONSTRAINT compliance_management_frameworks_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY container_expiration_policies
|
||||
ADD CONSTRAINT container_expiration_policies_pkey PRIMARY KEY (project_id);
|
||||
|
||||
|
|
@ -19445,6 +19472,8 @@ CREATE UNIQUE INDEX idx_jira_connect_subscriptions_on_installation_id_namespace_
|
|||
|
||||
CREATE INDEX idx_members_created_at_user_id_invite_token ON members USING btree (created_at) WHERE ((invite_token IS NOT NULL) AND (user_id IS NULL));
|
||||
|
||||
CREATE INDEX idx_merge_requests_on_id_and_merge_jid ON merge_requests USING btree (id, merge_jid) WHERE ((merge_jid IS NOT NULL) AND (state_id = 4));
|
||||
|
||||
CREATE INDEX idx_merge_requests_on_source_project_and_branch_state_opened ON merge_requests USING btree (source_project_id, source_branch) WHERE (state_id = 1);
|
||||
|
||||
CREATE INDEX idx_merge_requests_on_state_id_and_merge_status ON merge_requests USING btree (state_id, merge_status) WHERE ((state_id = 1) AND ((merge_status)::text = 'can_be_merged'::text));
|
||||
|
|
@ -19987,6 +20016,8 @@ CREATE INDEX index_clusters_on_user_id ON clusters USING btree (user_id);
|
|||
|
||||
CREATE UNIQUE INDEX index_commit_user_mentions_on_note_id ON commit_user_mentions USING btree (note_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_compliance_management_frameworks_on_group_id_and_name ON compliance_management_frameworks USING btree (group_id, name);
|
||||
|
||||
CREATE INDEX index_container_expiration_policies_on_next_run_at_and_enabled ON container_expiration_policies USING btree (next_run_at, enabled);
|
||||
|
||||
CREATE INDEX index_container_repositories_on_project_id ON container_repositories USING btree (project_id);
|
||||
|
|
@ -23668,6 +23699,9 @@ ALTER TABLE ONLY requirements_management_test_reports
|
|||
ALTER TABLE ONLY pool_repositories
|
||||
ADD CONSTRAINT fk_rails_d2711daad4 FOREIGN KEY (source_project_id) REFERENCES projects(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY compliance_management_frameworks
|
||||
ADD CONSTRAINT fk_rails_d3240d6339 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY group_group_links
|
||||
ADD CONSTRAINT fk_rails_d3a0488427 FOREIGN KEY (shared_group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ successfully, you must replicate their data using some other means.
|
|||
| [Maven Repository](../../../user/packages/maven_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
|
||||
| [Conan Repository](../../../user/packages/conan_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
|
||||
| [NuGet Repository](../../../user/packages/nuget_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
|
||||
| [PyPi Repository](../../../user/packages/pypi_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
|
||||
| [PyPI Repository](../../../user/packages/pypi_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
|
||||
| [Composer Repository](../../../user/packages/composer_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
|
||||
| [Versioned Terraform State](../../terraform_state.md) | **Yes** (13.5) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_terraform_state_version_replication`, enabled by default |
|
||||
| [External merge request diffs](../../merge_request_diffs.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/33817) | No | Via Object Storage provider if supported. Native Geo support (Beta). | |
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ disable enforcement. For more information, see the documentation on configuring
|
|||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
1. Run `sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml`
|
||||
1. Run `sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml`
|
||||
to confirm that Gitaly can perform callbacks to the GitLab internal API.
|
||||
|
||||
**For installations from source**
|
||||
|
|
@ -364,7 +364,7 @@ disable enforcement. For more information, see the documentation on configuring
|
|||
```
|
||||
|
||||
1. Save the files and [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
1. Run `sudo -u git /home/git/gitlab-shell/bin/check -config /home/git/gitlab-shell/config.yml`
|
||||
1. Run `sudo -u git /home/git/gitaly/gitaly-hooks check /home/git/gitaly/config.toml`
|
||||
to confirm that Gitaly can perform callbacks to the GitLab internal API.
|
||||
|
||||
### Configure Gitaly clients
|
||||
|
|
@ -711,6 +711,15 @@ Gitaly Go process. Some examples of things that are implemented in `gitaly-ruby`
|
|||
- RPCs that deal with wikis.
|
||||
- RPCs that create commits on behalf of a user, such as merge commits.
|
||||
|
||||
We recommend:
|
||||
|
||||
- At least 300MB memory per worker.
|
||||
- No more than one worker per core.
|
||||
|
||||
NOTE: **Note:**
|
||||
`gitaly-ruby` is planned to be eventually removed. To track progress, see the
|
||||
[Remove the Gitaly-Ruby sidecar](https://gitlab.com/groups/gitlab-org/-/epics/2862) epic.
|
||||
|
||||
### Configure number of `gitaly-ruby` workers
|
||||
|
||||
`gitaly-ruby` has much less capacity than Gitaly implemented in Go. If your Gitaly server has to handle lots of
|
||||
|
|
|
|||
|
|
@ -873,10 +873,10 @@ Particular attention should be shown to:
|
|||
gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Verify each `gitlab-shell` on each Gitaly node can reach GitLab. On each Gitaly node run:
|
||||
1. Verify on each Gitaly node the Git Hooks can reach GitLab. On each Gitaly node run:
|
||||
|
||||
```shell
|
||||
/opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
/opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
1. Verify that GitLab can reach Praefect:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ The Packages feature allows GitLab to act as a repository for the following:
|
|||
|
||||
| Software repository | Description | Available in GitLab version |
|
||||
| ------------------- | ----------- | --------------------------- |
|
||||
| [PyPi Repository](../../user/packages/pypi_repository/index.md) | The GitLab PyPi Repository enables every project in GitLab to have its own space to store [PyPi](https://pypi.org/) packages. | 12.10+ |
|
||||
| [PyPI Repository](../../user/packages/pypi_repository/index.md) | The GitLab PyPI Repository enables every project in GitLab to have its own space to store [PyPI](https://pypi.org/) packages. | 12.10+ |
|
||||
| [Composer Repository](../../user/packages/composer_repository/index.md) | The GitLab Composer Repository enables every project in GitLab to have its own space to store [Composer](https://getcomposer.org/) packages. | 13.1+ |
|
||||
| [NuGet Repository](../../user/packages/nuget_repository/index.md) | The GitLab NuGet Repository enables every project in GitLab to have its own space to store [NuGet](https://www.nuget.org/) packages. | 12.8+ |
|
||||
| [Conan Repository](../../user/packages/conan_repository/index.md) | The GitLab Conan Repository enables every project in GitLab to have its own space to store [Conan](https://conan.io/) packages. | 12.4+ |
|
||||
|
|
|
|||
|
|
@ -1879,7 +1879,7 @@ On each node perform the following:
|
|||
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
|
|
|
|||
|
|
@ -1879,7 +1879,7 @@ On each node perform the following:
|
|||
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ To configure the Gitaly server:
|
|||
1. Confirm that Gitaly can perform callbacks to the internal API:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
### Gitaly TLS support
|
||||
|
|
|
|||
|
|
@ -1223,7 +1223,7 @@ On each node:
|
|||
1. Confirm that Gitaly can perform callbacks to the internal API:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
1. Verify the GitLab services are running:
|
||||
|
|
|
|||
|
|
@ -1879,7 +1879,7 @@ On each node perform the following:
|
|||
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
|
|
|
|||
|
|
@ -1222,7 +1222,7 @@ On each node:
|
|||
1. Confirm that Gitaly can perform callbacks to the internal API:
|
||||
|
||||
```shell
|
||||
sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
|
||||
sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
|
||||
```
|
||||
|
||||
1. Verify the GitLab services are running:
|
||||
|
|
|
|||
|
|
@ -11619,6 +11619,7 @@ type Mutation {
|
|||
toggleAwardEmoji(input: ToggleAwardEmojiInput!): ToggleAwardEmojiPayload @deprecated(reason: "Use awardEmojiToggle. Deprecated in 13.2")
|
||||
updateAlertStatus(input: UpdateAlertStatusInput!): UpdateAlertStatusPayload
|
||||
updateBoard(input: UpdateBoardInput!): UpdateBoardPayload
|
||||
updateBoardEpicUserPreferences(input: UpdateBoardEpicUserPreferencesInput!): UpdateBoardEpicUserPreferencesPayload
|
||||
updateBoardList(input: UpdateBoardListInput!): UpdateBoardListPayload
|
||||
updateContainerExpirationPolicy(input: UpdateContainerExpirationPolicyInput!): UpdateContainerExpirationPolicyPayload
|
||||
updateEpic(input: UpdateEpicInput!): UpdateEpicPayload
|
||||
|
|
@ -12257,42 +12258,47 @@ type PackageFileRegistryEdge {
|
|||
|
||||
enum PackageTypeEnum {
|
||||
"""
|
||||
Packages from the composer package manager
|
||||
Packages from the Composer package manager
|
||||
"""
|
||||
COMPOSER
|
||||
|
||||
"""
|
||||
Packages from the conan package manager
|
||||
Packages from the Conan package manager
|
||||
"""
|
||||
CONAN
|
||||
|
||||
"""
|
||||
Packages from the generic package manager
|
||||
Packages from the Debian package manager
|
||||
"""
|
||||
DEBIAN
|
||||
|
||||
"""
|
||||
Packages from the Generic package manager
|
||||
"""
|
||||
GENERIC
|
||||
|
||||
"""
|
||||
Packages from the golang package manager
|
||||
Packages from the Golang package manager
|
||||
"""
|
||||
GOLANG
|
||||
|
||||
"""
|
||||
Packages from the maven package manager
|
||||
Packages from the Maven package manager
|
||||
"""
|
||||
MAVEN
|
||||
|
||||
"""
|
||||
Packages from the npm package manager
|
||||
Packages from the Npm package manager
|
||||
"""
|
||||
NPM
|
||||
|
||||
"""
|
||||
Packages from the nuget package manager
|
||||
Packages from the Nuget package manager
|
||||
"""
|
||||
NUGET
|
||||
|
||||
"""
|
||||
Packages from the pypi package manager
|
||||
Packages from the Pypi package manager
|
||||
"""
|
||||
PYPI
|
||||
}
|
||||
|
|
@ -18470,6 +18476,51 @@ type UpdateAlertStatusPayload {
|
|||
todo: Todo
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated input type of UpdateBoardEpicUserPreferences
|
||||
"""
|
||||
input UpdateBoardEpicUserPreferencesInput {
|
||||
"""
|
||||
The board global ID
|
||||
"""
|
||||
boardId: BoardID!
|
||||
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""
|
||||
Whether the epic should be collapsed in the board
|
||||
"""
|
||||
collapsed: Boolean!
|
||||
|
||||
"""
|
||||
ID of an epic to set preferences for
|
||||
"""
|
||||
epicId: EpicID!
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated return type of UpdateBoardEpicUserPreferences
|
||||
"""
|
||||
type UpdateBoardEpicUserPreferencesPayload {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""
|
||||
User preferences for the epic in the board after mutation
|
||||
"""
|
||||
epicUserPreferences: BoardEpicUserPreferences
|
||||
|
||||
"""
|
||||
Errors encountered during execution of the mutation.
|
||||
"""
|
||||
errors: [String!]!
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated input type of UpdateBoard
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -34109,6 +34109,33 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updateBoardEpicUserPreferences",
|
||||
"description": null,
|
||||
"args": [
|
||||
{
|
||||
"name": "input",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "UpdateBoardEpicUserPreferencesInput",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "UpdateBoardEpicUserPreferencesPayload",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updateBoardList",
|
||||
"description": null,
|
||||
|
|
@ -36318,49 +36345,55 @@
|
|||
"enumValues": [
|
||||
{
|
||||
"name": "MAVEN",
|
||||
"description": "Packages from the maven package manager",
|
||||
"description": "Packages from the Maven package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "NPM",
|
||||
"description": "Packages from the npm package manager",
|
||||
"description": "Packages from the Npm package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "CONAN",
|
||||
"description": "Packages from the conan package manager",
|
||||
"description": "Packages from the Conan package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "NUGET",
|
||||
"description": "Packages from the nuget package manager",
|
||||
"description": "Packages from the Nuget package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "PYPI",
|
||||
"description": "Packages from the pypi package manager",
|
||||
"description": "Packages from the Pypi package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "COMPOSER",
|
||||
"description": "Packages from the composer package manager",
|
||||
"description": "Packages from the Composer package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "GENERIC",
|
||||
"description": "Packages from the generic package manager",
|
||||
"description": "Packages from the Generic package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "GOLANG",
|
||||
"description": "Packages from the golang package manager",
|
||||
"description": "Packages from the Golang package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "DEBIAN",
|
||||
"description": "Packages from the Debian package manager",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
|
|
@ -54019,6 +54052,136 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "UpdateBoardEpicUserPreferencesInput",
|
||||
"description": "Autogenerated input type of UpdateBoardEpicUserPreferences",
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "boardId",
|
||||
"description": "The board global ID",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "BoardID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "epicId",
|
||||
"description": "ID of an epic to set preferences for",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "EpicID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "collapsed",
|
||||
"description": "Whether the epic should be collapsed in the board",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Boolean",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "clientMutationId",
|
||||
"description": "A unique identifier for the client performing the mutation.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "UpdateBoardEpicUserPreferencesPayload",
|
||||
"description": "Autogenerated return type of UpdateBoardEpicUserPreferences",
|
||||
"fields": [
|
||||
{
|
||||
"name": "clientMutationId",
|
||||
"description": "A unique identifier for the client performing the mutation.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "epicUserPreferences",
|
||||
"description": "User preferences for the epic in the board after mutation",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "BoardEpicUserPreferences",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "errors",
|
||||
"description": "Errors encountered during execution of the mutation.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [
|
||||
|
||||
],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "UpdateBoardInput",
|
||||
|
|
|
|||
|
|
@ -2623,6 +2623,16 @@ Autogenerated return type of UpdateAlertStatus.
|
|||
| `issue` | Issue | The issue created after mutation |
|
||||
| `todo` | Todo | The todo after mutation |
|
||||
|
||||
### UpdateBoardEpicUserPreferencesPayload
|
||||
|
||||
Autogenerated return type of UpdateBoardEpicUserPreferences.
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
|
||||
| `epicUserPreferences` | BoardEpicUserPreferences | User preferences for the epic in the board after mutation |
|
||||
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
||||
|
||||
### UpdateBoardListPayload
|
||||
|
||||
Autogenerated return type of UpdateBoardList.
|
||||
|
|
@ -3416,14 +3426,15 @@ Values for sorting projects.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| `COMPOSER` | Packages from the composer package manager |
|
||||
| `CONAN` | Packages from the conan package manager |
|
||||
| `GENERIC` | Packages from the generic package manager |
|
||||
| `GOLANG` | Packages from the golang package manager |
|
||||
| `MAVEN` | Packages from the maven package manager |
|
||||
| `NPM` | Packages from the npm package manager |
|
||||
| `NUGET` | Packages from the nuget package manager |
|
||||
| `PYPI` | Packages from the pypi package manager |
|
||||
| `COMPOSER` | Packages from the Composer package manager |
|
||||
| `CONAN` | Packages from the Conan package manager |
|
||||
| `DEBIAN` | Packages from the Debian package manager |
|
||||
| `GENERIC` | Packages from the Generic package manager |
|
||||
| `GOLANG` | Packages from the Golang package manager |
|
||||
| `MAVEN` | Packages from the Maven package manager |
|
||||
| `NPM` | Packages from the Npm package manager |
|
||||
| `NUGET` | Packages from the Nuget package manager |
|
||||
| `PYPI` | Packages from the Pypi package manager |
|
||||
|
||||
### PipelineConfigSourceEnum
|
||||
|
||||
|
|
|
|||
|
|
@ -94,3 +94,51 @@ Example response:
|
|||
"merged_config": "---\n:another_test:\n :stage: test\n :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n"
|
||||
}
|
||||
```
|
||||
|
||||
## Validate a project's CI configuration
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231352) in GitLab 13.5.
|
||||
|
||||
Checks if a project's latest (`HEAD` of the project's default branch)
|
||||
`.gitlab-ci.yml` configuration is valid. This endpoint uses all namespace
|
||||
specific data available, including variables, local includes, and so on.
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/ci/lint
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ---------- | ------- | -------- | -------- |
|
||||
| `dry_run` | boolean | no | Run pipeline creation simulation, or only do static check. |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl "https://gitlab.example.com/api/v4/projects/:id/ci/lint"
|
||||
```
|
||||
|
||||
Example responses:
|
||||
|
||||
- Valid config:
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"merged_yaml": "---\n:test_job:\n :script: echo 1\n",
|
||||
"errors": [],
|
||||
"warnings": []
|
||||
}
|
||||
```
|
||||
|
||||
- Invalid config:
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": false,
|
||||
"merged_yaml": "---\n:test_job:\n :script: echo 1\n",
|
||||
"errors": [
|
||||
"jobs config should contain at least one visible job"
|
||||
],
|
||||
"warnings": []
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ Example response:
|
|||
|
||||
- GitLab Geo
|
||||
- GitLab Shell's `bin/check`
|
||||
- Gitaly
|
||||
|
||||
## Get new 2FA recovery codes using an SSH key
|
||||
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ The following are some available Rake tasks:
|
|||
| [`sudo gitlab-rake gitlab:elastic:index`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Enables Elasticsearch indexing and run `gitlab:elastic:create_empty_index`, `gitlab:elastic:clear_index_status`, `gitlab:elastic:index_projects`, and `gitlab:elastic:index_snippets`. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:index_projects`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Iterates over all projects and queues Sidekiq jobs to index them in the background. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:index_projects_status`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Determines the overall status of the indexing. It is done by counting the total number of indexed projects, dividing by a count of the total number of projects, then multiplying by 100. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:clear_index_status`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Deletes all instances of IndexStatus for all projects. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:clear_index_status`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Deletes all instances of IndexStatus for all projects. Note that this command will result in a complete wipe of the index, and it should be used with caution. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:create_empty_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Generates an empty index and assigns an alias for it on the Elasticsearch side only if it doesn't already exist. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:delete_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Removes the GitLab index and alias (if exists) on the Elasticsearch instance. |
|
||||
| [`sudo gitlab-rake gitlab:elastic:recreate_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Wrapper task for `gitlab:elastic:delete_index[<TARGET_NAME>]` and `gitlab:elastic:create_empty_index[<TARGET_NAME>]`. |
|
||||
|
|
|
|||
|
|
@ -914,7 +914,7 @@ restore:
|
|||
sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
|
||||
```
|
||||
|
||||
Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
|
||||
Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:restore` instead.
|
||||
|
||||
CAUTION: **Warning:**
|
||||
`gitlab-rake gitlab:backup:restore` doesn't set the correct file system
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ group: Package
|
|||
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 PyPi Repository
|
||||
# GitLab PyPI Repository
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208747) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
|
||||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
|
||||
|
||||
With the GitLab PyPi Repository, every project can have its own space to store PyPi packages.
|
||||
With the GitLab PyPI Repository, every project can have its own space to store PyPI packages.
|
||||
|
||||
The GitLab PyPi Repository works with:
|
||||
The GitLab PyPI Repository works with:
|
||||
|
||||
- [pip](https://pypi.org/project/pip/)
|
||||
- [twine](https://pypi.org/project/twine/)
|
||||
|
|
@ -20,13 +20,13 @@ The GitLab PyPi Repository works with:
|
|||
|
||||
You need a recent version of [pip](https://pypi.org/project/pip/) and [twine](https://pypi.org/project/twine/).
|
||||
|
||||
## Enabling the PyPi Repository
|
||||
## Enabling the PyPI Repository
|
||||
|
||||
NOTE: **Note:**
|
||||
This option is available only if your GitLab administrator has
|
||||
[enabled support for the Package Registry](../../../administration/packages/index.md).
|
||||
|
||||
After the PyPi Repository is enabled, it is available for all new projects
|
||||
After the PyPI Repository is enabled, it is available for all new projects
|
||||
by default. To enable it for existing projects, or if you want to disable it:
|
||||
|
||||
1. Navigate to your project's **Settings > General > Visibility, project features, permissions**.
|
||||
|
|
@ -37,8 +37,8 @@ You should then be able to see the **Packages & Registries** section on the left
|
|||
|
||||
## Getting started
|
||||
|
||||
This section covers creating a new example PyPi package to upload. This is a
|
||||
quickstart to test out the **GitLab PyPi Registry**. If you already understand how
|
||||
This section covers creating a new example PyPI package to upload. This is a
|
||||
quickstart to test out the **GitLab PyPI Registry**. If you already understand how
|
||||
to build and publish your own packages, move on to the [next section](#adding-the-gitlab-pypi-repository-as-a-source).
|
||||
|
||||
### Create a project
|
||||
|
|
@ -152,10 +152,10 @@ And confirm your output matches the below:
|
|||
mypypipackage-0.0.1-py3-none-any.whl mypypipackage-0.0.1.tar.gz
|
||||
```
|
||||
|
||||
Our package is now all set up and ready to be uploaded to the **GitLab PyPi
|
||||
Our package is now all set up and ready to be uploaded to the **GitLab PyPI
|
||||
Package Registry**. Before we do so, we next need to set up authentication.
|
||||
|
||||
## Adding the GitLab PyPi Repository as a source
|
||||
## Adding the GitLab PyPI Repository as a source
|
||||
|
||||
### Authenticating with a personal access token
|
||||
|
||||
|
|
@ -256,7 +256,7 @@ TWINE_PASSWORD=<personal_access_token or deploy_token> TWINE_USERNAME=<username
|
|||
```
|
||||
|
||||
If you did not follow the guide above, then you need to ensure your package
|
||||
has been properly built and you [created a PyPi package with `setuptools`](https://packaging.python.org/tutorials/packaging-projects/).
|
||||
has been properly built and you [created a PyPI package with `setuptools`](https://packaging.python.org/tutorials/packaging-projects/).
|
||||
|
||||
You can then upload your package using the following command:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Entities
|
||||
module Ci
|
||||
module Lint
|
||||
class Result < Grape::Entity
|
||||
expose :valid?, as: :valid
|
||||
expose :errors
|
||||
expose :warnings
|
||||
expose :merged_yaml
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -25,5 +25,24 @@ module API
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
desc 'Validation of .gitlab-ci.yml content' do
|
||||
detail 'This feature was introduced in GitLab 13.5.'
|
||||
end
|
||||
params do
|
||||
optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
|
||||
end
|
||||
get ':id/ci/lint' do
|
||||
authorize! :download_code, user_project
|
||||
|
||||
content = user_project.repository.gitlab_ci_yml_for(user_project.commit.id, user_project.ci_config_path_or_default)
|
||||
result = Gitlab::Ci::Lint
|
||||
.new(project: user_project, current_user: current_user)
|
||||
.validate(content, dry_run: params[:dry_run])
|
||||
|
||||
present result, with: Entities::Ci::Lint::Result, current_user: current_user
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ module Gitlab
|
|||
module Ci
|
||||
class Lint
|
||||
class Result
|
||||
attr_reader :jobs, :errors, :warnings
|
||||
attr_reader :jobs, :merged_yaml, :errors, :warnings
|
||||
|
||||
def initialize(jobs:, errors:, warnings:)
|
||||
def initialize(jobs:, merged_yaml:, errors:, warnings:)
|
||||
@jobs = jobs
|
||||
@merged_yaml = merged_yaml
|
||||
@errors = errors
|
||||
@warnings = warnings
|
||||
end
|
||||
|
|
@ -39,6 +40,7 @@ module Gitlab
|
|||
|
||||
Result.new(
|
||||
jobs: dry_run_convert_to_jobs(pipeline.stages),
|
||||
merged_yaml: pipeline.merged_yaml,
|
||||
errors: pipeline.error_messages.map(&:content),
|
||||
warnings: pipeline.warning_messages(limit: ::Gitlab::Ci::Warnings::MAX_LIMIT).map(&:content)
|
||||
)
|
||||
|
|
@ -54,6 +56,7 @@ module Gitlab
|
|||
|
||||
Result.new(
|
||||
jobs: static_validation_convert_to_jobs(result),
|
||||
merged_yaml: result.merged_yaml,
|
||||
errors: result.errors,
|
||||
warnings: result.warnings.take(::Gitlab::Ci::Warnings::MAX_LIMIT) # rubocop: disable CodeReuse/ActiveRecord
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ module Gitlab
|
|||
error(result.errors.first, config_error: true)
|
||||
end
|
||||
|
||||
@pipeline.merged_yaml = result.merged_yaml
|
||||
|
||||
rescue => ex
|
||||
Gitlab::ErrorTracking.track_exception(ex,
|
||||
project_id: project.id,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Gitlab
|
|||
@attachment = params.fetch(:attachment, nil)
|
||||
@job = params.fetch(:job, nil)
|
||||
|
||||
@key = sanitize_key_name("#{classname}_#{name}")
|
||||
@key = hash_key("#{classname}_#{name}")
|
||||
end
|
||||
|
||||
def has_attachment?
|
||||
|
|
@ -42,8 +42,8 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def sanitize_key_name(key)
|
||||
key.gsub(/[^0-9A-Za-z]/, '-')
|
||||
def hash_key(key)
|
||||
Digest::SHA256.hexdigest(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,18 +12,24 @@ module Gitlab
|
|||
def initialize(name = nil)
|
||||
@name = name
|
||||
@test_cases = {}
|
||||
@all_test_cases = []
|
||||
@total_time = 0.0
|
||||
@duplicate_cases = []
|
||||
end
|
||||
|
||||
def add_test_case(test_case)
|
||||
@duplicate_cases << test_case if existing_key?(test_case)
|
||||
|
||||
@test_cases[test_case.status] ||= {}
|
||||
@test_cases[test_case.status][test_case.key] = test_case
|
||||
@total_time += test_case.execution_time
|
||||
end
|
||||
|
||||
def each_test_case
|
||||
@test_cases.each do |status, test_cases|
|
||||
test_cases.values.each do |test_case|
|
||||
yield test_case
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def total_count
|
||||
return 0 if suite_error
|
||||
|
|
@ -86,10 +92,6 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def existing_key?(test_case)
|
||||
@test_cases[test_case.status]&.key?(test_case.key)
|
||||
end
|
||||
|
||||
def sort_by_status
|
||||
@test_cases = @test_cases.sort_by { |status, _| Gitlab::Ci::Reports::TestCase::STATUS_TYPES.index(status) }.to_h
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
module Gitlab
|
||||
module Redis
|
||||
class HLL
|
||||
BATCH_SIZE = 300
|
||||
KEY_REGEX = %r{\A(\w|-|:)*\{\w*\}(\w|-|:)*\z}.freeze
|
||||
KeyFormatError = Class.new(StandardError)
|
||||
|
||||
|
|
@ -29,17 +30,24 @@ module Gitlab
|
|||
# 2020-216-{project_action}
|
||||
# i_{analytics}_dev_ops_score-2020-32
|
||||
def add(key:, value:, expiry:)
|
||||
unless KEY_REGEX.match?(key)
|
||||
raise KeyFormatError.new("Invalid key format. #{key} key should have changeable parts in curly braces. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands")
|
||||
end
|
||||
validate_key!(key)
|
||||
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
redis.multi do |multi|
|
||||
multi.pfadd(key, value)
|
||||
Array.wrap(value).each_slice(BATCH_SIZE) { |batch| multi.pfadd(key, batch) }
|
||||
|
||||
multi.expire(key, expiry)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_key!(key)
|
||||
return if KEY_REGEX.match?(key)
|
||||
|
||||
raise KeyFormatError.new("Invalid key format. #{key} key should have changeable parts in curly braces. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,13 @@ module Gitlab
|
|||
ISSUE_REOPENED = 'g_project_management_issue_reopened'
|
||||
ISSUE_TITLE_CHANGED = 'g_project_management_issue_title_changed'
|
||||
ISSUE_WEIGHT_CHANGED = 'g_project_management_issue_weight_changed'
|
||||
ISSUE_CROSS_REFERENCED = 'g_project_management_issue_cross_referenced'
|
||||
ISSUE_MOVED = 'g_project_management_issue_moved'
|
||||
ISSUE_RELATED = 'g_project_management_issue_related'
|
||||
ISSUE_UNRELATED = 'g_project_management_issue_unrelated'
|
||||
ISSUE_MARKED_AS_DUPLICATE = 'g_project_management_issue_marked_as_duplicate'
|
||||
ISSUE_LOCKED = 'g_project_management_issue_locked'
|
||||
ISSUE_UNLOCKED = 'g_project_management_issue_unlocked'
|
||||
|
||||
class << self
|
||||
def track_issue_created_action(author:, time: Time.zone.now)
|
||||
|
|
@ -67,6 +74,34 @@ module Gitlab
|
|||
track_unique_action(ISSUE_WEIGHT_CHANGED, author, time)
|
||||
end
|
||||
|
||||
def track_issue_cross_referenced_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_CROSS_REFERENCED, author, time)
|
||||
end
|
||||
|
||||
def track_issue_moved_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_MOVED, author, time)
|
||||
end
|
||||
|
||||
def track_issue_related_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_RELATED, author, time)
|
||||
end
|
||||
|
||||
def track_issue_unrelated_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_UNRELATED, author, time)
|
||||
end
|
||||
|
||||
def track_issue_marked_as_duplicate_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_MARKED_AS_DUPLICATE, author, time)
|
||||
end
|
||||
|
||||
def track_issue_locked_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_LOCKED, author, time)
|
||||
end
|
||||
|
||||
def track_issue_unlocked_action(author:, time: Time.zone.now)
|
||||
track_unique_action(ISSUE_UNLOCKED, author, time)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_unique_action(action, author, time)
|
||||
|
|
|
|||
|
|
@ -185,6 +185,11 @@
|
|||
redis_slot: incident_management
|
||||
category: incident_management
|
||||
aggregation: weekly
|
||||
# Testing category
|
||||
- name: i_testing_test_case_parsed
|
||||
category: testing
|
||||
redis_slot: testing
|
||||
aggregation: weekly
|
||||
# Project Management group
|
||||
- name: g_project_management_issue_title_changed
|
||||
category: issues_edit
|
||||
|
|
@ -234,3 +239,31 @@
|
|||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_cross_referenced
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_moved
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_related
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_unrelated
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_marked_as_duplicate
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_locked
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
- name: g_project_management_issue_unlocked
|
||||
category: issues_edit
|
||||
redis_slot: project_management
|
||||
aggregation: daily
|
||||
|
|
|
|||
|
|
@ -18305,7 +18305,7 @@ msgstr ""
|
|||
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|PyPi"
|
||||
msgid "PackageRegistry|PyPI"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Recipe: %{recipe}"
|
||||
|
|
@ -18389,7 +18389,7 @@ msgstr ""
|
|||
msgid "PackageType|NuGet"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageType|PyPi"
|
||||
msgid "PackageType|PyPI"
|
||||
msgstr ""
|
||||
|
||||
msgid "Packages"
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ function run_task() {
|
|||
local ruby_cmd="${1}"
|
||||
local task_runner_pod=$(get_pod "task-runner")
|
||||
|
||||
kubectl exec -it --namespace "${namespace}" "${task_runner_pod}" -- gitlab-rails runner "${ruby_cmd}"
|
||||
kubectl exec --namespace "${namespace}" "${task_runner_pod}" -- gitlab-rails runner "${ruby_cmd}"
|
||||
}
|
||||
|
||||
function disable_sign_ups() {
|
||||
|
|
@ -150,7 +150,7 @@ function disable_sign_ups() {
|
|||
|
||||
# Create the root token
|
||||
local ruby_cmd="token = User.find_by_username('root').personal_access_tokens.create(scopes: [:api], name: 'Token to disable sign-ups'); token.set_token('${REVIEW_APPS_ROOT_TOKEN}'); begin; token.save!; rescue(ActiveRecord::RecordNotUnique); end"
|
||||
run_task "${ruby_cmd}"
|
||||
retry "run_task \"${ruby_cmd}\""
|
||||
|
||||
# Disable sign-ups
|
||||
local signup_enabled=$(retry 'curl --silent --show-error --request PUT --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" "${CI_ENVIRONMENT_URL}/api/v4/application/settings?signup_enabled=false" | jq ".signup_enabled"')
|
||||
|
|
|
|||
|
|
@ -24,19 +24,19 @@ RSpec.describe "Every controller" do
|
|||
let_it_be(:routes_without_category) do
|
||||
controller_actions.map do |controller, action|
|
||||
next if controller.feature_category_for_action(action)
|
||||
next unless controller.to_s.start_with?('B', 'C', 'D', 'E', 'F', 'Projects::MergeRequestsController')
|
||||
|
||||
next unless controller.to_s.start_with?('B', 'C', 'D', 'E', 'F',
|
||||
'H', 'I', 'J', 'K', 'L',
|
||||
'M', 'N', 'O', 'Q', 'R',
|
||||
'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z',
|
||||
'Projects::MergeRequestsController')
|
||||
|
||||
"#{controller}##{action}"
|
||||
end.compact
|
||||
end
|
||||
|
||||
it "has feature categories" do
|
||||
routes_without_category.map { |x| x.split('#') }.group_by(&:first).each do |controller, actions|
|
||||
puts controller
|
||||
puts actions.map { |x| ":#{x.last}" }.sort.join(', ')
|
||||
puts ''
|
||||
end
|
||||
|
||||
expect(routes_without_category).to be_empty, "#{routes_without_category} did not have a category"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -197,16 +197,40 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
|
|||
context 'with not expiry date' do
|
||||
let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
|
||||
|
||||
it 'exposes needed information' do
|
||||
get_show_json
|
||||
context 'when artifacts are unlocked' do
|
||||
before do
|
||||
job.pipeline.unlocked!
|
||||
end
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('job/job_details')
|
||||
expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
|
||||
expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
|
||||
expect(json_response['artifact']).not_to have_key('keep_path')
|
||||
expect(json_response['artifact']).not_to have_key('expired')
|
||||
expect(json_response['artifact']).not_to have_key('expired_at')
|
||||
it 'exposes needed information' do
|
||||
get_show_json
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('job/job_details')
|
||||
expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
|
||||
expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
|
||||
expect(json_response['artifact']).not_to have_key('keep_path')
|
||||
expect(json_response['artifact']).not_to have_key('expired')
|
||||
expect(json_response['artifact']).not_to have_key('expired_at')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when artifacts are locked' do
|
||||
before do
|
||||
job.pipeline.artifacts_locked!
|
||||
end
|
||||
|
||||
it 'exposes needed information' do
|
||||
get_show_json
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('job/job_details')
|
||||
expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
|
||||
expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
|
||||
expect(json_response['artifact']).not_to have_key('keep_path')
|
||||
expect(json_response['artifact']).not_to have_key('expired')
|
||||
expect(json_response['artifact']).not_to have_key('expired_at')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
factory :debian_package do
|
||||
package_type { :debian }
|
||||
end
|
||||
|
||||
factory :npm_package do
|
||||
sequence(:name) { |n| "@#{project.root_namespace.path}/package-#{n}"}
|
||||
version { '1.0.0' }
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue