Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-12-14 00:32:28 +00:00
parent 44b16c9776
commit ca1a45a955
40 changed files with 327 additions and 103 deletions

View File

@ -1 +1 @@
967661bb7027d5b38e01bd26f3ed3887d078410c
c8d9c76d7f3ab259d0b743b2c79a678e88832a85

View File

@ -1 +1 @@
ed8e69891a82913e19430e094c192833ea5cb066
40c7b25469a48f2eb811a9f797d412a2b9923433

View File

@ -5,8 +5,12 @@ query flowMetricsCommitsQuery(
$endDate: Time!
$labelNames: [String!]
) {
flowMetricsCommits(fullPath: $fullPath, from: $startDate, to: $endDate, labelNames: $labelNames)
@client {
flowMetricsCommits(
fullPath: $fullPath
startDate: $startDate
endDate: $endDate
labelNames: $labelNames
) @client {
value
identifier
links

View File

@ -5,8 +5,13 @@ const NO_COMMIT_DATA_ERROR = 'No commit data returned';
export const resolvers = {
Query: {
flowMetricsCommits(_, { fullPath, ...params }) {
return getValueStreamSummaryMetrics(fullPath, params)
flowMetricsCommits(_, { fullPath, startDate, endDate, labelNames, ...params }) {
return getValueStreamSummaryMetrics(fullPath, {
...params,
created_after: startDate,
created_before: endDate,
label_names: labelNames,
})
.then(({ data = [] }) => {
const commits = data.filter((metric) => metric.identifier === FLOW_METRICS.COMMITS);

View File

@ -9,8 +9,8 @@ type FlowMetricsCommits {
extend type Query {
flowMetricsCommits(
fullPath: ID!
from: Time!
to: Time!
startDate: Time!
endDate: Time!
labelNames: [String!]
): FlowMetricsCommits
}

View File

@ -5,6 +5,7 @@ import WikiHeader from './components/wiki_header.vue';
import WikiContent from './components/wiki_content.vue';
import WikiEditForm from './components/wiki_form.vue';
import WikiAlert from './components/wiki_alert.vue';
import eventHub, { EVENT_EDIT_WIKI_DONE, EVENT_EDIT_WIKI_START } from './event_hub';
export default {
components: {
@ -37,8 +38,10 @@ export default {
if (this.isEditing) {
url.searchParams.set('edit', 'true');
eventHub.$emit(EVENT_EDIT_WIKI_START);
} else {
url.searchParams.delete('edit');
eventHub.$emit(EVENT_EDIT_WIKI_DONE);
}
window.history.pushState({}, '', url);

View File

@ -0,0 +1,6 @@
import createEventHub from '~/helpers/event_hub_factory';
export default createEventHub();
export const EVENT_EDIT_WIKI_START = Symbol('eventEditWikiStart');
export const EVENT_EDIT_WIKI_DONE = Symbol('eventEditWikiDone');

View File

@ -5,6 +5,7 @@ import wikiPageQuery from '~/wikis/graphql/wiki_page.query.graphql';
import SkeletonNote from '~/vue_shared/components/notes/skeleton_note.vue';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_PROJECT, TYPENAME_GROUP } from '~/graphql_shared/constants';
import eventHub, { EVENT_EDIT_WIKI_DONE, EVENT_EDIT_WIKI_START } from '../../event_hub';
import OrderedLayout from './ordered_layout.vue';
import PlaceholderNote from './placeholder_note.vue';
import WikiNotesActivityHeader from './wiki_notes_activity_header.vue';
@ -75,6 +76,7 @@ export default {
id: index,
isSkeletonNote: true,
})),
isEditingPage: false,
};
},
computed: {
@ -82,6 +84,15 @@ export default {
return this.$apollo.queries.wikiPage;
},
},
mounted() {
eventHub.$on(EVENT_EDIT_WIKI_START, () => {
this.isEditingPage = true;
});
eventHub.$on(EVENT_EDIT_WIKI_DONE, () => {
this.isEditingPage = false;
});
},
methods: {
setPlaceHolderNote(note) {
this.placeholderNote = note;
@ -109,7 +120,7 @@ export default {
};
</script>
<template>
<div>
<div v-if="!isEditingPage">
<wiki-notes-activity-header />
<ordered-layout :slot-keys="slotKeys">
<template #form>

View File

@ -13,15 +13,17 @@ module IssuableCollectionsAction
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues
@issues = issuables_collection
.non_archived
.page(params[:page])
@issuable_meta_data = Gitlab::IssuableMetadata.new(current_user, @issues).data
respond_to do |format|
format.html
format.atom { render layout: 'xml' }
format.atom do
@issues = issuables_collection
.non_archived
.page(params[:page])
@issuable_meta_data = Gitlab::IssuableMetadata.new(current_user, @issues).data
render layout: 'xml'
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables

View File

@ -71,6 +71,10 @@ class WikiPage
set_attributes if persisted?
end
def meta
WikiPage::Meta.find_by_canonical_slug(slug, container)
end
# The escaped URL path of this page.
def slug
attributes[:slug].presence || ::Wiki.preview_slug(title, format)

View File

@ -30,6 +30,8 @@ class WikiPage
joins(:slugs).where(slug_table_name => { canonical: true, slug: slug })
end
delegate :wiki, to: :container
class << self
# Return the (updated) WikiPage::Meta record for a given wiki page
#
@ -100,6 +102,10 @@ class WikiPage
end
end
def wiki_page
wiki.find_page(canonical_slug, load_content: true)
end
def container
project || namespace
end

View File

@ -141,14 +141,12 @@ You can impersonate a user in the following ways:
1. On the left sidebar, at the bottom, select **Admin**.
1. On the left sidebar, select **Overview > Users**.
1. From the list of users, select a user.
1. Select **Impersonate**.
1. On the top right, select **Impersonate**.
- With the API, using [impersonation tokens](../api/rest/authentication.md#impersonation-tokens).
All impersonation activities are [captured with audit events](audit_event_reports.md#user-impersonation).
By default, impersonation is enabled. GitLab can be configured to [disable impersonation](../api/rest/authentication.md#disable-impersonation).
![The user impersonation button.](img/impersonate_user_button_v13_8.png)
### User identities
> - The ability to see a user's SCIM identity was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294608) in GitLab 15.3.
@ -163,7 +161,7 @@ When using authentication providers, administrators can see the identities for a
This list shows the user's identities, including SCIM identities. Administrators can use this information to troubleshoot SCIM-related issues and confirm
the identities being used for an account.
### User Permission Export
### User permission export
DETAILS:
**Tier:** Premium, Ultimate
@ -172,7 +170,7 @@ DETAILS:
An administrator can export user permissions for all users in the GitLab instance from the **Admin** area's Users page.
The export lists direct membership the users have in groups and projects.
The following data is included in the export:
The export process exports the first 100,000 users, and includes this data:
- Username
- Email
@ -181,9 +179,11 @@ The following data is included in the export:
- Access level ([Project](../user/permissions.md#project-members-permissions) and [Group](../user/permissions.md#group-members-permissions))
- Date of last activity. For a list of activities that populate this column, see the [Users API documentation](../api/users.md#list-a-users-activity).
Only the first 100,000 user accounts are exported.
To do this:
![The user permission export button.](img/export_permissions_v13_11.png)
1. On the left sidebar, at the bottom, select **Admin**.
1. Select **Overview > Users**.
1. On the top right, select **Export permissions as CSV** (**{export}**).
### Users statistics

View File

@ -10,9 +10,6 @@ DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** Self-managed
> - Target roles [introduced](https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/461) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `role_targeted_broadcast_messages`. Disabled by default.
> - Theme [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83251) and background color removed in GitLab 14.10.
GitLab can display two types of broadcast messages to users of a GitLab instance:
- Banners
@ -22,25 +19,37 @@ Broadcast messages can be managed using the [broadcast messages API](../api/broa
## Banners
Banners are shown on the top of a page and optionally in the command line as a Git remote response.
Banners are shown on the top of a page, and optionally in the command line as a Git remote response.
![A broadcast message banner displaying a welcome message.](img/broadcast_messages_banner_v15_0.png)
![A broadcast message banner displaying a welcome message.](img/broadcast_messages_banner_v17_7.png)
```shell
$ git push
...
remote:
remote: **Welcome** to GitLab :wave:
remote: **Welcome to GitLab** :wave:
remote:
...
```
If more than one banner is active at one time, they are displayed at the top of the page in order of creation. In the command line, only the latest banner is shown.
If more than one banner is active at one time, they are displayed at the top of the page in order of
creation. In the command line, only the latest banner is shown.
## Notifications
Notifications are shown on the bottom right of a page and can contain placeholders. A placeholder is replaced with an attribute of the active user. Placeholders must be surrounded by curly braces, for example `{{name}}`.
The available placeholders are:
GitLab shows notifications on the bottom right of a page. They can contain placeholders,
which are replaced with the attributes of the current user:
![A broadcast message notification using the name placeholder.](img/broadcast_messages_notification_v17_7.png)
```markdown
{{name}}, would you like to give us feedback?
<a href="example.com">Take our survey!</a>
```
If more than one notification is active at one time, only the newest is shown.
Notifications support these placeholders:
- `{{email}}`
- `{{name}}`
@ -48,11 +57,7 @@ The available placeholders are:
- `{{username}}`
- `{{instance_id}}`
If the user is not signed in, user related values are empty.
![A broadcast message notification using the name placeholder.](img/broadcast_messages_notification_v12_10.png)
If more than one notification is active at one time, only the newest is shown.
If the user is not signed in, user-related values are empty.
## Add a broadcast message
@ -61,25 +66,34 @@ To display messages to users on your GitLab instance, add a broadcast message.
To add a broadcast message:
1. On the left sidebar, at the bottom, select **Admin**.
1. Select **Messages**.
1. Select **Add new message**.
1. Add the text for the message to the **Message** field. You can style a message's content using Markdown, emoji, and the `a` and `br` HTML tags.
The `br` tag inserts a line break. The `a` HTML tag accepts `class` and `style` attributes with the following CSS properties:
- `color`
- `border`
- `background`
- `padding`
- `margin`
- `text-decoration`
1. On the left sidebar, select **Messages**.
1. On the right, select **Add new message**.
1. Add your **Message** text:
- Message contents can include Markdown, emoji, and the `a` and `br` HTML tags.
- The `br` tag inserts a line break.
- The `a` HTML tag accepts `class` and `style` attributes with the following CSS properties:
- `color`
- `border`
- `background`
- `padding`
- `margin`
- `text-decoration`
1. For **Type**, select `banner` or `notification`.
1. Select a **Theme**. The default theme is `indigo`.
1. Select the **Dismissable** checkbox to enable users to dismiss the broadcast message.
1. Optional. Clear the **Git remote responses** checkbox to prevent broadcast messages from being displayed in the command line as Git remote responses.
1. Optional. Select **Target roles** to only show the broadcast message to users with the selected roles. The message displays on group, subgroup, and project pages, and does not display in Git remote responses.
1. If required, add a **Target Path** to only show the broadcast message on URLs matching that path. You can use the wildcard character `*` to match multiple URLs, for example `mygroup/myproject*`.
1. To enable users to dismiss the broadcast message, select **Dismissable**.
1. Optional. To skip showing the broadcast message in the command line as a Git remote response, select clear the **Git remote responses**.
1. Optional. To show the message only to a subset of users, select **Target broadcast message**:
- Show to all users on all pages.
- Show to all users on specific matching pages.
- Show only to users who have specific roles on groups or project pages. This setting displays your message on
group, subgroup, and project pages, but does not display in Git remote responses.
1. If required, select the **Target roles** to show the broadcast message to.
1. If required, add a **Target Path** to only show the broadcast message on URLs matching that path.
Use the wildcard character `*` to match multiple URLs, like `mygroup/myproject*`.
1. Select a date and time (UTC) for the message to start and end.
1. Select **Add broadcast message**.
When a broadcast message expires, it no longer displays in the user interface but is still listed in the
When a broadcast message expires, it no longer displays in the user interface, but is still listed in the
list of broadcast messages.
## Edit a broadcast message
@ -107,15 +121,3 @@ To delete a broadcast message:
1. From the list of broadcast messages, select the delete button for the message.
When a broadcast message is deleted, it's removed from the list of broadcast messages.
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
important to describe those, too. Think of things that may go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
Each scenario can be a third-level heading, for example `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1377,6 +1377,7 @@ job:
them fail with a [`could not retrieve the needed artifacts` error](../jobs/job_artifacts_troubleshooting.md#error-message-this-job-could-not-start-because-it-could-not-retrieve-the-needed-artifacts).
Set the expiry time to be longer, or use [`dependencies`](#dependencies) in later jobs
to ensure they don't try to fetch expired artifacts.
- `artifacts:expire_in` doesn't affect GitLab Pages deployments. To configure Pages deployments' expiry, use [`pages:pages.expire_in`](#pagespagesexpire_in).
#### `artifacts:expose_as`
@ -3534,8 +3535,9 @@ Use `expire_in` to specify how long a deployment should be available before
it expires. After the deployment is expired, it's deactivated by a cron
job running every 10 minutes.
Extra deployments expire by default. To prevent them from expiring, set the
value to `never`.
By default, [parallel deployments](../../user/project/pages/index.md#parallel-deployments) expire
automatically after 24 hours.
To disable this behavior, set the value to `never`.
**Keyword type**: Job keyword. You can use it only as part of a `pages` job.

View File

@ -59,7 +59,7 @@ Amazon Q can analyze Java 8 or 11 code and determine the necessary Java changes
Prerequisites:
- You must [have a runner configured for your project](https://docs.gitlab.com/runner/register/).
- You must [have a runner and a CI/CD pipeline configured for your project](../../ci/index.md).
To upgrade Java:
@ -69,7 +69,10 @@ To upgrade Java:
1. Save the issue. Then, in a comment, type `/q transform`.
1. Select **Comment**.
A merge request with the code changes needed for the upgrade is created.
A CI/CD job starts. A comment is displayed with the details and a link to the job.
- If the job is successful, a merge request with the code changes needed for the upgrade is created.
- If the job fails, a comment provides details about potential fixes.
## Use GitLab Duo with Amazon Q in a merge request

View File

@ -33,11 +33,13 @@ To set up GitLab Duo with Amazon Q, you must:
- [Create an identity provider](#create-an-iam-identity-provider)
- [Create an IAM role](#create-an-iam-role)
- [Enter the ARN in GitLab and enable Amazon Q](#enter-the-arn-in-gitlab-and-enable-amazon-q)
- [Add the Amazon Q user to your project](#add-the-amazon-q-user-to-your-project)
### Prerequisites
- You must have a self-managed GitLab instance:
- With an HTTPS URL that can be accessed by Amazon Q.
- With an HTTPS URL that can be accessed by Amazon Q (the SSL certificate must not be self-signed).
For more details about SSL, see [Configure SSL for a Linux package installation](https://docs.gitlab.com/omnibus/settings/ssl/).
- With an Ultimate subscription that is synchronized with GitLab. (No trial access.)
- With the `amazon_q_integration` [feature flag enabled](../../administration/feature_flags.md).
- GitLab Duo features [must be turned on](../gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features).
@ -70,6 +72,9 @@ Now, create an AWS identity provider:
Next, you must create an IAM role that trusts the IAM identity provider and can
access Amazon Q.
NOTE:
After you set up the IAM role, you cannot change the AWS account that's associated with the role.
1. In the AWS IAM console, select **Access Management > Roles > Create role**.
1. Select **Web identity**.
1. For **Web identity**, select the provider URL you entered earlier.
@ -165,7 +170,24 @@ Prerequisites:
1. Select **Save changes**.
When you save, an API should contact the AI Gateway to create an OAuth application on Amazon Q.
To confirm that it was successful, check the logs for a `204`.
To confirm that it was successful:
- In the Amazon CloudWatch console log, check for a `204` status code. For more information, see
[What is Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)?
- In GitLab, a notification that says `Amazon Q settings have been saved` is displayed.
- In GitLab, on the left sidebar, select **Applications**. The Amazon Q OAuth application is displayed.
## Add the Amazon Q user to your project
Now add the Amazon Q service account user as a member of your project.
1. In GitLab, on the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. In the upper-right corner, select **Invite members**.
1. For **Username, name, or email address**, select **Amazon Q Service**.
1. For **Select a role**, select **Developer**.
1. Select **Invite**.
### Configure the AI gateway

View File

@ -187,7 +187,7 @@ DETAILS:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162826) in GitLab 17.4.
You can configure your Pages deployments to be automatically deleted after
a period of time has passed by specifying a duration at `pages.expire_in`:
a period of time has passed by specifying a duration at [`pages.expire_in`](../../../ci/yaml/index.md#pagespagesexpire_in):
```yaml
deploy-pages:
@ -202,15 +202,16 @@ deploy-pages:
```
By default, [parallel deployments](#parallel-deployments) expire
automatically after 24 hours. To disable this behavior, set `pages.expire_in` to `never`.
automatically after 24 hours.
To disable this behavior, set `pages.expire_in` to `never`.
Expired deployments are stopped by a cron job that runs every 10 minutes.
Stopped deployments are subsequently deleted by another cron job that also
runs every 10 minutes. To recover it, follow the steps described in
[Recover a stopped deployment](#recover-a-stopped-deployment).
A stopped or deleted deployment is no longer available on the web. Users will
see a 404 Not found error page at its URL, until another deployment is created
A stopped or deleted deployment is no longer available on the web.
Users see a `404 Not found` error page at its URL, until another deployment is created
with the same URL configuration.
The previous YAML example uses [user-defined job names](#user-defined-job-names).

View File

@ -17,6 +17,7 @@ module Gitlab
UnexpectedIdentityError = Class.new(IdentityError)
TooManyIdentitiesLinkedError = Class.new(IdentityError)
MissingCompositeIdentityError = Class.new(::Gitlab::Access::AccessDeniedError)
MissingServiceAccountError = Class.new(::Gitlab::Access::AccessDeniedError)
# TODO: why is this called 3 times in doorkeeper_access_spec.rb specs?
def self.link_from_oauth_token(oauth_token)
@ -41,6 +42,14 @@ module Gitlab
end
end
def self.link_from_web_request(service_account:, scoped_user:)
raise MissingServiceAccountError, 'service account is required' unless service_account
fabricate(service_account).tap do |identity|
identity.link!(scoped_user) if identity&.composite?
end
end
def self.sidekiq_restore!(job)
ids = Array(job[COMPOSITE_IDENTITY_SIDEKIQ_ARG])

View File

@ -50166,6 +50166,15 @@ msgstr ""
msgid "SecurityOrchestration|All types"
msgstr ""
msgid "SecurityOrchestration|Allow except on these packages"
msgstr ""
msgid "SecurityOrchestration|Allowed licenses"
msgstr ""
msgid "SecurityOrchestration|Allowlist details"
msgstr ""
msgid "SecurityOrchestration|An error occurred assigning your security policy project"
msgstr ""
@ -50280,6 +50289,15 @@ msgstr ""
msgid "SecurityOrchestration|Delete policy: %{policy}"
msgstr ""
msgid "SecurityOrchestration|Denied licenses"
msgstr ""
msgid "SecurityOrchestration|Deny except on these packages"
msgstr ""
msgid "SecurityOrchestration|Denylist details"
msgstr ""
msgid "SecurityOrchestration|Description"
msgstr ""

View File

@ -213,7 +213,6 @@ spec/frontend/lib/utils/breadcrumbs_spec.js
spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js
spec/frontend/members/components/app_spec.js
spec/frontend/members/components/modals/leave_modal_spec.js
spec/frontend/members/components/table/drawer/role_details_drawer_spec.js
spec/frontend/members/components/table/max_role_spec.js
spec/frontend/members/components/table/members_pagination_spec.js
spec/frontend/members/components/table/members_table_spec.js
@ -288,7 +287,6 @@ spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
spec/frontend/sidebar/components/confidential/confidentiality_dropdown_spec.js
spec/frontend/sidebar/components/confidential/sidebar_confidentiality_widget_spec.js
spec/frontend/sidebar/components/incidents/escalation_status_spec.js
spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js
spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js
spec/frontend/sidebar/components/labels/labels_select_vue/labels_select_root_spec.js
spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_spec.js

View File

@ -15,14 +15,14 @@ RSpec.describe DashboardController, feature_category: :code_review_workflow do
sign_in(user)
end
describe 'GET issues' do
it_behaves_like 'issuables list meta-data', :issue, :issues
it_behaves_like 'issuables requiring filter', :issues
describe 'GET issues.atom' do
it_behaves_like 'issuables list meta-data', :issue, :issues, format: :atom
it_behaves_like 'issuables requiring filter', :issues, format: :atom
it 'includes tasks in issue list' do
task = create(:work_item, :task, project: project, author: user)
get :issues, params: { author_id: user.id }
get :issues, params: { author_id: user.id }, format: :atom
expect(assigns[:issues].map(&:id)).to include(task.id)
end

View File

@ -105,6 +105,7 @@ end
RSpec.shared_examples 'default branch pipeline' do
it 'is valid' do
expect(pipeline.yaml_errors).to be nil
expect(pipeline.errors).to be_empty
expect(pipeline.status).to eq('created')
expect(jobs).to include(expected_job_name)
end
@ -113,6 +114,7 @@ end
RSpec.shared_examples 'merge request pipeline' do
it "succeeds with expected job" do
expect(pipeline.yaml_errors).to be nil
expect(pipeline.errors).to be_empty
expect(pipeline.status).to eq('created')
expect(jobs).to include(expected_job_name)
end
@ -123,6 +125,7 @@ RSpec.shared_examples 'merge train pipeline' do
it "succeeds with expected job" do
expect(pipeline.yaml_errors).to be nil
expect(pipeline.errors).to be_empty
expect(pipeline.status).to eq('created')
expect(jobs).to include('pre-merge-checks')
expect(jobs).not_to include('upload-frontend-fixtures')

View File

@ -37,14 +37,15 @@ FactoryBot.define do
factory :wiki_page_meta, class: 'WikiPage::Meta' do
title { generate(:wiki_page_title) }
project { association(:project) unless namespace.present? || container.present? }
container do
@overrides[:project] ||
@overrides[:namespace] ||
association(:project)
end
trait :for_wiki_page do
transient do
wiki_page { association(:wiki_page, container: container) }
end
container { @overrides[:wiki_page]&.container || association(:project) }
wiki_page { association(:wiki_page, container: container) }
container { @overrides[:wiki_page]&.container || container }
title { wiki_page.title }
initialize_with do

View File

@ -2,7 +2,7 @@
require "spec_helper"
RSpec.describe 'Project wikis', :js, feature_category: :wiki, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/508966' do
RSpec.describe 'Project wikis', :js, feature_category: :wiki do
let_it_be(:user) { create(:user) }
let(:wiki) { create(:project_wiki, user: user, project: project) }

View File

@ -17,7 +17,7 @@ describe('~/analytics/shared/graphql/resolvers', () => {
describe('flowMetricsCommits', () => {
const mockFullPath = 'fake/namespace/path';
const mockParams = { startDate: '2024-12-11', endDate: '2024-12-11' };
const mockParams = { startDate: '2024-11-11', endDate: '2024-12-11' };
const requestParams = {
fullPath: mockFullPath,
...mockParams,
@ -39,7 +39,10 @@ describe('~/analytics/shared/graphql/resolvers', () => {
it('will set the request parameters', async () => {
await mockResolvers.Query.flowMetricsCommits(null, requestParams);
expect(api.getValueStreamSummaryMetrics).toHaveBeenCalledWith(mockFullPath, mockParams);
expect(api.getValueStreamSummaryMetrics).toHaveBeenCalledWith(mockFullPath, {
created_after: '2024-11-11',
created_before: '2024-12-11',
});
});
it('will only return the commit data', async () => {

View File

@ -2,7 +2,7 @@ import { GlDrawer, GlAlert } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import RoleDetailsDrawer from '~/members/components/table/drawer/role_details_drawer.vue';
import MembersTableCell from '~/members/components/table/members_table_cell.vue';
import MembersTableCell from 'ee_else_ce/members/components/table/members_table_cell.vue';
import MemberAvatar from '~/members/components/table/member_avatar.vue';
import RoleSelector from '~/members/components/role_selector.vue';
import { roleDropdownItems } from '~/members/utils';

View File

@ -7,6 +7,11 @@ import PlaceholderNote from '~/pages/shared/wikis/wiki_notes/components/placehol
import SkeletonNote from '~/vue_shared/components/notes/skeleton_note.vue';
import WikiDiscussion from '~/pages/shared/wikis/wiki_notes/components/wiki_discussion.vue';
import WikiPageQuery from '~/wikis/graphql/wiki_page.query.graphql';
import WikiNotesActivityHeader from '~/pages/shared/wikis/wiki_notes/components/wiki_notes_activity_header.vue';
import eventHub, {
EVENT_EDIT_WIKI_DONE,
EVENT_EDIT_WIKI_START,
} from '~/pages/shared/wikis/event_hub';
import { note, noteableId } from '../mock_data';
describe('WikiNotesApp', () => {
@ -40,6 +45,26 @@ describe('WikiNotesApp', () => {
wrapper = createWrapper();
});
describe('when editing a wiki page', () => {
beforeEach(async () => {
eventHub.$emit(EVENT_EDIT_WIKI_START);
await nextTick();
});
it('should hide notes when editing a wiki page', () => {
expect(wrapper.findComponent(WikiNotesActivityHeader).exists()).toBe(false);
});
it('should show notes when editing a wiki page is done', async () => {
eventHub.$emit(EVENT_EDIT_WIKI_DONE);
await nextTick();
expect(wrapper.findComponent(WikiNotesActivityHeader).exists()).toBe(true);
});
});
it('should render skeleton notes before content loads', () => {
wrapper = createWrapper();
const skeletonNotes = wrapper.findAllComponents(SkeletonNote);

View File

@ -153,11 +153,7 @@ describe('SidebarEscalationStatus', () => {
});
it('updates the status', () => {
// Sometimes status has a intermediate wrapping component. A quirk of vue-test-utils
// means that in that case 'value' is exposed as a prop. If no wrapping component
// exists it is exposed as an attribute.
const statusValue =
findStatusComponent().props('value') || findStatusComponent().attributes('value');
const statusValue = findStatusComponent().props('value');
expect(statusValue).toBe(STATUS_ACKNOWLEDGED);
});
});

View File

@ -123,6 +123,80 @@ RSpec.describe Gitlab::Auth::Identity, :request_store, feature_category: :system
end
end
describe '.link_from_web_request' do
context 'when composite identity feature flag is enabled' do
context 'when service_account has composite identity enforced' do
before do
allow(primary_user).to receive(:has_composite_identity?).and_return(true)
end
it 'creates and links identity with scope user' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity.primary_user).to eq(primary_user)
expect(identity.scoped_user).to eq(scoped_user)
expect(identity).to be_linked
end
context 'when trying to link different scoped users' do
let(:another_scope_user) { create(:user) }
it 'raises IdentityLinkMismatchError when trying to link different scoped users' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect do
identity.link!(another_scope_user)
end.to raise_error(described_class::IdentityLinkMismatchError)
end
end
end
context 'when service_account does not have composite identity enforced' do
it 'creates identity without linking' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity).not_to be_linked
end
end
context 'when composite identity feature flag is disabled' do
before do
stub_feature_flags(composite_identity: false)
end
it 'creates identity without linking' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity.primary_user).to eq(primary_user)
expect(identity).not_to be_linked
end
end
context 'when service_account is not present' do
it 'raises an error' do
expect do
described_class.link_from_web_request(
service_account: nil,
scoped_user: scoped_user
)
end.to raise_error(described_class::MissingServiceAccountError)
end
end
end
end
describe '.sidekiq_restore!' do
context 'when job has primary and scoped identity stored' do
let(:job) { { 'jid' => 123, 'sqci' => [primary_user.id, scoped_user.id] } }

View File

@ -185,6 +185,17 @@ RSpec.describe WikiPage::Meta, feature_category: :wiki do
end
end
describe '#wiki_page' do
let(:wiki_page) { create(:wiki_page, container: project, content: 'test content') }
let(:meta) { create(:wiki_page_meta, :for_wiki_page, container: project, wiki_page: wiki_page) }
subject { meta.wiki_page }
it 'finds the wiki page for the meta record' do
expect(subject).to eq(wiki_page)
end
end
describe '.find_or_create' do
let(:old_title) { generate(:wiki_page_title) }
let(:last_known_slug) { generate(:sluggified_title) }

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true
RSpec.shared_examples 'issuables list meta-data' do |issuable_type, action = nil|
RSpec.shared_examples 'issuables list meta-data' do |issuable_type, action = nil, format: :html|
include ProjectForksHelper
def get_action(action, project, extra_params = {})
if action
get action, params: { author_id: project.creator.id }.merge(extra_params)
get action, params: { author_id: project.creator.id }.merge(extra_params), format: format
else
get :index, params: { namespace_id: project.namespace, project_id: project }.merge(extra_params)
get :index, params: { namespace_id: project.namespace, project_id: project }.merge(extra_params), format: format
end
end
@ -19,6 +19,8 @@ RSpec.shared_examples 'issuables list meta-data' do |issuable_type, action = nil
end
end
let(:format) { format }
let!(:issuables) do
%w[fix improve/awesome].map do |source_branch|
create_issuable(issuable_type, project, source_branch: source_branch)

View File

@ -1,17 +1,15 @@
# frozen_string_literal: true
RSpec.shared_examples 'issuables requiring filter' do |action|
RSpec.shared_examples 'issuables requiring filter' do |action, format: :html|
it "doesn't load any issuables if no filter is set" do
expect_any_instance_of(described_class).not_to receive(:issuables_collection)
get action
expect(response).to render_template(action)
get action, format: format
end
it "loads issuables if at least one filter is set" do
expect_any_instance_of(described_class).to receive(:issuables_collection).and_call_original
get action, params: { author_id: user.id }
get action, params: { author_id: user.id }, format: format
end
end

View File

@ -79,6 +79,10 @@ RSpec.shared_examples 'User updates wiki page' do
expect(page).to have_content('My awesome wiki!')
end
it 'does not show comments when editing' do
expect(page).not_to have_content('Activity')
end
it 'updates entry in redirects.yml file on changing page path' do
wiki.repository.update_file(
user, '.gitlab/redirects.yml',

View File

@ -57,6 +57,17 @@ RSpec.shared_examples 'wiki_page' do |container_type|
subject { persisted_page }
end
describe '#meta' do
let(:wiki_page) { create(:wiki_page, container: container, content: 'test content') }
let!(:meta) { create(:wiki_page_meta, :for_wiki_page, container: container, wiki_page: wiki_page) }
subject { wiki_page.meta }
it 'finds the meta record for the page' do
expect(subject).to eq(meta)
end
end
describe '#front_matter' do
let(:wiki_page) { create(:wiki_page, container: container, content: content) }