Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a66948df0c
commit
112fe349cb
81 changed files with 548 additions and 257 deletions
|
@ -1031,6 +1031,7 @@ Gitlab/NamespacedClass:
|
|||
- 'app/finders/joined_groups_finder.rb'
|
||||
- 'app/finders/keys_finder.rb'
|
||||
- 'app/finders/labels_finder.rb'
|
||||
- 'app/finders/lfs_pointers_finder.rb'
|
||||
- 'app/finders/license_template_finder.rb'
|
||||
- 'app/finders/members_finder.rb'
|
||||
- 'app/finders/merge_request_target_project_finder.rb'
|
||||
|
|
|
@ -28,6 +28,10 @@ export default {
|
|||
GlLoadingIcon,
|
||||
GlIcon,
|
||||
UserAccessRoleBadge,
|
||||
ComplianceFrameworkLabel: () =>
|
||||
import(
|
||||
'ee_component/vue_shared/components/compliance_framework_label/compliance_framework_label.vue'
|
||||
),
|
||||
itemCaret,
|
||||
itemTypeIcon,
|
||||
itemStats,
|
||||
|
@ -67,6 +71,9 @@ export default {
|
|||
hasAvatar() {
|
||||
return this.group.avatarUrl !== null;
|
||||
},
|
||||
hasComplianceFramework() {
|
||||
return Boolean(this.group.complianceFramework?.name);
|
||||
},
|
||||
isGroup() {
|
||||
return this.group.type === 'group';
|
||||
},
|
||||
|
@ -82,6 +89,9 @@ export default {
|
|||
microdata() {
|
||||
return this.group.microdata || {};
|
||||
},
|
||||
complianceFramework() {
|
||||
return this.group.complianceFramework;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClickRowGroup(e) {
|
||||
|
@ -167,6 +177,13 @@ export default {
|
|||
<user-access-role-badge v-if="group.permission" class="gl-mt-3">
|
||||
{{ group.permission }}
|
||||
</user-access-role-badge>
|
||||
<compliance-framework-label
|
||||
v-if="hasComplianceFramework"
|
||||
class="gl-mt-3"
|
||||
:name="complianceFramework.name"
|
||||
:color="complianceFramework.color"
|
||||
:description="complianceFramework.description"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="group.description" class="description">
|
||||
<span
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { normalizeHeaders, parseIntPagination } from '../../lib/utils/common_utils';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
|
||||
import { getGroupItemMicrodata } from './utils';
|
||||
|
||||
export default class GroupsStore {
|
||||
|
@ -70,7 +71,7 @@ export default class GroupsStore {
|
|||
? rawGroupItem.subgroup_count
|
||||
: rawGroupItem.children_count;
|
||||
|
||||
return {
|
||||
const groupItem = {
|
||||
id: rawGroupItem.id,
|
||||
name: rawGroupItem.name,
|
||||
fullName: rawGroupItem.full_name,
|
||||
|
@ -98,6 +99,16 @@ export default class GroupsStore {
|
|||
pendingRemoval: rawGroupItem.marked_for_deletion,
|
||||
microdata: this.showSchemaMarkup ? getGroupItemMicrodata(rawGroupItem) : {},
|
||||
};
|
||||
|
||||
if (!isEmpty(rawGroupItem.compliance_management_framework)) {
|
||||
groupItem.complianceFramework = {
|
||||
name: rawGroupItem.compliance_management_framework.name,
|
||||
color: rawGroupItem.compliance_management_framework.color,
|
||||
description: rawGroupItem.compliance_management_framework.description,
|
||||
};
|
||||
}
|
||||
|
||||
return groupItem;
|
||||
}
|
||||
|
||||
removeGroup(group, parentGroup) {
|
||||
|
|
|
@ -35,7 +35,6 @@ import GlFieldErrors from './gl_field_errors';
|
|||
import initUserPopovers from './user_popovers';
|
||||
import initBroadcastNotifications from './broadcast_notification';
|
||||
import { initTopNav } from './nav';
|
||||
import navEventHub, { EVENT_RESPONSIVE_TOGGLE } from './nav/event_hub';
|
||||
|
||||
import 'ee_else_ce/main_ee';
|
||||
|
||||
|
@ -203,11 +202,7 @@ $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function ajaxComplete
|
|||
});
|
||||
|
||||
$('.navbar-toggler').on('click', () => {
|
||||
// The order is important. The `menu-expanded` is used as a source of truth for now.
|
||||
// This can be simplified when the :combined_menu feature flag is removed.
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/333180
|
||||
$('.header-content').toggleClass('menu-expanded');
|
||||
navEventHub.$emit(EVENT_RESPONSIVE_TOGGLE);
|
||||
document.body.classList.toggle('top-nav-responsive-open');
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
import { FREQUENT_ITEMS_PROJECTS, FREQUENT_ITEMS_GROUPS } from '~/frequent_items/constants';
|
||||
import { BV_DROPDOWN_SHOW, BV_DROPDOWN_HIDE } from '~/lib/utils/constants';
|
||||
import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue';
|
||||
import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '../event_hub';
|
||||
import { resetMenuItemsActive, hasMenuExpanded } from '../utils';
|
||||
import { resetMenuItemsActive } from '../utils';
|
||||
import ResponsiveHeader from './responsive_header.vue';
|
||||
import ResponsiveHome from './responsive_home.vue';
|
||||
import TopNavContainerView from './top_nav_container_view.vue';
|
||||
|
@ -33,25 +32,14 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
eventHub.$on(EVENT_RESPONSIVE_TOGGLE, this.updateResponsiveOpen);
|
||||
this.$root.$on(BV_DROPDOWN_SHOW, this.showMobileOverlay);
|
||||
this.$root.$on(BV_DROPDOWN_HIDE, this.hideMobileOverlay);
|
||||
|
||||
this.updateResponsiveOpen();
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off(EVENT_RESPONSIVE_TOGGLE, this.onToggle);
|
||||
this.$root.$off(BV_DROPDOWN_SHOW, this.showMobileOverlay);
|
||||
this.$root.$off(BV_DROPDOWN_HIDE, this.hideMobileOverlay);
|
||||
},
|
||||
methods: {
|
||||
updateResponsiveOpen() {
|
||||
if (hasMenuExpanded()) {
|
||||
document.body.classList.add('top-nav-responsive-open');
|
||||
} else {
|
||||
document.body.classList.remove('top-nav-responsive-open');
|
||||
}
|
||||
},
|
||||
onMenuItemClick({ view }) {
|
||||
if (view) {
|
||||
this.activeView = view;
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import eventHubFactory from '~/helpers/event_hub_factory';
|
||||
|
||||
export const EVENT_RESPONSIVE_TOGGLE = 'top-nav-responsive-toggle';
|
||||
|
||||
export default eventHubFactory();
|
|
@ -1,2 +0,0 @@
|
|||
export const hasMenuExpanded = () =>
|
||||
Boolean(document.querySelector('.header-content.menu-expanded'));
|
|
@ -1,2 +1 @@
|
|||
export * from './has_menu_expanded';
|
||||
export * from './reset_menu_items_active';
|
||||
|
|
|
@ -162,6 +162,9 @@ export const IMAGE_STATUS_ALERT_TYPE = {
|
|||
[DELETE_FAILED]: 'warning',
|
||||
};
|
||||
|
||||
export const PACKAGE_DELETE_HELP_PAGE_PATH = helpPagePath('user/packages/container_registry', {
|
||||
anchor: 'delete-images',
|
||||
});
|
||||
export const PACKAGE_DELETE_HELP_PAGE_PATH = helpPagePath(
|
||||
'user/packages/container_registry/index',
|
||||
{
|
||||
anchor: 'delete-images',
|
||||
},
|
||||
);
|
||||
|
|
|
@ -188,7 +188,7 @@ export default {
|
|||
<partial-cleanup-alert
|
||||
v-if="showPartialCleanupWarning"
|
||||
:run-cleanup-policies-help-page-path="config.runCleanupPoliciesHelpPagePath"
|
||||
:cleanup-policies-help-page-path="config.cleanupPoliciesHelpPagePath"
|
||||
:cleanup-policies-help-page-path="config.expirationPolicyHelpPagePath"
|
||||
@dismiss="dismissPartialCleanupWarning"
|
||||
/>
|
||||
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<script>
|
||||
/* eslint-disable vue/no-v-html */
|
||||
import { GlFormGroup, GlButton, GlModal, GlToast, GlToggle, GlLink } from '@gitlab/ui';
|
||||
import {
|
||||
GlFormGroup,
|
||||
GlButton,
|
||||
GlModal,
|
||||
GlToast,
|
||||
GlToggle,
|
||||
GlLink,
|
||||
GlSafeHtmlDirective,
|
||||
} from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
|
@ -18,6 +25,9 @@ export default {
|
|||
GlToggle,
|
||||
GlLink,
|
||||
},
|
||||
directives: {
|
||||
SafeHtml: GlSafeHtmlDirective,
|
||||
},
|
||||
formLabels: {
|
||||
createProject: __('Self monitoring'),
|
||||
},
|
||||
|
@ -137,7 +147,7 @@ export default {
|
|||
</div>
|
||||
<div class="settings-content">
|
||||
<form name="self-monitoring-form">
|
||||
<p ref="selfMonitoringFormText" v-html="selfMonitoringFormText"></p>
|
||||
<p ref="selfMonitoringFormText" v-safe-html="selfMonitoringFormText"></p>
|
||||
<gl-form-group>
|
||||
<gl-toggle
|
||||
v-model="selfMonitorEnabled"
|
||||
|
|
|
@ -27,17 +27,6 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important
|
|||
display: none;
|
||||
}
|
||||
|
||||
.menu-expanded {
|
||||
.more-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -103,18 +92,6 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important
|
|||
.navbar-collapse > ul.nav > li:not(.d-none) {
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
&.menu-expanded {
|
||||
@include media-breakpoint-down(xs) {
|
||||
.hide-when-menu-expanded {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
|
@ -673,19 +650,30 @@ $top-nav-hover-bg: var(--indigo-900-alpha-008, $indigo-900-alpha-008) !important
|
|||
}
|
||||
|
||||
.top-nav-responsive-open {
|
||||
.hide-when-top-nav-responsive-open {
|
||||
@include media-breakpoint-down(xs) {
|
||||
.more-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
.navbar-collapse {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.hide-when-top-nav-responsive-open {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.top-nav-responsive {
|
||||
@include media-breakpoint-down(xs) {
|
||||
.top-nav-responsive {
|
||||
@include gl-display-block;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-gitlab .header-content .title-container {
|
||||
flex: 0;
|
||||
.navbar-gitlab .header-content .title-container {
|
||||
flex: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
36
app/finders/lfs_pointers_finder.rb
Normal file
36
app/finders/lfs_pointers_finder.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class LfsPointersFinder
|
||||
def initialize(repository, path)
|
||||
@repository = repository
|
||||
@path = path
|
||||
end
|
||||
|
||||
def execute
|
||||
return [] unless ref
|
||||
|
||||
blob_ids = tree.blobs.map(&:id)
|
||||
|
||||
# When current endpoint is a Blob then `tree.blobs` will be empty, it means we need to analyze
|
||||
# the current Blob in order to determine if it's a LFS object
|
||||
blob_ids = Array.wrap(current_blob&.id) if blob_ids.empty?
|
||||
|
||||
Gitlab::Git::Blob.batch_lfs_pointers(repository, blob_ids).map(&:id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :repository, :path
|
||||
|
||||
def ref
|
||||
repository.root_ref
|
||||
end
|
||||
|
||||
def tree
|
||||
repository.tree(ref, path)
|
||||
end
|
||||
|
||||
def current_blob
|
||||
repository.blob_at(ref, path)
|
||||
end
|
||||
end
|
|
@ -59,8 +59,8 @@ module Projects
|
|||
# @return [Array<[user_id, access_level]>]
|
||||
def user_ids_and_access_levels_from_all_memberships
|
||||
strong_memoize(:user_ids_and_access_levels_from_all_memberships) do
|
||||
all_possible_avenues_of_membership.flat_map do |relation|
|
||||
relation.pluck(*USER_ID_AND_ACCESS_LEVEL) # rubocop: disable CodeReuse/ActiveRecord
|
||||
all_possible_avenues_of_membership.flat_map do |members|
|
||||
apply_scopes(members).pluck(*USER_ID_AND_ACCESS_LEVEL) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -86,7 +86,7 @@ module Projects
|
|||
members << Member.from_union(members_per_batch)
|
||||
end
|
||||
|
||||
members.flatten
|
||||
Member.from_union(members)
|
||||
end
|
||||
|
||||
def project_owner_acting_as_maintainer
|
||||
|
@ -120,6 +120,10 @@ module Projects
|
|||
Arel.sql(column_alias)
|
||||
)
|
||||
end
|
||||
|
||||
def apply_scopes(members)
|
||||
members
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Projects
|
||||
module Members
|
||||
class EffectiveAccessLevelPerUserFinder < EffectiveAccessLevelFinder
|
||||
def initialize(project, user)
|
||||
@project = project
|
||||
@user = user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :user
|
||||
|
||||
def apply_scopes(members)
|
||||
super.where(user_id: user.id) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AuthorizedProjectUpdate
|
||||
class ProjectRecalculatePerUserService < ProjectRecalculateService
|
||||
def initialize(project, user)
|
||||
@project = project
|
||||
@user = user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :user
|
||||
|
||||
def apply_scopes(project_authorizations)
|
||||
super.where(user_id: user.id) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
def effective_access_levels
|
||||
Projects::Members::EffectiveAccessLevelPerUserFinder.new(project, user).execute
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,7 +26,7 @@ module AuthorizedProjectUpdate
|
|||
|
||||
def current_authorizations
|
||||
strong_memoize(:current_authorizations) do
|
||||
project.project_authorizations
|
||||
apply_scopes(project.project_authorizations)
|
||||
.pluck(:user_id, :access_level) # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
|
@ -35,8 +35,7 @@ module AuthorizedProjectUpdate
|
|||
strong_memoize(:fresh_authorizations) do
|
||||
result = []
|
||||
|
||||
Projects::Members::EffectiveAccessLevelFinder.new(project)
|
||||
.execute
|
||||
effective_access_levels
|
||||
.each_batch(of: BATCH_SIZE, column: :user_id) do |member_batch|
|
||||
result += member_batch.pluck(:user_id, 'MAX(access_level)') # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
@ -76,5 +75,13 @@ module AuthorizedProjectUpdate
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def apply_scopes(project_authorizations)
|
||||
project_authorizations
|
||||
end
|
||||
|
||||
def effective_access_levels
|
||||
Projects::Members::EffectiveAccessLevelFinder.new(project).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
%a.gl-sr-only.gl-accessibility{ href: "#content-body" } Skip to content
|
||||
.container-fluid
|
||||
.header-content
|
||||
.title-container.hide-when-menu-expanded
|
||||
.title-container.hide-when-top-nav-responsive-open
|
||||
%h1.title
|
||||
%span.gl-sr-only GitLab
|
||||
= link_to root_path, title: _('Dashboard'), id: 'logo', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation') do
|
||||
|
|
|
@ -161,7 +161,7 @@ If the **primary** and **secondary** nodes have a checksum verification mismatch
|
|||
![Project administration page](img/checksum-differences-admin-project-page.png)
|
||||
|
||||
1. Go to the project's repository directory on both **primary** and **secondary** nodes
|
||||
(the path is usually `/var/opt/gitlab/git-data/repositories`). Note that if `git_data_dirs`
|
||||
(the path is usually `/var/opt/gitlab/git-data/repositories`). If `git_data_dirs`
|
||||
is customized, check the directory layout on your server to be sure:
|
||||
|
||||
```shell
|
||||
|
|
|
@ -94,7 +94,7 @@ follow these steps to avoid unnecessary data loss:
|
|||
|
||||
1. Until a [read-only mode](https://gitlab.com/gitlab-org/gitlab/-/issues/14609)
|
||||
is implemented, updates must be prevented from happening manually to the
|
||||
**primary**. Note that your **secondary** node still needs read-only
|
||||
**primary**. Your **secondary** node still needs read-only
|
||||
access to the **primary** node during the maintenance window:
|
||||
|
||||
1. At the scheduled time, using your cloud provider or your node's firewall, block
|
||||
|
|
|
@ -79,7 +79,7 @@ follow these steps to avoid unnecessary data loss:
|
|||
|
||||
1. Until a [read-only mode](https://gitlab.com/gitlab-org/gitlab/-/issues/14609)
|
||||
is implemented, updates must be prevented from happening manually to the
|
||||
**primary**. Note that your **secondary** node still needs read-only
|
||||
**primary**. Your **secondary** node still needs read-only
|
||||
access to the **primary** node during the maintenance window:
|
||||
|
||||
1. At the scheduled time, using your cloud provider or your node's firewall, block
|
||||
|
|
|
@ -101,12 +101,12 @@ From the perspective of a user performing Git operations:
|
|||
- The **primary** site behaves as a full read-write GitLab instance.
|
||||
- **Secondary** sites are read-only but proxy Git push operations to the **primary** site. This makes **secondary** sites appear to support push operations themselves.
|
||||
|
||||
To simplify the diagram, some necessary components are omitted. Note that:
|
||||
To simplify the diagram, some necessary components are omitted.
|
||||
|
||||
- Git over SSH requires [`gitlab-shell`](https://gitlab.com/gitlab-org/gitlab-shell) and OpenSSH.
|
||||
- Git over HTTPS required [`gitlab-workhorse`](https://gitlab.com/gitlab-org/gitlab-workhorse).
|
||||
|
||||
Note that a **secondary** site needs two different PostgreSQL databases:
|
||||
A **secondary** site needs two different PostgreSQL databases:
|
||||
|
||||
- A read-only database instance that streams data from the main GitLab database.
|
||||
- [Another database instance](#geo-tracking-database) used internally by the **secondary** site to record what data has been replicated.
|
||||
|
|
|
@ -286,9 +286,9 @@ The two most obvious issues that can become apparent in the dashboard are:
|
|||
- You are using a custom certificate or custom CA (see the [troubleshooting document](troubleshooting.md)).
|
||||
- The instance is firewalled (check your firewall rules).
|
||||
|
||||
Please note that disabling a **secondary** site stops the synchronization process.
|
||||
Disabling a **secondary** site stops the synchronization process.
|
||||
|
||||
Please note that if `git_data_dirs` is customized on the **primary** site for multiple
|
||||
If `git_data_dirs` is customized on the **primary** site for multiple
|
||||
repository shards you must duplicate the same configuration on each **secondary** site.
|
||||
|
||||
Point your users to the [Using a Geo Site guide](usage.md).
|
||||
|
|
|
@ -204,7 +204,7 @@ successfully, you must replicate their data using some other means.
|
|||
|[Server-side Git hooks](../../server_hooks.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1867) | No | No | |
|
||||
|[Elasticsearch integration](../../../integration/elasticsearch.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | No | |
|
||||
|[GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | Via Object Storage provider if supported. **No** native Geo support (Beta). | |
|
||||
|[Dependency proxy images](../../../user/packages/dependency_proxy/index.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/259694) | No | No | Blocked on [Geo: Secondary Mimicry](https://gitlab.com/groups/gitlab-org/-/epics/1528). Note that replication of this cache is not needed for Disaster Recovery purposes because it can be recreated from external sources. |
|
||||
|[Dependency proxy images](../../../user/packages/dependency_proxy/index.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/259694) | No | No | Blocked on [Geo: Secondary Mimicry](https://gitlab.com/groups/gitlab-org/-/epics/1528). Replication of this cache is not needed for Disaster Recovery purposes because it can be recreated from external sources. |
|
||||
|[Vulnerability Export](../../../user/application_security/vulnerability_report/#export-vulnerability-details) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | | Not planned because they are ephemeral and sensitive. They can be regenerated on demand. |
|
||||
|
||||
#### Limitation of verification for files in Object Storage
|
||||
|
|
|
@ -154,7 +154,7 @@ the **primary** database. Use the following as a guide.
|
|||
1. Generate an MD5 hash of the desired password for the database user that the
|
||||
GitLab application uses to access the read-replica database:
|
||||
|
||||
Note that the username (`gitlab` by default) is incorporated into the hash.
|
||||
The username (`gitlab` by default) is incorporated into the hash.
|
||||
|
||||
```shell
|
||||
gitlab-ctl pg-password-md5 gitlab
|
||||
|
@ -203,7 +203,7 @@ the **primary** database. Use the following as a guide.
|
|||
geo_postgresql['enable'] = false
|
||||
|
||||
##
|
||||
## Disable all other services that aren't needed. Note that we had to enable
|
||||
## Disable all other services that aren't needed. We had to enable
|
||||
## geo_secondary_role to cause some configuration changes to postgresql, but
|
||||
## the role enables single-node services by default.
|
||||
##
|
||||
|
@ -241,7 +241,7 @@ Configure the tracking database.
|
|||
1. Generate an MD5 hash of the desired password for the database user that the
|
||||
GitLab application uses to access the tracking database:
|
||||
|
||||
Note that the username (`gitlab_geo` by default) is incorporated into the
|
||||
The username (`gitlab_geo` by default) is incorporated into the
|
||||
hash.
|
||||
|
||||
```shell
|
||||
|
|
|
@ -242,7 +242,7 @@ the tracking database on port 5432.
|
|||
|
||||
1. Save the file and [reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
|
||||
1. The reconfigure should automatically create the database. If needed, you can perform this task manually. Note that this task (whether run by itself or during reconfigure) requires the database user to be a superuser.
|
||||
1. The reconfigure should automatically create the database. If needed, you can perform this task manually. This task (whether run by itself or during reconfigure) requires the database user to be a superuser.
|
||||
|
||||
```shell
|
||||
gitlab-rake geo:db:create
|
||||
|
|
|
@ -952,7 +952,7 @@ result as you did at the start. For example:
|
|||
{enforced="true",status="ok"} 4424.985419441742
|
||||
```
|
||||
|
||||
Note that `enforced="true"` means that authentication is being enforced.
|
||||
`enforced="true"` means that authentication is being enforced.
|
||||
|
||||
## Pack-objects cache **(FREE SELF)**
|
||||
|
||||
|
@ -1076,7 +1076,7 @@ cache hit and the average amount of storage used by cache files.
|
|||
Entries older than `max_age` get evicted from the in-memory metadata
|
||||
store, and deleted from disk.
|
||||
|
||||
Note that eviction does not interfere with ongoing requests, so it is OK
|
||||
Eviction does not interfere with ongoing requests, so it is OK
|
||||
for `max_age` to be less than the time it takes to do a fetch over a
|
||||
slow connection. This is because Unix filesystems do not truly delete
|
||||
a file until all processes that are reading the deleted file have
|
||||
|
|
|
@ -195,7 +195,7 @@ instructions only work on Omnibus-provided PostgreSQL:
|
|||
```
|
||||
|
||||
Replace `<PRAEFECT_SQL_PASSWORD_HASH>` with the hash of the password you generated in the
|
||||
preparation step. Note that it is prefixed with `md5` literal.
|
||||
preparation step. It is prefixed with `md5` literal.
|
||||
|
||||
1. The PgBouncer that is shipped with Omnibus is configured to use [`auth_query`](https://www.pgbouncer.org/config.html#generic-settings)
|
||||
and uses `pg_shadow_lookup` function. You need to create this function in `praefect_production`
|
||||
|
|
|
@ -80,7 +80,7 @@ GitLab displays your link in the **Menu > Admin > Monitoring > Metrics Dashboard
|
|||
|
||||
When setting up Grafana through the process above, no scope shows in the screen at
|
||||
**Menu >** **{admin}** **Admin > Applications > GitLab Grafana**. However, the `read_user` scope is
|
||||
required and is provided to the application automatically. Note that setting any scope other than
|
||||
required and is provided to the application automatically. Setting any scope other than
|
||||
`read_user` without also including `read_user` leads to this error when you try to log in using
|
||||
GitLab as the OAuth provider:
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ lookups via database lookup.
|
|||
|
||||
As part of [setting up Geo](../geo/index.md#setup-instructions),
|
||||
you are required to follow the steps outlined below for both the primary and
|
||||
secondary nodes, but note that the `Write to "authorized keys" file` checkbox
|
||||
secondary nodes, but the `Write to "authorized keys" file` checkbox
|
||||
only needs to be unchecked on the primary node since it is reflected
|
||||
automatically on the secondary if database replication is working.
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ which you can set it up:
|
|||
the Pages daemon is installed, so you must share it through the network.
|
||||
- Run the Pages daemon in the same server as GitLab, listening on the same IP
|
||||
but on different ports. In that case, you must proxy the traffic with
|
||||
a load balancer. If you choose that route note that you should use TCP load
|
||||
a load balancer. If you choose that route, you should use TCP load
|
||||
balancing for HTTPS. If you use TLS-termination (HTTPS-load balancing), the
|
||||
pages can't be served with user-provided certificates. For
|
||||
HTTP it's OK to use HTTP or TCP load balancing.
|
||||
|
|
|
@ -41,7 +41,7 @@ which you can set it up:
|
|||
the Pages daemon is installed, so you must share it through the network.
|
||||
1. Run the Pages daemon in the same server as GitLab, listening on the same IP
|
||||
but on different ports. In that case, you must proxy the traffic with
|
||||
a load balancer. If you choose that route, note that you should use TCP load
|
||||
a load balancer. If you choose that route, you should use TCP load
|
||||
balancing for HTTPS. If you use TLS-termination (HTTPS-load balancing), the
|
||||
pages aren't able to be served with user-provided certificates. For
|
||||
HTTP, it's OK to use HTTP or TCP load balancing.
|
||||
|
|
|
@ -889,7 +889,7 @@ with:
|
|||
sudo gitlab-ctl stop patroni
|
||||
```
|
||||
|
||||
Note that stopping or restarting Patroni service on the leader node will trigger the automatic failover. If you
|
||||
Stopping or restarting Patroni service on the leader node will trigger the automatic failover. If you
|
||||
want to signal Patroni to reload its configuration or restart PostgreSQL process without triggering the failover, you
|
||||
must use the `reload` or `restart` sub-commands of `gitlab-ctl patroni` instead. These two sub-commands are wrappers of
|
||||
the same `patronictl` commands.
|
||||
|
@ -1015,7 +1015,7 @@ Here are a few key facts that you must consider before upgrading PostgreSQL:
|
|||
- Upgrading PostgreSQL creates a new data directory with a new control data. From Patroni's perspective
|
||||
this is a new cluster that needs to be bootstrapped again. Therefore, as part of the upgrade procedure,
|
||||
the cluster state (stored in Consul) is wiped out. Once the upgrade is completed, Patroni
|
||||
bootstraps a new cluster. **Note that this changes your _cluster ID_**.
|
||||
bootstraps a new cluster. **This changes your _cluster ID_**.
|
||||
|
||||
- The procedures for upgrading leader and replicas are not the same. That is why it is important to use the
|
||||
right procedure on each node.
|
||||
|
|
|
@ -21,7 +21,7 @@ There are 3 things that are checked to determine integrity.
|
|||
1. Check for `config.lock` in the repository directory.
|
||||
1. Check for any branch/references lock files in `refs/heads`.
|
||||
|
||||
It's important to note that the existence of `config.lock` or reference locks
|
||||
The existence of `config.lock` or reference locks
|
||||
alone do not necessarily indicate a problem. Lock files are routinely created
|
||||
and removed as Git and GitLab perform operations on the repository. They serve
|
||||
to prevent data integrity issues. However, if a Git operation is interrupted these
|
||||
|
|
|
@ -683,8 +683,6 @@ To make this work with Sentinel:
|
|||
]
|
||||
```
|
||||
|
||||
Note that:
|
||||
|
||||
- Redis URLs should be in the format: `redis://:PASSWORD@SENTINEL_PRIMARY_NAME`, where:
|
||||
- `PASSWORD` is the plaintext password for the Redis instance.
|
||||
- `SENTINEL_PRIMARY_NAME` is the Sentinel primary name set with `redis['master_name']`,
|
||||
|
@ -731,7 +729,7 @@ redis_master_role['enable'] = true # enable only one of them
|
|||
redis_replica_role['enable'] = true # enable only one of them
|
||||
|
||||
# When Redis primary or Replica role are enabled, the following services are
|
||||
# enabled/disabled. Note that if Redis and Sentinel roles are combined, both
|
||||
# enabled/disabled. If Redis and Sentinel roles are combined, both
|
||||
# services are enabled.
|
||||
|
||||
# The following services are disabled
|
||||
|
|
|
@ -345,7 +345,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
|
|||
The Internal Load Balancer is used to balance any internal connections the GitLab environment requires
|
||||
such as connections to [PgBouncer](#configure-pgbouncer) and [Praefect](#configure-praefect) (Gitaly Cluster).
|
||||
|
||||
Note that it's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
It's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
|
||||
The following IP will be used as an example:
|
||||
|
||||
|
|
|
@ -347,7 +347,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
|
|||
The Internal Load Balancer is used to balance any internal connections the GitLab environment requires
|
||||
such as connections to [PgBouncer](#configure-pgbouncer) and [Praefect](#configure-praefect) (Gitaly Cluster).
|
||||
|
||||
Note that it's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
It's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
|
||||
The following IP will be used as an example:
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
|
|||
The Internal Load Balancer is used to balance any internal connections the GitLab environment requires
|
||||
such as connections to [PgBouncer](#configure-pgbouncer) and [Praefect](#configure-praefect) (Gitaly Cluster).
|
||||
|
||||
Note that it's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
It's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
|
||||
The following IP will be used as an example:
|
||||
|
||||
|
@ -2086,7 +2086,7 @@ but with smaller performance requirements, several modifications can be consider
|
|||
- Combining select nodes: Some nodes can be combined to reduce complexity at the cost of some performance:
|
||||
- GitLab Rails and Sidekiq: Sidekiq nodes can be removed and the component instead enabled on the GitLab Rails nodes.
|
||||
- PostgreSQL and PgBouncer: PgBouncer nodes can be removed and the component instead enabled on PostgreSQL with the Internal Load Balancer pointing to them instead.
|
||||
- Reducing the node counts: Some node types do not need consensus and can run with fewer nodes (but more than one for redundancy). Note that this will also lead to reduced performance.
|
||||
- Reducing the node counts: Some node types do not need consensus and can run with fewer nodes (but more than one for redundancy). This will also lead to reduced performance.
|
||||
- GitLab Rails and Sidekiq: Stateless services don't have a minimum node count. Two are enough for redundancy.
|
||||
- Gitaly and Praefect: A quorum is not strictly necessary. Two Gitaly nodes and two Praefect nodes are enough for redundancy.
|
||||
- Running select components in reputable Cloud PaaS solutions: Select components of the GitLab setup can instead be run on Cloud Provider PaaS solutions. By doing this, additional dependent components can also be removed:
|
||||
|
|
|
@ -354,7 +354,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
|
|||
The Internal Load Balancer is used to balance any internal connections the GitLab environment requires
|
||||
such as connections to [PgBouncer](#configure-pgbouncer) and [Praefect](#configure-praefect) (Gitaly Cluster).
|
||||
|
||||
Note that it's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
It's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
|
||||
The following IP will be used as an example:
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
|
|||
The Internal Load Balancer is used to balance any internal connections the GitLab environment requires
|
||||
such as connections to [PgBouncer](#configure-pgbouncer) and [Praefect](#configure-praefect) (Gitaly Cluster).
|
||||
|
||||
Note that it's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
It's a separate node from the External Load Balancer and shouldn't have any access externally.
|
||||
|
||||
The following IP will be used as an example:
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ session by running:
|
|||
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0')
|
||||
```
|
||||
|
||||
Note that this change only affects the current Rails console session and will
|
||||
This change only affects the current Rails console session and will
|
||||
not be persisted in the GitLab production environment or in the next Rails
|
||||
console session.
|
||||
|
||||
|
@ -213,7 +213,7 @@ downtime. Otherwise skip to the next section.
|
|||
exit
|
||||
```
|
||||
|
||||
Note that if the Puma process terminates before you are able to run these
|
||||
If the Puma process terminates before you are able to run these
|
||||
commands, GDB will report an error. To buy more time, you can always raise the
|
||||
Puma worker timeout. For omnibus users, you can edit `/etc/gitlab/gitlab.rb` and
|
||||
increase it from 60 seconds to 600:
|
||||
|
|
|
@ -22,7 +22,7 @@ guidance of a Support Engineer, or running them in a test environment with a
|
|||
backup of the instance ready to be restored, just in case.
|
||||
|
||||
WARNING:
|
||||
Please also note that as GitLab changes, changes to the code are inevitable,
|
||||
As GitLab changes, changes to the code are inevitable,
|
||||
and so some scripts may not work as they once used to. These are not kept
|
||||
up-to-date as these scripts/commands were added as they were found/needed. As
|
||||
mentioned above, we recommend running these scripts under the supervision of a
|
||||
|
|
|
@ -135,7 +135,7 @@ and they will assist you with any issues you are having.
|
|||
# source-style commands should also work
|
||||
cd /srv/gitlab && bundle exec rake gitlab:check RAILS_ENV=production
|
||||
|
||||
# run GitLab check. Note that the output can be confusing and invalid because of the specific structure of GitLab installed via helm chart
|
||||
# run GitLab check. The output can be confusing and invalid because of the specific structure of GitLab installed via helm chart
|
||||
/usr/local/bin/gitlab-rake gitlab:check
|
||||
|
||||
# open console without entering pod
|
||||
|
|
|
@ -265,7 +265,7 @@ user.save!(validate: false)
|
|||
This is not recommended, as validations are usually put in place to ensure the
|
||||
integrity and consistency of user-provided data.
|
||||
|
||||
Note that a validation error will prevent the entire object from being saved to
|
||||
A validation error will prevent the entire object from being saved to
|
||||
the database. We'll see a little of this in the next section. If you're getting
|
||||
a mysterious red banner in the GitLab UI when submitting a form, this can often
|
||||
be the fastest way to get to the root of the problem.
|
||||
|
|
|
@ -199,7 +199,7 @@ To fix this problem:
|
|||
git config --global http.sslCAInfo ~/.ssl/gitlab.domain.tld.crt
|
||||
```
|
||||
|
||||
- Disable SSL verification in your Git client. Note that this intended as a
|
||||
- Disable SSL verification in your Git client. This is intended as a
|
||||
temporary measure, as it could be considered a security risk.
|
||||
|
||||
```shell
|
||||
|
|
|
@ -57,7 +57,7 @@ Available types for the `action` parameter, and the resources that might be affe
|
|||
- Design
|
||||
- Wiki page
|
||||
|
||||
Note that these options are in lower case.
|
||||
These options are in lowercase.
|
||||
|
||||
### Target Types
|
||||
|
||||
|
@ -71,7 +71,7 @@ Available target types for the `target_type` parameter are:
|
|||
- `snippet`
|
||||
- `user`
|
||||
|
||||
Note that these options are in lower case.
|
||||
These options are in lowercase.
|
||||
|
||||
### Date formatting
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ POST /features/:name
|
|||
| `project` | string | no | A projects path, for example `gitlab-org/gitlab-foss` |
|
||||
| `force` | boolean | no | Skip feature flag validation checks, such as a YAML definition |
|
||||
|
||||
Note that you can enable or disable a feature for a `feature_group`, a `user`,
|
||||
You can enable or disable a feature for a `feature_group`, a `user`,
|
||||
a `group`, and a `project` in a single API call.
|
||||
|
||||
```shell
|
||||
|
|
|
@ -33,7 +33,7 @@ To use this in a [`script` definition](../ci/yaml/index.md#script) inside
|
|||
|
||||
- The `JOB-TOKEN` header with the GitLab-provided `CI_JOB_TOKEN` variable.
|
||||
For example, the following job downloads the artifacts of the job with ID
|
||||
`42`. Note that the command is wrapped into single quotes because it contains a
|
||||
`42`. The command is wrapped in single quotes because it contains a
|
||||
colon (`:`):
|
||||
|
||||
```yaml
|
||||
|
@ -98,7 +98,7 @@ To use this in a [`script` definition](../ci/yaml/index.md#script) inside
|
|||
|
||||
- The `JOB-TOKEN` header with the GitLab-provided `CI_JOB_TOKEN` variable.
|
||||
For example, the following job downloads the artifacts of the `test` job
|
||||
of the `main` branch. Note that the command is wrapped into single quotes
|
||||
of the `main` branch. The command is wrapped in single quotes
|
||||
because it contains a colon (`:`):
|
||||
|
||||
```yaml
|
||||
|
|
|
@ -85,7 +85,7 @@ Supported attributes:
|
|||
## Get a blob from repository
|
||||
|
||||
Allows you to receive information about blob in repository like size and
|
||||
content. Note that blob content is Base64 encoded. This endpoint can be accessed
|
||||
content. Blob content is Base64 encoded. This endpoint can be accessed
|
||||
without authentication if the repository is publicly accessible.
|
||||
|
||||
```plaintext
|
||||
|
@ -149,7 +149,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.com/api/v4/pr
|
|||
## Compare branches, tags or commits
|
||||
|
||||
This endpoint can be accessed without authentication if the repository is
|
||||
publicly accessible. Note that diffs could have an empty diff string if [diff limits](../development/diffs.md#diff-limits) are reached.
|
||||
publicly accessible. Diffs can have an empty diff string if [diff limits](../development/diffs.md#diff-limits) are reached.
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/repository/compare
|
||||
|
@ -607,7 +607,7 @@ template: |
|
|||
{% end %}
|
||||
```
|
||||
|
||||
Note that when specifying the template you should use `template: |` and not
|
||||
When specifying the template you should use `template: |` and not
|
||||
`template: >`, as the latter doesn't preserve newlines in the template.
|
||||
|
||||
### Template data
|
||||
|
|
|
@ -24,7 +24,7 @@ in the following table.
|
|||
## Get file from repository
|
||||
|
||||
Allows you to receive information about file in repository like name, size,
|
||||
content. Note that file content is Base64 encoded. This endpoint can be accessed
|
||||
content. File content is Base64 encoded. This endpoint can be accessed
|
||||
without authentication if the repository is publicly accessible.
|
||||
|
||||
```plaintext
|
||||
|
|
|
@ -259,7 +259,7 @@ GET /projects/:id/services/buildkite
|
|||
## Campfire
|
||||
|
||||
Send notifications about push events to Campfire chat rooms.
|
||||
Note that [new users can no longer sign up for Campfire](https://basecamp.com/retired/campfire).
|
||||
[New users can no longer sign up for Campfire](https://basecamp.com/retired/campfire).
|
||||
|
||||
### Create/Edit Campfire service
|
||||
|
||||
|
|
|
@ -408,7 +408,7 @@ users. Either `password`, `reset_password`, or `force_random_password`
|
|||
must be specified. If `reset_password` and `force_random_password` are
|
||||
both `false`, then `password` is required.
|
||||
|
||||
Note that `force_random_password` and `reset_password` take priority
|
||||
`force_random_password` and `reset_password` take priority
|
||||
over `password`. In addition, `reset_password` and
|
||||
`force_random_password` can be used together.
|
||||
|
||||
|
@ -1600,7 +1600,7 @@ Example response:
|
|||
> Requires admin permissions.
|
||||
> Token values are returned once. Make sure you save it - you can't access it again.
|
||||
|
||||
It creates a new impersonation token. Note that only administrators can do this.
|
||||
It creates a new impersonation token. Only administrators can do this.
|
||||
You are only able to create impersonation tokens to impersonate the user and perform
|
||||
both API calls and Git reads and writes. The user can't see these tokens in their profile
|
||||
settings page.
|
||||
|
|
|
@ -8,7 +8,7 @@ group: database
|
|||
|
||||
This document is a proposal to work towards reducing and limiting table sizes on GitLab.com. We establish a **measurable target** by limiting table size to a certain threshold. This will be used as an indicator to drive database focus and decision making. With GitLab.com growing, we continuously re-evaluate which tables need to be worked on to prevent or otherwise fix violations.
|
||||
|
||||
Note that this is not meant to be a hard rule but rather a strong indication that work needs to be done to break a table apart or otherwise reduce its size.
|
||||
This is not meant to be a hard rule but rather a strong indication that work needs to be done to break a table apart or otherwise reduce its size.
|
||||
|
||||
This is meant to be read in context with the [Database Sharding blueprint](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64115),
|
||||
which paints the bigger picture. This proposal here is thought to be part of the "debloating step" below, as we aim to reduce storage requirements and improve data modeling. Partitioning is part of the standard tool-belt: where possible, we can already use partitioning as a solution to cut physical table sizes significantly. Both will help to prepare efforts like decomposition (database usage is already optimized) and sharding (database is already partitioned along an identified data access dimension).
|
||||
|
@ -124,7 +124,7 @@ In order to maintain and improve operational stability and lessen development bu
|
|||
1. Indexes are smaller, can be maintained more efficiently and fit better into memory
|
||||
1. Data migrations are easier to reason about, take less time to implement and execute
|
||||
|
||||
Note that this target is *pragmatic*: We understand table sizes depend on feature usage, code changes and other factors - which all change over time. We may not always find solutions where we can tightly limit the size of physical tables once and for all. That is acceptable though and we primarily aim to keep the situation on GitLab.com under control. We adapt our efforts to the situation present on GitLab.com and will re-evaluate frequently.
|
||||
This target is *pragmatic*: We understand table sizes depend on feature usage, code changes and other factors - which all change over time. We may not always find solutions where we can tightly limit the size of physical tables once and for all. That is acceptable though and we primarily aim to keep the situation on GitLab.com under control. We adapt our efforts to the situation present on GitLab.com and will re-evaluate frequently.
|
||||
|
||||
While there are changes we can make that lead to a constant maximum physical table size over time, this doesn't need to be the case necessarily. Consider for example hash partitioniong, which breaks a table down into a static number of partitions. With data growth over time, individual partitions will also grow in size and may eventually reach the threshold size again. We strive to get constant table sizes, but it is acceptable to ship easier solutions that don't have this characteristic but improve the situation for a considerable amount of time.
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ We already use Database Lab from [postgres.ai](https://postgres.ai/), which is a
|
|||
|
||||
Internally, this is based on ZFS and implements a "thin-cloning technology". That is, ZFS snapshots are being used to clone the data and it exposes a full read/write PostgreSQL cluster based on the cloned data. This is called a *thin clone*. It is rather short lived and is going to be destroyed again shortly after we are finished using it.
|
||||
|
||||
It is important to note that a thin clone is fully read/write. This allows us to execute migrations on top of it.
|
||||
A thin clone is fully read/write. This allows us to execute migrations on top of it.
|
||||
|
||||
Database Lab provides an API we can interact with to manage thin clones. In order to automate the migration and query testing, we add steps to the `gitlab/gitlab-org` CI pipeline. This triggers automation that performs the following steps for a given merge request:
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ GitLab CI/CD supports numerous configuration options:
|
|||
| [Optimize GitLab and GitLab Runner for large repositories](large_repositories/index.md) | Recommended strategies for handling large repositories. |
|
||||
| [`.gitlab-ci.yml` full reference](yaml/index.md) | All the attributes you can use with GitLab CI/CD. |
|
||||
|
||||
Note that certain operations can only be performed according to the
|
||||
Certain operations can only be performed according to the
|
||||
[user](../user/permissions.md#gitlab-cicd-permissions) and [job](../user/permissions.md#job-permissions) permissions.
|
||||
|
||||
## Feature set
|
||||
|
|
|
@ -73,6 +73,13 @@ Do not use **Developer permissions**. A user who is assigned the Developer role
|
|||
See [the Microsoft style guide](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/d/disable-disabled) for guidance.
|
||||
Use **inactive** or **off** instead. ([Vale](../testing.md#vale) rule: [`InclusionAbleism.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionAbleism.yml))
|
||||
|
||||
## earlier
|
||||
|
||||
Use when talking about version numbers.
|
||||
|
||||
- Avoid: In GitLab 14.1 and lower.
|
||||
- Use instead: In GitLab 14.1 and earlier.
|
||||
|
||||
## easily
|
||||
|
||||
Do not use. If the user doesn't find the process to be easy, we lose their trust.
|
||||
|
@ -151,6 +158,13 @@ Do not use. If the user doesn't find the feature or process to be handy, we lose
|
|||
|
||||
Do not use. Instead, direct readers to the GitLab [reference architectures](../../../administration/reference_architectures/index.md) for information about configuring GitLab for handling greater amounts of users.
|
||||
|
||||
## higher
|
||||
|
||||
Do not use when talking about version numbers.
|
||||
|
||||
- Avoid: In GitLab 14.1 and higher.
|
||||
- Use instead: In GitLab 14.1 and later.
|
||||
|
||||
## I
|
||||
|
||||
Do not use first-person singular. Use **you**, **we**, or **us** instead. ([Vale](../testing.md#vale) rule: [`FirstPerson.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/FirstPerson.yml))
|
||||
|
@ -171,10 +185,24 @@ Lowercase.
|
|||
|
||||
Lowercase.
|
||||
|
||||
## later
|
||||
|
||||
Use when talking about version numbers.
|
||||
|
||||
- Avoid: In GitLab 14.1 and higher.
|
||||
- Use instead: In GitLab 14.1 and later.
|
||||
|
||||
## log in, log on
|
||||
|
||||
Do not use. Use [sign in](#sign-in) instead. If the user interface has **Log in**, you can use it.
|
||||
|
||||
## lower
|
||||
|
||||
Do not use when talking about version numbers.
|
||||
|
||||
- Avoid: In GitLab 14.1 and lower.
|
||||
- Use instead: In GitLab 14.1 and earlier.
|
||||
|
||||
## Maintainer
|
||||
|
||||
When writing about the Maintainer role:
|
||||
|
|
|
@ -6,9 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Akismet **(FREE)**
|
||||
|
||||
GitLab leverages [Akismet](https://akismet.com/) to protect against spam.
|
||||
GitLab uses Akismet to prevent the creation of spam issues on public projects. Issues
|
||||
created through the web UI or the API can be submitted to Akismet for review.
|
||||
GitLab uses [Akismet](https://akismet.com/) to prevent the creation of
|
||||
spam issues on public projects. Issues created through the web UI or the API can be submitted to
|
||||
Akismet for review.
|
||||
|
||||
Detected spam is rejected, and an entry is added in the **Spam Log** section of the
|
||||
Admin page.
|
||||
|
@ -19,7 +19,10 @@ NOTE:
|
|||
In GitLab 8.11 and later, all issues are submitted to Akismet.
|
||||
In earlier GitLab versions, this only applied to API and non-project members.
|
||||
|
||||
## Configuration
|
||||
Akismet configuration is available to users on self-managed GitLab. Akismet is already enabled on
|
||||
GitLab SaaS (GitLab.com), where it's configuration and management are handled by GitLab Inc.
|
||||
|
||||
## Configuration **(FREE SELF)**
|
||||
|
||||
To use Akismet:
|
||||
|
||||
|
@ -35,7 +38,7 @@ To use Akismet:
|
|||
|
||||
![Screenshot of Akismet settings](img/akismet_settings.png)
|
||||
|
||||
## Training
|
||||
## Training **(FREE SELF)**
|
||||
|
||||
To better differentiate between spam and ham, you can train the Akismet
|
||||
filter whenever there is a false positive or false negative.
|
||||
|
|
35
doc/legal/developer_certificate_of_origin.md
Normal file
35
doc/legal/developer_certificate_of_origin.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
stage: none
|
||||
group: unassigned
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Developer Certificate of Origin Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors, 1 Letterman Drive, Suite D4700, San Francisco, CA 94129, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
|
||||
|
||||
## License
|
||||
|
||||
All documentation content is licensed to this project under [Creative Commons: CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode).
|
||||
|
||||
All contributions to this project are licensed under the following license:
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -36,13 +36,13 @@ If you receive a license file from GitLab (for example a new trial), you can upl
|
|||
|
||||
The first time you visit your GitLab EE installation signed in as an administrator,
|
||||
you should see a note urging you to upload a license with a link that takes you
|
||||
to the **License** area.
|
||||
to the **Subscriptions** area.
|
||||
|
||||
Otherwise, to manually go to the **License** area:
|
||||
Otherwise, to manually go to the **Subscriptions** area:
|
||||
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
|
||||
1. On the left sidebar, select **License**, and select **Upload New License**.
|
||||
1. Sign in to your GitLab self-managed instance.
|
||||
1. From the top menu, select the Admin Area **{admin}**.
|
||||
1. From the left sidebar, select **Subscriptions**, and select **Upload a license file**.
|
||||
|
||||
- *If you've received a `.gitlab-license` file:*
|
||||
1. Download the license file to your local machine.
|
||||
|
@ -91,7 +91,7 @@ is active until the end of the license period. When that period ends, the
|
|||
instance will [fall back](#what-happens-when-your-license-expires) to Free-only
|
||||
functionality.
|
||||
|
||||
You can review the license details at any time by going to **Admin Area > License**.
|
||||
You can review the license details at any time by going to **Admin Area > Subscription**.
|
||||
|
||||
## Notification before the license expires
|
||||
|
||||
|
@ -111,12 +111,12 @@ before this occurs.
|
|||
- To resume functionality, upload a new license.
|
||||
- To fall back to Free features, delete all expired licenses.
|
||||
|
||||
### Remove a license
|
||||
### Remove a license file
|
||||
|
||||
To remove a license from a self-managed instance:
|
||||
To remove a license file from a self-managed instance:
|
||||
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin** to go to the [Admin Area](index.md).
|
||||
1. On the left sidebar, select **License**.
|
||||
1. From the top menu, select the Admin Area **{admin}**.
|
||||
1. From the left sidebar, select **Subscriptions**
|
||||
1. Select **Remove license**.
|
||||
|
||||
These steps may need to be repeated to completely remove all licenses, including those applied in the past.
|
||||
|
@ -134,7 +134,7 @@ The banner disappears after the new license becomes active.
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
### There is no License tab in the Admin Area
|
||||
### There is no Subscription tab in the Admin Area
|
||||
|
||||
If you originally installed Community Edition rather than Enterprise Edition you must
|
||||
[upgrade to Enterprise Edition](../../update/index.md#community-to-enterprise-edition)
|
||||
|
|
|
@ -423,6 +423,21 @@ CLI (`dotnet`):
|
|||
- `nuget install`: Install a package from the registry.
|
||||
- `dotnet add`: Install a package from the registry.
|
||||
|
||||
## Example project
|
||||
|
||||
For an example, see the Guided Exploration project
|
||||
[Utterly Automated Software and Artifact Versioning with GitVersion](https://gitlab.com/guided-explorations/devops-patterns/utterly-automated-versioning).
|
||||
This project:
|
||||
|
||||
- Generates NuGet packages by the `msbuild` method.
|
||||
- Generates NuGet packages by the `nuget.exe` method.
|
||||
- Uses GitLab releases and `release-cli` in connection with NuGet packaging.
|
||||
- Uses a tool called [GitVersion](https://gitversion.net/)
|
||||
to automatically determine and increment versions for the NuGet package in complex repositories.
|
||||
|
||||
You can copy this example project to your own group or instance for testing. See the project page
|
||||
for more details on what other GitLab CI patterns are demonstrated.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
To improve performance, NuGet caches files related to a package. If you encounter issues, clear the
|
||||
|
|
|
@ -47,16 +47,6 @@ module ExtractsPath
|
|||
end
|
||||
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
def lfs_blob_ids
|
||||
blob_ids = tree.blobs.map(&:id)
|
||||
|
||||
# When current endpoint is a Blob then `tree.blobs` will be empty, it means we need to analyze
|
||||
# the current Blob in order to determine if it's a LFS object
|
||||
blob_ids = Array.wrap(@repo.blob_at(@commit.id, @path)&.id) if blob_ids.empty? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
@lfs_blob_ids = Gitlab::Git::Blob.batch_lfs_pointers(repository_container.repository, blob_ids).map(&:id) # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Override in controllers to determine which actions are subject to the redirect
|
||||
|
|
|
@ -24,10 +24,13 @@ module Gitlab
|
|||
end
|
||||
|
||||
def log_error!(extra_context = {})
|
||||
error = LimitExceededError.new(message)
|
||||
# TODO: change this to Gitlab::ErrorTracking.log_exception(error, extra_context)
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/32906
|
||||
::Gitlab::ErrorTracking.track_exception(error, extra_context)
|
||||
::Gitlab::ErrorTracking.log_exception(limit_exceeded_error, extra_context)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def limit_exceeded_error
|
||||
LimitExceededError.new(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,7 +24,7 @@ module Gitlab
|
|||
name = :gitlab_ci_pipeline_size_builds
|
||||
comment = 'Pipeline size'
|
||||
labels = { source: nil }
|
||||
buckets = [0, 1, 5, 10, 20, 50, 100, 200, 500, 1000]
|
||||
buckets = [0, 1, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 3000]
|
||||
|
||||
::Gitlab::Metrics.histogram(name, comment, labels, buckets)
|
||||
end
|
||||
|
|
|
@ -14,8 +14,8 @@ module Gitlab
|
|||
@observations = []
|
||||
end
|
||||
|
||||
def observe(migration, &block)
|
||||
observation = Observation.new(migration)
|
||||
def observe(version:, name:, &block)
|
||||
observation = Observation.new(version, name)
|
||||
observation.success = true
|
||||
|
||||
exception = nil
|
||||
|
|
|
@ -4,7 +4,8 @@ module Gitlab
|
|||
module Database
|
||||
module Migrations
|
||||
Observation = Struct.new(
|
||||
:migration,
|
||||
:version,
|
||||
:name,
|
||||
:walltime,
|
||||
:success,
|
||||
:total_database_size_change,
|
||||
|
|
|
@ -23,7 +23,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def record(observation)
|
||||
File.rename(@file_path, File.join(Instrumentation::RESULT_DIR, "#{observation.migration}-query-details.json"))
|
||||
File.rename(@file_path, File.join(Instrumentation::RESULT_DIR, "#{observation.version}_#{observation.name}-query-details.json"))
|
||||
end
|
||||
|
||||
def record_sql_event(_name, started, finished, _unique_id, payload)
|
||||
|
|
|
@ -18,7 +18,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def record(observation)
|
||||
File.rename(@log_file_path, File.join(Instrumentation::RESULT_DIR, "#{observation.migration}.log"))
|
||||
File.rename(@log_file_path, File.join(Instrumentation::RESULT_DIR, "#{observation.version}_#{observation.name}.log"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -220,7 +220,7 @@ namespace :gitlab do
|
|||
instrumentation = Gitlab::Database::Migrations::Instrumentation.new
|
||||
|
||||
pending_migrations.each do |migration|
|
||||
instrumentation.observe(migration.version) do
|
||||
instrumentation.observe(version: migration.version, name: migration.name) do
|
||||
ActiveRecord::Migrator.new(:up, ctx.migrations, ctx.schema_migration, migration.version).run
|
||||
end
|
||||
end
|
||||
|
|
44
spec/finders/lfs_pointers_finder_spec.rb
Normal file
44
spec/finders/lfs_pointers_finder_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe LfsPointersFinder do
|
||||
subject(:finder) { described_class.new(repository, path) }
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:repository) { project.repository }
|
||||
|
||||
let(:path) { nil }
|
||||
|
||||
describe '#execute' do
|
||||
subject { finder.execute }
|
||||
|
||||
let(:expected_blob_id) { '0c304a93cb8430108629bbbcaa27db3343299bc0' }
|
||||
|
||||
context 'when path has no LFS files' do
|
||||
it { is_expected.to eq([]) }
|
||||
end
|
||||
|
||||
context 'when path points to LFS file' do
|
||||
let(:path) { 'files/lfs/lfs_object.iso' }
|
||||
|
||||
it 'returns LFS blob ids' do
|
||||
is_expected.to eq([expected_blob_id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when path points to directory with LFS files' do
|
||||
let(:path) { 'files/lfs/' }
|
||||
|
||||
it 'returns LFS blob ids' do
|
||||
is_expected.to eq([expected_blob_id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when repository is empty' do
|
||||
let(:project) { create(:project, :empty_repo) }
|
||||
|
||||
it { is_expected.to eq([]) }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Projects::Members::EffectiveAccessLevelPerUserFinder, '#execute' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
# The result set is being converted to json just for the ease of testing.
|
||||
subject { described_class.new(project, user).execute.as_json }
|
||||
|
||||
context 'a combination of all possible avenues of membership' do
|
||||
let_it_be(:another_user) { create(:user) }
|
||||
let_it_be(:shared_with_group) { create(:group) }
|
||||
|
||||
before do
|
||||
create(:project_group_link, :maintainer, project: project, group: shared_with_group)
|
||||
create(:group_group_link, :reporter, shared_group: project.group, shared_with_group: shared_with_group)
|
||||
|
||||
shared_with_group.add_maintainer(user)
|
||||
shared_with_group.add_maintainer(another_user)
|
||||
group.add_guest(user)
|
||||
group.add_guest(another_user)
|
||||
project.add_developer(user)
|
||||
project.add_developer(another_user)
|
||||
end
|
||||
|
||||
it 'includes the highest access level from all avenues of memberships for the specific user alone' do
|
||||
expect(subject).to eq(
|
||||
[{
|
||||
'user_id' => user.id,
|
||||
'access_level' => Gitlab::Access::MAINTAINER, # From project_group_link
|
||||
'id' => nil
|
||||
}]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import GroupFolder from '~/groups/components/group_folder.vue';
|
||||
import GroupItem from '~/groups/components/group_item.vue';
|
||||
import ItemActions from '~/groups/components/item_actions.vue';
|
||||
|
@ -22,8 +22,7 @@ describe('GroupItemComponent', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent();
|
||||
|
||||
return Vue.nextTick();
|
||||
return waitForPromises();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -3,16 +3,10 @@ import ResponsiveApp from '~/nav/components/responsive_app.vue';
|
|||
import ResponsiveHeader from '~/nav/components/responsive_header.vue';
|
||||
import ResponsiveHome from '~/nav/components/responsive_home.vue';
|
||||
import TopNavContainerView from '~/nav/components/top_nav_container_view.vue';
|
||||
import eventHub, { EVENT_RESPONSIVE_TOGGLE } from '~/nav/event_hub';
|
||||
import { resetMenuItemsActive } from '~/nav/utils/reset_menu_items_active';
|
||||
import KeepAliveSlots from '~/vue_shared/components/keep_alive_slots.vue';
|
||||
import { TEST_NAV_DATA } from '../mock_data';
|
||||
|
||||
const HTML_HEADER_CONTENT = '<div class="header-content"></div>';
|
||||
const HTML_MENU_EXPANDED = '<div class="menu-expanded"></div>';
|
||||
const HTML_HEADER_WITH_MENU_EXPANDED =
|
||||
'<div></div><div class="header-content menu-expanded"></div>';
|
||||
|
||||
describe('~/nav/components/responsive_app.vue', () => {
|
||||
let wrapper;
|
||||
|
||||
|
@ -26,13 +20,10 @@ describe('~/nav/components/responsive_app.vue', () => {
|
|||
},
|
||||
});
|
||||
};
|
||||
const triggerResponsiveToggle = () => eventHub.$emit(EVENT_RESPONSIVE_TOGGLE);
|
||||
|
||||
const findHome = () => wrapper.findComponent(ResponsiveHome);
|
||||
const findMobileOverlay = () => wrapper.find('[data-testid="mobile-overlay"]');
|
||||
const findSubviewHeader = () => wrapper.findComponent(ResponsiveHeader);
|
||||
const findSubviewContainer = () => wrapper.findComponent(TopNavContainerView);
|
||||
const hasBodyResponsiveOpen = () => document.body.classList.contains('top-nav-responsive-open');
|
||||
const hasMobileOverlayVisible = () => findMobileOverlay().classes('mobile-nav-open');
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -57,23 +48,6 @@ describe('~/nav/components/responsive_app.vue', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it.each`
|
||||
bodyHtml | expectation
|
||||
${''} | ${false}
|
||||
${HTML_HEADER_CONTENT} | ${false}
|
||||
${HTML_MENU_EXPANDED} | ${false}
|
||||
${HTML_HEADER_WITH_MENU_EXPANDED} | ${true}
|
||||
`(
|
||||
'with responsive toggle event and html set to $bodyHtml, responsive open = $expectation',
|
||||
({ bodyHtml, expectation }) => {
|
||||
document.body.innerHTML = bodyHtml;
|
||||
|
||||
triggerResponsiveToggle();
|
||||
|
||||
expect(hasBodyResponsiveOpen()).toBe(expectation);
|
||||
},
|
||||
);
|
||||
|
||||
it.each`
|
||||
events | expectation
|
||||
${[]} | ${false}
|
||||
|
@ -96,17 +70,6 @@ describe('~/nav/components/responsive_app.vue', () => {
|
|||
);
|
||||
});
|
||||
|
||||
describe('with menu expanded in body', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = HTML_HEADER_WITH_MENU_EXPANDED;
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('sets the body responsive open', () => {
|
||||
expect(hasBodyResponsiveOpen()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
const projectsContainerProps = {
|
||||
containerClass: 'gl-px-3',
|
||||
frequentItemsDropdownType: ResponsiveApp.FREQUENT_ITEMS_PROJECTS.namespace,
|
||||
|
@ -159,17 +122,4 @@ describe('~/nav/components/responsive_app.vue', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when destroyed', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('responsive toggle event does nothing', () => {
|
||||
triggerResponsiveToggle();
|
||||
|
||||
expect(hasBodyResponsiveOpen()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -335,7 +335,7 @@ describe('Details Page', () => {
|
|||
describe('Partial Cleanup Alert', () => {
|
||||
const config = {
|
||||
runCleanupPoliciesHelpPagePath: 'foo',
|
||||
cleanupPoliciesHelpPagePath: 'bar',
|
||||
expirationPolicyHelpPagePath: 'bar',
|
||||
userCalloutsPath: 'call_out_path',
|
||||
userCalloutId: 'call_out_id',
|
||||
showUnfinishedTagCleanupCallout: true,
|
||||
|
@ -367,7 +367,7 @@ describe('Details Page', () => {
|
|||
|
||||
expect(findPartialCleanupAlert().props()).toEqual({
|
||||
runCleanupPoliciesHelpPagePath: config.runCleanupPoliciesHelpPagePath,
|
||||
cleanupPoliciesHelpPagePath: config.cleanupPoliciesHelpPagePath,
|
||||
cleanupPoliciesHelpPagePath: config.expirationPolicyHelpPagePath,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -213,20 +213,4 @@ RSpec.describe ExtractsPath do
|
|||
expect(extract_ref_without_atom('foo.atom')).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#lfs_blob_ids' do
|
||||
let(:tag) { @project.repository.add_tag(@project.owner, 'my-annotated-tag', 'master', 'test tag') }
|
||||
let(:ref) { tag.target }
|
||||
let(:params) { { ref: ref, path: 'README.md' } }
|
||||
|
||||
before do
|
||||
@project = create(:project, :repository)
|
||||
end
|
||||
|
||||
it 'handles annotated tags' do
|
||||
assign_ref_vars
|
||||
|
||||
expect(lfs_blob_ids).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -85,7 +85,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Deployments do
|
|||
end
|
||||
|
||||
it 'logs the error' do
|
||||
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
|
||||
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
|
||||
instance_of(Gitlab::Ci::Limit::LimitExceededError),
|
||||
project_id: project.id, plan: namespace.actual_plan_name
|
||||
)
|
||||
|
|
|
@ -5,14 +5,15 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
describe '#observe' do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:migration) { 1234 }
|
||||
let(:migration_name) { 'test' }
|
||||
let(:migration_version) { '12345' }
|
||||
|
||||
it 'executes the given block' do
|
||||
expect { |b| subject.observe(migration, &b) }.to yield_control
|
||||
expect { |b| subject.observe(version: migration_version, name: migration_name, &b) }.to yield_control
|
||||
end
|
||||
|
||||
context 'behavior with observers' do
|
||||
subject { described_class.new(observers).observe(migration) {} }
|
||||
subject { described_class.new(observers).observe(version: migration_version, name: migration_name) {} }
|
||||
|
||||
let(:observers) { [observer] }
|
||||
let(:observer) { instance_double('Gitlab::Database::Migrations::Observers::MigrationObserver', before: nil, after: nil, record: nil) }
|
||||
|
@ -21,7 +22,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
expect(observer).to receive(:before).ordered
|
||||
expect(observer).to receive(:after).ordered
|
||||
expect(observer).to receive(:record).ordered do |observation|
|
||||
expect(observation.migration).to eq(migration)
|
||||
expect(observation.version).to eq(migration_version)
|
||||
end
|
||||
|
||||
subject
|
||||
|
@ -47,7 +48,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
end
|
||||
|
||||
context 'on successful execution' do
|
||||
subject { described_class.new.observe(migration) {} }
|
||||
subject { described_class.new.observe(version: migration_version, name: migration_name) {} }
|
||||
|
||||
it 'records walltime' do
|
||||
expect(subject.walltime).not_to be_nil
|
||||
|
@ -58,12 +59,16 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
end
|
||||
|
||||
it 'records the migration version' do
|
||||
expect(subject.migration).to eq(migration)
|
||||
expect(subject.version).to eq(migration_version)
|
||||
end
|
||||
|
||||
it 'records the migration name' do
|
||||
expect(subject.name).to eq(migration_name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'upon failure' do
|
||||
subject { described_class.new.observe(migration) { raise 'something went wrong' } }
|
||||
subject { described_class.new.observe(version: migration_version, name: migration_name) { raise 'something went wrong' } }
|
||||
|
||||
it 'raises the exception' do
|
||||
expect { subject }.to raise_error(/something went wrong/)
|
||||
|
@ -73,7 +78,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
subject { instance.observations.first }
|
||||
|
||||
before do
|
||||
instance.observe(migration) { raise 'something went wrong' }
|
||||
instance.observe(version: migration_version, name: migration_name) { raise 'something went wrong' }
|
||||
rescue StandardError
|
||||
# ignore
|
||||
end
|
||||
|
@ -89,7 +94,11 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
end
|
||||
|
||||
it 'records the migration version' do
|
||||
expect(subject.migration).to eq(migration)
|
||||
expect(subject.version).to eq(migration_version)
|
||||
end
|
||||
|
||||
it 'records the migration name' do
|
||||
expect(subject.name).to eq(migration_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -101,8 +110,8 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
|||
let(:migration2) { double('migration2', call: nil) }
|
||||
|
||||
it 'records observations for all migrations' do
|
||||
subject.observe('migration1') {}
|
||||
subject.observe('migration2') { raise 'something went wrong' } rescue nil
|
||||
subject.observe(version: migration_version, name: migration_name) {}
|
||||
subject.observe(version: migration_version, name: migration_name) { raise 'something went wrong' } rescue nil
|
||||
|
||||
expect(subject.observations.size).to eq(2)
|
||||
end
|
||||
|
|
|
@ -4,14 +4,15 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::Database::Migrations::Observers::QueryDetails do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration) }
|
||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
||||
let(:connection) { ActiveRecord::Base.connection }
|
||||
let(:query) { "select date_trunc('day', $1::timestamptz) + $2 * (interval '1 hour')" }
|
||||
let(:query_binds) { [Time.current, 3] }
|
||||
let(:directory_path) { Dir.mktmpdir }
|
||||
let(:log_file) { "#{directory_path}/#{migration}-query-details.json" }
|
||||
let(:log_file) { "#{directory_path}/#{migration_version}_#{migration_name}-query-details.json" }
|
||||
let(:query_details) { Gitlab::Json.parse(File.read(log_file)) }
|
||||
let(:migration) { 20210422152437 }
|
||||
let(:migration_version) { 20210422152437 }
|
||||
let(:migration_name) { 'test' }
|
||||
|
||||
before do
|
||||
stub_const('Gitlab::Database::Migrations::Instrumentation::RESULT_DIR', directory_path)
|
||||
|
|
|
@ -4,12 +4,13 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::Database::Migrations::Observers::QueryLog do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration) }
|
||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
||||
let(:connection) { ActiveRecord::Base.connection }
|
||||
let(:query) { 'select 1' }
|
||||
let(:directory_path) { Dir.mktmpdir }
|
||||
let(:log_file) { "#{directory_path}/current.log" }
|
||||
let(:migration) { 20210422152437 }
|
||||
let(:migration_version) { 20210422152437 }
|
||||
let(:migration_name) { 'test' }
|
||||
|
||||
before do
|
||||
stub_const('Gitlab::Database::Migrations::Instrumentation::RESULT_DIR', directory_path)
|
||||
|
@ -22,7 +23,7 @@ RSpec.describe Gitlab::Database::Migrations::Observers::QueryLog do
|
|||
it 'writes a file with the query log' do
|
||||
observe
|
||||
|
||||
expect(File.read("#{directory_path}/#{migration}.log")).to include(query)
|
||||
expect(File.read("#{directory_path}/#{migration_version}_#{migration_name}.log")).to include(query)
|
||||
end
|
||||
|
||||
it 'does not change the default logger' do
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe AuthorizedProjectUpdate::ProjectRecalculatePerUserService, '#execute' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:another_user) { create(:user) }
|
||||
|
||||
subject(:execute) { described_class.new(project, user).execute }
|
||||
|
||||
it 'returns success' do
|
||||
expect(execute.success?).to eq(true)
|
||||
end
|
||||
|
||||
context 'when there are no changes to be made' do
|
||||
it 'does not change authorizations' do
|
||||
expect { execute }.not_to(change { ProjectAuthorization.count })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are changes to be made' do
|
||||
context 'when addition is required' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
project.add_developer(another_user)
|
||||
project.project_authorizations.where(user: [user, another_user]).delete_all
|
||||
end
|
||||
|
||||
it 'adds a new authorization record for the specific user' do
|
||||
expect { execute }.to(
|
||||
change { project.project_authorizations.where(user: user).count }
|
||||
.from(0).to(1)
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not add a new authorization record for the other user' do
|
||||
expect { execute }.not_to(
|
||||
change { project.project_authorizations.where(user: another_user).count }
|
||||
)
|
||||
end
|
||||
|
||||
it 'adds a new authorization record with the correct access level for the specific user' do
|
||||
execute
|
||||
|
||||
project_authorization = project.project_authorizations.where(
|
||||
user: user,
|
||||
access_level: Gitlab::Access::DEVELOPER
|
||||
)
|
||||
|
||||
expect(project_authorization).to exist
|
||||
end
|
||||
end
|
||||
|
||||
context 'when removal is required' do
|
||||
before do
|
||||
create(:project_authorization, user: user, project: project)
|
||||
create(:project_authorization, user: another_user, project: project)
|
||||
end
|
||||
|
||||
it 'removes the authorization record for the specific user' do
|
||||
expect { execute }.to(
|
||||
change { project.project_authorizations.where(user: user).count }
|
||||
.from(1).to(0)
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not remove the authorization record for the other user' do
|
||||
expect { execute }.not_to(
|
||||
change { project.project_authorizations.where(user: another_user).count }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an update in access level is required' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
project.add_developer(another_user)
|
||||
project.project_authorizations.where(user: [user, another_user]).delete_all
|
||||
create(:project_authorization, project: project, user: user, access_level: Gitlab::Access::GUEST)
|
||||
create(:project_authorization, project: project, user: another_user, access_level: Gitlab::Access::GUEST)
|
||||
end
|
||||
|
||||
it 'updates the authorization of the specific user to the correct access level' do
|
||||
expect { execute }.to(
|
||||
change { project.project_authorizations.find_by(user: user).access_level }
|
||||
.from(Gitlab::Access::GUEST).to(Gitlab::Access::DEVELOPER)
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not update the authorization of the other user to the correct access level' do
|
||||
expect { execute }.not_to(
|
||||
change { project.project_authorizations.find_by(user: another_user).access_level }
|
||||
.from(Gitlab::Access::GUEST)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -276,8 +276,8 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout do
|
|||
let(:ctx) { double('ctx', migrations: all_migrations, schema_migration: double, get_all_versions: existing_versions) }
|
||||
let(:instrumentation) { instance_double(Gitlab::Database::Migrations::Instrumentation, observations: observations) }
|
||||
let(:existing_versions) { [1] }
|
||||
let(:all_migrations) { [double('migration1', version: 1), pending_migration] }
|
||||
let(:pending_migration) { double('migration2', version: 2) }
|
||||
let(:all_migrations) { [double('migration1', version: 1, name: 'test'), pending_migration] }
|
||||
let(:pending_migration) { double('migration2', version: 2, name: 'test') }
|
||||
let(:filename) { Gitlab::Database::Migrations::Instrumentation::STATS_FILENAME }
|
||||
let(:result_dir) { Dir.mktmpdir }
|
||||
let(:observations) { %w[some data] }
|
||||
|
@ -303,7 +303,7 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout do
|
|||
end
|
||||
|
||||
it 'instruments the pending migration' do
|
||||
expect(instrumentation).to receive(:observe).with(2).and_yield
|
||||
expect(instrumentation).to receive(:observe).with(version: 2, name: 'test').and_yield
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
|
@ -15,7 +15,6 @@ RSpec.describe 'projects/tree/show' do
|
|||
before do
|
||||
assign(:project, project)
|
||||
assign(:repository, repository)
|
||||
assign(:lfs_blob_ids, [])
|
||||
|
||||
allow(view).to receive(:can?).and_return(true)
|
||||
allow(view).to receive(:can_collaborate_with_project?).and_return(true)
|
||||
|
|
Loading…
Reference in a new issue