提交 66d42037 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 a496f41f
......@@ -44,13 +44,15 @@ docs lint:
- .default-tags
- .default-retry
- .docs:rules:docs-lint
image: "registry.gitlab.com/gitlab-org/gitlab-docs:docs-lint"
image: "registry.gitlab.com/gitlab-org/gitlab-docs:lint"
stage: test
needs: []
script:
- scripts/lint-doc.sh
# Lint Markdown
- markdownlint --config .markdownlint.json 'doc/**/*.md'
# Lint content (error-level text-scoped rules only)
- vale --minAlertLevel error --ignore-syntax doc
# Prepare docs for build
- mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX
- cd /tmp/gitlab-docs
......
......@@ -207,11 +207,11 @@ karma-as-if-foss:
extends: .frontend-job-base
script:
- date
- yarn jest --ci --coverage
- yarn jest --ci --coverage --testSequencer ./scripts/frontend/parallel_ci_sequencer.js
cache:
key: jest
paths:
- tmp/jest/jest/
- tmp/cache/jest/
policy: pull-push
jest:
......@@ -229,6 +229,7 @@ jest:
- tmp/tests/frontend/
reports:
junit: junit_jest.xml
parallel: 2
jest-as-if-foss:
extends:
......@@ -239,6 +240,26 @@ jest-as-if-foss:
cache:
policy: pull
coverage-frontend:
extends:
- .default-tags
- .default-retry
- .frontend:rules:default-frontend-jobs
needs: ["jest"]
stage: post-test
before_script:
- yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
script:
- yarn node scripts/frontend/merge_coverage_frontend.js
artifacts:
name: coverage-frontend
expire_in: 31d
paths:
- coverage-frontend/
cache:
paths:
- .yarn-cache/
.qa-frontend-node:
extends:
- .default-tags
......
......@@ -123,5 +123,6 @@
"YouTrack"
],
"code_blocks": false
}
},
"code-fence-style": false
}
<script>
import _ from 'underscore';
import { GlIcon } from '@gitlab/ui';
import { GlIcon, GlButton } from '@gitlab/ui';
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
......@@ -26,6 +26,7 @@ export default {
CommitEdit,
CommitMessageDropdown,
GlIcon,
GlButton,
MergeImmediatelyConfirmationDialog: () =>
import(
'ee_component/vue_merge_request_widget/components/merge_immediately_confirmation_dialog.vue'
......@@ -67,18 +68,13 @@ export default {
return 'success';
},
mergeButtonClass() {
const defaultClass = 'btn btn-sm btn-success accept-merge-request';
const failedClass = `${defaultClass} btn-danger`;
const inActionClass = `${defaultClass} btn-info`;
mergeButtonVariant() {
if (this.status === 'failed') {
return failedClass;
return 'danger';
} else if (this.status === 'pending') {
return inActionClass;
return 'info';
}
return defaultClass;
return 'success';
},
iconClass() {
if (
......@@ -267,16 +263,16 @@ export default {
<div class="media-body">
<div class="mr-widget-body-controls media space-children">
<span class="btn-group">
<button
<gl-button
size="sm"
class="qa-merge-button accept-merge-request"
:variant="mergeButtonVariant"
:disabled="isMergeButtonDisabled"
:class="mergeButtonClass"
type="button"
class="qa-merge-button"
:loading="isMakingRequest"
@click="handleMergeButtonClick(isAutoMergeAvailable)"
>
<i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
{{ mergeButtonText }}
</button>
</gl-button>
<button
v-if="shouldShowMergeImmediatelyDropdown"
:disabled="isMergeButtonDisabled"
......
<script>
import $ from 'jquery';
import { __ } from '~/locale';
import { GlButton } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import createFlash from '~/flash';
import statusIcon from '../mr_widget_status_icon.vue';
import StatusIcon from '../mr_widget_status_icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
import eventHub from '../../event_hub';
export default {
name: 'WorkInProgress',
components: {
statusIcon,
StatusIcon,
GlButton,
},
directives: {
tooltip,
......@@ -23,8 +25,15 @@ export default {
isMakingRequest: false,
};
},
computed: {
wipInfoTooltip() {
return s__(
'mrWidget|When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged',
);
},
},
methods: {
removeWIP() {
handleRemoveWIP() {
this.isMakingRequest = true;
this.service
.removeWIP()
......@@ -52,29 +61,22 @@ export default {
<i
v-tooltip
class="fa fa-question-circle"
:title="
s__(
'mrWidget|When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged',
)
"
:aria-label="
s__(
'mrWidget|When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged',
)
"
:title="wipInfoTooltip"
:aria-label="wipInfoTooltip"
>
</i>
</span>
<button
<gl-button
v-if="mr.removeWIPPath"
size="sm"
variant="default"
:disabled="isMakingRequest"
type="button"
class="btn btn-default btn-sm js-remove-wip"
@click="removeWIP"
:loading="isMakingRequest"
class="js-remove-wip"
@click="handleRemoveWIP"
>
<i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
{{ s__('mrWidget|Resolve WIP status') }}
</button>
</gl-button>
</div>
</div>
</template>
......@@ -28,6 +28,10 @@ module Resolvers
end
end
def self.complexity
0
end
def self.resolver_complexity(args, child_complexity:)
complexity = 1
complexity += 1 if args[:sort]
......
......@@ -9,7 +9,7 @@ module Types
def initialize(*args, **kwargs, &block)
@calls_gitaly = !!kwargs.delete(:calls_gitaly)
@constant_complexity = !!kwargs[:complexity]
kwargs[:complexity] ||= field_complexity(kwargs[:resolver_class])
kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity])
@feature_flag = kwargs[:feature_flag]
kwargs = check_feature_flag(kwargs)
......@@ -51,7 +51,9 @@ module Types
args
end
def field_complexity(resolver_class)
def field_complexity(resolver_class, current)
return current if current.present? && current > 0
if resolver_class
field_resolver_complexity
else
......@@ -66,22 +68,30 @@ module Types
# proc because we set complexity depending on arguments and number of
# items which can be loaded.
proc do |ctx, args, child_complexity|
next base_complexity unless resolver_complexity_enabled?(ctx)
# Resolvers may add extra complexity depending on used arguments
complexity = child_complexity + self.resolver&.try(:resolver_complexity, args, child_complexity: child_complexity).to_i
complexity += 1 if calls_gitaly?
field_defn = to_graphql
if field_defn.connection?
# Resolvers may add extra complexity depending on number of items being loaded.
page_size = field_defn.connection_max_page_size || ctx.schema.default_max_page_size
limit_value = [args[:first], args[:last], page_size].compact.min
multiplier = self.resolver&.try(:complexity_multiplier, args).to_f
complexity += complexity * limit_value * multiplier
end
complexity += complexity * connection_complexity_multiplier(ctx, args)
complexity.to_i
end
end
def resolver_complexity_enabled?(ctx)
ctx.fetch(:graphql_resolver_complexity_flag) { |key| ctx[key] = Feature.enabled?(:graphql_resolver_complexity) }
end
def connection_complexity_multiplier(ctx, args)
# Resolvers may add extra complexity depending on number of items being loaded.
field_defn = to_graphql
return 0 unless field_defn.connection?
page_size = field_defn.connection_max_page_size || ctx.schema.default_max_page_size
limit_value = [args[:first], args[:last], page_size].compact.min
multiplier = self.resolver&.try(:complexity_multiplier, args).to_f
limit_value * multiplier
end
end
end
......@@ -16,7 +16,7 @@ module Spammable
attr_accessor :spam_log
alias_method :spam?, :spam
after_validation :check_for_spam, on: [:create, :update]
after_validation :invalidate_if_spam, on: [:create, :update]
cattr_accessor :spammable_attrs, instance_accessor: false do
[]
......@@ -37,7 +37,7 @@ module Spammable
end
end
def check_for_spam
def invalidate_if_spam
error_msg = if Gitlab::Recaptcha.enabled?
"Your #{spammable_entity_type} has been recognized as spam. "\
"Please, change the content or solve the reCAPTCHA to proceed."
......
---
title: Update iOS (Swift) project template logo
merge_request: 25049
author:
type: changed
require 'gitlab/testing/request_blocker_middleware'
require 'gitlab/testing/request_inspector_middleware'
require 'gitlab/testing/clear_thread_memory_cache_middleware'
Rails.application.configure do
# Make sure the middleware is inserted first in middleware chain
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::RequestBlockerMiddleware)
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::RequestInspectorMiddleware)
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::ClearThreadMemoryCacheMiddleware)
# Settings specified here will take precedence over those in config/application.rb
......
......@@ -75,7 +75,7 @@ must disable the **primary** node.
single recommendation. You may need to:
- Reconfigure the load balancers.
- Change DNS records (e.g., point the primary DNS record to the **secondary**
- Change DNS records (for example, point the primary DNS record to the **secondary**
node in order to stop usage of the **primary** node).
- Stop the virtual servers.
- Block traffic through a firewall.
......
......@@ -337,8 +337,8 @@ How this feature will work:
### Be careful with sensitive information
With some [Runner Executors](https://docs.gitlab.com/runner/executors/README.html),
if you can run a job on the Runner, you can get access to any code it runs
and get the token of the Runner. With shared Runners, this means that anyone
if you can run a job on the Runner, you can get full access to the file system,
and thus any code it runs as well as the token of the Runner. With shared Runners, this means that anyone
that runs jobs on the Runner, can access anyone else's code that runs on the
Runner.
......
......@@ -825,10 +825,8 @@ This could result in some unexpected behavior, including:
Available rule clauses include:
- [`if`](#rulesif)
(similar to [`only:variables`](#onlyvariablesexceptvariables)).
- [`changes`](#ruleschanges)
(same as [`only:changes`](#onlychangesexceptchanges)).
- [`if`](#rulesif) (similar to [`only:variables`](#onlyvariablesexceptvariables))
- [`changes`](#ruleschanges) (same as [`only:changes`](#onlychangesexceptchanges))
- [`exists`](#rulesexists)
For example, using `if`. This configuration specifies that `job` should be built
......@@ -895,7 +893,6 @@ docker build:
- if: '$VAR == "string value"'
when: manual # Will include the job and set to when:manual if the expression evaluates to true, after the `changes:` rule fails to match.
- when: on_success # If neither of the first rules match, set to on_success
```
In this example, a job either set to:
......@@ -956,6 +953,47 @@ job:
In this example, if the first rule matches, then the job will have `when: manual` and `allow_failure: true`.
#### Exclude jobs with `rules:` from certain pipelines
Jobs with `rules:` can cause two pipelines to be created unexpectedly:
- One pipeline from pushing a commit to a branch.
- A second ["detached" pipeline for a merge request](../merge_request_pipelines/index.md).
`only` and `except` jobs do not trigger merge request pipelines by default, but this
is not the case for jobs with `rules:`, which may be surprising if migrating from `only`
and `except` to `rules:`.
If you are using `rules:` and you see two pipelines for commits to branches that have
a merge request, you have two options:
- Individually exclude each job that uses `rules:` from merge request pipelines. The
example below will cause the job to **not** run in *pipelines for merge requests*,
but it **will** run in pipelines for *new tags and pipelines running on branch refs*:
```yaml
job:
rules:
- if: $CI_MERGE_REQUEST_ID
when: never
- when: manual
script:
- echo hello
```
- Add a global [`workflow: rules`](#workflowrules) to allow pipelines in only certain
situations. The example below will only run pipelines for merge requests, new tags and
changes to master. It will **not** run any pipelines *on any branch except master*, but
it will run **detached merge request pipelines** for any merge request, targeting any branch:
```yaml
workflow:
rules:
- if: $CI_MERGE_REQUEST_ID
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == "master"
```
#### Complex rule clauses
To conjoin `if`, `changes`, and `exists` clauses with an AND, use them in the
......
......@@ -146,6 +146,7 @@ graph RL;
U2["frontend-fixtures-as-if-foss<br/>(EE default refs only)"];
V["webpack-dev-server, static-analysis"];
M[coverage];
O[coverage-frontend];
N["pages (master only)"];
Q[package-and-qa];
S["RSpec<br/>(e.g. rspec unit pg9)"]
......@@ -190,6 +191,7 @@ subgraph "`test` stage"
subgraph "`post-test` stage"
M --> |happens after| S
O --> |needs `jest`| I
end
subgraph "`review-prepare` stage"
......
......@@ -2,70 +2,77 @@
type: index, reference
---
# Customer Docs
# GitLab subscription
This section contains information for:
Access to GitLab features is provided on a subscription basis. A subscription entitles users to the features of a specific GitLab tier. Each tier provides a set of features. A subscription is valid for 12 months.
- New customers about choosing [which GitLab](#which-gitlab) is right for you.
- Existing customers about [managing subscriptions](#managing-subscriptions).
## Choosing a GitLab subscription
Also see our [subscription FAQ](https://about.gitlab.com/pricing/licensing-faq/).
When choosing a subscription, consider the following factors:
## Which GitLab?
- [GitLab tier](#choosing-a-gitlab-tier)
- [GitLab.com or self-managed](#choosing-between-gitlabcom-or-self-managed)
- [Group or personal subscription (GitLab.com only)](#choosing-a-gitlabcom-group-or-personal-subscription)
- [Number of users](#choosing-the-number-of-users)
There are two ways to use GitLab:
### Choosing a GitLab tier
- [GitLab.com](#gitlabcom): GitLab's SaaS offering. You don't need to install
anything to use GitLab.com, you only need to
[sign up](https://gitlab.com/users/sign_in) and start using GitLab straight away.
- [GitLab self-managed](#gitlab-self-managed): Install, administer, and maintain
your own GitLab instance.
Pricing is [tier-based](https://about.gitlab.com/pricing/), allowing you to choose the features which fit your budget. See the [feature comparison](https://about.gitlab.com/pricing/gitlab-com/feature-comparison/) for information on what features are available at each tier.
The following sections outline tiers and features within GitLab.com
and GitLab self-managed.
### Choosing between GitLab.com or self-managed
### GitLab.com
There are some differences in how a subscription applies, depending if you use GitLab.com or a self-managed instance.
GitLab.com is hosted, managed, and administered by GitLab, Inc., with
[free and paid subscriptions](https://about.gitlab.com/pricing/) for individuals
and teams in the following tiers:
- [GitLab.com](#gitlabcom): GitLab's software-as-a-service offering. You don't need to install anything to use GitLab.com, you only need to [sign up](https://gitlab.com/users/sign_in) and start using GitLab straight away.
- [GitLab self-managed](#self-managed): Install, administer, and maintain your own GitLab instance.
| Tier | Includes same features available in |
|:-------|:----------------------------------------------------|
| Free | [Core](#gitlab-self-managed) self-managed tier. |
| Bronze | [Starter](#gitlab-self-managed) self-managed tier. |
| Silver | [Premium](#gitlab-self-managed) self-managed tier. |
| Gold | [Ultimate](#gitlab-self-managed) self-managed tier. |
On a self-managed instance, a GitLab subscription provides the same set of features for all users. On GitLab.com you can apply a subscription to either a group or a personal namespace.
GitLab.com subscriptions grant access
to the same features available in GitLab self-managed, **except
[administration](../administration/index.md) tools and settings**.
### Choosing a GitLab.com group or personal subscription
GitLab.com allows you to apply your subscription to a group or your personal user.
On GitLab.com you can apply a subscription to either a group or a personal namespace.
When applied to:
- A **group**, the group, all subgroups, and all projects under the selected
group on GitLab.com will have the features of the associated plan. It is
recommended to go with a group plan when managing projects and users of an
organization.
group on GitLab.com will have the features of the associated tier. GitLab recommends
choosing a group plan when managing an organization's projects and users.
- A **personal userspace** instead, all projects will have features with the
subscription applied, but as it is not a group, group features will not be available.
subscription applied, but as it's not a group, group features won't be available.
### Choosing the number of users
There are some differences between who is counted in a subscription, depending if you use GitLab.com or a self-managed instance.
#### GitLab.com
A GitLab.com subscription uses a concurrent (_seat_) model. You pay for a subscription according to the maximum number of users enabled at once. You can add and remove users during the subscription period, as long as the total users at any given time is within your subscription count.
Every occupied seat, whether by person, job, or bot is counted in the subscription, with the following exception:
- Members with Guest permissions on a Gold subscription.
TIP: **Tip:**
To support the open source community and encourage the development of open
source projects, GitLab grants access to **Gold** features for all GitLab.com
**public** projects, regardless of the subscription.
The following resources are available for more information on GitLab.com:
#### Self-managed
A self-managed subscription uses a hybrid model. You pay for a subscription according to the maximum number of users enabled during the subscription period. At the end of the subscription period, the maximum number of simultaneous users in the self-managed installation is checked. If the number of users is higher than your subscription, you are billed for the extra users. The maximum number of simultaneous users is also used to calculate the cost of subscription renewal.
Every occupied seat, whether by person, job, or bot is counted in the subscription, with the following exceptions:
- Blocked users who are blocked prior to the renewal of a subscription won't be counted as active users for the renewal subscription. They may count as active users in the subscription period in which they were originally added.
- Members with Guest permissions on an Ultimate subscription.
- Special internal GitLab accounts: `Ghost User` and `Support Bot`.
- [Feature comparison](https://about.gitlab.com/pricing/gitlab-com/feature-comparison/), for information on what features are available at each tier.
- [GitLab pricing page](https://about.gitlab.com/pricing/), for subscription information and a free trial.
- Our [product marketing page](https://about.gitlab.com/handbook/marketing/product-marketing/), for additional information including:
- How [different tiers are licensed](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers).
- The different [GitLab distributions](https://about.gitlab.com/handbook/marketing/product-marketing/#distributions).
NOTE: **Note:**
If you have LDAP integration enabled, anyone in the configured domain can sign up for a GitLab account. This can result in an unexpected bill at time of renewal. Consider [disabling new signups](../user/admin_area/settings/sign_up_restrictions.md) and managing new users manually instead.
## Obtain a GitLab subscription
#### Subscribing to GitLab.com
### Subscribe to GitLab.com
To subscribe to GitLab.com:
......@@ -78,10 +85,10 @@ To subscribe to GitLab.com:
1. Create additional users and
[add them to the group](../user/group/index.md#add-users-to-a-group).
1. Select the **Bronze**, **Silver**, or **Gold** GitLab.com plan through the
[GitLab Subscription Manager](https://customers.gitlab.com/).
1. Link your GitLab.com account with your GitLab Subscription Manager account.
Once signed into the GitLab Subscription Manager, if your account is not
already linked, you will prompted to link your account with a
[Customers Portal](https://customers.gitlab.com/).
1. Link your GitLab.com account with your Customers Portal account.
Once signed into the Customers Portal, if your account is not
already linked, you will be prompted to link your account with a
**Link my GitLab Account** button.
1. Associate the group with the subscription.
......@@ -89,112 +96,60 @@ TIP: **Tip:**
You can also go to the [**My Account**](https://customers.gitlab.com/customers/edit)
page to add or change the GitLab.com account link.
### GitLab self-managed
With GitLab self-managed, you deploy your own GitLab instance on-premises or on a cloud of your choice.
GitLab self-managed is available for [free and with paid subscriptions](https://about.gitlab.com/pricing/#self-managed) in the following tiers:
| Tier | Includes |
|:---------|:-----------------------------------------------|
| Core | Core features. |
| Starter | Core and Starter features. |
| Premium | Core, Starter, and Premium features. |
| Ultimate | Core, Starter, Premium, and Ultimate features. |
The following resources are available for more information on GitLab self-managed:
- [Feature comparison](https://about.gitlab.com/pricing/self-managed/feature-comparison/), for information on what features are available at each tier.
- [GitLab pricing page](https://about.gitlab.com/pricing/#self-managed), for subscription information and a free trial.
- Our [product marketing page](https://about.gitlab.com/handbook/marketing/product-marketing/), for additional information including:
- How [different tiers are licensed](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers).
- The different [GitLab distributions](https://about.gitlab.com/handbook/marketing/product-marketing/#distributions).
#### Subscribing through GitLab self-managed
### Subscribe through GitLab self-managed
To subscribe to GitLab through a self-managed installation:
1. [Install](https://about.gitlab.com/install/) GitLab.
1. Complete the installation with
[administration tasks](../administration/index.md).
1. Select the **Starter**, **Premium**, or **Ultimate** self-managed plan
through the [GitLab Subscription Manager](https://customers.gitlab.com/).
1. Apply your license file. After purchase, a license file is sent to the email
address associated to the GitLab Subscription Manager account,
which needs to be
[uploaded to your GitLab instance](../user/admin_area/license.md#uploading-your-license).
1. Go to the [Customers Portal](https://customers.gitlab.com/) and purchase a **Starter**, **Premium**, or **Ultimate** self-managed plan.
1. After purchase, a license file is sent to the email address associated to the Customers Portal account,
which must be [uploaded to your GitLab instance](../user/admin_area/license.md#uploading-your-license).
TIP: **Tip:**
If you are purchasing a subscription for an existing **Core** self-managed
instance, ensure you are purchasing enough seats to
If you're purchasing a subscription for an existing **Core** self-managed
instance, ensure you're purchasing enough seats to
[cover your users](../user/admin_area/index.md#administering-users).
## Managing subscriptions
You can view and manage subscriptions through our
[GitLab Subscription Manager](https://customers.gitlab.com/).
### View subscription and seats
## Manage your GitLab account
Visit the
[GitLab Subscription Manager](https://customers.gitlab.com/subscriptions) to
view and manage:
With the [Customers Portal](https://customers.gitlab.com/) you can:
- The subscriptions you have purchased.
- The number of seats associated with the subscription.
- Retrieve copies of invoices.
- Change the credit card on file.
For more information, please see our:
- [Subscription FAQ](https://about.gitlab.com/pricing/licensing-faq/).
- [Pricing page](https://about.gitlab.com/pricing/), which includes information
on our [true-up pricing policy](https://about.gitlab.com/handbook/ceo/pricing/#true-up-pricing)
when adding more users other than at the time of purchase.
NOTE: **Note:**
The GitLab Subscription Manager account can have the same email address as your
GitLab.com account, but is a _separate_ login. If the two accounts are
linked together, you can use the **Or sign in with GitLab.com**
link underneath the **Sign In** button.
- [Change billing information](#change-billing-information)
- [Change the linked account](#change-the-linked-account)
- [Change the associated namespace](#change-the-associated-namespace)
### Change billing information
To change billing information:
1. Log in to [GitLab Subscription Manager](https://customers.gitlab.com/customers/sign_in).
1. Log in to [Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Go to the **My Account** page.
1. Make the required changes to the **Account Details** information.
1. Click **Update Account**.
NOTE: **Note:**
Future purchases will use the information in this section.
The email listed in this section is used for the GitLab Subscription Manager
The email listed in this section is used for the Customers Portal
login and for license-related email communication.
### Manage GitLab.com account
This section provided information specific to managing subscriptions with a
GitLab.com account.
### Change the linked account
#### Change linked account
To change the GitLab.com account associated with a GitLab Subscription Manager
To change the GitLab.com account associated with a Customers Portal
account:
1. Log in to the
[GitLab Subscription Manager](https://customers.gitlab.com/customers/sign_in).
[Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Go to [GitLab.com](https://gitlab.com) in a separate browser tab. Ensure you
are not logged in.
1. On the GitLab Subscription Manager page, click
1. On the Customers Portal page, click
[**My Account**](https://customers.gitlab.com/customers/edit) in the top menu.
1. Under **Your GitLab.com account**, click **Change linked account** button.
1. Log in to [GitLab.com](https://gitlab.com) account to link to.
1. Log in to the [GitLab.com](https://gitlab.com) account you want to link to Customers Portal.
#### Change associated namespace
### Change the associated namespace
With a linked GitLab.com account:
1. Log in to the [GitLab Subscription Manager](https://customers.gitlab.com/customers/sign_in).
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
1. Navigate to the **Manage Purchases** page.
1. Click **Change linked group**.
1. Select the desired group from the **This subscription is for** dropdown.
......@@ -202,15 +157,15 @@ With a linked GitLab.com account:
Subscription charges are calculated based on the total number of users in a group, including its subgroups and nested projects. If the total number of users exceeds the number of seats in your subscription, you will be charged for the additional users.
### Confirm or upgrade your subscription
## View your subscription
To see the status of your GitLab.com subscription, you can click on the
**Billings** section of the relevant namespace:
To see the status of your GitLab.com subscription, log into GitLab.com and go to the **Billing** section of the relevant namespace:
- For individuals:
1. Go to **User Avatar > Settings**.
1. Click **Billing**.
- For groups, go to the group's **Settings** dropdown, under **Billing**.
- For groups:
1. From the group page (*not* from a project within the group), go to **Settings > Billing**.
The following table describes details of your subscription for groups:
......@@ -219,161 +174,182 @@ The following table describes details of your subscription for groups:
| Seats in subscription | If this is a paid plan, represents the number of seats you've paid to support in your group. |
| Seats currently in use | Number of active seats currently in use. |
| Max seats used | Highest number of seats you've used. If this exceeds the seats in subscription, you may owe an additional fee for the additional users. |
| Seats owed | If your max seats used exceeds the seats in your subscription, you'll owe an additional fee for the users you've added. |
| Seats owed | If your maximum seats used exceeds the seats in your subscription, you'll owe an additional fee for the users you've added. |
| Subscription start date | Date your subscription started. If this is for a Free plan, is the date you transitioned off your group's paid plan. |
| Subscription end date | Date your current subscription will end. Does not apply to Free plans. |
#### CI pipeline minutes
## Renew your subscription
CI pipeline minutes are the execution time for your [pipelines](../ci/pipelines.md) on GitLab's shared runners. Each [GitLab.com tier](https://about.gitlab.com/pricing/) includes a monthly quota of CI pipeline minutes.
To renew your subscription, [prepare for the renewal](#prepare-for-renewal), then do one of the following:
Quotas apply to:
- [Renew a GitLab.com subscription](#renew-or-change-a-gitlabcom-subscription).
- [Renew a self-managed subscription](#renew-a-self-managed-subscription).
- Groups, where the minutes are shared across all members of the group, its subgroups, and nested projects. To view the group's usage, navigate to the group's page, then **Settings > Usage Quotas**.
### Prepare for renewal
- Your personal account, where the minutes are available for your personal projects. To view and buy personal minutes, click your avatar, then **Settings > Pipeline quota**.
The [Customers Portal](https://customers.gitlab.com/customers/sign_in) is your tool for renewing and modifying your subscription. Before going ahead with renewal, log in and verify or update:
Only pipeline minutes for GitLab shared runners are restricted. If you have a specific runner set up for your projects, there is no limit to your build time on GitLab.com.
- The invoice contact details on the **My Account** page.
- The credit card on file in the **Payment Methods** page.
The minutes limit does not apply to public projects.
TIP: **Tip:**
Contact our [support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) if you need assistance accessing the Customers Portal or if you need to change the contact person who manages your subscription.
The available quota is reset on the first of each calendar month at midnight UTC.
Check who is accessing your system. Are there user accounts which are no longer active? It's important to regularly review your GitLab user accounts because:
If you reach your limit, you can [purchase additional CI minutes](#extra-shared-runners-pipeline-minutes), or upgrade your account to [Silver or Gold](https://about.gitlab.com/pricing/). Your own runners can still be used even if you reach your limits.
- A GitLab subscription is based on the number of users. Renewing a subscription for too many users results in you paying more than you should. Attempting to renew a subscription for too few users will result in the renewal failing.
- Stale user accounts can be a security risk. A regular review helps reduce this risk.
##### How pipeline quota usage is calculated
#### Users over License
Pipeline quota usage is calculated as the sum of the duration of each individual job. This is slightly different to how pipeline _duration_ is [calculated](../ci/pipelines.md#how-pipeline-duration-is-calculated). Pipeline quota usage doesn't consider the intersection of jobs.
A GitLab subscription is valid for a specific number of users. For details, see [Choose the number of users](#choosing-the-number-of-users). If the active user count exceeds the number included in the subscription, known as the number of _users over license_, you must pay for the excess number of users either before renewal, or at the time of renewal. This is also known the _true up_ process.
A simple example is:
##### Purchase additional seats for GitLab.com
A (1, 3)
B (2, 4)
C (6, 7)
There is no self-service option for purchasing additional seats. You must request a quotation from GitLab Sales. To do so, contact GitLab via our [support form](https://support.gitlab.com/hc/en-us/requests/new) and select **Licensing and Renewals Problems** from the menu.
In the example:
The amount charged per seat is calculated by one of the following methods:
A begins at 1 and ends at 3.
B begins at 2 and ends at 4.
C begins at 6 and ends at 7.
Visually, it can be viewed as:
- If paid before renewal, the amount per seat is calculated on a prorated basis. For example, if the user was added 3 months before the end of the subscription period, the amount owing is calculated as: (3 / 12) x annual fee.
- If paid on renewal, the amount per seat is the standard annual fee.
```
0 1 2 3 4 5 6 7
AAAAAAA
BBBBBBB
CCCC
```
##### Purchase additional users for self-managed
The sum of each individual job is being calculated therefore in this example, `8` runner minutes would be used for this pipeline:
Self-managed instances can add users to a subscription any time during the subscription period. The cost of additional users added during the subscription period is prorated from the date of purchase through the end of the subscription period.
```
A + B + C = 3 + 3 + 2 => 8
```
To add users to a subscription:
#### Extra Shared Runners pipeline minutes
1. Log in to [Customers Portal](https://customers.gitlab.com/).
1. Select **Manage Purchases**.
1. Select **Add more seats**.
1. Enter the number of additional users.
1. Select **Proceed to checkout**.
1. Review the **Subscription Upgrade Detail**. The system lists the total price for all users on the system and a credit for what you've already paid. You will only be charged for the net change.
1. Select **Confirm Upgrade**.
If you're using GitLab.com, you can purchase additional CI minutes so your
pipelines will not be blocked after you have used all your CI minutes from your
main quota. Additional minutes:
The following will be emailed to you:
- Are only used once the shared quota included in your subscription runs out.
- Roll over month to month.
- A payment receipt. You can also access this information in the Customers Portal under **Payment History**.
- A new license. [Upload this license](../user/admin_area/license.md#uploading-your-license) to your instance to use it.
Each month, any minutes that you used will be deducted from your balance of additional minutes.
Therefore, the number of minutes used and available will reflect your *current*
month's usage and availability. Purchased remaining minutes not used in the
current month will be rolled out over to the next month.
### Renew or change a GitLab.com subscription
For example:
To renew for more users than are currently active in your GitLab.com system, contact our sales team via `renewals@gitlab.com` for assistance as this can't be done in Customers Portal.
- February 15: A group buys 4000 minutes. The count reads 0/4000 minutes.
- February 28: The group has used 1500 minutes. The count reads 1500/4000 minutes. Thus, there are 2500 minutes remaining.
- March 1: The counter reads: 0/2500 minutes rolled out from February's remaining quota.
To change the [GitLab tier](https://about.gitlab.com/pricing/), select **Upgrade** under your subscription on the [My Account](https://customers.gitlab.com/subscriptions) page.
##### Purchasing additional minutes
#### Automatic renewal
To purchase additional minutes, follow these steps.
To view or change automatic subscription renewal (at the same tier as the previous period), log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in), and:
1. For group minutes, go to **Group > Settings > Pipelines quota**.
- If you see a **Resume subscription** button, your subscription was cancelled previously. Click it to resume automatic renewal.
- If you see **Cancel subscription**, your subscription is set to automatically renew at the end of the subscription period. Click it to cancel automatic renewal.
For personal project minutes, click your avatar, then **Settings > Pipeline quota**.
With automatic renewal enabled, the subscription will automatically renew on the expiration date and there will be no gap in available service.
An invoice will be generated for the renewal and available for viewing or download in the [Payment History](https://customers.gitlab.com/receipts) page. If you have difficulty during the renewal process, contact our [support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) for assistance.
1. Click **Buy additional minutes**.
### Renew a self-managed subscription
1. Locate the subscription card that is linked to your group on GitLab.com,
click **Buy more CI minutes**, and complete the details about the transaction.
Starting 30 days before a subscription expires, GitLab notifies administrators of the date of expiry with a banner in the GitLab user interface.
![Buy additional minutes](img/buy_minutes_card.png)
We recommend following these steps during renewal:
1. Once we have processed your payment, the extra CI minutes
will be synced to your Group and you can visualize it from the
**Group > Settings > Pipelines quota** page:
1. Prune any inactive or unwanted users by [blocking them](../user/admin_area/blocking_unblocking_users.md#blocking-a-user).
1. Determine if you have a need for user growth in the upcoming subscription.
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) and select the **Renew** button beneath your existing subscription.
![Additional minutes](img/additional_minutes.png)
TIP: **Tip:**
If you need to change your [GitLab tier](https://about.gitlab.com/pricing/), contact our sales team via `renewals@gitlab.com` for assistance as this can't be done in Customers Portal.
The **Additional minutes** displayed now includes the purchased additional CI minutes, plus any
minutes rolled over from last month.
1. In the first box, enter the total number of user licenses you’ll need for the upcoming year. Be sure this number is at least **equal to, or greater than** the number of active users in the system at the time of performing the renewal.
1. Enter the number of [users over license](#users-over-license) in the second box for the user overage incurred in your previous subscription term.
Be aware that:
1. If you have purchased extra CI minutes before the purchase of a paid plan,
we will calculate a pro-rated charge for your paid plan. That means you may
be charged for less than one year since your subscription was previously
created with the extra CI minutes.
1. Once the extra CI minutes has been assigned to a Group they cannot be transferred
to a different Group.
1. If you have some minutes used over your default quota, these minutes will
be deducted from your Additional Minutes quota immediately after your purchase of additional
minutes.
##### What happens when my CI minutes run out
When the CI minutes run out, an email is sent automatically to notify the owner(s)
of the group/namespace, including a link to [purchase more minutes](https://customers.gitlab.com/plans).
If you are not the owner of the group, you will need to contact them to let them know they need to
[purchase more minutes](https://customers.gitlab.com/plans).
TIP: **Tip:**
You can find the _users over license_ in your instance's **Admin** dashboard by clicking on {**admin**} (**Admin Area**) in the top bar, or going to `/admin`.
## Subscription changes and your data
1. Review your renewal details and complete the payment process.
1. A license for the renewal term will be available on the [Manage Purchases](https://customers.gitlab.com/subscriptions) page beneath your new subscription details.
1. [Upload](../user/admin_area/license.md) your new license to your instance.
When your subscription or trial expires, GitLab does not delete your data.
An invoice will be generated for the renewal and available for viewing or download in the [Payment History](https://customers.gitlab.com/receipts) page. If you have difficulty during the renewal process, contact our [support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) for assistance.
However, depending on the tier and feature, your data may become inaccessible.
## Subscription expiry
Please note that some features may not behave as expected if a graceful
fallback is not currently implemented. For example,
[environment specific variables not being passed](https://gitlab.com/gitlab-org/gitlab-foss/issues/52825).
When your subscription or trial expires, GitLab does not delete your data, but it may become inaccessible, depending on the tier at expiry. Some features may not behave as expected if you're not prepared for the expiry. For example, [environment specific variables not being passed](https://gitlab.com/gitlab-org/gitlab/issues/24759).
If you renew or upgrade, your data will again be accessible.
### Self-managed data
### Self-managed GitLab data
For self-managed customers, there is a two-week grace period when your features
will continue to work as-is, after which the entire instance will become read
only.
However, if you remove the license, you will immediately revert to Core
features.
features, and the instance will be read / write again.
## Need help?
## CI pipeline minutes
[GitLab's Documentation](https://docs.gitlab.com/) offers a wide range of
topics covering the use and administration of GitLab.
CI pipeline minutes are the execution time for your [pipelines](../ci/pipelines.md) on GitLab's shared runners. Each [GitLab.com tier](https://about.gitlab.com/pricing/) includes a monthly quota of CI pipeline minutes.
We also encourage all users to search our project trackers for known issues and
existing feature requests in:
Quotas apply to:
- Groups, where the minutes are shared across all members of the group, its subgroups, and nested projects. To view the group's usage, navigate to the group's page, then **Settings > Usage Quotas**.
- Your personal account, where the minutes are available for your personal projects. To view and buy personal minutes, click your avatar, then **Settings > Pipeline quota**.
Only pipeline minutes for GitLab shared runners are restricted. If you have a specific runner set up for your projects, there is no limit to your build time on GitLab.com.
The minutes limit does not apply to public projects.
The available quota is reset on the first of each calendar month at midnight UTC.
When the CI minutes are depleted, an email is sent automatically to notify the owner(s)
of the group/namespace. You can [purchase additional CI minutes](#purchasing-additional-ci-minutes), or upgrade your account to [Silver or Gold](https://about.gitlab.com/pricing/). Your own runners can still be used even if you reach your limits.
- [GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/issues/) for features
included in all tiers.
- [GitLab EE](https://gitlab.com/gitlab-org/gitlab/issues/) for paid-tier
features.
### Purchasing additional CI minutes
If you're using GitLab.com, you can purchase additional CI minutes so your
pipelines won't be blocked after you have used all your CI minutes from your
main quota. Additional minutes:
- Are only used once the shared quota included in your subscription runs out.
- Roll over month to month.
To purchase additional minutes for your group on GitLab.com:
1. From your group, go to **Settings > Pipeline quota**.
1. Locate the subscription card that's linked to your group on GitLab.com, click **Buy more CI minutes**, and complete the details about the transaction.
1. Once we have processed your payment, the extra CI minutes will be synced to your group.
1. To confirm the available CI minutes, go to **Group > Settings > Pipelines quota**.
The **Additional minutes** displayed now includes the purchased additional CI minutes, plus any minutes rolled over from last month.
To purchase additional minutes for your personal namespace:
1. Click your avatar, then go to **Settings > Pipeline quota**.
1. Locate the subscription card that's linked to your personal namespace on GitLab.com, click **Buy more CI minutes**, and complete the details about the transaction. Once we have processed your payment, the extra CI minutes will be synced to your Group.
1. To confirm the available CI minutes for your personal projects, click your avatar, then go to **Settings > Pipeline quota**.
The **Additional minutes** displayed now includes the purchased additional CI minutes, plus any minutes rolled over from last month.
Be aware that:
- If you have purchased extra CI minutes before the purchase of a paid plan,
we will calculate a pro-rated charge for your paid plan. That means you may
be charged for less than one year since your subscription was previously
created with the extra CI minutes.
- Once the extra CI minutes has been assigned to a Group they can't be transferred
to a different Group.
- If you have used more minutes than your default quota, these minutes will
be deducted from your Additional Minutes quota immediately after your purchase of additional
minutes.
## Contact Support
We also encourage all users to search our project trackers for known issues and
existing feature requests in the [GitLab](https://gitlab.com/gitlab-org/gitlab/issues/) project.
These issues are the best avenue for getting updates on specific product plans
and for communicating directly with the relevant GitLab team members.
### Contacting Support
Learn more about:
- The tiers of [GitLab Support](https://about.gitlab.com/support/).
......
......@@ -41,7 +41,7 @@ Please note that for the deactivation option to be visible to an admin, the user
Users can also be deactivated using the [GitLab API](../../api/users.md#deactivate-user).
NOTE: **Note:**
A deactivated user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions).
A deactivated user does not consume a [seat](../../subscriptions/index.md#choosing-the-number-of-users).
## Activating a user
......@@ -60,7 +60,7 @@ Users can also be activated using the [GitLab API](../../api/users.md#activate-u
NOTE: **Note:**
Activating a user will change the user's state to active and it consumes a
[seat](../../subscriptions/index.md#managing-subscriptions).
[seat](../../subscriptions/index.md#choosing-the-number-of-users).
TIP: **Tip:**
A deactivated user can also activate their account by themselves by simply logging back via the UI.
......@@ -30,7 +30,7 @@ Personal projects, and group and user history of the blocked user will be left i
Users can also be blocked using the [GitLab API](../../api/users.md#block-user).
NOTE: **Note:**
A blocked user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions).
A blocked user does not consume a [seat](../../subscriptions/index.md#choosing-the-number-of-users).
## Unblocking a user
......@@ -45,4 +45,4 @@ Users can also be unblocked using the [GitLab API](../../api/users.md#unblock-us
NOTE: **Note:**
Unblocking a user will change the user's state to active and it consumes a
[seat](../../subscriptions/index.md#managing-subscriptions).
[seat](../../subscriptions/index.md#choosing-the-number-of-users).
......@@ -117,7 +117,7 @@ service included with GitLab that coordinates the jobs.
If the project is on GitLab.com, shared Runners are available
(the first 2000 minutes are free, you can
[buy more later](../../subscriptions/index.md#extra-shared-runners-pipeline-minutes))
[buy more later](../../subscriptions/index.md#purchasing-additional-ci-minutes))
and you do not have to deploy one if they are enough for your needs. If a
project-specific Runner is desired, or there are no shared Runners, it is easy
to deploy one.
......
......@@ -104,7 +104,7 @@ Linux Shared Runners on GitLab.com run in [autoscale mode] and are powered by Go
Autoscaling means reduced waiting times to spin up CI/CD jobs, and isolated VMs for each project,
thus maximizing security. They're free to use for public open source projects and limited
to 2000 CI minutes per month per group for private projects. More minutes
[can be purchased](../../subscriptions/index.md#extra-shared-runners-pipeline-minutes), if
[can be purchased](../../subscriptions/index.md#purchasing-additional-ci-minutes), if
needed. Read about all [GitLab.com plans](https://about.gitlab.com/pricing/).
All your CI/CD jobs run on [n1-standard-1 instances](https://cloud.google.com/compute/docs/machine-types) with 3.75GB of RAM, CoreOS and the latest Docker Engine
......
......@@ -55,6 +55,14 @@ if (IS_EE) {
collectCoverageFrom.push(rootDirEE.replace('$1', '/**/*.{js,vue}'));
}
const coverageDirectory = () => {
if (process.env.CI_NODE_INDEX && process.env.CI_NODE_TOTAL) {
return `<rootDir>/coverage-frontend/jest-${process.env.CI_NODE_INDEX}-${process.env.CI_NODE_TOTAL}`;
}
return '<rootDir>/coverage-frontend/';
};
// eslint-disable-next-line import/no-commonjs
module.exports = {
clearMocks: true,
......@@ -62,7 +70,7 @@ module.exports = {
moduleFileExtensions: ['js', 'json', 'vue'],
moduleNameMapper,
collectCoverageFrom,
coverageDirectory: '<rootDir>/coverage-frontend/',
coverageDirectory: coverageDirectory(),
coverageReporters: ['json', 'lcov', 'text-summary', 'clover'],
cacheDirectory: '<rootDir>/tmp/cache/jest',
modulePathIgnorePatterns: ['<rootDir>/.yarn-cache/'],
......
......@@ -14,6 +14,7 @@ module Gitlab
MAX_CHANGED_LINES_IN_COMMIT = 30
SHORT_REFERENCE_REGEX = %r{([\w\-\/]+)?(#|!|&|%)\d+\b}.freeze
DEFAULT_SUBJECT_DESCRIPTION = 'commit subject'
WIP_PREFIX = 'WIP: '
PROBLEMS = {
subject_too_short: "The %s must contain at least #{MIN_SUBJECT_WORDS_COUNT} words",
subject_too_long: "The %s may not be longer than #{MAX_LINE_LENGTH} characters",
......@@ -164,7 +165,7 @@ module Gitlab
end
def subject
message_parts[0]
message_parts[0].delete_prefix(WIP_PREFIX)
end
def separator
......
......@@ -40,7 +40,7 @@ module Gitlab
ProjectTemplate.new('rails', 'Ruby on Rails', _('Includes an MVC structure, Gemfile, Rakefile, along with many others, to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/rails', 'illustrations/logos/rails.svg'),
ProjectTemplate.new('spring', 'Spring', _('Includes an MVC structure, mvnw and pom.xml to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/spring', 'illustrations/logos/spring.svg'),
ProjectTemplate.new('express', 'NodeJS Express', _('Includes an MVC structure to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/express', 'illustrations/logos/express.svg'),
ProjectTemplate.new('iosswift', 'iOS (Swift)', _('A ready-to-go template for use with iOS Swift apps.'), 'https://gitlab.com/gitlab-org/project-templates/iosswift'),
ProjectTemplate.new('iosswift', 'iOS (Swift)', _('A ready-to-go template for use with iOS Swift apps.'), 'https://gitlab.com/gitlab-org/project-templates/iosswift', 'illustrations/logos/swift.svg'),
ProjectTemplate.new('dotnetcore', '.NET Core', _('A .NET Core console application template, customizable for any .NET Core project'), 'https://gitlab.com/gitlab-org/project-templates/dotnetcore', 'illustrations/logos/dotnet.svg'),
ProjectTemplate.new('android', 'Android', _('A ready-to-go template for use with Android apps.'), 'https://gitlab.com/gitlab-org/project-templates/android', 'illustrations/logos/android.svg'),
ProjectTemplate.new('gomicro', 'Go Micro', _('Go Micro is a framework for micro service development.'), 'https://gitlab.com/gitlab-org/project-templates/go-micro'),
......
# frozen_string_literal: true
module Gitlab
module Testing
class ClearThreadMemoryCacheMiddleware
def initialize(app)
@app = app
end
def call(env)
Gitlab::ThreadMemoryCache.cache_backend.clear
@app.call(env)
end
end
end
end
const { create } = require('istanbul-reports');
const { createCoverageMap } = require('istanbul-lib-coverage');
const { createContext } = require('istanbul-lib-report');
const { resolve } = require('path');
const { sync } = require('glob');
const coverageMap = createCoverageMap();
const coverageDir = resolve(__dirname, '../../coverage-frontend');
const reportFiles = sync(`${coverageDir}/*/coverage-final.json`);
// Normalize coverage report generated by jest that has additional "data" key
// https://github.com/facebook/jest/issues/2418#issuecomment-423806659
const normalizeReport = report => {
const normalizedReport = Object.assign({}, report);
Object.entries(normalizedReport).forEach(([k, v]) => {
if (v.data) normalizedReport[k] = v.data;
});
return normalizedReport;
};
reportFiles
.map(reportFile => require(reportFile))
.map(normalizeReport)
.forEach(report => coverageMap.merge(report));
const context = createContext({ coverageMap: coverageMap, dir: 'coverage-frontend' });
['json', 'lcov', 'text-summary', 'clover'].forEach(reporter => {
create(reporter, {}).execute(context);
});
const Sequencer = require('@jest/test-sequencer').default;
class ParallelCISequencer extends Sequencer {
constructor() {
super();
this.ciNodeIndex = Number(process.env.CI_NODE_INDEX || '1');
this.ciNodeTotal = Number(process.env.CI_NODE_TOTAL || '1');
}
sort(tests) {
const sortedTests = this.sortByPath(tests);
const testsForThisRunner = this.distributeAcrossCINodes(sortedTests);
console.log(`CI_NODE_INDEX: ${this.ciNodeIndex}`);
console.log(`CI_NODE_TOTAL: ${this.ciNodeTotal}`);
console.log(`Total number of tests: ${tests.length}`);
console.log(`Total number of tests for this runner: ${testsForThisRunner.length}`);
return testsForThisRunner;
}
sortByPath(tests) {
return tests.sort((test1, test2) => {
if (test1.path < test2.path) {
return -1;
}
if (test1.path > test2.path) {
return 1;
}
return 0;
});
}
distributeAcrossCINodes(tests) {
return tests.filter((test, index) => {
return index % this.ciNodeTotal === this.ciNodeIndex - 1;
});
}
}
module.exports = ParallelCISequencer;
......@@ -143,16 +143,11 @@ describe "Issues > User edits issue", :js do
end
it 'allows user to unselect themselves' do
issue2 = create(:issue, project: project, author: user)
issue2 = create(:issue, project: project, author: user, assignees: [user])
visit project_issue_path(project, issue2)
page.within '.assignee' do
click_link 'Edit'
click_link user.name
close_dropdown_menu_if_visible
page.within '.value .author' do
expect(page).to have_content user.name
end
......
......@@ -11,81 +11,77 @@ describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do
let(:admin) { create(:admin) }
around do |example|
Timecop.freeze(Time.zone.parse('2018-03-12 09:06')) do
example.run
end
end
it 'User sees their active sessions' do
Capybara::Session.new(:session1)
Capybara::Session.new(:session2)
Capybara::Session.new(:session3)
# note: headers can only be set on the non-js (aka. rack-test) driver
using_session :session1 do
Capybara.page.driver.header(
'User-Agent',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0'
)
gitlab_sign_in(user)
end
# set an additional session on another device
using_session :session2 do
Capybara.page.driver.header(
'User-Agent',
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B466 [FBDV/iPhone7,2]'
)
gitlab_sign_in(user)
end
# set an admin session impersonating the user
using_session :session3 do
Capybara.page.driver.header(
'User-Agent',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'
)
gitlab_sign_in(admin)
visit admin_user_path(user)
click_link 'Impersonate'
end
using_session :session1 do
visit profile_active_sessions_path
expect(page).to(
have_selector('ul.list-group li.list-group-item', { text: 'Signed in on',
count: 2 }))
expect(page).to have_content(
'127.0.0.1 ' \
'This is your current session ' \
'Firefox on Ubuntu ' \
'Signed in on 12 Mar 09:06'
)
expect(page).to have_selector '[title="Desktop"]', count: 1
expect(page).to have_content(
'127.0.0.1 ' \
'Last accessed on 12 Mar 09:06 ' \
'Mobile Safari on iOS ' \
'Signed in on 12 Mar 09:06'
)
expect(page).to have_selector '[title="Smartphone"]', count: 1
expect(page).not_to have_content('Chrome on Windows')
Timecop.freeze(Time.zone.parse('2018-03-12 09:06')) do
Capybara::Session.new(:session1)
Capybara::Session.new(:session2)
Capybara::Session.new(:session3)
# note: headers can only be set on the non-js (aka. rack-test) driver
using_session :session1 do
Capybara.page.driver.header(
'User-Agent',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0'
)
gitlab_sign_in(user)
end
# set an additional session on another device
using_session :session2 do
Capybara.page.driver.header(
'User-Agent',
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B466 [FBDV/iPhone7,2]'
)
gitlab_sign_in(user)
end
# set an admin session impersonating the user
using_session :session3 do
Capybara.page.driver.header(
'User-Agent',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'
)
gitlab_sign_in(admin)
visit admin_user_path(user)
click_link 'Impersonate'
end
using_session :session1 do
visit profile_active_sessions_path
expect(page).to(
have_selector('ul.list-group li.list-group-item', { text: 'Signed in on',
count: 2 }))
expect(page).to have_content(
'127.0.0.1 ' \
'This is your current session ' \
'Firefox on Ubuntu ' \
'Signed in on 12 Mar 09:06'
)
expect(page).to have_selector '[title="Desktop"]', count: 1
expect(page).to have_content(
'127.0.0.1 ' \
'Last accessed on 12 Mar 09:06 ' \
'Mobile Safari on iOS ' \
'Signed in on 12 Mar 09:06'
)
expect(page).to have_selector '[title="Smartphone"]', count: 1
expect(page).not_to have_content('Chrome on Windows')
end
end
end
it 'User can revoke a session', :js, :redis_session_store do
it 'User can revoke a session', :js do
Capybara::Session.new(:session1)
Capybara::Session.new(:session2)
......
......@@ -200,7 +200,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
end
end
context 'when third party offers are disabled' do
context 'when third party offers are disabled', :clean_gitlab_redis_shared_state do
let(:admin) { create(:admin) }
before do
......
......@@ -9,7 +9,7 @@ describe 'Projects > Snippets > Create Snippet', :js do
let_it_be(:project) { create(:project, :public) }
def description_field
find('.js-description-input input,textarea')
find('.js-description-input').find('input,textarea')
end
def fill_form
......
......@@ -6,7 +6,7 @@ describe 'User creates snippet', :js do
let(:user) { create(:user) }
def description_field
find('.js-description-input input,textarea')
find('.js-description-input').find('input,textarea')
end
before do
......
......@@ -14,7 +14,7 @@ describe 'User creates snippet', :js do
end
def description_field
find('.js-description-input input,textarea')
find('.js-description-input').find('input,textarea')
end
def fill_form
......
......@@ -89,6 +89,8 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
title="Copy login command"
type="button"
>
<!---->
<svg
class="gl-icon s16"
>
......@@ -126,6 +128,8 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
title="Copy build command"
type="button"
>
<!---->
<svg
class="gl-icon s16"
>
......@@ -155,6 +159,8 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
title="Copy push command"
type="button"
>
<!---->
<svg
class="gl-icon s16"
>
......
......@@ -8,6 +8,8 @@ exports[`Expand button on click when short text is provided renders button after
style="display: none;"
type="button"
>
<!---->
<svg
aria-hidden="true"
class="s12 ic-ellipsis_h"
......@@ -32,6 +34,8 @@ exports[`Expand button on click when short text is provided renders button after
style=""
type="button"
>
<!---->
<svg
aria-hidden="true"
class="s12 ic-ellipsis_h"
......@@ -51,6 +55,8 @@ exports[`Expand button when short text is provided renders button before text 1`
class="btn js-text-expander-prepend text-expander btn-blank btn-secondary btn-md"
type="button"
>
<!---->
<svg
aria-hidden="true"
class="s12 ic-ellipsis_h"
......@@ -75,6 +81,8 @@ exports[`Expand button when short text is provided renders button before text 1`
style="display: none;"
type="button"
>
<!---->
<svg
aria-hidden="true"
class="s12 ic-ellipsis_h"
......
......@@ -46,7 +46,15 @@ describe Types::BaseField do
expect(field.to_graphql.complexity).to eq 12
end
context 'when field has a resolver proc' do
context 'when field has a resolver' do
context 'when a valid complexity is already set' do
let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: resolver, complexity: 2, max_page_size: 100, null: true) }
it 'uses this complexity' do
expect(field.to_graphql.complexity).to eq 2
end
end
context 'and is a connection' do
let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: resolver, max_page_size: 100, null: true) }
......@@ -59,6 +67,17 @@ describe Types::BaseField do
expect(field.to_graphql.complexity.call({}, { first: 1 }, 2)).to eq 2
expect(field.to_graphql.complexity.call({}, { first: 1, foo: true }, 2)).to eq 4
end
context 'when graphql_resolver_complexity is disabled' do
before do
stub_feature_flags(graphql_resolver_complexity: false)
end
it 'sets default field complexity' do
expect(field.to_graphql.complexity.call({}, {}, 2)).to eq 1
expect(field.to_graphql.complexity.call({}, { first: 50 }, 2)).to eq 1
end
end
end
context 'and is not a connection' do
......
......@@ -145,34 +145,30 @@ describe('ReadyToMerge', () => {
});
});
describe('mergeButtonClass', () => {
const defaultClass = 'btn btn-sm btn-success accept-merge-request';
const failedClass = `${defaultClass} btn-danger`;
const inActionClass = `${defaultClass} btn-info`;
describe('mergeButtonVariant', () => {
it('defaults to success class', () => {
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
expect(vm.mergeButtonClass).toEqual(defaultClass);
expect(vm.mergeButtonVariant).toEqual('success');
});
it('returns success class for success status', () => {
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
Vue.set(vm.mr, 'pipeline', true);
expect(vm.mergeButtonClass).toEqual(defaultClass);
expect(vm.mergeButtonVariant).toEqual('success');
});
it('returns info class for pending status', () => {
Vue.set(vm.mr, 'availableAutoMergeStrategies', [MTWPS_MERGE_STRATEGY]);
expect(vm.mergeButtonClass).toEqual(inActionClass);
expect(vm.mergeButtonVariant).toEqual('info');
});
it('returns failed class for failed status', () => {
it('returns danger class for failed status', () => {
vm.mr.hasCI = true;
expect(vm.mergeButtonClass).toEqual(failedClass);
expect(vm.mergeButtonVariant).toEqual('danger');
});
});
......
......@@ -43,7 +43,7 @@ describe('Wip', () => {
is_new_mr_data: true,
};
describe('removeWIP', () => {
describe('handleRemoveWIP', () => {
it('should make a request to service and handle response', done => {
const vm = createComponent();
......@@ -57,7 +57,7 @@ describe('Wip', () => {
}),
);
vm.removeWIP();
vm.handleRemoveWIP();
setTimeout(() => {
expect(vm.isMakingRequest).toBeTruthy();
expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
......
......@@ -152,6 +152,18 @@ describe Gitlab::Danger::CommitLinter do
end
end
context 'when subject is a WIP' do
let(:final_message) { 'A B C' }
# commit message with prefix will be over max length. commit message without prefix will be of maximum size
let(:commit_message) { described_class::WIP_PREFIX + final_message + 'D' * (described_class::WARN_SUBJECT_LENGTH - final_message.size) }
it 'does not have any problems' do
commit_linter.lint
expect(commit_linter.problems).to be_empty
end
end
context 'when subject is too short and too long' do
let(:commit_message) { 'A ' + 'B' * described_class::MAX_LINE_LENGTH }
......@@ -183,7 +195,7 @@ describe Gitlab::Danger::CommitLinter do
end
end
context 'when subject ands with a period' do
context 'when subject ends with a period' do
let(:commit_message) { 'A B C.' }
it 'adds a problem' do
......
......@@ -36,6 +36,46 @@ describe Spammable do
end
end
describe '#invalidate_if_spam' do
using RSpec::Parameterized::TableSyntax
context 'when the model is spam' do
where(:recaptcha_enabled, :error) do
true | /solve the reCAPTCHA to proceed/
false | /has been discarded/
end
with_them do
subject { invalidate_if_spam(true, recaptcha_enabled) }
it 'has an error related to spam on the model' do
expect(subject.errors.messages[:base]).to match_array error
end
end
end
context 'when the model is not spam' do
[true, false].each do |enabled|
let(:recaptcha_enabled) { enabled }
subject { invalidate_if_spam(false, recaptcha_enabled) }
it 'returns no error' do
expect(subject.errors.messages[:base]).to be_empty
end
end
end
def invalidate_if_spam(is_spam, recaptcha_enabled)
stub_application_setting(recaptcha_enabled: recaptcha_enabled)
issue.tap do |i|
i.spam = is_spam
i.invalidate_if_spam
end
end
end
describe '#submittable_as_spam_by?' do
let(:admin) { build(:admin) }
let(:user) { build(:user) }
......
......@@ -152,4 +152,52 @@ describe 'GraphQL' do
end
end
end
describe 'resolver complexity' do
let_it_be(:project) { create(:project, :public) }
let(:query) do
graphql_query_for(
'project',
{ 'fullPath' => project.full_path },
query_graphql_field(resource, {}, 'edges { node { iid } }')
)
end
before do
stub_const('GitlabSchema::DEFAULT_MAX_COMPLEXITY', 6)
stub_feature_flags(graphql_resolver_complexity: true)
end
context 'when fetching single resource' do
let(:resource) { 'issues(first: 1)' }
it 'processes the query' do
post_graphql(query)
expect(graphql_errors).to be_nil
end
end
context 'when fetching too many resources' do
let(:resource) { 'issues(first: 100)' }
it 'returns an error' do
post_graphql(query)
expect_graphql_errors_to_include(/which exceeds max complexity/)
end
context 'when graphql_resolver_complexity is disabled' do
before do
stub_feature_flags(graphql_resolver_complexity: false)
end
it 'processes the query' do
post_graphql(query)
expect(graphql_errors).to be_nil
end
end
end
end
end
......@@ -60,7 +60,7 @@ Capybara.register_driver :chrome do |app|
)
end
Capybara.server = :webrick
Capybara.server = :puma
Capybara.javascript_driver = :chrome
Capybara.default_max_wait_time = timeout
Capybara.ignore_hidden_elements = true
......
......@@ -740,15 +740,15 @@
dependencies:
vue-eslint-parser "^7.0.0"
"@gitlab/svgs@^1.99.0":
version "1.99.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.99.0.tgz#bcf971c3a14920218e86da71ca115244b23a4a3f"
integrity sha512-bxYFxnmuoWPBU9isL3/CYFlr+k2YWU47Pq0vfmSmL7uLnb/vYymfZZF5p3erlZ62WGwuT3kp4GnuoZBMfmannA==
"@gitlab/svgs@^1.101.0":
version "1.101.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.101.0.tgz#5440ada1774758e42fd67212d495a29523dd0d5e"
integrity sha512-GE6wRn0UqA5f0pmX5wL/vTgUnAgZEdTIDam+OTMuMxf5a1jfxc1KlSLudgZbS3O/W79jN4uMkTdZ7X8gEzAChw==
"@gitlab/ui@^9.11.2":
version "9.11.2"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.11.2.tgz#ffb58bb10c6a8cd503a622946ed78512e9c18c6d"
integrity sha512-9acsjQ9+hSaAIGpiARNF4XfQUhulWiausns9JUTrN9XEQpa1o/EsDYqwP0HfSOMZ8JhnjSI2NGYVf+LIH5oudg==
"@gitlab/ui@^9.16.0":
version "9.16.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.16.0.tgz#ac66b55cffdfd9ac2df2abddb11445edc3494732"
integrity sha512-9PbFgqNxIAGn1LyIcnlqQuNGAiBT/fqTx8vPdaDQkdScFZksZOBwiIhpxnRk9UFABC3h+0TNeHgVigD7TKGqJw==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
......@@ -5418,6 +5418,11 @@ has-flag@^3.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-symbols@^1.0.0, has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
......@@ -5552,6 +5557,11 @@ html-entities@^1.2.1:
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
html-escaper@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491"
integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==
html-minifier@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56"
......@@ -6283,6 +6293,11 @@ istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5:
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==
istanbul-lib-coverage@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
istanbul-lib-hook@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133"
......@@ -6312,6 +6327,15 @@ istanbul-lib-report@^2.0.4, istanbul-lib-report@^2.0.8:
make-dir "^2.1.0"
supports-color "^6.1.0"
istanbul-lib-report@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==
dependencies:
istanbul-lib-coverage "^3.0.0"
make-dir "^3.0.0"
supports-color "^7.1.0"
istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8"
......@@ -6330,6 +6354,14 @@ istanbul-reports@^2.1.1, istanbul-reports@^2.2.4:
dependencies:
handlebars "^4.1.2"
istanbul-reports@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.0.tgz#d4d16d035db99581b6194e119bbf36c963c5eb70"
integrity sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==
dependencies:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
istextorbinary@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53"
......@@ -10836,6 +10868,13 @@ supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
dependencies:
has-flag "^4.0.0"
svg-tags@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册