Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2d33993941
commit
da1268042d
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
-->
|
||||
|
|
@ -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"
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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/)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
<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>
<copy-code></copy-code>
</div>`;
|
||||
const EMPTY_CODE_BLOCK_HTML = `<div class="gl-relative markdown-code-block js-markdown-code">
<pre class="code highlight js-syntax-highlight language-javascript" data-canonical-lang="js" data-sourcepos="1:1-2:3"><code></code></pre>

</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
|
||||
${'```'}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue