Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
709948b7a6
commit
cc4e1c884c
|
|
@ -629,7 +629,6 @@ RSpec/FactoryBot/AvoidCreate:
|
|||
- 'spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb'
|
||||
- 'spec/views/projects/pipelines/show.html.haml_spec.rb'
|
||||
- 'spec/views/projects/project_members/index.html.haml_spec.rb'
|
||||
- 'spec/views/projects/runners/_specific_runners.html.haml_spec.rb'
|
||||
- 'spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb'
|
||||
- 'spec/views/projects/settings/integrations/edit.html.haml_spec.rb'
|
||||
- 'spec/views/projects/settings/merge_requests/show.html.haml_spec.rb'
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -544,7 +544,7 @@ gem 'lockbox', '~> 1.1.1'
|
|||
gem 'valid_email', '~> 0.1'
|
||||
|
||||
# JSON
|
||||
gem 'json', '~> 2.5.1'
|
||||
gem 'json', '~> 2.6.3'
|
||||
gem 'json_schemer', '~> 0.2.18'
|
||||
gem 'oj', '~> 3.13.21'
|
||||
gem 'oj-introspect', '~> 0.7'
|
||||
|
|
|
|||
|
|
@ -295,8 +295,8 @@
|
|||
{"name":"jira-ruby","version":"2.1.4","platform":"ruby","checksum":"4267c095cac8323b9eef3ba866eb28bb1388b7623a5abb60c1e7caf12d4adb9e"},
|
||||
{"name":"jmespath","version":"1.6.2","platform":"ruby","checksum":"238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1"},
|
||||
{"name":"js_regex","version":"3.8.0","platform":"ruby","checksum":"7934bcdd5a0e6d5af4a520288fd4684a02a472ae55831d9178ccaf82356344b5"},
|
||||
{"name":"json","version":"2.5.1","platform":"java","checksum":"be284a0c4a9d0373e81b0d5dfe71ed5b18d0479f05970e60a77be89a2978ce6c"},
|
||||
{"name":"json","version":"2.5.1","platform":"ruby","checksum":"918d8c41dacb7cfdbe0c7bbd6014a5372f0cf1c454ca150e9f4010fe80cc3153"},
|
||||
{"name":"json","version":"2.6.3","platform":"java","checksum":"ea8c47427a2c876121b9a0ab53043ca390013a76374330eabd923bd81914e563"},
|
||||
{"name":"json","version":"2.6.3","platform":"ruby","checksum":"86aaea16adf346a2b22743d88f8dcceeb1038843989ab93cda44b5176c845459"},
|
||||
{"name":"json-jwt","version":"1.15.3","platform":"ruby","checksum":"66db4f14e538a774c15502a5b5b26b1f3e7585481bbb96df490aa74b5c2d6110"},
|
||||
{"name":"json_schemer","version":"0.2.18","platform":"ruby","checksum":"3362c21efbefdd12ce994e541a1e7fdb86fd267a6541dd8715e8a580fe3b6be6"},
|
||||
{"name":"jsonpath","version":"1.1.2","platform":"ruby","checksum":"6804124c244d04418218acb85b15c7caa79c592d7d6970195300428458946d3a"},
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ GEM
|
|||
character_set (~> 1.4)
|
||||
regexp_parser (~> 2.5)
|
||||
regexp_property_values (~> 1.0)
|
||||
json (2.5.1)
|
||||
json (2.6.3)
|
||||
json-jwt (1.15.3)
|
||||
activesupport (>= 4.2)
|
||||
aes_key_wrap
|
||||
|
|
@ -1712,7 +1712,7 @@ DEPENDENCIES
|
|||
ipynbdiff!
|
||||
jira-ruby (~> 2.1.4)
|
||||
js_regex (~> 3.8)
|
||||
json (~> 2.5.1)
|
||||
json (~> 2.6.3)
|
||||
json_schemer (~> 0.2.18)
|
||||
jwt (~> 2.1.0)
|
||||
kaminari (~> 1.2.2)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export default {
|
|||
category="tertiary"
|
||||
:aria-label="__('Remove')"
|
||||
:title="__('Remove')"
|
||||
class="gl-align-self-center gl-p-1! gl-absolute! gl-w-auto! gl-top-4 gl-right-4"
|
||||
class="gl-align-self-center gl-p-1! gl-absolute! gl-w-auto! gl-right-4 gl-top-half gl-translate-y-n50"
|
||||
data-testid="item-remove"
|
||||
@click.stop.prevent="removeFrequentItem(itemId)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlModal, GlEmptyState } from '@gitlab/ui';
|
||||
import { createAlert } from '~/flash';
|
||||
import { HTTP_STATUS_FORBIDDEN } from '~/lib/utils/http_status';
|
||||
import { mergeUrlParams, getParameterByName } from '~/lib/utils/url_utility';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
|
||||
|
|
@ -225,7 +226,7 @@ export default {
|
|||
})
|
||||
.catch((err) => {
|
||||
let message = COMMON_STR.FAILURE;
|
||||
if (err.status === 403) {
|
||||
if (err.status === HTTP_STATUS_FORBIDDEN) {
|
||||
message = COMMON_STR.LEAVE_FORBIDDEN;
|
||||
}
|
||||
createAlert({ message });
|
||||
|
|
|
|||
|
|
@ -1,34 +1,31 @@
|
|||
<script>
|
||||
import {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
GlSearchBoxByType,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
import { GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import Api from '~/api';
|
||||
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
dropdownHeader: __('Namespaces'),
|
||||
headerText: __('Namespaces'),
|
||||
searchPlaceholder: __('Search for Namespace'),
|
||||
anyNamespace: __('Any namespace'),
|
||||
reset: __('Clear'),
|
||||
},
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
GlLoadingIcon,
|
||||
GlSearchBoxByType,
|
||||
GlCollapsibleListbox,
|
||||
},
|
||||
props: {
|
||||
showAny: {
|
||||
type: Boolean,
|
||||
origSelectedId: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: false,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
origSelectedText: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
toggleTextPlaceholder: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: __('Namespace'),
|
||||
|
|
@ -42,50 +39,66 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
namespaceOptions: [],
|
||||
selectedNamespaceId: null,
|
||||
selectedNamespace: null,
|
||||
selectedNamespaceId: this.origSelectedId,
|
||||
selectedNamespaceText: this.origSelectedText,
|
||||
searchTerm: '',
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
selectedNamespaceName() {
|
||||
if (this.selectedNamespaceId === null) {
|
||||
return this.placeholder;
|
||||
}
|
||||
return this.selectedNamespace;
|
||||
toggleText() {
|
||||
return this.selectedNamespaceText || this.toggleTextPlaceholder;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
searchTerm() {
|
||||
this.fetchNamespaces(this.searchTerm);
|
||||
selectedNamespaceId(val) {
|
||||
if (!val) {
|
||||
this.selectedNamespaceText = null;
|
||||
}
|
||||
|
||||
this.selectedNamespaceText = this.namespaceOptions.find(({ value }) => value === val)?.text;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchNamespaces();
|
||||
},
|
||||
methods: {
|
||||
fetchNamespaces(filter) {
|
||||
fetchNamespaces() {
|
||||
this.isLoading = true;
|
||||
this.namespaceOptions = [];
|
||||
return Api.namespaces(filter, (namespaces) => {
|
||||
this.namespaceOptions = namespaces;
|
||||
|
||||
return Api.namespaces(this.searchTerm, (namespaces) => {
|
||||
this.namespaceOptions = this.formatNamespaceOptions(namespaces);
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
selectNamespace(key) {
|
||||
this.selectedNamespaceId = this.namespaceOptions[key].id;
|
||||
this.selectedNamespace = this.getNamespaceString(this.namespaceOptions[key]);
|
||||
this.$emit('setNamespace', this.selectedNamespaceId);
|
||||
formatNamespaceOptions(namespaces) {
|
||||
if (!namespaces) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return namespaces.map((namespace) => {
|
||||
return {
|
||||
value: String(namespace.id),
|
||||
text: this.getNamespaceString(namespace),
|
||||
};
|
||||
});
|
||||
},
|
||||
selectAnyNamespace() {
|
||||
this.selectedNamespaceId = null;
|
||||
this.selectedNamespace = null;
|
||||
this.$emit('setNamespace', null);
|
||||
selectNamespace(value) {
|
||||
this.selectedNamespaceId = value;
|
||||
this.$emit('setNamespace', this.selectedNamespaceId);
|
||||
},
|
||||
getNamespaceString(namespace) {
|
||||
return `${namespace.kind}: ${namespace.full_path}`;
|
||||
},
|
||||
search: debounce(function debouncedSearch(searchQuery) {
|
||||
this.searchTerm = searchQuery?.trim();
|
||||
this.fetchNamespaces();
|
||||
}, DEFAULT_DEBOUNCE_AND_THROTTLE_MS),
|
||||
onReset() {
|
||||
this.selectedNamespaceId = null;
|
||||
this.$emit('setNamespace', null);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -99,45 +112,19 @@ export default {
|
|||
type="hidden"
|
||||
data-testid="hidden-input"
|
||||
/>
|
||||
<gl-dropdown
|
||||
:text="selectedNamespaceName"
|
||||
:header-text="$options.i18n.dropdownHeader"
|
||||
toggle-class="dropdown-menu-toggle large"
|
||||
data-testid="namespace-dropdown"
|
||||
:right="true"
|
||||
>
|
||||
<template #header>
|
||||
<gl-search-box-by-type
|
||||
v-model.trim="searchTerm"
|
||||
class="namespace-search-box"
|
||||
debounce="250"
|
||||
:placeholder="$options.i18n.searchPlaceholder"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="showAny">
|
||||
<gl-dropdown-item @click="selectAnyNamespace">
|
||||
{{ $options.i18n.anyNamespace }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-divider />
|
||||
</template>
|
||||
|
||||
<gl-loading-icon v-if="isLoading" />
|
||||
|
||||
<gl-dropdown-item
|
||||
v-for="(namespace, key) in namespaceOptions"
|
||||
:key="namespace.id"
|
||||
@click="selectNamespace(key)"
|
||||
>
|
||||
{{ getNamespaceString(namespace) }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
<gl-collapsible-listbox
|
||||
:items="namespaceOptions"
|
||||
:header-text="$options.i18n.headerText"
|
||||
:reset-button-label="$options.i18n.reset"
|
||||
:toggle-text="toggleText"
|
||||
:search-placeholder="$options.i18n.searchPlaceholder"
|
||||
:searching="isLoading"
|
||||
:selected="selectedNamespaceId"
|
||||
toggle-class="gl-w-full gl-flex-direction-column gl-align-items-stretch!"
|
||||
searchable
|
||||
@reset="onReset"
|
||||
@search="search"
|
||||
@select="selectNamespace"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* workaround position: relative imposed by .top-area .nav-controls */
|
||||
.namespace-search-box >>> input {
|
||||
position: static;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import Vue from 'vue';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import { mergeUrlParams } from '~/lib/utils/url_utility';
|
||||
import ProjectsList from '~/projects_list';
|
||||
import NamespaceSelect from './components/namespace_select.vue';
|
||||
|
|
@ -12,16 +11,17 @@ function mountNamespaceSelect() {
|
|||
return false;
|
||||
}
|
||||
|
||||
const { showAny, fieldName, placeholder, updateLocation } = el.dataset;
|
||||
const { fieldName, toggleTextPlaceholder, selectedId, selectedText, updateLocation } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
render(createComponent) {
|
||||
return createComponent(NamespaceSelect, {
|
||||
props: {
|
||||
showAny: parseBoolean(showAny),
|
||||
fieldName,
|
||||
placeholder,
|
||||
toggleTextPlaceholder,
|
||||
origSelectedId: selectedId,
|
||||
origSelectedText: selectedText,
|
||||
},
|
||||
on: {
|
||||
setNamespace(newNamespace) {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
def after_request_hook(user)
|
||||
return unless user.persisted?
|
||||
|
||||
track_creation user: user
|
||||
Gitlab::Tracking.event(self.class.name, 'successfully_submitted_form', user: user)
|
||||
end
|
||||
|
||||
|
|
@ -145,6 +146,11 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
users_sign_up_welcome_path(glm_tracking_params)
|
||||
end
|
||||
|
||||
def track_creation(user:)
|
||||
label = user_invited? ? 'invited' : 'signup'
|
||||
Gitlab::Tracking.event(self.class.name, 'create_user', label: label, user: user)
|
||||
end
|
||||
|
||||
def ensure_destroy_prerequisites_met
|
||||
if current_user.solo_owned_groups.present?
|
||||
redirect_to profile_account_path,
|
||||
|
|
@ -252,9 +258,15 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
end
|
||||
end
|
||||
|
||||
def after_pending_invitations_hook
|
||||
member_id = session.delete(:originating_member_id)
|
||||
def user_invited?
|
||||
!!member_id
|
||||
end
|
||||
|
||||
def member_id
|
||||
@member_id ||= session.delete(:originating_member_id)
|
||||
end
|
||||
|
||||
def after_pending_invitations_hook
|
||||
return unless member_id
|
||||
|
||||
# if invited multiple times to different projects, only the email clicked will be counted as accepted
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# AcceptingProjectSharesFinder
|
||||
#
|
||||
# Used to filter Shareable Groups by a set of params
|
||||
#
|
||||
# Arguments:
|
||||
# current_user - which user is requesting groups
|
||||
# params:
|
||||
# search: string
|
||||
module Groups
|
||||
class AcceptingProjectSharesFinder < Base
|
||||
def initialize(current_user, project_to_be_shared, params = {})
|
||||
@current_user = current_user
|
||||
@params = params
|
||||
@project_to_be_shared = project_to_be_shared
|
||||
end
|
||||
|
||||
def execute
|
||||
return Group.none unless can_share_project?
|
||||
|
||||
groups = if has_admin_access?
|
||||
Group.all
|
||||
else
|
||||
groups_with_guest_access_plus
|
||||
end
|
||||
|
||||
groups = groups.search(params[:search]) if params[:search].present?
|
||||
|
||||
sort(groups).with_route
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :current_user, :project_to_be_shared, :params
|
||||
|
||||
def has_admin_access?
|
||||
current_user&.can_read_all_resources?
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/Finder
|
||||
def groups_with_guest_access_plus
|
||||
GroupsFinder.new(current_user, min_access_level: Gitlab::Access::GUEST).execute
|
||||
end
|
||||
# rubocop: enable CodeReuse/Finder
|
||||
|
||||
def can_share_project?
|
||||
Ability.allowed?(current_user, :admin_project, project_to_be_shared) &&
|
||||
project_to_be_shared.allowed_to_share_with_group?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,7 +5,7 @@ module Groups
|
|||
private
|
||||
|
||||
def sort(items)
|
||||
items.order(Group.arel_table[:path].asc, Group.arel_table[:id].asc) # rubocop: disable CodeReuse/ActiveRecord
|
||||
items.reorder(Group.arel_table[:path].asc, Group.arel_table[:id].asc) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
def by_search(items)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ module Resolvers
|
|||
previous_stage_jobs_or_needs: [:needs, :pipeline],
|
||||
artifacts: [:job_artifacts],
|
||||
pipeline: [:user],
|
||||
project: [{ project: [:route, { namespace: [:route] }] }],
|
||||
detailed_status: [
|
||||
:metadata,
|
||||
{ pipeline: [:merge_request] },
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ module Types
|
|||
field :web_path, GraphQL::Types::String, null: true,
|
||||
description: 'Web path of the job.'
|
||||
|
||||
field :project, Types::ProjectType, null: true, description: 'Project that the job belongs to.'
|
||||
|
||||
def kind
|
||||
return ::Ci::Build unless [::Ci::Build, ::Ci::Bridge].include?(object.class)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,10 +13,11 @@ class Packages::Debian::FileMetadatum < ApplicationRecord
|
|||
}
|
||||
|
||||
validates :file_type, presence: true
|
||||
validates :file_type, inclusion: { in: %w[unknown] }, if: -> { package_file&.package&.debian_incoming? }
|
||||
validates :file_type, inclusion: { in: %w[unknown] },
|
||||
if: -> { package_file&.package&.debian_incoming? || package_file&.package&.processing? }
|
||||
validates :file_type,
|
||||
inclusion: { in: %w[source dsc deb udeb buildinfo changes] },
|
||||
if: -> { package_file&.package&.debian_package? }
|
||||
if: -> { package_file&.package&.debian_package? && !package_file&.package&.processing? }
|
||||
|
||||
validates :component,
|
||||
presence: true,
|
||||
|
|
|
|||
|
|
@ -43,14 +43,12 @@ class ProtectedBranch < ApplicationRecord
|
|||
end
|
||||
|
||||
def self.new_cache(project, ref_name, dry_run: true)
|
||||
if Feature.enabled?(:hash_based_cache_for_protected_branches, project)
|
||||
ProtectedBranches::CacheService.new(project).fetch(ref_name, dry_run: dry_run) do # rubocop: disable CodeReuse/ServiceClass
|
||||
self.matching(ref_name, protected_refs: protected_refs(project)).present?
|
||||
end
|
||||
ProtectedBranches::CacheService.new(project).fetch(ref_name, dry_run: dry_run) do # rubocop: disable CodeReuse/ServiceClass
|
||||
self.matching(ref_name, protected_refs: protected_refs(project)).present?
|
||||
end
|
||||
end
|
||||
|
||||
# Deprecated: https://gitlab.com/gitlab-org/gitlab/-/issues/368279
|
||||
# Deprecated: https://gitlab.com/gitlab-org/gitlab/-/issues/370608
|
||||
# ----------------------------------------------------------------
|
||||
CACHE_EXPIRE_IN = 1.hour
|
||||
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ module Ci
|
|||
# Create shared runner. Requires admin access
|
||||
{ runner_type: :instance_type }
|
||||
elsif runner_registrar_valid?('project') && project = ::Project.find_by_runners_token(registration_token)
|
||||
# Create a specific runner for the project
|
||||
# Create a project runner
|
||||
{ runner_type: :project_type, scope: project }
|
||||
elsif runner_registrar_valid?('group') && group = ::Group.find_by_runners_token(registration_token)
|
||||
# Create a specific runner for the group
|
||||
# Create a group runner
|
||||
{ runner_type: :group_type, scope: group }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,19 +10,23 @@ module Packages
|
|||
# used by ExclusiveLeaseGuard
|
||||
DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
|
||||
|
||||
def initialize(package_file, creator, distribution_name, component_name)
|
||||
def initialize(package_file, distribution_name, component_name)
|
||||
@package_file = package_file
|
||||
@creator = creator
|
||||
@distribution_name = distribution_name
|
||||
@component_name = component_name
|
||||
end
|
||||
|
||||
def execute
|
||||
return if @package_file.package.pending_destruction?
|
||||
|
||||
try_obtain_lease do
|
||||
validate!
|
||||
|
||||
@package_file.transaction do
|
||||
package.transaction do
|
||||
rename_package_and_set_version
|
||||
update_package
|
||||
update_file_metadata
|
||||
cleanup_temp_package
|
||||
end
|
||||
|
||||
::Packages::Debian::GenerateDistributionWorker.perform_async(:project, package.debian_distribution.id)
|
||||
|
|
@ -40,6 +44,80 @@ module Packages
|
|||
raise ArgumentError, "invalid package file type: #{file_metadata[:file_type]}"
|
||||
end
|
||||
|
||||
def file_metadata
|
||||
::Packages::Debian::ExtractMetadataService.new(@package_file).execute
|
||||
end
|
||||
strong_memoize_attr :file_metadata
|
||||
|
||||
def package
|
||||
package = temp_package.project
|
||||
.packages
|
||||
.debian
|
||||
.with_name(package_name)
|
||||
.with_version(package_version)
|
||||
.with_debian_codename(@distribution_name)
|
||||
.not_pending_destruction
|
||||
.last
|
||||
package || temp_package
|
||||
end
|
||||
strong_memoize_attr :package
|
||||
|
||||
def temp_package
|
||||
@package_file.package
|
||||
end
|
||||
strong_memoize_attr :temp_package
|
||||
|
||||
def package_name
|
||||
package_name_and_version[0]
|
||||
end
|
||||
|
||||
def package_version
|
||||
package_name_and_version[1]
|
||||
end
|
||||
|
||||
def package_name_and_version
|
||||
package_name = file_metadata[:fields]['Package']
|
||||
package_version = file_metadata[:fields]['Version']
|
||||
|
||||
if file_metadata[:fields]['Source']
|
||||
# "sample" or "sample (1.2.3~alpha2)"
|
||||
source_field_parts = file_metadata[:fields]['Source'].split(SOURCE_FIELD_SPLIT_REGEX)
|
||||
package_name = source_field_parts[0]
|
||||
package_version = source_field_parts[2] || package_version
|
||||
end
|
||||
|
||||
[package_name, package_version]
|
||||
end
|
||||
strong_memoize_attr :package_name_and_version
|
||||
|
||||
def rename_package_and_set_version
|
||||
package.update!(
|
||||
name: package_name,
|
||||
version: package_version,
|
||||
status: :default
|
||||
)
|
||||
end
|
||||
|
||||
def update_package
|
||||
return unless using_temporary_package?
|
||||
|
||||
package.update!(
|
||||
debian_publication_attributes: { distribution_id: distribution.id }
|
||||
)
|
||||
end
|
||||
|
||||
def using_temporary_package?
|
||||
package.id == temp_package.id
|
||||
end
|
||||
|
||||
def distribution
|
||||
Packages::Debian::DistributionsFinder.new(
|
||||
@package_file.package.project,
|
||||
codename: @distribution_name
|
||||
).execute.last!
|
||||
end
|
||||
strong_memoize_attr :distribution
|
||||
|
||||
def update_file_metadata
|
||||
::Packages::UpdatePackageFileService.new(@package_file, package_id: package.id)
|
||||
.execute
|
||||
|
|
@ -55,36 +133,8 @@ module Packages
|
|||
)
|
||||
end
|
||||
|
||||
def package
|
||||
strong_memoize(:package) do
|
||||
package_name = file_metadata[:fields]['Package']
|
||||
package_version = file_metadata[:fields]['Version']
|
||||
|
||||
if file_metadata[:fields]['Source']
|
||||
# "sample" or "sample (1.2.3~alpha2)"
|
||||
source_field_parts = file_metadata[:fields]['Source'].split(SOURCE_FIELD_SPLIT_REGEX)
|
||||
package_name = source_field_parts[0]
|
||||
package_version = source_field_parts[2] || package_version
|
||||
end
|
||||
|
||||
params = {
|
||||
'name': package_name,
|
||||
'version': package_version,
|
||||
'distribution_name': @distribution_name
|
||||
}
|
||||
response = Packages::Debian::FindOrCreatePackageService.new(project, @creator, params).execute
|
||||
response.payload[:package]
|
||||
end
|
||||
end
|
||||
|
||||
def file_metadata
|
||||
strong_memoize(:metadata) do
|
||||
::Packages::Debian::ExtractMetadataService.new(@package_file).execute
|
||||
end
|
||||
end
|
||||
|
||||
def project
|
||||
@package_file.package.project
|
||||
def cleanup_temp_package
|
||||
temp_package.destroy unless using_temporary_package?
|
||||
end
|
||||
|
||||
# used by ExclusiveLeaseGuard
|
||||
|
|
|
|||
|
|
@ -16,13 +16,10 @@
|
|||
.nav-controls.gl-pl-2
|
||||
.search-holder
|
||||
= render 'shared/projects/search_form', autofocus: true, admin_view: true
|
||||
- current_namespace = _('Namespace')
|
||||
- if params[:namespace_id].present?
|
||||
- namespace = Namespace.find(params[:namespace_id])
|
||||
- current_namespace = "#{namespace.kind}: #{namespace.full_path}"
|
||||
%button.dropdown-menu-toggle.btn.btn-default.btn-md.gl-button.js-namespace-select{ data: { show_any: 'true', field_name: 'namespace_id', placeholder: current_namespace, update_location: 'true' }, type: 'button' }
|
||||
%span.gl-dropdown-button-text
|
||||
= current_namespace
|
||||
- selected_text = "#{namespace.kind}: #{namespace.full_path}" if namespace
|
||||
.js-namespace-select{ data: { field_name: 'namespace_id', selected_id: namespace&.id, selected_text: selected_text, update_location: 'true' } }
|
||||
|
||||
= link_to new_project_path, class: 'gl-button btn btn-confirm' do
|
||||
= _('New Project')
|
||||
|
|
|
|||
|
|
@ -140,10 +140,7 @@
|
|||
.col-sm-3.col-form-label
|
||||
= f.label :new_namespace_id, _("Namespace")
|
||||
.col-sm-9
|
||||
- placeholder = _('Search for Namespace')
|
||||
%button.dropdown-menu-toggle.btn.btn-default.btn-md.gl-button.js-namespace-select{ data: { field_name: 'new_namespace_id', placeholder: placeholder }, type: 'button' }
|
||||
%span.gl-dropdown-button-text
|
||||
= placeholder
|
||||
.js-namespace-select{ data: { field_name: 'new_namespace_id', toggle_text_placeholder: _('Search for Namespace') } }
|
||||
|
||||
.form-group.row
|
||||
.offset-sm-3.col-sm-9
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
= render_if_exists 'groups/merge_request_approval_settings', expanded: expanded, group: @group, user: current_user
|
||||
= render_if_exists 'groups/insights', expanded: expanded
|
||||
= render_if_exists 'groups/analytics_dashboards', expanded: expanded
|
||||
|
||||
%section.settings.no-animate#js-badge-settings{ class: ('expanded' if expanded) }
|
||||
.settings-header
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
%h4
|
||||
= _('Specific runners')
|
||||
= s_('Runners|Project runners')
|
||||
|
||||
.bs-callout.help-callout
|
||||
- if can?(current_user, :register_project_runners, @project)
|
||||
= _('These runners are specific to this project.')
|
||||
= s_('Runners|These runners are assigned to this project.')
|
||||
- if params[:ci_runner_templates]
|
||||
%hr
|
||||
= render partial: 'ci/runner/setup_runner_in_aws',
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
%hr
|
||||
= render partial: 'ci/runner/how_to_setup_runner',
|
||||
locals: { registration_token: @project.runners_token,
|
||||
type: s_('Runners|specific'),
|
||||
type: _('project'),
|
||||
reset_token_url: reset_registration_token_namespace_project_settings_ci_cd_path,
|
||||
project_path: @project.path_with_namespace,
|
||||
group_path: '' }
|
||||
|
|
@ -22,13 +22,13 @@
|
|||
%hr
|
||||
|
||||
- if @project_runners.any?
|
||||
%h4.underlined-title= _('Available specific runners')
|
||||
%ul.bordered-list.activated-specific-runners
|
||||
%h4.underlined-title= s_('Runners|Assigned project runners')
|
||||
%ul.bordered-list{ data: { testid: 'assigned_project_runners' } }
|
||||
= render partial: 'projects/runners/runner', collection: @project_runners, as: :runner
|
||||
= paginate @project_runners, theme: "gitlab", param_name: "project_page", params: { expand_runners: true, anchor: 'js-runners-settings' }
|
||||
|
||||
- if @assignable_runners.any?
|
||||
%h4.underlined-title= _('Other available runners')
|
||||
%ul.bordered-list.available-specific-runners
|
||||
%ul.bordered-list{ data: { testid: 'available_project_runners' } }
|
||||
= render partial: 'projects/runners/runner', collection: @assignable_runners, as: :runner
|
||||
= paginate @assignable_runners, theme: "gitlab", param_name: "specific_page", :params => { :anchor => 'js-runners-settings'}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.row
|
||||
.col-sm-6
|
||||
= render 'projects/runners/specific_runners'
|
||||
= render 'projects/runners/project_runners'
|
||||
.col-sm-6
|
||||
= render 'projects/runners/shared_runners'
|
||||
= render 'projects/runners/group_runners'
|
||||
|
|
|
|||
|
|
@ -5,5 +5,4 @@
|
|||
= render partial: 'projects/issues/issue', collection: @issues
|
||||
= paginate @issues, theme: "gitlab"
|
||||
- else
|
||||
- project_select_button = local_assigns.fetch(:project_select_button, false)
|
||||
= render 'shared/empty_states/issues', project_select_button: project_select_button
|
||||
= render 'shared/empty_states/issues'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
- button_path = local_assigns.fetch(:new_project_issue_button_path, false)
|
||||
- project_select_button = local_assigns.fetch(:project_select_button, false)
|
||||
- show_import_button = local_assigns.fetch(:show_import_button, false) && can?(current_user, :import_issues, @project)
|
||||
- has_button = button_path || project_select_button
|
||||
- closed_issues_count = issuables_count_for_state(:issues, :closed)
|
||||
- opened_issues_count = issuables_count_for_state(:issues, :opened)
|
||||
- is_opened_state = params[:state] == 'opened'
|
||||
|
|
@ -39,11 +37,9 @@
|
|||
= _("The Issue Tracker is the place to add things that need to be improved or solved in a project")
|
||||
%p
|
||||
= _("Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable.")
|
||||
- if has_button
|
||||
- if button_path
|
||||
.text-center
|
||||
- if project_select_button
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: _('issue'), type: :issues, with_feature_enabled: 'issues'
|
||||
- elsif show_new_issue_link?(@project)
|
||||
- if show_new_issue_link?(@project)
|
||||
= link_to _('New issue'), button_path, class: 'gl-button btn btn-confirm', id: 'new_issue_link'
|
||||
|
||||
- if show_import_button
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
- button_path = local_assigns.fetch(:button_path, false)
|
||||
- project_select_button = local_assigns.fetch(:project_select_button, false)
|
||||
- has_button = button_path || project_select_button
|
||||
- closed_merged_count = issuables_count_for_state(:merged, :closed)
|
||||
- opened_merged_count = issuables_count_for_state(:merged, :opened)
|
||||
- is_opened_state = params[:state] == 'opened'
|
||||
|
|
@ -37,9 +35,6 @@
|
|||
= _("Merge requests are a place to propose changes you've made to a project and discuss those changes with others")
|
||||
%p
|
||||
= _("Interested parties can even contribute by pushing commits if they want to.")
|
||||
- if has_button
|
||||
- if button_path
|
||||
.text-center
|
||||
- if project_select_button
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: _('merge request'), type: :merge_requests, with_feature_enabled: 'merge_requests'
|
||||
- else
|
||||
= link_to _('New merge request'), button_path, class: 'gl-button btn btn-confirm', title: _('New merge request'), id: 'new_merge_request_link', data: { qa_selector: "new_merge_request_button" }
|
||||
= link_to _('New merge request'), button_path, class: 'gl-button btn btn-confirm', title: _('New merge request'), id: 'new_merge_request_link', data: { qa_selector: "new_merge_request_button" }
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@
|
|||
title: s_('Runners|This runner is associated with specific projects.'),
|
||||
dismissible: false) do |c|
|
||||
= c.body do
|
||||
= s_('Runners|You can set up a specific runner to be used by multiple projects but you cannot make this a shared or group runner.')
|
||||
= link_to _('Learn more.'), help_page_path('ci/runners/runners_scope', anchor: 'specific-runners'), target: '_blank', rel: 'noopener noreferrer'
|
||||
= s_('Runners|You can set up a project runner to be used by multiple projects but you cannot make this a shared or group runner.')
|
||||
= link_to _('Learn more.'), help_page_path('ci/runners/runners_scope', anchor: 'project-runners'), target: '_blank', rel: 'noopener noreferrer'
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@
|
|||
- elsif runner.group_type?
|
||||
= gl_badge_tag s_('Runners|group'), variant: :success
|
||||
- else
|
||||
= gl_badge_tag s_('Runners|specific'), variant: :info
|
||||
= gl_badge_tag s_('Runners|project'), variant: :info
|
||||
|
|
|
|||
|
|
@ -14,21 +14,20 @@ module Packages
|
|||
queue_namespace :package_repositories
|
||||
feature_category :package_registry
|
||||
|
||||
def perform(package_file_id, user_id, distribution_name, component_name)
|
||||
def perform(package_file_id, distribution_name, component_name)
|
||||
@package_file_id = package_file_id
|
||||
@user_id = user_id
|
||||
@distribution_name = distribution_name
|
||||
@component_name = component_name
|
||||
|
||||
return unless package_file && user && distribution_name && component_name
|
||||
return unless package_file && distribution_name && component_name
|
||||
# return if file has already been processed
|
||||
return unless package_file.debian_file_metadatum&.unknown?
|
||||
|
||||
::Packages::Debian::ProcessPackageFileService.new(package_file, user, distribution_name, component_name).execute
|
||||
::Packages::Debian::ProcessPackageFileService.new(package_file, distribution_name, component_name).execute
|
||||
rescue StandardError => e
|
||||
Gitlab::ErrorTracking.log_exception(e, package_file_id: @package_file_id, user_id: @user_id,
|
||||
Gitlab::ErrorTracking.log_exception(e, package_file_id: @package_file_id,
|
||||
distribution_name: @distribution_name, component_name: @component_name)
|
||||
package_file.destroy!
|
||||
package_file.package.update_column(:status, :error)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -37,11 +36,6 @@ module Packages
|
|||
::Packages::PackageFile.find_by_id(@package_file_id)
|
||||
end
|
||||
strong_memoize_attr :package_file
|
||||
|
||||
def user
|
||||
::User.find_by_id(@user_id)
|
||||
end
|
||||
strong_memoize_attr :user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: hash_based_cache_for_protected_branches
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92934
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368279
|
||||
milestone: '15.3'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: true
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: use_primary_and_secondary_stores_for_duplicate_jobs
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85740
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364381
|
||||
milestone:
|
||||
type: development
|
||||
group: group::scalability
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: use_primary_store_as_default_for_duplicate_jobs
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85740
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364381
|
||||
milestone:
|
||||
type: development
|
||||
group: group::scalability
|
||||
default_enabled: false
|
||||
|
|
@ -196,6 +196,10 @@ dast_profiles_pipelines:
|
|||
- table: ci_pipelines
|
||||
column: ci_pipeline_id
|
||||
on_delete: async_delete
|
||||
dast_profiles_tags:
|
||||
- table: tags
|
||||
column: tag_id
|
||||
on_delete: async_delete
|
||||
dast_scanner_profiles_builds:
|
||||
- table: ci_builds
|
||||
column: ci_build_id
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
table_name: dast_profiles_tags
|
||||
classes:
|
||||
- Dast::ScannerProfileTag
|
||||
feature_categories:
|
||||
- dynamic_application_security_testing
|
||||
description: Join Table for Runner tags and DAST Profiles
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108371
|
||||
milestone: '15.8'
|
||||
gitlab_schema: gitlab_main
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateDastProfilesTags < Gitlab::Database::Migration[2.1]
|
||||
def up
|
||||
create_table :dast_profiles_tags do |t|
|
||||
t.references :dast_profile, null: false, foreign_key: { on_delete: :cascade },
|
||||
index: { name: 'i_dast_profiles_tags_on_scanner_profiles_id' }
|
||||
|
||||
t.bigint :tag_id, null: false
|
||||
|
||||
t.index :tag_id, name: :index_dast_profiles_tags_on_tag_id
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :dast_profiles_tags
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
dad6e8972db3829dc6c02013ee87b08aa9bf4c50e58b35b0dbd67935ee4c266a
|
||||
|
|
@ -14573,6 +14573,21 @@ CREATE TABLE dast_profiles_pipelines (
|
|||
|
||||
COMMENT ON TABLE dast_profiles_pipelines IS '{"owner":"group::dynamic analysis","description":"Join table between DAST Profiles and CI Pipelines"}';
|
||||
|
||||
CREATE TABLE dast_profiles_tags (
|
||||
id bigint NOT NULL,
|
||||
dast_profile_id bigint NOT NULL,
|
||||
tag_id bigint NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE dast_profiles_tags_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE dast_profiles_tags_id_seq OWNED BY dast_profiles_tags.id;
|
||||
|
||||
CREATE TABLE dast_scanner_profiles (
|
||||
id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
|
|
@ -24104,6 +24119,8 @@ ALTER TABLE ONLY dast_profile_schedules ALTER COLUMN id SET DEFAULT nextval('das
|
|||
|
||||
ALTER TABLE ONLY dast_profiles ALTER COLUMN id SET DEFAULT nextval('dast_profiles_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY dast_profiles_tags ALTER COLUMN id SET DEFAULT nextval('dast_profiles_tags_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY dast_scanner_profiles ALTER COLUMN id SET DEFAULT nextval('dast_scanner_profiles_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY dast_scanner_profiles_tags ALTER COLUMN id SET DEFAULT nextval('dast_scanner_profiles_tags_id_seq'::regclass);
|
||||
|
|
@ -25979,6 +25996,9 @@ ALTER TABLE ONLY dast_profiles_pipelines
|
|||
ALTER TABLE ONLY dast_profiles
|
||||
ADD CONSTRAINT dast_profiles_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY dast_profiles_tags
|
||||
ADD CONSTRAINT dast_profiles_tags_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY dast_scanner_profiles_builds
|
||||
ADD CONSTRAINT dast_scanner_profiles_builds_pkey PRIMARY KEY (dast_scanner_profile_id, ci_build_id);
|
||||
|
||||
|
|
@ -28305,6 +28325,8 @@ CREATE INDEX i_compliance_frameworks_on_id_and_created_at ON compliance_manageme
|
|||
|
||||
CREATE INDEX i_dast_pre_scan_verification_steps_on_pre_scan_verification_id ON dast_pre_scan_verification_steps USING btree (dast_pre_scan_verification_id);
|
||||
|
||||
CREATE INDEX i_dast_profiles_tags_on_scanner_profiles_id ON dast_profiles_tags USING btree (dast_profile_id);
|
||||
|
||||
CREATE INDEX i_dast_scanner_profiles_tags_on_scanner_profiles_id ON dast_scanner_profiles_tags USING btree (dast_scanner_profile_id);
|
||||
|
||||
CREATE UNIQUE INDEX i_pm_licenses_on_spdx_identifier ON pm_licenses USING btree (spdx_identifier);
|
||||
|
|
@ -29287,6 +29309,8 @@ CREATE UNIQUE INDEX index_dast_profiles_on_project_id_and_name ON dast_profiles
|
|||
|
||||
CREATE UNIQUE INDEX index_dast_profiles_pipelines_on_ci_pipeline_id ON dast_profiles_pipelines USING btree (ci_pipeline_id);
|
||||
|
||||
CREATE INDEX index_dast_profiles_tags_on_tag_id ON dast_profiles_tags USING btree (tag_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_dast_scanner_profiles_on_project_id_and_name ON dast_scanner_profiles USING btree (project_id, name);
|
||||
|
||||
CREATE INDEX index_dast_scanner_profiles_tags_on_tag_id ON dast_scanner_profiles_tags USING btree (tag_id);
|
||||
|
|
@ -35332,6 +35356,9 @@ ALTER TABLE ONLY merge_request_user_mentions
|
|||
ALTER TABLE ONLY x509_commit_signatures
|
||||
ADD CONSTRAINT fk_rails_ab07452314 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY dast_profiles_tags
|
||||
ADD CONSTRAINT fk_rails_ab9e643cd8 FOREIGN KEY (dast_profile_id) REFERENCES dast_profiles(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY resource_iteration_events
|
||||
ADD CONSTRAINT fk_rails_abf5d4affa FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -1961,6 +1961,7 @@ Input type: `DastProfileCreateInput`
|
|||
| <a id="mutationdastprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the profile belongs to. |
|
||||
| <a id="mutationdastprofilecreatename"></a>`name` | [`String!`](#string) | Name of the profile. |
|
||||
| <a id="mutationdastprofilecreaterunaftercreate"></a>`runAfterCreate` | [`Boolean`](#boolean) | Run scan using profile after creation. Defaults to false. |
|
||||
| <a id="mutationdastprofilecreatetaglist"></a>`tagList` | [`[String!]`](#string) | Indicates the runner tags associated with the profile. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
@ -2027,6 +2028,7 @@ Input type: `DastProfileUpdateInput`
|
|||
| <a id="mutationdastprofileupdateid"></a>`id` | [`DastProfileID!`](#dastprofileid) | ID of the profile to be deleted. |
|
||||
| <a id="mutationdastprofileupdatename"></a>`name` | [`String`](#string) | Name of the profile. |
|
||||
| <a id="mutationdastprofileupdaterunafterupdate"></a>`runAfterUpdate` | [`Boolean`](#boolean) | Run scan using profile after update. Defaults to false. |
|
||||
| <a id="mutationdastprofileupdatetaglist"></a>`tagList` | [`[String!]`](#string) | Indicates the runner tags associated with the profile. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
@ -2051,7 +2053,7 @@ Input type: `DastScannerProfileCreateInput`
|
|||
| <a id="mutationdastscannerprofilecreatescantype"></a>`scanType` | [`DastScanTypeEnum`](#dastscantypeenum) | Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan. |
|
||||
| <a id="mutationdastscannerprofilecreateshowdebugmessages"></a>`showDebugMessages` | [`Boolean`](#boolean) | Indicates if debug messages should be included in DAST console output. True to include the debug messages. |
|
||||
| <a id="mutationdastscannerprofilecreatespidertimeout"></a>`spiderTimeout` | [`Int`](#int) | Maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="mutationdastscannerprofilecreatetaglist"></a>`tagList` | [`[String!]`](#string) | Indicates the runner tags associated with the scanner profile. |
|
||||
| <a id="mutationdastscannerprofilecreatetaglist"></a>`tagList` **{warning-solid}** | [`[String!]`](#string) | **Deprecated:** Moved to DastProfile. Deprecated in 15.8. |
|
||||
| <a id="mutationdastscannerprofilecreatetargettimeout"></a>`targetTimeout` | [`Int`](#int) | Maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="mutationdastscannerprofilecreateuseajaxspider"></a>`useAjaxSpider` | [`Boolean`](#boolean) | Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider. |
|
||||
|
||||
|
|
@ -2098,7 +2100,7 @@ Input type: `DastScannerProfileUpdateInput`
|
|||
| <a id="mutationdastscannerprofileupdatescantype"></a>`scanType` | [`DastScanTypeEnum`](#dastscantypeenum) | Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan. |
|
||||
| <a id="mutationdastscannerprofileupdateshowdebugmessages"></a>`showDebugMessages` | [`Boolean`](#boolean) | Indicates if debug messages should be included in DAST console output. True to include the debug messages. |
|
||||
| <a id="mutationdastscannerprofileupdatespidertimeout"></a>`spiderTimeout` | [`Int!`](#int) | Maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="mutationdastscannerprofileupdatetaglist"></a>`tagList` | [`[String!]`](#string) | Indicates the runner tags associated with the scanner profile. |
|
||||
| <a id="mutationdastscannerprofileupdatetaglist"></a>`tagList` **{warning-solid}** | [`[String!]`](#string) | **Deprecated:** Moved to DastProfile. Deprecated in 15.8. |
|
||||
| <a id="mutationdastscannerprofileupdatetargettimeout"></a>`targetTimeout` | [`Int!`](#int) | Maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="mutationdastscannerprofileupdateuseajaxspider"></a>`useAjaxSpider` | [`Boolean`](#boolean) | Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider. |
|
||||
|
||||
|
|
@ -11241,6 +11243,7 @@ CI/CD variables for a GitLab instance.
|
|||
| <a id="cijobpipeline"></a>`pipeline` | [`Pipeline`](#pipeline) | Pipeline the job belongs to. |
|
||||
| <a id="cijobplayable"></a>`playable` | [`Boolean!`](#boolean) | Indicates the job can be played. |
|
||||
| <a id="cijobpreviousstagejobsorneeds"></a>`previousStageJobsOrNeeds` | [`JobNeedUnionConnection`](#jobneedunionconnection) | Jobs that must complete before the job runs. Returns `BuildNeed`, which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise. (see [Connections](#connections)) |
|
||||
| <a id="cijobproject"></a>`project` | [`Project`](#project) | Project that the job belongs to. |
|
||||
| <a id="cijobqueuedat"></a>`queuedAt` | [`Time`](#time) | When the job was enqueued and marked as pending. |
|
||||
| <a id="cijobqueuedduration"></a>`queuedDuration` | [`Duration`](#duration) | How long the job was enqueued before starting. |
|
||||
| <a id="cijobrefname"></a>`refName` | [`String`](#string) | Ref name of the job. |
|
||||
|
|
@ -12001,6 +12004,7 @@ Represents a DAST Profile.
|
|||
| <a id="dastprofileeditpath"></a>`editPath` | [`String`](#string) | Relative web path to the edit page of a profile. |
|
||||
| <a id="dastprofileid"></a>`id` | [`DastProfileID!`](#dastprofileid) | ID of the profile. |
|
||||
| <a id="dastprofilename"></a>`name` | [`String`](#string) | Name of the profile. |
|
||||
| <a id="dastprofiletaglist"></a>`tagList` | [`[String!]`](#string) | Runner tags associated with the profile. |
|
||||
|
||||
### `DastProfileBranch`
|
||||
|
||||
|
|
@ -12055,7 +12059,7 @@ Represents a DAST scanner profile.
|
|||
| <a id="dastscannerprofilescantype"></a>`scanType` | [`DastScanTypeEnum`](#dastscantypeenum) | Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan. |
|
||||
| <a id="dastscannerprofileshowdebugmessages"></a>`showDebugMessages` | [`Boolean!`](#boolean) | Indicates if debug messages should be included in DAST console output. True to include the debug messages. |
|
||||
| <a id="dastscannerprofilespidertimeout"></a>`spiderTimeout` | [`Int`](#int) | Maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="dastscannerprofiletaglist"></a>`tagList` | [`[String!]`](#string) | Runner tags associated with the scanner profile. |
|
||||
| <a id="dastscannerprofiletaglist"></a>`tagList` **{warning-solid}** | [`[String!]`](#string) | **Deprecated** in 15.8. Moved to DastProfile. |
|
||||
| <a id="dastscannerprofiletargettimeout"></a>`targetTimeout` | [`Int`](#int) | Maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="dastscannerprofileuseajaxspider"></a>`useAjaxSpider` | [`Boolean!`](#boolean) | Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider. |
|
||||
|
||||
|
|
|
|||
|
|
@ -1135,6 +1135,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
|
|||
> - Immediately deleting subgroups was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/360008) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `immediate_delete_subgroup_api`. Disabled by default.
|
||||
> - Immediately deleting subgroups was [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/368276) in GitLab 15.4.
|
||||
> - Immediately deleting subgroups was [enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/368276) by default in GitLab 15.4.
|
||||
> - The flag `immediate_delete_subgroup_api` for immediately deleting subgroups was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/374069) in GitLab 15.9.
|
||||
|
||||
Only available to group owners and administrators.
|
||||
|
||||
|
|
|
|||
|
|
@ -1173,6 +1173,40 @@ GET /projects/:id/groups
|
|||
]
|
||||
```
|
||||
|
||||
## List a project's shareable groups
|
||||
|
||||
Get a list of groups that can be shared with a project
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/share_locations
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|-----------------------------|-------------------|------------------------|-------------|
|
||||
| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
|
||||
| `search` | string | **{dotted-circle}** No | Search for specific groups. |
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 22,
|
||||
"web_url": "http://127.0.0.1:3000/groups/gitlab-org",
|
||||
"name": "Gitlab Org",
|
||||
"avatar_url": null,
|
||||
"full_name": "Gitlab Org",
|
||||
"full_path": "gitlab-org"
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"web_url": "http://127.0.0.1:3000/groups/gnuwget",
|
||||
"name": "Gnuwget",
|
||||
"avatar_url": null,
|
||||
"full_name": "Gnuwget",
|
||||
"full_path": "gnuwget"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Get project events
|
||||
|
||||
Refer to the [Events API documentation](events.md#list-a-projects-visible-events).
|
||||
|
|
@ -2586,20 +2620,6 @@ GET /projects/:id/push_rule
|
|||
}
|
||||
```
|
||||
|
||||
Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/)
|
||||
can also see the `commit_committer_check` and `reject_unsigned_commits`
|
||||
parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"project_id": 3,
|
||||
"commit_committer_check": false,
|
||||
"reject_unsigned_commits": false
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Add project push rule
|
||||
|
||||
Adds a push rule to a specified project.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ GitLab and the runner are then connected.
|
|||
|
||||
## List owned runners
|
||||
|
||||
Get a list of specific runners available to the user.
|
||||
Get a list of runners available to the user.
|
||||
|
||||
```plaintext
|
||||
GET /runners
|
||||
|
|
@ -46,7 +46,7 @@ GET /runners?tag_list=tag1,tag2
|
|||
|
||||
| Attribute | Type | Required | Description |
|
||||
|------------|--------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to return, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
|
||||
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to return, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
|
||||
| `type` | string | no | The type of runners to return, one of: `instance_type`, `group_type`, `project_type` |
|
||||
| `status` | string | no | The status of runners to return, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
|
||||
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
|
||||
|
|
@ -97,7 +97,7 @@ Example response:
|
|||
|
||||
## List all runners **(FREE SELF)**
|
||||
|
||||
Get a list of all runners in the GitLab instance (specific and shared). Access
|
||||
Get a list of all runners in the GitLab instance (project and shared). Access
|
||||
is restricted to users with administrator access.
|
||||
|
||||
```plaintext
|
||||
|
|
@ -325,7 +325,7 @@ Example response:
|
|||
|
||||
### Pause a runner
|
||||
|
||||
Pause a specific runner.
|
||||
Pause a runner.
|
||||
|
||||
```plaintext
|
||||
PUT --form "paused=true" /runners/:runner_id
|
||||
|
|
@ -463,7 +463,7 @@ GET /projects/:id/runners?tag_list=tag1,tag2
|
|||
| Attribute | Type | Required | Description |
|
||||
|------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to return, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
|
||||
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to return, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
|
||||
| `type` | string | no | The type of runners to return, one of: `instance_type`, `group_type`, `project_type` |
|
||||
| `status` | string | no | The status of runners to return, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
|
||||
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
|
||||
|
|
@ -514,7 +514,7 @@ Example response:
|
|||
|
||||
## Enable a runner in project
|
||||
|
||||
Enable an available specific runner in the project.
|
||||
Enable an available project runner in the project.
|
||||
|
||||
```plaintext
|
||||
POST /projects/:id/runners
|
||||
|
|
@ -548,7 +548,7 @@ Example response:
|
|||
|
||||
## Disable a runner from project
|
||||
|
||||
Disable a specific runner from the project. It works only if the project isn't
|
||||
Disable a project runner from the project. It works only if the project isn't
|
||||
the only project associated with the specified runner. If so, an error is
|
||||
returned. Use the call to [delete a runner](#delete-a-runner) instead.
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ To ensure maximum availability of the cache, do one or more of the following:
|
|||
|
||||
- [Tag your runners](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) and use the tag on jobs
|
||||
that share the cache.
|
||||
- [Use runners that are only available to a particular project](../runners/runners_scope.md#prevent-a-specific-runner-from-being-enabled-for-other-projects).
|
||||
- [Use runners that are only available to a particular project](../runners/runners_scope.md#prevent-a-project-runner-from-being-enabled-for-other-projects).
|
||||
- [Use a `key`](../yaml/index.md#cachekey) that fits your workflow. For example,
|
||||
you can configure a different cache for each branch.
|
||||
|
||||
|
|
|
|||
|
|
@ -8,15 +8,30 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
> - `CI_JOB_JWT` variable for reading secrets from Vault [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) in GitLab 12.10.
|
||||
> - `CI_JOB_JWT_V2` variable to support additional OIDC providers [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346737) in GitLab 14.7.
|
||||
> - [ID tokens](../yaml/index.md) to support any OIDC provider, including HashiCorp Vault, [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356986) in GitLab 15.7.
|
||||
|
||||
GitLab CI/CD supports [OpenID Connect (OIDC)](https://openid.net/connect/faq/) that allows your build and deployment job access to cloud credentials and services. Historically, teams stored secrets in projects or applied permissions on the GitLab Runner instance to build and deploy. To support this, a predefined variable named `CI_JOB_JWT_V2` is included in the CI/CD job allowing you to follow a scalable and least-privilege security approach.
|
||||
GitLab CI/CD supports [OpenID Connect (OIDC)](https://openid.net/connect/faq/) to
|
||||
give your build and deployment jobs access to cloud credentials and services.
|
||||
Historically, teams stored secrets in projects or applied permissions on the GitLab Runner
|
||||
instance to build and deploy. OIDC capable [ID tokens](../yaml/index.md#id_tokens) are configurable
|
||||
in the CI/CD job allowing you to follow a scalable and least-privilege security approach.
|
||||
|
||||
In GitLab 15.6 and earlier, you must use `CI_JOB_JWT_V2` instead of an ID token,
|
||||
but it is not customizable. In GitLab 14.6 an earlier you must use the `CI_JOB_JWT`, which has limited support.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Account on GitLab.
|
||||
- Access to a cloud provider that supports OIDC to configure authorization and create roles.
|
||||
|
||||
The original implementation of `CI_JOB_JWT` supports [HashiCorp Vault integration](../examples/authenticating-with-hashicorp-vault/index.md). The updated implementation of `CI_JOB_JWT_V2` supports additional cloud providers with OIDC including AWS, Azure, GCP, and Vault.
|
||||
ID tokens and `CI_JOB_JWT_V2` support cloud providers with OIDC, including:
|
||||
|
||||
- AWS
|
||||
- Azure
|
||||
- GCP
|
||||
- HashiCorp Vault
|
||||
|
||||
The `CI_JOB_JWT` only supports the [HashiCorp Vault integration](../examples/authenticating-with-hashicorp-vault/index.md).
|
||||
|
||||
NOTE:
|
||||
Configuring OIDC enables JWT token access to the target environments for all pipelines.
|
||||
|
|
@ -25,10 +40,6 @@ review for the pipeline, focusing on the additional access. You can use the [sof
|
|||
as a starting point, and for more information about supply chain attacks, see
|
||||
[How a DevOps Platform helps protect against supply chain attacks](https://about.gitlab.com/blog/2021/04/28/devops-platform-supply-chain-attacks/).
|
||||
|
||||
The `CI_JOB_JWT_V2` variable is available for testing, but the full feature is planned
|
||||
to be generally available when [issue 360657](https://gitlab.com/gitlab-org/gitlab/-/issues/360657)
|
||||
is complete.
|
||||
|
||||
## Use cases
|
||||
|
||||
- Removes the need to store secrets in your GitLab group or project. Temporary credentials can be retrieved from your cloud provider through OIDC.
|
||||
|
|
@ -39,18 +50,18 @@ is complete.
|
|||
|
||||
## How it works
|
||||
|
||||
Each job has a JSON web token (JWT) provided as a CI/CD [predefined variable](../variables/predefined_variables.md) named `CI_JOB_JWT` or `CI_JOB_JWT_V2`. This JWT can be used to authenticate with the OIDC-supported cloud provider such as AWS, Azure, GCP, or Vault.
|
||||
Each job can be configured with ID tokens, which are provided as a CI/CD variable. These JWTs can be used to authenticate with the OIDC-supported cloud provider such as AWS, Azure, GCP, or Vault.
|
||||
|
||||
The following fields are included in the JWT:
|
||||
|
||||
| Field | When | Description |
|
||||
| ----------------------- | ------ | ----------- |
|
||||
| `aud` | Always | Specified in the [ID tokens](../yaml/index.md#id_tokens) configuration |
|
||||
| `jti` | Always | Unique identifier for this token |
|
||||
| `iss` | Always | Issuer, the domain of your GitLab instance |
|
||||
| `iat` | Always | Issued at |
|
||||
| `nbf` | Always | Not valid before |
|
||||
| `exp` | Always | Expires at |
|
||||
| `aud` | Always | Issuer, the domain of your GitLab instance |
|
||||
| `sub` | Always |`project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}` |
|
||||
| `namespace_id` | Always | Use this to scope to group or user level namespace by ID |
|
||||
| `namespace_path` | Always | Use this to scope to group or user level namespace by path |
|
||||
|
|
@ -72,7 +83,7 @@ The following fields are included in the JWT:
|
|||
{
|
||||
"jti": "c82eeb0c-5c6f-4a33-abf5-4c474b92b558",
|
||||
"iss": "https://gitlab.example.com",
|
||||
"aud": "https://gitlab.example.com",
|
||||
"aud": "https://vault.example.com",
|
||||
"iat": 1585710286,
|
||||
"nbf": 1585798372,
|
||||
"exp": 1585713886,
|
||||
|
|
@ -102,8 +113,8 @@ sequenceDiagram
|
|||
participant GitLab
|
||||
Note right of Cloud: Create OIDC identity provider
|
||||
Note right of Cloud: Create role with conditionals
|
||||
Note left of GitLab: CI/CD job with CI_JOB_JWT_V2
|
||||
GitLab->>+Cloud: Call cloud API with CI_JOB_JWT_V2
|
||||
Note left of GitLab: CI/CD job with ID token
|
||||
GitLab->>+Cloud: Call cloud API with ID token
|
||||
Note right of Cloud: Decode & verify JWT with public key (https://gitlab/-/jwks)
|
||||
Note right of Cloud: Validate audience defined in OIDC
|
||||
Note right of Cloud: Validate conditional (sub, aud) role
|
||||
|
|
@ -115,14 +126,25 @@ sequenceDiagram
|
|||
|
||||
1. Create an OIDC identity provider in the cloud (for example, AWS, Azure, GCP, Vault).
|
||||
1. Create a conditional role in the cloud service that filters to a group, project, branch, or tag.
|
||||
1. The CI/CD job includes a predefined variable `CI_JOB_JWT_V2` that is a JWT token. You can use this token for authorization with your cloud API.
|
||||
1. The CI/CD job includes an ID token which is a JWT token. You can use this token for authorization with your cloud API.
|
||||
1. The cloud verifies the token, validates the conditional role from the payload, and returns a temporary credential.
|
||||
|
||||
## Configure a conditional role with OIDC claims
|
||||
|
||||
To configure the trust between GitLab and OIDC, you must create a conditional role in the cloud provider that checks against the JWT token. The condition is validated against the JWT to create a trust specifically against two claims, the audience and subject.
|
||||
To configure the trust between GitLab and OIDC, you must create a conditional role in the cloud provider that checks against the JWT.
|
||||
The condition is validated against the JWT to create a trust specifically against two claims, the audience and subject.
|
||||
|
||||
- Audience or `aud`: Configured as part of the ID token:
|
||||
|
||||
```yaml
|
||||
job_needing_oidc_auth:
|
||||
id_tokens:
|
||||
OIDC_TOKEN:
|
||||
aud: https://oidc.provider.com
|
||||
script:
|
||||
- echo $OIDC_TOKEN
|
||||
```
|
||||
|
||||
- Audience or `aud`: The URL of the GitLab instance. This is defined when the identity provider is first configured in your cloud provider.
|
||||
- Subject or `sub`: A concatenation of metadata describing the GitLab CI/CD workflow including the group, project, branch, and tag. The `sub` field is in the following format:
|
||||
- `project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}`
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ On self-managed GitLab instances:
|
|||
- Administrators can [assign more CI/CD minutes](#set-the-quota-of-cicd-minutes-for-a-specific-namespace)
|
||||
if a namespace uses all the CI/CD minutes in its monthly quota.
|
||||
|
||||
[Specific runners](../runners/runners_scope.md#specific-runners) are not subject to a quota of CI/CD minutes.
|
||||
[Project runners](../runners/runners_scope.md#project-runners) are not subject to a quota of CI/CD minutes.
|
||||
|
||||
## Set the quota of CI/CD minutes for all namespaces
|
||||
|
||||
|
|
@ -216,9 +216,9 @@ The cost factors on self-managed instances are:
|
|||
|
||||
#### Cost factor for community contributions to GitLab projects
|
||||
|
||||
Community contributors can use up to 300,000 minutes on shared runners when contributing to open source projects
|
||||
Community contributors can use up to 300,000 minutes on shared runners when contributing to open source projects
|
||||
maintained by GitLab. The maximum of 300,000 minutes would only be possible if contributing exclusively to projects [part of the GitLab product](https://about.gitlab.com/handbook/engineering/metrics/#projects-that-are-part-of-the-product). The total number of minutes available on shared runners
|
||||
is reduced by the CI/CD minutes used by pipelines from other projects.
|
||||
is reduced by the CI/CD minutes used by pipelines from other projects.
|
||||
The 300,000 minutes applies to all SaaS tiers, and the cost factor calculation is:
|
||||
|
||||
- `Monthly minute quota / 300,000 job duration minutes = Cost factor`
|
||||
|
|
|
|||
|
|
@ -473,6 +473,7 @@ a few different methods, based on where the variable is created or defined.
|
|||
### Pass YAML-defined CI/CD variables
|
||||
|
||||
You can use the `variables` keyword to pass CI/CD variables to a downstream pipeline.
|
||||
These variables are "trigger variables" for [variable precedence](../variables/index.md#cicd-variable-precedence).
|
||||
|
||||
For example:
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ On GitLab.com, you cannot override the job timeout for shared runners and must u
|
|||
To set the maximum job timeout:
|
||||
|
||||
1. In a project, go to **Settings > CI/CD > Runners**.
|
||||
1. Select your specific runner to edit the settings.
|
||||
1. Select your project runner to edit the settings.
|
||||
1. Enter a value under **Maximum job timeout**. Must be 10 minutes or more. If not
|
||||
defined, the [project's job timeout setting](../pipelines/settings.md#set-a-limit-for-how-long-jobs-can-run)
|
||||
is used.
|
||||
|
|
@ -89,7 +89,7 @@ To protect or unprotect a runner:
|
|||
1. Check the **Protected** option.
|
||||
1. Select **Save changes**.
|
||||
|
||||

|
||||

|
||||
|
||||
### Forks
|
||||
|
||||
|
|
@ -150,7 +150,7 @@ the source of the HTTP requests it makes to GitLab when polling for jobs. The
|
|||
IP address is always kept up to date so if the runner IP changes it
|
||||
automatically updates in GitLab.
|
||||
|
||||
The IP address for shared runners and specific runners can be found in
|
||||
The IP address for shared runners and project runners can be found in
|
||||
different places.
|
||||
|
||||
### Determine the IP address of a shared runner
|
||||
|
|
@ -164,16 +164,16 @@ the GitLab instance. To determine this:
|
|||
|
||||

|
||||
|
||||
### Determine the IP address of a specific runner
|
||||
### Determine the IP address of a project runner
|
||||
|
||||
To can find the IP address of a runner for a specific project,
|
||||
To can find the IP address of a runner for a project project,
|
||||
you must have the Owner role for the
|
||||
project.
|
||||
|
||||
1. Go to the project's **Settings > CI/CD** and expand the **Runners** section.
|
||||
1. On the details page you should see a row for **IP Address**.
|
||||
|
||||

|
||||

|
||||
|
||||
## Use tags to control which jobs a runner can run
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -11,8 +11,8 @@ Runners are available based on who you want to have access:
|
|||
|
||||
- [Shared runners](#shared-runners) are available to all groups and projects in a GitLab instance.
|
||||
- [Group runners](#group-runners) are available to all projects and subgroups in a group.
|
||||
- [Specific runners](#specific-runners) are associated with specific projects.
|
||||
Typically, specific runners are used for one project at a time.
|
||||
- [Project runners](#project-runners) are associated with specific projects.
|
||||
Typically, project runners are used by one project at a time.
|
||||
|
||||
## Shared runners
|
||||
|
||||
|
|
@ -241,78 +241,78 @@ You must have the Owner role for the group.
|
|||
You must remove it from each project first.
|
||||
1. On the confirmation dialog, select **OK**.
|
||||
|
||||
## Specific runners
|
||||
## Project runners
|
||||
|
||||
Use _specific runners_ when you want to use runners for specific projects. For example,
|
||||
Use _project runners_ when you want to use runners for specific projects. For example,
|
||||
when you have:
|
||||
|
||||
- Jobs with specific requirements, like a deploy job that requires credentials.
|
||||
- Projects with a lot of CI activity that can benefit from being separate from other runners.
|
||||
|
||||
You can set up a specific runner to be used by multiple projects. Specific runners
|
||||
You can set up a project runner to be used by multiple projects. Project runners
|
||||
must be enabled for each project explicitly.
|
||||
|
||||
Specific runners process jobs by using a first in, first out ([FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics))) queue.
|
||||
Project runners process jobs by using a first in, first out ([FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics))) queue.
|
||||
|
||||
NOTE:
|
||||
Specific runners do not get shared with forked projects automatically.
|
||||
Project runners do not get shared with forked projects automatically.
|
||||
A fork *does* copy the CI/CD settings of the cloned repository.
|
||||
|
||||
### Create a specific runner
|
||||
### Create a project runner
|
||||
|
||||
You can create a specific runner for your self-managed GitLab instance or for GitLab.com.
|
||||
You can create a project runner for your self-managed GitLab instance or for GitLab.com.
|
||||
|
||||
Prerequisite:
|
||||
|
||||
- You must have at least the Maintainer role for the project.
|
||||
|
||||
To create a specific runner:
|
||||
To create a project runner:
|
||||
|
||||
1. [Install GitLab Runner](https://docs.gitlab.com/runner/install/).
|
||||
1. On the top bar, select **Main menu > Projects** and find the project where you want to use the runner.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. In the **Specific runners** section, note the URL and token.
|
||||
1. In the **Project runners** section, note the URL and token.
|
||||
1. [Register the runner](https://docs.gitlab.com/runner/register/).
|
||||
|
||||
The runner is now enabled for the project.
|
||||
|
||||
### Enable a specific runner for a different project
|
||||
### Enable a project runner for a different project
|
||||
|
||||
After a specific runner is created, you can enable it for other projects.
|
||||
After a project runner is created, you can enable it for other projects.
|
||||
|
||||
Prerequisites:
|
||||
You must have at least the Maintainer role for:
|
||||
|
||||
- The project where the runner is already enabled.
|
||||
- The project where you want to enable the runner.
|
||||
- The specific runner must not be [locked](#prevent-a-specific-runner-from-being-enabled-for-other-projects).
|
||||
- The project runner must not be [locked](#prevent-a-project-runner-from-being-enabled-for-other-projects).
|
||||
|
||||
To enable a specific runner for a project:
|
||||
To enable a project runner for a project:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find the project where you want to enable the runner.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. In the **Specific runners** area, by the runner you want, select **Enable for this project**.
|
||||
1. In the **Project runners** area, by the runner you want, select **Enable for this project**.
|
||||
|
||||
You can edit a specific runner from any of the projects it's enabled for.
|
||||
You can edit a project runner from any of the projects it's enabled for.
|
||||
The modifications, which include unlocking and editing tags and the description,
|
||||
affect all projects that use the runner.
|
||||
|
||||
An administrator can [enable the runner for multiple projects](../../user/admin_area/settings/continuous_integration.md#enable-a-specific-runner-for-multiple-projects).
|
||||
An administrator can [enable the runner for multiple projects](../../user/admin_area/settings/continuous_integration.md#enable-a-project-runner-for-multiple-projects).
|
||||
|
||||
### Prevent a specific runner from being enabled for other projects
|
||||
### Prevent a project runner from being enabled for other projects
|
||||
|
||||
You can configure a specific runner so it is "locked" and cannot be enabled for other projects.
|
||||
You can configure a project runner so it is "locked" and cannot be enabled for other projects.
|
||||
This setting can be enabled when you first [register a runner](https://docs.gitlab.com/runner/register/),
|
||||
but can also be changed later.
|
||||
|
||||
To lock or unlock a specific runner:
|
||||
To lock or unlock a project runner:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find the project where you want to enable the runner.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Runners**.
|
||||
1. Find the specific runner you want to lock or unlock. Make sure it's enabled. You cannot lock shared or group runners.
|
||||
1. Find the project runner you want to lock or unlock. Make sure it's enabled. You cannot lock shared or group runners.
|
||||
1. Select **Edit** (**{pencil}**).
|
||||
1. Select the **Lock to current projects** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
stage: Verify
|
||||
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
|
||||
type: tutorial
|
||||
---
|
||||
|
||||
# OpenID Connect (OIDC) Authentication Using ID Tokens **(FREE)**
|
||||
|
||||
You can authenticate with third party services using GitLab CI/CD's
|
||||
[ID tokens](../yaml/index.md#id_tokens).
|
||||
|
||||
## ID Tokens
|
||||
|
||||
[ID tokens](../yaml/index.md#id_tokens) are JSON Web Tokens (JWTs) that can be added to a GitLab CI/CD job. They can be used for OIDC
|
||||
authentication with third-party services, and are used by the [`secrets`](../yaml/index.md#secrets) keyword to authenticate with HashiCorp Vault.
|
||||
|
||||
ID tokens are configured in the `.gitlab-ci.yml`. For example:
|
||||
|
||||
```yaml
|
||||
job_with_id_tokens:
|
||||
id_tokens:
|
||||
FIRST_ID_TOKEN:
|
||||
aud: https://first.service.com
|
||||
SECOND_ID_TOKEN:
|
||||
aud: https://second.service.com
|
||||
script:
|
||||
- first-service-authentication-script.sh $FIRST_ID_TOKEN
|
||||
- second-service-authentication-script.sh $SECOND_ID_TOKEN
|
||||
```
|
||||
|
||||
In this example, the two tokens have different `aud` claims. Third party services can be configured to reject tokens
|
||||
that do not have an `aud` claim matching their bound audience. Use this functionality to reduce the number of
|
||||
services with which a token can authenticate. This reduces the severity of having a token compromised.
|
||||
|
||||
## Manual ID Token authentication
|
||||
|
||||
You can use ID tokens for OIDC authentication with a third party service. For example:
|
||||
|
||||
```yaml
|
||||
manual_authentication:
|
||||
variables:
|
||||
VAULT_ADDR: http://vault.example.com:8200
|
||||
image: vault:latest
|
||||
id_tokens:
|
||||
VAULT_ID_TOKEN:
|
||||
aud: http://vault.example.com:8200
|
||||
script:
|
||||
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-example jwt=$VAULT_ID_TOKEN)"
|
||||
- export PASSWORD="$(vault kv get -field=password secret/myproject/example/db)"
|
||||
- my-authentication-script.sh $VAULT_TOKEN $PASSWORD
|
||||
```
|
||||
|
||||
## Automatic ID Token authentication with HashiCorp Vault **(PREMIUM)**
|
||||
|
||||
You can use ID tokens to automatically fetch secrets from HashiCorp Vault with the
|
||||
[`secrets`](../yaml/index.md#secrets) keyword.
|
||||
|
||||
### Enable automatic ID token authentication
|
||||
|
||||
To enable automatic ID token authentication:
|
||||
|
||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand **Token Access**.
|
||||
1. Toggle **Limit JSON Web Token (JWT) access** to enabled.
|
||||
|
||||
### Configure automatic ID Token authentication
|
||||
|
||||
If one ID token is defined, the `secrets` keyword automatically uses it to authenticate with Vault. For example:
|
||||
|
||||
```yaml
|
||||
job_with_secrets:
|
||||
id_tokens:
|
||||
VAULT_ID_TOKEN:
|
||||
aud: https://example.vault.com
|
||||
secrets:
|
||||
PROD_DB_PASSWORD:
|
||||
vault: example/db/password # authenticates using $VAULT_ID_TOKEN
|
||||
script:
|
||||
- access-prod-db.sh --token $PROD_DB_PASSWORD
|
||||
```
|
||||
|
||||
If more than one ID token is defined, use the `token` keyword to specify which token should be used. For example:
|
||||
|
||||
```yaml
|
||||
job_with_secrets:
|
||||
id_tokens:
|
||||
FIRST_ID_TOKEN:
|
||||
aud: https://first.service.com
|
||||
SECOND_ID_TOKEN:
|
||||
aud: https://second.service.com
|
||||
secrets:
|
||||
FIRST_DB_PASSWORD:
|
||||
vault: first/db/password
|
||||
token: $FIRST_ID_TOKEN
|
||||
SECOND_DB_PASSWORD:
|
||||
vault: second/db/password
|
||||
token: $SECOND_ID_TOKEN
|
||||
script:
|
||||
- access-first-db.sh --token $FIRST_DB_PASSWORD
|
||||
- access-second-db.sh --token $SECOND_DB_PASSWORD
|
||||
```
|
||||
|
|
@ -23,10 +23,16 @@ GitLab has selected [Vault by HashiCorp](https://www.vaultproject.io) as the
|
|||
first supported provider, and [KV-V2](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v2)
|
||||
as the first supported secrets engine.
|
||||
|
||||
GitLab authenticates using Vault's
|
||||
By default, GitLab authenticates using Vault's
|
||||
[JSON Web Token (JWT) authentication method](https://developer.hashicorp.com/vault/docs/auth/jwt#jwt-authentication), using
|
||||
the [JSON Web Token](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) (`CI_JOB_JWT`)
|
||||
introduced in GitLab 12.10.
|
||||
the [JSON Web Token](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) (`CI_JOB_JWT`).
|
||||
|
||||
[ID tokens](../yaml/index.md#id_tokens) is the preferred secure way to authenticate with Vault,
|
||||
because ID tokens are defined per-job. GitLab can also authenticate with Vault by using the `CI_JOB_JWT`,
|
||||
but that token is provided to every job, which can be a security risk.
|
||||
|
||||
The [Authenticating and Reading Secrets With HashiCorp Vault](../examples/authenticating-with-hashicorp-vault/index.md)
|
||||
tutorial has more details about authenticating with ID tokens.
|
||||
|
||||
You must [configure your Vault server](#configure-your-vault-server) before you
|
||||
can use [use Vault secrets in a CI job](#use-vault-secrets-in-a-ci-job).
|
||||
|
|
@ -106,9 +112,14 @@ After [configuring your Vault server](#configure-your-vault-server), you can use
|
|||
the secrets stored in Vault by defining them with the `vault` keyword:
|
||||
|
||||
```yaml
|
||||
secrets:
|
||||
DATABASE_PASSWORD:
|
||||
vault: production/db/password@ops # translates to secret `ops/data/production/db`, field `password`
|
||||
job_using_vault:
|
||||
id_tokens:
|
||||
VAULT_ID_TOKEN:
|
||||
aud: https://gitlab.com
|
||||
secrets:
|
||||
DATABASE_PASSWORD:
|
||||
vault: production/db/password@ops # translates to secret `ops/data/production/db`, field `password`
|
||||
token: $VAULT_ID_TOKEN
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
|
@ -125,9 +136,13 @@ To overwrite the default behavior, set the `file` option explicitly:
|
|||
|
||||
```yaml
|
||||
secrets:
|
||||
id_tokens:
|
||||
VAULT_ID_TOKEN:
|
||||
aud: https://gitlab.com
|
||||
DATABASE_PASSWORD:
|
||||
vault: production/db/password@ops
|
||||
file: false
|
||||
token: $VAULT_ID_TOKEN
|
||||
```
|
||||
|
||||
In this example, the secret value is put directly in the `DATABASE_PASSWORD` variable
|
||||
|
|
@ -177,8 +192,8 @@ Always restrict your roles to a project or namespace by using one of the provide
|
|||
claims like `project_id` or `namespace_id`. Without these restrictions, any JWT
|
||||
generated by this GitLab instance may be allowed to authenticate using this role.
|
||||
|
||||
For a full list of `CI_JOB_JWT` claims, read the
|
||||
[How it works](../examples/authenticating-with-hashicorp-vault/index.md#how-it-works) section of the
|
||||
For a full list of ID token JWT claims, read the
|
||||
[How It Works](../examples/authenticating-with-hashicorp-vault/index.md#how-it-works) section of the
|
||||
[Authenticating and Reading Secrets With HashiCorp Vault](../examples/authenticating-with-hashicorp-vault/index.md) tutorial.
|
||||
|
||||
You can also specify some attributes for the resulting Vault tokens, such as time-to-live,
|
||||
|
|
@ -188,7 +203,7 @@ for the JSON web token method.
|
|||
|
||||
## Using a self-signed Vault server
|
||||
|
||||
When the Vault server is using a self-signed certificate, you will see the following error in the job logs:
|
||||
When the Vault server is using a self-signed certificate, you see the following error in the job logs:
|
||||
|
||||
```plaintext
|
||||
ERROR: Job failed (system failure): resolving secrets: initializing Vault service: preparing authenticated client: checking Vault server health: Get https://vault.example.com:8000/v1/sys/health?drsecondarycode=299&performancestandbycode=299&sealedcode=299&standbycode=299&uninitcode=299: x509: certificate signed by unknown authority
|
||||
|
|
@ -197,7 +212,7 @@ ERROR: Job failed (system failure): resolving secrets: initializing Vault servic
|
|||
You have two options to solve this error:
|
||||
|
||||
- Add the self-signed certificate to the GitLab Runner server's CA store.
|
||||
If you deployed GitLab Runner using the [Helm chart](https://docs.gitlab.com/runner/install/kubernetes.html), you will have to create your own GitLab Runner image.
|
||||
If you deployed GitLab Runner using the [Helm chart](https://docs.gitlab.com/runner/install/kubernetes.html), you have to create your own GitLab Runner image.
|
||||
- Use the `VAULT_CACERT` environment variable to configure GitLab Runner to trust the certificate:
|
||||
- If you are using systemd to manage GitLab Runner, see [how to add an environment variable for GitLab Runner](https://docs.gitlab.com/runner/configuration/init.html#setting-custom-environment-variables).
|
||||
- If you deployed GitLab Runner using the [Helm chart](https://docs.gitlab.com/runner/install/kubernetes.html):
|
||||
|
|
|
|||
|
|
@ -3794,6 +3794,43 @@ job:
|
|||
- The `file` keyword is a setting for the CI/CD variable and must be nested under
|
||||
the CI/CD variable name, not in the `vault` section.
|
||||
|
||||
#### `secrets:token`
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356986) in GitLab 15.8.
|
||||
|
||||
Use `secrets:token` to explicitly select a token to use when authenticating with Vault by referencing the token's CI/CD variable.
|
||||
|
||||
This keyword has no effect if [**Limit JSON Web Token (JWT) access**](../secrets/id_token_authentication.md#enable-automatic-id-token-authentication)
|
||||
is disabled.
|
||||
|
||||
**Keyword type**: Job keyword. You can use it only as part of a job.
|
||||
|
||||
**Possible inputs**:
|
||||
|
||||
- The name of an ID token
|
||||
|
||||
**Example of `secrets:token`**:
|
||||
|
||||
```yaml
|
||||
job:
|
||||
id_tokens:
|
||||
AWS_TOKEN:
|
||||
aud: https://aws.example.com
|
||||
VAULT_TOKEN:
|
||||
aud: https://vault.example.com
|
||||
secrets:
|
||||
DB_PASSWORD:
|
||||
vault: gitlab/production/db
|
||||
token: $VAULT_TOKEN
|
||||
```
|
||||
|
||||
**Additional details**:
|
||||
|
||||
- When the `token` keyword is not set and **Limit JSON Web Token (JWT) access** enabled, the first ID token
|
||||
is used to authenticate.
|
||||
- When **Limit JSON Web Token (JWT) access** is disabled, the `token` keyword is ignored and the `CI_JOB_JWT`
|
||||
CI/CD variable is used to authenticate.
|
||||
|
||||
### `services`
|
||||
|
||||
Use `services` to specify any additional Docker images that your scripts require to run successfully. The [`services` image](../services/index.md) is linked
|
||||
|
|
|
|||
|
|
@ -231,15 +231,7 @@ end
|
|||
### Error budget attribution and ownership
|
||||
|
||||
This SLI is used for service level monitoring. It feeds into the
|
||||
[error budget for stage groups](../stage_group_observability/index.md#error-budget). For this
|
||||
particular SLI, we have opted everyone out by default to give time to
|
||||
set the correct urgencies on endpoints before it affects a group's
|
||||
error budget.
|
||||
|
||||
To include this SLI in the error budget, remove the `rails_requests`
|
||||
from the `ignored_components` array in the entry for your group. Read
|
||||
more about what is configurable in the
|
||||
[runbooks documentation](https://gitlab.com/gitlab-com/runbooks/-/tree/master/services#teamsyml).
|
||||
[error budget for stage groups](../stage_group_observability/index.md#error-budget).
|
||||
|
||||
For more information, read the epic for
|
||||
[defining custom SLIs and incorporating them into error budgets](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/525)).
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ looks for the next jobs to be transitioned towards completion. While doing that,
|
|||
updates the status of jobs, stages and the overall pipeline.
|
||||
|
||||
On the right side of the diagram we have a list of [runners](../../ci/runners/index.md)
|
||||
connected to the GitLab instance. These can be shared runners, group runners, or project-specific runners.
|
||||
connected to the GitLab instance. These can be shared runners, group runners, or project runners.
|
||||
The communication between runners and the Rails server occurs through a set of API endpoints, grouped as
|
||||
the `Runner API Gateway`.
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ After the runner is [registered](https://docs.gitlab.com/runner/register/) using
|
|||
- The type of runner it is registered as:
|
||||
- a shared runner
|
||||
- a group runner
|
||||
- a project specific runner
|
||||
- a project runner
|
||||
- Any associated tags.
|
||||
|
||||
The runner initiates the communication by requesting jobs to execute with `POST /api/v4/jobs/request`. Although polling happens every few seconds, we leverage caching through HTTP headers to reduce the server-side work load if the job queue doesn't change.
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ You can use these fake tokens as examples:
|
|||
| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
|
||||
| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
|
||||
| CI/CD variable | `Li8j-mLUVA3eZYjPfd_H` |
|
||||
| Specific runner token | `yrnZW46BrtBFqM7xDzE7dddd` |
|
||||
| Project runner token | `yrnZW46BrtBFqM7xDzE7dddd` |
|
||||
| Shared runner token | `6Vk7ZsosqQyfreAxXTZr` |
|
||||
| Trigger token | `be20d8dcc028677c931e04f3871a9b` |
|
||||
| Webhook secret token | `6XhDroRcYPM5by_h-HLY` |
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ Or the feature category can be specified in the action itself:
|
|||
```ruby
|
||||
module API
|
||||
class Users < ::API::Base
|
||||
get ':id', feature_category: :users do
|
||||
get ':id', feature_category: :user_profile do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ memory than it costs to have Workhorse look after it.
|
|||
- Workhorse does not connect to PostgreSQL, only to Rails and (optionally) Redis.
|
||||
- We assume that all requests that reach Workhorse pass through an
|
||||
upstream proxy such as NGINX or Apache first.
|
||||
- Workhorse does not accept HTTPS connections.
|
||||
- Workhorse does not clean up idle client connections.
|
||||
- We assume that all requests to Rails pass through Workhorse.
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ To make full use of Auto DevOps with Kubernetes, you need:
|
|||
[Docker Machine](https://docs.gitlab.com/runner/executors/docker_machine.html).
|
||||
|
||||
Runners should be registered as [shared runners](../../ci/runners/runners_scope.md#shared-runners)
|
||||
for the entire GitLab instance, or [specific runners](../../ci/runners/runners_scope.md#specific-runners)
|
||||
for the entire GitLab instance, or [project runners](../../ci/runners/runners_scope.md#project-runners)
|
||||
that are assigned to specific projects.
|
||||
|
||||
- **Prometheus** (for [Auto Monitoring](stages.md#auto-monitoring))
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ Any time a new project is created, the shared runners are available.
|
|||
As an administrator you can set either a global or namespace-specific
|
||||
limit on the number of [CI/CD minutes](../../../ci/pipelines/cicd_minutes.md) you can use.
|
||||
|
||||
## Enable a specific runner for multiple projects
|
||||
## Enable a project runner for multiple projects
|
||||
|
||||
If you have already registered a [specific runner](../../../ci/runners/runners_scope.md#specific-runners)
|
||||
If you have already registered a [project runner](../../../ci/runners/runners_scope.md#project-runners)
|
||||
you can assign that runner to other projects.
|
||||
|
||||
To enable a specific runner for more than one project:
|
||||
To enable a project runner for more than one project:
|
||||
|
||||
1. On the top bar, select **Main menu > Admin**.
|
||||
1. From the left sidebar, select **CI/CD > Runners**.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
> Introduced in GitLab 11.0.
|
||||
|
||||
This page describes SAML for groups. For instance-wide SAML on self-managed GitLab instances, see [SAML OmniAuth Provider](../../../integration/saml.md).
|
||||
This page describes SAML for groups. For instance-wide SAML on self-managed GitLab instances, see [SAML SSO for self-managed GitLab instances](../../../integration/saml.md).
|
||||
[View the differences between SaaS and Self-Managed Authentication and Authorization Options](../../../administration/auth/index.md#saas-vs-self-managed-comparison).
|
||||
|
||||
SAML on GitLab.com allows users to sign in through their SAML identity provider. If the user is not already a member, the sign-in process automatically adds the user to the appropriate group.
|
||||
|
|
|
|||
|
|
@ -222,8 +222,8 @@ The following table lists project permissions available for each role:
|
|||
|
||||
1. On self-managed GitLab instances, guest users are able to perform this action only on
|
||||
public and internal projects (not on private projects). [External users](admin_area/external_users.md)
|
||||
must be given explicit access even if the project is internal. Users with the Guest role on GitLab.com are
|
||||
only able to perform this action on public projects because internal visibility is not available.
|
||||
must be given explicit access even if the project is internal. Users with the Guest role on GitLab.com are
|
||||
only able to perform this action on public projects because internal visibility is not available.
|
||||
2. Guest users can only view the [confidential issues](project/issues/confidential_issues.md) they created themselves or are assigned to.
|
||||
3. Not allowed for Guest, Reporter, Developer, Maintainer, or Owner. See [protected branches](project/protected_branches.md).
|
||||
4. If the [branch is protected](project/protected_branches.md), this depends on the access given to Developers and Maintainers.
|
||||
|
|
@ -287,7 +287,7 @@ More details about the permissions for some project-level features follow.
|
|||
| View a job with [debug logging](../ci/variables/index.md#enable-debug-logging) | | | | ✓ | ✓ | ✓ |
|
||||
| Use pipeline editor | | | | ✓ | ✓ | ✓ |
|
||||
| Run [interactive web terminals](../ci/interactive_web_terminal/index.md) | | | | ✓ | ✓ | ✓ |
|
||||
| Add specific runners to project | | | | | ✓ | ✓ |
|
||||
| Add project runners to project | | | | | ✓ | ✓ |
|
||||
| Clear runner caches manually | | | | | ✓ | ✓ |
|
||||
| Enable shared runners in project | | | | | ✓ | ✓ |
|
||||
| Manage CI/CD settings | | | | | ✓ | ✓ |
|
||||
|
|
|
|||
|
|
@ -117,17 +117,27 @@ Hi, please message @frank :incoming_envelope:
|
|||
|
||||
## Actions that mark a to-do item as done
|
||||
|
||||
Any action to an issue, merge request, or epic marks its
|
||||
Various actions on the to-do item object (like issue, merge request, or epic) mark its
|
||||
corresponding to-do item as done.
|
||||
|
||||
Actions that dismiss to-do items include:
|
||||
To-do items are marked as done if you:
|
||||
|
||||
- Changing the assignee
|
||||
- Changing the milestone
|
||||
- Closing the issue or merge request
|
||||
- Adding or removing a label
|
||||
- Commenting on the issue
|
||||
- Resolving a [design discussion thread](project/issues/design_management.md#resolve-a-discussion-thread-on-a-design)
|
||||
- Add an award emoji to the description or comment.
|
||||
- Add or remove a label.
|
||||
- Change the assignee.
|
||||
- Change the milestone.
|
||||
- Close the to-do item's object.
|
||||
- Create a comment.
|
||||
- Edit the description.
|
||||
- Resolve a [design discussion thread](project/issues/design_management.md#resolve-a-discussion-thread-on-a-design).
|
||||
|
||||
To-do items are **not** marked as done if you:
|
||||
|
||||
- Add a linked item (like a [linked issue](project/issues/related_issues.md)).
|
||||
- Add a child item (like [child epic](group/epics/manage_epics.md#multi-level-child-epics) or [task](tasks.md)).
|
||||
- Add a [time entry](project/time_tracking.md).
|
||||
- Assign yourself.
|
||||
- Change the [health status](project/issues/managing_issues.md#health-status).
|
||||
|
||||
If someone else closes, merges, or takes action on an issue, merge request, or
|
||||
epic, your to-do item remains pending.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module API
|
|||
helpers do
|
||||
params :deprecated_filter_params do
|
||||
optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
|
||||
desc: 'Deprecated: Use `type` or `status` instead. The scope of specific runners to return'
|
||||
desc: 'Deprecated: Use `type` or `status` instead. The scope of runners to return'
|
||||
end
|
||||
|
||||
params :filter_params do
|
||||
|
|
@ -111,9 +111,9 @@ module API
|
|||
present paginate(runners), with: Entities::Ci::Runner
|
||||
end
|
||||
|
||||
desc 'Get all runners - shared and specific' do
|
||||
desc 'Get all runners - shared and project' do
|
||||
summary 'List all runners'
|
||||
detail 'Get a list of all runners in the GitLab instance (specific and shared). ' \
|
||||
detail 'Get a list of all runners in the GitLab instance (shared and project). ' \
|
||||
'Access is restricted to users with administrator access.'
|
||||
success Entities::Ci::Runner
|
||||
failure [[400, 'Scope contains invalid value'], [401, 'Unauthorized']]
|
||||
|
|
@ -286,7 +286,7 @@ module API
|
|||
end
|
||||
|
||||
desc 'Enable a runner in project' do
|
||||
detail "Enable an available specific runner in the project."
|
||||
detail "Enable an available project runner in the project."
|
||||
success Entities::Ci::Runner
|
||||
failure [[400, 'Bad Request'],
|
||||
[403, 'No access granted'], [403, 'Runner is a group runner'], [403, 'Runner is locked'],
|
||||
|
|
@ -308,7 +308,7 @@ module API
|
|||
end
|
||||
|
||||
desc "Disable project's runner" do
|
||||
summary "Disable a specific runner from the project"
|
||||
summary "Disable a project runner from the project"
|
||||
detail "It works only if the project isn't the only project associated with the specified runner. " \
|
||||
"If so, an error is returned. Use the call to delete a runner instead."
|
||||
success Entities::Ci::Runner
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ module API
|
|||
|
||||
before { authenticate_non_get! }
|
||||
|
||||
feature_category :projects, ['/projects/:id/custom_attributes', '/projects/:id/custom_attributes/:key']
|
||||
feature_category :projects, %w[
|
||||
/projects/:id/custom_attributes
|
||||
/projects/:id/custom_attributes/:key
|
||||
/projects/:id/share_locations
|
||||
]
|
||||
|
||||
PROJECT_ATTACHMENT_SIZE_EXEMPT = 1.gigabyte
|
||||
|
||||
|
|
@ -351,6 +355,20 @@ module API
|
|||
render_validation_error!(project)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Returns group that can be shared with the given project' do
|
||||
success Entities::Group
|
||||
end
|
||||
params do
|
||||
requires :id, type: Integer, desc: 'The id of the project'
|
||||
optional :search, type: String, desc: 'Return list of groups matching the search criteria'
|
||||
end
|
||||
get ':id/share_locations' do
|
||||
groups = ::Groups::AcceptingProjectSharesFinder.new(current_user, user_project, declared_params(include_missing: false)).execute
|
||||
|
||||
present_groups groups
|
||||
end
|
||||
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ module Gitlab
|
|||
def valid_json?(metadata)
|
||||
Oj.load(metadata)
|
||||
true
|
||||
rescue Oj::ParseError, EncodingError, JSON::ParserError, Encoding::UndefinedConversionError
|
||||
rescue Oj::ParseError, EncodingError, JSON::ParserError, JSON::GeneratorError, Encoding::UndefinedConversionError
|
||||
false
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ module Gitlab
|
|||
# Without forcing the encoding to UTF-8 and then replacing
|
||||
# invalid UTF-8 sequences we can get an error when serializing
|
||||
# the Hash to JSON.
|
||||
# Encoding::UndefinedConversionError:
|
||||
# Encoding::UndefinedConversionError (or possibly JSON::GeneratorError in json 2.6.1+):
|
||||
# "\xE2" from ASCII-8BIT to UTF-8
|
||||
{ text: encode_utf8_no_detect(text) }.tap do |result|
|
||||
result[:style] = style.to_s if style.set?
|
||||
|
|
|
|||
|
|
@ -65,13 +65,15 @@ module Gitlab
|
|||
|
||||
status_code = Gitlab::PollingInterval.polling_enabled? ? 304 : 429
|
||||
|
||||
add_instrument_for_cache_hit(status_code, route, request)
|
||||
|
||||
Gitlab::ApplicationContext.push(
|
||||
feature_category: route.feature_category,
|
||||
caller_id: route.caller_id
|
||||
caller_id: route.caller_id,
|
||||
remote_ip: request.remote_ip
|
||||
)
|
||||
|
||||
request.env[Gitlab::Metrics::RequestsRackMiddleware::REQUEST_URGENCY_KEY] = route.urgency
|
||||
add_instrument_for_cache_hit(status_code, route, request)
|
||||
|
||||
new_headers = {
|
||||
'ETag' => etag,
|
||||
'X-Gitlab-From-Cache' => 'true'
|
||||
|
|
@ -102,7 +104,10 @@ module Gitlab
|
|||
format: request.format.ref,
|
||||
method: request.request_method,
|
||||
path: request.filtered_path,
|
||||
status: status
|
||||
status: status,
|
||||
metadata: Gitlab::ApplicationContext.current,
|
||||
request_urgency: route.urgency.name,
|
||||
target_duration_s: route.urgency.duration
|
||||
}
|
||||
|
||||
ActiveSupport::Notifications.instrument(
|
||||
|
|
|
|||
|
|
@ -3,24 +3,34 @@
|
|||
module Gitlab
|
||||
module EtagCaching
|
||||
module Router
|
||||
Route = Struct.new(:router, :regexp, :name, :feature_category, :caller_id) do
|
||||
Route = Struct.new(:router, :regexp, :name, :feature_category, :caller_id, :urgency, keyword_init: true) do
|
||||
delegate :match, to: :regexp
|
||||
delegate :cache_key, to: :router
|
||||
end
|
||||
|
||||
module Helpers
|
||||
def build_route(attrs)
|
||||
EtagCaching::Router::Route.new(self, *attrs)
|
||||
def build_graphql_route(regexp, name, feature_category)
|
||||
EtagCaching::Router::Route.new(
|
||||
router: self,
|
||||
regexp: regexp,
|
||||
name: name,
|
||||
feature_category: feature_category,
|
||||
# This information can be loaded from the graphql query, but is not
|
||||
# included yet
|
||||
# https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/665
|
||||
caller_id: nil,
|
||||
urgency: Gitlab::EndpointAttributes::DEFAULT_URGENCY
|
||||
)
|
||||
end
|
||||
|
||||
def build_rails_route(attrs)
|
||||
regexp, name, controller, action_name = *attrs
|
||||
def build_rails_route(regexp, name, controller, action_name)
|
||||
EtagCaching::Router::Route.new(
|
||||
self,
|
||||
regexp,
|
||||
name,
|
||||
controller.feature_category_for_action(action_name).to_s,
|
||||
controller.endpoint_id_for_action(action_name).to_s
|
||||
router: self,
|
||||
regexp: regexp,
|
||||
name: name,
|
||||
feature_category: controller.feature_category_for_action(action_name).to_s,
|
||||
caller_id: controller.endpoint_id_for_action(action_name).to_s,
|
||||
urgency: controller.urgency_for_action(action_name)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Gitlab
|
|||
'on_demand_scans',
|
||||
'dynamic_application_security_testing'
|
||||
]
|
||||
].map(&method(:build_route)).freeze
|
||||
].map { |attrs| build_graphql_route(*attrs) }.freeze
|
||||
|
||||
def self.match(request)
|
||||
return unless request.path_info == graphql_api_path
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ module Gitlab
|
|||
::Projects::MergeRequests::ContentController,
|
||||
:cached_widget
|
||||
]
|
||||
].map(&method(:build_rails_route)).freeze
|
||||
].map { |attrs| build_rails_route(*attrs) }.freeze
|
||||
|
||||
# Overridden in EE to add more routes
|
||||
def self.all_routes
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ module Gitlab
|
|||
opts = standardize_opts(opts)
|
||||
|
||||
Oj.load(string, opts)
|
||||
rescue Oj::ParseError, EncodingError, Encoding::UndefinedConversionError => ex
|
||||
rescue Oj::ParseError, EncodingError, Encoding::UndefinedConversionError, JSON::GeneratorError => ex
|
||||
raise parser_error, ex
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ module Gitlab
|
|||
'not_owned', 'source_code_management',
|
||||
FEATURE_CATEGORY_DEFAULT].freeze
|
||||
|
||||
REQUEST_URGENCY_KEY = 'gitlab.request_urgency'
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
|
@ -142,7 +144,9 @@ module Gitlab
|
|||
|
||||
def urgency_for_env(env)
|
||||
endpoint_urgency =
|
||||
if env['api.endpoint'].present?
|
||||
if env[REQUEST_URGENCY_KEY].present?
|
||||
env[REQUEST_URGENCY_KEY]
|
||||
elsif env['api.endpoint'].present?
|
||||
env['api.endpoint'].options[:for].try(:urgency_for_app, env['api.endpoint'])
|
||||
elsif env['action_controller.instance'].present? && env['action_controller.instance'].respond_to?(:urgency)
|
||||
env['action_controller.instance'].urgency
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Redis
|
||||
# Pseudo-store to transition `Gitlab::SidekiqMiddleware::DuplicateJobs` from
|
||||
# using `Sidekiq.redis` to using the `SharedState` redis store.
|
||||
class DuplicateJobs < ::Gitlab::Redis::Wrapper
|
||||
class << self
|
||||
def store_name
|
||||
'SharedState'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redis
|
||||
primary_store = ::Redis.new(Gitlab::Redis::SharedState.params)
|
||||
|
||||
# `Sidekiq.redis` is a namespaced redis connection. This means keys are actually being stored under
|
||||
# "resque:gitlab:resque:gitlab:duplicate:". For backwards compatibility, we make the secondary store
|
||||
# namespaced in the same way, but omit it from the primary so keys have proper format there.
|
||||
# rubocop:disable Cop/RedisQueueUsage
|
||||
secondary_store = ::Redis::Namespace.new(
|
||||
Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE, redis: ::Redis.new(Gitlab::Redis::Queues.params)
|
||||
)
|
||||
# rubocop:enable Cop/RedisQueueUsage
|
||||
|
||||
MultiStore.new(primary_store, secondary_store, name.demodulize)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -120,7 +120,8 @@ module Gitlab
|
|||
@debian_version_regex ||= %r{
|
||||
\A(?:
|
||||
(?:([0-9]{1,9}):)? (?# epoch)
|
||||
([0-9][0-9a-z\.+~]*-?){1,15} (?# version-revision)
|
||||
([0-9][0-9a-z\.+~]*) (?# version)
|
||||
(-[0-9a-z\.+~]+){0,14} (?# -revision)
|
||||
(?<!-)
|
||||
)\z}xi.freeze
|
||||
end
|
||||
|
|
|
|||
|
|
@ -251,16 +251,8 @@ module Gitlab
|
|||
!scheduled? && options[:if_deduplicated] == :reschedule_once
|
||||
end
|
||||
|
||||
def with_redis
|
||||
if Feature.enabled?(:use_primary_and_secondary_stores_for_duplicate_jobs) ||
|
||||
Feature.enabled?(:use_primary_store_as_default_for_duplicate_jobs)
|
||||
# TODO: Swap for Gitlab::Redis::SharedState after store transition
|
||||
# https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/923
|
||||
Gitlab::Redis::DuplicateJobs.with { |redis| yield redis }
|
||||
else
|
||||
# Keep the old behavior intact if neither feature flag is turned on
|
||||
Sidekiq.redis { |redis| yield redis } # rubocop:disable Cop/SidekiqRedisCall
|
||||
end
|
||||
def with_redis(&block)
|
||||
Sidekiq.redis(&block) # rubocop:disable Cop/SidekiqRedisCall
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4713,9 +4713,6 @@ msgstr ""
|
|||
msgid "Any milestone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Any namespace"
|
||||
msgstr ""
|
||||
|
||||
msgid "App ID"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -5980,9 +5977,6 @@ msgstr ""
|
|||
msgid "Available on-demand"
|
||||
msgstr ""
|
||||
|
||||
msgid "Available specific runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "Avatar for %{assigneeName}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19867,6 +19861,9 @@ msgstr ""
|
|||
msgid "GroupSelect|Select a group"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Analytics Dashboards"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Applied to all subgroups unless overridden by a group owner. Groups already added to the project lose access."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19969,6 +19966,12 @@ msgstr ""
|
|||
msgid "GroupSettings|Select parent group"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Select the project containing Analytics Dashboards configuration files"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Select the project containing Analytics Dashboards configuration files."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Select the project containing the %{code_start}.gitlab/insights.yml%{code_end} file"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -20008,6 +20011,9 @@ msgstr ""
|
|||
msgid "GroupSettings|What are badges?"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|What is Analytics Dashboards?"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|What is Insights?"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -22847,6 +22853,9 @@ msgstr ""
|
|||
msgid "Invalid status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid two-factor code."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -27142,6 +27151,9 @@ msgstr ""
|
|||
msgid "MlExperimentsEmptyState|No Experiments to Show"
|
||||
msgstr ""
|
||||
|
||||
msgid "Modal updated"
|
||||
msgstr ""
|
||||
|
||||
msgid "ModalButton|Add projects"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36272,6 +36284,9 @@ msgstr ""
|
|||
msgid "Runners|Assigned Projects (%{projectCount})"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Assigned project runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Associated with one or more projects"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36486,6 +36501,9 @@ msgstr ""
|
|||
msgid "Runners|Project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Project runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Property Name"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36666,6 +36684,9 @@ msgstr ""
|
|||
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|These runners are assigned to this project."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|This group currently has 1 stale runner."
|
||||
msgid_plural "Runners|This group currently has %d stale runners."
|
||||
msgstr[0] ""
|
||||
|
|
@ -36755,7 +36776,7 @@ msgstr ""
|
|||
msgid "Runners|Yes, start deleting stale runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|You can set up a specific runner to be used by multiple projects but you cannot make this a shared or group runner."
|
||||
msgid "Runners|You can set up a project runner to be used by multiple projects but you cannot make this a shared or group runner."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
|
||||
|
|
@ -36770,10 +36791,10 @@ msgstr ""
|
|||
msgid "Runners|paused"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|shared"
|
||||
msgid "Runners|project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|specific"
|
||||
msgid "Runners|shared"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runner|Owner"
|
||||
|
|
@ -39544,6 +39565,15 @@ msgstr ""
|
|||
msgid "SlackIntegration|You may need to reinstall the GitLab for Slack app when we %{linkStart}make updates or change permissions%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "SlackModal|Are you sure you want to change the project?"
|
||||
msgstr ""
|
||||
|
||||
msgid "SlackModal|If you change the project, you'll lose any text entered in the form."
|
||||
msgstr ""
|
||||
|
||||
msgid "SlackModal|If you've entered some text, consider saving it somewhere to avoid losing any content."
|
||||
msgstr ""
|
||||
|
||||
msgid "SlackService|1. %{slash_command_link_start}Add a slash command%{slash_command_link_end} in your Slack team using this information:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -39859,6 +39889,9 @@ msgstr ""
|
|||
msgid "Something went wrong while updating assignees"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong while updating the modal."
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong while updating your list settings"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40195,9 +40228,6 @@ msgstr ""
|
|||
msgid "Spam log successfully submitted as ham."
|
||||
msgstr ""
|
||||
|
||||
msgid "Specific runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "Specified URL cannot be used: \"%{reason}\""
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -42815,9 +42845,6 @@ msgstr ""
|
|||
msgid "These runners are shared across projects in this group."
|
||||
msgstr ""
|
||||
|
||||
msgid "These runners are specific to this project."
|
||||
msgstr ""
|
||||
|
||||
msgid "These variables are inherited from the parent group."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe RegistrationsController do
|
||||
RSpec.describe RegistrationsController, feature_category: :users do
|
||||
include TermsHelper
|
||||
include FullNameHelper
|
||||
|
||||
|
|
@ -215,11 +215,18 @@ RSpec.describe RegistrationsController do
|
|||
property: member.id.to_s,
|
||||
user: member.reload.user
|
||||
)
|
||||
|
||||
expect_snowplow_event(
|
||||
category: 'RegistrationsController',
|
||||
action: 'create_user',
|
||||
label: 'invited',
|
||||
user: member.reload.user
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when member does not exist from the session key value' do
|
||||
let(:originating_member_id) { -1 }
|
||||
let(:originating_member_id) { nil }
|
||||
|
||||
it 'does not track invite acceptance' do
|
||||
subject
|
||||
|
|
@ -229,6 +236,13 @@ RSpec.describe RegistrationsController do
|
|||
action: 'accepted',
|
||||
label: 'invite_email'
|
||||
)
|
||||
|
||||
expect_snowplow_event(
|
||||
category: 'RegistrationsController',
|
||||
action: 'create_user',
|
||||
label: 'signup',
|
||||
user: member.reload.user
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ FactoryBot.define do
|
|||
|
||||
transient do
|
||||
without_package_files { false }
|
||||
file_metadatum_trait { :keep }
|
||||
file_metadatum_trait { processing? ? :unknown : :keep }
|
||||
published_in { :create }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
|
|||
visit edit_admin_runner_path(runner)
|
||||
end
|
||||
|
||||
it 'removed specific runner from project' do
|
||||
it 'removed project runner from project' do
|
||||
within '[data-testid="assigned-projects"]' do
|
||||
click_on 'Disable'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Contributions Calendar', :js, feature_category: :users do
|
||||
RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
|
||||
include MobileHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Dashboard > Activity', feature_category: :users do
|
||||
RSpec.describe 'Dashboard > Activity', feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Tooltips on .timeago dates', :js, feature_category: :users do
|
||||
RSpec.describe 'Tooltips on .timeago dates', :js, feature_category: :user_profile do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, name: 'test', namespace: user.namespace) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Project member activity', :js, feature_category: :users do
|
||||
RSpec.describe 'Project member activity', :js, feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public, name: 'x', namespace: user.namespace) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Explore Topics', feature_category: :users do
|
||||
RSpec.describe 'Explore Topics', feature_category: :user_profile do
|
||||
context 'when no topics exist' do
|
||||
it 'renders empty message', :aggregate_failures do
|
||||
visit topics_explore_projects_path
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User explores projects', feature_category: :users do
|
||||
RSpec.describe 'User explores projects', feature_category: :user_profile do
|
||||
context 'when some projects exist' do
|
||||
let_it_be(:archived_project) { create(:project, :archived) }
|
||||
let_it_be(:internal_project) { create(:project, :internal) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Upload a user avatar', :js, feature_category: :users do
|
||||
RSpec.describe 'Upload a user avatar', :js, feature_category: :user_profile do
|
||||
let_it_be(:user, reload: true) { create(:user) }
|
||||
|
||||
let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User Cluster', :js, feature_category: :users do
|
||||
RSpec.describe 'User Cluster', :js, feature_category: :user_profile do
|
||||
include GoogleApi::CloudPlatformHelpers
|
||||
|
||||
let(:group) { create(:group) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile account page', :js, feature_category: :users do
|
||||
RSpec.describe 'Profile account page', :js, feature_category: :user_profile do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Account', :js, feature_category: :users do
|
||||
RSpec.describe 'Profile > Account', :js, feature_category: :user_profile do
|
||||
let(:user) { create(:user, username: 'foo') }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state, feature_category: :users do
|
||||
RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state, feature_category: :user_profile do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
|
||||
let(:user) do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Chat', feature_category: :users do
|
||||
RSpec.describe 'Profile > Chat', feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
let(:integration) { create(:integration) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Emails', feature_category: :users do
|
||||
RSpec.describe 'Profile > Emails', feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
let(:other_user) { create(:user) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > GPG Keys', feature_category: :users do
|
||||
RSpec.describe 'Profile > GPG Keys', feature_category: :user_profile do
|
||||
let(:user) { create(:user, email: GpgHelpers::User2.emails.first) }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > SSH Keys', feature_category: :users do
|
||||
RSpec.describe 'Profile > SSH Keys', feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Applications', feature_category: :users do
|
||||
RSpec.describe 'Profile > Applications', feature_category: :user_profile do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Password', feature_category: :users do
|
||||
RSpec.describe 'Profile > Password', feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
def fill_passwords(password, confirmation)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Personal Access Tokens', :js, feature_category: :users do
|
||||
RSpec.describe 'Profile > Personal Access Tokens', :js, feature_category: :user_profile do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
include Spec::Support::Helpers::AccessTokenHelpers
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Two factor auths', feature_category: :users do
|
||||
RSpec.describe 'Two factor auths', feature_category: :user_profile do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
|
||||
context 'when signed in' do
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Profile > Notifications > User changes notified_of_own_activity setting', :js,
|
||||
feature_category: :users do
|
||||
feature_category: :user_profile do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User edit preferences profile', :js, feature_category: :users do
|
||||
RSpec.describe 'User edit preferences profile', :js, feature_category: :user_profile do
|
||||
include StubLanguagesTranslationPercentage
|
||||
|
||||
# Empty value doesn't change the levels
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User edit profile', feature_category: :users do
|
||||
RSpec.describe 'User edit profile', feature_category: :user_profile do
|
||||
include Spec::Support::Helpers::Features::NotesHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User manages applications', feature_category: :users do
|
||||
RSpec.describe 'User manages applications', feature_category: :user_profile do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:new_application_path) { applications_profile_path }
|
||||
let_it_be(:index_path) { oauth_applications_path }
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue