diff options
22 files changed, 206 insertions, 115 deletions
diff --git a/app/assets/javascripts/error_tracking/components/error_details_info.vue b/app/assets/javascripts/error_tracking/components/error_details_info.vue index f6f39f178fb..0b4eabe25d1 100644 --- a/app/assets/javascripts/error_tracking/components/error_details_info.vue +++ b/app/assets/javascripts/error_tracking/components/error_details_info.vue @@ -34,20 +34,14 @@ export default { lastReleaseLink() { return `${this.error.externalBaseUrl}/releases/${this.error.lastReleaseVersion}`; }, - firstCommitLink() { - return `${this.error.externalBaseUrl}/-/commit/${this.error.firstReleaseVersion}`; - }, - lastCommitLink() { - return `${this.error.externalBaseUrl}/-/commit/${this.error.lastReleaseVersion}`; - }, shortFirstReleaseVersion() { - return this.error.firstReleaseVersion.substr(0, 10); + return this.error.firstReleaseVersion?.substr(0, 10); }, shortLastReleaseVersion() { - return this.error.lastReleaseVersion.substr(0, 10); + return this.error.lastReleaseVersion?.substr(0, 10); }, shortGitlabCommit() { - return this.error.gitlabCommit.substr(0, 10); + return this.error.gitlabCommit?.substr(0, 10); }, }, methods: { @@ -72,11 +66,11 @@ export default { data-testid="error-count-card" > <template #header> - <span>{{ __('Events') }}</span> + {{ __('Events') }} </template> <template #default> - <span>{{ error.count }}</span> + {{ error.count }} </template> </gl-card> @@ -87,61 +81,66 @@ export default { data-testid="user-count-card" > <template #header> - <span>{{ __('Users') }}</span> + {{ __('Users') }} </template> <template #default> - <span>{{ error.userCount }}</span> + {{ error.userCount }} </template> </gl-card> <gl-card - v-if="error.firstReleaseVersion" + v-if="error.firstSeen" :class="$options.CARD_CLASS" :body-class="$options.BODY_CLASS" :header-class="$options.HEADER_CLASS" data-testid="first-release-card" > <template #header> - <gl-icon v-gl-tooltip :title="shortFirstReleaseVersion" name="commit" class="gl-mr-1" /> - <span>{{ __('First seen') }}</span> + {{ __('First seen') }} </template> - <template #default> - <gl-link v-if="error.integrated" :href="firstCommitLink" class="gl-font-lg"> - <time-ago-tooltip :time="error.firstSeen" /> - </gl-link> + <template v-if="error.integrated" #default> + <time-ago-tooltip :time="error.firstSeen" /> + <span v-if="shortFirstReleaseVersion" class="gl-font-sm gl-text-secondary"> + <gl-icon name="commit" class="gl-mr-1" :size="12" />{{ shortFirstReleaseVersion }} + </span> + </template> - <gl-link v-else :href="firstReleaseLink" target="_blank" class="gl-font-lg"> + <template v-else #default> + <gl-link :href="firstReleaseLink" target="_blank" class="gl-font-lg"> <time-ago-tooltip :time="error.firstSeen" /> </gl-link> </template> </gl-card> <gl-card - v-if="error.lastReleaseVersion" + v-if="error.lastSeen" :class="$options.CARD_CLASS" :body-class="$options.BODY_CLASS" :header-class="$options.HEADER_CLASS" data-testid="last-release-card" > <template #header> - <gl-icon v-gl-tooltip :title="shortLastReleaseVersion" name="commit" class="gl-mr-1" /> {{ __('Last seen') }} </template> - <template #default> - <gl-link v-if="error.integrated" :href="lastCommitLink" class="gl-font-lg"> - <time-ago-tooltip :time="error.lastSeen" /> - </gl-link> - <gl-link v-else :href="lastReleaseLink" target="_blank" class="gl-font-lg"> + <template v-if="error.integrated" #default> + <time-ago-tooltip :time="error.lastSeen" /> + <span v-if="shortLastReleaseVersion" class="gl-font-sm gl-text-secondary"> + <gl-icon name="commit" class="gl-mr-1" :size="12" />{{ shortLastReleaseVersion }} + </span> + </template> + + <template v-else #default> + <gl-link :href="lastReleaseLink" target="_blank" class="gl-font-lg"> <time-ago-tooltip :time="error.lastSeen" /> </gl-link> </template> </gl-card> <gl-card - v-if="error.gitlabCommit" + v-if="!error.integrated && error.gitlabCommit" :class="$options.CARD_CLASS" :body-class="$options.BODY_CLASS" :header-class="$options.HEADER_CLASS" diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue index 6d4979ac785..40e175fab99 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue @@ -21,10 +21,8 @@ import { packageTypeToTrackCategory } from '~/packages_and_registries/package_re import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; import DependencyRow from '~/packages_and_registries/package_registry/components/details/dependency_row.vue'; import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue'; -import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue'; import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue'; import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue'; -import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue'; import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue'; import { PACKAGE_TYPE_NUGET, @@ -76,9 +74,13 @@ export default { PackageHistory, AdditionalMetadata, InstallationCommands, - PackageFiles, + PackageFiles: () => + import('~/packages_and_registries/package_registry/components/details/package_files.vue'), DeletePackages, - PackageVersionsList, + PackageVersionsList: () => + import( + '~/packages_and_registries/package_registry/components/details/package_versions_list.vue' + ), }, directives: { GlTooltip: GlTooltipDirective, diff --git a/app/models/user.rb b/app/models/user.rb index 1bd0dbd5d5f..5d31f9e54b4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2260,6 +2260,10 @@ class User < ApplicationRecord abuse_trust_scores.spamcheck.average(:score) || 0.0 end + def telesign_score + abuse_trust_scores.telesign.order(created_at: :desc).first&.score || 0.0 + end + def trust_scores_for_source(source) abuse_trust_scores.where(source: source) end diff --git a/doc/architecture/blueprints/organization/index.md b/doc/architecture/blueprints/organization/index.md index bd8d085413c..8eb367ddfc8 100644 --- a/doc/architecture/blueprints/organization/index.md +++ b/doc/architecture/blueprints/organization/index.md @@ -1,7 +1,7 @@ --- status: ongoing creation-date: "2023-04-05" -authors: [ "@lohrc" ] +authors: [ "@lohrc", "alexpooley" ] coach: "@ayufan" approvers: [ "@lohrc" ] owning-stage: "~devops::data stores" @@ -47,6 +47,7 @@ The Organization focuses on creating a better experience for Organizations to ma - Aggregation: Data from all groups and projects in an Organization can be aggregated. - An Organization includes settings, data, and features from all groups and projects under the same owner (including personal namespaces). - Cascading behavior: Organization cascades behavior to all the projects and groups that are owned by the same Organization. It can be decided at the Organization level whether a setting can be overridden or not on the levels beneath. +- Minimal burden on customers: The addition of Organizations should not change existing group and project paths to minimize the impact of URL changes. ### Non-Goals @@ -89,7 +90,7 @@ The Organization MVC will contain the following functionality: - Instance setting to allow the creation of multiple Organizations. This will be enabled by default on GitLab.com, and disabled for self-managed GitLab. - Every instance will have a default organization. Initially, all users will be managed by this default Organization. - Organization Owner. The creation of an Organization appoints that user as the Organization Owner. Once established, the Organization Owner can appoint other Organization Owners. -- Organization users. A user is managed by one Organization, but can be part of multiple Organizations. +- Organization users. A user is managed by one Organization, but can be part of multiple Organizations. Users are able to navigate between the different Organizations they are part of. - Setup settings. Containing the Organization name, ID, description, README, and avatar. Settings are editable by the Organization Owner. - Setup flow. Users are able to build an Organization on top of an existing top-level group. New users are able to create an Organization from scratch and to start building top-level groups from there. - Visibility. Options will be `public` and `private`. A nonuser of a specific Organization will not see private Organizations in the explore section. Visibility is editable by the Organization Owner. @@ -107,10 +108,10 @@ Organization Users can get access to groups and projects as: - A project member: this grants access to the project, and limited access to parent groups, regardless of their visibility. - A non-member: this grants access to public and internal groups and projects of that Organization. To access a private group or project in an Organization, a user must become a member. -Organization Users can be managed by the Organization as: +Organization Users can be managed in the following ways: -- Enterprise Users, managed by the Organization. This includes control over their user account and the ability to block the user. -- Non-Enterprise Users, managed by the User. Non-Enterprise Users can be removed from an Organization, but their user account remains in their control. +- As [Enterprise Users](../../../user/enterprise_user/index.md), managed by the Organization. This includes control over their user account and the ability to block the user. +- As Non-Enterprise Users, managed by the Default Organization. Non-Enterprise Users can be removed from an Organization, but the user keeps ownership of their user account. Enterprise Users are only available to Organizations with a Premium or Ultimate subscription. Organizations on the free tier will only be able to host Non-Enterprise Users. @@ -118,6 +119,10 @@ Enterprise Users are only available to Organizations with a Premium or Ultimate Non-users are external to the Organization and can only access the public resources of an Organization, such as public projects. +### Routing + +Today only users, projects, namespaces and container images are considered routable entities which require global uniqueness on `https://gitlab.com/<path>/-/`. Initially, Organization routes will be [unscoped](../../../development/routing.md). Organizations will follow the path `https://gitlab.com/-/organizations/org-name/` as one of the design goals is that the addition of Organizations should not change existing group and project paths. + ## Iteration Plan The following iteration plan outlines how we intend to arrive at the Organization MVC. We are following the guidelines for [Experiment, Beta, and Generally Available features](../../../policy/alpha-beta-support.md). @@ -161,6 +166,7 @@ After the initial rollout of Organizations, the following functionality will be 1. Cascading Organization setting to enforce security scans. 1. Scan result policies at the Organization level. 1. Compliance frameworks. +1. [Support the agent for Kubernetes sharing at the Organization level](https://gitlab.com/gitlab-org/gitlab/-/issues/382731). ## Alternative Solutions @@ -169,7 +175,10 @@ An alternative approach to building Organizations is to convert top-level groups ## Decision Log - 2023-05-10: [Billing is not part of the Organization MVC](https://gitlab.com/gitlab-org/gitlab/-/issues/406614#note_1384055365) +- 2023-05-15: [Organization route setup](https://gitlab.com/gitlab-org/gitlab/-/issues/409913#note_1388679761) ## Links - [Organization epic](https://gitlab.com/groups/gitlab-org/-/epics/9265) +- [Enterprise Users](../../../user/enterprise_user/index.md) +- [Cells blueprint](../cells/index.md) diff --git a/doc/ci/review_apps/img/review_apps_preview_in_mr.png b/doc/ci/review_apps/img/review_apps_preview_in_mr.png Binary files differdeleted file mode 100644 index 3e6506a6a3a..00000000000 --- a/doc/ci/review_apps/img/review_apps_preview_in_mr.png +++ /dev/null diff --git a/doc/ci/review_apps/img/review_apps_preview_in_mr_v16_0.png b/doc/ci/review_apps/img/review_apps_preview_in_mr_v16_0.png Binary files differnew file mode 100644 index 00000000000..40345b9987f --- /dev/null +++ b/doc/ci/review_apps/img/review_apps_preview_in_mr_v16_0.png diff --git a/doc/ci/review_apps/img/view_on_env_blob.png b/doc/ci/review_apps/img/view_on_env_blob.png Binary files differdeleted file mode 100644 index acc457fbb38..00000000000 --- a/doc/ci/review_apps/img/view_on_env_blob.png +++ /dev/null diff --git a/doc/ci/review_apps/img/view_on_env_mr.png b/doc/ci/review_apps/img/view_on_env_mr.png Binary files differdeleted file mode 100644 index 0e61814a65d..00000000000 --- a/doc/ci/review_apps/img/view_on_env_mr.png +++ /dev/null diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md index 004bd9dfc5f..f1646bee7d0 100644 --- a/doc/ci/review_apps/index.md +++ b/doc/ci/review_apps/index.md @@ -35,7 +35,7 @@ Access to the review app is made available as a link on the [merge request](../. The following is an example of a merge request with an environment set dynamically. -![review app in merge request](img/review_apps_preview_in_mr.png) +![review app in merge request](img/review_apps_preview_in_mr_v16_0.png) In this example, a branch was: @@ -185,13 +185,9 @@ After you have the route mapping set up, it takes effect in the following locati ![View app file list in merge request widget](img/view_on_mr_widget.png) -- In the diff for a comparison or commit. +- In the diff for a comparison or commit, by selecting **View** (**{external-link}**) next to the file. - ![View on environment button in merge request diff](img/view_on_env_mr.png) - -- In the blob file view. - - ![View on environment button in file view](img/view_on_env_blob.png) +- In the blob file view, by selecting **View** (**{external-link}**) next to the file. <!--- start_remove The following content will be removed on remove_date: '2024-05-22' --> ## Visual Reviews (deprecated) **(PREMIUM)** diff --git a/doc/development/labels/index.md b/doc/development/labels/index.md index 50b6ec74575..dfd2a9e4fd3 100644 --- a/doc/development/labels/index.md +++ b/doc/development/labels/index.md @@ -194,6 +194,8 @@ The current department labels are: - `~"UX"` - `~"Quality"` +- `~"infrastructure"` +- `~"security"` ## Team labels @@ -206,8 +208,10 @@ people. The current team labels are: -- `~"Delivery"~` +- `~"Delivery"` - `~"Technical Writing"` +- `~"Engineering Productivity"` +- `~"Contributor Success"` ### Naming and color convention diff --git a/doc/user/enterprise_user/index.md b/doc/user/enterprise_user/index.md index ffeaaa8c591..8cebdf2749d 100644 --- a/doc/user/enterprise_user/index.md +++ b/doc/user/enterprise_user/index.md @@ -43,11 +43,18 @@ Prerequisites: - A custom domain name `example.com` or subdomain `subdomain.example.com`. - Access to your domain's server control panel to set up a DNS `TXT` record to verify your domain's ownership. +- A project in the group. +- You must have the Owner role in the top-level group. Setting up a verified domain is similar to [setting up a custom domain on GitLab Pages](../project/pages/custom_domains_ssl_tls_certification/index.md). However, you must: -- Link the domain to a project. For more information on group-level domain verification, see [issue 5299](https://gitlab.com/groups/gitlab-org/-/epics/5299). -- Configure the DNS `TXT` record to verify the domain's ownership. +- Link the domain to a single project. +- Configure the `TXT` only in the DNS record to verify the domain's ownership. + +Domain verification is tied to the project you choose. A project is required because domain verification reuses the GitLab Pages verification feature, which requires a project. Domain verification applies at the top-level group and to all subgroups and projects nested under that top-level parent group. +A member in the chosen project with [at least the Maintainer role](../permissions.md#project-members-permissions) can modify or remove the domain verification. +If needed, you can create a new project to set up domain verification directly under your top-level group. This limits the ability to modify the domain verification to members with at least the Maintainer role. +For more information on group-level domain verification, see [epic 5299](https://gitlab.com/groups/gitlab-org/-/epics/5299). Steps: diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md index c330e39533e..871174d3281 100644 --- a/doc/user/group/manage.md +++ b/doc/user/group/manage.md @@ -646,7 +646,7 @@ Support for group-level settings for merge request approval rules is tracked in WARNING: This feature is in [Beta](../../policy/alpha-beta-support.md#beta). Code Suggestions use generative AI to suggest code while you're developing. -Due to high demand, this feature will have unscheduled downtime and code suggestions in VS Code may be delayed. +Due to high demand, this feature may have unscheduled downtime and code suggestions in VS Code may be delayed. Code Suggestions may produce [low-quality or incomplete suggestions](../project/repository/code_suggestions.md#model-accuracy-and-quality). Beta users should read about the [known limitations](../project/repository/code_suggestions.md#known-limitations). @@ -656,6 +656,8 @@ This setting enables users in the group to access [Code Suggestions](../project/ This setting [cascades to all projects](../project/merge_requests/approvals/settings.md#settings-cascading) that belong to the group. +However, each user can enable or disable Code Suggestions for themselves. + To enable Code Suggestions for a group: 1. On the top bar, select **Main menu > Groups** and find your group. diff --git a/doc/user/project/merge_requests/approvals/img/approvals_premium_mr_widget_16_0.png b/doc/user/project/merge_requests/approvals/img/approvals_premium_mr_widget_16_0.png Binary files differnew file mode 100644 index 00000000000..727dac0916b --- /dev/null +++ b/doc/user/project/merge_requests/approvals/img/approvals_premium_mr_widget_16_0.png diff --git a/doc/user/project/merge_requests/approvals/img/approvals_premium_mr_widget_v13_3.png b/doc/user/project/merge_requests/approvals/img/approvals_premium_mr_widget_v13_3.png Binary files differdeleted file mode 100644 index 306bf57354d..00000000000 --- a/doc/user/project/merge_requests/approvals/img/approvals_premium_mr_widget_v13_3.png +++ /dev/null diff --git a/doc/user/project/merge_requests/approvals/rules.md b/doc/user/project/merge_requests/approvals/rules.md index d55ca5dff04..3a6ce48d071 100644 --- a/doc/user/project/merge_requests/approvals/rules.md +++ b/doc/user/project/merge_requests/approvals/rules.md @@ -104,7 +104,7 @@ supports multiple default rules: When an [eligible approver](#eligible-approvers) approves a merge request, it reduces the number of approvals left (the **Approvals** column) for all rules that the approver belongs to: -![Approvals premium merge request widget](img/approvals_premium_mr_widget_v13_3.png) +![Approvals premium merge request widget](img/approvals_premium_mr_widget_16_0.png) <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> For an overview, see [Multiple Approvers](https://www.youtube.com/watch?v=8JQJ5821FrA). diff --git a/doc/user/project/repository/branches/img/delete_merged_branches.png b/doc/user/project/repository/branches/img/delete_merged_branches.png Binary files differdeleted file mode 100644 index 649a758b95f..00000000000 --- a/doc/user/project/repository/branches/img/delete_merged_branches.png +++ /dev/null diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md index 7c09ce5c580..05494789b83 100644 --- a/doc/user/project/repository/branches/index.md +++ b/doc/user/project/repository/branches/index.md @@ -244,15 +244,22 @@ To compare branches in a repository: ## Delete merged branches -![Delete merged branches](img/delete_merged_branches.png) +Merged branches can be deleted in bulk if they meet all of these criteria: -This feature allows merged branches to be deleted in bulk. Only branches that -have been merged into the project's default branch and -[are not protected](../../protected_branches.md) are deleted as part of -this operation. +- They are not [protected branches](../../protected_branches.md). +- They have been merged into the project's default branch. -It's particularly useful to clean up old branches that were not deleted -automatically when a merge request was merged. +Prerequisites: + +- You must have at least the Developer role in the project. + +To do this: + +1. On the top bar, select **Main menu > Projects** and find your project. +1. On the left sidebar, select **Repository > Branches**. +1. On the upper right corner of the page, select **More** **{ellipsis_v}**. +1. Select **Delete merged branches**. +1. In the modal window, enter the word `delete` to confirm, then select **Delete merged branches**. ## Related topics diff --git a/doc/user/project/repository/code_suggestions.md b/doc/user/project/repository/code_suggestions.md index 5e79f33542a..c3d29261f07 100644 --- a/doc/user/project/repository/code_suggestions.md +++ b/doc/user/project/repository/code_suggestions.md @@ -56,11 +56,25 @@ We are making improvements to the Code Suggestions underlying AI model weekly to Usage of Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/). Learn about [data usage when using Code Suggestions](#code-suggestions-data-usage). +## Enable Code Suggestions for an individual user + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1 as [Beta](/ee/policy/alpha-beta-support.md#beta). + +Each user can enable Code Suggestions for themselves: + +1. On the top bar, in the upper-right corner, select your avatar. +1. On the left sidebar, select **Preferences**. +1. In the **Code Suggestions** section, enable the setting. + +NOTE: +If Code Suggestions is [enabled for the group](../../group/manage.md#group-code-suggestions), the group setting overrides the user setting. + ## Enable Code Suggestions in VS Code Prerequisites: - Your group owner must enable the [group level code suggestions setting](../../group/manage.md#group-code-suggestions). +- Code Suggestions must be [enabled for your user account](#enable-code-suggestions-for-an-individual-user). - If using a [personal access token](../../profile/personal_access_tokens.md#create-a-personal-access-token), the token must have the `read_api` and `read_user` scopes. To enable Code Suggestions in VS Code: diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8f709205234..d06749ed65f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1913,6 +1913,9 @@ msgstr "" msgid "AI|Something went wrong. Please try again later" msgstr "" +msgid "AI|Text generated by AI" +msgstr "" + msgid "AI|The container element wasn't found, stopping AI Genie." msgstr "" @@ -44497,8 +44500,10 @@ msgstr "" msgid "TanukiBot|Give feedback" msgstr "" -msgid "TanukiBot|Sources" -msgstr "" +msgid "TanukiBot|Source" +msgid_plural "TanukiBot|Sources" +msgstr[0] "" +msgstr[1] "" msgid "TanukiBot|There was an error communicating with GitLab Chat. Please try again later." msgstr "" @@ -46107,7 +46112,7 @@ msgstr "" msgid "This feature requires local storage to be enabled" msgstr "" -msgid "This field is auto-calculated based on the Progress score of its direct children. You can overwrite this value but it will be replaced by the auto-calcualtion anytime the Progress score of its direct children is updated." +msgid "This field is auto-calculated based on the Progress score of its direct children. You can overwrite this value but it will be replaced by the auto-calculation anytime the Progress score of its direct children is updated." msgstr "" msgid "This field is required" diff --git a/spec/frontend/error_tracking/components/error_details_info_spec.js b/spec/frontend/error_tracking/components/error_details_info_spec.js index 4a741a4c31e..a3f4b0e0dd8 100644 --- a/spec/frontend/error_tracking/components/error_details_info_spec.js +++ b/spec/frontend/error_tracking/components/error_details_info_spec.js @@ -40,43 +40,45 @@ describe('ErrorDetails', () => { }); it('should render a card with error counts', () => { - expect(wrapper.findByTestId('error-count-card').text()).toContain('Events 12'); + expect(wrapper.findByTestId('error-count-card').text()).toMatchInterpolatedText('Events 12'); }); it('should render a card with user counts', () => { - expect(wrapper.findByTestId('user-count-card').text()).toContain('Users 2'); + expect(wrapper.findByTestId('user-count-card').text()).toMatchInterpolatedText('Users 2'); }); - describe('release links', () => { - it('if firstReleaseVersion is missing, does not render a card', () => { + describe('first seen card', () => { + it('if firstSeen is missing, does not render a card', () => { + mountComponent({ + firstSeen: undefined, + }); expect(wrapper.findByTestId('first-release-card').exists()).toBe(false); }); - describe('if firstReleaseVersion link exists', () => { - it('renders the first release card', () => { - mountComponent({ - firstReleaseVersion: 'first-release-version', - }); - const card = wrapper.findByTestId('first-release-card'); - expect(card.exists()).toBe(true); - expect(card.text()).toContain('First seen'); - expect(card.findComponent(GlLink).exists()).toBe(true); - expect(card.findComponent(TimeAgoTooltip).exists()).toBe(true); + it('if firstSeen exists renders a card', () => { + mountComponent({ + firstSeen: '2017-05-26T13:32:48Z', }); + const card = wrapper.findByTestId('first-release-card'); + expect(card.exists()).toBe(true); + expect(card.text()).toContain('First seen'); + expect(card.findComponent(TimeAgoTooltip).exists()).toBe(true); + expect(card.findComponent(TimeAgoTooltip).props('time')).toBe('2017-05-26T13:32:48Z'); + }); - it('renders a link to the commit if error is integrated', () => { + describe('if firstReleaseVersion link exists', () => { + it('shows the shortened release tag as text, if error is integrated', () => { mountComponent({ - externalBaseUrl: 'external-base-url', firstReleaseVersion: 'first-release-version', firstSeen: '2023-04-20T17:02:06+00:00', integrated: true, }); - expect( - wrapper.findByTestId('first-release-card').findComponent(GlLink).attributes('href'), - ).toBe('external-base-url/-/commit/first-release-version'); + const card = wrapper.findByTestId('first-release-card'); + expect(card.text()).toMatchInterpolatedText('First seen first-rele'); + expect(card.findComponent(GlLink).exists()).toBe(false); }); - it('renders a link to the release if error is not integrated', () => { + it('renders a link to the release, if error is not integrated', () => { mountComponent({ externalBaseUrl: 'external-base-url', firstReleaseVersion: 'first-release-version', @@ -88,36 +90,40 @@ describe('ErrorDetails', () => { ).toBe('external-base-url/releases/first-release-version'); }); }); + }); - it('if lastReleaseVersion is missing, does not render a card', () => { + describe('last seen card', () => { + it('if lastSeen is missing, does not render a card', () => { + mountComponent({ + lastSeen: undefined, + }); expect(wrapper.findByTestId('last-release-card').exists()).toBe(false); }); - describe('if lastReleaseVersion link exists', () => { - it('renders the last release card', () => { - mountComponent({ - lastReleaseVersion: 'last-release-version', - }); - const card = wrapper.findByTestId('last-release-card'); - expect(card.exists()).toBe(true); - expect(card.text()).toContain('Last seen'); - expect(card.findComponent(GlLink).exists()).toBe(true); - expect(card.findComponent(TimeAgoTooltip).exists()).toBe(true); + it('if lastSeen exists renders a card', () => { + mountComponent({ + lastSeen: '2017-05-26T13:32:48Z', }); + const card = wrapper.findByTestId('last-release-card'); + expect(card.exists()).toBe(true); + expect(card.text()).toContain('Last seen'); + expect(card.findComponent(TimeAgoTooltip).exists()).toBe(true); + expect(card.findComponent(TimeAgoTooltip).props('time')).toBe('2017-05-26T13:32:48Z'); + }); - it('renders a link to the commit if error is integrated', () => { + describe('if lastReleaseVersion link exists', () => { + it('shows the shortened release tag as text, if error is integrated', () => { mountComponent({ - externalBaseUrl: 'external-base-url', lastReleaseVersion: 'last-release-version', lastSeen: '2023-04-20T17:02:06+00:00', integrated: true, }); - expect( - wrapper.findByTestId('last-release-card').findComponent(GlLink).attributes('href'), - ).toBe('external-base-url/-/commit/last-release-version'); + const card = wrapper.findByTestId('last-release-card'); + expect(card.text()).toMatchInterpolatedText('Last seen last-relea'); + expect(card.findComponent(GlLink).exists()).toBe(false); }); - it('renders a link to the release if error is integrated', () => { + it('renders a link to the release, if error is not integrated', () => { mountComponent({ externalBaseUrl: 'external-base-url', lastReleaseVersion: 'last-release-version', diff --git a/spec/frontend/repository/components/table/index_spec.js b/spec/frontend/repository/components/table/index_spec.js index f7be367887c..a89a107b68f 100644 --- a/spec/frontend/repository/components/table/index_spec.js +++ b/spec/frontend/repository/components/table/index_spec.js @@ -1,11 +1,24 @@ +import Vue, { nextTick } from 'vue'; +import VueApollo from 'vue-apollo'; import { GlSkeletonLoader, GlButton } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; -import { nextTick } from 'vue'; import Table from '~/repository/components/table/index.vue'; import TableRow from '~/repository/components/table/row.vue'; +import refQuery from '~/repository/queries/ref.query.graphql'; +import createMockApollo from 'helpers/mock_apollo_helper'; -let vm; -let $apollo; +let wrapper; + +const createMockApolloProvider = (ref) => { + Vue.use(VueApollo); + const apolloProver = createMockApollo([]); + apolloProver.clients.defaultClient.cache.writeQuery({ + query: refQuery, + data: { ref, escapedRef: ref }, + }); + + return apolloProver; +}; const MOCK_BLOBS = [ { @@ -70,8 +83,15 @@ const MOCK_COMMITS = [ }, ]; -function factory({ path, isLoading = false, hasMore = true, entries = {}, commits = [] }) { - vm = shallowMount(Table, { +function factory({ + path, + isLoading = false, + hasMore = true, + entries = {}, + commits = [], + ref = 'main', +}) { + wrapper = shallowMount(Table, { propsData: { path, isLoading, @@ -79,13 +99,11 @@ function factory({ path, isLoading = false, hasMore = true, entries = {}, commit hasMore, commits, }, - mocks: { - $apollo, - }, + apolloProvider: createMockApolloProvider(ref), }); } -const findTableRows = () => vm.findAllComponents(TableRow); +const findTableRows = () => wrapper.findAllComponents(TableRow); describe('Repository table component', () => { it.each` @@ -94,14 +112,10 @@ describe('Repository table component', () => { ${'app/assets'} | ${'main'} ${'/'} | ${'test'} `('renders table caption for $ref in $path', async ({ path, ref }) => { - factory({ path }); - - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - vm.setData({ ref }); + factory({ path, ref }); await nextTick(); - expect(vm.find('.table').attributes('aria-label')).toEqual( + expect(wrapper.find('.table').attributes('aria-label')).toEqual( `Files, directories, and submodules in the path ${path} for commit reference ${ref}`, ); }); @@ -109,7 +123,7 @@ describe('Repository table component', () => { it('shows loading icon', () => { factory({ path: '/', isLoading: true }); - expect(vm.findComponent(GlSkeletonLoader).exists()).toBe(true); + expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true); }); it('renders table rows', () => { @@ -152,7 +166,7 @@ describe('Repository table component', () => { }); describe('Show more button', () => { - const showMoreButton = () => vm.findComponent(GlButton); + const showMoreButton = () => wrapper.findComponent(GlButton); it.each` hasMore | expectButtonToExist @@ -170,7 +184,7 @@ describe('Repository table component', () => { await nextTick(); - expect(vm.emitted('showMore')).toHaveLength(1); + expect(wrapper.emitted('showMore')).toHaveLength(1); }); }); }); diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d5c7ed59d6a..f5b274301ca 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -7760,4 +7760,26 @@ RSpec.describe User, feature_category: :user_profile do end end end + + describe '#telesign_score' do + let_it_be(:user1) { create(:user) } + let_it_be(:user2) { create(:user) } + + context 'when the user has a telesign risk score' do + before do + create(:abuse_trust_score, user: user1, score: 12.0, source: :telesign) + create(:abuse_trust_score, user: user1, score: 24.0, source: :telesign) + end + + it 'returns the latest score' do + expect(user1.telesign_score).to be(24.0) + end + end + + context 'when the user does not have a telesign risk score' do + it 'defaults to zero' do + expect(user2.telesign_score).to be(0.0) + end + end + end end |