Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e6b6fb6028
commit
fc0afaf7da
|
|
@ -633,7 +633,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/project_statistics.md @aqualls
|
||||
/doc/api/project_templates.md @aqualls
|
||||
/doc/api/project_vulnerabilities.md @aqualls
|
||||
/doc/api/projects.md @msedlakjakubowski
|
||||
/doc/api/projects.md @lciutacu
|
||||
/doc/api/protected_branches.md @aqualls
|
||||
/doc/api/protected_environments.md @rdickenson
|
||||
/doc/api/protected_tags.md @aqualls
|
||||
|
|
@ -766,6 +766,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/gitaly.md @eread
|
||||
/doc/development/gitlab_flavored_markdown/ @ashrafkhamis
|
||||
/doc/development/gitlab_flavored_markdown/specification_guide/ @ashrafkhamis
|
||||
/doc/development/gitlab_shell/ @aqualls
|
||||
/doc/development/graphql_guide/ @ashrafkhamis
|
||||
/doc/development/graphql_guide/batchloader.md @aqualls
|
||||
/doc/development/i18n/ @eread
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { debounce } from 'lodash';
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { backOff } from '~/lib/utils/common_utils';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import statusCodes from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { __, s__ } from '~/locale';
|
||||
import { queryTypes, formDataValidator } from '../constants';
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ function backOffRequest(makeRequestCallback) {
|
|||
return backOff((next, stop) => {
|
||||
makeRequestCallback()
|
||||
.then((resp) => {
|
||||
if (resp.status === statusCodes.OK) {
|
||||
if (resp.status === HTTP_STATUS_OK) {
|
||||
stop(resp);
|
||||
} else {
|
||||
next();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { createAlert, VARIANT_WARNING } from '~/flash';
|
|||
import { diffViewerModes } from '~/ide/constants';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
import httpStatusCodes, { HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import Poll from '~/lib/utils/poll';
|
||||
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
|
||||
import { __, s__ } from '~/locale';
|
||||
|
|
@ -248,7 +248,7 @@ export const fetchCoverageFiles = ({ commit, state }) => {
|
|||
data: state.endpointCoverage,
|
||||
method: 'getCoverageReports',
|
||||
successCallback: ({ status, data }) => {
|
||||
if (status === httpStatusCodes.OK) {
|
||||
if (status === HTTP_STATUS_OK) {
|
||||
commit(types.SET_COVERAGE_DATA, data);
|
||||
|
||||
coveragePoll.stop();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export const HTTP_STATUS_ABORTED = 0;
|
||||
export const HTTP_STATUS_OK = 200;
|
||||
export const HTTP_STATUS_CREATED = 201;
|
||||
export const HTTP_STATUS_ACCEPTED = 202;
|
||||
export const HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
|
|
@ -28,7 +29,7 @@ const httpStatusCodes = {
|
|||
};
|
||||
|
||||
export const successCodes = [
|
||||
httpStatusCodes.OK,
|
||||
HTTP_STATUS_OK,
|
||||
HTTP_STATUS_CREATED,
|
||||
HTTP_STATUS_ACCEPTED,
|
||||
HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import httpStatusCodes from './http_status';
|
||||
import { HTTP_STATUS_OK } from './http_status';
|
||||
import Poll from './poll';
|
||||
|
||||
/**
|
||||
|
|
@ -30,7 +30,7 @@ export default (url, config = {}) =>
|
|||
data: { url, config },
|
||||
method: 'axiosGet',
|
||||
successCallback: (response) => {
|
||||
if (response.status === httpStatusCodes.OK) {
|
||||
if (response.status === HTTP_STATUS_OK) {
|
||||
resolve(response);
|
||||
eTagPoll.stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { backOff } from '~/lib/utils/common_utils';
|
||||
import statusCodes, { HTTP_STATUS_ACCEPTED } from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_ACCEPTED, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { __, s__ } from '~/locale';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ export const requestCreateProject = ({ dispatch, state, commit }) => {
|
|||
export const requestCreateProjectStatus = ({ dispatch, state }, jobId) => {
|
||||
backOffRequest(() => axios.get(state.createProjectStatusEndpoint, { params: { job_id: jobId } }))
|
||||
.then((resp) => {
|
||||
if (resp.status === statusCodes.OK) {
|
||||
if (resp.status === HTTP_STATUS_OK) {
|
||||
dispatch('requestCreateProjectSuccess', resp.data);
|
||||
}
|
||||
})
|
||||
|
|
@ -95,7 +95,7 @@ export const requestDeleteProject = ({ dispatch, state, commit }) => {
|
|||
export const requestDeleteProjectStatus = ({ dispatch, state }, jobId) => {
|
||||
backOffRequest(() => axios.get(state.deleteProjectStatusEndpoint, { params: { job_id: jobId } }))
|
||||
.then((resp) => {
|
||||
if (resp.status === statusCodes.OK) {
|
||||
if (resp.status === HTTP_STATUS_OK) {
|
||||
dispatch('requestDeleteProjectSuccess', resp.data);
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,24 +6,43 @@ export default {
|
|||
GlIcon,
|
||||
},
|
||||
props: {
|
||||
count: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
href: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
ariaLabel() {
|
||||
return `${this.label} ${this.count}`;
|
||||
},
|
||||
component() {
|
||||
return this.href ? 'a' : 'button';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a
|
||||
href="#"
|
||||
<component
|
||||
:is="component"
|
||||
:aria-label="ariaLabel"
|
||||
:href="href"
|
||||
class="counter gl-relative gl-display-inline-block gl-flex-grow-1 gl-text-center gl-py-3 gl-bg-gray-10 gl-rounded-base gl-text-black-normal gl-border gl-border-gray-a-08 gl-font-sm gl-font-weight-bold"
|
||||
>
|
||||
<gl-icon :name="icon" />
|
||||
{{ count }}
|
||||
</a>
|
||||
<gl-icon aria-hidden="true" :name="icon" />
|
||||
<span aria-hidden="true">{{ count }}</span>
|
||||
</component>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlCollapse } from '@gitlab/ui';
|
||||
import { user, counts, context } from '../mock_data';
|
||||
import { context } from '../mock_data';
|
||||
import UserBar from './user_bar.vue';
|
||||
import ContextSwitcherToggle from './context_switcher_toggle.vue';
|
||||
import ContextSwitcher from './context_switcher.vue';
|
||||
|
|
@ -8,8 +8,6 @@ import BottomBar from './bottom_bar.vue';
|
|||
|
||||
export default {
|
||||
context,
|
||||
user,
|
||||
counts,
|
||||
components: {
|
||||
GlCollapse,
|
||||
UserBar,
|
||||
|
|
@ -17,6 +15,12 @@ export default {
|
|||
ContextSwitcher,
|
||||
BottomBar,
|
||||
},
|
||||
props: {
|
||||
sidebarData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contextSwitcherOpened: false,
|
||||
|
|
@ -30,7 +34,7 @@ export default {
|
|||
class="super-sidebar gl-fixed gl-bottom-0 gl-left-0 gl-display-flex gl-flex-direction-column gl-bg-gray-10 gl-border-r gl-border-gray-a-08 gl-z-index-9999"
|
||||
data-testid="super-sidebar"
|
||||
>
|
||||
<user-bar :user="$options.user" :counts="$options.counts" />
|
||||
<user-bar :sidebar-data="sidebarData" />
|
||||
<div class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-overflow-hidden">
|
||||
<div class="gl-flex-grow-1 gl-overflow-auto">
|
||||
<context-switcher-toggle :context="$options.context" :expanded="contextSwitcherOpened" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { GlAvatar, GlDropdown, GlIcon } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
|
||||
import logo from '../../../../views/shared/_logo.svg';
|
||||
|
|
@ -14,16 +15,17 @@ export default {
|
|||
NewNavToggle,
|
||||
Counter,
|
||||
},
|
||||
i18n: {
|
||||
issues: __('Issues'),
|
||||
mergeRequests: __('Merge requests'),
|
||||
todoList: __('To-Do list'),
|
||||
},
|
||||
directives: {
|
||||
SafeHtml,
|
||||
},
|
||||
inject: ['rootPath', 'toggleNewNavEndpoint'],
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
counts: {
|
||||
sidebarData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
|
@ -47,15 +49,29 @@ export default {
|
|||
</button>
|
||||
<gl-dropdown data-testid="user-dropdown" variant="link" no-caret>
|
||||
<template #button-content>
|
||||
<gl-avatar :entity-name="user.name" :src="user.avatar_url" :size="32" />
|
||||
<gl-avatar :entity-name="sidebarData.name" :src="sidebarData.avatar_url" :size="32" />
|
||||
</template>
|
||||
<new-nav-toggle :endpoint="toggleNewNavEndpoint" enabled />
|
||||
</gl-dropdown>
|
||||
</div>
|
||||
<div class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2">
|
||||
<counter icon="issues" :count="counts.assigned_issues" />
|
||||
<counter icon="merge-request-open" :count="counts.assigned_merge_requests" />
|
||||
<counter icon="todo-done" :count="counts.pending_todos" />
|
||||
<counter
|
||||
icon="issues"
|
||||
:count="sidebarData.assigned_open_issues_count"
|
||||
:href="sidebarData.issues_dashboard_path"
|
||||
:label="$options.i18n.issues"
|
||||
/>
|
||||
<counter
|
||||
icon="merge-request-open"
|
||||
:count="sidebarData.assigned_open_merge_requests_count"
|
||||
:label="$options.i18n.mergeRequests"
|
||||
/>
|
||||
<counter
|
||||
icon="todo-done"
|
||||
:count="sidebarData.todos_pending_count"
|
||||
href="/dashboard/todos"
|
||||
:label="$options.i18n.todoList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,5 @@
|
|||
import { s__ } from '~/locale';
|
||||
|
||||
export const user = {
|
||||
name: 'GitLab Bot',
|
||||
avatar_url: '',
|
||||
};
|
||||
|
||||
export const counts = {
|
||||
assigned_issues: 0,
|
||||
assigned_merge_requests: 4,
|
||||
pending_todos: 12,
|
||||
};
|
||||
|
||||
export const context = {
|
||||
title: 'Typeahead.js',
|
||||
link: '/',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export const initSuperSidebar = () => {
|
|||
|
||||
if (!el) return false;
|
||||
|
||||
const { rootPath, toggleNewNavEndpoint } = el.dataset;
|
||||
const { rootPath, sidebar, toggleNewNavEndpoint } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
|
|
@ -16,7 +16,11 @@ export const initSuperSidebar = () => {
|
|||
toggleNewNavEndpoint,
|
||||
},
|
||||
render(h) {
|
||||
return h(SuperSidebar);
|
||||
return h(SuperSidebar, {
|
||||
props: {
|
||||
sidebarData: JSON.parse(sidebar),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Visibility from 'visibilityjs';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import Poll from '~/lib/utils/poll';
|
||||
|
||||
import * as types from './mutation_types';
|
||||
|
|
@ -63,7 +63,7 @@ export const fetchArtifacts = ({ state, dispatch }) => {
|
|||
|
||||
export const receiveArtifactsSuccess = ({ commit }, response) => {
|
||||
// With 204 we keep polling and don't update the state
|
||||
if (response.status === httpStatusCodes.OK) {
|
||||
if (response.status === HTTP_STATUS_OK) {
|
||||
commit(types.RECEIVE_ARTIFACTS_SUCCESS, response.data);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ class Projects::ProtectedRefsController < Projects::ApplicationController
|
|||
flash[:alert] = protected_ref.errors.full_messages.join(', ').html_safe
|
||||
end
|
||||
|
||||
redirect_to_repository_settings(@project, anchor: params[:update_section])
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_repository_settings(@project, anchor: params[:update_section]) }
|
||||
format.json { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ProtectedBranchesHelper
|
||||
def protected_branch_can_admin_entity?(protected_branch_entity)
|
||||
if protected_branch_entity.is_a?(Group)
|
||||
can?(current_user, :admin_group, protected_branch_entity)
|
||||
else
|
||||
can?(current_user, :admin_project, protected_branch_entity)
|
||||
end
|
||||
end
|
||||
|
||||
def protected_branch_path_by_entity(protected_branch, protected_branch_entity)
|
||||
if protected_branch_entity.is_a?(Group)
|
||||
group_protected_branch_path(protected_branch_entity, protected_branch)
|
||||
else
|
||||
project_protected_branch_path(protected_branch_entity, protected_branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -31,6 +31,18 @@ module SidebarsHelper
|
|||
Sidebars::Groups::Context.new(**context_data)
|
||||
end
|
||||
|
||||
def super_sidebar_context(user)
|
||||
{
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
avatar_url: user.avatar_url,
|
||||
assigned_open_issues_count: user.assigned_open_issues_count,
|
||||
assigned_open_merge_requests_count: user.assigned_open_merge_requests_count,
|
||||
todos_pending_count: user.todos_pending_count,
|
||||
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sidebar_attributes_for_object(object)
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@ class ProtectedBranch < ApplicationRecord
|
|||
name == project.default_branch
|
||||
end
|
||||
|
||||
def entity
|
||||
group || project
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_either_project_or_top_group
|
||||
|
|
@ -111,7 +115,7 @@ class ProtectedBranch < ApplicationRecord
|
|||
errors.add(:base, _('must be associated with a Group or a Project'))
|
||||
elsif project && group
|
||||
errors.add(:base, _('cannot be associated with both a Group and a Project'))
|
||||
elsif group && group.root_ancestor != group
|
||||
elsif group && group.subgroup?
|
||||
errors.add(:base, _('cannot be associated with a subgroup'))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProtectedBranch::MergeAccessLevel < ApplicationRecord
|
||||
include Importable
|
||||
include ProtectedBranchAccess
|
||||
# default value for the access_level column
|
||||
GITLAB_DEFAULT_ACCESS_LEVEL = Gitlab::Access::MAINTAINER
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProtectedBranch::PushAccessLevel < ApplicationRecord
|
||||
include Importable
|
||||
include ProtectedBranchAccess
|
||||
# default value for the access_level column
|
||||
GITLAB_DEFAULT_ACCESS_LEVEL = Gitlab::Access::MAINTAINER
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProtectedTag::CreateAccessLevel < ApplicationRecord
|
||||
include Importable
|
||||
include ProtectedTagAccess
|
||||
|
||||
def check_access(user)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,13 @@ module Ci
|
|||
|
||||
duration >= LOG_MAX_CREATION_THRESHOLD
|
||||
end
|
||||
|
||||
l.log_when do |observations|
|
||||
pipeline_includes_count = observations['pipeline_includes_count']
|
||||
next false unless pipeline_includes_count
|
||||
|
||||
pipeline_includes_count.to_i > Gitlab::Ci::Config::External::Context::MAX_INCLUDES
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module Environments
|
|||
)
|
||||
end
|
||||
|
||||
ServiceResponse.success(message: 'Successfully scheduled stale environments to stop')
|
||||
ServiceResponse.success(message: 'Successfully requested stop for all stale environments')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,4 +32,4 @@
|
|||
- kroki_available_formats.each do |format|
|
||||
= f.gitlab_ui_checkbox_component format[:name], format[:label]
|
||||
|
||||
= f.submit _('Save changes'), class: "btn gl-button btn-confirm"
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@
|
|||
- c.header do
|
||||
= s_('ProjectSettings|Transfer project')
|
||||
- c.body do
|
||||
= form_for @project, url: transfer_admin_project_path(@project), method: :put do |f|
|
||||
= gitlab_ui_form_for @project, url: transfer_admin_project_path(@project), method: :put do |f|
|
||||
.form-group.row
|
||||
.col-sm-3.col-form-label
|
||||
= f.label :new_namespace_id, _("Namespace")
|
||||
|
|
@ -147,13 +147,13 @@
|
|||
|
||||
.form-group.row
|
||||
.offset-sm-3.col-sm-9
|
||||
= f.submit _('Transfer'), class: 'gl-button btn btn-confirm'
|
||||
= f.submit _('Transfer'), pajamas_button: true
|
||||
|
||||
= render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5 repository-check' }) do |c|
|
||||
- c.header do
|
||||
= _("Repository check")
|
||||
- c.body do
|
||||
= form_for @project, url: repository_check_admin_project_path(@project), method: :post do |f|
|
||||
= gitlab_ui_form_for @project, url: repository_check_admin_project_path(@project), method: :post do |f|
|
||||
.form-group
|
||||
- if @project.last_repository_check_at.nil?
|
||||
= _("This repository has never been checked.")
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
= link_to sprite_icon('question-o'), help_page_path('administration/repository_checks')
|
||||
|
||||
.form-group
|
||||
= f.submit _('Trigger repository check'), class: 'gl-button btn btn-confirm'
|
||||
= f.submit _('Trigger repository check'), pajamas_button: true
|
||||
|
||||
.col-md-6
|
||||
- if @group
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
.login-box.gl-p-5
|
||||
.login-body
|
||||
- if @user.two_factor_otp_enabled?
|
||||
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if @user.two_factor_webauthn_u2f_enabled?}" }) do |f|
|
||||
= gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if @user.two_factor_webauthn_u2f_enabled?}" }) do |f|
|
||||
- resource_params = params[resource_name].presence || params
|
||||
= f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
|
||||
%div
|
||||
|
|
@ -11,6 +11,6 @@
|
|||
= f.text_field :otp_attempt, class: 'form-control gl-form-input', required: true, autofocus: true, autocomplete: 'off', title: _('This field is required.'), data: { qa_selector: 'two_fa_code_field' }
|
||||
%p.form-text.text-muted.hint= _("Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.")
|
||||
.prepend-top-20
|
||||
= f.submit _("Verify code"), class: "gl-button btn btn-confirm", data: { qa_selector: 'verify_code_button' }
|
||||
= f.submit _("Verify code"), pajamas_button: true, data: { qa_selector: 'verify_code_button' }
|
||||
- if @user.two_factor_webauthn_u2f_enabled?
|
||||
= render "authentication/authenticate", params: params, resource: resource, resource_name: resource_name, render_remember_me: true, target_path: new_user_session_path
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
- if show_omniauth_providers && omniauth_providers_placement == :top
|
||||
= render 'devise/shared/signup_omniauth_providers_top'
|
||||
|
||||
= form_for(resource, as: "new_#{resource_name}", url: url, html: { class: 'new_user gl-show-field-errors js-arkose-labs-form', 'aria-live' => 'assertive' }, data: { testid: 'signup-form' }) do |f|
|
||||
= gitlab_ui_form_for(resource, as: "new_#{resource_name}", url: url, html: { class: 'new_user gl-show-field-errors js-arkose-labs-form', 'aria-live' => 'assertive' }, data: { testid: 'signup-form' }) do |f|
|
||||
.devise-errors
|
||||
= render 'devise/shared/error_messages', resource: resource
|
||||
- if Gitlab::CurrentSettings.invisible_captcha_enabled
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
= recaptcha_tags nonce: content_security_policy_nonce
|
||||
|
||||
.submit-container.gl-mt-5
|
||||
= f.submit button_text, class: 'btn gl-button btn-confirm gl-display-block gl-w-full', data: { qa_selector: 'new_user_register_button' }
|
||||
= f.submit button_text, pajamas_button: true, class: 'gl-w-full', data: { qa_selector: 'new_user_register_button' }
|
||||
- if Gitlab::CurrentSettings.sign_in_text.present? && Feature.enabled?(:restyle_login_page, @project)
|
||||
.gl-pt-5
|
||||
= markdown_field(Gitlab::CurrentSettings.current_application_settings, :sign_in_text)
|
||||
|
|
|
|||
|
|
@ -8,5 +8,7 @@
|
|||
= render "shared/deploy_tokens/index", group_or_project: @group, description: deploy_token_description
|
||||
= render "default_branch", group: @group
|
||||
|
||||
= render_if_exists "protected_branches/protected_branches", protected_branch_entity: @group
|
||||
|
||||
- if can?(current_user, :change_push_rules, @group)
|
||||
= render "push_rules"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
- @left_sidebar = true
|
||||
.layout-page.hide-when-top-nav-responsive-open{ class: page_with_sidebar_class }
|
||||
- if show_super_sidebar?
|
||||
%aside.js-super-sidebar.nav-sidebar{ data: { root_path: root_path, toggle_new_nav_endpoint: profile_preferences_url } }
|
||||
- sidebar_data = super_sidebar_context(current_user).to_json
|
||||
%aside.js-super-sidebar.nav-sidebar{ data: { root_path: root_path, sidebar: sidebar_data, toggle_new_nav_endpoint: profile_preferences_url } }
|
||||
- elsif defined?(nav) && nav
|
||||
= render "layouts/nav/sidebar/#{nav}"
|
||||
.content-wrapper.content-wrapper-margin{ class: "#{@content_wrapper_class}" }
|
||||
|
|
|
|||
|
|
@ -16,4 +16,4 @@
|
|||
= render 'shared/import_form', f: f
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Start import', class: 'gl-button btn btn-confirm', data: { disable_with: false }
|
||||
= f.submit 'Start import', pajamas_button: true, data: { disable_with: false }
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
= render "protected_branches/index"
|
||||
= render "protected_branches/index", protected_branch_entity: protected_branch_entity
|
||||
= render "projects/protected_tags/index"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
-# The shared parts of the views can be found in the `shared` directory.
|
||||
-# Those are used throughout the actual views. These `shared` views are then
|
||||
-# reused in EE.
|
||||
= render "projects/settings/repository/protected_branches"
|
||||
= render "projects/settings/repository/protected_branches", protected_branch_entity: @project
|
||||
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
|
||||
= render @deploy_keys
|
||||
= render "projects/cleanup/show"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
- can_admin_project = can?(current_user, :admin_project, @project)
|
||||
- can_admin_entity = protected_branch_can_admin_entity?(protected_branch_entity)
|
||||
|
||||
= render layout: 'protected_branches/shared/branches_list', locals: { can_admin_project: can_admin_project } do
|
||||
= render partial: 'protected_branches/protected_branch', collection: @protected_branches
|
||||
= render layout: 'protected_branches/shared/branches_list', locals: { can_admin_entity: can_admin_entity, protected_branch_entity: protected_branch_entity } do
|
||||
= render partial: 'protected_branches/protected_branch', collection: @protected_branches, locals: { protected_branch_entity: protected_branch_entity }
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@
|
|||
dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_push_dropdown_content' , dropdown_testid: 'allowed-to-push-dropdown',
|
||||
data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes', qa_selector: 'allowed_to_push_dropdown' }})
|
||||
|
||||
= render 'protected_branches/shared/create_protected_branch'
|
||||
= render 'protected_branches/shared/create_protected_branch', protected_branch_entity: protected_branch_entity
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- content_for :create_protected_branch do
|
||||
= render 'protected_branches/create_protected_branch'
|
||||
= render 'protected_branches/create_protected_branch', protected_branch_entity: protected_branch_entity
|
||||
|
||||
- content_for :branches_list do
|
||||
= render "protected_branches/branches_list"
|
||||
= render "protected_branches/branches_list", protected_branch_entity: protected_branch_entity
|
||||
|
||||
= render 'protected_branches/shared/index'
|
||||
= render 'protected_branches/shared/index', protected_branch_entity: protected_branch_entity
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
= render layout: 'protected_branches/shared/protected_branch', locals: { protected_branch: protected_branch } do
|
||||
= render layout: 'protected_branches/shared/protected_branch', locals: { protected_branch: protected_branch, protected_branch_entity: protected_branch_entity } do
|
||||
= render_if_exists 'protected_branches/update_protected_branch', protected_branch: protected_branch
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
%col{ width: "20%" }
|
||||
%col{ width: "10%" }
|
||||
%col{ width: "10%" }
|
||||
- if can_admin_project
|
||||
- if can_admin_entity
|
||||
%col
|
||||
%thead
|
||||
%tr
|
||||
|
|
@ -28,9 +28,9 @@
|
|||
%span.has-tooltip{ data: { container: 'body' }, title: s_('ProtectedBranch|Allow all users with push access to force push.'), 'aria-hidden': 'true' }
|
||||
= sprite_icon('question', size: 16, css_class: 'gl-text-gray-500')
|
||||
|
||||
= render_if_exists 'protected_branches/ee/code_owner_approval_table_head'
|
||||
= render_if_exists 'protected_branches/ee/code_owner_approval_table_head', protected_branch_entity: protected_branch_entity
|
||||
|
||||
- if can_admin_project
|
||||
- if can_admin_entity
|
||||
%th
|
||||
%tbody
|
||||
= yield
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
= gitlab_ui_form_for [@project, @protected_branch], html: { class: 'new-protected-branch js-new-protected-branch' } do |f|
|
||||
= gitlab_ui_form_for [protected_branch_entity, @protected_branch], html: { class: 'new-protected-branch js-new-protected-branch' } do |f|
|
||||
%input{ type: 'hidden', name: 'update_section', value: 'js-protected-branches-settings' }
|
||||
= render Pajamas::CardComponent.new(card_options: { class: "gl-mb-5" }) do |c|
|
||||
- c.header do
|
||||
|
|
@ -8,11 +8,18 @@
|
|||
.form-group.row
|
||||
= f.label :name, s_('ProtectedBranch|Branch:'), class: 'col-sm-12'
|
||||
.col-sm-12
|
||||
= render partial: "protected_branches/shared/dropdown", locals: { f: f, toggle_classes: 'gl-w-full! gl-form-input-lg' }
|
||||
- if protected_branch_entity.is_a?(Group)
|
||||
= f.text_field :name, placeholder: 'prod*', class: 'form-control gl-w-full! gl-form-input-lg'
|
||||
- else
|
||||
= render partial: "protected_branches/shared/dropdown", locals: { f: f, toggle_classes: 'gl-w-full! gl-form-input-lg' }
|
||||
.form-text.text-muted
|
||||
- wildcards_url = help_page_url('user/project/protected_branches', anchor: 'configure-multiple-protected-branches-by-using-a-wildcard')
|
||||
- wildcards_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: wildcards_url }
|
||||
= (s_("ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported.") % { wildcards_link_start: wildcards_link_start, wildcards_link_end: '</a>', code_tag_start: '<code>', code_tag_end: '</code>' }).html_safe
|
||||
- placeholders = { wildcards_link_start: wildcards_link_start, wildcards_link_end: '</a>', code_tag_start: '<code>', code_tag_end: '</code>' }
|
||||
- if protected_branch_entity.is_a?(Group)
|
||||
= (s_("ProtectedBranch|Only %{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported.") % placeholders).html_safe
|
||||
- else
|
||||
= (s_("ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported.") % placeholders).html_safe
|
||||
.form-group.row
|
||||
= f.label :merge_access_levels_attributes, s_("ProtectedBranch|Allowed to merge:"), class: 'col-sm-12'
|
||||
.col-sm-12
|
||||
|
|
@ -30,6 +37,6 @@
|
|||
- force_push_docs_url = help_page_url('topics/git/git_rebase', anchor: 'force-push')
|
||||
- force_push_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: force_push_docs_url }
|
||||
= (s_("ProtectedBranch|Allow all users with push access to %{tag_start}force push%{tag_end}.") % { tag_start: force_push_link_start, tag_end: '</a>' }).html_safe
|
||||
= render_if_exists 'protected_branches/ee/code_owner_approval_form', f: f
|
||||
= render_if_exists 'protected_branches/ee/code_owner_approval_form', f: f, protected_branch_entity: protected_branch_entity
|
||||
- c.footer do
|
||||
= f.submit s_('ProtectedBranch|Protect'), disabled: true, data: { qa_selector: 'protect_button' }, pajamas_button: true
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
- can_admin_entity = protected_branch_can_admin_entity?(protected_branch_entity)
|
||||
- expanded = expanded_by_default?
|
||||
|
||||
%section.settings.no-animate#js-protected-branches-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_branches_settings_content' } }
|
||||
|
|
@ -14,7 +15,7 @@
|
|||
= s_("ProtectedBranch|By default, protected branches restrict who can modify the branch.")
|
||||
= link_to s_("ProtectedBranch|Learn more."), help_page_path("user/project/protected_branches", anchor: "who-can-modify-a-protected-branch")
|
||||
|
||||
- if can? current_user, :admin_project, @project
|
||||
- if can_admin_entity
|
||||
= content_for :create_protected_branch
|
||||
|
||||
= content_for :branches_list
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
- can_admin_project = can?(current_user, :admin_project, @project)
|
||||
- can_admin_entity = protected_branch_can_admin_entity?(protected_branch_entity)
|
||||
- url = protected_branch_path_by_entity(protected_branch, protected_branch_entity)
|
||||
|
||||
%tr.js-protected-branch-edit-form{ data: { url: namespace_project_protected_branch_path(@project.namespace, @project, protected_branch), testid: 'protected-branch' } }
|
||||
%tr.js-protected-branch-edit-form{ data: { url: url, testid: 'protected-branch' } }
|
||||
%td
|
||||
%span.ref-name= protected_branch.name
|
||||
|
||||
- if @project.root_ref?(protected_branch.name)
|
||||
- if protected_branch_entity.is_a?(Project) && protected_branch_entity.root_ref?(protected_branch.name)
|
||||
= gl_badge_tag s_('ProtectedBranch|default'), variant: :info
|
||||
|
||||
%div
|
||||
- if protected_branch.wildcard?
|
||||
- matching_branches = protected_branch.matching(repository.branch_names)
|
||||
= link_to pluralize(matching_branches.count, "matching branch"), namespace_project_protected_branch_path(@project.namespace, @project, protected_branch)
|
||||
- elsif !protected_branch.commit
|
||||
%span.text-muted Branch was deleted.
|
||||
- if protected_branch_entity.is_a?(Project)
|
||||
%div
|
||||
- if protected_branch.wildcard?
|
||||
- matching_branches = protected_branch.matching(repository.branch_names)
|
||||
= link_to pluralize(matching_branches.count, "matching branch"), namespace_project_protected_branch_path(@project.namespace, @project, protected_branch)
|
||||
- elsif !protected_branch.commit
|
||||
%span.text-muted= s_('ProtectedBranch|Branch does not exist.')
|
||||
|
||||
= yield
|
||||
|
||||
= render_if_exists 'protected_branches/ee/code_owner_approval_table', protected_branch: protected_branch
|
||||
= render_if_exists 'protected_branches/ee/code_owner_approval_table', protected_branch: protected_branch, protected_branch_entity: protected_branch_entity
|
||||
|
||||
- if can_admin_project
|
||||
- if can_admin_entity
|
||||
%td
|
||||
= link_to s_('ProtectedBranch|Unprotect'), [@project, protected_branch, { update_section: 'js-protected-branches-settings' }], disabled: local_assigns[:disabled], aria: { label: s_('ProtectedBranch|Unprotect branch') }, data: { confirm: s_('ProtectedBranch|Branch will be writable for developers. Are you sure?'), confirm_btn_variant: 'danger' }, method: :delete, class: "btn gl-button btn-danger btn-sm"
|
||||
= link_to s_('ProtectedBranch|Unprotect'), [protected_branch_entity, protected_branch, { update_section: 'js-protected-branches-settings' }], disabled: local_assigns[:disabled], aria: { label: s_('ProtectedBranch|Unprotect branch') }, data: { confirm: s_('ProtectedBranch|Branch will be writable for developers. Are you sure?'), confirm_btn_variant: 'danger' }, method: :delete, class: "btn gl-button btn-danger btn-sm"
|
||||
|
|
|
|||
|
|
@ -6,19 +6,52 @@ class PipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker
|
|||
data_consistency :always
|
||||
|
||||
include CronjobQueue
|
||||
include ::Gitlab::ExclusiveLeaseHelpers
|
||||
|
||||
LOCK_RETRY = 3
|
||||
LOCK_TTL = 5.minutes
|
||||
|
||||
feature_category :continuous_integration
|
||||
worker_resource_boundary :cpu
|
||||
|
||||
def perform
|
||||
Ci::PipelineSchedule.runnable_schedules.preloaded.find_in_batches do |schedules|
|
||||
schedules.each do |schedule|
|
||||
next unless schedule.project
|
||||
if Feature.enabled?(:ci_use_run_pipeline_schedule_worker)
|
||||
in_lock(lock_key, **lock_params) do
|
||||
Ci::PipelineSchedule
|
||||
.select(:id, :owner_id, :project_id) # Minimize the selected columns
|
||||
.runnable_schedules
|
||||
.preloaded
|
||||
.find_in_batches do |schedules|
|
||||
RunPipelineScheduleWorker.bulk_perform_async_with_contexts(
|
||||
schedules,
|
||||
arguments_proc: ->(schedule) { [schedule.id, schedule.owner_id] },
|
||||
context_proc: ->(schedule) { { project: schedule.project, user: schedule.owner } }
|
||||
)
|
||||
end
|
||||
end
|
||||
else
|
||||
Ci::PipelineSchedule.runnable_schedules.preloaded.find_in_batches do |schedules|
|
||||
schedules.each do |schedule|
|
||||
next unless schedule.project
|
||||
|
||||
with_context(project: schedule.project, user: schedule.owner) do
|
||||
Ci::PipelineScheduleService.new(schedule.project, schedule.owner).execute(schedule)
|
||||
with_context(project: schedule.project, user: schedule.owner) do
|
||||
Ci::PipelineScheduleService.new(schedule.project, schedule.owner).execute(schedule)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lock_key
|
||||
self.class.name.underscore
|
||||
end
|
||||
|
||||
def lock_params
|
||||
{
|
||||
ttl: LOCK_TTL,
|
||||
retries: LOCK_RETRY
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ class RunPipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker
|
|||
|
||||
return unless schedule && schedule.project && user
|
||||
|
||||
if Feature.enabled?(:ci_use_run_pipeline_schedule_worker)
|
||||
return if schedule.next_run_at > Time.current
|
||||
|
||||
update_next_run_at_for(schedule)
|
||||
end
|
||||
|
||||
run_pipeline_schedule(schedule, user)
|
||||
end
|
||||
|
||||
|
|
@ -37,6 +43,12 @@ class RunPipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker
|
|||
|
||||
private
|
||||
|
||||
def update_next_run_at_for(schedule)
|
||||
# Ensure `next_run_at` is set properly before creating a pipeline.
|
||||
# Otherwise, multiple pipelines could be created in a short interval.
|
||||
schedule.schedule_next_run!
|
||||
end
|
||||
|
||||
def error(schedule, error)
|
||||
failed_creation_counter.increment
|
||||
log_error(schedule, error)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: ci_use_run_pipeline_schedule_worker
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106661
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378361
|
||||
milestone: '15.8'
|
||||
type: development
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddQueryIndexForCiPipelineSchedules < Gitlab::Database::Migration[2.1]
|
||||
TABLE_NAME = :ci_pipeline_schedules
|
||||
INDEX_NAME = :index_ci_pipeline_schedules_on_id_and_next_run_at_and_active
|
||||
COLUMNS = %i[id next_run_at].freeze
|
||||
INDEX_CONDITION = 'active = TRUE'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index(TABLE_NAME, COLUMNS, name: INDEX_NAME, where: INDEX_CONDITION)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index(TABLE_NAME, COLUMNS, name: INDEX_NAME)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
43f0493091c58f1573613d5672a999bf07994ced2b7172a7aef9148f4d8b8dbe
|
||||
|
|
@ -28907,6 +28907,8 @@ CREATE INDEX index_ci_pipeline_metadata_on_project_id ON ci_pipeline_metadata US
|
|||
|
||||
CREATE UNIQUE INDEX index_ci_pipeline_schedule_variables_on_schedule_id_and_key ON ci_pipeline_schedule_variables USING btree (pipeline_schedule_id, key);
|
||||
|
||||
CREATE INDEX index_ci_pipeline_schedules_on_id_and_next_run_at_and_active ON ci_pipeline_schedules USING btree (id, next_run_at) WHERE (active = true);
|
||||
|
||||
CREATE INDEX index_ci_pipeline_schedules_on_next_run_at_and_active ON ci_pipeline_schedules USING btree (next_run_at, active);
|
||||
|
||||
CREATE INDEX index_ci_pipeline_schedules_on_owner_id ON ci_pipeline_schedules USING btree (owner_id);
|
||||
|
|
|
|||
|
|
@ -412,3 +412,28 @@ Example response:
|
|||
"updated_at": "2019-05-27T18:55:13.252Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Stop stale environments
|
||||
|
||||
Issue stop request to all environments that were last modified or deployed to before a specified date. Excludes protected environments. Returns `200` if stop request was successful and `400` if the before date is invalid. For details of exactly when the environment is stopped, see [Stop an environment](../ci/environments/index.md#stop-an-environment).
|
||||
|
||||
```plaintext
|
||||
POST /projects/:id/environments/stop_stale
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------|----------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `before` | date | yes | Stop environments that have been modified or deployed to before the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Valid inputs are between 10 years ago and 1 week ago |
|
||||
|
||||
```shell
|
||||
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments/stop_stale?before=10%2F10%2F2021"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Successfully requested stop for all stale environments"
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -436,6 +436,8 @@ There are multiple ways to clean up [dynamic environments](#create-a-dynamic-env
|
|||
- If you do _NOT_ use [merge request pipelines](../pipelines/merge_request_pipelines.md), GitLab stops an environment [when the associated feature branch is deleted](#stop-an-environment-when-a-branch-is-deleted).
|
||||
- If you set [an expiry period to an environment](../yaml/index.md#environmentauto_stop_in), GitLab stops an environment [when it's expired](#stop-an-environment-after-a-certain-time-period).
|
||||
|
||||
To stop stale environments, you can [use the API](../../api/environments.md#stop-stale-environments).
|
||||
|
||||
#### Stop an environment when a branch is deleted
|
||||
|
||||
You can configure environments to stop when a branch is deleted.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Code Review
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Approval Rules development guide **(FREE)**
|
||||
# Approval Rules development guide
|
||||
|
||||
This document explains the backend design and flow of all related functionality
|
||||
about [merge request approval rules](../user/project/merge_requests/approvals/index.md).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Configure
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Auto DevOps development guide **(FREE)**
|
||||
# Auto DevOps development guide
|
||||
|
||||
This document provides a development guide for contributors to
|
||||
[Auto DevOps](../topics/autodevops/index.md).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Pipeline Authoring
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Documenting the `.gitlab-ci.yml` keywords **(FREE)**
|
||||
# Documenting the `.gitlab-ci.yml` keywords
|
||||
|
||||
The [CI/CD YAML reference](../../ci/yaml/index.md) uses a standard style to make it easier to use and update.
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: index, concepts, howto
|
||||
---
|
||||
|
||||
# CI/CD development documentation **(FREE)**
|
||||
# CI/CD development documentation
|
||||
|
||||
Development guides that are specific to CI/CD are listed here:
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: index, howto
|
||||
---
|
||||
|
||||
# Contribute to the CI/CD Schema **(FREE)**
|
||||
# Contribute to the CI/CD Schema
|
||||
|
||||
The [pipeline editor](../../ci/pipeline_editor/index.md) uses a CI/CD schema to enhance
|
||||
the authoring experience of our CI/CD configuration files. With the CI/CD schema, the editor can:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: index, concepts, howto
|
||||
---
|
||||
|
||||
# Development guide for GitLab CI/CD templates **(FREE)**
|
||||
# Development guide for GitLab CI/CD templates
|
||||
|
||||
This document explains how to develop [GitLab CI/CD templates](../../ci/examples/index.md#cicd-templates).
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Code Review
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Code Intelligence **(FREE)**
|
||||
# Code Intelligence
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/1576) in GitLab 13.1.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Respond
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Distributed Tracing - development guidelines **(FREE)**
|
||||
# Distributed Tracing - development guidelines
|
||||
|
||||
GitLab is instrumented for distributed tracing. Distributed Tracing in GitLab is currently considered **experimental**, as it has not yet been tested at scale on GitLab.com.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Global Search
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Elasticsearch knowledge **(PREMIUM SELF)**
|
||||
# Elasticsearch knowledge
|
||||
|
||||
This area is to maintain a compendium of useful information when working with Elasticsearch.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Editor
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Content Editor development guidelines **(FREE)**
|
||||
# Content Editor development guidelines
|
||||
|
||||
The Content Editor is a UI component that provides a WYSIWYG editing
|
||||
experience for [GitLab Flavored Markdown](../../user/markdown.md) in the GitLab application.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Product Analytics
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Customizable dashboards **(PREMIUM)**
|
||||
# Customizable dashboards
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98610) in GitLab 15.5 as an [Alpha feature](../../policy/alpha-beta-support.md#alpha-features).
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Code Review
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Merge request widget extensions **(FREE)**
|
||||
# Merge request widget extensions
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44616) in GitLab 13.6.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Editor
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Source Editor **(FREE)**
|
||||
# Source Editor
|
||||
|
||||
**Source Editor** provides the editing experience at GitLab. This thin wrapper around
|
||||
[the Monaco editor](https://microsoft.github.io/monaco-editor/) provides necessary
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Geo
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Geo (development) **(PREMIUM SELF)**
|
||||
# Geo (development)
|
||||
|
||||
Geo connects GitLab instances together. One GitLab instance is
|
||||
designated as a **primary** site and can be run with multiple
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
<!-- vale gitlab.GitLabFlavoredMarkdown = NO -->
|
||||
|
||||
# GitLab Flavored Markdown (GLFM) developer documentation **(FREE)**
|
||||
# GitLab Flavored Markdown (GLFM) developer documentation
|
||||
|
||||
This page contains the MVC for the developer documentation for GitLab Flavored Markdown (GLFM).
|
||||
For the user documentation about Markdown in GitLab, refer to
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
<!-- vale gitlab.GitLabFlavoredMarkdown = NO -->
|
||||
|
||||
# GitLab Flavored Markdown (GLFM) Specification Guide **(FREE)**
|
||||
# GitLab Flavored Markdown (GLFM) Specification Guide
|
||||
|
||||
## Summary
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
description: "GitLab's development guidelines for Integrations"
|
||||
---
|
||||
|
||||
# Integrations development guide **(FREE)**
|
||||
# Integrations development guide
|
||||
|
||||
This page provides development guidelines for implementing [GitLab integrations](../../user/project/integrations/index.md),
|
||||
which are part of our [main Rails project](https://gitlab.com/gitlab-org/gitlab).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Integrations
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# How to run Jenkins in development environment (on macOS) **(FREE)**
|
||||
# How to run Jenkins in development environment (on macOS)
|
||||
|
||||
This is a step by step guide on how to set up [Jenkins](https://www.jenkins.io/) on your local machine and connect to it from your GitLab instance. GitLab triggers webhooks on Jenkins, and Jenkins connects to GitLab using the API. By running both applications on the same machine, we can make sure they are able to access each other.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Integrations
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Set up a development environment **(FREE)**
|
||||
# Set up a development environment
|
||||
|
||||
The following are required to install and test the app:
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: "To determine the technical writer assigned to the Stage/Group associated
|
|||
type: reference, api
|
||||
---
|
||||
|
||||
# Internal API **(FREE)**
|
||||
# Internal API
|
||||
|
||||
The internal API is used by different GitLab components, it cannot be
|
||||
used by other consumers. This documentation is intended for people
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Configure
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Kubernetes integration - development guidelines **(FREE)**
|
||||
# Kubernetes integration - development guidelines
|
||||
|
||||
This document provides various guidelines when developing for the GitLab
|
||||
[Kubernetes integration](../user/infrastructure/clusters/index.md).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Source Code
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Git LFS developer information **(FREE)**
|
||||
# Git LFS developer information
|
||||
|
||||
This page contains developer-centric information for GitLab team members. For the
|
||||
user documentation, see [Git Large File Storage](../topics/git/lfs/index.md).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Respond
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# GitLab Developers Guide to Logging **(FREE)**
|
||||
# GitLab Developers Guide to Logging
|
||||
|
||||
[GitLab Logs](../administration/logs/index.md) play a critical role for both
|
||||
administrators and GitLab team members to diagnose problems in the field.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Geo
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Internal workings of GitLab Maintenance Mode **(PREMIUM SELF)**
|
||||
# Internal workings of GitLab Maintenance Mode
|
||||
|
||||
## Where is Maintenance Mode enforced?
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Code Review
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Merge request diffs development guide **(FREE)**
|
||||
# Merge request diffs development guide
|
||||
|
||||
This document explains the backend design and flow of merge request diffs.
|
||||
It should help contributors:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Respond
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Working with Prometheus Metrics **(FREE)**
|
||||
# Working with Prometheus Metrics
|
||||
|
||||
## Adding to the library
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: index, concepts, howto
|
||||
---
|
||||
|
||||
# Sec section development **(FREE)**
|
||||
# Sec section development
|
||||
|
||||
The Sec section is responsible for GitLab application security features, the "Sec" part of
|
||||
DevSecOps. Development guides that are specific to the Sec section are listed here.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Product Intelligence
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Service Ping Guide **(FREE SELF)**
|
||||
# Service Ping Guide
|
||||
|
||||
> - Introduced in GitLab Ultimate 11.2, more statistics.
|
||||
> - In GitLab 14.1, [renamed from Usage Ping to Service Ping](https://gitlab.com/groups/gitlab-org/-/epics/5990). In 14.0 and earlier, use the Usage Ping documentation for the Rails commands appropriate to your version.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
description: "GitLab's development guidelines for Wikis"
|
||||
---
|
||||
|
||||
# Wikis development guide **(FREE)**
|
||||
# Wikis development guide
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227027) in GitLab 13.5.
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ A deactivated user:
|
|||
|
||||
- Cannot access Git repositories or the API.
|
||||
- Does not receive any notifications from GitLab.
|
||||
- Does not be able to use [slash commands](../../integration/slash_commands.md).
|
||||
- Cannot use [slash commands](../../integration/slash_commands.md).
|
||||
- Does not consume a [seat](../../subscriptions/self_managed/index.md#billable-users).
|
||||
|
||||
Personal projects, and group and user history of the deactivated user are left intact.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: reference
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: concepts, howto
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: 'To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments'
|
||||
type: reference, index, howto
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: reference
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Workspace
|
||||
group: Organization
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -188,6 +188,35 @@ module API
|
|||
present environment, with: Entities::Environment, current_user: current_user
|
||||
end
|
||||
|
||||
desc 'Stop stale environments' do
|
||||
detail 'It returns `200` if stale environment check was scheduled successfully'
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' }
|
||||
]
|
||||
tags %w[environments]
|
||||
end
|
||||
params do
|
||||
requires :before,
|
||||
type: DateTime,
|
||||
desc: 'Stop all environments that were last modified or deployed to before this date.'
|
||||
end
|
||||
post ':id/environments/stop_stale' do
|
||||
authorize! :stop_environment, user_project
|
||||
|
||||
bad_request!('Invalid Date') if params[:before] < 10.years.ago || params[:before] > 1.week.ago
|
||||
|
||||
service_response = ::Environments::StopStaleService.new(user_project, current_user, params.slice(:before)).execute
|
||||
|
||||
if service_response.error?
|
||||
status 400
|
||||
else
|
||||
status 200
|
||||
end
|
||||
|
||||
present message: service_response.message
|
||||
end
|
||||
|
||||
desc 'Get a specific environment' do
|
||||
success Entities::Environment
|
||||
failure [
|
||||
|
|
|
|||
|
|
@ -90,14 +90,14 @@ module Banzai
|
|||
end
|
||||
|
||||
def get_uri(html_attr)
|
||||
uri = URI(html_attr.value)
|
||||
uri = Addressable::URI.parse(html_attr.value)
|
||||
|
||||
uri if uri.relative? && uri.path.present?
|
||||
rescue URI::Error, Addressable::URI::InvalidURIError
|
||||
end
|
||||
|
||||
def process_link_to_repository_attr(html_attr)
|
||||
uri = URI(html_attr.value)
|
||||
uri = Addressable::URI.parse(html_attr.value)
|
||||
|
||||
if uri.relative? && uri.path.present?
|
||||
html_attr.value = rebuild_relative_uri(uri).to_s
|
||||
|
|
|
|||
|
|
@ -127,6 +127,10 @@ module Gitlab
|
|||
.observe({ plan: project.actual_plan_name }, jobs_count)
|
||||
end
|
||||
|
||||
def observe_pipeline_includes_count(pipeline)
|
||||
logger.observe(:pipeline_includes_count, pipeline.config_metadata&.[](:includes)&.count, once: true)
|
||||
end
|
||||
|
||||
def increment_pipeline_failure_reason_counter(reason)
|
||||
metrics.pipeline_failure_reason_counter
|
||||
.increment(reason: (reason || :unknown_failure).to_s)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue