Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-08-07 09:09:28 +00:00
parent 0a154f21ff
commit 3bf86ff021
30 changed files with 542 additions and 66 deletions

View File

@ -1,7 +1,7 @@
<script>
// eslint-disable-next-line no-restricted-imports
import { mapState } from 'vuex';
import { GlBadge, GlTab, GlTabs } from '@gitlab/ui';
import { GlBadge, GlTab, GlTabs, GlButton, GlModalDirective } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { s__, sprintf } from '~/locale';
import { getParameterByName } from '~/lib/utils/url_utility';
@ -12,6 +12,9 @@ import {
import importSourceUsersQuery from '../graphql/queries/import_source_users.query.graphql';
import PlaceholdersTable from './placeholders_table.vue';
import CsvUploadModal from './csv_upload_modal.vue';
const UPLOAD_CSV_PLACEHOLDERS_MODAL_ID = 'upload-placeholders-csv-modal';
const DEFAULT_PAGE_SIZE = 20;
@ -21,10 +24,14 @@ export default {
GlBadge,
GlTab,
GlTabs,
GlButton,
PlaceholdersTable,
CsvUploadModal,
},
directives: {
GlModal: GlModalDirective,
},
inject: ['group'],
data() {
return {
selectedTabIndex: 0,
@ -36,7 +43,6 @@ export default {
},
};
},
apollo: {
sourceUsers: {
query: importSourceUsersQuery,
@ -58,7 +64,6 @@ export default {
},
},
},
computed: {
...mapState('placeholder', ['pagination']),
isLoading() {
@ -86,7 +91,6 @@ export default {
this.unassignedCount = this.pagination.awaitingReassignmentItems;
this.reassignedCount = this.pagination.reassignedItems;
},
methods: {
onConfirm(item) {
this.$toast.show(
@ -98,14 +102,12 @@ export default {
this.reassignedCount += 1;
this.unassignedCount -= 1;
},
onPrevPage() {
this.cursor = {
before: this.sourceUsers.pageInfo.startCursor,
after: null,
};
},
onNextPage() {
this.cursor = {
after: this.sourceUsers.pageInfo.endCursor,
@ -113,11 +115,12 @@ export default {
};
},
},
uploadCsvModalId: UPLOAD_CSV_PLACEHOLDERS_MODAL_ID,
};
</script>
<template>
<gl-tabs v-model="selectedTabIndex" class="gl-mt-3">
<gl-tabs v-model="selectedTabIndex" nav-class="gl-grow gl-items-center gl-mt-3">
<gl-tab>
<template #title>
<span>{{ s__('UserMapping|Awaiting reassignment') }}</span>
@ -151,5 +154,18 @@ export default {
@next="onNextPage"
/>
</gl-tab>
<template #tabs-end>
<gl-button
v-gl-modal="$options.uploadCsvModalId"
variant="link"
icon="media"
class="gl-ml-auto"
data-testid="reassign-csv-button"
>
{{ s__('UserMapping|Reassign with CSV file') }}
</gl-button>
<csv-upload-modal :modal-id="$options.uploadCsvModalId" />
</template>
</gl-tabs>
</template>

View File

@ -0,0 +1,78 @@
<script>
import { GlModal, GlLink, GlSprintf, GlButton, GlAlert } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { s__, __ } from '~/locale';
export default {
components: {
GlModal,
GlLink,
GlSprintf,
GlButton,
GlAlert,
},
inject: {
reassignmentCsvDownloadPath: {
default: '',
},
},
props: {
modalId: {
type: String,
required: true,
},
},
docsLink: helpPagePath('user/project/import/index', {
anchor: 'request-reassignment-by-using-a-csv-file',
}),
i18n: {
description: s__(
'UserMapping|Use a CSV file to reassign contributions from placeholder users to existing group members. This can be done in a few steps. %{linkStart}Learn more about matching users by CSV%{linkEnd}.',
),
},
primaryAction: {
text: s__('UserMapping|Reassign'),
},
cancelAction: {
text: __('Cancel'),
},
};
</script>
<template>
<gl-modal
:ref="modalId"
:modal-id="modalId"
:title="s__('UserMapping|Reassign with CSV file')"
:action-primary="$options.primaryAction"
:action-cancel="$options.cancelAction"
>
<gl-sprintf :message="$options.i18n.description">
<template #link="{ content }">
<gl-link :href="$options.docsLink" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
<ol class="gl-ml-0 gl-mt-5">
<li>
<gl-button
:href="reassignmentCsvDownloadPath"
variant="link"
icon="download"
data-testid="csv-download-button"
class="vertical-align-text-top"
>{{ s__('UserMapping|Download the pre-filled CSV template.') }}</gl-button
>
</li>
<li>{{ s__('UserMapping|Review and complete filling out the CSV file.') }}</li>
<li>{{ s__('UserMapping|Upload reviewed and completed CSV file.') }}</li>
</ol>
<gl-alert variant="warning" :dismissible="false">
{{
s__(
'UserMapping|Once you select "Reassign", the processing will start and users will receive and email to accept the contribution reassignment. Once a users has accepted the reassignment, it cannot be undone. Check all data is correct before continuing.',
)
}}
</gl-alert>
</gl-modal>
</template>

View File

@ -293,6 +293,7 @@ export default {
} else {
this.unsetError();
this.workItemsToAdd = [];
this.closeForm();
}
})
.catch(() => {
@ -328,6 +329,7 @@ export default {
} else {
this.unsetError();
this.$emit('addChild');
this.closeForm();
}
})
.catch(() => {
@ -340,6 +342,9 @@ export default {
this.submitInProgress = false;
});
},
closeForm() {
this.$emit('cancel');
},
},
i18n: {
titleInputLabel: __('Title'),
@ -446,7 +451,7 @@ export default {
>
{{ addOrCreateButtonLabel }}
</gl-button>
<gl-button category="secondary" size="small" @click="$emit('cancel')">
<gl-button category="secondary" size="small" @click="closeForm">
{{ s__('WorkItem|Cancel') }}
</gl-button>
</gl-form>

View File

@ -6,4 +6,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/472750
milestone: '17.3'
group: group::source code
type: beta
default_enabled: false
default_enabled: true

View File

@ -6,4 +6,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/468669
milestone: '17.2'
group: group::authorization
type: beta
default_enabled: false
default_enabled: true

View File

@ -0,0 +1,9 @@
---
name: autoflow_enabled
feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/12120
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/160947
rollout_issue_url:
milestone: '17.3'
group: group::environments
type: wip
default_enabled: false

View File

@ -52,6 +52,12 @@ Users are considered inactive in LDAP when they:
- Are marked as disabled or deactivated in Active Directory through the user account control attribute. This means attribute
`userAccountControl:1.2.840.113556.1.4.803` has bit 2 set.
To check if a user is active or inactive in LDAP, use the following PowerShell command and the [Active Directory Module](https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps) to check the Active Directory:
```powershell
Get-ADUser -Identity <username> -Properties userAccountControl | Select-Object Name, userAccountControl
```
GitLab checks LDAP users' status:
- When signing in using any authentication provider.

View File

@ -1211,9 +1211,11 @@ than GitLab to prevent XSS attacks.
### Rate limits
> - [Changed](https://gitlab.com/groups/gitlab-org/-/epics/14653) in GitLab 17.3: You can exclude subnets from Pages rate limits.
You can enforce rate limits to help minimize the risk of a Denial of Service (DoS) attack. GitLab Pages
uses a [token bucket algorithm](https://en.wikipedia.org/wiki/Token_bucket) to enforce rate limiting. By default,
requests or TLS connections that exceed the specified limits are reported but not rejected.
requests or TLS connections that exceed the specified limits are reported and rejected.
GitLab Pages supports the following types of rate limiting:
@ -1222,20 +1224,25 @@ GitLab Pages supports the following types of rate limiting:
HTTP request-based rate limits are enforced using the following:
- `rate_limit_source_ip`: Set the maximum threshold in number of requests per client IP per second. Set to 0 to disable this feature.
- `rate_limit_source_ip`: Sets the maximum threshold in number of requests per client IP per second. Set to 0 to disable this feature.
- `rate_limit_source_ip_burst`: Sets the maximum threshold of number of requests allowed in an initial outburst of requests per client IP.
For example, when you load a web page that loads a number of resources at the same time.
- `rate_limit_domain`: Set the maximum threshold in number of requests per hosted pages domain per second. Set to 0 to disable this feature.
- `rate_limit_domain`: Sets the maximum threshold in number of requests per hosted pages domain per second. Set to 0 to disable this feature.
- `rate_limit_domain_burst`: Sets the maximum threshold of number of requests allowed in an initial outburst of requests per hosted pages domain.
TLS connection-based rate limits are enforced using the following:
- `rate_limit_tls_source_ip`: Set the maximum threshold in number of TLS connections per client IP per second. Set to 0 to disable this feature.
- `rate_limit_tls_source_ip`: Sets the maximum threshold in number of TLS connections per client IP per second. Set to 0 to disable this feature.
- `rate_limit_tls_source_ip_burst`: Sets the maximum threshold of number of TLS connections allowed in an initial outburst of TLS connections per client IP.
For example, when you load a web page from different web browsers at the same time.
- `rate_limit_tls_domain`: Set the maximum threshold in number of TLS connections per hosted pages domain per second. Set to 0 to disable this feature.
- `rate_limit_tls_domain`: Sets the maximum threshold in number of TLS connections per hosted pages domain per second. Set to 0 to disable this feature.
- `rate_limit_tls_domain_burst`: Sets the maximum threshold of number of TLS connections allowed in an initial outburst of TLS connections per hosted pages domain.
To allow certain IP ranges (subnets) to bypass all rate limits:
- `rate_limit_subnets_allow_list`: Sets the allow list with the IP ranges (subnets) that should bypass all rate limits.
For example, `['1.2.3.4/24', '2001:db8::1/32']`.
An IPv6 address receives a large prefix in the 128-bit address space. The prefix is typically at least size /64. Because of the large number of possible addresses, if the client's IP address is IPv6, the limit is applied to the IPv6 prefix with a length of 64, rather than the entire IPv6 address.
#### Enable HTTP requests rate limits by source-IP

View File

@ -73,7 +73,7 @@ glab mr merge
## GitLab Duo for the CLI
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** Experiment, Self-managed, GitLab Dedicated
The GitLab CLI includes features powered by [GitLab Duo](../../user/ai_features.md). These include:

View File

@ -269,7 +269,7 @@ After you save a visualization, you can add it to a new or existing custom dashb
### Generate a custom visualization with GitLab Duo
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment

View File

@ -32,7 +32,7 @@ the Vulnerability Report's [Activity filter](../vulnerability_report/index.md#ac
## Explaining a vulnerability
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10368) in GitLab 16.0 as an [experiment](../../../policy/experiment-beta-support.md#experiment) on GitLab.com.
@ -90,7 +90,7 @@ The following data is shared with third-party AI APIs:
## Vulnerability resolution
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment

View File

@ -12,7 +12,7 @@ The following GitLab Duo features are
## Summarize issue discussions with Discussion summary
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment
@ -76,7 +76,7 @@ Provide feedback on this experimental feature in [issue 416833](https://gitlab.c
## Summarize an issue with Issue description generation
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment

View File

@ -26,7 +26,7 @@ how and where you can access these features.
### GitLab Duo Chat
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Tier: GitLab.com and Self-managed:** For a limited time, Premium or Ultimate. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Help you write and understand code faster, get up to speed on the status of projects,
@ -55,7 +55,7 @@ DETAILS:
### Code explanation in the IDE
DETAILS:
**Tier: GitLab.com and Self-managed:** Premium or Ultimate for a limited time. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Tier: GitLab.com and Self-managed:** For a limited time, Premium or Ultimate. In the future, Premium with GitLab Duo Pro or Ultimate with [GitLab Duo Pro or Enterprise](../../subscriptions/subscription-add-ons.md). **GitLab Dedicated:** GitLab Duo Pro or Enterprise.
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Helps you understand the selected code by explaining it more clearly.
@ -76,7 +76,7 @@ DETAILS:
### GitLab Duo for the CLI
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment, Self-managed, GitLab Dedicated
@ -87,7 +87,7 @@ DETAILS:
### Merge commit message generation
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Helps you merge more quickly by generating meaningful commit messages.
@ -97,7 +97,7 @@ DETAILS:
### Root cause analysis
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123692) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment) on GitLab.com.
@ -110,7 +110,7 @@ DETAILS:
### Vulnerability explanation
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
- Helps you understand vulnerabilities, how they can be exploited, and how to fix them.
@ -134,7 +134,7 @@ DETAILS:
### Merge request summary
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Beta
@ -147,7 +147,7 @@ DETAILS:
### Issue description generation
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment
@ -158,7 +158,7 @@ DETAILS:
### Discussion summary
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment
@ -183,7 +183,7 @@ DETAILS:
### Code review summary
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment
@ -195,7 +195,7 @@ DETAILS:
### Vulnerability resolution
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment
@ -206,7 +206,7 @@ DETAILS:
### Product Analytics
DETAILS:
**Tier:** Ultimate for a limited time. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com
**Status:** Experiment

View File

@ -85,7 +85,7 @@ Alternatively, you can use root cause analysis to [troubleshoot failed CI/CD job
## Troubleshoot failed CI/CD jobs with root cause analysis
DETAILS:
**Tier:** Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md)
**Tier:** For a limited time, Ultimate. In the future, Ultimate with [GitLab Duo Enterprise](../../subscriptions/subscription-add-ons.md).
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123692) in GitLab 16.2 as an [experiment](../../policy/experiment-beta-support.md#experiment) on GitLab.com.

View File

@ -303,6 +303,31 @@ If you don't want to display achievements on your profile, you can opt out. To d
1. In the **Main settings** section, clear the **Display achievements on your profile** checkbox.
1. Select **Update profile settings**.
## Change visibility of specific achievements
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161225) in GitLab 17.3.
If you don't want to display all achievements on your profile, you can change the visibility of specific achievements.
To hide one of your achievements, call the [`userAchievementsUpdate` GraphQL mutation](../../api/graphql/reference/index.md#mutationuserachievementsupdate).
```graphql
mutation {
userAchievementsUpdate(input: {
userAchievementId: "gid://gitlab/Achievements::UserAchievement/<user achievement id>"
showOnProfile: false
}) {
userAchievement {
id
showOnProfile
}
errors
}
}
```
To show one of your achievements again, call the same mutation with the value `true` for the `showOnProfile` argument.
## Reorder achievements
By default, achievements on your profile are displayed in ascending order by awarded date.

View File

@ -42,6 +42,7 @@ Code generation is used when:
- You write a comment and press <kbd>Enter</kbd>.
- You enter an empty function or method.
- The file you're editing has fewer than five lines of code.
Code generation requests take longer than code completion requests, but provide more accurate responses because:
- A larger LLM is used.

View File

@ -82,7 +82,7 @@ If you are not authenticated, then the list shows public projects only.
To view projects you are a member of:
1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **View all my projects**.
On the left sidebar, **Projects** is selected. On the list, on the **Yours** tab,
all the projects you are a member of are displayed.
@ -96,6 +96,12 @@ called `my-project` under your username, the project is created at `https://gitl
To view your personal projects:
1. On the left sidebar, select **Search or go to**.
1. Select **View all my projects**.
1. Select the **Personal** tab.
Or
1. On the left sidebar, select your avatar and then your username.
1. On the left sidebar, select **Personal projects**.
@ -103,6 +109,12 @@ To view your personal projects:
To view projects you have [starred](#star-a-project):
1. On the left sidebar, select **Search or go to**.
1. Select **View all my projects**.
1. Select the **Starred** tab.
Or
1. On the left sidebar, select your avatar and then your username.
1. On the left sidebar, select **Starred projects**.
@ -259,8 +271,7 @@ Active pipeline schedules of archived projects don't become read-only.
Archived projects are:
- Labeled with an `archived` badge on the project page.
- Listed on the group page in the **Inactive** tab.
- Hidden from project lists in **Your Work** and **Explore**.
- Listed in the **Inactive** tab on the group page, **Your work** page, and **Explore** page.
- Read-only.
Prerequisites:
@ -328,9 +339,7 @@ You can sort projects by:
- Name
- Created date
- Updated date
- Owner
You can also choose to hide or show archived projects.
- Stars
### Filter projects by language
@ -343,10 +352,22 @@ You can filter projects by the programming language they use. To do this:
1. Select either:
- **View all your projects**, to filter your projects.
- **Explore**, to filter all projects you can access.
1. Above the list of projects, select **Search or filter results**.
1. From the **Language** dropdown list, select the language you want to filter projects by.
A list of projects that use the selected language is displayed.
### View only projects you own
To view only the projects you are the owner of:
1. On the left sidebar, select **Search or go to**.
1. Select either:
- **View all your projects**, to filter your projects.
- **Explore**, to filter all projects you can access.
1. Above the list of projects, select **Search or filter results**.
1. From the **Role** dropdown list, select **Owner**.
## Rename a repository
A project's repository name defines its URL and its place on the file disk

View File

@ -391,6 +391,7 @@ module API
mount ::API::Ml::Mlflow::Entrypoint
end
mount ::API::Internal::Autoflow
mount ::API::Internal::Base
mount ::API::Internal::Coverage if Gitlab::Utils.to_boolean(ENV['COVERBAND_ENABLED'], default: false)
mount ::API::Internal::Lfs

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module API
module Helpers
module KasHelpers
def authenticate_gitlab_kas_request!
render_api_error!('KAS JWT authentication invalid', 401) unless Gitlab::Kas.verify_api_request(headers)
end
def gitaly_info(project)
Gitlab::GitalyClient.connection_data(project.repository_storage)
end
def gitaly_repository(project)
project.repository.gitaly_repository.to_h
end
end
end
end

View File

@ -14,10 +14,6 @@ module API
'k8s_api_proxy_requests_via_pat_access' => 'request_api_proxy_access_via_pat'
}.freeze
def authenticate_gitlab_kas_request!
render_api_error!('KAS JWT authentication invalid', 401) unless Gitlab::Kas.verify_api_request(headers)
end
def agent_token
cluster_agent_token_from_authorization_token
end
@ -28,14 +24,6 @@ module API
end
strong_memoize_attr :agent
def gitaly_info(project)
Gitlab::GitalyClient.connection_data(project.repository_storage)
end
def gitaly_repository(project)
project.repository.gitaly_repository.to_h
end
def check_agent_token
unauthorized! unless agent_token

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
module API
# AutoFlow Internal API
module Internal
class Autoflow < ::API::Base
before do
authenticate_gitlab_kas_request!
end
helpers ::API::Helpers::KasHelpers
namespace 'internal' do
namespace 'autoflow' do
desc 'Retrieve repository information' do
detail 'Retrieve repository information for the given project'
end
params do
requires :id, type: String, desc: 'ID or full path of the project'
end
get '/repository_info', feature_category: :deployment_management, urgency: :low do
project = find_project(params[:id])
not_found! unless project
status 200
{
project_id: project.id,
gitaly_info: gitaly_info(project),
gitaly_repository: gitaly_repository(project),
default_branch: project.default_branch_or_main
}
end
end
end
end
end
end

View File

@ -8,6 +8,7 @@ module API
authenticate_gitlab_kas_request!
end
helpers ::API::Helpers::KasHelpers
helpers ::API::Helpers::Kubernetes::AgentHelpers
namespace 'internal' do

View File

@ -9,6 +9,7 @@ module Gitlab
STUB_CLASSES = {
agent_tracker: Gitlab::Agent::AgentTracker::Rpc::AgentTracker::Stub,
configuration_project: Gitlab::Agent::ConfigurationProject::Rpc::ConfigurationProject::Stub,
autoflow: Gitlab::Agent::AutoFlow::Rpc::AutoFlow::Stub,
notifications: Gitlab::Agent::Notifications::Rpc::Notifications::Stub
}.freeze
@ -54,6 +55,34 @@ module Gitlab
.git_push_event(request, metadata: metadata)
end
def send_autoflow_event(project:, type:, id:, data:)
# We only want to send events if AutoFlow is enabled and no-op otherwise
return unless Feature.enabled?(:autoflow_enabled, project)
project_proto = Gitlab::Agent::Event::Project.new(
id: project.id,
full_path: project.full_path
)
request = Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest.new(
event: Gitlab::Agent::Event::CloudEvent.new(
id: id,
source: "GitLab",
spec_version: "v1",
type: type,
attributes: {
datacontenttype: Gitlab::Agent::Event::CloudEvent::CloudEventAttributeValue.new(
ce_string: "application/json"
)
},
text_data: data.to_json
),
flow_project: project_proto
)
stub_for(:autoflow)
.cloud_event(request, metadata: metadata)
end
private
def stub_for(service)

View File

@ -15825,6 +15825,9 @@ msgstr ""
msgid "CreateValueStreamForm|'%{name}' Value Stream created"
msgstr ""
msgid "CreateValueStreamForm|'%{name}' Value Stream has been successfully created."
msgstr ""
msgid "CreateValueStreamForm|'%{name}' Value Stream saved"
msgstr ""
@ -57953,6 +57956,9 @@ msgstr ""
msgid "UserMapping|Don't reassign"
msgstr ""
msgid "UserMapping|Download the pre-filled CSV template."
msgstr ""
msgid "UserMapping|Import details:"
msgstr ""
@ -57974,6 +57980,9 @@ msgstr ""
msgid "UserMapping|Notify again"
msgstr ""
msgid "UserMapping|Once you select \"Reassign\", the processing will start and users will receive and email to accept the contribution reassignment. Once a users has accepted the reassignment, it cannot be undone. Check all data is correct before continuing."
msgstr ""
msgid "UserMapping|Original user: %{source_name} (%{source_username})"
msgstr ""
@ -58001,6 +58010,9 @@ msgstr ""
msgid "UserMapping|Reassign placeholder to"
msgstr ""
msgid "UserMapping|Reassign with CSV file"
msgstr ""
msgid "UserMapping|Reassigned"
msgstr ""
@ -58058,6 +58070,9 @@ msgstr ""
msgid "UserMapping|Rejected"
msgstr ""
msgid "UserMapping|Review and complete filling out the CSV file."
msgstr ""
msgid "UserMapping|Review reassignment details"
msgstr ""
@ -58094,6 +58109,12 @@ msgstr ""
msgid "UserMapping|To learn more about reassignments, visit the docs (%{help_link}). If you don't recognize this request, report abuse (%{report_link})."
msgstr ""
msgid "UserMapping|Upload reviewed and completed CSV file."
msgstr ""
msgid "UserMapping|Use a CSV file to reassign contributions from placeholder users to existing group members. This can be done in a few steps. %{linkStart}Learn more about matching users by CSV%{linkEnd}."
msgstr ""
msgid "UserMapping|You have approved the reassignment of contributions from %{strong_open}%{source_user_name} (@%{source_username})%{strong_close} on %{strong_open}%{source_hostname}%{strong_close} to yourself on the group %{strong_open}%{destination_group}%{strong_close}. Reassignment processing is in progress. You&#39;ll have access to the group soon."
msgstr ""

View File

@ -2,15 +2,16 @@ import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
import { GlTab, GlTabs } from '@gitlab/ui';
import { GlTab, GlTabs, GlModal } from '@gitlab/ui';
import { createAlert } from '~/alert';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import setWindowLocation from 'helpers/set_window_location_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
import PlaceholdersTabApp from '~/members/placeholders/components/app.vue';
import PlaceholdersTable from '~/members/placeholders/components/placeholders_table.vue';
import CsvUploadModal from '~/members/placeholders/components/csv_upload_modal.vue';
import importSourceUsersQuery from '~/members/placeholders/graphql/queries/import_source_users.query.graphql';
import { MEMBERS_TAB_TYPES } from '~/members/constants';
import {
@ -38,7 +39,10 @@ describe('PlaceholdersTabApp', () => {
show: jest.fn(),
};
const createComponent = ({ queryHandler = sourceUsersQueryHandler } = {}) => {
const createComponent = ({
queryHandler = sourceUsersQueryHandler,
mountFn = shallowMountExtended,
} = {}) => {
store = new Vuex.Store({
modules: {
[MEMBERS_TAB_TYPES.placeholder]: {
@ -52,20 +56,31 @@ describe('PlaceholdersTabApp', () => {
mockApollo = createMockApollo([[importSourceUsersQuery, queryHandler]]);
wrapper = shallowMount(PlaceholdersTabApp, {
wrapper = mountFn(PlaceholdersTabApp, {
apolloProvider: mockApollo,
store,
provide: {
group: mockGroup,
reassignmentCsvDownloadPath: 'foo/bar',
},
mocks: { $toast },
stubs: { GlTab },
stubs: {
GlTabs: stubComponent(GlTabs, {
template: RENDER_ALL_SLOTS_TEMPLATE,
}),
GlTab,
GlModal: stubComponent(GlModal, {
template: RENDER_ALL_SLOTS_TEMPLATE,
}),
},
});
};
const findTabs = () => wrapper.findComponent(GlTabs);
const findTabAt = (index) => wrapper.findAllComponents(GlTab).at(index);
const findPlaceholdersTable = () => wrapper.findComponent(PlaceholdersTable);
const findReassignCsvButton = () => wrapper.findByTestId('reassign-csv-button');
const findCsvModal = () => wrapper.findComponent(CsvUploadModal);
it('renders tabs', () => {
createComponent();
@ -250,4 +265,23 @@ describe('PlaceholdersTabApp', () => {
});
});
});
describe('reassign CSV button', () => {
it('renders the button and the modal', () => {
createComponent();
expect(findReassignCsvButton().exists()).toBe(true);
expect(findCsvModal().exists()).toBe(true);
});
it('shows modal when button is clicked', async () => {
createComponent({ mountFn: mountExtended });
findReassignCsvButton().trigger('click');
await nextTick();
expect(findCsvModal().findComponent(GlModal).isVisible()).toBe(true);
});
});
});

View File

@ -0,0 +1,36 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import CsvUploadModal from '~/members/placeholders/components/csv_upload_modal.vue';
describe('CsvUploadModal', () => {
let wrapper;
const defaultInjectedAttributes = {
reassignmentCsvDownloadPath: 'foo/bar',
};
const findDownloadLink = () => wrapper.findByTestId('csv-download-button');
function createComponent() {
return shallowMountExtended(CsvUploadModal, {
propsData: {
modalId: 'csv-upload-modal',
},
provide: {
...defaultInjectedAttributes,
},
});
}
beforeEach(() => {
wrapper = createComponent();
});
it('has the CSV download button with the required attributes', () => {
const downloadLink = findDownloadLink();
expect(downloadLink.exists()).toBe(true);
expect(downloadLink.attributes('href')).toBe(
defaultInjectedAttributes.reassignmentCsvDownloadPath,
);
});
});

View File

@ -181,7 +181,7 @@ describe('WorkItemLinksForm', () => {
expect(findInput().props('state')).toBe(false);
});
it('creates child task in non confidential parent', async () => {
it('creates child task in non confidential parent and closes the form', async () => {
findInput().vm.$emit('input', 'Create task test');
findForm().vm.$emit('submit', {
@ -201,6 +201,7 @@ describe('WorkItemLinksForm', () => {
},
});
expect(wrapper.emitted('addChild')).toEqual([[]]);
expect(wrapper.emitted('cancel')).toEqual([[]]);
});
it('creates child task in confidential parent', async () => {
@ -244,7 +245,7 @@ describe('WorkItemLinksForm', () => {
expect(findWorkItemTokenInput().exists()).toBe(false);
});
it('creates child issue in non confidential parent', async () => {
it('creates child issue in non confidential parent and closes the form', async () => {
findInput().vm.$emit('input', 'Create issue test');
findProjectSelector().vm.$emit('selectProject', projectData[0].fullPath);
@ -267,6 +268,7 @@ describe('WorkItemLinksForm', () => {
},
});
expect(wrapper.emitted('addChild')).toEqual([[]]);
expect(wrapper.emitted('cancel')).toEqual([[]]);
});
it('creates child issue in confidential parent', async () => {
@ -423,7 +425,7 @@ describe('WorkItemLinksForm', () => {
});
});
it('selects and adds children', async () => {
it('selects, adds children and closes the form', async () => {
await selectAvailableWorkItemTokens();
expect(findAddChildButton().text()).toBe('Add tasks');
@ -435,7 +437,9 @@ describe('WorkItemLinksForm', () => {
preventDefault: jest.fn(),
});
await waitForPromises();
expect(updateMutationResolver).toHaveBeenCalled();
expect(wrapper.emitted('cancel')).toEqual([[]]);
});
it('shows validation error when non-confidential child items are being added to confidential parent', async () => {

View File

@ -37,12 +37,12 @@ RSpec.describe Gitlab::Kas::Client do
allow(Gitlab::Kas).to receive(:enabled?).and_return(true)
allow(Gitlab::Kas).to receive(:internal_url).and_return(kas_url)
expect(JSONWebToken::HMACToken).to receive(:new)
allow(JSONWebToken::HMACToken).to receive(:new)
.with(Gitlab::Kas.secret)
.and_return(token)
expect(token).to receive(:issuer=).with(Settings.gitlab.host)
expect(token).to receive(:audience=).with(described_class::JWT_AUDIENCE)
allow(token).to receive(:issuer=).with(Settings.gitlab.host)
allow(token).to receive(:audience=).with(described_class::JWT_AUDIENCE)
end
describe '#get_connected_agents_by_agent_ids' do
@ -110,6 +110,59 @@ RSpec.describe Gitlab::Kas::Client do
it { expect(subject).to eq(agent_configurations) }
end
describe '#send_autoflow_event' do
subject { described_class.new.send_autoflow_event(project: project, type: 'any-type', id: 'any-id', data: { 'any-data-key': 'any-data-value' }) }
context 'when autoflow_enabled FF is disabled' do
before do
stub_feature_flags(autoflow_enabled: false)
end
it { expect(subject).to be_nil }
end
context 'when autoflow_enabled FF is enabled' do
let(:stub) { instance_double(Gitlab::Agent::AutoFlow::Rpc::AutoFlow::Stub) }
let(:request) { instance_double(Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest) }
let(:event_param) { instance_double(Gitlab::Agent::Event::CloudEvent) }
let(:project_param) { instance_double(Gitlab::Agent::Event::Project) }
let(:response) { double(Gitlab::Agent::AutoFlow::Rpc::CloudEventResponse) }
before do
stub_feature_flags(autoflow_enabled: true)
expect(Gitlab::Agent::AutoFlow::Rpc::AutoFlow::Stub).to receive(:new)
.with('example.kas.internal', :this_channel_is_insecure, timeout: described_class::TIMEOUT)
.and_return(stub)
expect(Gitlab::Agent::Event::Project).to receive(:new)
.with(id: project.id, full_path: project.full_path)
.and_return(project_param)
expect(Gitlab::Agent::Event::CloudEvent).to receive(:new)
.with(id: 'any-id', source: "GitLab", spec_version: "v1", type: 'any-type',
attributes: {
datacontenttype: Gitlab::Agent::Event::CloudEvent::CloudEventAttributeValue.new(
ce_string: "application/json"
)
},
text_data: '{"any-data-key":"any-data-value"}'
)
.and_return(event_param)
expect(Gitlab::Agent::AutoFlow::Rpc::CloudEventRequest).to receive(:new)
.with(event: event_param, flow_project: project_param)
.and_return(request)
expect(stub).to receive(:cloud_event)
.with(request, metadata: { 'authorization' => 'bearer test-token' })
.and_return(response)
end
it { expect(subject).to eq(response) }
end
end
describe '#send_git_push_event' do
let(:stub) { instance_double(Gitlab::Agent::Notifications::Rpc::Notifications::Stub) }
let(:request) { instance_double(Gitlab::Agent::Notifications::Rpc::GitPushEventRequest) }

View File

@ -207,7 +207,7 @@ RSpec.describe Ci::BuildTraceChunks::Fog do
create(:ci_build_trace_chunk, :fog_with_data, chunk_index: 1, build: build)
end
it 'deletes multiple data' do
it 'deletes multiple data', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/456375' do
files = connection.directories.new(key: bucket).files
expect(files.count).to eq(2)

View File

@ -0,0 +1,84 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Internal::Autoflow, feature_category: :deployment_management do
let(:jwt_auth_headers) do
jwt_token = JWT.encode(
{ 'iss' => Gitlab::Kas::JWT_ISSUER, 'aud' => Gitlab::Kas::JWT_AUDIENCE },
Gitlab::Kas.secret,
'HS256'
)
{ Gitlab::Kas::INTERNAL_API_KAS_REQUEST_HEADER => jwt_token }
end
let(:jwt_secret) { SecureRandom.random_bytes(Gitlab::Kas::SECRET_LENGTH) }
before do
allow(Gitlab::Kas).to receive(:secret).and_return(jwt_secret)
end
shared_examples 'authorization' do
context 'when not authenticated' do
it 'returns 401' do
send_request(headers: { Gitlab::Kas::INTERNAL_API_KAS_REQUEST_HEADER => '' })
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
describe 'GET /internal/autoflow/repository_info' do
def send_request(headers: {}, params: {})
get api('/internal/autoflow/repository_info'), params: params, headers: headers.reverse_merge(jwt_auth_headers)
end
def expect_success_response
expect(response).to have_gitlab_http_status(:success)
expect(json_response).to match(
a_hash_including(
'project_id' => project.id,
'gitaly_info' => a_hash_including(
'address' => match(/\.socket$/),
'token' => 'secret'
),
'gitaly_repository' => a_hash_including(
'storage_name' => project.repository_storage,
'relative_path' => "#{project.disk_path}.git",
'gl_repository' => "project-#{project.id}",
'gl_project_path' => project.full_path
),
'default_branch' => project.default_branch_or_main
)
)
end
include_examples 'authorization'
context 'when project exists' do
let_it_be(:project) { create(:project) }
it 'returns expected data for numerical project id', :aggregate_failures do
send_request(params: { id: project.id })
expect_success_response
end
it 'returns expected data for project full path', :aggregate_failures do
send_request(params: { id: project.full_path })
expect_success_response
end
end
context 'when project does not exists' do
it 'returns expected data', :aggregate_failures do
send_request(params: { id: non_existing_record_id })
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end