Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-04-10 00:11:14 +00:00
parent 42be04412b
commit d7f87de3d4
84 changed files with 1257 additions and 489 deletions

View File

@ -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'

View File

@ -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

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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);
}
}
}
}
}

View File

@ -1,3 +1,4 @@
/* stylelint-disable scss/at-rule-no-unknown */
@tailwind base;
@tailwind utilities;

View File

@ -1,5 +1,7 @@
/* stylelint-disable scss/at-rule-no-unknown */
@tailwind base;
.gl-border {
@apply gl-border-gray-100;
@apply gl-border-solid;

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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']))

View File

@ -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

View File

@ -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
)
{

View File

@ -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 })

View File

@ -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) }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
efa4c1150358295bff0560247d55af67f30252f098c039abb203fbe135b0f287

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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).

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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&not%5Blabels%5D%5B%5D=QA&not%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&not%5Blabels%5D%5B%5D=QA&not%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

View File

@ -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?

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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."

View 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

View File

@ -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 ""

View File

@ -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

View File

@ -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

View File

@ -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,
});
});
});
});
});
});

View File

@ -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,
});
});
});
});

View File

@ -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', () => {

View File

@ -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' });

View File

@ -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)

View File

@ -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)

View File

@ -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}"

View File

@ -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/"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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