Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-11-07 12:14:08 +00:00
parent 2d33993941
commit da1268042d
30 changed files with 553 additions and 67 deletions

View File

@ -1145,7 +1145,7 @@ lib/gitlab/checks/**
/doc/user/project/repository/code_suggestions/ @jglassman1
/doc/user/project/repository/files/index.md @ashrafkhamis
/doc/user/project/repository/monorepos/ @eread
/doc/user/project/repository/web_editor.md @ashrafkhamis
/doc/user/project/repository/web_editor.md @brendan777
/doc/user/project/requirements/ @msedlakjakubowski
/doc/user/project/service_desk/ @msedlakjakubowski
/doc/user/project/settings/import_export.md @ashrafkhamis

View File

@ -0,0 +1,147 @@
# Test case name: TC-XX-## <!-- Example: TC-MH-1 -->
## Test case scenario
_Describe the test scenario this task corresponds to_
<!-- Example: New customer buys new SaaS Premium subscription via CDot between April 3, 2023 and April 2, 2024. -->
<table>
<tr>
<th>Deal Type (select everything that applies)</th>
<th>Product Type (select everything that applies)</th>
<th>Product Tier</th>
<th>Deal Term (months)</th>
<th>Ramped segments</th>
<th>Initial Purchase Discounted?</th>
<th>Purchase Method</th>
<th>Purchase Path</th>
</tr>
<tr>
<td>
<ul>
<li>- [ ] New</li>
<li>- [ ] Add-on (Storage, CI minutes)</li>
<li>- [ ] Add seats</li>
<li>- [ ] Manual renewal</li>
<li>- [ ] Auto-renewal</li>
<li>- [ ] Upgrade</li>
<li>- [ ] Cancellation</li>
<li>- [ ] First order</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] SaaS</li>
<li>- [ ] Self-managed</li>
<li>- [ ] True-up</li>
<li>- [ ] Add-on (Storage, CI minutes)</li>
<li>- [ ] Extra seats</li>
<li>- [ ] Professional services only</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] Premium</li>
<li>- [ ] Ultimate</li>
<li>- [ ] Premium > Ultimate (upgrade)</li>
<li>- [ ] Legacy Premium</li>
<li>- [ ] Legacy Ultimate</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] 12</li>
<li>- [ ] 24</li>
<li>- [ ] 36</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] Non-Ramp</li>
<li>- [ ] 2</li>
<li>- [ ] 3</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] Yes</li>
<li>- [ ] No</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] Web store</li>
<li>- [ ] Sales-assisted</li>
<li>- [ ] Automated</li>
</ul>
</td>
<td>
<ul>
<li>- [ ] Direct</li>
<li>- [ ] Partner</li>
</ul>
</td>
</tr>
</table>
## Artifacts
_Add various artifacts for this test scenario for reference_
1. Account (SFDC):
1. Opportunity (SFDC):
1. Quote (SFDC):
1. Order form (SFDC):
1. Subscription (Zuora):
1. Test case dependency (if any):
## Test steps
_List the steps to be performed to verify this scenario_
<!-- Example:
1. **GitLab.com:**: Purchase a subscription for a group
2. **CustomersDot:** Visit Customers Portal at http://customers.staging.gitlab.com
3. **CustomersDot:** Verify subscription details for purchased subscription
-->
## Expected result
_Describe the expected outcome of this test scenario_
### Screenshots
| Step | Screenshot |
|---|---|
| | |
<!--
You might want to create a comment or a separate issue for each of the following items, to ensure sign-off from all departments:
- [ ] Deal Desk sign-off
- [ ] Billing sign-off
- [ ] Revenue sign-off
- [ ] Fulfillment sign-off
- [ ] Data sign-off
-->
/confidential
/label ~"devops::fulfillment" ~"section::fulfillment"
<!--
You might also want to add some of the following labels, or weight:
/label ~workflow::
/label ~estimation::
/label ~group::
/label ~Category:
/label ~maintenance::
/weight
-->

View File

@ -0,0 +1,117 @@
<!--
This Issue template is meant to provide guidance for User Acceptance Tests.
1. Create the Issue and assign a title referring to the tested feature.
1. Fill the below details when relevant.
-->
# User Acceptance Testing
# Summary
Manual testing for the <issue-link> feature.
# Pre-requisite
_Add any steps to be performed before end to end testing can begin_
- [ ] Set a milestone for the test session issue to inform all the DRIs about the upcoming testing session.
- [ ] System leaders identify a DRI to participate in the testing session.
- [ ] Completion of Staging Rollout issue ([example](https://gitlab.com/gitlab-org/customers-gitlab-com/-/issues/6202)).
- [ ] Ensure all testers have the right access/permissions in all our Staging applications (Zuora, Salesforce, CDot, etc) for testing purposes.
- [ ] Ensure all system DRIs have reviewed the new test scenarios and approved the changes.
- [ ] Sales Systems: `@handle`.
- [ ] Sales Ops: `@handle`.
- [ ] Enterprise Apps: `@handle`.
- [ ] Data: `@handle`.
- [ ] Billing: `@handle`.
- [ ] Revenue: `@handle`.
- [ ] Fulfillment: `@pm-handle` and `@em-handle`.
- [ ] Communicate an estimated time for the testing session to all the DRIs.
- [ ] **{-Enable feature flag:}** {feature-flag-name} on {environment-name}: [Feature flag rollout issue](<link to feature flag rollout issue>).
- [ ] Clear any caches.
# Useful Links
_Add any links that are helpful to carry out testing such as links to the flows involved, etc._
<!--
Example below:
1. [Zuora Staging](https://test.zuora.com/)
1. [Salesforce Staging](https://gitlab--test1.sandbox.my.salesforce.com)
-->
1. ...
# How to
1. Create a [**Task**](User%20Acceptance%20Test%20Task.md) for each scenario mentioned in the list.
- The Task holds each relevant Test Case for the scenario in its own section.
- Each section holds that case's testing outcome and artifacts. (E.g. screenshots, screen recordings, or text notes.)
1. Create a [**Test Case**](https://gitlab.com/gitlab-org/customers-gitlab-com/-/quality/test_cases) for each variation of the scenario, if one does not already exist. (E.g. testing across product tiers or user roles.)
- The Test Case outlines the testing scenario, the test steps involved, and the expected result.
- **Make sure to set the Test Case to be confidential if applicable when it's created**, as it might not be confidential by default.
1. Before testing a Task, assign yourself to it to avoid multiple people testing the same scenario.
1. **\[Optional\]** assign a tested Task to a PM for review.
- Use the `Task` comments section to discuss any unexpected behaviour and create follow-up Issue(s).
1. **\[Optional\]** A PM should sign-off the test scenario if everything looks good. The, close the Task, and mark it as complete in this issue.
1. Add [Bug(s)](#identified-bugs) and/or [Question(s)](#open-questions) to the corresponding sections below.
# Test Cases
<table>
<tr>
<th>Scenario #</th>
<th>Task</th>
<th>Test Case</th>
<th>Scenario</th>
<th>Expected Outcome</th>
<th>Product Sign-off</th>
<th>UX Sign-off</th>
</tr>
<tr>
<td>
</td>
<td>
</td>
<td>
</td>
<td>
</td>
<td>
</td>
<td>
</td>
<td>
</td>
</tr>
</table>
# Identified Bugs
| Bugs | Testing type (Automated/ Manual) | Resolution | MR | DRI |
|------|----------------------------------|------------|-----|-----|
| | | | | |
| Question | Related Test Case | Answer | DRI |
| -------- | ----------------- | -------| --- |
| _Summary of question here (can have link to discussion from comments)_ | _Test case link_ | _Final answer / resolution_ | _Person responsible for answering question_ |
## Sign-offs
_Once all scenarios have passed validation, stakeholders will provide final sign-off below_
- [ ] Sales Systems: `@handle`
- [ ] Sales Ops: `@handle`
- [ ] Enterprise Apps: `@handle`
- [ ] Data: `@handle`
- [ ] Billing: `@handle`
- [ ] Revenue: `@handle`
- [ ] Fulfillment: `@pm-handle` and `@em-handle`
/label ~"devops::fulfillment" ~"section::fulfillment"

View File

@ -151,7 +151,6 @@ Layout/EmptyLineAfterMagicComment:
- 'ee/app/serializers/ee/issue_entity.rb'
- 'ee/app/serializers/license_compliance/collapsed_comparer_entity.rb'
- 'ee/app/serializers/license_compliance/comparer_serializer.rb'
- 'ee/app/services/analytics/cycle_analytics/aggregator_service.rb'
- 'ee/app/services/arkose/blocked_users_report_service.rb'
- 'ee/app/services/audit_events/streaming/headers/base.rb'
- 'ee/app/services/audit_events/streaming/headers/destroy_service.rb'

View File

@ -287,7 +287,6 @@ Style/IfUnlessModifier:
- 'ee/app/serializers/ee/blob_entity.rb'
- 'ee/app/serializers/linked_epic_issue_entity.rb'
- 'ee/app/serializers/vulnerabilities/finding_serializer.rb'
- 'ee/app/services/analytics/cycle_analytics/aggregator_service.rb'
- 'ee/app/services/analytics/cycle_analytics/validations.rb'
- 'ee/app/services/app_sec/dast/pipelines/find_latest_service.rb'
- 'ee/app/services/app_sec/dast/profiles/build_config_service.rb'

View File

@ -199,7 +199,7 @@ export default {
this.contentEditor.setEditable(false);
this.contentEditor.eventHub.$emit(ALERT_EVENT, {
message: __(
'An error occurred while trying to render the content editor. Please try again.',
'An error occurred while trying to render the rich text editor. Please try again.',
),
variant: VARIANT_DANGER,
actionLabel: __('Retry'),

View File

@ -1,5 +1,6 @@
import { lowlight } from 'lowlight/lib/core';
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
import { Fragment } from '@tiptap/pm/model';
import { mergeAttributes, textblockTypeInputRule } from '@tiptap/core';
import { VueNodeViewRenderer } from '@tiptap/vue-2';
import languageLoader from '../services/code_block_language_loader';
@ -61,16 +62,17 @@ export default CodeBlockLowlight.extend({
tag: 'div.markdown-code-block',
skip: true,
},
{
tag: 'pre.js-syntax-highlight',
preserveWhitespace: 'full',
},
// Matches HTML generated by Banzai::Filter::SyntaxHighlightFilter,
// Banzai::Filter::MathFilter, Banzai::Filter::MermaidFilter,
// or Banzai::Filter::SuggestionFilter
{
tag: 'pre.code.highlight',
preserveWhitespace: 'full',
getContent(element, schema) {
return element.textContent
? Fragment.from(schema.text(element.textContent))
: Fragment.empty;
},
},
// Matches HTML generated by Banzai::Filter::MathFilter,
// after being transformed by ~/behaviors/markdown/render_math.js

View File

@ -36,7 +36,7 @@ class Analytics::CycleAnalytics::Aggregation < ApplicationRecord
self["last_#{mode}_run_at"] = Time.current
end
def reset_full_run_cursors
def complete
self.last_full_issues_id = nil
self.last_full_issues_updated_at = nil
self.last_full_merge_requests_id = nil

View File

@ -33,6 +33,10 @@ module Analytics
self.runtimes_in_seconds = (runtimes_in_seconds + [runtime]).last(STATS_SIZE_LIMIT)
self.processed_records = (self.processed_records + [processed_records]).last(STATS_SIZE_LIMIT)
end
def complete
self.last_completed_at = Time.current
end
end
end
end

View File

@ -323,7 +323,7 @@ class Member < ApplicationRecord
after_create :update_two_factor_requirement, unless: :invite?
after_create :create_organization_user_record
after_update :post_update_hook, unless: [:pending?, :importing?], if: :hook_prerequisites_met?
after_update :create_organization_user_record, if: :saved_change_to_user_id? # only occurs on invite acceptance
after_update :create_organization_user_record, if: :accepted_invite_or_request?
after_destroy :destroy_notification_setting
after_destroy :post_destroy_member_hook, unless: :pending?, if: :hook_prerequisites_met?
after_destroy :post_destroy_access_request_hook, if: [:request?, :hook_prerequisites_met?]
@ -777,11 +777,17 @@ class Member < ApplicationRecord
end
def create_organization_user_record
return if invite?
return if pending?
return if source.organization.blank?
Organizations::OrganizationUser.create_organization_record_for(user_id, source.organization_id)
end
def accepted_invite_or_request?
# `user_id` is nil for member invited through email and will be set once the user has created an account.
# `requested_at` is defined only while the membership access request is still pending.
saved_change_to_user_id? || saved_change_to_requested_at?
end
end
Member.prepend_mod_with('Member')

View File

@ -7,6 +7,8 @@ class Namespace::Detail < ApplicationRecord
validates :namespace, presence: true
validates :description, length: { maximum: 255 }
ignore_column :pending_delete, remove_with: '17.7', remove_after: '2024-11-22'
self.primary_key = :namespace_id
# This method should not be called directly. Instead, it is available on the namespace via delegation and should

View File

@ -59,12 +59,10 @@ module Groups
private
def mark_deleted
group.update_attribute(:pending_delete, true)
group.update_attribute(:deleted_at, Time.current)
end
def unmark_deleted
group.update_attribute(:pending_delete, false)
group.update_attribute(:deleted_at, nil)
end

View File

@ -0,0 +1,93 @@
---
stage: Fulfillment
group: Provision
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Assign GitLab Duo seats by using GraphQL
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** GitLab.com
Use the GraphQL API to assign GitLab Duo seats to users.
## Prerequisites
- You must have the Owner role for the group you want to assign seats to.
- You must have a personal access token with the `api` scope.
## Get the add-on purchase ID
To start, retrieve the purchase ID for the GitLab Duo add-on:
```graphql
query {
addOnPurchases (namespaceId: "gid://gitlab/Group/YOUR_NAMESPACE_ID")
{
name
purchasedQuantity
assignedQuantity
id
}
}
```
## Assign a GitLab Duo seat to specific users
Then assign seats to specific users:
```graphql
mutation {
userAddOnAssignmentBulkCreate(input: {
addOnPurchaseId: "gid://gitlab/GitlabSubscriptions::AddOnPurchase/YOUR_ADDON_PURCHASE_ID",
userIds: [
"gid://gitlab/User/USER_ID_1",
"gid://gitlab/User/USER_ID_2",
"gid://gitlab/User/USER_ID_3"
]
}) {
addOnPurchase {
id
name
assignedQuantity
purchasedQuantity
}
users {
nodes {
id
username
}
}
errors
}
}
```
## Use GraphiQL
You can use [GraphiQL](https://gitlab.com/-/graphql-explorer) to assign seats to users.
1. Copy the add-on purchase ID code excerpt.
1. Open GraphiQL.
1. In the left window, enter the query:
```graphql
query {
addOnPurchases (namespaceId: "gid://gitlab/Group/YOUR_NAMESPACE_ID")
{
name
purchasedQuantity
assignedQuantity
id
}
}
```
1. Select **Play**.
1. Repeat to assign a GitLab Duo seat to specific users.
## Related topics
- [GraphQL API Resources](reference/index.md)
- [GraphQL specific entities, like fragments and interfaces](https://graphql.org/learn/)

View File

@ -811,6 +811,44 @@ LLM models are constantly evolving, and GitLab needs to regularly update our AI
Provide a comprehensive guide for migrating AI models within GitLab.
#### Expected Duration
Model migrations typically follow these general timelines:
- **Simple Model Updates (Same Provider):** 2-3 weeks
- Example: Upgrading from Claude Sonnet 3.5 to 3.6
- Involves model validation, testing, and staged rollout
- Primary focus on maintaining stability and performance
- Can sometimes be expedited when urgent, but 2 weeks is standard
- **Complex Migrations:** 1-2 months (full milestone or longer)
- Example: Adding support for a new provider like AWS Bedrock
- Example: Major version upgrades with breaking changes (e.g., Claude 2 to 3)
- Requires significant API integration work
- May need infrastructure changes
- Extensive testing and validation required
#### Timeline Factors
Several factors can impact migration timelines:
- Current system stability and recent incidents
- Resource availability and competing priorities
- Complexity of behavioral changes in new model
- Scale of testing required
- Feature flag rollout strategy
#### Best Practices
- Always err on the side of caution with initial timeline estimates
- Use feature flags for gradual rollouts to minimize risk
- Plan for buffer time to handle unexpected issues
- Communicate conservative timelines externally while working to deliver faster
- Prioritize system stability over speed of deployment
NOTE:
While some migrations can technically be completed quickly, we typically plan for longer timelines to ensure proper testing and staged rollouts. This approach helps maintain system stability and reliability.
### Scope
Applicable to all AI model-related teams at GitLab. We currently only support using Anthropic and Google Vertex models, with plans to support AWS Bedrock models in the [future](https://gitlab.com/gitlab-org/gitlab/-/issues/498119).
@ -819,11 +857,39 @@ Applicable to all AI model-related teams at GitLab. We currently only support us
Before starting a model migration:
- Verify the new model is supported in our current AI-Gateway API specification
- Document any known behavioral changes or improvements in the new model
- Create an issue under the [AI Model Version Migration Initiative epic](https://gitlab.com/groups/gitlab-org/-/epics/15650) with the following:
- Label with `group::ai framework`
- Document any known behavioral changes or improvements in the new model
- Include any breaking changes or compatibility issues
- Reference any model provider documentation about the changes
- Verify the new model is supported in our current AI-Gateway API specification by:
- Check model definitions in AI Gateway:
- For LiteLLM models: `ai_gateway/models/v2/container.py`
- For Anthropic models: `ai_gateway/models/anthropic.py`
- For new providers: Create a new model definition file in `ai_gateway/models/`
- Verify model configurations:
- Model enum definitions
- Stop tokens
- Timeout settings
- Completion type (text or chat)
- Max token limits
- Testing the model locally in AI Gateway:
- Set up the [AI Gateway development environment](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist#how-to-run-the-server-locally)
- Configure the necessary API keys in your `.env` file
- Test the model using the Swagger UI at `http://localhost:5052/docs`
- If the model isn't supported, create an issue in the [AI Gateway repository](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist) to add support
- Review the provider's API documentation for any breaking changes:
- [Anthropic API Documentation](https://docs.anthropic.com/claude/reference/versions)
- [Google Vertex AI Documentation](https://cloud.google.com/vertex-ai/docs/reference)
- Ensure you have access to testing environments and monitoring tools
- Complete model evaluation using the [Prompt Library](https://gitlab.com/gitlab-org/modelops/ai-model-validation-and-research/ai-evaluation/prompt-library/-/blob/main/doc/how-to/run_duo_chat_eval.md)
NOTE:
Documentation of model changes is crucial for tracking the impact of migrations and helping with future troubleshooting. Always create an issue to track these changes before beginning the migration process.
### Migration Tasks
#### Migration Tasks for Anthropic Model
@ -858,11 +924,18 @@ The model selection logic should be implemented in:
#### Rollout Strategy
- Enable the feature flag for a small percentage of users/groups initially
- Monitor performance metrics and error rates
- Monitor performance metrics and error rates using:
- [Sidekiq Service dashboard](https://dashboards.gitlab.net/d/sidekiq-main/sidekiq-overview) for error ratios and response latency
- [AI Gateway metrics dashboard](https://dashboards.gitlab.net/d/ai-gateway-main/ai-gateway3a-overview?orgId=1) for gateway-specific metrics
- [AI Gateway logs](https://log.gprd.gitlab.net/app/r/s/zKEel) for detailed error investigation
- [Feature usage dashboard](https://log.gprd.gitlab.net/app/r/s/egybF) for adoption metrics
- [Periscope dashboard](https://app.periscopedata.com/app/gitlab/1137231/Ai-Features) for token usage and feature statistics
- Gradually increase the rollout percentage
- If issues arise, quickly disable the feature flag to rollback to the previous model
- Once stability is confirmed, remove the feature flag and make the migration permanent
For more details on monitoring during migrations, see the [Monitoring and Metrics](#monitoring-and-metrics) section below.
### Scope of Work
#### AI Features to Migrate

View File

@ -34,7 +34,7 @@ Each event is defined in a separate YAML file consisting of the following fields
| `introduced_by_url` | no | The URL to the merge request that introduced the event. |
| `distributions` | yes | The [distributions](https://handbook.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. Can be set to one or more of `ce` or `ee`. |
| `tiers` | yes | The [tiers](https://handbook.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/) where the tracked feature is available. Can be set to one or more of `free`, `premium`, or `ultimate`. |
| `additional_properties` | no | A list of additional properties that are sent with the event. Each record must have `description` field. Built-in properties are: `label` (string), `property` (string) and `value` (numeric). [Custom](quick_start.md#additional-properties) properties can be added if the built-in options are not sufficient. |
| `additional_properties` | no | A list of additional properties that are sent with the event. Each additional property must have a record entry with a `description` field. It is required to add all the additional properties that would be sent with the event in the event definition file. Built-in properties are: `label` (string), `property` (string) and `value` (numeric). [Custom](quick_start.md#additional-properties) properties can be added if the built-in options are not sufficient. |
### Example event definition

View File

@ -109,15 +109,18 @@ track_internal_event(
)
```
If you need to pass more than three additional properties, you can use the `additional_properties` hash with your custom keys:
If you need to pass more than the three built-in additional properties, you can use the `additional_properties` hash with your custom keys:
```ruby
track_internal_event(
"code_suggestion_accepted",
user: user,
additional_properties: {
# Built-in properties
label: editor_name,
property: suggestion_type,
value: suggestion_shown_duration
value: suggestion_shown_duration,
# Your custom properties
lang: 'ruby',
custom_key: 'custom_value'
}
@ -369,7 +372,7 @@ Sometimes we want to send internal events when the component is rendered or load
#### Additional properties
Additional properties can be passed when tracking events. They can be used to save additional data related to given event. It is possible to send a maximum of three additional properties with keys `label` (string), `property` (string) and `value`(numeric).
You can include additional properties with events to save additional data. When included you must define each additional property in the `additional_properties` field. It is possible to send the three built-in additional properties with keys `label` (string), `property` (string) and `value`(numeric) and [custom additional properties](quick_start.md#additional-properties) if the built-in properties are not sufficient.
NOTE:
Do not pass the page URL or page path as an additional property because we already track the pseudonymized page URL for each event.

View File

@ -42,6 +42,7 @@ Git includes a complete set of [traces for debugging Git commands](https://git-s
- `GIT_TRACE_PERFORMANCE=1`: enables tracing of performance data, showing how long each particular `git` invocation takes.
- `GIT_TRACE_SETUP=1`: enables tracing of what `git` is discovering about the repository and environment it's interacting with.
- `GIT_TRACE_PACKET=1`: enables packet-level tracing for network operations.
- `GIT_CURL_VERBOSE=1`: enables `curl`'s verbose output, which [may include credentials](https://curl.se/docs/manpage.html#-v).
## Broken pipe errors on `git push`

View File

@ -1,6 +1,6 @@
---
stage: Create
group: Remote Development
group: Source Code
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
description: "Use the Web Editor to create, upload, and edit text files directly in the GitLab UI."
---

View File

@ -6187,7 +6187,7 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
msgid "An error occurred while trying to render the content editor. Please try again."
msgid "An error occurred while trying to render the rich text editor. Please try again."
msgstr ""
msgid "An error occurred while trying to run a new pipeline for this merge request."

View File

@ -48,7 +48,7 @@ describe('content_editor/components/bubble_menus/code_block_bubble_menu', () =>
const preTag = ({ language, content = 'test' } = {}) => {
const languageAttr = language ? ` data-canonical-lang="${language}"` : '';
return `<pre class="js-syntax-highlight"${languageAttr}>${content}</pre>`;
return `<pre class="code highlight js-syntax-highlight"${languageAttr}>${content}</pre>`;
};
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);

View File

@ -184,7 +184,7 @@ describe('ContentEditor', () => {
it('displays error alert indicating that the content editor failed to load', () => {
expect(findContentEditorAlert().text()).toContain(
'An error occurred while trying to render the content editor. Please try again.',
'An error occurred while trying to render the rich text editor. Please try again.',
);
});

View File

@ -4,6 +4,7 @@ import languageLoader from '~/content_editor/services/code_block_language_loader
import { createTestEditor, triggerNodeInputRule } from '../test_utils';
const CODE_BLOCK_HTML = `<div class="gl-relative markdown-code-block js-markdown-code">&#x000A;<pre data-sourcepos="1:1-3:3" data-canonical-lang="javascript" class="code highlight js-syntax-highlight language-javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>&#x000A;<copy-code></copy-code>&#x000A;</div>`;
const EMPTY_CODE_BLOCK_HTML = `<div class="gl-relative markdown-code-block js-markdown-code">&#x000A;<pre class="code highlight js-syntax-highlight language-javascript" data-canonical-lang="js" data-sourcepos="1:1-2:3"><code></code></pre>&#x000A;&#x000A;</div>`;
jest.mock('~/content_editor/services/code_block_language_loader');
@ -52,6 +53,22 @@ describe('content_editor/extensions/code_block_highlight', () => {
});
});
it('correctly parses HTML with empty code block', () => {
tiptapEditor.commands.setContent(EMPTY_CODE_BLOCK_HTML);
expect(tiptapEditor.getJSON()).toEqual(
doc(
codeBlock(
{
language: 'js',
class: 'code highlight js-syntax-highlight language-javascript',
},
'',
),
).toJSON(),
);
});
describe.each`
inputRule
${'```'}

View File

@ -84,14 +84,14 @@ RSpec.describe Analytics::CycleAnalytics::Aggregation, type: :model, feature_cat
end
end
describe '#reset_full_run_cursors' do
describe '#complete' do
it 'resets all full run cursors to nil' do
aggregation.last_full_issues_id = 111
aggregation.last_full_issues_updated_at = Time.current
aggregation.last_full_merge_requests_id = 111
aggregation.last_full_merge_requests_updated_at = Time.current
aggregation.reset_full_run_cursors
aggregation.complete
expect(aggregation).to have_attributes(
last_full_issues_id: nil,

View File

@ -64,13 +64,9 @@ RSpec.describe Analytics::CycleAnalytics::StageAggregation, type: :model, featur
it_behaves_like 'has cursor fields', Issue
it_behaves_like 'has cursor fields', MergeRequest
describe '#refresh_last_run' do
it 'updates the run_at column' do
freeze_time do
aggregation.refresh_last_run
expect(aggregation.last_run_at).to eq(Time.current)
end
describe '#refresh_last_run', :freeze_time do
it 'updates last_run_at column' do
expect { aggregation.refresh_last_run }.to change { aggregation.last_run_at }.to(Time.current)
end
end
@ -85,5 +81,11 @@ RSpec.describe Analytics::CycleAnalytics::StageAggregation, type: :model, featur
)
end
end
describe '#complete', :freeze_time do
it 'updates last_completed_at column' do
expect { aggregation.complete }.to change { aggregation.last_completed_at }.to(Time.current)
end
end
end
end

View File

@ -1419,44 +1419,71 @@ RSpec.describe Member, feature_category: :groups_and_projects do
it_behaves_like 'does not create an organization_user entry'
end
context 'when member is an access request' do
let(:member) { create(:group_member, :access_request, source: group, user: user) }
it_behaves_like 'does not create an organization_user entry'
end
end
context 'when updating' do
context 'when member is an invite' do
let_it_be(:member, reload: true) { create(:group_member, :invited, source: group) }
shared_examples 'an action that creates an organization record after commit' do
it 'inserts new record on member creation' do
expect { commit_member }.to change { Organizations::OrganizationUser.count }.by(1)
expect(group.organization.user?(user)).to be(true)
end
context 'when accepting the invite' do
let_it_be(:user) { create(:user) }
context 'when organization does not exist' do
let_it_be(:member) { create(:group_member) }
subject(:commit_member) { member.accept_invite!(user) }
it_behaves_like 'does not create an organization_user entry'
end
end
it 'inserts new record on member creation' do
expect { commit_member }.to change { Organizations::OrganizationUser.count }.by(1)
expect(group.organization.user?(user)).to be(true)
context 'when member accept invite' do
let_it_be_with_reload(:member, reload: true) { create(:group_member, :invited, source: group) }
subject(:commit_member) { member.accept_invite!(user) }
it_behaves_like 'an action that creates an organization record after commit'
context 'when updating the organization_users is not successful' do
before do
allow(Organizations::OrganizationUser)
.to receive(:create_organization_record_for).once.and_raise(ActiveRecord::StatementTimeout)
end
context 'when updating the organization_users is not successful' do
before do
allow(Organizations::OrganizationUser)
.to receive(:create_organization_record_for).once.and_raise(ActiveRecord::StatementTimeout)
end
it 'rolls back the member creation' do
expect { commit_member }.to raise_error(ActiveRecord::StatementTimeout)
expect(group.organization.user?(user)).to be(false)
expect(member.reset.user).to be_nil
end
end
context 'when organization does not exist' do
let_it_be(:member) { create(:group_member) }
it_behaves_like 'does not create an organization_user entry'
it 'rolls back the member creation', :aggregate_failures do
expect { commit_member }.to raise_error(ActiveRecord::StatementTimeout)
expect(group.organization.user?(user)).to be(false)
expect(member.reset.user).to be_nil
end
end
end
context 'when updating a non user_id attribute' do
context "when member's access request is approved" do
let_it_be_with_reload(:member) { create(:group_member, :access_request, source: group, user: user) }
subject(:commit_member) { member.accept_request(@owner_user) }
it_behaves_like 'an action that creates an organization record after commit'
context 'when updating the organization_users is not successful' do
before do
allow(Organizations::OrganizationUser)
.to receive(:create_organization_record_for).once.and_raise(ActiveRecord::StatementTimeout)
end
it 'rolls back the member creation', :aggregate_failures do
expect { commit_member }.to raise_error(ActiveRecord::StatementTimeout)
expect(group.organization.user?(user)).to be(false)
expect(member.reset.requested_at).not_to be_nil
end
end
end
context 'when updating a non user_id/requested_at attribute' do
let_it_be(:member) { create(:group_member, :reporter, source: group) }
subject(:commit_member) { member.update!(access_level: GroupMember::DEVELOPER) }

View File

@ -671,8 +671,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
it { is_expected.to delegate_method(:token_expiry_notify_inherited).to(:namespace_settings) }
it { is_expected.to delegate_method(:token_expiry_notify_inherited=).to(:namespace_settings).with_arguments(:args) }
it { is_expected.to delegate_method(:add_creator).to(:namespace_details) }
it { is_expected.to delegate_method(:pending_delete).to(:namespace_details) }
it { is_expected.to delegate_method(:pending_delete=).to(:namespace_details).with_arguments(:args) }
it { is_expected.to delegate_method(:deleted_at).to(:namespace_details) }
it { is_expected.to delegate_method(:deleted_at=).to(:namespace_details).with_arguments(:args) }

View File

@ -183,7 +183,7 @@ RSpec.describe Server, feature_category: :service_ping do
await { Net::HTTP.new('localhost', port).options('/com.snowplowanalytics.snowplow/tp2') }
end
it 'applies the correct headers' do
it 'applies the correct headers', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/498779' do
expect(response.code).to eq('200')
expect(response.header['Access-Control-Allow-Credentials']).to eq('true')
expect(response.header['Access-Control-Allow-Headers']).to eq('Content-Type')
@ -194,7 +194,7 @@ RSpec.describe Server, feature_category: :service_ping do
describe 'GET /micro/good -> list tracked structured events' do
subject(:response) { await { Net::HTTP.get_response url_for("/micro/good") } }
it 'successfully returns tracked events' do
it 'successfully returns tracked events', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/498777' do
expect(response.code).to eq('200')
expect(response.body).to eq("[]")
end

View File

@ -88,7 +88,6 @@ RSpec.describe Groups::DestroyService, feature_category: :groups_and_projects do
shared_examples 'marks the group as delete' do |async|
it 'marks the group as deleted', :freeze_time do
expect(group).to receive(:update_attribute).with(:pending_delete, true)
expect(group).to receive(:update_attribute).with(:deleted_at, Time.current)
destroy_group(group, user, async)
@ -125,7 +124,6 @@ RSpec.describe Groups::DestroyService, feature_category: :groups_and_projects do
it 'unmarks the group as delete' do
expect { destroy_group(group, user, false) }.to raise_error(StandardError)
expect(group.pending_delete).to be_falsey
expect(group.deleted_at).to be_nil
end
end

View File

@ -102,7 +102,7 @@ module CycleAnalyticsHelpers
def create_value_stream_aggregation(namespace)
aggregation = Analytics::CycleAnalytics::Aggregation.safe_create_for_namespace(namespace)
Analytics::CycleAnalytics::AggregatorService.new(aggregation: aggregation).execute
Analytics::CycleAnalytics::NamespaceAggregatorService.new(aggregation: aggregation).execute
end
def select_group_and_custom_value_stream(group, custom_value_stream_name)

View File

@ -186,7 +186,7 @@ module ValueStreamsDashboardHelpers
end
end
Analytics::CycleAnalytics::DataLoaderService.new(group: project.group, model: Issue).execute
Analytics::CycleAnalytics::DataLoaderService.new(namespace: project.group, model: Issue).execute
end
def create_mock_merge_request_metrics(project)