Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
42be04412b
commit
d7f87de3d4
|
|
@ -1,22 +0,0 @@
|
|||
---
|
||||
# Cop supports --autocorrect.
|
||||
Style/KeywordParametersOrder:
|
||||
Exclude:
|
||||
- 'ee/app/services/analytics/devops_adoption/enabled_namespaces/create_service.rb'
|
||||
- 'ee/app/services/analytics/devops_adoption/enabled_namespaces/find_or_create_service.rb'
|
||||
- 'ee/app/services/audit_events/user_impersonation_group_audit_event_service.rb'
|
||||
- 'ee/lib/gitlab/elastic/helper.rb'
|
||||
- 'ee/lib/gitlab/insights/executors/dora_executor.rb'
|
||||
- 'ee/lib/gitlab/insights/executors/issuable_executor.rb'
|
||||
- 'ee/spec/requests/api/deployments_spec.rb'
|
||||
- 'lib/gitlab/background_migration/batched_migration_job.rb'
|
||||
- 'lib/gitlab/checks/timed_logger.rb'
|
||||
- 'lib/gitlab/ci/reports/security/finding.rb'
|
||||
- 'lib/gitlab/cleanup/personal_access_tokens.rb'
|
||||
- 'lib/gitlab/database/partitioning/monthly_strategy.rb'
|
||||
- 'lib/gitlab/database/with_lock_retries.rb'
|
||||
- 'lib/gitlab/diff/diff_refs.rb'
|
||||
- 'lib/gitlab/email/smime/signer.rb'
|
||||
- 'lib/gitlab/exclusive_lease.rb'
|
||||
- 'lib/gitlab/merge_requests/mergeability/results_store.rb'
|
||||
- 'lib/microsoft_teams/notifier.rb'
|
||||
|
|
@ -42,6 +42,11 @@ export default {
|
|||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
trackImportClick: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -82,12 +87,18 @@ export default {
|
|||
v-if="showImportButton"
|
||||
v-gl-modal="importModalId"
|
||||
data-testid="import-from-csv-button"
|
||||
:data-track-action="trackImportClick && 'click_import_csv_project_issues_empty_list_page'"
|
||||
:data-track-label="trackImportClick && 'import_csv_project_issues_empty_list'"
|
||||
:data-track-experiment="trackImportClick && 'issues_mrs_empty_state'"
|
||||
:item="dropdownItems.importCSV"
|
||||
/>
|
||||
<gl-disclosure-dropdown-item
|
||||
v-if="showImportButton && canEdit"
|
||||
data-testid="import-from-jira-link"
|
||||
:item="dropdownItems.importFromJIRA"
|
||||
:data-track-action="trackImportClick && 'click_import_jira_project_issues_empty_list_page'"
|
||||
:data-track-label="trackImportClick && 'import_jira_project_issues_empty_list'"
|
||||
:data-track-experiment="trackImportClick && 'issues_mrs_empty_state'"
|
||||
/>
|
||||
|
||||
<csv-export-modal
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export default {
|
|||
'showNewIssueLink',
|
||||
'signInPath',
|
||||
'groupId',
|
||||
'isProject',
|
||||
],
|
||||
props: {
|
||||
currentTabCount: {
|
||||
|
|
@ -65,7 +66,13 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="isSignedIn">
|
||||
<div
|
||||
v-if="isSignedIn"
|
||||
data-testid="signed-in-empty-state-block"
|
||||
:data-track-action="isProject && 'render_project_issues_empty_list_page'"
|
||||
:data-track-label="isProject && 'project_issues_empty_list'"
|
||||
:data-track-experiment="isProject && 'issues_mrs_empty_state'"
|
||||
>
|
||||
<gitlab-experiment name="issues_mrs_empty_state">
|
||||
<template #candidate>
|
||||
<empty-state-without-any-issues-experiment
|
||||
|
|
@ -83,7 +90,12 @@ export default {
|
|||
data-testid="issuable-empty-state"
|
||||
>
|
||||
<template #description>
|
||||
<gl-link :href="$options.issuesHelpPagePath">
|
||||
<gl-link
|
||||
:href="$options.issuesHelpPagePath"
|
||||
:data-track-action="isProject && 'click_learn_more_project_issues_empty_list_page'"
|
||||
:data-track-label="isProject && 'learn_more_project_issues_empty_list'"
|
||||
:data-track-experiment="isProject && 'issues_mrs_empty_state'"
|
||||
>
|
||||
{{ $options.i18n.noIssuesDescription }}
|
||||
</gl-link>
|
||||
<p v-if="canCreateProjects">
|
||||
|
|
@ -108,6 +120,9 @@ export default {
|
|||
:href="newIssuePath"
|
||||
variant="confirm"
|
||||
class="gl-mx-2 gl-mb-3"
|
||||
data-track-action="click_new_issue_project_issues_empty_list_page"
|
||||
data-track-label="new_issue_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
>
|
||||
{{ $options.i18n.newIssueLabel }}
|
||||
</gl-button>
|
||||
|
|
@ -121,6 +136,7 @@ export default {
|
|||
<csv-import-export-buttons
|
||||
:export-csv-path="exportCsvPathWithQuery"
|
||||
:issuable-count="currentTabCount"
|
||||
track-import-click
|
||||
/>
|
||||
</gl-disclosure-dropdown>
|
||||
|
||||
|
|
@ -141,7 +157,14 @@ export default {
|
|||
<p class="gl-text-center gl-mb-0">
|
||||
<gl-sprintf :message="$options.i18n.jiraIntegrationMessage">
|
||||
<template #jiraDocsLink="{ content }">
|
||||
<gl-link :href="jiraIntegrationPath">{{ content }}</gl-link>
|
||||
<gl-link
|
||||
:href="jiraIntegrationPath"
|
||||
:data-track-action="isProject && 'click_jira_int_project_issues_empty_list_page'"
|
||||
:data-track-label="isProject && 'jira_int_project_issues_empty_list'"
|
||||
:data-track-experiment="isProject && 'issues_mrs_empty_state'"
|
||||
>
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ export default {
|
|||
:href="newIssuePath"
|
||||
variant="confirm"
|
||||
data-testid="empty-state-new-issue-btn"
|
||||
data-track-action="click_new_issue_project_issues_empty_list_page"
|
||||
data-track-label="new_issue_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
>
|
||||
{{ __('Create a new issue') }}
|
||||
</gl-button>
|
||||
|
|
@ -102,6 +105,9 @@ export default {
|
|||
button-class="gl-w-full"
|
||||
variant="default"
|
||||
:text="__('Email a new issue')"
|
||||
data-track-action="click_email_issue_project_issues_empty_list_page"
|
||||
data-track-label="email_issue_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -121,6 +127,9 @@ export default {
|
|||
v-gl-modal="importModalId"
|
||||
class="gl-mt-3 gl-ml-0! gl-mb-0!"
|
||||
data-testid="empty-state-import-csv-btn"
|
||||
data-track-action="click_import_csv_project_issues_empty_list_page"
|
||||
data-track-label="import_csv_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
>
|
||||
{{ __('Import CSV') }}
|
||||
</gl-button>
|
||||
|
|
@ -130,6 +139,9 @@ export default {
|
|||
class="gl-mt-3 gl-mb-0!"
|
||||
:href="projectImportJiraPath"
|
||||
data-testid="empty-state-import-jira-btn"
|
||||
data-track-action="click_import_jira_project_issues_empty_list_page"
|
||||
data-track-label="import_jira_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
>
|
||||
{{ __('Import from Jira') }}
|
||||
</gl-button>
|
||||
|
|
@ -137,7 +149,14 @@ export default {
|
|||
</template>
|
||||
</gl-card-empty-state-experiment>
|
||||
|
||||
<a class="gl-text-decoration-none!" :href="$options.issuesHelpPagePath">
|
||||
<a
|
||||
class="gl-text-decoration-none!"
|
||||
:href="$options.issuesHelpPagePath"
|
||||
data-testid="empty-state-learn-more-link"
|
||||
data-track-action="click_learn_more_project_issues_empty_list_page"
|
||||
data-track-label="learn_more_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
>
|
||||
<gl-card-empty-state-experiment
|
||||
class="gl-h-13 gl-justify-content-center gl-hover-text-blue-600 gl-text-gray-900"
|
||||
icon="issue-type-issue"
|
||||
|
|
@ -157,7 +176,14 @@ export default {
|
|||
<div
|
||||
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-justify-content-center"
|
||||
>
|
||||
<a class="gl-text-decoration-none!" :href="jiraIntegrationPath">
|
||||
<a
|
||||
class="gl-text-decoration-none!"
|
||||
:href="jiraIntegrationPath"
|
||||
data-testid="empty-state-jira-int-link"
|
||||
data-track-action="click_jira_int_project_issues_empty_list_page"
|
||||
data-track-label="jira_int_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
>
|
||||
<gl-card-empty-state-experiment
|
||||
class="gl-h-13 gl-hover-text-blue-600 gl-text-gray-900"
|
||||
icon="api"
|
||||
|
|
|
|||
|
|
@ -1080,7 +1080,12 @@ export default {
|
|||
|
||||
<gitlab-experiment v-if="showIssuableByEmail" name="issues_mrs_empty_state">
|
||||
<template #control>
|
||||
<issuable-by-email class="gl-text-center gl-pt-5 gl-pb-7" />
|
||||
<issuable-by-email
|
||||
class="gl-text-center gl-pt-5 gl-pb-7"
|
||||
data-track-action="click_email_issue_project_issues_empty_list_page"
|
||||
data-track-label="email_issue_project_issues_empty_list"
|
||||
data-track-experiment="issues_mrs_empty_state"
|
||||
/>
|
||||
</template>
|
||||
</gitlab-experiment>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,3 +11,25 @@
|
|||
vertical-align: sub;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This temporarily restores the legacy breadcrumbs styles on the primary HAML breadcrumbs.
|
||||
* Those styles got changed in https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/3663,
|
||||
* causing a regression in this particular instance which does not use a Vue component and is
|
||||
* therefore unable to collapse overflowing items within a disclosure dropdown.
|
||||
* These temporary overrides will be removed as part of https://gitlab.com/gitlab-org/gitlab/-/issues/358113.
|
||||
*/
|
||||
.tmp-breadcrumbs-fix {
|
||||
.gl-breadcrumb-list {
|
||||
flex-wrap: wrap;
|
||||
max-width: none;
|
||||
|
||||
.gl-breadcrumb-item {
|
||||
> a {
|
||||
@include media-breakpoint-down(xs) {
|
||||
@include str-truncated($breadcrumb-max-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
/* stylelint-disable scss/at-rule-no-unknown */
|
||||
|
||||
@tailwind base;
|
||||
@tailwind utilities;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* stylelint-disable scss/at-rule-no-unknown */
|
||||
|
||||
@tailwind base;
|
||||
|
||||
.gl-border {
|
||||
@apply gl-border-gray-100;
|
||||
@apply gl-border-solid;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ module Resolvers
|
|||
required: false,
|
||||
default_value: nil
|
||||
|
||||
argument :referrer_type, GraphQL::Types::String,
|
||||
description: 'Comma-separated list of artifact types used to filter referrers. Applies only when `referrers` is set to `true`.',
|
||||
required: false,
|
||||
default_value: nil
|
||||
|
||||
alias_method :container_repository, :object
|
||||
|
||||
def resolve(sort:, **filters)
|
||||
|
|
@ -31,7 +36,8 @@ module Resolvers
|
|||
sort: map_sort_field(sort),
|
||||
name: filters[:name],
|
||||
page_size: page_size,
|
||||
referrers: filters[:referrers]
|
||||
referrers: filters[:referrers],
|
||||
referrer_type: filters[:referrer_type]
|
||||
)
|
||||
|
||||
Gitlab::Graphql::ExternallyPaginatedArray.new(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module Resolvers
|
|||
argument :iid, GraphQL::Types::String, required: true, description: 'IID of the work item.'
|
||||
|
||||
def ready?(**args)
|
||||
return false if Feature.disabled?(:namespace_level_work_items, resource_parent)
|
||||
return false if Feature.disabled?(:namespace_level_work_items, resource_parent) && resource_parent.is_a?(Group)
|
||||
|
||||
super
|
||||
end
|
||||
|
|
|
|||
|
|
@ -72,6 +72,13 @@ module Types
|
|||
extras: [:lookahead],
|
||||
resolver: ::Resolvers::Achievements::AchievementsResolver
|
||||
|
||||
field :work_item, Types::WorkItemType,
|
||||
null: true,
|
||||
resolver: Resolvers::Namespaces::WorkItemResolver,
|
||||
alpha: { milestone: '16.10' },
|
||||
description: 'Find a work item by IID directly associated with the namespace(project or group). Returns ' \
|
||||
'`null` for group level work items if the `namespace_level_work_items` feature flag is disabled.'
|
||||
|
||||
markdown_field :description_html, null: true
|
||||
|
||||
def timelog_categories
|
||||
|
|
|
|||
|
|
@ -1162,7 +1162,7 @@ module Ci
|
|||
end
|
||||
|
||||
def job_jwt_variables
|
||||
if id_tokens?
|
||||
if Feature.enabled?(:remove_shared_jwts) || id_tokens?
|
||||
id_tokens_variables
|
||||
else
|
||||
predefined_jwt_variables
|
||||
|
|
@ -1183,6 +1183,8 @@ module Ci
|
|||
|
||||
def id_tokens_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless id_tokens?
|
||||
|
||||
id_tokens.each do |var_name, token_data|
|
||||
token = Gitlab::Ci::JwtV2.for_build(self, aud: expanded_id_token_aud(token_data['aud']))
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ module Routable
|
|||
.where(source_type_condition)
|
||||
.where(path_condition)
|
||||
|
||||
source_ids = routes_matching_condition.pluck(:source_id)
|
||||
source_ids = routes_matching_condition.select(:source_id)
|
||||
result = route_scope.where(id: source_ids)
|
||||
|
||||
if preload_routes
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ class ContainerRepository < ApplicationRecord
|
|||
raise 'too many pages requested' if page_count >= MAX_TAGS_PAGES
|
||||
end
|
||||
|
||||
def tags_page(before: nil, last: nil, sort: nil, name: nil, page_size: 100, referrers: nil)
|
||||
def tags_page(before: nil, last: nil, sort: nil, name: nil, page_size: 100, referrers: nil, referrer_type: nil)
|
||||
raise ArgumentError, 'not a migrated repository' unless migrated?
|
||||
|
||||
page = gitlab_api_client.tags(
|
||||
|
|
@ -508,7 +508,8 @@ class ContainerRepository < ApplicationRecord
|
|||
last: last,
|
||||
sort: sort,
|
||||
name: name,
|
||||
referrers: referrers
|
||||
referrers: referrers,
|
||||
referrer_type: referrer_type
|
||||
)
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -816,6 +816,7 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
scope :in_organization, -> (organization) { where(organization: organization) }
|
||||
scope :by_project_namespace, -> (project_namespace) { where(project_namespace_id: project_namespace) }
|
||||
|
||||
scope :not_a_fork, -> {
|
||||
left_outer_joins(:fork_network_member).where(fork_network_member: { forked_from_project_id: nil })
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class Route < MainClusterwide::ApplicationRecord
|
|||
after_update :create_redirect_for_old_path
|
||||
after_update :rename_descendants
|
||||
|
||||
scope :by_paths, -> (paths) { where(arel_table[:path].lower.in(paths.map(&:downcase))) }
|
||||
scope :inside_path, -> (path) { where('routes.path LIKE ?', "#{sanitize_sql_like(path)}/%") }
|
||||
scope :for_routable, -> (routable) { where(source: routable) }
|
||||
scope :for_routable_type, -> (routable_type) { where(source_type: routable_type) }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
module Namespaces
|
||||
class ProjectNamespacePolicy < Namespaces::GroupProjectNamespaceSharedPolicy
|
||||
# TODO: once https://gitlab.com/gitlab-org/gitlab/-/issues/364277 is solved, this
|
||||
# should not be necessary anymore, and should be replaced with `delegate(:project)`.
|
||||
delegate(:reload_project)
|
||||
delegate(:project)
|
||||
|
||||
rule { can?(:read_project) }.enable :read_namespace
|
||||
rule { ~can?(:read_project) }.prevent :read_namespace
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
- unless @skip_current_level_breadcrumb
|
||||
- push_to_schema_breadcrumb(@breadcrumb_title, breadcrumb_title_link)
|
||||
|
||||
%nav.breadcrumbs.gl-breadcrumbs{ 'aria-label': _('Breadcrumbs'), data: { testid: 'breadcrumb-links' } }
|
||||
%nav.breadcrumbs.gl-breadcrumbs.tmp-breadcrumbs-fix{ 'aria-label': _('Breadcrumbs'), data: { testid: 'breadcrumb-links' } }
|
||||
%ul.breadcrumb.gl-breadcrumb-list.js-breadcrumbs-list.gl-flex-grow-1
|
||||
- unless hide_top_links
|
||||
= header_title
|
||||
|
|
|
|||
|
|
@ -35,4 +35,4 @@
|
|||
title: _("There are no closed merge requests"))
|
||||
|
||||
- else
|
||||
= render_if_exists 'shared/empty_states/empty_merge_requests_without_filters', button_path: button_path
|
||||
= render_if_exists 'shared/empty_states/merge_requests_without_filters', button_path: button_path
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
- button_path = local_assigns[:button_path]
|
||||
- button_text = _('New merge request')
|
||||
|
||||
- project_tracking_data = @project ? { track_action: 'click_new_mr_project_mrs_empty_list_page',
|
||||
track_label: 'new_mr_project_mrs_empty_list',
|
||||
track_experiment: 'issues_mrs_empty_state' } : {}
|
||||
|
||||
= render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-state/empty-merge-requests-md.svg',
|
||||
empty_state_options: { data: { testid: 'issuable-empty-state' } },
|
||||
title: _("Merge requests are a place to propose changes you've made to a project and discuss those changes with others")) do |c|
|
||||
|
|
@ -13,4 +17,4 @@
|
|||
title: button_text,
|
||||
id: 'new_merge_request_link',
|
||||
variant: :confirm,
|
||||
data: { testid: 'new-merge-request-button', event_tracking: 'click_new_merge_request_empty_list' }
|
||||
data: { testid: 'new-merge-request-button', **project_tracking_data }
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: pre_receive_secret_detection_beta_release
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148668
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/454583
|
||||
milestone: '16.11'
|
||||
type: beta
|
||||
group: group::secret detection
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: remove_shared_jwts
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423106
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148106
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/452294
|
||||
milestone: '16.11'
|
||||
group: group::pipeline security
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -62,6 +62,12 @@ module.exports = {
|
|||
Maybe compatible?
|
||||
*/
|
||||
outlineWidth: false,
|
||||
/*
|
||||
Disable preflight styles so that `@tailwind base` compiles to CSS vars declarations without
|
||||
any of the resets which we don't need.
|
||||
More on this at https://tailwindcss.com/docs/preflight.
|
||||
*/
|
||||
preflight: false,
|
||||
},
|
||||
theme: {
|
||||
// These extends probably should be moved to GitLab UI:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ classes:
|
|||
- Atlassian::Identity
|
||||
feature_categories:
|
||||
- system_access
|
||||
description: Stores Atlassian credentials that are used to integrate with Atlassian API
|
||||
description: Stores Atlassian credentials that are used to integrate with Atlassian
|
||||
API
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40176
|
||||
milestone: '13.4'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64728
|
||||
milestone: '14.2'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/b6316689fdc2d142af85b17d511d39e50712b420
|
||||
milestone: '11.6'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: stores the canonical version of user's primary email address
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27722
|
||||
milestone: '13.0'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ classes:
|
|||
- UserHighestRole
|
||||
feature_categories:
|
||||
- system_access
|
||||
description: Stores highest role per User they have in a Group or a Project. If a User has an open invite or pending access request or no membership the highest role will be set to nil.
|
||||
description: Stores highest role per User they have in a Group or a Project. If a
|
||||
User has an open invite or pending access request or no membership the highest role
|
||||
will be set to nil.
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26987
|
||||
milestone: '12.9'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47846
|
||||
milestone: '13.7'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
|||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35797
|
||||
milestone: '13.2'
|
||||
gitlab_schema: gitlab_main
|
||||
gitlab_schema: gitlab_main_clusterwide
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveIndexMergeRequestsOnTargetProjectIdAndIidAndStateId < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.11'
|
||||
|
||||
INDEX_NAME = 'index_merge_requests_on_target_project_id_and_iid_and_state_id'
|
||||
COLUMN_NAMES = %i[target_project_id iid state_id]
|
||||
|
||||
# TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/454262
|
||||
def up
|
||||
prepare_async_index_removal :merge_requests, COLUMN_NAMES, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
unprepare_async_index :merge_requests, COLUMN_NAMES, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
efa4c1150358295bff0560247d55af67f30252f098c039abb203fbe135b0f287
|
||||
|
|
@ -144,7 +144,7 @@ GitLab Dedicated limits the number of reverse PrivateLink connections to 10.
|
|||
|
||||
### IP allowlist
|
||||
|
||||
GitLab Dedicated allows you to control which IP addresses can access your instance through an IP allowlist. Once the IP allowlist has been enabled, when an IP not on the allowlist tries to access your instance an `HTTP 403 Forbidden` response is returned. The IP allowlist is applied to incoming Web requests only and does not apply to incoming SSH requests.
|
||||
GitLab Dedicated allows you to control which IP addresses can access your instance through an IP allowlist. Once the IP allowlist has been enabled, when an IP not on the allowlist tries to access your instance an `HTTP 403 Forbidden` response is returned.
|
||||
|
||||
IP addresses that have been added to your IP allowlist can be viewed on the Configuration page in Switchboard. You can add or remove IP addresses from your allowlist with Switchboard or a support request.
|
||||
|
||||
|
|
|
|||
|
|
@ -86,9 +86,6 @@ The following metrics are available:
|
|||
| `gitlab_transaction_event_push_branch_total` | Counter | 9.4 | Counter for all branch pushes | |
|
||||
| `gitlab_transaction_event_rails_exception_total` | Counter | 9.4 | Counter for number of rails exceptions | |
|
||||
| `gitlab_transaction_event_receive_email_total` | Counter | 9.4 | Counter for received emails | `handler` |
|
||||
| `gitlab_transaction_event_remote_mirrors_failed_total` | Counter | 10.8 | Counter for failed remote mirrors | |
|
||||
| `gitlab_transaction_event_remote_mirrors_finished_total` | Counter | 10.8 | Counter for finished remote mirrors | |
|
||||
| `gitlab_transaction_event_remote_mirrors_running_total` | Counter | 10.8 | Counter for running remote mirrors | |
|
||||
| `gitlab_transaction_event_remove_branch_total` | Counter | 9.4 | Counter when a branch is removed for any repository | |
|
||||
| `gitlab_transaction_event_remove_repository_total` | Counter | 9.4 | Counter when a repository is removed | |
|
||||
| `gitlab_transaction_event_remove_tag_total` | Counter | 9.4 | Counter when a tag is remove for any repository | |
|
||||
|
|
@ -413,6 +410,9 @@ configuration option in `gitlab.yml`. These metrics are served from the
|
|||
| `geo_design_management_repositories_verified` | Gauge | 16.1 | Number of design repositories verified on secondary | `url` |
|
||||
| `geo_design_management_repositories_verification_failed` | Gauge | 16.1 | Number of design repositories verifications failed on secondary | `url` |
|
||||
| `gitlab_ci_queue_active_runners_total` | Histogram | 16.3 | The number of active runners that can process the CI/CD queue in a project | |
|
||||
| `gitlab_transaction_event_remote_mirrors_failed_total` | Counter | 10.8 | Counter for failed remote mirrors | |
|
||||
| `gitlab_transaction_event_remote_mirrors_finished_total` | Counter | 10.8 | Counter for finished remote mirrors | |
|
||||
| `gitlab_transaction_event_remote_mirrors_running_total` | Counter | 10.8 | Counter for running remote mirrors | |
|
||||
|
||||
## Database load balancing metrics
|
||||
|
||||
|
|
|
|||
|
|
@ -17600,6 +17600,7 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="containerrepositorydetailstagsname"></a>`name` | [`String`](#string) | Search by tag name. |
|
||||
| <a id="containerrepositorydetailstagsreferrertype"></a>`referrerType` | [`String`](#string) | Comma-separated list of artifact types used to filter referrers. Applies only when `referrers` is set to `true`. |
|
||||
| <a id="containerrepositorydetailstagsreferrers"></a>`referrers` | [`Boolean`](#boolean) | Include tag referrers. |
|
||||
| <a id="containerrepositorydetailstagssort"></a>`sort` | [`ContainerRepositoryTagSort`](#containerrepositorytagsort) | Sort tags by these criteria. |
|
||||
|
||||
|
|
@ -24509,6 +24510,22 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="namespacescanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
|
||||
|
||||
##### `Namespace.workItem`
|
||||
|
||||
Find a work item by IID directly associated with the namespace(project or group). Returns `null` for group level work items if the `namespace_level_work_items` feature flag is disabled.
|
||||
|
||||
DETAILS:
|
||||
**Introduced** in GitLab 16.10.
|
||||
**Status**: Experiment.
|
||||
|
||||
Returns [`WorkItem`](#workitem).
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="namespaceworkitemiid"></a>`iid` | [`String!`](#string) | IID of the work item. |
|
||||
|
||||
### `NamespaceBan`
|
||||
|
||||
#### Fields
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ vulnerability management features without running a pipeline.
|
|||
1. Log in to GitLab.
|
||||
1. Go to `/-/user_settings/personal_access_tokens` and generate a personal access token with `api` permissions.
|
||||
1. Go to your project page and find the project ID. You can find the project ID below the project title.
|
||||
1. [Clone the GitLab repository](../../gitlab-basics/start-using-git.md#clone-a-repository) to your local machine.
|
||||
1. Clone the GitLab repository to your local machine.
|
||||
1. Open a terminal and go to `gitlab/qa` directory.
|
||||
1. Run `bundle install`
|
||||
1. Run the following command:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ info: "To determine the technical writer assigned to the Stage/Group associated
|
|||
description: "Add, commit, and push a file to your Git repository using the command line."
|
||||
---
|
||||
|
||||
# Use Git to add a file to a repository
|
||||
# Add files and make changes to a Git repository
|
||||
|
||||
You use Git the Git command line to add files, and make changes to existing files, and delete files in a Git repository.
|
||||
|
||||
## Add files to a Git repository
|
||||
|
||||
To add a new file from the command line:
|
||||
|
||||
|
|
@ -86,7 +90,7 @@ repository.
|
|||
To create a merge request, copy the link sent back from the remote
|
||||
repository and paste it into a browser window.
|
||||
|
||||
## Add a file to the last commit
|
||||
### Add a file to the last commit
|
||||
|
||||
```shell
|
||||
git add <filename>
|
||||
|
|
@ -96,6 +100,108 @@ git commit --amend
|
|||
Append `--no-edit` to the `commit` command if you do not want to edit the commit
|
||||
message.
|
||||
|
||||
## Make changes to existing files
|
||||
|
||||
When you make changes to files in a repository, Git tracks the changes
|
||||
against the most recent version of the checked out branch. You can use
|
||||
Git commands to review and commit your changes to the branch, and push
|
||||
your work to GitLab.
|
||||
|
||||
### View repository status
|
||||
|
||||
When you add, change, or delete files or folders, Git knows about the
|
||||
changes. To check which files have been changed:
|
||||
|
||||
- From your repository, run `git status`.
|
||||
|
||||
The branch name, most recent commit, and any new or changed files are displayed.
|
||||
New files are displayed in green. Changed files are displayed in red.
|
||||
|
||||
### View differences
|
||||
|
||||
You can display the difference (or diff) between your local
|
||||
changes and the most recent version of a branch. View a diff to
|
||||
understand your local changes before you commit them to the branch.
|
||||
|
||||
To view the differences between your local unstaged changes and the
|
||||
latest version that you cloned or pulled:
|
||||
|
||||
- From your repository, run `git diff`.
|
||||
|
||||
To compare your changes against a specific branch, run
|
||||
`git diff <branch>`.
|
||||
|
||||
The diff is displayed:
|
||||
|
||||
- Lines with additions begin with a plus (`+`) and are displayed in green.
|
||||
- Lines with removals or changes begin with a minus (`-`) and are displayed in red.
|
||||
|
||||
If the diff is large, by default only a portion of the diff is
|
||||
displayed. You can advance the diff with <kbd>Enter</kbd>, and quit
|
||||
back to your terminal with <kbd>Q</kbd>.
|
||||
|
||||
### Add and commit local changes
|
||||
|
||||
When you're ready to write your changes to the branch, you can commit
|
||||
them. A commit includes a comment that records information about the
|
||||
changes, and usually becomes the new tip of the branch.
|
||||
|
||||
Git doesn't automatically include any files you move, change, or
|
||||
delete in a commit. This prevents you from accidentally including a
|
||||
change or file, like a temporary directory. To include changes in a
|
||||
commit, stage them with `git add`.
|
||||
|
||||
To stage and commit your changes:
|
||||
|
||||
1. From your repository, for each file or directory you want to add, run `git add <file name or path>`.
|
||||
|
||||
To stage all files in the current working directory, run `git add .`.
|
||||
|
||||
1. Confirm that the files have been added to staging:
|
||||
|
||||
```shell
|
||||
git status
|
||||
```
|
||||
|
||||
The files are displayed in green.
|
||||
|
||||
1. To commit the staged files:
|
||||
|
||||
```shell
|
||||
git commit -m "<comment that describes the changes>"
|
||||
```
|
||||
|
||||
The changes are committed to the branch.
|
||||
|
||||
### Commit all changes
|
||||
|
||||
You can stage all your changes and commit them with one command:
|
||||
|
||||
```shell
|
||||
git commit -a -m "<comment that describes the changes>"
|
||||
```
|
||||
|
||||
Be careful your commit doesn't include files you don't want to record
|
||||
to the remote repository. As a rule, always check the status of your
|
||||
local repository before you commit changes.
|
||||
|
||||
### Send changes to GitLab
|
||||
|
||||
To push all local changes to the remote repository:
|
||||
|
||||
```shell
|
||||
git push <remote> <name-of-branch>
|
||||
```
|
||||
|
||||
For example, to push your local commits to the `main` branch of the `origin` remote:
|
||||
|
||||
```shell
|
||||
git push origin main
|
||||
```
|
||||
|
||||
Sometimes Git does not allow you to push to a repository. Instead,
|
||||
you must [force an update](../topics/git/git_rebase.md#force-pushing).
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Add file from the UI](../user/project/repository/index.md#add-a-file-from-the-ui)
|
||||
|
|
|
|||
|
|
@ -7,119 +7,9 @@ description: "Introduction to using Git through the command line."
|
|||
|
||||
# Command line Git
|
||||
|
||||
You can do many Git operations directly in GitLab. However, the command line is required for advanced tasks,
|
||||
like fixing complex merge conflicts or rolling back commits.
|
||||
You can do many Git operations directly in GitLab. However, the command line is required for advanced tasks.
|
||||
|
||||
If you're new to Git and want to learn by working in your own project,
|
||||
[learn how to make your first commit](../tutorials/make_first_git_commit/index.md).
|
||||
|
||||
For a quick reference of Git commands, download a [Git Cheat Sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf).
|
||||
|
||||
Learn how [GitLab became the backbone of the Worldline](https://about.gitlab.com/customers/worldline/) development environment.
|
||||
|
||||
To help you visualize what you're doing locally, you can install a
|
||||
[Git GUI app](https://git-scm.com/downloads/guis).
|
||||
|
||||
## Choose a repository
|
||||
|
||||
Before you begin, choose the repository you want to work in. You can use any project you have permission to
|
||||
access on GitLab.com or any other GitLab instance.
|
||||
|
||||
To use the repository in the examples on this page:
|
||||
|
||||
1. Go to [https://gitlab.com/gitlab-tests/sample-project/](https://gitlab.com/gitlab-tests/sample-project/).
|
||||
1. In the upper-right corner, select **Fork**.
|
||||
1. Choose a namespace for your fork.
|
||||
|
||||
The project becomes available at `https://gitlab.com/<your-namespace>/sample-project/`.
|
||||
|
||||
You can [fork](../user/project/repository/forking_workflow.md#create-a-fork) any project you have access to.
|
||||
|
||||
## Clone a repository
|
||||
|
||||
When you clone a repository, the files from the remote repository are downloaded to your computer,
|
||||
and a connection is created.
|
||||
|
||||
This connection requires you to add credentials. You can either use SSH or HTTPS. SSH is recommended.
|
||||
|
||||
### Clone with SSH
|
||||
|
||||
Clone with SSH when you want to authenticate only one time.
|
||||
|
||||
1. Authenticate with GitLab by following the instructions in the [SSH documentation](../user/ssh.md).
|
||||
1. On the left sidebar, select **Search or go to** and find the project you want to clone.
|
||||
1. On the project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with SSH**.
|
||||
1. Open a terminal and go to the directory where you want to clone the files.
|
||||
Git automatically creates a folder with the repository name and downloads the files there.
|
||||
1. Run this command:
|
||||
|
||||
```shell
|
||||
git clone git@gitlab.com:gitlab-tests/sample-project.git
|
||||
```
|
||||
|
||||
1. To view the files, go to the new directory:
|
||||
|
||||
```shell
|
||||
cd sample-project
|
||||
```
|
||||
|
||||
You can also
|
||||
[clone a repository and open it directly in Visual Studio Code](../user/project/repository/index.md#clone-and-open-in-visual-studio-code).
|
||||
|
||||
### Clone with HTTPS
|
||||
|
||||
Clone with HTTPS when you want to authenticate each time you perform an operation between your computer and GitLab.
|
||||
[OAuth credential helpers](../user/profile/account/two_factor_authentication.md#oauth-credential-helpers) can decrease
|
||||
the number of times you must manually authenticate, making HTTPS a seamless experience.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find the project you want to clone.
|
||||
1. On the project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with HTTPS**.
|
||||
1. Open a terminal and go to the directory where you want to clone the files.
|
||||
1. Run the following command. Git automatically creates a folder with the repository name and downloads the files there.
|
||||
|
||||
```shell
|
||||
git clone https://gitlab.com/gitlab-tests/sample-project.git
|
||||
```
|
||||
|
||||
1. GitLab requests your username and password.
|
||||
|
||||
If you have enabled two-factor authentication (2FA) on your account, you cannot use your account password. Instead, you can do one of the following:
|
||||
|
||||
- [Clone using a token](#clone-using-a-token) with `read_repository` or `write_repository` permissions.
|
||||
- Install an [OAuth credential helper](../user/profile/account/two_factor_authentication.md#oauth-credential-helpers).
|
||||
|
||||
If you have not enabled 2FA, use your account password.
|
||||
|
||||
1. To view the files, go to the new directory:
|
||||
|
||||
```shell
|
||||
cd sample-project
|
||||
```
|
||||
|
||||
NOTE:
|
||||
On Windows, if you enter your password incorrectly multiple times and an `Access denied` message appears,
|
||||
add your namespace (username or group) to the path:
|
||||
`git clone https://namespace@gitlab.com/gitlab-org/gitlab.git`.
|
||||
|
||||
#### Clone using a token
|
||||
|
||||
Clone with HTTPS using a token if:
|
||||
|
||||
- You want to use 2FA.
|
||||
- You want to have a revocable set of credentials scoped to one or more repositories.
|
||||
|
||||
You can use any of these tokens to authenticate when cloning over HTTPS:
|
||||
|
||||
- [Personal access tokens](../user/profile/personal_access_tokens.md).
|
||||
- [Deploy tokens](../user/project/deploy_tokens/index.md).
|
||||
- [Project access tokens](../user/project/settings/project_access_tokens.md).
|
||||
- [Group access tokens](../user/group/settings/group_access_tokens.md).
|
||||
|
||||
```shell
|
||||
git clone https://<username>:<token>@gitlab.example.com/tanuki/awesome_project.git
|
||||
```
|
||||
|
||||
### Convert a local directory into a repository
|
||||
## Convert a local directory into a repository
|
||||
|
||||
You can initialize a local folder so Git tracks it as a repository.
|
||||
|
||||
|
|
@ -137,7 +27,7 @@ You can initialize a local folder so Git tracks it as a repository.
|
|||
1. Add the [path to your remote repository](#add-a-remote)
|
||||
so Git can upload your files into the correct project.
|
||||
|
||||
#### Add a remote
|
||||
### Add a remote
|
||||
|
||||
You add a "remote" to tell Git which remote repository in GitLab is tied
|
||||
to the specific local folder on your computer.
|
||||
|
|
@ -153,9 +43,7 @@ To add a remote to your local copy:
|
|||
git remote add origin git@gitlab.com:username/projectpath.git
|
||||
```
|
||||
|
||||
After you've done that, you can [stage your files](#add-and-commit-local-changes) and [upload them to GitLab](#send-changes-to-gitlab).
|
||||
|
||||
#### View your remote repositories
|
||||
### View your remote repositories
|
||||
|
||||
To view your remote repositories, type:
|
||||
|
||||
|
|
@ -165,7 +53,7 @@ git remote -v
|
|||
|
||||
The `-v` flag stands for verbose.
|
||||
|
||||
### Download the latest changes in the project
|
||||
## Download the latest changes in the project
|
||||
|
||||
To work on an up-to-date copy of the project, you `pull` to get all the changes made by users
|
||||
since the last time you cloned or pulled the project. Replace `<name-of-branch>`
|
||||
|
|
@ -244,153 +132,6 @@ git log -- <file>
|
|||
gitk <file>
|
||||
```
|
||||
|
||||
## Branches
|
||||
|
||||
A **branch** is a copy of the files in the repository at the time you create the branch.
|
||||
You can work in your branch without affecting other branches. When
|
||||
you're ready to add your changes to the main codebase, you can merge your branch into
|
||||
the default branch, for example, `main`.
|
||||
|
||||
Use branches when you:
|
||||
|
||||
- Want to add code to a project but you're not sure if it works properly.
|
||||
- Are collaborating on the project with others, and don't want your work to get mixed up.
|
||||
|
||||
A new branch is often called **feature branch** to differentiate from the
|
||||
[default branch](../user/project/repository/branches/default.md).
|
||||
|
||||
### Create a branch
|
||||
|
||||
To create a feature branch:
|
||||
|
||||
```shell
|
||||
git checkout -b <name-of-branch>
|
||||
```
|
||||
|
||||
GitLab enforces [branch naming rules](../user/project/repository/branches/index.md#name-your-branch)
|
||||
to prevent problems, and provides
|
||||
[branch naming patterns](../user/project/repository/branches/index.md#prefix-branch-names-with-issue-numbers)
|
||||
to streamline merge request creation.
|
||||
|
||||
### Switch to a branch
|
||||
|
||||
All work in Git is done in a branch.
|
||||
You can switch between branches to see the state of the files and work in that branch.
|
||||
|
||||
To switch to an existing branch:
|
||||
|
||||
```shell
|
||||
git checkout <name-of-branch>
|
||||
```
|
||||
|
||||
For example, to change to the `main` branch:
|
||||
|
||||
```shell
|
||||
git checkout main
|
||||
```
|
||||
|
||||
## Make changes
|
||||
|
||||
When you make changes to files in a repository, Git tracks the changes
|
||||
against the most recent version of the checked out branch. You can use
|
||||
Git commands to review and commit your changes to the branch, and push
|
||||
your work to GitLab.
|
||||
|
||||
### View repository status
|
||||
|
||||
When you add, change, or delete files or folders, Git knows about the
|
||||
changes. To check which files have been changed:
|
||||
|
||||
- From your repository, run `git status`.
|
||||
|
||||
The branch name, most recent commit, and any new or changed files are displayed.
|
||||
New files are displayed in green. Changed files are displayed in red.
|
||||
|
||||
### View differences
|
||||
|
||||
You can display the difference (or diff) between your local
|
||||
changes and the most recent version of a branch. View a diff to
|
||||
understand your local changes before you commit them to the branch.
|
||||
|
||||
To view the differences between your local unstaged changes and the
|
||||
latest version that you cloned or pulled:
|
||||
|
||||
- From your repository, run `git diff`.
|
||||
|
||||
To compare your changes against a specific branch, run
|
||||
`git diff <branch>`.
|
||||
|
||||
The diff is displayed:
|
||||
|
||||
- Lines with additions begin with a plus (`+`) and are displayed in green.
|
||||
- Lines with removals or changes begin with a minus (`-`) and are displayed in red.
|
||||
|
||||
If the diff is large, by default only a portion of the diff is
|
||||
displayed. You can advance the diff with <kbd>Enter</kbd>, and quit
|
||||
back to your terminal with <kbd>Q</kbd>.
|
||||
|
||||
### Add and commit local changes
|
||||
|
||||
When you're ready to write your changes to the branch, you can commit
|
||||
them. A commit includes a comment that records information about the
|
||||
changes, and usually becomes the new tip of the branch.
|
||||
|
||||
Git doesn't automatically include any files you move, change, or
|
||||
delete in a commit. This prevents you from accidentally including a
|
||||
change or file, like a temporary directory. To include changes in a
|
||||
commit, stage them with `git add`.
|
||||
|
||||
To stage and commit your changes:
|
||||
|
||||
1. From your repository, for each file or directory you want to add, run `git add <file name or path>`.
|
||||
|
||||
To stage all files in the current working directory, run `git add .`.
|
||||
|
||||
1. Confirm that the files have been added to staging:
|
||||
|
||||
```shell
|
||||
git status
|
||||
```
|
||||
|
||||
The files are displayed in green.
|
||||
|
||||
1. To commit the staged files:
|
||||
|
||||
```shell
|
||||
git commit -m "<comment that describes the changes>"
|
||||
```
|
||||
|
||||
The changes are committed to the branch.
|
||||
|
||||
### Commit all changes
|
||||
|
||||
You can stage all your changes and commit them with one command:
|
||||
|
||||
```shell
|
||||
git commit -a -m "<comment that describes the changes>"
|
||||
```
|
||||
|
||||
Be careful your commit doesn't include files you don't want to record
|
||||
to the remote repository. As a rule, always check the status of your
|
||||
local repository before you commit changes.
|
||||
|
||||
### Send changes to GitLab
|
||||
|
||||
To push all local changes to the remote repository:
|
||||
|
||||
```shell
|
||||
git push <remote> <name-of-branch>
|
||||
```
|
||||
|
||||
For example, to push your local commits to the `main` branch of the `origin` remote:
|
||||
|
||||
```shell
|
||||
git push origin main
|
||||
```
|
||||
|
||||
Sometimes Git does not allow you to push to a repository. Instead,
|
||||
you must [force an update](../topics/git/git_rebase.md#force-pushing).
|
||||
|
||||
## Delete changes
|
||||
|
||||
If want to undo your changes, you can use Git commands to go back to an earlier version of a repository.
|
||||
|
|
@ -469,7 +210,7 @@ changes from the original repository. It is common to call this remote repositor
|
|||
|
||||
You can now use the `upstream` as a [`<remote>` to `pull` new updates](#download-the-latest-changes-in-the-project)
|
||||
from the original repository, and use the `origin`
|
||||
to [push local changes](#send-changes-to-gitlab) and create merge requests.
|
||||
to [push local changes](add-file.md#send-changes-to-gitlab) and create merge requests.
|
||||
|
||||
## Related topics
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,159 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Get started with Git
|
||||
|
||||
You can use Git from a command line to interact with GitLab.
|
||||
If you're new to Git and want to learn by working in your own project,
|
||||
[learn how to make your first commit](../../tutorials/make_first_git_commit/index.md).
|
||||
|
||||
For a quick reference of Git commands, download a [Git Cheat Sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf).
|
||||
|
||||
Learn how [GitLab became the backbone of the Worldline](https://about.gitlab.com/customers/worldline/) development environment.
|
||||
|
||||
To help you visualize what you're doing locally, you can install a
|
||||
[Git GUI app](https://git-scm.com/downloads/guis).
|
||||
|
||||
## Choose a repository
|
||||
|
||||
Before you begin, choose the repository you want to work in. You can use any project you have permission to
|
||||
access on GitLab.com or any other GitLab instance.
|
||||
|
||||
To use the repository in the examples on this page:
|
||||
|
||||
1. Go to [https://gitlab.com/gitlab-tests/sample-project/](https://gitlab.com/gitlab-tests/sample-project/).
|
||||
1. In the upper-right corner, select **Fork**.
|
||||
1. Choose a namespace for your fork.
|
||||
|
||||
The project becomes available at `https://gitlab.com/<your-namespace>/sample-project/`.
|
||||
|
||||
You can [fork](../../user/project/repository/forking_workflow.md#create-a-fork) any project you have access to.
|
||||
|
||||
## Cloning Git repositories
|
||||
|
||||
When you clone a repository, the files from the remote repository are downloaded to your computer,
|
||||
and a connection is created.
|
||||
|
||||
This connection requires you to add credentials. You can either use SSH or HTTPS. SSH is recommended.
|
||||
|
||||
### Clone with SSH
|
||||
|
||||
Clone with SSH when you want to authenticate only one time.
|
||||
|
||||
1. Authenticate with GitLab by following the instructions in the [SSH documentation](../../user/ssh.md).
|
||||
1. On the left sidebar, select **Search or go to** and find the project you want to clone.
|
||||
1. On the project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with SSH**.
|
||||
1. Open a terminal and go to the directory where you want to clone the files.
|
||||
Git automatically creates a folder with the repository name and downloads the files there.
|
||||
1. Run this command:
|
||||
|
||||
```shell
|
||||
git clone git@gitlab.com:gitlab-tests/sample-project.git
|
||||
```
|
||||
|
||||
1. To view the files, go to the new directory:
|
||||
|
||||
```shell
|
||||
cd sample-project
|
||||
```
|
||||
|
||||
You can also
|
||||
[clone a repository and open it directly in Visual Studio Code](../../user/project/repository/index.md#clone-and-open-in-visual-studio-code).
|
||||
|
||||
### Clone with HTTPS
|
||||
|
||||
Clone with HTTPS when you want to authenticate each time you perform an operation between your computer and GitLab.
|
||||
[OAuth credential helpers](../../user/profile/account/two_factor_authentication.md#oauth-credential-helpers) can decrease
|
||||
the number of times you must manually authenticate, making HTTPS a seamless experience.
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find the project you want to clone.
|
||||
1. On the project's overview page, in the upper-right corner, select **Code**, then copy the URL for **Clone with HTTPS**.
|
||||
1. Open a terminal and go to the directory where you want to clone the files.
|
||||
1. Run the following command. Git automatically creates a folder with the repository name and downloads the files there.
|
||||
|
||||
```shell
|
||||
git clone https://gitlab.com/gitlab-tests/sample-project.git
|
||||
```
|
||||
|
||||
1. GitLab requests your username and password.
|
||||
|
||||
If you have enabled two-factor authentication (2FA) on your account, you cannot use your account password. Instead, you can do one of the following:
|
||||
|
||||
- [Clone using a token](#clone-using-a-token) with `read_repository` or `write_repository` permissions.
|
||||
- Install an [OAuth credential helper](../../user/profile/account/two_factor_authentication.md#oauth-credential-helpers).
|
||||
|
||||
If you have not enabled 2FA, use your account password.
|
||||
|
||||
1. To view the files, go to the new directory:
|
||||
|
||||
```shell
|
||||
cd sample-project
|
||||
```
|
||||
|
||||
NOTE:
|
||||
On Windows, if you enter your password incorrectly multiple times and an `Access denied` message appears,
|
||||
add your namespace (username or group) to the path:
|
||||
`git clone https://namespace@gitlab.com/gitlab-org/gitlab.git`.
|
||||
|
||||
#### Clone using a token
|
||||
|
||||
Clone with HTTPS using a token if:
|
||||
|
||||
- You want to use 2FA.
|
||||
- You want to have a revocable set of credentials scoped to one or more repositories.
|
||||
|
||||
You can use any of these tokens to authenticate when cloning over HTTPS:
|
||||
|
||||
- [Personal access tokens](../../user/profile/personal_access_tokens.md).
|
||||
- [Deploy tokens](../../user/project/deploy_tokens/index.md).
|
||||
- [Project access tokens](../../user/project/settings/project_access_tokens.md).
|
||||
- [Group access tokens](../../user/group/settings/group_access_tokens.md).
|
||||
|
||||
```shell
|
||||
git clone https://<username>:<token>@gitlab.example.com/tanuki/awesome_project.git
|
||||
```
|
||||
|
||||
## Using Git branches
|
||||
|
||||
A **branch** is a copy of the files in the repository at the time you create the branch.
|
||||
You can work in your branch without affecting other branches. When
|
||||
you're ready to add your changes to the main codebase, you can merge your branch into
|
||||
the default branch, for example, `main`.
|
||||
|
||||
Use branches when you:
|
||||
|
||||
- Want to add code to a project but you're not sure if it works properly.
|
||||
- Are collaborating on the project with others, and don't want your work to get mixed up.
|
||||
|
||||
A new branch is often called **feature branch** to differentiate from the
|
||||
[default branch](../../user/project/repository/branches/default.md).
|
||||
|
||||
### Create a branch
|
||||
|
||||
To create a feature branch:
|
||||
|
||||
```shell
|
||||
git checkout -b <name-of-branch>
|
||||
```
|
||||
|
||||
GitLab enforces [branch naming rules](../../user/project/repository/branches/index.md#name-your-branch)
|
||||
to prevent problems, and provides
|
||||
[branch naming patterns](../../user/project/repository/branches/index.md#prefix-branch-names-with-issue-numbers)
|
||||
to streamline merge request creation.
|
||||
|
||||
### Switch to a branch
|
||||
|
||||
All work in Git is done in a branch.
|
||||
You can switch between branches to see the state of the files and work in that branch.
|
||||
|
||||
To switch to an existing branch:
|
||||
|
||||
```shell
|
||||
git checkout <name-of-branch>
|
||||
```
|
||||
|
||||
For example, to change to the `main` branch:
|
||||
|
||||
```shell
|
||||
git checkout main
|
||||
```
|
||||
|
||||
## Common terms
|
||||
|
||||
|
|
@ -35,10 +187,6 @@ To create a copy of a remote repository's files on your computer, you **clone**
|
|||
When you clone a repository, you can sync the repository with the remote repository in GitLab.
|
||||
You can modify the files locally and upload the changes to the remote repository on GitLab.
|
||||
|
||||
**Get started:**
|
||||
|
||||
- [Clone a repository from GitLab to your local machine](../../gitlab-basics/start-using-git.md#clone-a-repository).
|
||||
|
||||
### Pull
|
||||
|
||||
When the remote repository changes, your local copy is behind. You can update your local copy with the new
|
||||
|
|
@ -57,7 +205,7 @@ changes to GitLab. This action is known as **pushing** to the remote, because yo
|
|||
|
||||
**Get started**:
|
||||
|
||||
- [Send changes to GitLab](../../gitlab-basics/start-using-git.md#send-changes-to-gitlab).
|
||||
- [Send changes to GitLab](../../gitlab-basics/add-file.md#send-changes-to-gitlab).
|
||||
|
||||
### Fork
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
description: "How to install Git on your local machine."
|
||||
---
|
||||
|
||||
# Installing Git
|
||||
# Install and configure Git
|
||||
|
||||
To begin contributing to GitLab projects, you must download and install the Git client on your computer.
|
||||
|
||||
|
|
|
|||
|
|
@ -107,9 +107,7 @@ To back up an entire project on GitLab.com, you can export it either:
|
|||
With exports, be aware of [what is and is not](../project/settings/import_export.md#project-items-that-are-exported)
|
||||
included in a project export.
|
||||
|
||||
GitLab is built on Git, so you can back up just the repository of a project by
|
||||
[cloning](../../gitlab-basics/start-using-git.md#clone-a-repository) it to
|
||||
another computer.
|
||||
GitLab is built on Git, so you can back up just the repository of a project by cloning it to another computer.
|
||||
Similarly, you can clone a project's wiki to back it up. All files
|
||||
[uploaded after August 22, 2020](../project/wiki/index.md#create-a-new-wiki-page)
|
||||
are included when cloning.
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ or API. However, administrators can use a workaround:
|
|||
- [Create a project pipeline](../../../api/pipelines.md#create-a-new-pipeline) in one of the group's projects.
|
||||
- [Create an issue](../../../api/issues.md#new-issue) in one of the group's projects.
|
||||
|
||||
1. Use the group token to [clone a group's project](../../../gitlab-basics/start-using-git.md#clone-with-https)
|
||||
1. Use the group token to [clone a group's project](../../../topics/git/get_started.md#clone-with-https)
|
||||
using HTTPS.
|
||||
|
||||
## Revoke a group access token using the UI
|
||||
|
|
|
|||
|
|
@ -351,8 +351,8 @@ When you install from source, the `composer` configures an
|
|||
access to the project's Git repository.
|
||||
Depending on the project visibility, the access type is different:
|
||||
|
||||
- On public projects, the `https` Git URL is used. Make sure you can [clone the repository with HTTPS](../../../gitlab-basics/start-using-git.md#clone-with-https).
|
||||
- On internal or private projects, the `ssh` Git URL is used. Make sure you can [clone the repository with SSH](../../../gitlab-basics/start-using-git.md#clone-with-ssh).
|
||||
- On public projects, the `https` Git URL is used. Make sure you can [clone the repository with HTTPS](../../../topics/git/get_started.md#clone-with-https).
|
||||
- On internal or private projects, the `ssh` Git URL is used. Make sure you can [clone the repository with SSH](../../../topics/git/get_started.md#clone-with-ssh).
|
||||
|
||||
You can access the `ssh` Git URL from a CI/CD job using [SSH keys with GitLab CI/CD](../../../ci/ssh_keys/index.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ You can create a merge request by running Git commands on your local machine.
|
|||
git commit -m "My commit message"
|
||||
```
|
||||
|
||||
1. [Push your branch and its commits to GitLab](../../../gitlab-basics/start-using-git.md#send-changes-to-gitlab):
|
||||
1. Push your branch and its commits to GitLab:
|
||||
|
||||
```shell
|
||||
git push origin my-new-branch
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ To update your fork from the command line, first ensure that you have configured
|
|||
an `upstream` remote repository for your fork:
|
||||
|
||||
1. Clone your fork locally, if you have not already done so. For more information, see
|
||||
[Clone a repository](../../../gitlab-basics/start-using-git.md#clone-a-repository).
|
||||
[Cloning Git repositories](../../../topics/git/get_started.md#cloning-git-repositories).
|
||||
1. View the remotes configured for your fork:
|
||||
|
||||
```shell
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ to a branch in the repository. When you use the command line, you can commit mul
|
|||
|
||||
## Clone a repository
|
||||
|
||||
You can [clone a repository by using the command line](../../../gitlab-basics/start-using-git.md#clone-a-repository).
|
||||
You can [clone a repository by using the command line](../../../topics/git/get_started.md#cloning-git-repositories).
|
||||
|
||||
Alternatively, you can clone directly into a code editor.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Keeps
|
|||
# ```
|
||||
class QuarantineFlakyTests < ::Gitlab::Housekeeper::Keep
|
||||
MINIMUM_FLAKINESS_OCCURENCES = 1000
|
||||
FLAKY_TEST_ISSUES_URL = "https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab/issues/?order_by=updated_at&state=opened&labels%5B%5D=test&labels%5B%5D=failure%3A%3Aflaky-test¬%5Blabels%5D%5B%5D=QA¬%5Blabel_name%5D%5B%5D=quarantine&per_page=10"
|
||||
FLAKY_TEST_ISSUES_URL = "https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab/issues/?order_by=updated_at&state=opened&labels%5B%5D=test&labels%5B%5D=failure%3A%3Aflaky-test¬%5Blabels%5D%5B%5D=QA¬%5Blabel_name%5D%5B%5D=quarantine&per_page=100"
|
||||
FLAKY_TEST_ISSUE_NOTES_URL = "https://gitlab.com/api/v4/projects/gitlab-org%%2Fgitlab/issues/%<issue_iid>s/notes"
|
||||
EXAMPLE_LINE_REGEX = /([\w'",])? do$/
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ module Keeps
|
|||
- accept the merge request and schedule to improve the test
|
||||
- close the merge request in favor of another merge request to delete the test
|
||||
|
||||
Related to #{flaky_issue['web_url']}.
|
||||
Related to ##{flaky_issue['iid']}.
|
||||
MARKDOWN
|
||||
|
||||
group_label = flaky_issue['labels'].grep(/group::/).first
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ module ContainerRegistry
|
|||
end
|
||||
|
||||
# https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/gitlab/api.md#list-repository-tags
|
||||
def tags(path, page_size: 100, last: nil, before: nil, name: nil, sort: nil, referrers: nil)
|
||||
def tags(path, page_size: 100, last: nil, before: nil, name: nil, sort: nil, referrers: nil, referrer_type: nil)
|
||||
limited_page_size = [page_size, MAX_TAGS_PAGE_SIZE].min
|
||||
with_token_faraday do |faraday_client|
|
||||
url = "#{GITLAB_REPOSITORIES_PATH}/#{path}/tags/list/"
|
||||
|
|
@ -183,6 +183,7 @@ module ContainerRegistry
|
|||
req.params['name'] = name if name.present?
|
||||
req.params['sort'] = sort if sort
|
||||
req.params['referrers'] = 'true' if referrers
|
||||
req.params['referrer_type'] = referrer_type if referrer_type
|
||||
end
|
||||
|
||||
unless response.success?
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Gitlab
|
|||
DEFAULT_FEATURE_CATEGORY = :database
|
||||
|
||||
class << self
|
||||
def generic_instance(batch_table:, batch_column:, job_arguments: [], connection:)
|
||||
def generic_instance(batch_table:, batch_column:, connection:, job_arguments: [])
|
||||
new(
|
||||
batch_table: batch_table, batch_column: batch_column,
|
||||
job_arguments: job_arguments, connection: connection,
|
||||
|
|
@ -62,7 +62,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def initialize(
|
||||
start_id:, end_id:, batch_table:, batch_column:, sub_batch_size:, pause_ms:, job_arguments: [], connection:,
|
||||
start_id:, end_id:, batch_table:, batch_column:, sub_batch_size:, pause_ms:, connection:, job_arguments: [],
|
||||
sub_batch_exception: nil
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Gitlab
|
|||
|
||||
attr_reader :start_time, :header, :log, :timeout
|
||||
|
||||
def initialize(start_time: Time.now, log: [], header: "", timeout:)
|
||||
def initialize(timeout:, start_time: Time.now, log: [], header: "")
|
||||
@start_time = start_time
|
||||
@timeout = timeout
|
||||
@header = header
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ module Gitlab
|
|||
|
||||
delegate :file_path, :start_line, :end_line, to: :location
|
||||
|
||||
def initialize(identifiers:, flags: [], links: [], remediations: [], location:, evidence:, metadata_version:, name:, original_data:, report_type:, scanner:, scan:, uuid:, confidence: nil, severity: nil, details: {}, signatures: [], project_id: nil, vulnerability_finding_signatures_enabled: false, found_by_pipeline: nil, cvss: []) # rubocop:disable Metrics/ParameterLists
|
||||
def initialize(identifiers:, location:, evidence:, metadata_version:, name:, original_data:, report_type:, scanner:, scan:, uuid:, flags: [], links: [], remediations: [], confidence: nil, severity: nil, details: {}, signatures: [], project_id: nil, vulnerability_finding_signatures_enabled: false, found_by_pipeline: nil, cvss: []) # rubocop:disable Metrics/ParameterLists -- TODO: Reduce number of parameters in this function
|
||||
@confidence = confidence
|
||||
@identifiers = identifiers
|
||||
@flags = flags
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module Gitlab
|
|||
|
||||
attr_reader :logger, :cut_off_date, :revocation_time, :group
|
||||
|
||||
def initialize(cut_off_date: DEFAULT_TIME_PERIOD.ago.beginning_of_day, logger: nil, group_full_path:)
|
||||
def initialize(group_full_path:, cut_off_date: DEFAULT_TIME_PERIOD.ago.beginning_of_day, logger: nil)
|
||||
@cut_off_date = cut_off_date
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ module Gitlab
|
|||
[min_date, max_date]
|
||||
end
|
||||
|
||||
def partition_for(lower_bound: nil, upper_bound:)
|
||||
def partition_for(upper_bound:, lower_bound: nil)
|
||||
TimePartition.new(table_name, lower_bound, upper_bound)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ module Gitlab
|
|||
[10.seconds, 10.minutes]
|
||||
].freeze
|
||||
|
||||
def initialize(logger: NULL_LOGGER, allow_savepoints: true, timing_configuration: DEFAULT_TIMING_CONFIGURATION, klass: nil, env: ENV, connection:)
|
||||
def initialize(connection:, logger: NULL_LOGGER, allow_savepoints: true, timing_configuration: DEFAULT_TIMING_CONFIGURATION, klass: nil, env: ENV)
|
||||
@logger = logger
|
||||
@klass = klass
|
||||
@allow_savepoints = allow_savepoints
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Gitlab
|
|||
attr_reader :start_sha
|
||||
attr_reader :head_sha
|
||||
|
||||
def initialize(base_sha:, start_sha: base_sha, head_sha:)
|
||||
def initialize(base_sha:, head_sha:, start_sha: base_sha)
|
||||
@base_sha = base_sha
|
||||
@start_sha = start_sha
|
||||
@head_sha = head_sha
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module Gitlab
|
|||
# The `ca_certs` parameter, if provided, is an array of CA certificates
|
||||
# that will be attached in the signature together with the main `cert`.
|
||||
# This will be typically intermediate CAs
|
||||
def self.sign(cert:, key:, ca_certs: nil, data:)
|
||||
def self.sign(cert:, key:, data:, ca_certs: nil)
|
||||
signed_data = OpenSSL::PKCS7.sign(cert, key, data, Array.wrap(ca_certs), OpenSSL::PKCS7::DETACHED)
|
||||
OpenSSL::PKCS7.write_smime(signed_data)
|
||||
end
|
||||
|
|
@ -21,7 +21,7 @@ module Gitlab
|
|||
# in the array by creating a trusted store, stopping validation at the first match
|
||||
# This is relevant when using intermediate CAs, `ca_certs` should only
|
||||
# include the trusted, root CA
|
||||
def self.verify_signature(ca_certs: nil, signed_data:)
|
||||
def self.verify_signature(signed_data:, ca_certs: nil)
|
||||
store = OpenSSL::X509::Store.new
|
||||
store.set_default_paths
|
||||
Array.wrap(ca_certs).compact.each { |ca_cert| store.add_cert(ca_cert) }
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ module Gitlab
|
|||
set_skip_transaction_check_flag(previous_skip_transaction_check)
|
||||
end
|
||||
|
||||
def initialize(key, uuid: nil, timeout:)
|
||||
def initialize(key, timeout:, uuid: nil)
|
||||
@redis_shared_state_key = self.class.redis_shared_state_key(key)
|
||||
@timeout = timeout
|
||||
@uuid = uuid || SecureRandom.uuid
|
||||
|
|
|
|||
|
|
@ -15,18 +15,20 @@ module Gitlab
|
|||
|
||||
user_id = author_id(issue_event)
|
||||
note_body = cross_reference_note_content(mentioned_in_record.gfm_reference(project))
|
||||
track_activity(mentioned_in_record_class, user_id)
|
||||
create_note(issue_event, note_body, user_id)
|
||||
|
||||
note = create_note(issue_event, note_body, user_id)
|
||||
|
||||
track_activity(mentioned_in_record_class, note.author)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_activity(mentioned_in_class, user_id)
|
||||
def track_activity(mentioned_in_class, author)
|
||||
return if mentioned_in_class != Issue
|
||||
|
||||
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
|
||||
Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CROSS_REFERENCED,
|
||||
values: user_id
|
||||
Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_cross_referenced_action(
|
||||
author: author,
|
||||
project: project
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ module Gitlab
|
|||
def find
|
||||
BatchLoader::GraphQL.for(full_path).batch(key: model_class) do |full_paths, loader, args|
|
||||
scope = args[:key]
|
||||
# this logic cannot be placed in the NamespaceResolver due to N+1
|
||||
scope = scope.without_project_namespaces if scope == Namespace
|
||||
scope = scope.where_full_path_in(full_paths)
|
||||
scope = if scope == Namespace
|
||||
scope.id_in(Route.by_paths(full_paths).select(:namespace_id)).with_route
|
||||
else
|
||||
scope.where_full_path_in(full_paths)
|
||||
end
|
||||
|
||||
scope.each do |model_instance|
|
||||
loader.call(model_instance.full_path.downcase, model_instance)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module Gitlab
|
|||
module MergeRequests
|
||||
module Mergeability
|
||||
class ResultsStore
|
||||
def initialize(interface: RedisInterface.new, merge_request:)
|
||||
def initialize(merge_request:, interface: RedisInterface.new)
|
||||
@interface = interface
|
||||
@merge_request = merge_request
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,10 +10,6 @@ module Gitlab
|
|||
REDIS_SLOT = 'hll_counters'
|
||||
KEY_OVERRIDES_PATH = Rails.root.join('lib/gitlab/usage_data_counters/hll_redis_key_overrides.yml')
|
||||
LEGACY_EVENTS_PATH = Rails.root.join('lib/gitlab/usage_data_counters/hll_redis_legacy_events.yml')
|
||||
# To be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/439982
|
||||
HALF_MIGRATED_EVENTS = %w[
|
||||
g_project_management_issue_cross_referenced
|
||||
].freeze
|
||||
|
||||
EventError = Class.new(StandardError)
|
||||
UnknownEvent = Class.new(EventError)
|
||||
|
|
@ -159,7 +155,7 @@ module Gitlab
|
|||
"When an event gets migrated to Internal Events, its name needs to be removed " \
|
||||
"from hll_redis_legacy_events.yml and added to hll_redis_key_overrides.yml: #{link}"
|
||||
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(UnfinishedEventMigrationError.new(message), event_name: event_name)
|
||||
elsif !property_name && legacy_events.exclude?(event_name) && HALF_MIGRATED_EVENTS.exclude?(event_name)
|
||||
elsif !property_name && legacy_events.exclude?(event_name)
|
||||
message = "Event #{event_name} has been invoked with no property_name.\n" \
|
||||
"When a new non-internal event gets created, its name needs to be added " \
|
||||
"to the hll_redis_legacy_events.yml file."
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module MicrosoftTeams
|
|||
|
||||
private
|
||||
|
||||
def body(title: nil, summary: nil, attachments: nil, activity:)
|
||||
def body(activity:, title: nil, summary: nil, attachments: nil)
|
||||
result = { 'sections' => [] }
|
||||
|
||||
result['title'] = title
|
||||
|
|
|
|||
|
|
@ -5101,12 +5101,18 @@ msgstr ""
|
|||
msgid "Allow possible spam"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow pre-receive secret detection"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow project maintainers to configure repository mirroring"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow projects and subgroups to override the group setting"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow projects to enable pre-receive detection. This does not enable pre-receive secret detection. When you enable this feature, you accept the %{link_start}GitLab Testing Agreement%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow public access to pipelines and job details, including output logs and artifacts."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7888,6 +7894,9 @@ msgstr ""
|
|||
msgid "BetaBadge|A Beta feature:"
|
||||
msgstr ""
|
||||
|
||||
msgid "BetaBadge|A Beta feature: "
|
||||
msgstr ""
|
||||
|
||||
msgid "BetaBadge|Beta"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7906,6 +7915,9 @@ msgstr ""
|
|||
msgid "BetaBadge|What's Beta?"
|
||||
msgstr ""
|
||||
|
||||
msgid "BetaBadge|What's a Beta?"
|
||||
msgstr ""
|
||||
|
||||
msgid "BeyondIdentityService|API Token. User must have access to `git-commit-signing` endpoint."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13591,9 +13603,6 @@ msgstr ""
|
|||
msgid "Configure repository storage."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure secret detection behavior for all projects in your GitLab instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure settings for Advanced Search with Elasticsearch."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -15253,6 +15262,9 @@ msgstr ""
|
|||
msgid "CreateValueStreamForm|New stage"
|
||||
msgstr ""
|
||||
|
||||
msgid "CreateValueStreamForm|New value stream"
|
||||
msgstr ""
|
||||
|
||||
msgid "CreateValueStreamForm|Plan stage start"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -19515,9 +19527,6 @@ msgstr ""
|
|||
msgid "Enable or disable version check and Service Ping."
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable pre-receive secret detection"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable rate limiting for requests to the specified paths"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -30635,6 +30644,9 @@ msgstr ""
|
|||
msgid "Manage rules"
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage secret detection behavior for all projects in your GitLab instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "Manage two-factor authentication"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -32305,9 +32317,6 @@ msgstr ""
|
|||
msgid "Minimal Access"
|
||||
msgstr ""
|
||||
|
||||
msgid "Minimize the risk of secrets from being committed to any repository in this GitLab instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -38433,6 +38442,9 @@ msgstr ""
|
|||
msgid "Prevent project forking outside current group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Prevent secrets such as keys and API tokens from being committed to any repository in this GitLab instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "Prevent users from changing their profile name"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -46107,6 +46119,9 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|Pipeline execution"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Pipeline execution policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Please remove duplicated values"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -46167,9 +46182,15 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|Run %{scannerStart}%{scanner}%{scannerEnd} with the following options:"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Run a CI Yaml file from project: demo-project with ref: 123 File path: group-name/project-name/file-name"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Run a DAST scan with Scan Profile A and Site Profile A when a pipeline run against the main branch."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Run a customized CI Yaml file."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Save changes"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module QA
|
|||
module Page
|
||||
module MergeRequest
|
||||
class Index < Page::Base
|
||||
view 'app/views/shared/empty_states/_empty_merge_requests_without_filters.html.haml' do
|
||||
view 'app/views/shared/empty_states/_merge_requests_without_filters.html.haml' do
|
||||
element 'new-merge-request-button'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'capybara/dsl'
|
||||
|
||||
module QA
|
||||
module Vendor
|
||||
module Jira
|
||||
class JiraIssuePage < JiraAPI
|
||||
include Capybara::DSL
|
||||
include Scenario::Actable
|
||||
|
||||
def login(username, password)
|
||||
QA::Runtime::Logger.debug("Logging into JIRA with username: #{username} and password:#{password}")
|
||||
|
||||
fill_in 'login-form-username', with: username
|
||||
fill_in 'login-form-password', with: password
|
||||
click_on 'login-form-submit'
|
||||
end
|
||||
|
||||
def go_to_login_page
|
||||
click_on 'log in'
|
||||
end
|
||||
|
||||
def login_if_required(username, password)
|
||||
return unless login_required?
|
||||
|
||||
go_to_login_page
|
||||
login(username, password)
|
||||
end
|
||||
|
||||
def summary_field
|
||||
page.find('#summary').value
|
||||
end
|
||||
|
||||
def issue_description
|
||||
page.find('#description', visible: false).value
|
||||
end
|
||||
|
||||
def login_required?
|
||||
login_required = page.has_text?('You are not logged in')
|
||||
QA::Runtime::Logger.debug("login_required: #{login_required}")
|
||||
login_required
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@ describe('CsvImportExportButtons', () => {
|
|||
const exportCsvPath = '/gitlab-org/gitlab-test/-/issues/export_csv';
|
||||
const issuableCount = 10;
|
||||
|
||||
function createComponent(injectedProperties = {}) {
|
||||
function createComponent(injectedProperties = {}, props = {}) {
|
||||
glModalDirective = jest.fn();
|
||||
return mountExtended(CsvImportExportButtons, {
|
||||
directives: {
|
||||
|
|
@ -28,6 +28,7 @@ describe('CsvImportExportButtons', () => {
|
|||
propsData: {
|
||||
exportCsvPath,
|
||||
issuableCount,
|
||||
...props,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -140,5 +141,62 @@ describe('CsvImportExportButtons', () => {
|
|||
expect(findImportCsvModal().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tracking', () => {
|
||||
const experimentTracking = { 'data-track-experiment': 'issues_mrs_empty_state' };
|
||||
|
||||
const importCsvTracking = {
|
||||
'data-track-action': 'click_import_csv_project_issues_empty_list_page',
|
||||
'data-track-label': 'import_csv_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const importJiraTracking = {
|
||||
'data-track-action': 'click_import_jira_project_issues_empty_list_page',
|
||||
'data-track-label': 'import_jira_project_issues_empty_list',
|
||||
};
|
||||
|
||||
describe('when the trackImportClick=true', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent(
|
||||
{ showImportButton: true, canEdit: true },
|
||||
{ trackImportClick: true },
|
||||
);
|
||||
});
|
||||
|
||||
it('tracks import CSV button', () => {
|
||||
expect(findImportCsvButton().attributes()).toMatchObject({
|
||||
...importCsvTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks import Jira link', () => {
|
||||
expect(findImportFromJiraLink().attributes()).toMatchObject({
|
||||
...importJiraTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the trackImportClick=false', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({ showImportButton: true, canEdit: true });
|
||||
});
|
||||
|
||||
it('does not track import CSV button', () => {
|
||||
expect(findImportCsvButton().attributes()).not.toMatchObject({
|
||||
...importCsvTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not track import Jira link', () => {
|
||||
expect(findImportFromJiraLink().attributes()).not.toMatchObject({
|
||||
...importJiraTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ describe('EmptyStateWithoutAnyIssuesExperiment component', () => {
|
|||
const findIssuableByEmail = () => wrapper.findComponent(IssuableByEmail);
|
||||
const findCsvImportButton = () => wrapper.findByTestId('empty-state-import-csv-btn');
|
||||
const findImportFromJiraButton = () => wrapper.findByTestId('empty-state-import-jira-btn');
|
||||
const findLearnMoreLink = () => wrapper.findByTestId('empty-state-learn-more-link');
|
||||
const findJiraIntLink = () => wrapper.findByTestId('empty-state-jira-int-link');
|
||||
|
||||
const mountComponent = ({ props = {}, provide = {} } = {}) => {
|
||||
wrapper = mountExtended(EmptyStateWithoutAnyIssuesExperiment, {
|
||||
|
|
@ -156,4 +158,84 @@ describe('EmptyStateWithoutAnyIssuesExperiment component', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tracking', () => {
|
||||
const experimentTracking = { 'data-track-experiment': 'issues_mrs_empty_state' };
|
||||
|
||||
const newIssueButtonTracking = {
|
||||
'data-track-action': 'click_new_issue_project_issues_empty_list_page',
|
||||
'data-track-label': 'new_issue_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const issuableByEmailTracking = {
|
||||
'data-track-action': 'click_email_issue_project_issues_empty_list_page',
|
||||
'data-track-label': 'email_issue_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const importCsvTracking = {
|
||||
'data-track-action': 'click_import_csv_project_issues_empty_list_page',
|
||||
'data-track-label': 'import_csv_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const importJiraTracking = {
|
||||
'data-track-action': 'click_import_jira_project_issues_empty_list_page',
|
||||
'data-track-label': 'import_jira_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const learnMoreLinkTracking = {
|
||||
'data-track-action': 'click_learn_more_project_issues_empty_list_page',
|
||||
'data-track-label': 'learn_more_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const jiraIntLinkTracking = {
|
||||
'data-track-action': 'click_jira_int_project_issues_empty_list_page',
|
||||
'data-track-label': 'jira_int_project_issues_empty_list',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('tracks new issue button', () => {
|
||||
expect(findNewIssueButton().attributes()).toMatchObject({
|
||||
...newIssueButtonTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks IssuableByEmail', () => {
|
||||
expect(findIssuableByEmail().attributes()).toMatchObject({
|
||||
...issuableByEmailTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks import CSV button', () => {
|
||||
expect(findCsvImportButton().attributes()).toMatchObject({
|
||||
...importCsvTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks import Jira button', () => {
|
||||
expect(findImportFromJiraButton().attributes()).toMatchObject({
|
||||
...importJiraTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks learn more link', () => {
|
||||
expect(findLearnMoreLink().attributes()).toMatchObject({
|
||||
...learnMoreLinkTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks Jira integration link', () => {
|
||||
expect(findJiraIntLink().attributes()).toMatchObject({
|
||||
...jiraIntLinkTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ describe('EmptyStateWithoutAnyIssues component', () => {
|
|||
showNewIssueLink: false,
|
||||
signInPath: 'sign/in/path',
|
||||
groupId: '',
|
||||
isProject: false,
|
||||
};
|
||||
|
||||
const findSignedInEmptyStateBlock = () => wrapper.findByTestId('signed-in-empty-state-block');
|
||||
const findCsvImportExportButtons = () => wrapper.findComponent(CsvImportExportButtons);
|
||||
const findCsvImportExportDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
|
||||
const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
|
|
@ -177,6 +179,89 @@ describe('EmptyStateWithoutAnyIssues component', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tracking', () => {
|
||||
const experimentTracking = { 'data-track-experiment': 'issues_mrs_empty_state' };
|
||||
|
||||
const emptyStateBlockTracking = {
|
||||
'data-track-action': 'render_project_issues_empty_list_page',
|
||||
'data-track-label': 'project_issues_empty_list',
|
||||
};
|
||||
|
||||
const issueHelpLinkTracking = {
|
||||
'data-track-action': 'click_learn_more_project_issues_empty_list_page',
|
||||
'data-track-label': 'learn_more_project_issues_empty_list',
|
||||
};
|
||||
|
||||
const jiraDocsLinkTracking = {
|
||||
'data-track-action': 'click_jira_int_project_issues_empty_list_page',
|
||||
'data-track-label': 'jira_int_project_issues_empty_list',
|
||||
};
|
||||
|
||||
it('tracks new issue link', () => {
|
||||
mountComponent({ provide: { showNewIssueLink: true } });
|
||||
|
||||
expect(findNewIssueLink().attributes()).toMatchObject({
|
||||
'data-track-action': 'click_new_issue_project_issues_empty_list_page',
|
||||
'data-track-label': 'new_issue_project_issues_empty_list',
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the isProject=true', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ provide: { isProject: true } });
|
||||
});
|
||||
|
||||
it('tracks empty state block', () => {
|
||||
expect(findSignedInEmptyStateBlock().attributes()).toMatchObject({
|
||||
...emptyStateBlockTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks issue help link', () => {
|
||||
expect(findIssuesHelpPageLink().attributes()).toMatchObject({
|
||||
...issueHelpLinkTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('tracks Jira docs link', () => {
|
||||
expect(findJiraDocsLink().attributes()).toMatchObject({
|
||||
...jiraDocsLinkTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the isProject=false', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('does not track empty state block', () => {
|
||||
expect(findSignedInEmptyStateBlock().attributes()).not.toMatchObject({
|
||||
...emptyStateBlockTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not track issue help link', () => {
|
||||
expect(findIssuesHelpPageLink().attributes()).not.toMatchObject({
|
||||
...issueHelpLinkTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not track Jira docs link', () => {
|
||||
expect(findJiraDocsLink().attributes()).not.toMatchObject({
|
||||
...jiraDocsLinkTracking,
|
||||
...experimentTracking,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Jira section', () => {
|
||||
|
|
|
|||
|
|
@ -563,6 +563,16 @@ describe('CE IssuesListApp component', () => {
|
|||
},
|
||||
);
|
||||
|
||||
it('tracks IssuableByEmail', () => {
|
||||
wrapper = mountComponent({ provide: { initialEmail: true, canCreateIssue: true } });
|
||||
|
||||
expect(findIssuableByEmail().attributes()).toMatchObject({
|
||||
'data-track-action': 'click_email_issue_project_issues_empty_list_page',
|
||||
'data-track-label': 'email_issue_project_issues_empty_list',
|
||||
'data-track-experiment': 'issues_mrs_empty_state',
|
||||
});
|
||||
});
|
||||
|
||||
describe('when issues_mrs_empty_state candidate experiment', () => {
|
||||
beforeEach(() => {
|
||||
stubExperiments({ issues_mrs_empty_state: 'candidate' });
|
||||
|
|
|
|||
|
|
@ -83,16 +83,16 @@ RSpec.describe Resolvers::ContainerRepositoryTagsResolver, feature_category: :co
|
|||
context 'with parameters' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:before, :after, :sort, :name, :first, :last, :sort_value, :referrers) do
|
||||
nil | nil | 'NAME_DESC' | '' | 10 | nil | '-name' | nil
|
||||
'bb' | nil | 'NAME_ASC' | 'a' | nil | 5 | 'name' | false
|
||||
nil | 'aa' | 'NAME_DESC' | 'a' | 10 | nil | '-name' | true
|
||||
where(:before, :after, :sort, :name, :first, :last, :sort_value, :referrers, :referrer_type) do
|
||||
nil | nil | 'NAME_DESC' | '' | 10 | nil | '-name' | nil | nil
|
||||
'bb' | nil | 'NAME_ASC' | 'a' | nil | 5 | 'name' | false | nil
|
||||
nil | 'aa' | 'NAME_DESC' | 'a' | 10 | nil | '-name' | true | 'application/example'
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:args) do
|
||||
{ before: before, after: after, sort: sort, name: name,
|
||||
first: first, last: last, referrers: referrers }.compact
|
||||
{ before: before, after: after, sort: sort, name: name, first: first,
|
||||
last: last, referrers: referrers, referrer_type: referrer_type }.compact
|
||||
end
|
||||
|
||||
it 'calls ContainerRepository#tags_page with correct parameters' do
|
||||
|
|
@ -102,7 +102,8 @@ RSpec.describe Resolvers::ContainerRepositoryTagsResolver, feature_category: :co
|
|||
sort: sort_value,
|
||||
name: name,
|
||||
page_size: [first, last].map(&:to_i).max,
|
||||
referrers: referrers
|
||||
referrers: referrers,
|
||||
referrer_type: referrer_type
|
||||
)
|
||||
|
||||
resolver(args)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['Namespace'] do
|
|||
expected_fields = %w[
|
||||
id name path full_name full_path description description_html visibility
|
||||
lfs_enabled request_access_enabled projects root_storage_statistics shared_runners_setting
|
||||
timelog_categories achievements
|
||||
timelog_categories achievements work_item
|
||||
]
|
||||
|
||||
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter, feature_categ
|
|||
reference_filter(markdown)
|
||||
end
|
||||
|
||||
expect(control.count).to eq 2
|
||||
expect(control.count).to eq 1
|
||||
|
||||
markdown = "#{normal_project_reference} #{invalidate_reference(normal_project_reference)} #{group_project_reference} #{nested_project_reference}"
|
||||
|
||||
|
|
|
|||
|
|
@ -268,8 +268,6 @@ RSpec.describe ContainerRegistry::GitlabApiClient, feature_category: :container_
|
|||
end
|
||||
|
||||
context 'with referrers included' do
|
||||
subject { client.tags(path, page_size: page_size, referrers: true) }
|
||||
|
||||
let(:expected) do
|
||||
{
|
||||
pagination: {},
|
||||
|
|
@ -277,8 +275,12 @@ RSpec.describe ContainerRegistry::GitlabApiClient, feature_category: :container_
|
|||
}
|
||||
end
|
||||
|
||||
let(:input) { { referrers: 'true', referrer_type: 'application/vnd.example%2Btype' } }
|
||||
|
||||
subject { client.tags(path, page_size: page_size, **input) }
|
||||
|
||||
before do
|
||||
stub_tags(path, page_size: page_size, input: { referrers: 'true' }, respond_with: response)
|
||||
stub_tags(path, page_size: page_size, input: input, respond_with: response)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(expected) }
|
||||
|
|
@ -990,7 +992,8 @@ RSpec.describe ContainerRegistry::GitlabApiClient, feature_category: :container_
|
|||
name: input[:name],
|
||||
sort: input[:sort],
|
||||
before: input[:before],
|
||||
referrers: input[:referrers]
|
||||
referrers: input[:referrers],
|
||||
referrer_type: input[:referrer_type]
|
||||
}.compact
|
||||
|
||||
url = "#{registry_api_url}/gitlab/v1/repositories/#{path}/tags/list/"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_cache do
|
||||
RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_cache, feature_category: :importers do
|
||||
subject(:importer) { described_class.new(project, client) }
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
|
@ -67,6 +67,11 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g
|
|||
expect(issuable.notes[0]).to have_attributes expected_note_attrs
|
||||
expect(issuable.notes[0].system_note_metadata.action).to eq 'cross_reference'
|
||||
end
|
||||
|
||||
it_behaves_like 'internal event tracking' do
|
||||
let(:event) { 'g_project_management_issue_cross_referenced' }
|
||||
let(:subject) { importer.execute(issue_event) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when referenced in pull request' do
|
||||
|
|
@ -92,6 +97,12 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g
|
|||
expect(issuable.notes[0]).to have_attributes expected_note_attrs
|
||||
expect(issuable.notes[0].system_note_metadata.action).to eq 'cross_reference'
|
||||
end
|
||||
|
||||
it_behaves_like 'internal event not tracked' do
|
||||
let(:event) { 'g_project_management_issue_cross_referenced' }
|
||||
|
||||
subject { importer.execute(issue_event) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when referenced in out of project issue/pull_request' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Graphql::Loaders::FullPathModelLoader, feature_category: :shared do
|
||||
include RepoHelpers
|
||||
|
||||
describe '#find' do
|
||||
let_it_be(:group) { create(:group, path: 'test-group') }
|
||||
let_it_be(:project) { create(:project, namespace: group, path: 'test-project') }
|
||||
|
||||
context 'when looking for a group' do
|
||||
it 'finds a group' do
|
||||
result = described_class.new(Group, 'test-group').find
|
||||
expect(result.sync).to eq(group)
|
||||
end
|
||||
|
||||
context 'when passed in path matches a project instead' do
|
||||
it 'returns nothing' do
|
||||
result = described_class.new(Group, 'test-group/test-project').find
|
||||
expect(result.sync).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when looking for a project' do
|
||||
it 'finds a project' do
|
||||
result = described_class.new(Project, 'test-group/test-project').find
|
||||
expect(result.sync).to eq(project)
|
||||
end
|
||||
|
||||
context 'when passed in path matches a group instead' do
|
||||
it 'returns nothing' do
|
||||
result = described_class.new(Project, 'test-group').find
|
||||
expect(result.sync).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when looking for a Namespace' do
|
||||
it 'finds a project' do
|
||||
result = described_class.new(Namespace, 'test-group/test-project').find
|
||||
expect(result.sync).to eq(project.project_namespace)
|
||||
end
|
||||
|
||||
it 'finds a group' do
|
||||
result = described_class.new(Namespace, 'test-group').find
|
||||
expect(result.sync).to eq(group)
|
||||
end
|
||||
end
|
||||
|
||||
it 'only queries once' do
|
||||
expect do
|
||||
[
|
||||
described_class.new(Project, 'test-group/test-project').find,
|
||||
described_class.new(Group, 'test-group').find,
|
||||
described_class.new(Project, 'test-group/test-project').find,
|
||||
described_class.new(Group, 'test-group').find,
|
||||
described_class.new(Project, 'test-group/test-project').find
|
||||
].map(&:sync)
|
||||
end.not_to exceed_query_limit(4) # 1 for project, 1 for group and one to load routes for each
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2437,9 +2437,6 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
|
|||
{ key: 'CI_REPOSITORY_URL', value: build.repo_url, public: false, masked: false },
|
||||
{ key: 'CI_DEPENDENCY_PROXY_USER', value: 'gitlab-ci-token', public: true, masked: false },
|
||||
{ key: 'CI_DEPENDENCY_PROXY_PASSWORD', value: 'my-token', public: false, masked: true },
|
||||
{ key: 'CI_JOB_JWT', value: 'ci.job.jwt', public: false, masked: true },
|
||||
{ key: 'CI_JOB_JWT_V1', value: 'ci.job.jwt', public: false, masked: true },
|
||||
{ key: 'CI_JOB_JWT_V2', value: 'ci.job.jwtv2', public: false, masked: true },
|
||||
{ key: 'CI_JOB_NAME', value: 'test', public: true, masked: false },
|
||||
{ key: 'CI_JOB_NAME_SLUG', value: 'test', public: true, masked: false },
|
||||
{ key: 'CI_JOB_STAGE', value: 'test', public: true, masked: false },
|
||||
|
|
@ -2516,7 +2513,37 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
|
|||
end
|
||||
|
||||
it { is_expected.to be_instance_of(Gitlab::Ci::Variables::Collection) }
|
||||
it { expect(subject.to_runner_variables).to eq(predefined_variables) }
|
||||
|
||||
context 'when feature flag remove_shared_jwts enabled' do
|
||||
it { expect(subject.to_runner_variables).to eq(predefined_variables) }
|
||||
end
|
||||
|
||||
context 'when feature flag remove_shared_jwts disabled' do
|
||||
before do
|
||||
stub_feature_flags(remove_shared_jwts: false)
|
||||
predefined_variables.insert(11,
|
||||
*[{ key: 'CI_JOB_JWT', value: 'ci.job.jwt', public: false, masked: true },
|
||||
{ key: 'CI_JOB_JWT_V1', value: 'ci.job.jwt', public: false, masked: true },
|
||||
{ key: 'CI_JOB_JWT_V2', value: 'ci.job.jwtv2', public: false, masked: true }])
|
||||
end
|
||||
|
||||
it { expect(subject.to_runner_variables).to eq(predefined_variables) }
|
||||
|
||||
context 'when CI_JOB_JWT generation fails' do
|
||||
[
|
||||
OpenSSL::PKey::RSAError,
|
||||
Gitlab::Ci::Jwt::NoSigningKeyError
|
||||
].each do |reason_to_fail|
|
||||
it 'CI_JOB_JWT is not included' do
|
||||
expect(Gitlab::Ci::Jwt).to receive(:for_build).and_raise(reason_to_fail)
|
||||
expect(Gitlab::ErrorTracking).to receive(:track_exception)
|
||||
|
||||
expect { subject }.not_to raise_error
|
||||
expect(subject.pluck(:key)).not_to include('CI_JOB_JWT')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'excludes variables that require an environment or user' do
|
||||
environment_based_variables_collection = subject.filter do |variable|
|
||||
|
|
@ -2529,21 +2556,6 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
|
|||
expect(environment_based_variables_collection).to be_empty
|
||||
end
|
||||
|
||||
context 'when CI_JOB_JWT generation fails' do
|
||||
[
|
||||
OpenSSL::PKey::RSAError,
|
||||
Gitlab::Ci::Jwt::NoSigningKeyError
|
||||
].each do |reason_to_fail|
|
||||
it 'CI_JOB_JWT is not included' do
|
||||
expect(Gitlab::Ci::Jwt).to receive(:for_build).and_raise(reason_to_fail)
|
||||
expect(Gitlab::ErrorTracking).to receive(:track_exception)
|
||||
|
||||
expect { subject }.not_to raise_error
|
||||
expect(subject.pluck(:key)).not_to include('CI_JOB_JWT')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'variables ordering' do
|
||||
context 'when variables hierarchy is stubbed' do
|
||||
let(:build_pre_var) { { key: 'build', value: 'value', public: true, masked: false } }
|
||||
|
|
@ -3198,11 +3210,41 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
|
|||
|
||||
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
|
||||
|
||||
it 'returns static predefined variables' do
|
||||
expect(build.variables.size).to be >= 28
|
||||
expect(build.variables)
|
||||
.to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
|
||||
expect(build).not_to be_persisted
|
||||
context 'when feature flag remove_shared_jwts is enabled' do
|
||||
context 'and id_tokens are not present in the build' do
|
||||
it 'does not return id_token variables' do
|
||||
expect(build.variables)
|
||||
.not_to include(key: 'ID_TOKEN_1', value: 'feature', public: true, masked: false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and id_tokens are present in the build' do
|
||||
before do
|
||||
build.id_tokens = {
|
||||
'ID_TOKEN_1' => { aud: 'developers' },
|
||||
'ID_TOKEN_2' => { aud: 'maintainers' }
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns static predefined variables' do
|
||||
expect(build.variables)
|
||||
.to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
|
||||
expect(build).not_to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature flag remove_shared_jwts is disabled' do
|
||||
before do
|
||||
stub_feature_flags(remove_shared_jwts: false)
|
||||
end
|
||||
|
||||
it 'returns static predefined variables' do
|
||||
expect(build.variables.size).to be >= 28
|
||||
expect(build.variables)
|
||||
.to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
|
||||
expect(build).not_to be_persisted
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -865,9 +865,12 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
|
|||
let_it_be(:last) { 'last' }
|
||||
let_it_be(:sort) { '-name' }
|
||||
let_it_be(:name) { 'repo' }
|
||||
let_it_be(:referrers) { true }
|
||||
let_it_be(:referrer_type) { 'application/example' }
|
||||
|
||||
subject do
|
||||
repository.tags_page(before: before, last: last, sort: sort, name: name, page_size: page_size)
|
||||
repository.tags_page(before: before, last: last, sort: sort, name: name, page_size: page_size,
|
||||
referrers: referrers, referrer_type: referrer_type)
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
@ -877,7 +880,8 @@ RSpec.describe ContainerRepository, :aggregate_failures, feature_category: :cont
|
|||
it 'calls GitlabApiClient#tags and passes parameters' do
|
||||
allow(repository.gitlab_api_client).to receive(:tags).and_return({})
|
||||
expect(repository.gitlab_api_client).to receive(:tags).with(
|
||||
repository.path, page_size: page_size, before: before, last: last, sort: sort, name: name, referrers: nil)
|
||||
repository.path, page_size: page_size, before: before, last: last, sort: sort, name: name,
|
||||
referrers: referrers, referrer_type: referrer_type)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9444,4 +9444,25 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.by_project_namespace' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let(:project_namespace) { project.project_namespace }
|
||||
|
||||
it 'returns project' do
|
||||
expect(described_class.by_project_namespace(project_namespace)).to match_array([project])
|
||||
end
|
||||
|
||||
context 'when using ID' do
|
||||
it 'returns project' do
|
||||
expect(described_class.by_project_namespace(project_namespace.id)).to match_array([project])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when using non-existent-id' do
|
||||
it 'returns nothing' do
|
||||
expect(described_class.by_project_namespace(non_existing_record_id)).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,14 +59,38 @@ RSpec.describe Route do
|
|||
end
|
||||
|
||||
describe '.for_routable_type' do
|
||||
let!(:nested_group) { create(:group, path: 'foo', name: 'foo', parent: group) }
|
||||
let!(:project) { create(:project, path: 'other-project') }
|
||||
let_it_be(:group) { create(:group, path: 'git_lab', name: 'git_lab') }
|
||||
let_it_be(:nested_group) { create(:group, path: 'foo', name: 'foo', parent: group) }
|
||||
let_it_be(:project) { create(:project, path: 'other-project') }
|
||||
|
||||
it 'returns correct routes' do
|
||||
expect(described_class.for_routable_type(Project.name)).to match_array([project.route])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.by_paths' do
|
||||
let!(:nested_group) { create(:group, path: 'foo', name: 'foo', parent: group) }
|
||||
let!(:project) { create(:project, path: 'other-project', namespace: group) }
|
||||
|
||||
it 'returns correct routes' do
|
||||
expect(described_class.by_paths(%w[git_lab/foo git_lab/other-project])).to match_array(
|
||||
[nested_group.route, project.route]
|
||||
)
|
||||
end
|
||||
|
||||
context 'with all mismatched paths' do
|
||||
it 'returns no routes' do
|
||||
expect(described_class.by_paths(%w[foo other-project])).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'with some mismatched paths' do
|
||||
it 'returns no routes' do
|
||||
expect(described_class.by_paths(%w[foo git_lab/other-project])).to match_array([project.route])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#rename_descendants' do
|
||||
let!(:nested_group) { create(:group, path: 'test', name: 'test', parent: group) }
|
||||
let!(:deep_nested_group) { create(:group, path: 'foo', name: 'foo', parent: nested_group) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,13 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Namespaces::ProjectNamespacePolicy do
|
||||
RSpec.describe Namespaces::ProjectNamespacePolicy, feature_category: :groups_and_projects do
|
||||
include ExternalAuthorizationServiceHelpers
|
||||
include AdminModeHelper
|
||||
|
||||
let_it_be(:public_project) { create(:project, :public) }
|
||||
let_it_be(:private_project) { create(:project, :private) }
|
||||
|
||||
subject { described_class.new(current_user, namespace) }
|
||||
|
||||
it_behaves_like 'checks timelog categories permissions' do
|
||||
|
|
@ -10,4 +16,139 @@ RSpec.describe Namespaces::ProjectNamespacePolicy do
|
|||
let(:namespace) { project.project_namespace }
|
||||
let(:users_container) { project }
|
||||
end
|
||||
|
||||
context 'with read_namespace permissions' do
|
||||
let(:project) { public_project }
|
||||
let(:owner) { project.creator }
|
||||
let(:developer) { create(:user) }
|
||||
let(:admin) { create(:admin) }
|
||||
let(:namespace) { project.project_namespace }
|
||||
|
||||
before do
|
||||
project.add_developer(developer)
|
||||
end
|
||||
|
||||
it 'allows access when a user has read access to the project' do
|
||||
expect(described_class.new(owner, project.project_namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
expect(described_class.new(developer, project.project_namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
expect(described_class.new(admin, project.project_namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
end
|
||||
|
||||
it 'never checks the external service' do
|
||||
expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?)
|
||||
|
||||
expect(described_class.new(owner, namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
end
|
||||
|
||||
context 'with an external authorization service' do
|
||||
before do
|
||||
enable_external_authorization_service_check
|
||||
end
|
||||
|
||||
it 'allows access when the external service allows it' do
|
||||
external_service_allow_access(owner, project)
|
||||
external_service_allow_access(developer, project)
|
||||
|
||||
expect(described_class.new(owner, namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
expect(described_class.new(developer, namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
end
|
||||
|
||||
context 'with an admin' do
|
||||
context 'when admin mode is enabled', :enable_admin_mode do
|
||||
it 'does not check the external service and allows access' do
|
||||
expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?)
|
||||
|
||||
expect(described_class.new(admin, namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when admin mode is disabled' do
|
||||
it 'checks the external service and allows access' do
|
||||
external_service_allow_access(admin, project)
|
||||
|
||||
expect(::Gitlab::ExternalAuthorization).to receive(:access_allowed?)
|
||||
|
||||
expect(described_class.new(admin, namespace)).to be_allowed(:read_project, :read_namespace)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'prevents all but seeing a public project in a list when access is denied' do
|
||||
[developer, owner, build(:user), nil].each do |user|
|
||||
external_service_deny_access(user, project)
|
||||
policy = described_class.new(user, namespace)
|
||||
|
||||
expect(policy).not_to be_allowed(:read_project, :read_namespace)
|
||||
end
|
||||
end
|
||||
|
||||
it 'passes the full path to external authorization for logging purposes' do
|
||||
expect(::Gitlab::ExternalAuthorization)
|
||||
.to receive(:access_allowed?).with(owner, 'default_label', project.full_path).and_call_original
|
||||
|
||||
described_class.new(owner, namespace).allowed?(:read_project, :read_namespace)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with support bot user' do
|
||||
let(:current_user) { Users::Internal.support_bot }
|
||||
|
||||
context 'with service desk disabled' do
|
||||
it { expect(described_class.new(current_user, namespace)).not_to be_allowed(:read_project, :read_namespace) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with deploy key access actor' do
|
||||
context 'when project is private' do
|
||||
let(:project) { private_project }
|
||||
let!(:deploy_key) { create(:deploy_key, user: owner) }
|
||||
|
||||
subject { described_class.new(deploy_key, project.project_namespace) }
|
||||
|
||||
context 'when a read deploy key is enabled in the project' do
|
||||
let!(:deploy_keys_project) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) }
|
||||
|
||||
it { is_expected.to be_disallowed(:read_project, :read_namespace) }
|
||||
end
|
||||
|
||||
context 'when a write deploy key is enabled in the project' do
|
||||
let!(:deploy_keys_project) do
|
||||
create(:deploy_keys_project, :write_access, project: project, deploy_key: deploy_key)
|
||||
end
|
||||
|
||||
it { is_expected.to be_disallowed(:read_project, :read_namespace) }
|
||||
end
|
||||
|
||||
context 'when the deploy key is not enabled in the project' do
|
||||
it { is_expected.to be_disallowed(:read_project, :read_namespace) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when project is created and owned by a banned user' do
|
||||
let_it_be(:project) { create(:project, :public) }
|
||||
|
||||
let(:current_user) { developer }
|
||||
|
||||
before do
|
||||
allow(project).to receive(:created_and_owned_by_banned_user?).and_return(true)
|
||||
end
|
||||
|
||||
it { expect_disallowed(:read_project, :read_namespace) }
|
||||
|
||||
context 'when current user is an admin', :enable_admin_mode do
|
||||
let(:current_user) { admin }
|
||||
|
||||
it { expect_allowed(:read_project, :read_namespace) }
|
||||
end
|
||||
|
||||
context 'when hide_projects_of_banned_users FF is disabled' do
|
||||
before do
|
||||
stub_feature_flags(hide_projects_of_banned_users: false)
|
||||
end
|
||||
|
||||
it { expect_allowed(:read_project, :read_namespace) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'getting a single work item associated with a group', feature_category: :team_planning do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:guest) { create(:user).tap { |user| group.add_guest(user) } }
|
||||
let_it_be(:reporter) { create(:user).tap { |user| group.add_reporter(user) } }
|
||||
|
||||
let(:work_item_data) { graphql_data.dig('namespace', 'workItem') }
|
||||
let(:params) { { iid: query_work_item.iid.to_s } }
|
||||
let(:query) do
|
||||
graphql_query_for(
|
||||
'namespace',
|
||||
{ 'fullPath' => full_path },
|
||||
query_graphql_field('workItem', params, all_graphql_fields_for('workItems'.classify, max_depth: 2))
|
||||
)
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'identifies work item at namespace level' do
|
||||
context 'when the user cannot read the work item' do
|
||||
let(:current_user) { guest }
|
||||
let(:query_work_item) { confidential_work_item }
|
||||
|
||||
it 'returns does not return the work item' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(work_item_data).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user can read the work item' do
|
||||
it 'returns the work item' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(work_item_data).to include(
|
||||
'id' => query_work_item.to_gid.to_s,
|
||||
'iid' => query_work_item.iid.to_s
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when namespace is a group' do
|
||||
let_it_be(:group_work_item) { create(:work_item, :group_level, namespace: group, author: reporter) }
|
||||
let_it_be(:confidential_work_item) { create(:work_item, :confidential, namespace: group, author: reporter) }
|
||||
|
||||
let(:query_work_item) { group_work_item }
|
||||
let(:full_path) { group.full_path }
|
||||
let(:current_user) { reporter }
|
||||
|
||||
it_behaves_like 'identifies work item at namespace level'
|
||||
|
||||
context 'when the namespace_level_work_items feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(namespace_level_work_items: false)
|
||||
end
|
||||
|
||||
it 'does not return the work item' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(work_item_data).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when namespace is a project' do
|
||||
let_it_be(:project_work_item) { create(:work_item, project: project, author: reporter) }
|
||||
let_it_be(:confidential_work_item) { create(:work_item, :confidential, project: project, author: reporter) }
|
||||
|
||||
let(:query_work_item) { project_work_item }
|
||||
let(:full_path) { project.full_path }
|
||||
let(:current_user) { reporter }
|
||||
|
||||
it_behaves_like 'identifies work item at namespace level'
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@ RSpec.describe 'Query', feature_category: :groups_and_projects do
|
|||
let_it_be(:group_namespace) { create(:group, :private) }
|
||||
let_it_be(:public_group_namespace) { create(:group, :public) }
|
||||
let_it_be(:user_namespace) { create(:user_namespace, owner: user) }
|
||||
let_it_be(:project_namespace) { create(:project_namespace, parent: group_namespace) }
|
||||
let_it_be(:project) { create(:project, group: group_namespace) }
|
||||
|
||||
describe '.namespace' do
|
||||
subject { post_graphql(query, current_user: current_user) }
|
||||
|
|
@ -106,27 +106,31 @@ RSpec.describe 'Query', feature_category: :groups_and_projects do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'retrieving a namespace' do
|
||||
let(:target_namespace) { group_namespace }
|
||||
context 'when used with a private namespace' do
|
||||
context 'retrieving a group' do
|
||||
it_behaves_like 'retrieving a namespace' do
|
||||
let(:target_namespace) { group_namespace }
|
||||
|
||||
before do
|
||||
group_namespace.add_developer(user)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'retrieving a namespace' do
|
||||
let(:target_namespace) { user_namespace }
|
||||
end
|
||||
|
||||
context 'does not retrieve project namespace' do
|
||||
let(:target_namespace) { project_namespace }
|
||||
|
||||
before do
|
||||
subject
|
||||
before do
|
||||
group_namespace.add_developer(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not retrieve the record' do
|
||||
expect(query_result).to be_nil
|
||||
context 'retrieving a user namespace' do
|
||||
it_behaves_like 'retrieving a namespace' do
|
||||
let(:target_namespace) { user_namespace }
|
||||
end
|
||||
end
|
||||
|
||||
context 'retrieving a project' do
|
||||
it_behaves_like 'retrieving a namespace' do
|
||||
let(:target_namespace) { project }
|
||||
|
||||
before do
|
||||
group_namespace.add_developer(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -241,7 +241,8 @@ RSpec.describe API::ProjectContainerRepositories, feature_category: :container_r
|
|||
last: last_param,
|
||||
name: nil,
|
||||
before: nil,
|
||||
referrers: nil
|
||||
referrers: nil,
|
||||
referrer_type: nil
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ RSpec.shared_examples 'internal event tracking' do
|
|||
],
|
||||
**additional_properties
|
||||
)
|
||||
)
|
||||
).at_least(:once)
|
||||
|
||||
Gitlab::InternalEvents::EventDefinitions.unique_properties(event).each do |property|
|
||||
expect(fake_counter).to have_received(:track_event)
|
||||
|
|
@ -78,3 +78,20 @@ RSpec.shared_examples 'internal event tracking' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Requires a context containing:
|
||||
# - subject
|
||||
# Optionally, the context can contain:
|
||||
# - event
|
||||
|
||||
RSpec.shared_examples 'internal event not tracked' do
|
||||
it 'does not record an internal event' do
|
||||
if defined?(event)
|
||||
expect(Gitlab::InternalEvents).not_to receive(:track_event).with(event, any_args)
|
||||
else
|
||||
expect(Gitlab::InternalEvents).not_to receive(:track_event)
|
||||
end
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue