Skip to content
Snippets Groups Projects
Commit 22455f0a authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 2e86cd4d
No related branches found
No related tags found
No related merge requests found
Pipeline #1669561296 passed
Showing
with 445 additions and 73 deletions
5944b8220c7f7524f94b511ba120a8d05b4cb839
f016b0c3afd8c0807f3fdc9c833472194f972230
......@@ -87,7 +87,7 @@ export default {
},
dropzoneAllowList: ['.csv'],
docsLink: helpPagePath('user/project/import/_index', {
anchor: 'request-reassignment-by-using-a-csv-file',
anchor: 'reassign-contributions-and-memberships',
}),
i18n: {
description: s__(
......
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getExperiments(
$fullPath: ID!
$name: String
$orderBy: MlModelsOrderBy
$sort: SortDirectionEnum
$first: Int
$last: Int
$after: String
$before: String
) {
project(fullPath: $fullPath) {
id
mlExperiments(
name: $name
orderBy: $orderBy
sort: $sort
after: $after
before: $before
first: $first
last: $last
) {
count
nodes {
id
name
candidateCount
updatedAt
path
modelId
creator {
id
name
webUrl
avatarUrl
}
}
pageInfo {
...PageInfo
}
}
}
}
<script>
import {
GlAlert,
GlAvatar,
GlAvatarLink,
GlButton,
GlEmptyState,
GlKeysetPagination,
GlLink,
GlModalDirective,
GlTableLite,
} from '@gitlab/ui';
import { s__ } from '~/locale';
import { s__, sprintf } from '~/locale';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import ModelExperimentsHeader from '~/ml/experiment_tracking/components/model_experiments_header.vue';
import Pagination from '~/ml/experiment_tracking/components/pagination.vue';
import getExperimentsQuery from '~/ml/experiment_tracking/graphql/queries/get_experiments.query.graphql';
import { MLFLOW_USAGE_MODAL_ID } from '../constants';
const GRAPHQL_PAGE_SIZE = 20;
export default {
name: 'MlExperimentsIndexApp',
components: {
GlAlert,
GlAvatar,
GlAvatarLink,
GlButton,
GlEmptyState,
GlKeysetPagination,
GlLink,
GlTableLite,
ModelExperimentsHeader,
Pagination,
TimeAgoTooltip,
},
directives: {
......@@ -36,12 +43,8 @@ export default {
};
},
props: {
experiments: {
type: Array,
required: true,
},
pageInfo: {
type: Object,
projectPath: {
type: String,
required: true,
},
emptyStateSvgPath: {
......@@ -53,23 +56,89 @@ export default {
required: false,
default: '',
},
count: {
type: Number,
required: true,
},
apollo: {
experiments: {
query: getExperimentsQuery,
variables() {
return this.queryVariables;
},
update(data) {
return data?.project?.mlExperiments ?? [];
},
error(error) {
this.errorMessage = sprintf(
s__('MlModelRegistry|Failed to load experiments with error: %{error}'),
{ error: error.message },
);
Sentry.captureException(error);
},
skip() {
return this.skipQueries;
},
},
},
data() {
return {
experiments: [],
errorMessage: '',
skipQueries: false,
pageVariables: { first: GRAPHQL_PAGE_SIZE },
};
},
computed: {
hasExperiments() {
return this.experiments.length > 0;
pageInfo() {
return this.experiments?.pageInfo ?? {};
},
showExperimentsTable() {
return this.count;
},
showEmptyState() {
return this.experiments?.count === 0 && !this.isLoading;
},
tableItems() {
return this.experiments.map((exp) => ({
nameColumn: { name: exp.name, path: exp.path },
candidateCountColumn: exp.candidate_count,
creatorColumn: exp.user,
lastActivityColumn: exp.updated_at,
return this.items.map((exp) => ({
nameColumn: {
name: exp.name,
path: exp.path,
},
candidateCountColumn: exp.candidateCount,
creatorColumn: { ...exp.creator, iid: getIdFromGraphQLId(exp.creator.id) },
lastActivityColumn: exp.updatedAt,
}));
},
items() {
return this.experiments?.nodes ?? [];
},
count() {
return this.experiments?.count ?? 0;
},
isLoading() {
return this.$apollo.queries.experiments.loading;
},
queryVariables() {
return {
fullPath: this.projectPath,
first: GRAPHQL_PAGE_SIZE,
...this.pageVariables,
};
},
},
methods: {
nextPage() {
this.pageVariables = {
first: GRAPHQL_PAGE_SIZE,
last: null,
after: this.pageInfo.endCursor,
};
},
prevPage() {
this.pageVariables = {
first: null,
last: GRAPHQL_PAGE_SIZE,
before: this.pageInfo.startCursor,
};
},
},
i18n: {
createUsingMlflowLabel: s__('MlExperimentTracking|Create an experiment using MLflow'),
......@@ -96,7 +165,7 @@ export default {
<div>
<model-experiments-header :page-title="$options.i18n.titleLabel" :count="count" />
<template v-if="hasExperiments">
<template v-if="showExperimentsTable">
<gl-table-lite :items="tableItems" :fields="$options.tableFields">
<template #cell(nameColumn)="{ value: experiment }">
<gl-link :href="experiment.path">
......@@ -106,13 +175,13 @@ export default {
<template #cell(creatorColumn)="{ value: creator }">
<gl-avatar-link
v-if="creator"
:href="creator.path"
:href="creator.webUrl"
:title="creator.name"
class="js-user-link gl-text-subtle"
:data-user-id="creator.id"
:data-user-id="creator.iid"
>
<gl-avatar
:src="creator.avatar_url"
:src="creator.avatarUrl"
:size="16"
:entity-name="creator.name"
class="mr-2"
......@@ -125,10 +194,10 @@ export default {
</template>
</gl-table-lite>
<pagination v-if="hasExperiments" v-bind="pageInfo" />
<gl-keyset-pagination v-bind="pageInfo" @prev="prevPage" @next="nextPage" />
</template>
<gl-empty-state
v-else
v-if="showEmptyState"
:title="$options.i18n.emptyStateTitleLabel"
:svg-path="emptyStateSvgPath"
:svg-height="null"
......@@ -145,5 +214,8 @@ export default {
</gl-button>
</template>
</gl-empty-state>
<gl-alert v-if="errorMessage" variant="warning" :dismissible="false">
{{ errorMessage }}
</gl-alert>
</div>
</template>
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import MlExperimentsIndex from '~/ml/experiment_tracking/routes/experiments/index';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
Vue.use(VueApollo);
const initIndexMlExperiments = () => {
const element = document.querySelector('#js-project-ml-experiments-index');
......@@ -8,18 +11,19 @@ const initIndexMlExperiments = () => {
return undefined;
}
const { experiments, pageInfo, emptyStateSvgPath, mlflowTrackingUrl, count } = element.dataset;
const { projectPath, emptyStateSvgPath, mlflowTrackingUrl } = element.dataset;
const props = {
experiments: JSON.parse(experiments),
pageInfo: convertObjectPropsToCamelCase(JSON.parse(pageInfo)),
projectPath,
emptyStateSvgPath,
mlflowTrackingUrl,
count: parseInt(count, 10),
};
const apolloProvider = new VueApollo({ defaultClient: createDefaultClient() });
return new Vue({
el: element,
name: 'MlExperimentsIndexApp',
apolloProvider,
render(h) {
return h(MlExperimentsIndex, { props });
},
......
import { isLoggedIn } from '~/lib/utils/common_utils';
import { createAlert, VARIANT_INFO } from '~/alert';
import { __ } from '~/locale';
export function showForkSuggestionAlert(forkAndViewPath) {
const i18n = {
forkSuggestion: __(
"You can't edit files directly in this project. Fork this project and submit a merge request with your changes.",
),
fork: __('Fork'),
cancel: __('Cancel'),
};
const alert = createAlert({
message: i18n.forkSuggestion,
variant: VARIANT_INFO,
primaryButton: {
text: i18n.fork,
link: forkAndViewPath,
},
secondaryButton: {
text: i18n.cancel,
clickHandler: () => alert.dismiss(),
},
});
return alert;
}
/**
* Checks if the user can fork the project
* @param {Object} userPermissions - User permissions object
* @param {boolean} isUsingLfs - Whether the project is using LFS
* @returns {boolean}
*/
export const canFork = (userPermissions, isUsingLfs) => {
const { createMergeRequestIn, forkProject } = userPermissions;
return isLoggedIn() && !isUsingLfs && createMergeRequestIn && forkProject;
};
/**
* Checks if the fork suggestion should be shown for single file editor
* @param {Object} userPermissions - User permissions object
* @param {boolean} isUsingLfs - Whether the project is using LFS
* @param {boolean} canModifyBlob - Whether the user can modify the blob
* @returns {boolean}
*/
export const showSingleFileEditorForkSuggestion = (userPermissions, isUsingLfs, canModifyBlob) => {
return canFork(userPermissions, isUsingLfs) && !canModifyBlob;
};
/**
* Checks if the fork suggestion should be shown for Web IDE
* @param {Object} userPermissions - User permissions object
* @param {boolean} isUsingLfs - Whether the project is using LFS
* @param {boolean} canModifyBlobWithWebIde - Whether the user can modify the blob with Web IDE
* @returns {boolean}
*/
export const showWebIdeForkSuggestion = (userPermissions, isUsingLfs, canModifyBlobWithWebIde) => {
return canFork(userPermissions, isUsingLfs) && !canModifyBlobWithWebIde;
};
/**
* Checks if the fork suggestion should be shown
* @param {Object} userPermissions - User permissions object
* @param {boolean} isUsingLfs - Whether the project is using LFS
* @param {Object} blobInfo - blobInfo object, including canModifyBlob and canModifyBlobWithWebIde
* @returns {boolean}
*/
export const showForkSuggestion = (userPermissions, isUsingLfs, blobInfo) => {
return (
showSingleFileEditorForkSuggestion(userPermissions, isUsingLfs, blobInfo.canModifyBlob) ||
showWebIdeForkSuggestion(userPermissions, isUsingLfs, blobInfo.canModifyBlobWithWebIde)
);
};
......@@ -12,22 +12,13 @@ def keys
def payload
[
Rails.application.credentials.openid_connect_signing_key,
Gitlab::CurrentSettings.ci_jwt_signing_key,
cloud_connector_keys
].flatten.compact.map { |key_data| pem_to_jwk(key_data) }.uniq
end
def cloud_connector_keys
return unless Gitlab.ee?
CloudConnector::Keys.all_as_pem
end
def pem_to_jwk(key_data)
OpenSSL::PKey::RSA.new(key_data)
Gitlab::CurrentSettings.ci_jwt_signing_key
].compact.map do |key_data|
OpenSSL::PKey::RSA.new(key_data)
.public_key
.to_jwk
.slice(:kty, :kid, :e, :n)
.merge(use: 'sig', alg: 'RS256')
end
end
end
......@@ -398,6 +398,7 @@ def visible_attributes
:session_expire_delay,
:shared_runners_enabled,
:shared_runners_text,
:sign_in_restrictions,
:signup_enabled,
:silent_mode_enabled,
:slack_app_enabled,
......
......@@ -14,6 +14,8 @@ def initialize(only_ids: nil, exclude_ids: nil, preview: nil, user: nil, output_
@exclude_ids = parse_project_ids(exclude_ids)
@preview = !preview.blank?
@user = user
@success_count = 0
@failed_projects = []
@output_stream = output_stream
end
......@@ -25,6 +27,7 @@ def execute
migrate!
@output_stream.puts finish_message
@output_stream.puts summary_report
else
@output_stream.puts configuration_error_banner
end
......@@ -56,15 +59,19 @@ def migrate_project(project)
"Would have migrated project id: #{project.id}."
else
perform_migration!(project)
@success_count += 1
"Migrated project id: #{project.id}."
end
rescue StandardError => error
@failed_projects << project
"Error migrating project id: #{project.id}, error: #{error.message}"
end
def perform_migration!(project)
service = ::Ci::JobToken::AutopopulateAllowlistService.new(project, @user) # rubocop:disable CodeReuse/ServiceClass -- This class is not an ActiveRecord model
service.unsafe_execute!
::Ci::JobToken::AutopopulateAllowlistService # rubocop:disable CodeReuse/ServiceClass -- This class is not an ActiveRecord model
.new(project, @user)
.unsafe_execute!
end
def valid_configuration?
......@@ -93,6 +100,22 @@ def finish_message
end
end
def summary_report
return if preview_mode?
failure_count = @failed_projects.length
report_lines = []
report_lines << "Summary: \n"
report_lines << " #{@success_count} project(s) successfully migrated, #{failure_count} error(s) reported.\n"
if failure_count > 0
report_lines << " The following #{failure_count} project id(s) failed to migrate:\n"
report_lines << " #{@failed_projects.pluck(:id).join(', ')}" # rubocop:disable Database/AvoidUsingPluckWithoutLimit -- pluck limited by array size
end
report_lines.join
end
def preview_banner
banner("PREVIEW MODE ENABLED")
end
......
......@@ -27,8 +27,10 @@ def unsafe_execute!
ServiceResponse.success
rescue Ci::JobToken::AuthorizationsCompactor::Error => e
Gitlab::ErrorTracking.log_exception(e, { project_id: @project.id, user_id: @user.id })
ServiceResponse.error(message: e.message)
rescue StandardError => e
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, { project_id: @project.id, user_id: @user.id })
ServiceResponse.error(message: e)
end
def execute
......
......@@ -14,3 +14,4 @@
= render_if_exists 'shared/shared_runners_minutes_limit', project: project
= render 'projects/terraform_banner', project: project
= render 'projects/lfs_misconfiguration_banner', project: project
= render_if_exists 'projects/pages_deployments_limit_warning', project: project
......@@ -2,9 +2,7 @@
- page_title s_('MlExperimentTracking|Model experiments')
#js-project-ml-experiments-index{ data: {
experiments: experiments_as_data(@project, @experiments),
page_info: formatted_page_info(@page_info),
project_path: @project.full_path,
empty_state_svg_path: image_path('illustrations/status/status-new-md.svg'),
mlflow_tracking_url: mlflow_tracking_url(@project),
count: Ml::Experiment.count_for_project(@project),
} }
# frozen_string_literal: true
class AddLinkedResourcesWidgetToWorkItemTypes < Gitlab::Database::Migration[2.2]
include Gitlab::Database::MigrationHelpers::WorkItems::Widgets
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
milestone '17.9'
WORK_ITEM_TYPE_ENUM_VALUES = [0, 1, 4] # issue, incident, task
WIDGETS = [
{
name: 'LinkedResources',
widget_type: 27
}
]
def up
add_widget_definitions(type_enum_values: WORK_ITEM_TYPE_ENUM_VALUES, widgets: WIDGETS)
end
def down
remove_widget_definitions(type_enum_values: WORK_ITEM_TYPE_ENUM_VALUES, widgets: WIDGETS)
end
end
f43f98fded76d74380ba4243de7a4a071758b51f12b7309e70ee804f46e719ac
\ No newline at end of file
......@@ -18,28 +18,28 @@ DETAILS:
The following table shows the supported models along with their specific features and hardware requirements to help you select the model that best fits your infrastructure needs for optimal performance.
## Supported LLMs
## Supported models
Install one of the following GitLab-supported large language models (LLMs):
The following GitLab-supported large language models (LLMs) are generally available.
- Fully compatible: The model can likely handle the feature without any loss of quality.
- Largely compatible: The model supports the feature, but there might be compromises or limitations.
- Not compatible: The model is unsuitable for the feature, likely resulting in significant quality loss or performance issues.
<!-- vale gitlab_base.Spelling = NO -->
| Model family | Model | Supported platforms | Status | Code completion | Code generation | GitLab Duo Chat |
|--------------|-------|---------------------|--------|-----------------|-----------------|-----------------|
|Mistral Codestral | [Codestral 22B v0.1](https://huggingface.co/mistralai/Codestral-22B-v0.1) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) | Generally available | 🟢 Green | 🟢 Green | N/A |
| Mistral | [Mistral 7B-it v0.3](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.3) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) | Generally available | 🟢 Green | 🟢 Green | 🔴 Red |
| Mistral | [Mixtral 8x7B-it v0.1](https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) <br> [AWS Bedrock](https://aws.amazon.com/bedrock/mistral/) | Generally available | 🟢 Green | 🟢 Green | 🟡 Amber |
| Mistral | [Mixtral 8x22B-it v0.1](https://huggingface.co/mistralai/Mixtral-8x22B-Instruct-v0.1) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) | Generally available | 🟢 Green | 🟢 Green | 🟢 Green |
| Claude 3 | [Claude 3.5 Sonnet](https://www.anthropic.com/news/claude-3-5-sonnet) | [AWS Bedrock](https://aws.amazon.com/bedrock/claude/) | Generally available | 🟢 Green | 🟢 Green | 🟢 Green |
| GPT | [GPT-4 Turbo](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4) | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview) | Generally available | 🟢 Green | 🟢 Green | 🟡 Amber |
| GPT | [GPT-4o](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo) | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview) | Generally available | 🟢 Green | 🟢 Green | 🟢 Green |
| GPT | [GPT-4o-mini](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo) | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview) | Generally available | 🟢 Green | 🟢 Green | 🟡 Amber |
Legend:
- 🟢 Green - Fully compatible. The model can likely handle the feature without any loss of quality.
- 🟡 Amber - Largely compatible. The model supports the feature, but there might be compromises or limitations.
- 🔴 Red - Not compatible. The model is unsuitable for the feature, likely resulting in significant quality loss or performance issues.
| Model Family | Model | Supported Platforms | Code completion | Code generation | GitLab Duo Chat |
|-------------|-------|---------------------|-----------------|-----------------|-----------------|
| Mistral Codestral | [Codestral 22B v0.1](https://huggingface.co/mistralai/Codestral-22B-v0.1) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | N/A |
| Mistral | [Mistral 7B-it v0.3](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.3) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{dash-circle}** Not compatible |
| Mistral | [Mixtral 8x7B-it v0.1](https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments), [AWS Bedrock](https://aws.amazon.com/bedrock/mistral/) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{check-circle-dashed}** Limited compatibility |
| Mistral | [Mixtral 8x22B-it v0.1](https://huggingface.co/mistralai/Mixtral-8x22B-Instruct-v0.1) | [vLLM](supported_llm_serving_platforms.md#for-self-hosted-model-deployments) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{check-circle-dashed}** Limited compatibility |
| Claude 3 | [Claude 3.5 Sonnet](https://www.anthropic.com/news/claude-3-5-sonnet) | [AWS Bedrock](https://aws.amazon.com/bedrock/claude/) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible |
| GPT | [GPT-4 Turbo](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4) | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{check-circle-dashed}** Limited compatibility |
| GPT | [GPT-4o](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo) | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible |
| GPT | [GPT-4o-mini](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models?tabs=python-secure#gpt-4o-and-gpt-4-turbo) | [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview) | **{check-circle-filled}** Fully compatible | **{check-circle-filled}** Fully compatible | **{check-circle-dashed}** Limited compatibility |
### Experimental and beta models
The following models are configurable for the functionalities marked below, but are currently in experimental or beta status, under evaluation, and are excluded from the "Customer Integrated Models" definition in the [AI Functionality Terms](https://handbook.gitlab.com/handbook/legal/ai-functionality-terms/):
......
......@@ -66,6 +66,7 @@ Example response:
"default_preferred_language" : "en",
"failed_login_attempts_unlock_period_in_minutes": 30,
"restricted_visibility_levels" : [],
"sign_in_restrictions": {},
"password_authentication_enabled_for_web" : true,
"after_sign_out_path" : null,
"max_attachment_size" : 10,
......@@ -248,6 +249,7 @@ Example response:
]
},
"restricted_visibility_levels": [],
"sign_in_restrictions": {},
"max_attachment_size": 10,
"max_decompressed_archive_size": 25600,
"max_export_size": 50,
......@@ -660,6 +662,7 @@ to configure other related settings. These requirements are
| `sidekiq_job_limiter_compression_threshold_bytes` | integer | no | The threshold in bytes at which Sidekiq jobs are compressed before being stored in Redis. Default: 100,000 bytes (100 KB). |
| `sidekiq_job_limiter_limit_bytes` | integer | no | The threshold in bytes at which Sidekiq jobs are rejected. Default: 0 bytes (doesn't reject any job). |
| `signin_enabled` | string | no | (Deprecated: Use `password_authentication_enabled_for_web` instead) Flag indicating if password authentication is enabled for the web interface. |
| `sign_in_restrictions` | hash | no | Application sign in restrictions. |
| `signup_enabled` | boolean | no | Enable registration. Default is `true`. |
| `silent_admin_exports_enabled` | boolean | no | Enable [Silent admin exports](../administration/settings/import_and_export_settings.md#enable-silent-admin-exports). Default is `false`. |
| `silent_mode_enabled` | boolean | no | Enable [Silent mode](../administration/silent_mode/_index.md). Default is `false`. |
......
......@@ -2,14 +2,14 @@
stage: Tenant Scale
group: Cells Infrastructure
info: Analysis of Application Settings for Cells 1.0.
title: Application Settings analysis
---
# Application Settings analysis
## Statistics
- Number of attributes: 512
- Number of encrypted attributes: 41 (8.0%)
- Number of attributes documented: 311 (61.0%)
- Number of attributes documented: 312 (61.0%)
- Number of attributes on GitLab.com different from the defaults: 233 (46.0%)
- Number of attributes with `clusterwide` set: 512 (100.0%)
- Number of attributes with `clusterwide: true` set: 127 (25.0%)
......@@ -349,6 +349,7 @@ title: Application Settings analysis
| `plantuml_enabled` | `false` | `boolean` | `boolean` | `false` | `null` | `true` | `true`| `true` |
| `plantuml_url` | `false` | `character` | `string` | `false` | `null` | `true` | `true`| `true` |
| `polling_interval_multiplier` | `false` | `numeric` | `float` | `true` | `1.0` | `false` | `false`| `true` |
| `pre_receive_secret_detection_enabled` | `false` | `boolean` | `` | `true` | `false` | `false` | `true`| `false` |
| `prevent_merge_requests_author_approval` | `false` | `boolean` | `boolean` | `true` | `false` | `false` | `false`| `true` |
| `prevent_merge_requests_committers_approval` | `false` | `boolean` | `boolean` | `true` | `false` | `false` | `false`| `true` |
| `product_analytics_configurator_connection_string` | `true` | `bytea` | `` | `false` | `null` | `true` | `false`| `false` |
......@@ -409,7 +410,7 @@ title: Application Settings analysis
| `secret_detection_token_revocation_enabled` | `false` | `boolean` | `` | `true` | `false` | `true` | `false`| `false` |
| `secret_detection_token_revocation_token` | `true` | `text` | `` | `false` | `null` | `true` | `false`| `false` |
| `secret_detection_token_revocation_url` | `false` | `text` | `` | `false` | `null` | `true` | `false`| `false` |
| `secret_push_protection_available` | `false` | `boolean` | `boolean` | `true` | `false` | `true` | `true`| `true` |
| `secret_push_protection_available` | `false` | `boolean` | `boolean` | `false` | `false` | `true` | `true`| `true` |
| `security_approval_policies_limit` | `false` | `integer` | `integer` | `true` | `5` | `false` | `false`| `true` |
| `security_policies` | `false` | `jsonb` | `` | `true` | `'{}'::jsonb` | `true` | `false`| `false` |
| `security_policy_global_group_approvers_enabled` | `false` | `boolean` | `boolean` | `true` | `true` | `true` | `false`| `true` |
......@@ -430,7 +431,7 @@ title: Application Settings analysis
| `sidekiq_job_limiter_compression_threshold_bytes` | `false` | `integer` | `integer` | `true` | `100000` | `false` | `false`| `true` |
| `sidekiq_job_limiter_limit_bytes` | `false` | `integer` | `integer` | `true` | `0` | `true` | `false`| `true` |
| `sidekiq_job_limiter_mode` | `false` | `smallint` | `string` | `true` | `1` | `false` | `false`| `true` |
| `sign_in_restrictions` | `false` | `jsonb` | `` | `true` | `'{}'::jsonb` | `false` | `false`| `false` |
| `sign_in_restrictions` | `false` | `jsonb` | `hash` | `true` | `'{}'::jsonb` | `false` | `false`| `true` |
| `signup_enabled` | `false` | `boolean` | `boolean` | `false` | `null` | `true` | `false`| `true` |
| `silent_mode_enabled` | `false` | `boolean` | `boolean` | `true` | `false` | `false` | `false`| `true` |
| `slack_app_enabled` | `false` | `boolean` | `boolean` | `false` | `false` | `true` | `false`| `true` |
......
......@@ -49,6 +49,20 @@ This needs to be done for any new, or updated gems.
1. Check and commit the changes for `Gemfile.checksum`.
### Updating the `Gemfile.next.lock` File
Whenever gems are updated, ensure that the `Gemfile.next.lock` file remains consistent.
1. Sync the gem files
If you update `Gemfile.checksum`, you must sync the gem files by running:
```shell
bundle exec rake bundler:gemfile:sync
```
1. Review and commit changes
After syncing, verify the updates and commit any changes to `Gemfile.next.checksum` and `Gemfile.next.lock`.
## No gems fetched from Git repositories
We do not allow gems that are fetched from Git repositories. All gems have
......
......@@ -169,6 +169,116 @@ Example response:
}
```
#### Provision a namespace
Use to provision subscription related resources for a root namespace. This includes main plan, storage, compute minutes, and add-on purchases.
The endpoint processes resources independently - if one resource fails to provision, others continue to be provisioned.
You can provision one or more resources in a single request based on the parameters provided.
```plaintext
POST /internal/gitlab_subscriptions/namespaces/:id/provision
```
Parameters:
| Attribute | Type | Required | Description |
| :------------ | :-------- | :--------- | :------------ |
| `id` | integer | yes | ID of the namespace to provision |
The endpoint supports parameters for each resource nested under the `provision` root key:
| Attribute | Type | Required | Description |
| :------------ | :-------- | :--------- | :------------ |
| `main_plan` | hash | no | Hash object containing GitLab Subscription attributes |
| `storage` | hash | no | Hash object containing Storage attributes |
| `compute_minutes` | hash | no | Hash object containing Compute Minutes attributes |
| `add_on_purchases` | hash | no | Hash object containing Add-on Purchases attributes |
Main plan supported attributes:
| Attribute | Type | Required | Description |
| :------------ | :-------- | :--------- | :------------ |
| `plan_code` | string | no | Subscription tier code |
| `start_date` | date | no | Start date of subscription |
| `end_date` | date | no | End date of subscription |
| `seats` | integer | no | Number of seats in subscription |
| `max_seats_used` | integer | no | Highest number of billable users in the current subscription term |
| `auto_renew` | boolean | no | Whether subscription auto-renews on end date |
| `trial` | boolean | no | Whether subscription is a trial |
| `trial_starts_on` | date | no | Start date of trial. Required if trial is true |
| `trial_ends_on` | date | no | End date of trial |
Storage supported attributes:
| Attribute | Type | Required | Description |
| :------------ | :-------- | :--------- | :------------ |
| `additional_purchased_storage_size` | integer | no | Additional storage size |
| `additional_purchased_storage_ends_on` | date | no | Additional purchased storage ends on |
Compute Minutes supported attributes:
| Attribute | Type | Required | Description |
| :------------ | :-------- | :--------- | :------------ |
| `shared_runners_minutes_limit` | integer | no | Compute minutes quota |
| `extra_shared_runners_minutes_limit` | integer | no | Extra compute minutes |
Add-on Purchases Supported attributes:
| Attribute | Type | Required | Description |
| :------------ | :-------- | :--------- | :------------ |
| `quantity` | integer | No | Amount of units in the subscription add-on purchase. Must be a non-negative integer. (Example: Number of seats for Duo Pro add-on) |
| `started_on` | date | Yes | Date the subscription add-on purchase became available |
| `expires_on` | date | Yes | Expiration date of the subscription add-on purchase |
| `purchase_xid` | string | No | Identifier for the subscription add-on purchase (Example: Subscription name for a Duo Pro add-on) |
| `trial` | boolean | No | Whether the add-on is a trial |
Example request:
```shell
curl --request POST --header "X-CUSTOMERS-DOT-INTERNAL-TOKEN: <json-web-token>" "https://gitlab.com/api/v4/internal/gitlab_subscriptions/namespaces/1/provision" \
--data '{
"provision": {
"main_plan": {
"plan_code": "ultimate",
"seats": 30,
"start_date": "2024-01-01",
"end_date": "2025-01-01",
"max_seats_used": 10,
"auto_renew": true,
"trial": false,
"trial_starts_on": null,
"trial_ends_on": null
},
"storage": {
"additional_purchased_storage_size": 100,
"additional_purchased_storage_ends_on": "2025-01-01"
},
"compute_minutes": {
"extra_shared_runners_minutes_limit": 90,
"shared_runners_minutes_limit": 100
},
"add_on_purchases": {
"duo_enterprise": [{
"started_on": "2024-01-01",
"expires_on": "2025-01-01",
"purchase_xid": "A-S00001",
"quantity": 1,
"trial": false
}]
}
}
}'
```
Response Status Codes:
- 200 OK - Namespace provisioned successfully (empty response)
- 400 Bad Request - Invalid parameters or non-root namespace
- 401 Unauthorized - Invalid token
- 404 Not Found - Namespace doesn't exist
- 422 Unprocessable Entity - Validation errors during provisioning
### Subscriptions
The subscription endpoints are used by
......
......@@ -143,6 +143,12 @@ Tests can be put in quarantine by assigning `:quarantine` metadata. This means t
bundle exec rspec --tag quarantine
```
Alternatively, the `DISABLE_QUARATINE` variable can be used
```shell
DISABLE_QUARANTINE=true bundle exec bin/qa Test::Instance::All http://localhost:3000
```
### Custom `bin/qa` test runner
`bin/qa` is an additional custom wrapper script that abstracts away some of the more complicated setups that some tests require. This option requires test scenario and test instance's GitLab address to be specified in the command. For example, to run any `Instance` scenario test, the following command can be used:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment