Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-06-14 09:09:21 +00:00
parent 4fc8a50352
commit 1fc72cb876
112 changed files with 1275 additions and 1241 deletions

View File

@ -51,9 +51,9 @@ variables:
- echo "$(docker exec gdk bash -c "getent hosts \$HOSTNAME" | awk '{print $1}') gdk.test" >> /etc/hosts
- source scripts/utils.sh
- cd qa && bundle install
script:
- retry_exponential test_url ${GDK_URL}/users/sign_in
- echo -e "\e[0Ksection_end:`date +%s`:launch_gdk\r\e[0K"
script:
- echo -e "\e[0Ksection_start:`date +%s`:run_tests\r\e[0KRun E2E tests"
- QA_COMMAND="bundle exec bin/qa Test::Instance::All ${GDK_URL} -- ${RSPEC_TAGS} ${RSPEC_REPORT_OPTS}"
- echo "Running - '${QA_COMMAND}'"
@ -87,6 +87,21 @@ cache-gems:
script:
- cd qa && bundle install
# Take the existing GDK docker image and reconfigure it with Postgres load
# balancing. Adding 5s lag to 1 of the replicas to validate robustness of
# the load balancer.
.gdk-with-load-balancer-setup:
before_script:
- !reference [".gdk-qa-base", "before_script"]
- |
docker exec gdk bash -c "
gdk config set postgresql.replica.enabled true &&\
gdk config set postgresql.replica_2.enabled true &&\
gdk config set load_balancing.enabled true &&\
gdk reconfigure &&\
echo 'recovery_min_apply_delay = 5s' >> postgresql-replica-2/data/postgresql.conf &&\
gdk restart"
gdk-qa-smoke:
extends:
- .gdk-qa-base
@ -97,6 +112,19 @@ gdk-qa-smoke:
rules:
- when: always
gdk-qa-smoke-with-load-balancer:
extends:
- .gdk-qa-base
- .gdk-with-load-balancer-setup
variables:
TEST_GDK_TAGS: "--tag smoke"
QA_RUN_TYPE: gdk-qa-smoke
RSPEC_TAGS: --tag smoke
rules:
- changes:
- ".gitlab/ci/test-on-gdk/**"
- "lib/gitlab/database/load_balancing/**/*"
# TODO: set non manual once smoke tests prove to be stable
gdk-qa-reliable:
extends:
@ -110,6 +138,21 @@ gdk-qa-reliable:
rules:
- when: manual
gdk-qa-reliable-with-load-balancer:
extends:
- .gdk-qa-base
- .gdk-with-load-balancer-setup
parallel: 5
variables:
QA_RUN_TYPE: gdk-qa-blocking
QA_KNAPSACK_REPORT_NAME: ee-instance-parallel
RSPEC_TAGS: --tag smoke --tag reliable
allow_failure: true
rules:
- changes:
- ".gitlab/ci/test-on-gdk/**"
- "lib/gitlab/database/load_balancing/**/*"
gdk-qa-non-blocking:
extends:
- .gdk-qa-base

View File

@ -1957,7 +1957,6 @@ RSpec/ContextWording:
- 'spec/lib/gitlab/metrics/subscribers/rack_attack_spec.rb'
- 'spec/lib/gitlab/metrics_spec.rb'
- 'spec/lib/gitlab/middleware/basic_health_check_spec.rb'
- 'spec/lib/gitlab/middleware/compressed_json_spec.rb'
- 'spec/lib/gitlab/middleware/go_spec.rb'
- 'spec/lib/gitlab/middleware/multipart_spec.rb'
- 'spec/lib/gitlab/middleware/request_context_spec.rb'
@ -2390,7 +2389,6 @@ RSpec/ContextWording:
- 'spec/requests/api/deploy_tokens_spec.rb'
- 'spec/requests/api/deployments_spec.rb'
- 'spec/requests/api/environments_spec.rb'
- 'spec/requests/api/error_tracking/collector_spec.rb'
- 'spec/requests/api/files_spec.rb'
- 'spec/requests/api/generic_packages_spec.rb'
- 'spec/requests/api/graphql/ci/runner_spec.rb'

View File

@ -4043,7 +4043,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/metrics/web_transaction_spec.rb'
- 'spec/lib/gitlab/metrics_spec.rb'
- 'spec/lib/gitlab/middleware/basic_health_check_spec.rb'
- 'spec/lib/gitlab/middleware/compressed_json_spec.rb'
- 'spec/lib/gitlab/middleware/handle_ip_spoof_attack_error_spec.rb'
- 'spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb'
- 'spec/lib/gitlab/middleware/memory_report_spec.rb'

View File

@ -501,7 +501,6 @@ Style/ClassAndModuleChildren:
- 'ee/lib/ee/gitlab/throttle.rb'
- 'ee/lib/gitlab/path_locks_finder.rb'
- 'lib/api/error_tracking/client_keys.rb'
- 'lib/api/error_tracking/collector.rb'
- 'lib/api/error_tracking/project_settings.rb'
- 'lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings.rb'
- 'lib/gitlab/ci/badge/base.rb'

View File

@ -428,7 +428,6 @@ Style/GuardClause:
- 'ee/spec/support/ci/minutes_helpers.rb'
- 'haml_lint/linter/documentation_links.rb'
- 'lib/api/commits.rb'
- 'lib/api/error_tracking/collector.rb'
- 'lib/api/feature_flags.rb'
- 'lib/api/helpers.rb'
- 'lib/api/helpers/packages/conan/api_helpers.rb'

View File

@ -4,7 +4,13 @@ import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
import runnerCreateMutation from '~/ci/runner/graphql/new/runner_create.mutation.graphql';
import { modelToUpdateMutationVariables } from 'ee_else_ce/ci/runner/runner_update_form_utils';
import { captureException } from '../sentry_utils';
import { RUNNER_TYPES, DEFAULT_ACCESS_LEVEL, PROJECT_TYPE, GROUP_TYPE } from '../constants';
import {
RUNNER_TYPES,
DEFAULT_ACCESS_LEVEL,
PROJECT_TYPE,
GROUP_TYPE,
I18N_CREATE_ERROR,
} from '../constants';
export default {
name: 'RunnerCreateForm',
@ -82,17 +88,30 @@ export default {
});
if (errors?.length) {
this.$emit('error', new Error(errors.join(' ')));
this.saving = false;
} else {
this.onSuccess(runner);
this.onError(new Error(errors.join(' ')), true);
return;
}
if (!runner?.ephemeralRegisterUrl) {
// runner is missing information, report issue and
// fail naviation to register page.
this.onError(new Error(I18N_CREATE_ERROR));
return;
}
this.onSuccess(runner);
} catch (error) {
captureException({ error, component: this.$options.name });
this.$emit('error', error);
this.saving = false;
this.onError(error);
}
},
onError(error, isValidationError = false) {
if (!isValidationError) {
captureException({ error, component: this.$options.name });
}
this.$emit('error', error);
this.saving = false;
},
onSuccess(runner) {
this.$emit('saved', runner);
},

View File

@ -10,6 +10,7 @@ import {
GROUP_TYPE,
PROJECT_TYPE,
RUNNER_MANAGERS_HELP_URL,
I18N_STATUS_NEVER_CONTACTED,
} from '../constants';
import RunnerDetail from './runner_detail.vue';
import RunnerGroups from './runner_groups.vue';
@ -85,6 +86,7 @@ export default {
},
ACCESS_LEVEL_REF_PROTECTED,
RUNNER_MANAGERS_HELP_URL,
I18N_STATUS_NEVER_CONTACTED,
};
</script>
@ -99,7 +101,7 @@ export default {
<runner-detail :label="s__('Runners|Description')" :value="runner.description" />
<runner-detail
:label="s__('Runners|Last contact')"
:empty-value="s__('Runners|Never contacted')"
:empty-value="$options.I18N_STATUS_NEVER_CONTACTED"
>
<template v-if="runner.contactedAt" #value>
<time-ago :time="runner.contactedAt" />

View File

@ -1,13 +1,12 @@
<script>
import { GlCollapse, GlButton, GlIcon, GlSkeletonLoader, GlTableLite } from '@gitlab/ui';
import HelpPopover from '~/vue_shared/components/help_popover.vue';
import { GlCollapse, GlButton, GlIcon, GlSkeletonLoader } from '@gitlab/ui';
import { __, s__, formatNumber } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { createAlert } from '~/alert';
import runnerManagersQuery from '../graphql/show/runner_managers.query.graphql';
import { I18N_FETCH_ERROR } from '../constants';
import { captureException } from '../sentry_utils';
import { tableField } from '../utils';
import RunnerManagersTable from './runner_managers_table.vue';
export default {
name: 'RunnerManagersDetail',
@ -16,9 +15,7 @@ export default {
GlButton,
GlIcon,
GlSkeletonLoader,
GlTableLite,
TimeAgo,
HelpPopover,
RunnerManagersTable,
},
props: {
runner: {
@ -108,20 +105,7 @@ export default {
<gl-collapse :visible="expanded" class="gl-mt-5">
<gl-skeleton-loader v-if="loading" />
<gl-table-lite v-else-if="managers.length" :fields="$options.fields" :items="managers">
<template #head(systemId)="{ label }">
{{ label }}
<help-popover>
{{ s__('Runners|The unique ID for each runner that uses this configuration.') }}
</help-popover>
</template>
<template #cell(contactedAt)="{ item = {} }">
<template v-if="item.contactedAt">
<time-ago :time="item.contactedAt" />
</template>
<template v-else>{{ s__('Runners|Never contacted') }}</template>
</template>
</gl-table-lite>
<runner-managers-table v-else-if="managers.length" :items="managers" />
</gl-collapse>
</div>
</template>

View File

@ -4,6 +4,7 @@ import HelpPopover from '~/vue_shared/components/help_popover.vue';
import { s__ } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { tableField } from '../utils';
import { I18N_STATUS_NEVER_CONTACTED } from '../constants';
export default {
name: 'RunnerManagersTable',
@ -20,13 +21,6 @@ export default {
default: () => [],
},
},
data() {
return {
skip: true,
expanded: false,
managers: [],
};
},
fields: [
tableField({ key: 'systemId', label: s__('Runners|System ID') }),
tableField({ key: 'version', label: s__('Runners|Version') }),
@ -40,6 +34,7 @@ export default {
thClasses: ['gl-text-right'],
}),
],
I18N_STATUS_NEVER_CONTACTED,
};
</script>
@ -65,7 +60,7 @@ export default {
<template v-if="item.contactedAt">
<time-ago :time="item.contactedAt" />
</template>
<template v-else>{{ s__('Runners|Never contacted') }}</template>
<template v-else>{{ $options.I18N_STATUS_NEVER_CONTACTED }}</template>
</template>
</gl-table-lite>
</template>

View File

@ -9,6 +9,9 @@ export const RUNNER_DETAILS_PROJECTS_PAGE_SIZE = 5;
export const RUNNER_DETAILS_JOBS_PAGE_SIZE = 30;
export const I18N_FETCH_ERROR = s__('Runners|Something went wrong while fetching runner data.');
export const I18N_CREATE_ERROR = s__(
'Runners|An error occurred while creating the runner. Please try again.',
);
export const FILTER_CSS_CLASSES =
'gl-bg-gray-10 gl-p-5 gl-border-solid gl-border-gray-100 gl-border-0 gl-border-t-1 gl-border-b-1';

View File

@ -6,6 +6,12 @@ query getRunnerManagers($runnerId: CiRunnerID!) {
nodes {
id
systemId
version
revision
executorName
architectureName
platformName
ipAddress
contactedAt
}
}

View File

@ -1,5 +1,11 @@
<script>
import { GlLink, GlTable, GlDropdownItem, GlDropdown, GlIcon, GlButton } from '@gitlab/ui';
import {
GlLink,
GlTable,
GlDisclosureDropdownItem,
GlDisclosureDropdown,
GlButton,
} from '@gitlab/ui';
import { last } from 'lodash';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { __ } from '~/locale';
@ -13,9 +19,8 @@ export default {
components: {
GlLink,
GlTable,
GlIcon,
GlDropdown,
GlDropdownItem,
GlDisclosureDropdown,
GlDisclosureDropdownItem,
GlButton,
FileIcon,
TimeAgoTooltip,
@ -136,14 +141,16 @@ export default {
</template>
<template #cell(actions)="{ item }">
<gl-dropdown category="tertiary" right>
<template #button-content>
<gl-icon name="ellipsis_v" />
</template>
<gl-dropdown-item data-testid="delete-file" @click="$emit('delete-file', item)">
{{ $options.i18n.deleteFile }}
</gl-dropdown-item>
</gl-dropdown>
<gl-disclosure-dropdown category="tertiary" right no-caret icon="ellipsis_v">
<gl-disclosure-dropdown-item
data-testid="delete-file"
@action="$emit('delete-file', item)"
>
<template #list-item>
{{ $options.i18n.deleteFile }}
</template>
</gl-disclosure-dropdown-item>
</gl-disclosure-dropdown>
</template>
<template #row-details="{ item }">

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
module Mutations
module Achievements
class DeleteUserAchievement < BaseMutation
graphql_name 'UserAchievementsDelete'
include Gitlab::Graphql::Authorize::AuthorizeResource
field :user_achievement,
::Types::Achievements::UserAchievementType,
null: true,
description: 'Deleted user achievement.'
argument :user_achievement_id, ::Types::GlobalIDType[::Achievements::UserAchievement],
required: true,
description: 'Global ID of the user achievement being deleted.'
authorize :destroy_user_achievement
def resolve(args)
user_achievement = authorized_find!(id: args[:user_achievement_id])
result = ::Achievements::DestroyUserAchievementService.new(current_user, user_achievement).execute
{ user_achievement: result.payload, errors: result.errors }
end
def find_object(id:)
GitlabSchema.object_from_id(id, expected_type: ::Achievements::UserAchievement)
end
end
end
end

View File

@ -9,6 +9,7 @@ module Types
mount_mutation Mutations::Achievements::Award, alpha: { milestone: '15.10' }
mount_mutation Mutations::Achievements::Create, alpha: { milestone: '15.8' }
mount_mutation Mutations::Achievements::Delete, alpha: { milestone: '15.11' }
mount_mutation Mutations::Achievements::DeleteUserAchievement, alpha: { milestone: '16.1' }
mount_mutation Mutations::Achievements::Revoke, alpha: { milestone: '15.10' }
mount_mutation Mutations::Achievements::Update, alpha: { milestone: '15.11' }
mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs

View File

@ -163,6 +163,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :award_achievement
end
rule { can?(:owner_access) & achievements_enabled }.policy do
enable :destroy_user_achievement
end
rule { ~public_group & ~has_access }.prevent :read_counts
rule { ~can_read_group_member }.policy do

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
module Achievements
class DestroyUserAchievementService
attr_reader :current_user, :user_achievement
def initialize(current_user, user_achievement)
@current_user = current_user
@user_achievement = user_achievement
end
def execute
return error_no_permissions unless allowed?
user_achievement.delete
ServiceResponse.success(payload: user_achievement)
end
private
def allowed?
current_user&.can?(:destroy_user_achievement, user_achievement)
end
def error_no_permissions
error('You have insufficient permissions to delete this user achievement')
end
def error(message)
ServiceResponse.error(message: Array(message))
end
end
end

View File

@ -0,0 +1,58 @@
# frozen_string_literal: true
module Database
class MarkMigrationService
def initialize(connection:, version:)
@connection = connection
@version = version
end
def execute
return error(reason: :not_found) unless migration.present?
return error(reason: :invalid) if all_versions.include?(migration.version)
if create_version(version)
ServiceResponse.success
else
error(reason: :invalid)
end
end
private
attr_reader :connection, :version
def migration
@migration ||= connection
.migration_context
.migrations
.find { |migration| migration.version == version }
end
def all_versions
all_executed_migrations.map(&:to_i)
end
def all_executed_migrations
sm = Arel::SelectManager.new(arel_table)
sm.project(arel_table[:version])
sm.order(arel_table[:version].asc) # rubocop: disable CodeReuse/ActiveRecord
connection.select_values(sm, "#{self.class} Load")
end
def create_version(version)
im = Arel::InsertManager.new
im.into(arel_table)
im.insert(arel_table[:version] => version)
connection.insert(im, "#{self.class} Create", :version, version)
end
def arel_table
@arel_table ||= Arel::Table.new(:schema_migrations)
end
def error(reason:)
ServiceResponse.error(message: 'error', reason: reason)
end
end
end

View File

@ -22,7 +22,14 @@ module PersonalAccessTokens
last_used = @personal_access_token.last_used_at
last_used.nil? || (last_used <= 1.day.ago)
return true if last_used.nil?
if Feature.enabled?(:update_personal_access_token_usage_information_every_10_minutes) &&
last_used <= 10.minutes.ago
return true
end
last_used <= 1.day.ago
end
end
end

View File

@ -1,8 +0,0 @@
---
name: revert_daily_hll_events_to_weekly_aggregation
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114967
rollout_issue_url:
milestone: '16.0'
type: development
group: group::analytics instrumentation
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: update_personal_access_token_usage_information_every_10_minutes
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123154
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414945
milestone: '16.1'
type: development
group: group::authentication and authorization
default_enabled: true

View File

@ -10,7 +10,7 @@
The support for registration tokens and certain runner configuration arguments in the `POST` method operation on the `/api/v4/runners` endpoint is deprecated.
This endpoint [registers](https://docs.gitlab.com/ee/api/runners.html#register-a-new-runner) a runner
with a GitLab instance at the instance, group, or project level through the API. Registration tokens, and support for certain configuration arguments,
will be removed in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
will start returning the HTTP `410 Gone` status code in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
The configuration arguments disabled for authentication tokens are:

View File

@ -8,7 +8,7 @@
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383341 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The support for runner registration tokens is deprecated. As a consequence, the REST API endpoints to reset a registration token are also deprecated and will
be removed in GitLab 17.0.
return the HTTP `410 Gone` status code in GitLab 17.0.
The deprecated endpoints are:
- `POST /runners/reset_registration_token`

View File

@ -3,6 +3,8 @@
class ReMigrateRedisSlotKeys < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
KEY_EXPIRY_LENGTH = 6.weeks
DAILY_EVENTS =
%w[g_edit_by_web_ide
g_edit_by_sfe
@ -117,7 +119,7 @@ class ReMigrateRedisSlotKeys < Gitlab::Database::Migration[2.1]
end
def migrate_weekly_aggregated(event)
weeks_back = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH
weeks_back = KEY_EXPIRY_LENGTH
start_date = (Date.today - weeks_back).beginning_of_week - 1.day
end_date = Date.today.end_of_week + 1.day
@ -136,7 +138,7 @@ class ReMigrateRedisSlotKeys < Gitlab::Database::Migration[2.1]
temp_key = new_key + "_#{Time.current.to_i}"
ttl = redis.ttl(old_key)
ttl = ttl > 0 ? ttl : Gitlab::UsageDataCounters::HLLRedisCounter.send(:expiry, event)
ttl = ttl > 0 ? ttl : KEY_EXPIRY_LENGTH
redis.multi do |multi|
multi.set(temp_key, hll_blob, ex: 1.day.to_i)

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class DeleteIndexMembersOnSourceIdAndSourceType < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'index_members_on_source_id_and_source_type'
disable_ddl_transaction!
def up
remove_concurrent_index_by_name :members, name: INDEX_NAME
end
def down
add_concurrent_index :members, %i[source_id source_type], name: INDEX_NAME
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class DeleteIndexUniqueProjectAuthorizationsOnProjectIdUserId < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'index_unique_project_authorizations_on_project_id_user_id'
disable_ddl_transaction!
def up
remove_concurrent_index_by_name :project_authorizations, name: INDEX_NAME
end
def down
add_concurrent_index :project_authorizations, %i[project_id user_id], name: INDEX_NAME
end
end

View File

@ -0,0 +1 @@
cba57f523bb3d233ce1f7a0447ee25e37dafcd4ae3cd8a02ef052136e36b0938

View File

@ -0,0 +1 @@
24b2ac86b56c1eb32409d921dfba52dc9f9ba6817c9aa19ae5058d46926e79ce

View File

@ -31589,8 +31589,6 @@ CREATE INDEX index_members_on_requested_at ON members USING btree (requested_at)
CREATE INDEX index_members_on_source_and_type_and_access_level ON members USING btree (source_id, source_type, type, access_level);
CREATE INDEX index_members_on_source_id_and_source_type ON members USING btree (source_id, source_type);
CREATE INDEX index_members_on_source_state_type_access_level_and_user_id ON members USING btree (source_id, source_type, state, type, access_level, user_id) WHERE ((requested_at IS NULL) AND (invite_token IS NULL));
CREATE INDEX index_members_on_user_id_and_access_level_requested_at_is_null ON members USING btree (user_id, access_level) WHERE (requested_at IS NULL);
@ -32967,8 +32965,6 @@ CREATE UNIQUE INDEX index_unique_ci_runner_projects_on_runner_id_and_project_id
CREATE UNIQUE INDEX index_unique_issue_metrics_issue_id ON issue_metrics USING btree (issue_id);
CREATE UNIQUE INDEX index_unique_project_authorizations_on_project_id_user_id ON project_authorizations USING btree (project_id, user_id);
CREATE INDEX index_unit_test_failures_failed_at ON ci_unit_test_failures USING btree (failed_at DESC);
CREATE UNIQUE INDEX index_unit_test_failures_unique_columns ON ci_unit_test_failures USING btree (unit_test_id, failed_at DESC, build_id);

View File

@ -138,13 +138,13 @@ Example response:
"id": 1,
"active": true,
"public_key": "glet_aa77551d849c083f76d0bc545ed053a3",
"sentry_dsn": "https://glet_aa77551d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5"
"sentry_dsn": "https://glet_aa77551d849c083f76d0bc545ed053a3@example.com/errortracking/api/v1/projects/5"
},
{
"id": 3,
"active": true,
"public_key": "glet_0ff98b1d849c083f76d0bc545ed053a3",
"sentry_dsn": "https://glet_0ff98b1d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5"
"sentry_dsn": "https://glet_aa77551d849c083f76d0bc545ed053a3@example.com/errortracking/api/v1/projects/5"
}
]
```
@ -173,7 +173,7 @@ Example response:
"id": 3,
"active": true,
"public_key": "glet_0ff98b1d849c083f76d0bc545ed053a3",
"sentry_dsn": "https://glet_0ff98b1d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5"
"sentry_dsn": "https://glet_aa77551d849c083f76d0bc545ed053a3@example.com/errortracking/api/v1/projects/5"
}
```

View File

@ -6755,6 +6755,29 @@ Input type: `UploadDeleteInput`
| <a id="mutationuploaddeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationuploaddeleteupload"></a>`upload` | [`FileUpload`](#fileupload) | Deleted upload. |
### `Mutation.userAchievementsDelete`
WARNING:
**Introduced** in 16.1.
This feature is an Experiment. It can be changed or removed at any time.
Input type: `UserAchievementsDeleteInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationuserachievementsdeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationuserachievementsdeleteuserachievementid"></a>`userAchievementId` | [`AchievementsUserAchievementID!`](#achievementsuserachievementid) | Global ID of the user achievement being deleted. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationuserachievementsdeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationuserachievementsdeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationuserachievementsdeleteuserachievement"></a>`userAchievement` | [`UserAchievement`](#userachievement) | Deleted user achievement. |
### `Mutation.userCalloutCreate`
Input type: `UserCalloutCreateInput`

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/index.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/index.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-admin-area.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-admin-area.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-agent-for-kubernetes.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-agent-for-kubernetes.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-backups.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-backups.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-ci-runners.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-ci-runners.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-container-registry.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-container-registry.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-contributions-forks.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-contributions-forks.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-dashboard.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-dashboard.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-data-migration.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-data-migration.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-database-sequences.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-database-sequences.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-git-access.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-git-access.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-gitlab-pages.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-gitlab-pages.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-global-search.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-global-search.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-graphql.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-graphql.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-organizations.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-organizations.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-personal-namespaces.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-personal-namespaces.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-router-endpoints-classification.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-router-endpoints-classification.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-schema-changes.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-schema-changes.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-secrets.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-secrets.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-snippets.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-snippets.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-template.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-template.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/cells-feature-uploads.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/cells-feature-uploads.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/proposal-stateless-router-with-buffering-requests.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/proposal-stateless-router-with-buffering-requests.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -1,11 +0,0 @@
---
redirect_to: '../cells/proposal-stateless-router-with-routes-learning.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../cells/proposal-stateless-router-with-routes-learning.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -100,7 +100,7 @@ A major goal is that each member of a development team should have the same deve
A workspace should allow access to an existing development environment from multiple machines and locations across a single or multiple teams. It should also allow a user to make use of tools or runtimes not available on their local OS or manage multiple versions of them.
Additionally, remote development workspaces could provide a way to implement disaster recovery if we are able to leverage the capabilities of [Cells](../../../architecture/blueprints/pods/index.md).
Additionally, remote development workspaces could provide a way to implement disaster recovery if we are able to leverage the capabilities of [Cells](../../../architecture/blueprints/cells/index.md).
### Scalability

View File

@ -111,3 +111,17 @@ Related topics:
- If the VM image does not include the specific software version you need for your job, then the job execution time will increase as the required software needs to be fetched and installed.
- At this time, it is not possible to bring your own OS image.
- The keychain for user `gitlab` is not publicly available. You must create a keychain instead.
## Optimizing Homebrew
By default, Homebrew checks for updates at the start of any operation. Homebrew has a
release cycle that may be more frequent than the GitLab MacOS image release cycle. This
difference in release cycles may cause steps that call `brew` to take extra time to complete
while Homebrew makes updates.
To reduce build time due to unintended Homebrew updates, set the `HOMEBREW_NO_AUTO_UPDATE` variable in `.gitlab-ci.yml` :
```yaml
variables:
HOMEBREW_NO_AUTO_UPDATE: 1
```

View File

@ -961,20 +961,20 @@ To open either project or group settings:
```markdown
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
1. On the left sidebar, select **Settings > CI/CD**.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
```
To create a project:
```markdown
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. On the left sidebar, at the top, select **Create new...** (**{plus}**) and **New project/repository**.
```
To create a group:
```markdown
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New group**.
1. On the left sidebar, at the top, select **Create new...** (**{plus}**) and **New group**.
```
To open the Admin Area:
@ -999,6 +999,20 @@ To save the selection in some dropdown lists:
1. Select any area outside the dropdown list.
```
To view all your projects:
```markdown
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **View all your projects**.
```
To view all your groups:
```markdown
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **View all your groups**.
```
### Optional steps
If a step is optional, start the step with the word `Optional` followed by a period.
@ -1029,7 +1043,7 @@ Use the phrase **Complete the fields**.
For example:
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. On the left sidebar, select **Settings > Repository**.
1. Select **Settings > Repository**.
1. Expand **Push rules**.
1. Complete the fields.

View File

@ -54,7 +54,7 @@ The following migration helpers are available in `ee/app/workers/concerns/elasti
Backfills a specific field in an index. In most cases, the mapping for the field should already be added.
Requires the `index_name` and `field_name` methods.
Requires the `index_name` and `field_name` methods to backfill a single field.
```ruby
class MigrationName < Elastic::Migration
@ -72,6 +72,24 @@ class MigrationName < Elastic::Migration
end
```
Requires the `index_name` and `field_names` methods to backfill multiple fields if any field is null.
```ruby
class MigrationName < Elastic::Migration
include Elastic::MigrationBackfillHelper
private
def index_name
Issue.__elasticsearch__.index_name
end
def field_names
%w[schema_version visibility_level]
end
end
```
#### `Elastic::MigrationUpdateMappingsHelper`
Updates a mapping in an index by calling `put_mapping` with the mapping specified.

View File

@ -1,11 +0,0 @@
---
redirect_to: '../organization/index.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../organization/index.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -25,7 +25,7 @@ If you are unfamiliar with the command line, use the
<!-- Original source for this list: doc/user/project/repository/web_editor.md#upload-a-file -->
<!-- For why we duplicated the info, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111072#note_1267429478 -->
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
1. From the dropdown list, select **Upload file**.
1. Complete the fields. To create a merge request with the uploaded file, ensure the **Start a new merge request with these changes** toggle is turned on.

View File

@ -248,7 +248,8 @@ in this section whenever you need to update GitLab.
To determine the version of GitLab you're currently running:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Dashboard**.
1. Find the version under the **Components** table.

View File

@ -329,7 +329,8 @@ To prepare the new server:
```
1. Disable periodic background jobs:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. Under the Sidekiq dashboard, select **Cron** tab and then
**Disable All**.
@ -409,7 +410,8 @@ To prepare the new server:
1. [Restore the GitLab backup](#restore-gitlab).
1. Verify that the Redis database restored correctly:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. Under the Sidekiq dashboard, verify that the numbers
match with what was shown on the old server.

View File

@ -14,8 +14,9 @@ web interface.
## System hooks
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **System hooks**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **System Hooks**.
In a typical hardened environment, internal information is not transmitted or stored
outside of the system. For an offline environment system, this is
@ -32,8 +33,9 @@ encouraged for communications through system hooks.
## Push rules
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Push rules**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Push Rules**.
Ensure that the following items are selected:
@ -46,8 +48,9 @@ The adjustments help limit pushes to established and authorized users.
## Deploy keys
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Deploy keys**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Deploy Keys**.
Public deploy keys at are used to give read or read/write access to
**all** projects on the instance, and are intended for remote automation to access
@ -58,9 +61,9 @@ the documentation on [deploy keys](../user/project/deploy_keys/index.md) and
## General
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings**.
1. Select **General**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
Hardening adjustments can be made in 4 sections.
@ -177,9 +180,9 @@ For more detailed information, see
## Integrations
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings**.
1. Select **Integrations**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Integrations**.
In general, as long as administrators control and monitor usage, integrations
are fine in a hardened environment. Be cautious about integrations that allow
@ -189,9 +192,9 @@ process or authenticated user.
## Metrics and profiling
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings**.
1. Under **Integrations**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**.
The main focus for hardening is **Usage statistics**:
@ -207,9 +210,9 @@ help you make an informed decision, see
## Network
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings**.
1. Under **Network**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
For any setting that enables rate limiting, make sure it is selected. Default values
should be fine. Additionally there are numerous settings that enable access, and all

View File

@ -24,8 +24,10 @@ The user password length is set to a minimum of 8 characters by default.
To change the minimum password length using GitLab UI:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General** and expand **Sign-up restrictions**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-up restrictions**.
1. Enter a **Minimum password length** value greater than or equal to `8`.
1. Select **Save changes**.

View File

@ -20,9 +20,10 @@ The user's new password must meet all [password requirements](../user/profile/us
To reset a user's password in the UI:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. For the user whose password you want to update, select **Edit** (**{pencil-square}**).
1. For the user whose password you want to update, select **Edit**.
1. In the **Password** area, type a password and password confirmation.
1. Select **Save changes**.

View File

@ -20,8 +20,9 @@ limit the allowed SSH key algorithms.
GitLab allows you to restrict the allowed SSH key technology as well as specify
the minimum key length for each technology:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General** (`/admin/application_settings/general`).
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General** .
1. Expand the **Visibility and access controls** section:
![SSH keys restriction Admin Area settings](img/ssh_keys_restrictions_settings.png)

View File

@ -29,8 +29,9 @@ cannot leave the 2FA configuration area at `/-/profile/two_factor_auth`.
To enable 2FA for all users:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General** (`/admin/application_settings/general`).
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Sign-in restrictions** section, where you can configure both.
If you want 2FA enforcement to take effect during the next sign-in attempt,
@ -55,8 +56,8 @@ Prerequisites:
To enforce 2FA only for certain groups:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Select **All users in this group must set up two-factor authentication**.
1. Select **Save changes**.

View File

@ -25,7 +25,8 @@ If 2FA is enabled, users are locked after five failed sign-in attempts within 10
## Unlock a user from the Admin Area
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Use the search bar to find the locked user.
1. From the **User administration** dropdown list, select **Unlock**.

View File

@ -11,9 +11,10 @@ GitLab can be configured to require confirmation of a user's email address when
the user signs up. When this setting is enabled, the user is unable to sign in until
they confirm their email address.
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General** (`/admin/application_settings/general`).
1. Expand the **Sign-up restrictions** section and look for the **Email confirmation settings** options.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-up restrictions** and look for the **Email confirmation settings** options.
## Confirmation token expiry

View File

@ -47,8 +47,8 @@ Prerequisite:
To configure authentication settings for all media files:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Scroll to **Project visibility** and select **Require authentication to view media files**.

View File

@ -50,7 +50,8 @@ To prevent exploitation of insecure internal web services, all webhook and integ
To allow access to these addresses:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
1. Select the **Allow requests to the local network from webhooks and integrations** checkbox.
@ -63,7 +64,8 @@ Prerequisite:
[System hooks](../administration/system_hooks.md) can make requests to the local network by default. To prevent system hook requests to the local network:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
1. Clear the **Allow requests to the local network from system hooks** checkbox.
@ -78,7 +80,8 @@ Prerequisite:
To filter requests by blocking many requests:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
1. Select the **Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist** checkbox.
@ -103,7 +106,8 @@ Prerequisite:
To allow outbound requests to certain IP addresses and domains:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
1. In **Local IP addresses and domain names that hooks and integrations can access**, enter your IP addresses and domains.

View File

@ -420,7 +420,7 @@ While the above approach is recommended for most instances, Sidekiq can also be
The support for registration tokens and certain runner configuration arguments in the `POST` method operation on the `/api/v4/runners` endpoint is deprecated.
This endpoint [registers](https://docs.gitlab.com/ee/api/runners.html#register-a-new-runner) a runner
with a GitLab instance at the instance, group, or project level through the API. Registration tokens, and support for certain configuration arguments,
will be removed in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
will start returning the HTTP `410 Gone` status code in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
The configuration arguments disabled for authentication tokens are:
@ -576,7 +576,7 @@ we'll be introducing support in [this epic](https://gitlab.com/groups/gitlab-org
</div>
The support for runner registration tokens is deprecated. As a consequence, the REST API endpoints to reset a registration token are also deprecated and will
be removed in GitLab 17.0.
return the HTTP `410 Gone` status code in GitLab 17.0.
The deprecated endpoints are:
- `POST /runners/reset_registration_token`

View File

@ -0,0 +1,174 @@
---
stage: Analyze
group: Product Analytics
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Analytics dashboards (Experiment) **(ULTIMATE)**
> Introduced in GitLab 15.9 as an [Experiment](../../policy/experiment-beta-support.md#experiment) feature [with a flag](../../administration/feature_flags.md) named `combined_analytics_dashboards`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `combined_analytics_dashboards`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
## Dashboards
Each project can have an unlimited number of dashboards, only limited by the instances [repository size limits](../project/repository/reducing_the_repo_size_using_git.md#storage-limits).
These dashboards are defined using the GitLab YAML schema, and stored in the `.gitlab/analytics/dashboards/` directory of a project repository.
The dashboard file name and containing directory should be the same, for example `my_dashboard/my_dashboard.yaml`. For more information see [defining a dashboard](#define-a-dashboard).
Each dashboard can reference one or more [visualizations](#define-a-chart-visualization), which are shared across dashboards.
Project maintainers can enforce approval rules on dashboard changes using features such as [code owners](../project/codeowners/index.md) and [approval rules](../project/merge_requests/approvals/rules.md).
Your dashboard files are versioned in source control with the rest of a project's code.
### Data sources
A data source is a connection to a database or collection of data which can be used by your dashboard
filters and visualizations to query and retrieve results.
The following data sources are configured for analytics dashboards:
- [Product analytics](../product_analytics/index.md)
### View project dashboards
To view a list of dashboards for a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Dashboards**.
1. From the list of available dashboards, select the dashboard you want to view.
### Change the location of group dashboards
NOTE:
This feature will be connected to group-level dashboards as part of [issue #411572](https://gitlab.com/gitlab-org/gitlab/-/issues/411572).
To change the location of a group's dashboards:
1. On the top bar, select **Main menu > Projects** and find the project you want to store your dashboard files in.
The project must belong to the group for which you create the dashboards.
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Settings > General**.
1. Expand **Analytics**.
1. In the **Analytics Dashboards** section, select your dashboard files project.
1. Select **Save changes**.
### Change the location of project dashboards
Dashboards are usually defined in the project where the analytics data is being retrieved from.
However, you can also have a separate project for dashboards.
This is recommended if you want to enforce specific access rules to the dashboard definitions or share dashboards across multiple projects.
NOTE:
You can share dashboards only between projects that are located in the same group.
To change the location of project dashboards:
1. On the top bar, select **Main menu > Projects** and find or create the project to store your dashboard files.
1. On the top bar, select **Main menu > Projects** and find the analytics project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Analytics**.
1. In the **Analytics Dashboards** section, select your dashboard files project.
1. Select **Save changes**.
### Define a dashboard
To define a dashboard:
1. In `.gitlab/analytics/dashboards/`, create a directory named like the dashboard.
Each dashboard should have its own directory.
1. In the new directory, create a `.yaml` file with the same name as the directory, for example `.gitlab/analytics/dashboards/my_dashboard/my_dashboard.yaml`.
This file contains the dashboard definition. It must conform to the JSON schema defined in `ee/app/validators/json_schemas/analytics_dashboard.json`.
1. Optional. To create new visualizations to add to your dashboard see [defining a chart visualization](#define-a-chart-visualization).
For [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/analytics/product_analytics/dashboards/audience.yaml), if you want to create three dashboards (Conversion funnels, Demographic breakdown, and North star metrics)
and one visualization (line chart) that applies to all dashboards, the file structure would be:
```plaintext
.gitlab/analytics/dashboards
├── conversion_funnels
│ └── conversion_funnels.yaml
├── demographic_breakdown
│ └── demographic_breakdown.yaml
├── north_star_metrics
| └── north_star_metrics.yaml
├── visualizations
│ └── example_line_chart.yaml
```
### Define a chart visualization
You can define different charts, and add visualization options to some of them:
- Line chart, with the options listed in the [ECharts documentation](https://echarts.apache.org/en/option.html).
- Column chart, with the options listed in the [ECharts documentation](https://echarts.apache.org/en/option.html).
- Data table, with the only option to render `links` (array of objects, each with `text` and `href` properties to specify the dimensions to be used in links). See [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/validators/json_schemas/analytics_visualization.json?ref_type=heads#L112)).
- Single stat, with the only option to set `decimalPlaces` (number, default value is 0).
To define a chart for your dashboards:
1. In the `.gitlab/analytics/dashboards/visualizations/` directory, create a `.yaml` file.
The filename should be descriptive of the visualization it defines.
1. In the `.yaml` file, define the visualization configuration, according to the schema in
`ee/app/validators/json_schemas/analytics_visualization.json`.
For [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/gitlab/analytics/product_analytics/visualizations/events_over_time.yaml), to create a line chart that illustrates event count over time, in the `visualizations` folder
create a `line_chart.yaml` file with the following required fields:
- version
- type
- data
- options
## Dashboards designer
> Introduced in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `combined_analytics_dashboards_editor`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `combined_analytics_dashboards_editor`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
NOTE:
This feature does not work in conjunction with the `product_analytics_snowplow_support` feature flag.
You can use the dashboards designer to:
- Create custom dashboards
- Rename custom dashboards
- Add visualizations to new and existing custom dashboards
- Resize or move panels within custom dashboards
You cannot edit the built-in dashboards labeled as `By GitLab`.
To edit these dashboards you should create a new custom dashboard which uses the same visualizations.
### Create a custom dashboard
To create a custom dashboard:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Dashboards**.
1. Select **New dashboard**.
1. In the **New dashboard** input, enter the name of the dashboard.
1. From the **Add visualizations** list on the right, select the visualizations to add to the dashboard.
1. Optional. Drag or resize the selected panel how you prefer.
1. Select **Save**.
### Edit a custom dashboard
You can edit your custom dashboard's title and add or resize visualizations within the dashboard designer.
To edit an existing custom dashboard:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Dashboards**.
1. From the list of available dashboards, select a custom dashboard (one without the `By GitLab` label) you want to edit.
1. Select **Edit**.
1. Optional. Change the title of the dashboard.
1. Optional. From the **Add visualizations** list on the right, select other visualizations to add to the dashboard.
1. Optional. In the dashboard, select a panel and drag or resize it how you prefer.
1. Select **Save**.

View File

@ -33,6 +33,8 @@ GitLab provides several analytics features at the group level. Some of these fea
You can use GitLab to review analytics at the project level. Some of these features require you to use a higher tier than GitLab Free.
- [Analytics dashboards](analytics_dashboards.md), enabled with the `combined_analytics_dashboards_editor`
[feature flag](../../development/feature_flags/index.md#enabling-a-feature-flag-locally-in-development)
- [Application Security](../application_security/security_dashboard/index.md)
- [CI/CD & DORA](ci_cd_analytics.md)
- [Code Review](code_review_analytics.md)

View File

@ -1,11 +0,0 @@
---
redirect_to: '../terraform_module_registry/index.md'
remove_date: '2023-06-13'
---
This document was moved to [another location](../terraform_module_registry/index.md).
<!-- This redirect file can be deleted after <2023-06-13>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -83,6 +83,22 @@ Prerequisite:
1. Select **Enable product analytics** and enter the configuration values.
1. Select **Save changes**.
### Project-level settings
You can override the instance-level settings defined by the administrator on a per-project basis. This allows you to
have a different configured product analytics instance for your project.
Prerequisites:
- Product analytics must be enabled at the instance-level.
- You must have at least the Maintainer role for the project or group the project belongs to.
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Product Analytics**.
1. In the **Connect to your instance** section, enter the configuration values.
1. Select **Save changes**.
## Product analytics dashboards
> - Introduced in GitLab 15.5 behind the [feature flag](../../administration/feature_flags.md) named `product_analytics_internal_preview`. Disabled by default.
@ -93,129 +109,12 @@ On self-managed GitLab, by default this feature is not available. To make it ava
On GitLab.com, this feature is not available.
This feature is not ready for production use.
Each project can have an unlimited number of dashboards.
These dashboards are defined using the GitLab YAML schema, and stored in the `.gitlab/analytics/dashboards/` directory of a project repository.
The name of the file is the name of the dashboard.
Each dashboard can contain one or more visualizations (charts), which are shared across dashboards.
Product analytics dashboards are a subset of dashboards under [Analytics dashboards](../analytics/analytics_dashboards.md).
Project maintainers can enforce approval rules on dashboard changes using features such as code owners and approval rules.
Dashboards are versioned in source control with the rest of a project's code.
### View project dashboards
> Introduced in GitLab 15.9 behind the [feature flag](../../administration/feature_flags.md) named `combined_analytics_dashboards`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `combined_analytics_dashboards`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
To view a list of product analytics dashboards for a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Dashboards**.
1. From the list of available dashboards, select the dashboard you want to view.
### Define a dashboard
To define a dashboard:
1. In `.gitlab/analytics/dashboards/`, create a directory named like the dashboard.
Each dashboard should have its own directory.
1. In the new directory, create a `.yaml` file with the same name as the directory.
This file contains the dashboard definition. It must conform to the JSON schema defined in `ee/app/validators/json_schemas/product_analytics_dashboard.json`.
1. In the `.gitlab/analytics/dashboards/visualizations/` directory, create a `.yaml` file.
This file defines the visualization type for the dashboard. It must conform to the schema in
`ee/app/validators/json_schemas/product_analytics_visualization.json`.
For example, if you want to create three dashboards (Conversion funnels, Demographic breakdown, and North star metrics)
and one visualization (line chart) that applies to all dashboards, the file structure would be:
```plaintext
.gitlab/analytics/dashboards
├── conversion_funnels
│ └── conversion_funnels.yaml
├── demographic_breakdown
│ └── demographic_breakdown.yaml
├── north_star_metrics
| └── north_star_metrics.yaml
├── visualizations
│ └── example_line_chart.yaml
```
### Define a chart visualization
You can define different charts, and add visualization options to some of them:
- Line chart, with the options listed in the [ECharts documentation](https://echarts.apache.org/en/option.html).
- Column chart, with the options listed in the [ECharts documentation](https://echarts.apache.org/en/option.html).
- Data table, with the only option to render `links` (array of objects, each with `text` and `href` properties to specify the dimensions to be used in links). See [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/validators/json_schemas/analytics_visualization.json?ref_type=heads#L112)).
- Single stat, with the only option to set `decimalPlaces` (number, default value is 0).
To define a chart for your dashboards:
1. In the `.gitlab/product_analytics/dashboards/visualizations/` directory, create a `.yaml` file.
The filename should be descriptive of the visualization it defines.
1. In the `.yaml` file, define the visualization options, according to the schema in
`ee/app/validators/json_schemas/analytics_visualization.json`.
For [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/assets/javascripts/analytics/analytics_dashboards/gl_dashboards/product_analytics/visualizations/events_over_time.json), to create a line chart that illustrates event count over time, in the `visualizations` folder
create a `line_chart.yaml` file with the following required fields:
- version
- title
- type
- data
- options
## Dashboards editor
> Introduced in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `combined_analytics_dashboards_editor`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `combined_analytics_dashboards_editor`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
NOTE:
This feature does not work in conjunction with the `product_analytics_snowplow_support` feature flag.
You can use the dashboards editor to:
- Create dashboards
- Rename dashboards
- Add visualizations to new and existing dashboards
- Resize or move panels within dashboards
### Create a dashboard
To create a dashboard:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Dashboards**.
1. Select **New dashboard**.
1. In the **New dashboard** input, enter the name of the dashboard.
1. From the **Add visualizations** list on the right, select the visualizations to add to the dashboard.
1. Optional. Drag or resize the selected visualizations how you prefer.
1. Select **Save**.
### Edit a dashboard
You can rename your created dashboards and add or resize visualizations within them.
To edit an existing dashboard:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Dashboards**.
1. From the list of available dashboards, select the dashboard you want to edit.
1. Select **Edit**.
1. Optional. Change the name of the dashboard.
1. Optional. From the **Add visualizations** list on the right, select other visualizations to add to the dashboard.
1. Optional. In the dashboard, select a visualization and drag or resize it how you prefer.
1. Select **Save**.
Specifically product analytics dashboards and visualizations make use of the `cube_analytics` data type.
The `cube_analytics` data type connects to the Cube instance defined when [product analytics was enabled](#enable-product-analytics).
All filters and queries are sent to the Cube instance and the returned data is processed by the
product analytics data source to be rendered by the appropriate visualizations.
## Funnel analysis

View File

@ -202,6 +202,36 @@ mutation {
}
```
## Delete an awarded achievement
If you awarded an achievement to a user by mistake, you can delete it.
Prerequisites:
- You must have the Owner role for the namespace.
To delete an awarded achievement, call the [`userAchievementsDelete` GraphQL mutation](../../api/graphql/reference/index.md#mutationuserachievementsdelete).
```graphql
mutation {
userAchievementsDelete(input: {
userAchievementId: "gid://gitlab/Achievements::UserAchievement/<user achievement id>" }) {
userAchievement {
id
achievement {
id
name
}
user {
id
username
}
}
errors
}
}
```
## Delete an achievement
If you consider you no longer need an achievement, you can delete it.

View File

@ -86,7 +86,12 @@ At any time, you can revoke a personal access token.
## View the last time a token was used
Token usage information is updated every 24 hours. GitLab considers a token used when the token is used to:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/414945) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `update_personal_access_token_usage_information_every_10_minutes`. Enabled by default.
FLAG:
On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](../../administration/feature_flags.md) named `update_personal_access_token_usage_information_every_10_minutes`. On GitLab.com, this feature is available.
Token usage information is updated every 10 minutes. GitLab considers a token used when the token is used to:
- Authenticate with the [REST](../../api/rest/index.md) or [GraphQL](../../api/graphql/index.md) APIs.
- Perform a Git operation.

View File

@ -130,8 +130,8 @@ If you find that you have to add the same badges to several projects, you may wa
To add a new badge to a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Under **Link**, enter the URL that the badges should point to.
1. Under **Badge image URL**, enter the URL of the image that should be displayed.
@ -151,8 +151,8 @@ A common project badge presents the GitLab CI pipeline status.
To add this badge to a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Under **Name**, enter _Pipeline Status_.
1. Under **Link**, enter the following URL:
@ -180,8 +180,8 @@ If you need individual badges for each project, either:
To add a new badge to a group:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Under "Link", enter the URL that the badges should point to and under
"Badge image URL" the URL of the image that should be displayed.
@ -202,8 +202,8 @@ Badges associated with a group can be edited or deleted only at the [group level
You can view the exact link for your badges.
Then you can use the link to embed the badge in your HTML or Markdown pages.
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > CI/CD**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. In the **Pipeline status**, **Coverage report**, or **Latest release** sections, view the URLs for the images.
@ -269,8 +269,9 @@ https://gitlab.example.com/<project_path>/-/raw/<default_branch>/my-image.svg
To add a new badge with a custom image to a group or project:
1. On the top bar, select **Main menu** and find your group or project.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or
group.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Under **Name**, enter the name for the badge.
1. Under **Link**, enter the URL that the badge should point to.

View File

@ -32,8 +32,8 @@ directory in your repository.
To create an issue description template:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Repository**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Code > Repository**.
1. Next to the default branch, select **{plus}**.
1. Select **New file**.
1. Next to the default branch, in the **File name** text box, enter `.gitlab/issue_templates/mytemplate.md`,
@ -52,8 +52,8 @@ that depend on the contents of commit messages and branch names.
To create a merge request description template for a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Repository**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Code > Repository**.
1. Next to the default branch, select **{plus}**.
1. Select **New file**.
1. Next to the default branch, in the **File name** text box, enter `.gitlab/merge_request_templates/mytemplate.md`,
@ -124,8 +124,8 @@ As a result, you can use the same templates in issues and merge requests in all
To re-use templates [you've created](../project/description_templates.md#create-an-issue-template):
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
1. Select **Settings > General**.
1. Expand **Templates**.
1. From the dropdown list, select your template project as the template repository at group level.
1. Select **Save changes**.
@ -155,8 +155,8 @@ To set a default description template for merge requests, either:
This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
- Users on GitLab Premium and Ultimate: set the default template in project settings:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Merge requests**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings > Merge requests**.
1. In the **Default description template for merge requests** section, fill in the text area.
1. Select **Save changes**.
@ -167,8 +167,8 @@ To set a default description template for issues, either:
This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
- Users on GitLab Premium and Ultimate: set the default template in project settings:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > General**.
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
1. Select **Settings > General**.
1. Expand **Default description template for issues**.
1. Fill in the text area.
1. Select **Save changes**.

View File

@ -0,0 +1,62 @@
# frozen_string_literal: true
module API
module Admin
class Migrations < ::API::Base
feature_category :database
urgency :low
before do
authenticated_as_admin!
end
namespace 'admin' do
resources 'migrations/:timestamp/mark' do
desc 'Mark the migration as successfully executed' do
success [
{ code: 201, message: '201 Created' }
]
failure [
{ code: 401, message: '401 Unauthorized' },
{ code: 403, message: '403 Forbidden' },
{ code: 404, message: '404 Not found' },
{ code: 422, message: 'You can mark only pending migrations' }
]
tags %w[migrations]
end
params do
optional :database,
type: String,
values: Gitlab::Database.all_database_names,
desc: 'The name of the database',
default: 'main'
requires :timestamp,
type: Integer,
desc: 'The migration version timestamp'
end
post do
response = Database::MarkMigrationService.new(
connection: base_model.connection,
version: params[:timestamp]
).execute
if response.success?
created!
elsif response.reason == :not_found
not_found!
else
render_api_error!('You can mark only pending migrations', 422)
end
end
end
end
helpers do
def base_model
database = params[:database] || Gitlab::Database::MAIN_DATABASE_NAME
@base_model ||= Gitlab::Database.database_base_models[database]
end
end
end
end
end

View File

@ -182,6 +182,7 @@ module API
mount ::API::Admin::BatchedBackgroundMigrations
mount ::API::Admin::Ci::Variables
mount ::API::Admin::InstanceClusters
mount ::API::Admin::Migrations
mount ::API::Admin::PlanLimits
mount ::API::AlertManagementAlerts
mount ::API::Appearance
@ -327,7 +328,6 @@ module API
mount ::API::Ci::PipelineSchedules
mount ::API::Ci::SecureFiles
mount ::API::Discussions
mount ::API::ErrorTracking::Collector
mount ::API::GroupBoards
mount ::API::GroupLabels
mount ::API::GroupMilestones

View File

@ -21,7 +21,7 @@ module API
expose :id, documentation: { type: 'integer', example: 1 }
expose :active, documentation: { type: 'boolean' }
expose :public_key, documentation: { type: 'string', example: 'glet_aa77551d849c083f76d0bc545ed053a3' }
expose :sentry_dsn, documentation: { type: 'string', example: 'https://glet_aa77551d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5' }
expose :sentry_dsn, documentation: { type: 'string', example: 'https://glet_aa77551d849c083f76d0bc545ed053a3@example.com/errortracking/api/v1/projects/5' }
end
end
end

View File

@ -1,156 +0,0 @@
# frozen_string_literal: true
module API
# This API is responsible for collecting error tracking information
# from sentry client. It allows us to use GitLab as an alternative to
# sentry backend. For more details see https://gitlab.com/gitlab-org/gitlab/-/issues/329596.
class ErrorTracking::Collector < ::API::Base
feature_category :error_tracking
urgency :low
content_type :envelope, 'application/x-sentry-envelope'
content_type :json, 'application/json'
content_type :txt, 'text/plain'
default_format :envelope
rescue_from Gitlab::ErrorTracking::ErrorRepository::DatabaseError do |e|
render_api_error!(e.message, 400)
end
before do
not_found!('Project') unless project
not_found! unless feature_enabled?
not_found! unless active_client_key?
end
helpers do
def project
@project ||= find_project(params[:id])
end
def feature_enabled?
Feature.enabled?(:integrated_error_tracking, project) &&
project.error_tracking_setting&.integrated_enabled?
end
def find_client_key(public_key)
return unless public_key.present?
project.error_tracking_client_keys.active.find_by_public_key(public_key)
end
def active_client_key?
public_key = extract_public_key
find_client_key(public_key)
end
def extract_public_key
# Some SDK send public_key as a param. In this case we don't need to parse headers.
return params[:sentry_key] if params[:sentry_key].present?
begin
::ErrorTracking::Collector::SentryAuthParser.parse(request)[:public_key]
rescue StandardError
bad_request!('Failed to parse sentry request')
end
end
def validate_payload(payload)
unless ::ErrorTracking::Collector::PayloadValidator.new.valid?(payload)
bad_request!('Unsupported sentry payload')
end
end
end
desc 'Submit error tracking event to the project as envelope' do
detail 'This feature was introduced in GitLab 14.1.'
end
params do
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/envelope' do
# There is a reason why we have such uncommon path.
# We depend on a client side error tracking software which
# modifies URL for its own reasons.
#
# When we give user a URL like this
# HOST/api/v4/error_tracking/collector/123
#
# Then error tracking software will convert it like this:
# HOST/api/v4/error_tracking/collector/api/123/envelope/
begin
parsed_request = ::ErrorTracking::Collector::SentryRequestParser.parse(request)
rescue StandardError
bad_request!('Failed to parse sentry request')
end
type = parsed_request[:request_type]
# Sentry sends 2 requests on each exception: transaction and event.
# Everything else is not a desired behavior.
unless type == 'transaction' || type == 'event'
render_api_error!('400 Bad Request', 400)
break
end
# We don't have use for transaction request yet,
# so we record only event one.
if type == 'event'
validate_payload(parsed_request[:event])
::ErrorTracking::CollectErrorService
.new(project, nil, event: parsed_request[:event])
.execute
end
# Collector should never return any information back.
# Because DSN and public key are designed for public use,
# it is safe only for submission of new events.
#
# Some clients sdk require status 200 OK to work correctly.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/343531.
status 200
end
desc 'Submit error tracking event to the project' do
detail 'This feature was introduced in GitLab 14.1.'
end
params do
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/store' do
# There is a reason why we have such uncommon path.
# We depend on a client side error tracking software which
# modifies URL for its own reasons.
#
# When we give user a URL like this
# HOST/api/v4/error_tracking/collector/123
#
# Then error tracking software will convert it like this:
# HOST/api/v4/error_tracking/collector/api/123/store/
begin
parsed_body = Gitlab::Json.parse(request.body.read)
rescue StandardError
bad_request!('Failed to parse sentry request')
end
validate_payload(parsed_body)
::ErrorTracking::CollectErrorService
.new(project, nil, event: parsed_body)
.execute
# Collector should never return any information back.
# Because DSN and public key are designed for public use,
# it is safe only for submission of new events.
#
# Some clients sdk require status 200 OK to work correctly.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/343531.
status 200
end
end
end

View File

@ -114,7 +114,6 @@ module Gitlab
def known_event_entry
<<~YML
- name: #{event}
aggregation: weekly
YML
end

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::<%= class_name %>Metric do
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::<%= class_name %>Metric, feature_category: :service_ping do
let(:expected_value) { 1 }
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }

View File

@ -3,7 +3,6 @@
module Gitlab
module Middleware
class CompressedJson
COLLECTOR_PATH = '/api/v4/error_tracking/collector'
INSTANCE_PACKAGES_PATH = %r{
\A/api/v4/packages/npm/-/npm/v1/security/
(?:(?:advisories/bulk)|(?:audits/quick))\z (?# end)
@ -79,8 +78,7 @@ module Gitlab
end
def match_path?(env)
env['PATH_INFO'].start_with?((File.join(relative_url, COLLECTOR_PATH))) ||
match_packages_path?(env)
match_packages_path?(env)
end
def match_packages_path?(env)

View File

@ -3,18 +3,14 @@
module Gitlab
module UsageDataCounters
module HLLRedisCounter
DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH = 6.weeks
DEFAULT_DAILY_KEY_EXPIRY_LENGTH = 29.days
KEY_EXPIRY_LENGTH = 6.weeks
REDIS_SLOT = 'hll_counters'
EventError = Class.new(StandardError)
UnknownEvent = Class.new(EventError)
UnknownAggregation = Class.new(EventError)
AggregationMismatch = Class.new(EventError)
InvalidContext = Class.new(EventError)
KNOWN_EVENTS_PATH = File.expand_path('known_events/*.yml', __dir__)
ALLOWED_AGGREGATIONS = %i(daily weekly).freeze
# Track event on entity_id
# Increment a Redis HLL counter for unique event_name and entity_id
@ -24,7 +20,6 @@ module Gitlab
# Event example:
#
# - name: g_compliance_dashboard # Unique event name
# aggregation: weekly # Aggregation level, keys are stored weekly
#
# Usage:
#
@ -63,8 +58,7 @@ module Gitlab
# end_date - The end date of the time range.
# context - Event context, plan level tracking. Available if set when tracking.
def unique_events(event_names:, start_date:, end_date:, context: '')
count_unique_events(event_names: event_names, start_date: start_date, end_date: end_date, context: context) do |events|
raise AggregationMismatch, events unless events_same_aggregation?(events)
count_unique_events(event_names: event_names, start_date: start_date, end_date: end_date, context: context) do
raise InvalidContext if context.present? && !context.in?(valid_context_list)
end
end
@ -78,9 +72,7 @@ module Gitlab
end
def calculate_events_union(event_names:, start_date:, end_date:)
count_unique_events(event_names: event_names, start_date: start_date, end_date: end_date) do |events|
raise AggregationMismatch, events unless events_same_aggregation?(events)
end
count_unique_events(event_names: event_names, start_date: start_date, end_date: end_date)
end
private
@ -94,12 +86,7 @@ module Gitlab
return if event.blank?
return unless Feature.enabled?(:redis_hll_tracking, type: :ops)
if event[:aggregation].to_sym == :daily
weekly_event = event.dup.tap { |e| e['aggregation'] = 'weekly' }
Gitlab::Redis::HLL.add(key: redis_key(weekly_event, time, context), value: values, expiry: expiry(weekly_event))
end
Gitlab::Redis::HLL.add(key: redis_key(event, time, context), value: values, expiry: expiry(event))
Gitlab::Redis::HLL.add(key: redis_key(event, time, context), value: values, expiry: KEY_EXPIRY_LENGTH)
rescue StandardError => e
# Ignore any exceptions unless is dev or test env
@ -117,25 +104,18 @@ module Gitlab
yield events if block_given?
aggregation = events.first[:aggregation]
keys = keys_for_aggregation(events: events, start_date: start_date, end_date: end_date, context: context)
if Feature.disabled?(:revert_daily_hll_events_to_weekly_aggregation)
aggregation = 'weekly'
events = events.map { |e| e.merge(aggregation: 'weekly') }
end
keys = keys_for_aggregation(aggregation, events: events, start_date: start_date, end_date: end_date, context: context)
return FALLBACK unless keys.any?
redis_usage_data { Gitlab::Redis::HLL.count(keys: keys) }
end
def keys_for_aggregation(aggregation, events:, start_date:, end_date:, context: '')
if aggregation.to_sym == :daily
daily_redis_keys(events: events, start_date: start_date, end_date: end_date, context: context)
else
weekly_redis_keys(events: events, start_date: start_date, end_date: end_date, context: context)
end
def keys_for_aggregation(events:, start_date:, end_date:, context: '')
end_date = end_date.end_of_week - 1.week
(start_date.to_date..end_date.to_date).map do |date|
events.map { |event| redis_key(event, date, context) }
end.flatten.uniq
end
def load_events(wildcard)
@ -152,15 +132,6 @@ module Gitlab
known_events.map { |event| event[:name] }
end
def events_same_aggregation?(events)
aggregation = events.first[:aggregation]
events.all? { |event| event[:aggregation] == aggregation }
end
def expiry(event)
event[:aggregation].to_sym == :daily ? DEFAULT_DAILY_KEY_EXPIRY_LENGTH : DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH
end
def event_for(event_name)
known_events.find { |event| event[:name] == event_name.to_s }
end
@ -173,37 +144,14 @@ module Gitlab
def redis_key(event, time, context = '')
raise UnknownEvent, "Unknown event #{event[:name]}" unless known_events_names.include?(event[:name].to_s)
# ToDo: remove during https://gitlab.com/groups/gitlab-org/-/epics/9542 cleanup
raise UnknownAggregation, "Use :daily or :weekly aggregation" unless ALLOWED_AGGREGATIONS.include?(event[:aggregation].to_sym)
key = "{#{REDIS_SLOT}}_#{event[:name]}"
key = apply_time_aggregation(key, time, event)
year_week = time.strftime('%G-%V')
key = "#{key}-#{year_week}"
key = "#{context}_#{key}" if context.present?
key
end
def apply_time_aggregation(key, time, event)
if event[:aggregation].to_sym == :daily
year_day = time.strftime('%G-%j')
"#{year_day}-#{key}"
else
year_week = time.strftime('%G-%V')
"#{key}-#{year_week}"
end
end
def daily_redis_keys(events:, start_date:, end_date:, context: '')
(start_date.to_date..end_date.to_date).map do |date|
events.map { |event| redis_key(event, date, context) }
end.flatten
end
def weekly_redis_keys(events:, start_date:, end_date:, context: '')
end_date = end_date.end_of_week - 1.week
(start_date.to_date..end_date.to_date).map do |date|
events.map { |event| redis_key(event, date, context) }
end.flatten.uniq
end
end
end
end

View File

@ -45,10 +45,7 @@ namespace :gitlab do
events = event_pairs.each_with_object([]) do |(event_type, event_scope), events|
Packages::Event::ORIGINATOR_TYPES.excluding(:guest).each do |originator_type|
events_definition = Packages::Event.unique_counters_for(event_scope, event_type, originator_type).map do |event_name|
{
"name" => event_name,
"aggregation" => "weekly"
}
{ "name" => event_name }
end
events.concat(events_definition)

View File

@ -85,12 +85,13 @@ namespace :gitlab do
end
end
# rubocop:disable Gitlab/NoCodeCoverageComment
# :nocov: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/299453
def ci_template_event(event_name)
{
'name' => event_name,
'aggregation' => 'weekly'
}
{ 'name' => event_name }
end
# :nocov:
# rubocop:enable Gitlab/NoCodeCoverageComment
def implicit_auto_devops_event(expanded_template_name)
event_name = Gitlab::UsageDataCounters::CiTemplateUniqueCounter.ci_template_event_name(expanded_template_name, :auto_devops_source)

View File

@ -39376,6 +39376,9 @@ msgstr ""
msgid "Runners|An error has occurred fetching instructions"
msgstr ""
msgid "Runners|An error occurred while creating the runner. Please try again."
msgstr ""
msgid "Runners|An error occurred while deleting. Some runners may not have been deleted."
msgstr ""

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountFooMetric do
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountFooMetric, feature_category: :service_ping do
let(:expected_value) { 1 }
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }

View File

@ -11,6 +11,7 @@ import {
INSTANCE_TYPE,
GROUP_TYPE,
PROJECT_TYPE,
I18N_CREATE_ERROR,
} from '~/ci/runner/constants';
import runnerCreateMutation from '~/ci/runner/graphql/new/runner_create.mutation.graphql';
import { captureException } from '~/ci/runner/sentry_utils';
@ -188,5 +189,37 @@ describe('RunnerCreateForm', () => {
expect(captureException).not.toHaveBeenCalled();
});
});
describe('when no runner information is returned', () => {
beforeEach(async () => {
runnerCreateHandler.mockResolvedValue({
data: {
runnerCreate: {
errors: [],
runner: null,
},
},
});
findForm().vm.$emit('submit', { preventDefault });
await waitForPromises();
});
it('emits "error" result', () => {
expect(wrapper.emitted('error')[0]).toEqual([new TypeError(I18N_CREATE_ERROR)]);
});
it('does not show a saving state', () => {
expect(findSubmitBtn().props('loading')).toBe(false);
});
it('reports error', () => {
expect(captureException).toHaveBeenCalledTimes(1);
expect(captureException).toHaveBeenCalledWith({
component: 'RunnerCreateForm',
error: new Error(I18N_CREATE_ERROR),
});
});
});
});
});

View File

@ -2,16 +2,12 @@ import { GlCollapse, GlSkeletonLoader, GlTableLite } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { __ } from '~/locale';
import {
shallowMountExtended,
mountExtended,
extendedWrapper,
} from 'helpers/vue_test_utils_helper';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import RunnerManagersDetail from '~/ci/runner/components/runner_managers_detail.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import RunnerManagersTable from '~/ci/runner/components/runner_managers_table.vue';
import runnerManagersQuery from '~/ci/runner/graphql/show/runner_managers.query.graphql';
import { runnerData, runnerManagersData } from '../mock_data';
@ -33,8 +29,7 @@ describe('RunnerJobs', () => {
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findCollapse = () => wrapper.findComponent(GlCollapse);
const findRows = () => wrapper.findAll('tbody tr');
const findCell = ({ field, i }) => extendedWrapper(findRows().at(i)).findByTestId(`td-${field}`);
const findRunnerManagersTable = () => wrapper.findComponent(RunnerManagersTable);
const createComponent = ({ props, mountFn = shallowMountExtended } = {}) => {
wrapper = mountFn(RunnerManagersDetail, {
@ -162,21 +157,7 @@ describe('RunnerJobs', () => {
it('shows rows', () => {
expect(findCollapse().attributes('visible')).toBe('true');
expect(findRows()).toHaveLength(mockRunnerManagers.length);
});
it('shows system id', () => {
expect(findCell({ field: 'systemId', i: 0 }).text()).toBe(mockRunnerManagers[0].systemId);
expect(findCell({ field: 'systemId', i: 1 }).text()).toBe(mockRunnerManagers[1].systemId);
});
it('shows contacted at', () => {
expect(findCell({ field: 'contactedAt', i: 0 }).findComponent(TimeAgo).props('time')).toBe(
mockRunnerManagers[0].contactedAt,
);
expect(findCell({ field: 'contactedAt', i: 1 }).findComponent(TimeAgo).props('time')).toBe(
mockRunnerManagers[1].contactedAt,
);
expect(findRunnerManagersTable().props('items')).toEqual(mockRunnerManagers);
});
it('collapses when clicked', async () => {

View File

@ -1,20 +1,17 @@
import { GlTableLite } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { s__ } from '~/locale';
import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
import RunnerManagersTable from '~/ci/runner/components/runner_managers_table.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { I18N_STATUS_NEVER_CONTACTED } from '~/ci/runner/constants';
import { runnerManagersData } from '../mock_data';
jest.mock('~/alert');
jest.mock('~/ci/runner/sentry_utils');
const [runnerManager1, runnerManager2] = runnerManagersData.data.runner.managers.nodes;
Vue.use(VueApollo);
const mockItems = runnerManagersData.data.runner.managers.nodes;
describe('RunnerJobs', () => {
let wrapper;
@ -25,9 +22,11 @@ describe('RunnerJobs', () => {
const findCellText = (opts) => findCell(opts).text().replace(/\s+/g, ' ');
const createComponent = ({ item } = {}) => {
const [mockItem, ...otherItems] = mockItems;
wrapper = mountExtended(RunnerManagersTable, {
propsData: {
items: [{ ...runnerManager1, ...item }, runnerManager2],
items: [{ ...mockItem, ...item }, ...otherItems],
},
stubs: {
GlTableLite,
@ -54,8 +53,8 @@ describe('RunnerJobs', () => {
it('shows system id', () => {
createComponent();
expect(findCellText({ field: 'systemId', i: 0 })).toBe(runnerManager1.systemId);
expect(findCellText({ field: 'systemId', i: 1 })).toBe(runnerManager2.systemId);
expect(findCellText({ field: 'systemId', i: 0 })).toBe(mockItems[0].systemId);
expect(findCellText({ field: 'systemId', i: 1 })).toBe(mockItems[1].systemId);
});
it('shows version', () => {
@ -74,6 +73,14 @@ describe('RunnerJobs', () => {
expect(findCellText({ field: 'version', i: 0 })).toBe('1.0 (123456)');
});
it('shows revision without version', () => {
createComponent({
item: { version: null, revision: '123456' },
});
expect(findCellText({ field: 'version', i: 0 })).toBe('(123456)');
});
it('shows ip address', () => {
createComponent({
item: { ipAddress: '127.0.0.1' },
@ -117,7 +124,14 @@ describe('RunnerJobs', () => {
it('shows contacted at', () => {
createComponent();
expect(findCell({ field: 'contactedAt', i: 0 }).findComponent(TimeAgo).props('time')).toBe(
runnerManager1.contactedAt,
mockItems[0].contactedAt,
);
});
it('shows missing contacted at', () => {
createComponent({
item: { contactedAt: null },
});
expect(findCellText({ field: 'contactedAt', i: 0 })).toBe(I18N_STATUS_NEVER_CONTACTED);
});
});

View File

@ -1,4 +1,4 @@
import { GlDropdown, GlButton } from '@gitlab/ui';
import { GlDisclosureDropdown, GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue/';
import stubChildren from 'helpers/stub_children';
@ -19,7 +19,7 @@ describe('Package Files', () => {
const findSecondRowCommitLink = () => findSecondRow().find('[data-testid="commit-link"]');
const findFirstRowFileIcon = () => findFirstRow().findComponent(FileIcon);
const findFirstRowCreatedAt = () => findFirstRow().findComponent(TimeAgoTooltip);
const findFirstActionMenu = () => findFirstRow().findComponent(GlDropdown);
const findFirstActionMenu = () => findFirstRow().findComponent(GlDisclosureDropdown);
const findActionMenuDelete = () => findFirstActionMenu().find('[data-testid="delete-file"]');
const findFirstToggleDetailsButton = () => findFirstRow().findComponent(GlButton);
const findFirstRowShaComponent = (id) => wrapper.find(`[data-testid="${id}"]`);
@ -159,7 +159,7 @@ describe('Package Files', () => {
it('emits a delete event when clicked', () => {
createComponent();
findActionMenuDelete().vm.$emit('click');
findActionMenuDelete().vm.$emit('action');
const [[{ id }]] = wrapper.emitted('delete-file');
expect(id).toBe(npmFiles[0].id);

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Achievements::DeleteUserAchievement, feature_category: :user_profile do
include GraphqlHelpers
let_it_be(:maintainer) { create(:user) }
let_it_be(:owner) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:achievement) { create(:achievement, namespace: group) }
let_it_be(:user_achievement) { create(:user_achievement, achievement: achievement) }
describe '#resolve' do
subject(:resolve_mutation) do
described_class.new(object: nil, context: { current_user: current_user }, field: nil).resolve(
user_achievement_id: user_achievement&.to_global_id
)
end
before_all do
group.add_maintainer(maintainer)
group.add_owner(owner)
end
context 'when the user does not have permission' do
let(:current_user) { maintainer }
it 'raises an error' do
expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
.with_message(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
end
end
context 'when the user has permission' do
let(:current_user) { owner }
context 'when the params are invalid' do
let(:user_achievement) { nil }
it 'returns the validation error' do
expect { resolve_mutation }.to raise_error { Gitlab::Graphql::Errors::ArgumentError }
end
end
it 'deletes user_achievement' do
resolve_mutation
expect(Achievements::UserAchievement.find_by(id: user_achievement.id)).to be_nil
end
end
end
specify { expect(described_class).to require_graphql_authorizations(:destroy_user_achievement) }
end

View File

@ -280,7 +280,7 @@ RSpec.describe Gitlab::Analytics::InternalEventsGenerator, :silence_stdout, feat
describe 'Creating known event entry' do
let(:time_frames) { %w[7d 28d] }
let(:expected_known_events) { [{ "name" => event, "aggregation" => "weekly" }] }
let(:expected_known_events) { [{ "name" => event }] }
it 'creates a metric definition file using the template' do
described_class.new([], options).invoke_all

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Middleware::CompressedJson do
RSpec.describe Gitlab::Middleware::CompressedJson, feature_category: :shared do
let_it_be(:decompressed_input) { '{"foo": "bar"}' }
let_it_be(:input) { ActiveSupport::Gzip.compress(decompressed_input) }
@ -70,24 +70,6 @@ RSpec.describe Gitlab::Middleware::CompressedJson do
end
describe '#call' do
context 'with collector route' do
let(:path) { '/api/v4/error_tracking/collector/1/store' }
it_behaves_like 'decompress middleware'
context 'with no Content-Type' do
let(:content_type) { nil }
it_behaves_like 'decompress middleware'
end
include_context 'with relative url' do
let(:path) { "#{relative_url_root}/api/v4/error_tracking/collector/1/store" }
it_behaves_like 'decompress middleware'
end
end
context 'with packages route' do
context 'with instance level endpoint' do
context 'with npm advisory bulk url' do
@ -192,11 +174,11 @@ RSpec.describe Gitlab::Middleware::CompressedJson do
it_behaves_like 'passes input'
end
context 'payload is too large' do
context 'when payload is too large' do
let(:body_limit) { Gitlab::Middleware::CompressedJson::MAXIMUM_BODY_SIZE }
let(:decompressed_input) { 'a' * (body_limit + 100) }
let(:input) { ActiveSupport::Gzip.compress(decompressed_input) }
let(:path) { '/api/v4/error_tracking/collector/1/envelope' }
let(:path) { '/api/v4/packages/npm/-/npm/v1/security/advisories/bulk' }
it 'reads only limited size' do
expect(middleware.call(env))

View File

@ -23,91 +23,10 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
described_class.clear_memoization(:known_events)
end
describe '.track_event' do
# ToDo: remove during https://gitlab.com/groups/gitlab-org/-/epics/9542 cleanup
describe 'daily to weekly key migration precautions' do
let(:event_a_name) { 'example_event_a' }
let(:event_b_name) { 'example_event_b' }
let(:known_events) do
[
{ name: event_a_name, aggregation: 'daily' },
{ name: event_b_name, aggregation: 'weekly' }
].map(&:with_indifferent_access)
end
let(:start_date) { (Date.current - 1.week).beginning_of_week }
let(:end_date) { Date.current }
let(:daily_event) { known_events.first }
let(:daily_key) { described_class.send(:redis_key, daily_event, start_date) }
let(:weekly_key) do
weekly_event = known_events.first.merge(aggregation: 'weekly')
described_class.send(:redis_key, weekly_event, start_date)
end
before do
allow(described_class).to receive(:load_events).with(described_class::KNOWN_EVENTS_PATH).and_return(known_events)
allow(described_class).to receive(:load_events).with(/ee/).and_return([])
end
shared_examples 'writes daily events to daily and weekly keys' do
it :aggregate_failures do
expect(Gitlab::Redis::HLL).to receive(:add).with(expiry: 29.days, key: daily_key, value: 1).and_call_original
expect(Gitlab::Redis::HLL).to receive(:add).with(expiry: 6.weeks, key: weekly_key, value: 1).and_call_original
described_class.track_event(event_a_name, values: 1, time: start_date)
end
end
context 'when revert_daily_hll_events_to_weekly_aggregation FF is disabled' do
before do
stub_feature_flags(revert_daily_hll_events_to_weekly_aggregation: false)
end
it_behaves_like 'writes daily events to daily and weekly keys'
it 'aggregates weekly for daily keys', :aggregate_failures do
expect(Gitlab::Redis::HLL).to receive(:count).with(keys: [weekly_key]).and_call_original
expect(Gitlab::Redis::HLL).not_to receive(:count).with(keys: [daily_key]).and_call_original
described_class.unique_events(event_names: [event_a_name], start_date: start_date, end_date: end_date)
end
it 'does not persists changes to event aggregation attribute' do
described_class.unique_events(event_names: [event_a_name], start_date: start_date, end_date: end_date)
expect(described_class.known_events.find { |e| e[:name] == event_a_name }[:aggregation])
.to eql 'daily'
end
end
context 'when revert_daily_hll_events_to_weekly_aggregation FF is enabled' do
before do
stub_feature_flags(revert_daily_hll_events_to_weekly_aggregation: true)
end
# we want to write events no matter of the feature state
it_behaves_like 'writes daily events to daily and weekly keys'
it 'aggregates daily for daily keys', :aggregate_failures do
expect(Gitlab::Redis::HLL).to receive(:count).with(keys: [daily_key]).and_call_original
expect(Gitlab::Redis::HLL).not_to receive(:count).with(keys: [weekly_key]).and_call_original
described_class.unique_events(event_names: [event_a_name], start_date: start_date, end_date: start_date)
end
end
end
end
describe '.known_events' do
let(:ce_temp_dir) { Dir.mktmpdir }
let(:ce_temp_file) { Tempfile.new(%w[common .yml], ce_temp_dir) }
let(:ce_event) do
{
"name" => "ce_event",
"aggregation" => "weekly"
}
end
let(:ce_event) { { "name" => "ce_event" } }
before do
stub_const("#{described_class}::KNOWN_EVENTS_PATH", File.expand_path('*.yml', ce_temp_dir))
@ -144,13 +63,13 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:known_events) do
[
{ name: weekly_event, aggregation: "weekly" },
{ name: daily_event, aggregation: "daily" },
{ name: category_productivity_event, aggregation: "weekly" },
{ name: compliance_slot_event, aggregation: "weekly" },
{ name: no_slot, aggregation: "daily" },
{ name: different_aggregation, aggregation: "monthly" },
{ name: context_event, aggregation: 'weekly' }
{ name: weekly_event },
{ name: daily_event },
{ name: category_productivity_event },
{ name: compliance_slot_event },
{ name: no_slot },
{ name: different_aggregation },
{ name: context_event }
].map(&:with_indifferent_access)
end
@ -203,15 +122,11 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
it 'tracks events with multiple values' do
values = [entity1, entity2]
expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_analytics_contribution/, value: values,
expiry: described_class::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH)
expiry: described_class::KEY_EXPIRY_LENGTH)
described_class.track_event(:g_analytics_contribution, values: values)
end
it "raise error if metrics don't have same aggregation" do
expect { described_class.track_event(different_aggregation, values: entity1, time: Date.current) }.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownAggregation)
end
it 'raise error if metrics of unknown event' do
expect { described_class.track_event('unknown', values: entity1, time: Date.current) }.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
end
@ -248,22 +163,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
expect(keys).not_to be_empty
keys.each do |key|
expect(redis.ttl(key)).to be_within(5.seconds).of(described_class::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH)
end
end
end
end
context 'for daily events' do
it 'sets the keys in Redis to expire' do
described_class.track_event("no_slot", values: entity1)
Gitlab::Redis::SharedState.with do |redis|
keys = redis.scan_each(match: "*_no_slot").to_a
expect(keys).not_to be_empty
keys.each do |key|
expect(redis.ttl(key)).to be_within(5.seconds).of(described_class::DEFAULT_DAILY_KEY_EXPIRY_LENGTH)
expect(redis.ttl(key)).to be_within(5.seconds).of(described_class::KEY_EXPIRY_LENGTH)
end
end
end
@ -285,7 +185,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
values = [entity1, entity2]
expect(Gitlab::Redis::HLL).to receive(:add).with(key: /g_analytics_contribution/,
value: values,
expiry: described_class::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH)
expiry: described_class::KEY_EXPIRY_LENGTH)
described_class.track_event_in_context(:g_analytics_contribution, values: values, context: default_context)
end
@ -347,12 +247,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
expect(described_class.unique_events(event_names: [weekly_event], start_date: Date.current, end_date: 4.weeks.ago)).to eq(-1)
end
it "raise error if metrics don't have same aggregation" do
expect do
described_class.unique_events(event_names: [daily_event, weekly_event], start_date: 4.weeks.ago, end_date: Date.current)
end.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::AggregationMismatch)
end
context 'when data for the last complete week' do
it { expect(described_class.unique_events(event_names: [weekly_event], start_date: 1.week.ago, end_date: Date.current)).to eq(1) }
end
@ -369,12 +263,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
it { expect(described_class.unique_events(event_names: [weekly_event.to_sym], start_date: 4.weeks.ago, end_date: 3.weeks.ago)).to eq(1) }
end
context 'when using daily aggregation' do
it { expect(described_class.unique_events(event_names: [daily_event], start_date: 7.days.ago, end_date: Date.current)).to eq(2) }
it { expect(described_class.unique_events(event_names: [daily_event], start_date: 28.days.ago, end_date: Date.current)).to eq(3) }
it { expect(described_class.unique_events(event_names: [daily_event], start_date: 28.days.ago, end_date: 21.days.ago)).to eq(1) }
end
context 'when no slot is set' do
it { expect(described_class.unique_events(event_names: [no_slot], start_date: 7.days.ago, end_date: Date.current)).to eq(1) }
end
@ -388,7 +276,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
end
end
describe '.weekly_redis_keys' do
describe '.keys_for_aggregation' do
using RSpec::Parameterized::TableSyntax
let(:weekly_event) { 'i_search_total' }
@ -398,7 +286,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:week_three) { "{#{described_class::REDIS_SLOT}}_i_search_total-2021-01" }
let(:week_four) { "{#{described_class::REDIS_SLOT}}_i_search_total-2021-02" }
subject(:weekly_redis_keys) { described_class.send(:weekly_redis_keys, events: [redis_event], start_date: DateTime.parse(start_date), end_date: DateTime.parse(end_date)) }
subject(:keys_for_aggregation) { described_class.send(:keys_for_aggregation, events: [redis_event], start_date: DateTime.parse(start_date), end_date: DateTime.parse(end_date)) }
where(:start_date, :end_date, :keys) do
'2020-12-21' | '2020-12-21' | []
@ -421,11 +309,11 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
end
it 'returns 1 key for last for week' do
expect(described_class.send(:weekly_redis_keys, events: [redis_event], start_date: 7.days.ago.to_date, end_date: Date.current).size).to eq 1
expect(described_class.send(:keys_for_aggregation, events: [redis_event], start_date: 7.days.ago.to_date, end_date: Date.current).size).to eq 1
end
it 'returns 4 key for last for weeks' do
expect(described_class.send(:weekly_redis_keys, events: [redis_event], start_date: 4.weeks.ago.to_date, end_date: Date.current).size).to eq 4
expect(described_class.send(:keys_for_aggregation, events: [redis_event], start_date: 4.weeks.ago.to_date, end_date: Date.current).size).to eq 4
end
end
@ -434,9 +322,9 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:known_events) do
[
{ name: 'event_name_1', aggregation: "weekly" },
{ name: 'event_name_2', aggregation: "weekly" },
{ name: 'event_name_3', aggregation: "weekly" }
{ name: 'event_name_1' },
{ name: 'event_name_2' },
{ name: 'event_name_3' }
].map(&:with_indifferent_access)
end
@ -475,11 +363,11 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:time_range) { { start_date: 7.days.ago, end_date: DateTime.current } }
let(:known_events) do
[
{ name: 'event1_slot', aggregation: "weekly" },
{ name: 'event2_slot', aggregation: "weekly" },
{ name: 'event3_slot', aggregation: "weekly" },
{ name: 'event5_slot', aggregation: "daily" },
{ name: 'event4', aggregation: "weekly" }
{ name: 'event1_slot' },
{ name: 'event2_slot' },
{ name: 'event3_slot' },
{ name: 'event5_slot' },
{ name: 'event4' }
].map(&:with_indifferent_access)
end

Some files were not shown because too many files have changed in this diff Show More