Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
484a245a95
commit
59429d48eb
16 changed files with 132 additions and 170 deletions
|
@ -1 +1 @@
|
||||||
5c49f857a37ee47158e2caff7c963e7de9563e8b
|
1d200302f736b50b48bf7e9ec7eb28f0e01dc559
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlButton, GlModal } from '@gitlab/ui';
|
import { GlButton } from '@gitlab/ui';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||||
import { s__ } from '~/locale';
|
import { s__ } from '~/locale';
|
||||||
|
@ -7,13 +7,23 @@ import Autosave from '~/autosave';
|
||||||
import { isLoggedIn } from '~/lib/utils/common_utils';
|
import { isLoggedIn } from '~/lib/utils/common_utils';
|
||||||
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
|
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
|
||||||
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
|
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
|
||||||
|
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DesignReplyForm',
|
name: 'DesignReplyForm',
|
||||||
|
i18n: {
|
||||||
|
primaryBtn: s__('DesignManagement|Discard changes'),
|
||||||
|
cancelBtnCreate: s__('DesignManagement|Continue creating'),
|
||||||
|
cancelBtnUpdate: s__('DesignManagement|Continue editing'),
|
||||||
|
cancelCreate: s__('DesignManagement|Are you sure you want to cancel creating this comment?'),
|
||||||
|
cancelUpdate: s__('DesignManagement|Are you sure you want to cancel editing this comment?'),
|
||||||
|
newCommentButton: s__('DesignManagement|Comment'),
|
||||||
|
updateCommentButton: s__('DesignManagement|Save comment'),
|
||||||
|
},
|
||||||
|
markdownDocsPath: helpPagePath('user/markdown'),
|
||||||
components: {
|
components: {
|
||||||
MarkdownField,
|
MarkdownField,
|
||||||
GlButton,
|
GlButton,
|
||||||
GlModal,
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
markdownPreviewPath: {
|
markdownPreviewPath: {
|
||||||
|
@ -54,29 +64,10 @@ export default {
|
||||||
hasValue() {
|
hasValue() {
|
||||||
return this.value.trim().length > 0;
|
return this.value.trim().length > 0;
|
||||||
},
|
},
|
||||||
modalSettings() {
|
|
||||||
if (this.isNewComment) {
|
|
||||||
return {
|
|
||||||
title: s__('DesignManagement|Cancel comment confirmation'),
|
|
||||||
okTitle: s__('DesignManagement|Discard comment'),
|
|
||||||
cancelTitle: s__('DesignManagement|Keep comment'),
|
|
||||||
content: s__('DesignManagement|Are you sure you want to cancel creating this comment?'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
title: s__('DesignManagement|Cancel comment update confirmation'),
|
|
||||||
okTitle: s__('DesignManagement|Cancel changes'),
|
|
||||||
cancelTitle: s__('DesignManagement|Keep changes'),
|
|
||||||
content: s__('DesignManagement|Are you sure you want to cancel changes to this comment?'),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
buttonText() {
|
buttonText() {
|
||||||
return this.isNewComment
|
return this.isNewComment
|
||||||
? s__('DesignManagement|Comment')
|
? this.$options.i18n.newCommentButton
|
||||||
: s__('DesignManagement|Save comment');
|
: this.$options.i18n.updateCommentButton;
|
||||||
},
|
|
||||||
markdownDocsPath() {
|
|
||||||
return helpPagePath('user/markdown');
|
|
||||||
},
|
},
|
||||||
shortDiscussionId() {
|
shortDiscussionId() {
|
||||||
return isGid(this.discussionId) ? getIdFromGraphQLId(this.discussionId) : this.discussionId;
|
return isGid(this.discussionId) ? getIdFromGraphQLId(this.discussionId) : this.discussionId;
|
||||||
|
@ -94,12 +85,30 @@ export default {
|
||||||
},
|
},
|
||||||
cancelComment() {
|
cancelComment() {
|
||||||
if (this.hasValue && this.formText !== this.value) {
|
if (this.hasValue && this.formText !== this.value) {
|
||||||
this.$refs.cancelCommentModal.show();
|
this.confirmCancelCommentModal();
|
||||||
} else {
|
} else {
|
||||||
this.$emit('cancel-form');
|
this.$emit('cancel-form');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmCancelCommentModal() {
|
async confirmCancelCommentModal() {
|
||||||
|
const msg = this.isNewComment
|
||||||
|
? this.$options.i18n.cancelCreate
|
||||||
|
: this.$options.i18n.cancelUpdate;
|
||||||
|
|
||||||
|
const cancelBtn = this.isNewComment
|
||||||
|
? this.$options.i18n.cancelBtnCreate
|
||||||
|
: this.$options.i18n.cancelBtnUpdate;
|
||||||
|
|
||||||
|
const confirmed = await confirmAction(msg, {
|
||||||
|
primaryBtnText: this.$options.i18n.primaryBtn,
|
||||||
|
cancelBtnText: cancelBtn,
|
||||||
|
primaryBtnVariant: 'danger',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.$emit('cancel-form');
|
this.$emit('cancel-form');
|
||||||
this.autosaveDiscussion.reset();
|
this.autosaveDiscussion.reset();
|
||||||
},
|
},
|
||||||
|
@ -126,7 +135,7 @@ export default {
|
||||||
:markdown-preview-path="markdownPreviewPath"
|
:markdown-preview-path="markdownPreviewPath"
|
||||||
:enable-autocomplete="true"
|
:enable-autocomplete="true"
|
||||||
:textarea-value="value"
|
:textarea-value="value"
|
||||||
:markdown-docs-path="markdownDocsPath"
|
:markdown-docs-path="$options.markdownDocsPath"
|
||||||
class="bordered-box"
|
class="bordered-box"
|
||||||
>
|
>
|
||||||
<template #textarea>
|
<template #textarea>
|
||||||
|
@ -171,15 +180,5 @@ export default {
|
||||||
>{{ __('Cancel') }}</gl-button
|
>{{ __('Cancel') }}</gl-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<gl-modal
|
|
||||||
ref="cancelCommentModal"
|
|
||||||
ok-variant="danger"
|
|
||||||
:title="modalSettings.title"
|
|
||||||
:ok-title="modalSettings.okTitle"
|
|
||||||
:cancel-title="modalSettings.cancelTitle"
|
|
||||||
modal-id="cancel-comment-modal"
|
|
||||||
@ok="confirmCancelCommentModal"
|
|
||||||
>{{ modalSettings.content }}
|
|
||||||
</gl-modal>
|
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -311,8 +311,6 @@ class ProjectsController < Projects::ApplicationController
|
||||||
find_tags = true
|
find_tags = true
|
||||||
find_commits = true
|
find_commits = true
|
||||||
|
|
||||||
use_gitaly_pagination = Feature.enabled?(:use_gitaly_pagination_for_refs, @project)
|
|
||||||
|
|
||||||
unless find_refs.nil?
|
unless find_refs.nil?
|
||||||
find_branches = find_refs.include?('branches')
|
find_branches = find_refs.include?('branches')
|
||||||
find_tags = find_refs.include?('tags')
|
find_tags = find_refs.include?('tags')
|
||||||
|
@ -323,7 +321,7 @@ class ProjectsController < Projects::ApplicationController
|
||||||
|
|
||||||
if find_branches
|
if find_branches
|
||||||
branches = BranchesFinder.new(@repository, refs_params.merge(per_page: REFS_LIMIT))
|
branches = BranchesFinder.new(@repository, refs_params.merge(per_page: REFS_LIMIT))
|
||||||
.execute(gitaly_pagination: use_gitaly_pagination)
|
.execute(gitaly_pagination: true)
|
||||||
.take(REFS_LIMIT)
|
.take(REFS_LIMIT)
|
||||||
.map(&:name)
|
.map(&:name)
|
||||||
|
|
||||||
|
@ -332,7 +330,7 @@ class ProjectsController < Projects::ApplicationController
|
||||||
|
|
||||||
if find_tags && @repository.tag_count.nonzero?
|
if find_tags && @repository.tag_count.nonzero?
|
||||||
tags = TagsFinder.new(@repository, refs_params.merge(per_page: REFS_LIMIT))
|
tags = TagsFinder.new(@repository, refs_params.merge(per_page: REFS_LIMIT))
|
||||||
.execute(gitaly_pagination: use_gitaly_pagination)
|
.execute(gitaly_pagination: true)
|
||||||
.take(REFS_LIMIT)
|
.take(REFS_LIMIT)
|
||||||
.map(&:name)
|
.map(&:name)
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,9 @@ module BulkImports
|
||||||
def export_status
|
def export_status
|
||||||
strong_memoize(:export_status) do
|
strong_memoize(:export_status) do
|
||||||
fetch_export_status&.find { |item| item['relation'] == relation }
|
fetch_export_status&.find { |item| item['relation'] == relation }
|
||||||
|
rescue StandardError => e
|
||||||
|
{ 'status' => Export::FAILED, 'error' => e.message }
|
||||||
end
|
end
|
||||||
rescue StandardError => e
|
|
||||||
{ 'status' => Export::FAILED, 'error' => e.message }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_export_status
|
def fetch_export_status
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
name: use_gitaly_pagination_for_refs
|
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96448
|
|
||||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372049
|
|
||||||
milestone: '15.4'
|
|
||||||
type: development
|
|
||||||
group: group::source code
|
|
||||||
default_enabled: true
|
|
|
@ -53,6 +53,10 @@ Each time you implement a new feature/endpoint, whether it is at UI, API or Grap
|
||||||
|
|
||||||
Be careful to **also test [visibility levels](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/doc/development/permissions.md#feature-specific-permissions)** and not only project access rights.
|
Be careful to **also test [visibility levels](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/doc/development/permissions.md#feature-specific-permissions)** and not only project access rights.
|
||||||
|
|
||||||
|
The HTTP status code returned when an authorization check fails should generally be `404 Not Found` in order to avoid revealing information
|
||||||
|
about whether or not the requested resource exists. `403 Forbidden` may be appropriate if you need to display a specific message to the user
|
||||||
|
about why they cannot access the resource. If you are displaying a generic message such as "access denied", consider returning `404 Not Found` instead.
|
||||||
|
|
||||||
Some example of well implemented access controls and tests:
|
Some example of well implemented access controls and tests:
|
||||||
|
|
||||||
1. [example1](https://dev.gitlab.org/gitlab/gitlab-ee/-/merge_requests/710/diffs?diff_id=13750#af40ef0eaae3c1e018809e1d88086e32bccaca40_43_43)
|
1. [example1](https://dev.gitlab.org/gitlab/gitlab-ee/-/merge_requests/710/diffs?diff_id=13750#af40ef0eaae3c1e018809e1d88086e32bccaca40_43_43)
|
||||||
|
|
|
@ -136,6 +136,9 @@ We use the following categories to classify a metric:
|
||||||
- `subscription`: Data related to licensing.
|
- `subscription`: Data related to licensing.
|
||||||
- `standard`: Standard set of identifiers that are included when collecting data.
|
- `standard`: Standard set of identifiers that are included when collecting data.
|
||||||
|
|
||||||
|
An aggregate metric is a metric that is the sum of two or more child metrics. Service Ping uses the data category of
|
||||||
|
the aggregate metric to determine whether or not the data is included in the reported Service Ping payload.
|
||||||
|
|
||||||
### Metric name suggestion examples
|
### Metric name suggestion examples
|
||||||
|
|
||||||
#### Metric with `data_source: database`
|
#### Metric with `data_source: database`
|
||||||
|
|
|
@ -176,42 +176,36 @@ To change the password for this customers portal account:
|
||||||
|
|
||||||
### GitLab for Education
|
### GitLab for Education
|
||||||
|
|
||||||
For qualifying non-profit educational institutions, the [GitLab for Education](https://about.gitlab.com/solutions/education/) program provides
|
For qualifying non-profit educational institutions, the [GitLab for Education Program](https://about.gitlab.com/solutions/education/) provides GitLab Ultimate, plus 50,000 CI/CD minutes per month. The subscription granted under GitLab for Education can only be used for instructional use or non-commercial academic research. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Education Program page](https://about.gitlab.com/solutions/education/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/community-programs/education-program/).
|
||||||
the top GitLab tier, plus 50,000 CI/CD minutes per month.
|
|
||||||
|
|
||||||
The GitLab for Education license can only be used for instructional-use or
|
|
||||||
non-commercial academic research.
|
|
||||||
|
|
||||||
Find more information on how to apply and renew at
|
|
||||||
[GitLab for Education](https://about.gitlab.com/solutions/education/).
|
|
||||||
|
|
||||||
### GitLab for Open Source
|
### GitLab for Open Source
|
||||||
|
|
||||||
For qualifying open source projects, the [GitLab for Open Source Program](https://about.gitlab.com/solutions/open-source/) provides
|
For qualifying open source projects, the [GitLab for Open Source Program](https://about.gitlab.com/solutions/open-source/) provides GitLab Ultimate, plus 50,000 CI/CD minutes per month. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Open Source Program page](https://about.gitlab.com/solutions/open-source/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/opensource-program/).
|
||||||
GitLab Ultimate, plus 50,000 CI/CD minutes per month. For more information, see [program requirements](https://about.gitlab.com/solutions/open-source/join/#requirements), [renewals](https://about.gitlab.com/solutions/open-source/join/#renewals), and [program benefits](https://about.gitlab.com/solutions/open-source/join/).
|
|
||||||
|
|
||||||
If you have any questions, send an email to `opensource@gitlab.com` for assistance.
|
#### Meeting GitLab for Open Source Program requirements
|
||||||
|
|
||||||
#### License requirements for GitLab for Open Source Program members
|
NOTE:
|
||||||
|
GitLab for Open Source Program benefits apply to an entire GitLab namespace. To qualify for the GitLab for Open Source Program, all projects in an applicant's namespace must meet program requirements. Applicants submit materials related to one project in the applying namespace, and the open source program team uses that project to verify eligibility of the entire namespace.
|
||||||
|
|
||||||
GitLab for Open Source Program benefits apply to an entire GitLab namespace. To qualify for the GitLab for Open Source Program, **all projects in an applicant's namespace** must carry an [OSI-approved license](https://opensource.org/licenses/).
|
To meet GitLab for Open Source Program requirements, first add an OSI-approved open source license to all projects in your namespace.
|
||||||
|
|
||||||
To add a license:
|
To add a license to a project:
|
||||||
|
|
||||||
1. On the top bar, select **Main menu > Projects** and find your project.
|
1. On the top bar, select **Main menu > Projects** and find your project.
|
||||||
1. On the overview page, select **Add LICENSE**. If the license you want is not available as a license template, manually copy the entire, unaltered [text of your chosen license](https://opensource.org/licenses/alphabetical) into the `LICENSE` file. Note that GitLab defaults to **All rights reserved** if users do not perform this action.
|
1. On the overview page, select **Add LICENSE**. If the license you want is not available as a license template, manually copy the entire, unaltered [text of your chosen license](https://opensource.org/licenses/alphabetical) into the `LICENSE` file. Note that GitLab defaults to **All rights reserved** if users do not perform this action.
|
||||||
|
|
||||||
Applicants must add the correct license to each project in their respective groups or namespaces When you're sure you're using OSI-approved licenses for your projects, you can take your screenshots.
|
Applicants must add the correct license to each project in their respective groups or namespaces. When you're sure you're using OSI-approved licenses for your projects, you can take your screenshots.
|
||||||
|
|
||||||
#### Verification for Open Source Program
|
#### Verification for Open Source Program
|
||||||
|
|
||||||
As part of the [application verification process](https://about.gitlab.com/solutions/open-source/join/), you must upload **three screenshots**:
|
Next, take screenshots of your project to confirm that project's eligibility. You must upload three screenshots:
|
||||||
|
|
||||||
- [OSI-approved license overview](#screenshot-1-license-overview)
|
- [OSI-approved license overview](#screenshot-1-license-overview)
|
||||||
- [OSI-approved license contents](#screenshot-2-license-contents)
|
- [OSI-approved license contents](#screenshot-2-license-contents)
|
||||||
- [Publicly visible settings](#screenshot-3-publicly-visible-settings)
|
- [Publicly visible settings](#screenshot-3-publicly-visible-settings)
|
||||||
|
|
||||||
Benefits of the GitLab Open Source Program apply to all projects in a GitLab namespace. All projects in an eligible namespace must meet program requirements. However, if you submit materials for **one project** in your namespace, the open source program team uses that project to verify the contents of the entire namespace you use when applying to the program.
|
NOTE:
|
||||||
|
Benefits of the GitLab Open Source Program apply to all projects in a GitLab namespace. All projects in an eligible namespace must meet program requirements.
|
||||||
|
|
||||||
##### Screenshot 1: License overview
|
##### Screenshot 1: License overview
|
||||||
|
|
||||||
|
@ -243,24 +237,11 @@ To be eligible for the GitLab Open Source Program, projects must be publicly vis
|
||||||
![Publicly visible setting](img/publicly-visible.png)
|
![Publicly visible setting](img/publicly-visible.png)
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
Exceptions to this public visibility requirement apply in select circumstances (for example, in cases where a project may hold sensitive data). Email `opensource@gitlab.com` with details of your use case to request written permission for exceptions.
|
Exceptions to this public visibility requirement apply in select circumstances (for example, in cases where a project in an applicant's namespace may hold sensitive data). Email `opensource@gitlab.com` with details of your use case to request written permission for exceptions.
|
||||||
|
|
||||||
### GitLab for Startups
|
### GitLab for Startups
|
||||||
|
|
||||||
For qualifying startups, the [GitLab for Startups](https://about.gitlab.com/solutions/startups/) program provides
|
For qualifying startups, the [GitLab for Startups](https://about.gitlab.com/solutions/startups/) program provides GitLab Ultimate, plus 50,000 CI/CD minutes per month for 12 months. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Startups Program page](https://about.gitlab.com/solutions/startups/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/startups-program/).
|
||||||
the top GitLab tier, plus 50,000 CI/CD minutes per month for 12 months.
|
|
||||||
|
|
||||||
For more information, including program requirements, see the [Startup program's landing page](https://about.gitlab.com/solutions/startups/).
|
|
||||||
|
|
||||||
Send all questions and requests related to the GitLab for Startups program to `startups@gitlab.com`.
|
|
||||||
|
|
||||||
### Support for Community Programs
|
|
||||||
|
|
||||||
Because these Community Programs are free of cost, regular Priority Support is not included.
|
|
||||||
|
|
||||||
As a community member, you can follow this diagram to find support:
|
|
||||||
|
|
||||||
![Support diagram](img/support_diagram_c.png)
|
|
||||||
|
|
||||||
## Contact Support
|
## Contact Support
|
||||||
|
|
||||||
|
@ -269,12 +250,9 @@ Learn more about:
|
||||||
- The tiers of [GitLab Support](https://about.gitlab.com/support/).
|
- The tiers of [GitLab Support](https://about.gitlab.com/support/).
|
||||||
- [Submit a request via the Support Portal](https://support.gitlab.com/hc/en-us/requests/new).
|
- [Submit a request via the Support Portal](https://support.gitlab.com/hc/en-us/requests/new).
|
||||||
|
|
||||||
We also encourage all users to search our project trackers for known issues and
|
We also encourage all users to search our project trackers for known issues and existing feature requests in the [GitLab project](https://gitlab.com/gitlab-org/gitlab/-/issues/).
|
||||||
existing feature requests in the
|
|
||||||
[GitLab project](https://gitlab.com/gitlab-org/gitlab/-/issues/).
|
|
||||||
|
|
||||||
These issues are the best avenue for getting updates on specific product plans
|
These issues are the best avenue for getting updates on specific product plans and for communicating directly with the relevant GitLab team members.
|
||||||
and for communicating directly with the relevant GitLab team members.
|
|
||||||
|
|
||||||
<!-- ## Troubleshooting
|
<!-- ## Troubleshooting
|
||||||
|
|
||||||
|
|
|
@ -736,7 +736,7 @@ After DAST has authenticated with the application, all cookies are collected fro
|
||||||
For each cookie a matching session token is created for use by ZAP. This ensures ZAP is recognized
|
For each cookie a matching session token is created for use by ZAP. This ensures ZAP is recognized
|
||||||
by the application as correctly authenticated.
|
by the application as correctly authenticated.
|
||||||
|
|
||||||
Authentication supports single form logins, multi-step login forms, and authenticating to URLs outside of the configured target URL.
|
Authentication supports single form logins, multi-step login forms, and authenticating to URLs outside of the configured target URL.
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
**Never** run an authenticated scan against a production server. When an authenticated
|
**Never** run an authenticated scan against a production server. When an authenticated
|
||||||
|
@ -744,6 +744,17 @@ scan is run, it may perform *any* function that the authenticated user can. This
|
||||||
includes actions like modifying and deleting data, submitting forms, and following links.
|
includes actions like modifying and deleting data, submitting forms, and following links.
|
||||||
Only run an authenticated scan against a test server.
|
Only run an authenticated scan against a test server.
|
||||||
|
|
||||||
|
### SSO
|
||||||
|
|
||||||
|
DAST can authenticate to websites making use of SSO, with the following restrictions:
|
||||||
|
|
||||||
|
- DAST cannot bypass a CAPTCHA if the authentication flow includes one.
|
||||||
|
- DAST cannot handle multi-factor authentication like one-time passwords (OTP) by using SMS or authenticator apps.
|
||||||
|
- DAST must get a cookie, or a local or session storage, with a sufficiently random value.
|
||||||
|
|
||||||
|
The [authentication debug output](index.md#configure-the-authentication-debug-output) can be helpful for troubleshooting SSO authentication
|
||||||
|
with DAST.
|
||||||
|
|
||||||
### Log in using automatic detection of the login form
|
### Log in using automatic detection of the login form
|
||||||
|
|
||||||
By providing a `DAST_USERNAME`, `DAST_PASSWORD`, and `DAST_AUTH_URL`, DAST attempts to authenticate to the
|
By providing a `DAST_USERNAME`, `DAST_PASSWORD`, and `DAST_AUTH_URL`, DAST attempts to authenticate to the
|
||||||
|
|
|
@ -6,26 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Free user limit **(FREE SAAS)**
|
# Free user limit **(FREE SAAS)**
|
||||||
|
|
||||||
From October 19, 2022, namespaces in GitLab.com on the Free tier
|
From October 19, 2022, a five-user limit will apply to top-level [namespaces](namespace/index.md) with private visibility on GitLab SaaS. These limits will roll out gradually, and impacted users will be notified in GitLab.com at least 60 days before the limit is applied.
|
||||||
will be limited to five (5) members per [namespace](namespace/index.md).
|
|
||||||
This limit applies to top-level private groups.
|
|
||||||
|
|
||||||
On the transition date, if your namespace has six or more unique members:
|
When the five-user limit is applied, top-level private namespaces exceeding the user limit are placed in a read-only state. These namespaces cannot write new data to repositories, Git Large File Storage (LFS), packages, or registries.
|
||||||
|
|
||||||
- Five members will keep a status of `Active`.
|
|
||||||
- Remaining members will get a status of `Over limit` and lose access to the
|
|
||||||
group.
|
|
||||||
- Members invited through a group or project invitation outside of the namespace
|
|
||||||
will be removed. You can add these members back by inviting them through their
|
|
||||||
username or email address on the **Members** page for your group or project.
|
|
||||||
|
|
||||||
## How active members are determined
|
|
||||||
|
|
||||||
On the transition date, we'll automatically select the members who keep their `Active` status
|
|
||||||
in the following order, until we reach a total of five:
|
|
||||||
|
|
||||||
1. Members with the Owner or Maintainer role.
|
|
||||||
1. The most recently active members.
|
|
||||||
|
|
||||||
## Manage members in your namespace
|
## Manage members in your namespace
|
||||||
|
|
||||||
|
@ -43,7 +26,7 @@ Prerequisite:
|
||||||
1. To remove a member, select **Remove user**.
|
1. To remove a member, select **Remove user**.
|
||||||
|
|
||||||
If you need more time to manage your members, or to try GitLab features
|
If you need more time to manage your members, or to try GitLab features
|
||||||
with a team of more than five members, you can [start a trial](https://about.gitlab.com/free-trial/).
|
with a team of more than five members, you can [start a trial](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com&glm_content=free-user-limit).
|
||||||
A trial lasts for 30 days and includes an unlimited number of members.
|
A trial lasts for 30 days and includes an unlimited number of members.
|
||||||
|
|
||||||
## Related topics
|
## Related topics
|
||||||
|
|
|
@ -13518,19 +13518,10 @@ msgstr ""
|
||||||
msgid "DesignManagement|Are you sure you want to archive the selected designs?"
|
msgid "DesignManagement|Are you sure you want to archive the selected designs?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Are you sure you want to cancel changes to this comment?"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
|
msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Cancel changes"
|
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "DesignManagement|Cancel comment confirmation"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "DesignManagement|Cancel comment update confirmation"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
|
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
|
||||||
|
@ -13539,6 +13530,12 @@ msgstr ""
|
||||||
msgid "DesignManagement|Comment"
|
msgid "DesignManagement|Comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DesignManagement|Continue creating"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DesignManagement|Continue editing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Could not add a new comment. Please try again."
|
msgid "DesignManagement|Could not add a new comment. Please try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -13557,7 +13554,7 @@ msgstr ""
|
||||||
msgid "DesignManagement|Designs"
|
msgid "DesignManagement|Designs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Discard comment"
|
msgid "DesignManagement|Discard changes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Discussion"
|
msgid "DesignManagement|Discussion"
|
||||||
|
@ -13578,12 +13575,6 @@ msgstr ""
|
||||||
msgid "DesignManagement|Go to previous design"
|
msgid "DesignManagement|Go to previous design"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Keep changes"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "DesignManagement|Keep comment"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "DesignManagement|Requested design version does not exist. Showing latest version instead"
|
msgid "DesignManagement|Requested design version does not exist. Showing latest version instead"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -62,13 +62,9 @@ module QA
|
||||||
|
|
||||||
Support::Waiter.wait_until { has_element?(:group_select_dropdown_item) }
|
Support::Waiter.wait_until { has_element?(:group_select_dropdown_item) }
|
||||||
|
|
||||||
# Workaround for race condition with concurrent group API calls while searching
|
fill_element :group_select_dropdown_search_field, group_name
|
||||||
# Remove Retrier after https://gitlab.com/gitlab-org/gitlab/-/issues/349379 is resolved
|
Support::WaitForRequests.wait_for_requests
|
||||||
Support::Retrier.retry_on_exception do
|
click_button group_name
|
||||||
fill_element :group_select_dropdown_search_field, group_name
|
|
||||||
Support::WaitForRequests.wait_for_requests
|
|
||||||
click_button group_name
|
|
||||||
end
|
|
||||||
|
|
||||||
set_access_level(access_level)
|
set_access_level(access_level)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1235,26 +1235,6 @@ RSpec.describe ProjectsController do
|
||||||
get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
|
get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when use_gitaly_pagination_for_refs is disabled' do
|
|
||||||
before do
|
|
||||||
stub_feature_flags(use_gitaly_pagination_for_refs: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not use gitaly pagination' do
|
|
||||||
expected_params = ActionController::Parameters.new(ref: '123456', per_page: 100).permit!
|
|
||||||
|
|
||||||
expect_next_instance_of(BranchesFinder, project.repository, expected_params) do |finder|
|
|
||||||
expect(finder).to receive(:execute).with(gitaly_pagination: false).and_call_original
|
|
||||||
end
|
|
||||||
|
|
||||||
expect_next_instance_of(TagsFinder, project.repository, expected_params) do |finder|
|
|
||||||
expect(finder).to receive(:execute).with(gitaly_pagination: false).and_call_original
|
|
||||||
end
|
|
||||||
|
|
||||||
get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when gitaly is unavailable' do
|
context 'when gitaly is unavailable' do
|
||||||
before do
|
before do
|
||||||
expect_next_instance_of(TagsFinder) do |finder|
|
expect_next_instance_of(TagsFinder) do |finder|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import { nextTick } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
import Autosave from '~/autosave';
|
import Autosave from '~/autosave';
|
||||||
|
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
|
||||||
import DesignReplyForm from '~/design_management/components/design_notes/design_reply_form.vue';
|
import DesignReplyForm from '~/design_management/components/design_notes/design_reply_form.vue';
|
||||||
|
|
||||||
const showModal = jest.fn();
|
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
|
||||||
|
|
||||||
const GlModal = {
|
|
||||||
template: '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-ok"></slot></div>',
|
|
||||||
methods: {
|
|
||||||
show: showModal,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Design reply form component', () => {
|
describe('Design reply form component', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
@ -19,7 +13,6 @@ describe('Design reply form component', () => {
|
||||||
const findTextarea = () => wrapper.find('textarea');
|
const findTextarea = () => wrapper.find('textarea');
|
||||||
const findSubmitButton = () => wrapper.findComponent({ ref: 'submitButton' });
|
const findSubmitButton = () => wrapper.findComponent({ ref: 'submitButton' });
|
||||||
const findCancelButton = () => wrapper.findComponent({ ref: 'cancelButton' });
|
const findCancelButton = () => wrapper.findComponent({ ref: 'cancelButton' });
|
||||||
const findModal = () => wrapper.findComponent({ ref: 'cancelCommentModal' });
|
|
||||||
|
|
||||||
function createComponent(props = {}, mountOptions = {}) {
|
function createComponent(props = {}, mountOptions = {}) {
|
||||||
wrapper = mount(DesignReplyForm, {
|
wrapper = mount(DesignReplyForm, {
|
||||||
|
@ -29,7 +22,6 @@ describe('Design reply form component', () => {
|
||||||
noteableId: 'gid://gitlab/DesignManagement::Design/6',
|
noteableId: 'gid://gitlab/DesignManagement::Design/6',
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
stubs: { GlModal },
|
|
||||||
...mountOptions,
|
...mountOptions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,6 +34,7 @@ describe('Design reply form component', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
window.gon = originalGon;
|
window.gon = originalGon;
|
||||||
|
confirmAction.mockReset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('textarea has focus after component mount', () => {
|
it('textarea has focus after component mount', () => {
|
||||||
|
@ -199,7 +192,7 @@ describe('Design reply form component', () => {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
findTextarea().trigger('keyup.esc');
|
findTextarea().trigger('keyup.esc');
|
||||||
expect(showModal).toHaveBeenCalled();
|
expect(confirmAction).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits cancelForm event on Cancel button click if text was not changed', () => {
|
it('emits cancelForm event on Cancel button click if text was not changed', () => {
|
||||||
|
@ -213,17 +206,41 @@ describe('Design reply form component', () => {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
findCancelButton().trigger('click');
|
findCancelButton().trigger('click');
|
||||||
expect(showModal).toHaveBeenCalled();
|
expect(confirmAction).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits cancelForm event on modal Ok button click', () => {
|
it('emits cancelForm event when confirmed', async () => {
|
||||||
|
confirmAction.mockResolvedValueOnce(true);
|
||||||
const autosaveResetSpy = jest.spyOn(wrapper.vm.autosaveDiscussion, 'reset');
|
const autosaveResetSpy = jest.spyOn(wrapper.vm.autosaveDiscussion, 'reset');
|
||||||
|
|
||||||
findTextarea().trigger('keyup.esc');
|
wrapper.setProps({ value: 'test3' });
|
||||||
findModal().vm.$emit('ok');
|
await nextTick();
|
||||||
|
|
||||||
expect(wrapper.emitted('cancel-form')).toHaveLength(2);
|
findTextarea().trigger('keyup.esc');
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(confirmAction).toHaveBeenCalled();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(wrapper.emitted('cancel-form')).toHaveLength(1);
|
||||||
expect(autosaveResetSpy).toHaveBeenCalled();
|
expect(autosaveResetSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("doesn't emit cancelForm event when not confirmed", async () => {
|
||||||
|
confirmAction.mockResolvedValueOnce(false);
|
||||||
|
const autosaveResetSpy = jest.spyOn(wrapper.vm.autosaveDiscussion, 'reset');
|
||||||
|
|
||||||
|
wrapper.setProps({ value: 'test3' });
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
findTextarea().trigger('keyup.esc');
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(confirmAction).toHaveBeenCalled();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
expect(wrapper.emitted('cancel-form')).toBeUndefined();
|
||||||
|
expect(autosaveResetSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,6 +53,8 @@ RSpec.describe ChangePublicProjectsCostFactor, migration: :gitlab_ci do
|
||||||
expect(shared_2.public_projects_minutes_cost_factor).to eq(0)
|
expect(shared_2.public_projects_minutes_cost_factor).to eq(0)
|
||||||
expect(shared_3.public_projects_minutes_cost_factor).to eq(1)
|
expect(shared_3.public_projects_minutes_cost_factor).to eq(1)
|
||||||
expect(group_1.public_projects_minutes_cost_factor).to eq(0)
|
expect(group_1.public_projects_minutes_cost_factor).to eq(0)
|
||||||
|
|
||||||
|
schema_migrate_up!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -157,12 +157,20 @@ RSpec.describe BulkImports::ExportStatus do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when something goes wrong during export status fetch' do
|
context 'when something goes wrong during export status fetch' do
|
||||||
it 'returns exception class as error' do
|
it 'returns exception class as error and memoizes return value' do
|
||||||
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
|
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
|
||||||
allow(client).to receive(:get).and_raise(StandardError, 'Error!')
|
allow(client).to receive(:get).and_raise(StandardError, 'Error!')
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(subject.error).to eq('Error!')
|
expect(subject.error).to eq('Error!')
|
||||||
|
expect(subject.failed?).to eq(true)
|
||||||
|
|
||||||
|
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
|
||||||
|
allow(client).to receive(:get).and_return({ 'relation' => relation, 'status' => 'finished' })
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.error).to eq('Error!')
|
||||||
|
expect(subject.failed?).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue