Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-29 18:08:58 +00:00
parent 8c2d06cba7
commit a16398e10f
108 changed files with 1234 additions and 813 deletions

View File

@ -1 +1 @@
0fa08d953e0d5497fe5366836d0ed54b9ff557d8 31ea786fbf0a7874b44efcb1f8b43bc4536d9b7e

View File

@ -21,7 +21,7 @@
import { Mark } from 'prosemirror-model'; import { Mark } from 'prosemirror-model';
import { visitParents, SKIP } from 'unist-util-visit-parents'; import { visitParents, SKIP } from 'unist-util-visit-parents';
import { isFunction, isString, noop } from 'lodash'; import { isFunction, isString, noop, mapValues } from 'lodash';
const NO_ATTRIBUTES = {}; const NO_ATTRIBUTES = {};
@ -73,28 +73,47 @@ function createSourceMapAttributes(hastNode, markdown) {
} }
/** /**
* Compute ProseMirror nodes attributes from a Hast node. * Creates a function that resolves the attributes
* By default, this function includes sourcemap position * of a ProseMirror node based on a hast node.
* information in the object returned.
* *
* Other attributes are retrieved by invoking a getAttrs * @param {Object} params Parameters
* function provided by the ProseMirror node factory spec. * @param {String} params.markdown Markdown source from which the AST was generated
* * @param {Object} params.attributeTransformer An object that allows applying a transformation
* @param {*} proseMirrorNodeSpec ProseMirror node spec object * function to all the attributes listed in the attributes property.
* @param {HastNode} hastNode A hast node * @param {Array} params.attributeTransformer.attributes A list of attributes names
* @param {Array<HastNode>} hastParents All the ancestors of the hastNode * that the getAttrs function should apply the transformation
* @param {String} markdown Markdown source files content * @param {Function} params.attributeTransformer.transform A function that applies
* * a transform operation on an attribute value.
* @returns An object that contains a ProseMirror nodes attributes * @returns A `getAttrs` function
*/ */
function getAttrs(proseMirrorNodeSpec, hastNode, hastParents, markdown) { const getAttrsFactory = ({ attributeTransformer, markdown }) =>
const { getAttrs: specGetAttrs } = proseMirrorNodeSpec; /**
* Compute ProseMirror nodes attributes from a Hast node.
* By default, this function includes sourcemap position
* information in the object returned.
*
* Other attributes are retrieved by invoking a getAttrs
* function provided by the ProseMirror node factory spec.
*
* @param {Object} proseMirrorNodeSpec ProseMirror node spec object
* @param {Object} hastNode A hast node
* @param {Array} hastParents All the ancestors of the hastNode
* @param {String} markdown Markdown source files content
* @returns An object that contains a ProseMirror nodes attributes
*/
function getAttrs(proseMirrorNodeSpec, hastNode, hastParents) {
const { getAttrs: specGetAttrs } = proseMirrorNodeSpec;
const attributes = {
...createSourceMapAttributes(hastNode, markdown),
...(isFunction(specGetAttrs) ? specGetAttrs(hastNode, hastParents, markdown) : {}),
};
return { return mapValues(attributes, (value, key) =>
...createSourceMapAttributes(hastNode, markdown), attributeTransformer.attributes.includes(key)
...(isFunction(specGetAttrs) ? specGetAttrs(hastNode, hastParents, markdown) : {}), ? attributeTransformer.transform(value, key)
: value,
);
}; };
}
/** /**
* Keeps track of the Hast -> ProseMirror conversion process. * Keeps track of the Hast -> ProseMirror conversion process.
@ -322,7 +341,13 @@ class HastToProseMirrorConverterState {
* *
* @returns An object that contains ProseMirror node factories * @returns An object that contains ProseMirror node factories
*/ */
const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, markdown) => { const createProseMirrorNodeFactories = (
schema,
proseMirrorFactorySpecs,
attributeTransformer,
markdown,
) => {
const getAttrs = getAttrsFactory({ attributeTransformer, markdown });
const factories = { const factories = {
root: { root: {
selector: 'root', selector: 'root',
@ -355,20 +380,20 @@ const createProseMirrorNodeFactories = (schema, proseMirrorFactorySpecs, markdow
const nodeType = schema.nodeType(proseMirrorName); const nodeType = schema.nodeType(proseMirrorName);
state.closeUntil(parent); state.closeUntil(parent);
state.openNode(nodeType, hastNode, getAttrs(factory, hastNode, parent, markdown), factory); state.openNode(nodeType, hastNode, getAttrs(factory, hastNode, parent), factory);
}; };
} else if (factory.type === 'inline') { } else if (factory.type === 'inline') {
const nodeType = schema.nodeType(proseMirrorName); const nodeType = schema.nodeType(proseMirrorName);
factory.handle = (state, hastNode, parent) => { factory.handle = (state, hastNode, parent) => {
state.closeUntil(parent); state.closeUntil(parent);
state.openNode(nodeType, hastNode, getAttrs(factory, hastNode, parent, markdown), factory); state.openNode(nodeType, hastNode, getAttrs(factory, hastNode, parent), factory);
// Inline nodes do not have children therefore they are immediately closed // Inline nodes do not have children therefore they are immediately closed
state.closeNode(); state.closeNode();
}; };
} else if (factory.type === 'mark') { } else if (factory.type === 'mark') {
const markType = schema.marks[proseMirrorName]; const markType = schema.marks[proseMirrorName];
factory.handle = (state, hastNode, parent) => { factory.handle = (state, hastNode, parent) => {
state.openMark(markType, hastNode, getAttrs(factory, hastNode, parent, markdown), factory); state.openMark(markType, hastNode, getAttrs(factory, hastNode, parent), factory);
}; };
} else if (factory.type === 'ignore') { } else if (factory.type === 'ignore') {
factory.handle = noop; factory.handle = noop;
@ -581,9 +606,15 @@ export const createProseMirrorDocFromMdastTree = ({
factorySpecs, factorySpecs,
wrappableTags, wrappableTags,
tree, tree,
attributeTransformer,
markdown, markdown,
}) => { }) => {
const proseMirrorNodeFactories = createProseMirrorNodeFactories(schema, factorySpecs, markdown); const proseMirrorNodeFactories = createProseMirrorNodeFactories(
schema,
factorySpecs,
attributeTransformer,
markdown,
);
const state = new HastToProseMirrorConverterState(); const state = new HastToProseMirrorConverterState();
visitParents(tree, (hastNode, ancestors) => { visitParents(tree, (hastNode, ancestors) => {

View File

@ -125,6 +125,7 @@ const factorySpecs = {
selector: 'img', selector: 'img',
getAttrs: (hastNode) => ({ getAttrs: (hastNode) => ({
src: hastNode.properties.src, src: hastNode.properties.src,
canonicalSrc: hastNode.properties.src,
title: hastNode.properties.title, title: hastNode.properties.title,
alt: hastNode.properties.alt, alt: hastNode.properties.alt,
}), }),
@ -154,6 +155,7 @@ const factorySpecs = {
type: 'mark', type: 'mark',
selector: 'a', selector: 'a',
getAttrs: (hastNode) => ({ getAttrs: (hastNode) => ({
canonicalSrc: hastNode.properties.href,
href: hastNode.properties.href, href: hastNode.properties.href,
title: hastNode.properties.title, title: hastNode.properties.title,
}), }),
@ -182,6 +184,31 @@ const factorySpecs = {
}, },
}; };
const resolveUrl = (url) => {
try {
return new URL(url, window.location.origin).toString();
} catch {
return null;
}
};
const attributeTransformer = {
attributes: ['href', 'src'],
transform: (url) => {
if (!url) {
return url;
}
/**
* Resolves a URL if provided. The URL is not resolved against
* the client origin initially to protect the URL protocol
* when it is available, for example, we want to preserve
* mailto and application-specific protocols
*/
return resolveUrl(url);
},
};
export default () => { export default () => {
return { return {
deserialize: async ({ schema, markdown }) => { deserialize: async ({ schema, markdown }) => {
@ -193,6 +220,7 @@ export default () => {
factorySpecs, factorySpecs,
tree, tree,
wrappableTags, wrappableTags,
attributeTransformer,
markdown, markdown,
}), }),
skipRendering: ['footnoteReference', 'footnoteDefinition', 'code', 'definition'], skipRendering: ['footnoteReference', 'footnoteDefinition', 'code', 'definition'],

View File

@ -1,4 +1,5 @@
import { uniq, isString, omit, isFunction } from 'lodash'; import { uniq, isString, omit, isFunction } from 'lodash';
import { removeLastSlashInUrlPath, removeUrlProtocol } from '../../lib/utils/url_utility';
const defaultAttrs = { const defaultAttrs = {
td: { colspan: 1, rowspan: 1, colwidth: null }, td: { colspan: 1, rowspan: 1, colwidth: null },
@ -497,9 +498,7 @@ const linkType = (sourceMarkdown) => {
return LINK_HTML; return LINK_HTML;
}; };
const removeUrlProtocol = (url) => url.replace(/^\w+:\/?\/?/, ''); const normalizeUrl = (url) => decodeURIComponent(removeLastSlashInUrlPath(removeUrlProtocol(url)));
const normalizeUrl = (url) => decodeURIComponent(removeUrlProtocol(url));
/** /**
* Validates that the provided URL is well-formed * Validates that the provided URL is well-formed

View File

@ -669,3 +669,27 @@ export function constructWebIDEPath({
webIDEUrl(`/${sourceProjectFullPath}/merge_requests/${iid}`), webIDEUrl(`/${sourceProjectFullPath}/merge_requests/${iid}`),
); );
} }
/**
* Examples
*
* http://gitlab.com => gitlab.com
* https://gitlab.com => gitlab.com
*
* @param {String} url
* @returns A url without a protocol / scheme
*/
export const removeUrlProtocol = (url) => url.replace(/^\w+:\/?\/?/, '');
/**
* Examples
*
* https://www.gitlab.com/path/ => https://www.gitlab.com/path
* https://www.gitlab.com/?query=search => https://www.gitlab.com?query=search
* https://www.gitlab.com/#fragment => https://www.gitlab.com#fragment
*
* @param {String} url
* @returns A URL that does not have a path that ends with slash
*/
export const removeLastSlashInUrlPath = (url) =>
url.replace(/\/$/, '').replace(/\/(\?|#){1}([^/]*)$/, '$1$2');

View File

@ -1,54 +0,0 @@
/**
* Overrides styles from ToastUI editor
*/
.tui-editor-defaultUI {
// Toolbar buttons
.tui-editor-defaultUI-toolbar .toolbar-button {
color: $gray-500;
border: 0;
&:hover,
&:active {
color: $blue-500;
border: 0;
}
}
// Contextual menu's & popups
.tui-popup-wrapper {
@include gl-overflow-hidden;
@include gl-rounded-base;
@include gl-border-gray-200;
hr {
@include gl-m-0;
@include gl-bg-gray-200;
}
button {
@include gl-text-gray-700;
}
}
/**
* Overrides styles from ToastUI's Code Mirror (markdown mode) editor.
* Toast UI internally overrides some of these using the `.tui-md-` prefix.
* https://codemirror.net/doc/manual.html#styling
*/
.te-md-container .CodeMirror * {
@include gl-font-monospace;
@include gl-font-size-monospace;
@include gl-line-height-20;
}
}
/**
* Styling below ensures that YouTube videos are displayed in the editor the same as they would in about.gitlab.com
* https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/main/source/stylesheets/_base.scss#L977
*/
.video_container {
padding-bottom: 56.25%;
}

View File

@ -66,4 +66,9 @@ class DeployKey < Key
query query
end end
# This is used for the internal logic of AuditEvents::BuildService.
def impersonated?
false
end
end end

View File

@ -40,6 +40,7 @@ class Key < ApplicationRecord
after_destroy :refresh_user_cache after_destroy :refresh_user_cache
alias_attribute :fingerprint_md5, :fingerprint alias_attribute :fingerprint_md5, :fingerprint
alias_attribute :name, :title
scope :preload_users, -> { preload(:user) } scope :preload_users, -> { preload(:user) }
scope :for_user, -> (user) { where(user: user) } scope :for_user, -> (user) { where(user: user) }

View File

@ -1809,12 +1809,8 @@ class User < ApplicationRecord
end end
def attention_requested_open_merge_requests_count(force: false) def attention_requested_open_merge_requests_count(force: false)
if Feature.enabled?(:uncached_mr_attention_requests_count, self) Rails.cache.fetch(attention_request_cache_key, force: force, expires_in: COUNT_CACHE_VALIDITY_PERIOD) do
MergeRequestsFinder.new(self, attention: self.username, state: 'opened', non_archived: true).execute.count MergeRequestsFinder.new(self, attention: self.username, state: 'opened', non_archived: true).execute.count
else
Rails.cache.fetch(attention_request_cache_key, force: force, expires_in: COUNT_CACHE_VALIDITY_PERIOD) do
MergeRequestsFinder.new(self, attention: self.username, state: 'opened', non_archived: true).execute.count
end
end end
end end

View File

@ -1,8 +1,8 @@
--- ---
name: uncached_mr_attention_requests_count name: audit_event_streaming_git_operations_deploy_key_event
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84145 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93160
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/357480 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368765
milestone: '14.10' milestone: '15.3'
type: development type: development
group: group::code review group: group::release
default_enabled: false default_enabled: false

View File

@ -336,6 +336,7 @@ Users with at least the Owner role for a group can list event streaming destinat
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.9 [with a flag](../administration/feature_flags.md) named `audit_event_streaming_git_operations`. Disabled by default. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.9 [with a flag](../administration/feature_flags.md) named `audit_event_streaming_git_operations`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.0. > - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.0.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.1 by default. > - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.1 by default.
> - [Added `details.author_class` field](https://gitlab.com/gitlab-org/gitlab/-/issues/363876) in GitLab 15.3.
FLAG: FLAG:
On self-managed GitLab, by default this feature is available. To hide the On self-managed GitLab, by default this feature is available. To hide the
@ -377,6 +378,7 @@ Fetch:
"entity_type": "Project", "entity_type": "Project",
"details": { "details": {
"author_name": "Administrator", "author_name": "Administrator",
"author_class": "User",
"target_id": 29, "target_id": 29,
"target_type": "Project", "target_type": "Project",
"target_details": "example-project", "target_details": "example-project",
@ -408,6 +410,7 @@ Push:
"entity_type": "Project", "entity_type": "Project",
"details": { "details": {
"author_name": "Administrator", "author_name": "Administrator",
"author_class": "User",
"target_id": 29, "target_id": 29,
"target_type": "Project", "target_type": "Project",
"target_details": "example-project", "target_details": "example-project",
@ -429,6 +432,42 @@ Push:
} }
``` ```
#### Example payloads for SSH events with Deploy Key
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363876) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `audit_event_streaming_git_operations_deploy_key_event`. Disabled by default.
Fetch:
```json
{
"id": 1,
"author_id": -3,
"entity_id": 29,
"entity_type": "Project",
"details": {
"author_name": "deploy-key-name",
"author_class": "DeployKey",
"target_id": 29,
"target_type": "Project",
"target_details": "example-project",
"custom_message": {
"protocol": "ssh",
"action": "git-upload-pack"
},
"ip_address": "127.0.0.1",
"entity_path": "example-group/example-project"
},
"ip_address": "127.0.0.1",
"author_name": "deploy-key-name",
"entity_path": "example-group/example-project",
"target_details": "example-project",
"created_at": "2022-07-26T05:43:53.662Z",
"target_type": "Project",
"target_id": 29,
"event_type": "repository_git_operation"
}
```
### Example payloads for HTTP and HTTPS events ### Example payloads for HTTP and HTTPS events
Fetch: Fetch:
@ -441,6 +480,7 @@ Fetch:
"entity_type": "Project", "entity_type": "Project",
"details": { "details": {
"author_name": "Administrator", "author_name": "Administrator",
"author_class": "User",
"target_id": 29, "target_id": 29,
"target_type": "Project", "target_type": "Project",
"target_details": "example-project", "target_details": "example-project",
@ -472,6 +512,7 @@ Push:
"entity_type": "Project", "entity_type": "Project",
"details": { "details": {
"author_name": "Administrator", "author_name": "Administrator",
"author_class": "User",
"target_id": 29, "target_id": 29,
"target_type": "Project", "target_type": "Project",
"target_details": "example-project", "target_details": "example-project",
@ -493,6 +534,40 @@ Push:
} }
``` ```
#### Example payloads for HTTP and HTTPS events with Deploy Token
Fetch:
```json
{
"id": 1,
"author_id": -2,
"entity_id": 22,
"entity_type": "Project",
"details": {
"author_name": "deploy-token-name",
"author_class": "DeployToken",
"target_id": 22,
"target_type": "Project",
"target_details": "example-project",
"custom_message": {
"protocol": "http",
"action": "git-upload-pack"
},
"ip_address": "127.0.0.1",
"entity_path": "example-group/example-project"
},
"ip_address": "127.0.0.1",
"author_name": "deploy-token-name",
"entity_path": "example-group/example-project",
"target_details": "example-project",
"created_at": "2022-07-26T05:46:25.850Z",
"target_type": "Project",
"target_id": 22,
"event_type": "repository_git_operation"
}
```
### Example payloads for events from GitLab UI download button ### Example payloads for events from GitLab UI download button
Fetch: Fetch:
@ -506,6 +581,7 @@ Fetch:
"details": { "details": {
"custom_message": "Repository Download Started", "custom_message": "Repository Download Started",
"author_name": "example_username", "author_name": "example_username",
"author_class": "User",
"target_id": 29, "target_id": 29,
"target_type": "Project", "target_type": "Project",
"target_details": "example-group/example-project", "target_details": "example-group/example-project",

View File

@ -49,6 +49,18 @@ to all the members of that project's group. This might be interpreted as spam.
Notifications and mentions can be disabled in Notifications and mentions can be disabled in
[a group's settings](../group/manage.md#disable-email-notifications). [a group's settings](../group/manage.md#disable-email-notifications).
### Mention a group in an issue or merge request
When you mention a group in a comment, every member of the group gets a to-do item
added to their To-do list.
1. Open the MR or issue.
1. In a comment, type `@` followed by the user, group, or subgroup namespace.
For example, `@alex`, `@alex-team`, or `@alex-team/marketing`.
1. Select **Comment**.
A to-do item is created for all the group and subgroup members.
## Add a comment to a merge request diff ## Add a comment to a merge request diff
You can add comments to a merge request diff. These comments You can add comments to a merge request diff. These comments

View File

@ -48,29 +48,6 @@ For example, consider a user named Alex:
| Alex creates a group for their team with the group name `alex-team`. The group and its projects are available at: `https://gitlab.example.com/alex-team`. | The namespace in this case is `alex-team`. | | Alex creates a group for their team with the group name `alex-team`. The group and its projects are available at: `https://gitlab.example.com/alex-team`. | The namespace in this case is `alex-team`. |
| Alex creates a subgroup of `alex-team` with the subgroup name `marketing`. The subgroup and its projects are available at: `https://gitlab.example.com/alex-team/marketing`. | The namespace in this case is `alex-team/marketing`. | | Alex creates a subgroup of `alex-team` with the subgroup name `marketing`. The subgroup and its projects are available at: `https://gitlab.example.com/alex-team/marketing`. | The namespace in this case is `alex-team/marketing`. |
## Mention a group in an issue or merge request
When you mention a group in a comment, every member of the group gets a to-do item
added to their To-do list.
1. Open the MR or issue.
1. In a comment, type `@` followed by the user, group, or subgroup namespace.
For example, `@alex`, `@alex-team`, or `@alex-team/marketing`.
1. Select **Comment**.
A to-do item is created for all the group and subgroup members.
## Export members as CSV **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/287940) in GitLab 14.2.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/336520) in GitLab 14.5.
You can export a list of members in a group or subgroup as a CSV.
1. Go to your group or subgroup and select either **Group information > Members** or **Subgroup information > Members**.
1. Select **Export as CSV**.
1. After the CSV file has been generated, it is emailed as an attachment to the user that requested it.
## Related topics ## Related topics
- [Group wikis](../project/wiki/index.md) - [Group wikis](../project/wiki/index.md)

View File

@ -380,6 +380,17 @@ To disable group mentions:
1. Select **Disable group mentions**. 1. Select **Disable group mentions**.
1. Select **Save changes**. 1. Select **Save changes**.
## Export members as CSV **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/287940) in GitLab 14.2.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/336520) in GitLab 14.5.
You can export a list of members in a group or subgroup as a CSV.
1. Go to your group or subgroup and select either **Group information > Members** or **Subgroup information > Members**.
1. Select **Export as CSV**.
1. After the CSV file has been generated, it is emailed as an attachment to the user that requested it.
## User cap for groups ## User cap for groups
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330027) in GitLab 14.7. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330027) in GitLab 14.7.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,10 @@ module API
key || user key || user
end end
def deploy_key_or_user
key.instance_of?(DeployKey) ? key : user
end
def username def username
user&.username user&.username
end end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Gitlab
module Audit
class DeployKeyAuthor < Gitlab::Audit::NullAuthor
def initialize(name: nil)
super(id: -3, name: name)
end
def name
@name || _('Deploy Key')
end
end
end
end

View File

@ -24,6 +24,8 @@ module Gitlab
Gitlab::Audit::UnauthenticatedAuthor.new(name: name) Gitlab::Audit::UnauthenticatedAuthor.new(name: name)
elsif id == -2 elsif id == -2
Gitlab::Audit::DeployTokenAuthor.new(name: name) Gitlab::Audit::DeployTokenAuthor.new(name: name)
elsif id == -3
Gitlab::Audit::DeployKeyAuthor.new(name: name)
else else
Gitlab::Audit::DeletedAuthor.new(id: id, name: name) Gitlab::Audit::DeletedAuthor.new(id: id, name: name)
end end

View File

@ -20,13 +20,24 @@ namespace :contracts do
Pact::VerificationTask.new(:get_pipeline_header_data) do |pact| Pact::VerificationTask.new(:get_pipeline_header_data) do |pact|
pact.uri( pact.uri(
"#{contracts}/contracts/project/pipeline/show/pipelines#show-get_pipeline_header_data.json", "#{contracts}/contracts/project/pipeline/show/pipelines#show-get_pipeline_header_data.json",
pact_helper: "#{provider}/pact_helpers/project/pipeline/get_pipeline_header_data_helper.rb" pact_helper: "#{provider}/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb"
)
end
Pact::VerificationTask.new(:delete_pipeline) do |pact|
pact.uri(
"#{contracts}/contracts/project/pipeline/show/pipelines#show-delete_pipeline.json",
pact_helper: "#{provider}/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb"
) )
end end
desc 'Run all pipeline contract tests' desc 'Run all pipeline contract tests'
task 'test:pipelines', :contract_mr do |_t, arg| task 'test:pipelines', :contract_mr do |_t, arg|
errors = %w[get_list_project_pipelines get_pipeline_header_data].each_with_object([]) do |task, err| errors = %w[
get_list_project_pipelines
get_pipeline_header_data
delete_pipeline
].each_with_object([]) do |task, err|
Rake::Task["contracts:pipelines:pact:verify:#{task}"].execute Rake::Task["contracts:pipelines:pact:verify:#{task}"].execute
rescue StandardError, SystemExit rescue StandardError, SystemExit
err << "contracts:pipelines:pact:verify:#{task}" err << "contracts:pipelines:pact:verify:#{task}"

View File

@ -34,7 +34,7 @@ Usage: rake "gitlab:gitaly:install[/installation/dir,/storage/path]")
env["BUNDLE_DEPLOYMENT"] = 'false' env["BUNDLE_DEPLOYMENT"] = 'false'
end end
output, status = Gitlab::Popen.popen([make_cmd, 'all', 'git'], nil, env) output, status = Gitlab::Popen.popen([make_cmd, 'clean-build', 'all', 'git'], nil, env)
raise "Gitaly failed to compile: #{output}" unless status&.zero? raise "Gitaly failed to compile: #{output}" unless status&.zero?
end end
end end

View File

@ -12731,6 +12731,9 @@ msgid_plural "Deploys"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "Deploy Key"
msgstr ""
msgid "Deploy Keys" msgid "Deploy Keys"
msgstr "" msgstr ""

View File

@ -98,7 +98,6 @@
"cache-loader": "^4.1.0", "cache-loader": "^4.1.0",
"canvas-confetti": "^1.4.0", "canvas-confetti": "^1.4.0",
"clipboard": "^2.0.8", "clipboard": "^2.0.8",
"codemirror": "^5.48.4",
"codesandbox-api": "0.0.23", "codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2", "compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1", "copy-webpack-plugin": "^6.4.1",

View File

@ -0,0 +1,19 @@
const DeletePipeline = {
success: {
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
},
request: {
method: 'POST',
path: '/api/graphql',
},
variables: {
id: 'gid://gitlab/Ci::Pipeline/316112',
},
};
export { DeletePipeline };

View File

@ -23,3 +23,24 @@ export async function getPipelineHeaderDataRequest(endpoint) {
data: graphqlQuery, data: graphqlQuery,
}); });
} }
export async function deletePipeline(endpoint) {
const { url } = endpoint;
const query = await extractGraphQLQuery(
'app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql',
);
const graphqlQuery = {
query,
variables: {
id: 'gid://gitlab/Ci::Pipeline/316112',
},
};
return axios({
baseURL: url,
url: '/api/graphql',
method: 'POST',
headers: { Accept: '*/*' },
data: graphqlQuery,
});
}

View File

@ -6,24 +6,27 @@ import { GraphQLInteraction } from '@pact-foundation/pact';
import { extractGraphQLQuery } from '../../../helpers/graphql_query_extractor'; import { extractGraphQLQuery } from '../../../helpers/graphql_query_extractor';
import { PipelineHeaderData } from '../../../fixtures/project/pipeline/get_pipeline_header_data.fixture'; import { PipelineHeaderData } from '../../../fixtures/project/pipeline/get_pipeline_header_data.fixture';
import { getPipelineHeaderDataRequest } from '../../../resources/graphql/pipelines'; import { DeletePipeline } from '../../../fixtures/project/pipeline/delete_pipeline.fixture';
import { getPipelineHeaderDataRequest, deletePipeline } from '../../../resources/graphql/pipelines';
const CONSUMER_NAME = 'Pipelines#show'; const CONSUMER_NAME = 'Pipelines#show';
const CONSUMER_LOG = '../logs/consumer.log'; const CONSUMER_LOG = '../logs/consumer.log';
const CONTRACT_DIR = '../contracts/project/pipeline/show'; const CONTRACT_DIR = '../contracts/project/pipeline/show';
const PROVIDER_NAME = 'GET pipeline header data'; const GET_PIPELINE_HEADER_DATA_PROVIDER_NAME = 'GET pipeline header data';
const DELETE_PIPELINE_PROVIDER_NAME = 'DELETE pipeline';
// GraphQL query: getPipelineHeaderData // GraphQL query: getPipelineHeaderData
pactWith( pactWith(
{ {
consumer: CONSUMER_NAME, consumer: CONSUMER_NAME,
provider: PROVIDER_NAME, provider: GET_PIPELINE_HEADER_DATA_PROVIDER_NAME,
log: CONSUMER_LOG, log: CONSUMER_LOG,
dir: CONTRACT_DIR, dir: CONTRACT_DIR,
}, },
(provider) => { (provider) => {
describe(PROVIDER_NAME, () => { describe(GET_PIPELINE_HEADER_DATA_PROVIDER_NAME, () => {
beforeEach(async () => { beforeEach(async () => {
const query = await extractGraphQLQuery( const query = await extractGraphQLQuery(
'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql', 'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql',
@ -50,4 +53,41 @@ pactWith(
}, },
); );
// GraphQL query: deletePipeline
pactWith(
{
consumer: CONSUMER_NAME,
provider: DELETE_PIPELINE_PROVIDER_NAME,
log: CONSUMER_LOG,
dir: CONTRACT_DIR,
},
(provider) => {
describe(DELETE_PIPELINE_PROVIDER_NAME, () => {
beforeEach(async () => {
const query = await extractGraphQLQuery(
'app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql',
);
const graphqlQuery = new GraphQLInteraction()
.given('a pipeline for a project exists')
.uponReceiving('a request to delete the pipeline')
.withQuery(query)
.withRequest(DeletePipeline.request)
.withVariables(DeletePipeline.variables)
.willRespondWith(DeletePipeline.success);
provider.addInteraction(graphqlQuery);
});
it('returns a successful body', async () => {
const deletePipelineResponse = await deletePipeline({
url: provider.mockService.baseUrl,
});
expect(deletePipelineResponse.status).toEqual(DeletePipeline.success.status);
});
});
},
);
/* eslint-enable @gitlab/require-i18n-strings */ /* eslint-enable @gitlab/require-i18n-strings */

View File

@ -0,0 +1,44 @@
{
"consumer": {
"name": "Pipelines#show"
},
"provider": {
"name": "DELETE pipeline"
},
"interactions": [
{
"description": "a request to delete the pipeline",
"providerState": "a pipeline for a project exists",
"request": {
"method": "POST",
"path": "/api/graphql",
"headers": {
"content-type": "application/json"
},
"body": {
"query": "mutation deletePipeline($id: CiPipelineID!) {\n pipelineDestroy(input: { id: $id }) {\n errors\n }\n}\n",
"variables": {
"id": "gid://gitlab/Ci::Pipeline/316112"
}
},
"matchingRules": {
"$.body.query": {
"match": "regex",
"regex": "mutation\\s*deletePipeline\\(\\$id:\\s*CiPipelineID!\\)\\s*\\{\\s*pipelineDestroy\\(input:\\s*\\{\\s*id:\\s*\\$id\\s*\\}\\)\\s*\\{\\s*errors\\s*\\}\\s*\\}\\s*"
}
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json; charset=utf-8"
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "2.0.0"
}
}
}

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
require_relative '../../../../spec_helper'
require_relative '../../../../states/project/pipeline/show_state'
module Provider
module DeletePipelineHelper
Pact.service_provider "DELETE pipeline" do
app { Environments::Test.app }
honours_pact_with 'Pipelines#show' do
pact_uri '../contracts/project/pipeline/show/pipelines#show-delete_pipeline.json'
end
end
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative '../../../spec_helper' require_relative '../../../../spec_helper'
require_relative '../../../states/project/pipeline/pipeline_state' require_relative '../../../../states/project/pipeline/pipeline_state'
module Provider module Provider
module GetPipelinesHeaderDataHelper module GetPipelinesHeaderDataHelper

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
Pact.provider_states_for "Pipelines#show" do
provider_state "a pipeline for a project exists" do
set_up do
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
namespace = create(:namespace, name: 'gitlab-org')
project = create(:project, :repository, name: 'gitlab-qa', namespace: namespace, creator: user)
scheduled_job = create(:ci_build, :scheduled)
manual_job = create(:ci_build, :manual)
project.add_maintainer(user)
create(
:ci_pipeline,
:with_job,
:success,
id: 316112,
iid: 1,
project: project,
user: user,
duration: 10,
finished_at: '2022-06-01T02:47:31.432Z',
builds: [scheduled_job, manual_job]
)
end
end
end

View File

@ -257,7 +257,12 @@ describe('Client side Markdown processing', () => {
expectedDoc: doc( expectedDoc: doc(
paragraph( paragraph(
source('<img src="bar" alt="foo" />'), source('<img src="bar" alt="foo" />'),
image({ ...source('<img src="bar" alt="foo" />'), alt: 'foo', src: 'bar' }), image({
...source('<img src="bar" alt="foo" />'),
alt: 'foo',
canonicalSrc: 'bar',
src: 'http://test.host/bar',
}),
), ),
), ),
}, },
@ -275,7 +280,12 @@ describe('Client side Markdown processing', () => {
), ),
paragraph( paragraph(
source('<img src="bar" alt="foo" />'), source('<img src="bar" alt="foo" />'),
image({ ...source('<img src="bar" alt="foo" />'), alt: 'foo', src: 'bar' }), image({
...source('<img src="bar" alt="foo" />'),
alt: 'foo',
src: 'http://test.host/bar',
canonicalSrc: 'bar',
}),
), ),
), ),
}, },
@ -287,7 +297,8 @@ describe('Client side Markdown processing', () => {
link( link(
{ {
...source('[GitLab](https://gitlab.com "Go to GitLab")'), ...source('[GitLab](https://gitlab.com "Go to GitLab")'),
href: 'https://gitlab.com', href: 'https://gitlab.com/',
canonicalSrc: 'https://gitlab.com',
title: 'Go to GitLab', title: 'Go to GitLab',
}, },
'GitLab', 'GitLab',
@ -305,7 +316,8 @@ describe('Client side Markdown processing', () => {
link( link(
{ {
...source('[GitLab](https://gitlab.com "Go to GitLab")'), ...source('[GitLab](https://gitlab.com "Go to GitLab")'),
href: 'https://gitlab.com', href: 'https://gitlab.com/',
canonicalSrc: 'https://gitlab.com',
title: 'Go to GitLab', title: 'Go to GitLab',
}, },
'GitLab', 'GitLab',
@ -322,7 +334,8 @@ describe('Client side Markdown processing', () => {
link( link(
{ {
...source('www.commonmark.org'), ...source('www.commonmark.org'),
href: 'http://www.commonmark.org', canonicalSrc: 'http://www.commonmark.org',
href: 'http://www.commonmark.org/',
}, },
'www.commonmark.org', 'www.commonmark.org',
), ),
@ -338,6 +351,7 @@ describe('Client side Markdown processing', () => {
link( link(
{ {
...source('www.commonmark.org/help'), ...source('www.commonmark.org/help'),
canonicalSrc: 'http://www.commonmark.org/help',
href: 'http://www.commonmark.org/help', href: 'http://www.commonmark.org/help',
}, },
'www.commonmark.org/help', 'www.commonmark.org/help',
@ -355,6 +369,7 @@ describe('Client side Markdown processing', () => {
link( link(
{ {
...source('hello+xyz@mail.example'), ...source('hello+xyz@mail.example'),
canonicalSrc: 'mailto:hello+xyz@mail.example',
href: 'mailto:hello+xyz@mail.example', href: 'mailto:hello+xyz@mail.example',
}, },
'hello+xyz@mail.example', 'hello+xyz@mail.example',
@ -373,7 +388,8 @@ describe('Client side Markdown processing', () => {
{ {
sourceMapKey: null, sourceMapKey: null,
sourceMarkdown: null, sourceMarkdown: null,
href: 'https://gitlab.com', canonicalSrc: 'https://gitlab.com',
href: 'https://gitlab.com/',
}, },
'https://gitlab.com', 'https://gitlab.com',
), ),
@ -402,6 +418,7 @@ hard line break`,
image({ image({
...source('![GitLab Logo](https://gitlab.com/logo.png "GitLab Logo")'), ...source('![GitLab Logo](https://gitlab.com/logo.png "GitLab Logo")'),
alt: 'GitLab Logo', alt: 'GitLab Logo',
canonicalSrc: 'https://gitlab.com/logo.png',
src: 'https://gitlab.com/logo.png', src: 'https://gitlab.com/logo.png',
title: 'GitLab Logo', title: 'GitLab Logo',
}), }),
@ -595,7 +612,12 @@ two
paragraph( paragraph(
source('List item with an image ![bar](foo.png)'), source('List item with an image ![bar](foo.png)'),
'List item with an image', 'List item with an image',
image({ ...source('![bar](foo.png)'), alt: 'bar', src: 'foo.png' }), image({
...source('![bar](foo.png)'),
alt: 'bar',
canonicalSrc: 'foo.png',
src: 'http://test.host/foo.png',
}),
), ),
), ),
), ),
@ -944,8 +966,17 @@ Paragraph
paragraph( paragraph(
source('[![moon](moon.jpg)](/uri)'), source('[![moon](moon.jpg)](/uri)'),
link( link(
{ ...source('[![moon](moon.jpg)](/uri)'), href: '/uri' }, {
image({ ...source('![moon](moon.jpg)'), src: 'moon.jpg', alt: 'moon' }), ...source('[![moon](moon.jpg)](/uri)'),
canonicalSrc: '/uri',
href: 'http://test.host/uri',
},
image({
...source('![moon](moon.jpg)'),
canonicalSrc: 'moon.jpg',
src: 'http://test.host/moon.jpg',
alt: 'moon',
}),
), ),
), ),
), ),
@ -975,12 +1006,26 @@ Paragraph
source('~[moon](moon.jpg) and [sun](sun.jpg)~'), source('~[moon](moon.jpg) and [sun](sun.jpg)~'),
strike( strike(
source('~[moon](moon.jpg) and [sun](sun.jpg)~'), source('~[moon](moon.jpg) and [sun](sun.jpg)~'),
link({ ...source('[moon](moon.jpg)'), href: 'moon.jpg' }, 'moon'), link(
{
...source('[moon](moon.jpg)'),
canonicalSrc: 'moon.jpg',
href: 'http://test.host/moon.jpg',
},
'moon',
),
), ),
strike(source('~[moon](moon.jpg) and [sun](sun.jpg)~'), ' and '), strike(source('~[moon](moon.jpg) and [sun](sun.jpg)~'), ' and '),
strike( strike(
source('~[moon](moon.jpg) and [sun](sun.jpg)~'), source('~[moon](moon.jpg) and [sun](sun.jpg)~'),
link({ ...source('[sun](sun.jpg)'), href: 'sun.jpg' }, 'sun'), link(
{
...source('[sun](sun.jpg)'),
href: 'http://test.host/sun.jpg',
canonicalSrc: 'sun.jpg',
},
'sun',
),
), ),
), ),
), ),
@ -1094,7 +1139,12 @@ _world_.
paragraph( paragraph(
source('[GitLab][gitlab-url]'), source('[GitLab][gitlab-url]'),
link( link(
{ ...source('[GitLab][gitlab-url]'), href: 'https://gitlab.com', title: 'GitLab' }, {
...source('[GitLab][gitlab-url]'),
href: 'https://gitlab.com/',
canonicalSrc: 'https://gitlab.com',
title: 'GitLab',
},
'GitLab', 'GitLab',
), ),
), ),

View File

@ -1213,42 +1213,47 @@ paragraph
}; };
it.each` it.each`
mark | markdown | modifiedMarkdown | editAction mark | markdown | modifiedMarkdown | editAction
${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction} ${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction} ${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
${'bold'} | ${'<strong>bold</strong>'} | ${'<strong>bold modified</strong>'} | ${defaultEditAction} ${'bold'} | ${'<strong>bold</strong>'} | ${'<strong>bold modified</strong>'} | ${defaultEditAction}
${'bold'} | ${'<b>bold</b>'} | ${'<b>bold modified</b>'} | ${defaultEditAction} ${'bold'} | ${'<b>bold</b>'} | ${'<b>bold modified</b>'} | ${defaultEditAction}
${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction} ${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction} ${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
${'italic'} | ${'<em>italic</em>'} | ${'<em>italic modified</em>'} | ${defaultEditAction} ${'italic'} | ${'<em>italic</em>'} | ${'<em>italic modified</em>'} | ${defaultEditAction}
${'italic'} | ${'<i>italic</i>'} | ${'<i>italic modified</i>'} | ${defaultEditAction} ${'italic'} | ${'<i>italic</i>'} | ${'<i>italic modified</i>'} | ${defaultEditAction}
${'link'} | ${'[gitlab](https://gitlab.com)'} | ${'[gitlab modified](https://gitlab.com)'} | ${defaultEditAction} ${'link'} | ${'[gitlab](https://gitlab.com)'} | ${'[gitlab modified](https://gitlab.com)'} | ${defaultEditAction}
${'link'} | ${'<a href="https://gitlab.com">link</a>'} | ${'<a href="https://gitlab.com">link modified</a>'} | ${defaultEditAction} ${'link'} | ${'<a href="https://gitlab.com">link</a>'} | ${'<a href="https://gitlab.com/">link modified</a>'} | ${defaultEditAction}
${'link'} | ${'link www.gitlab.com'} | ${'modified link www.gitlab.com'} | ${prependContentEditAction} ${'link'} | ${'link www.gitlab.com'} | ${'modified link www.gitlab.com'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com'} | ${'modified link https://www.gitlab.com'} | ${prependContentEditAction} ${'link'} | ${'link https://www.gitlab.com'} | ${'modified link https://www.gitlab.com'} | ${prependContentEditAction}
${'link'} | ${'link(https://www.gitlab.com)'} | ${'modified link(https://www.gitlab.com)'} | ${prependContentEditAction} ${'link'} | ${'link(https://www.gitlab.com)'} | ${'modified link(https://www.gitlab.com)'} | ${prependContentEditAction}
${'link'} | ${'link(engineering@gitlab.com)'} | ${'modified link(engineering@gitlab.com)'} | ${prependContentEditAction} ${'link'} | ${'link(engineering@gitlab.com)'} | ${'modified link(engineering@gitlab.com)'} | ${prependContentEditAction}
${'link'} | ${'link <https://www.gitlab.com>'} | ${'modified link <https://www.gitlab.com>'} | ${prependContentEditAction} ${'link'} | ${'link <https://www.gitlab.com>'} | ${'modified link <https://www.gitlab.com>'} | ${prependContentEditAction}
${'link'} | ${'link [https://www.gitlab.com>'} | ${'modified link \\[https://www.gitlab.com>'} | ${prependContentEditAction} ${'link'} | ${'link [https://www.gitlab.com>'} | ${'modified link \\[https://www.gitlab.com>'} | ${prependContentEditAction}
${'link'} | ${'link <https://www.gitlab.com'} | ${'modified link <https://www.gitlab.com'} | ${prependContentEditAction} ${'link'} | ${'link <https://www.gitlab.com'} | ${'modified link <https://www.gitlab.com'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com>'} | ${'modified link [https://www.gitlab.com>](https://www.gitlab.com%3E)'} | ${prependContentEditAction} ${'link'} | ${'link https://www.gitlab.com>'} | ${'modified link [https://www.gitlab.com>](https://www.gitlab.com%3E)'} | ${prependContentEditAction}
${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction} ${'link'} | ${'link https://www.gitlab.com/path'} | ${'modified link https://www.gitlab.com/path'} | ${prependContentEditAction}
${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction} ${'link'} | ${'link https://www.gitlab.com?query=search'} | ${'modified link https://www.gitlab.com?query=search'} | ${prependContentEditAction}
${'code'} | ${'<code>code</code>'} | ${'<code>code modified</code>'} | ${defaultEditAction} ${'link'} | ${'link https://www.gitlab.com/#fragment'} | ${'modified link https://www.gitlab.com/#fragment'} | ${prependContentEditAction}
${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction} ${'link'} | ${'link https://www.gitlab.com/?query=search'} | ${'modified link https://www.gitlab.com/?query=search'} | ${prependContentEditAction}
${'strike'} | ${'<del>striked</del>'} | ${'<del>striked modified</del>'} | ${defaultEditAction} ${'link'} | ${'link https://www.gitlab.com#fragment'} | ${'modified link https://www.gitlab.com#fragment'} | ${prependContentEditAction}
${'strike'} | ${'<strike>striked</strike>'} | ${'<strike>striked modified</strike>'} | ${defaultEditAction} ${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction}
${'strike'} | ${'<s>striked</s>'} | ${'<s>striked modified</s>'} | ${defaultEditAction} ${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction} ${'code'} | ${'<code>code</code>'} | ${'<code>code modified</code>'} | ${defaultEditAction}
${'list'} | ${'* list item'} | ${'* list item modified'} | ${defaultEditAction} ${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
${'list'} | ${'+ list item'} | ${'+ list item modified'} | ${defaultEditAction} ${'strike'} | ${'<del>striked</del>'} | ${'<del>striked modified</del>'} | ${defaultEditAction}
${'list'} | ${'- list item 1\n- list item 2'} | ${'- list item 1\n- list item 2 modified'} | ${defaultEditAction} ${'strike'} | ${'<strike>striked</strike>'} | ${'<strike>striked modified</strike>'} | ${defaultEditAction}
${'list'} | ${'2) list item'} | ${'2) list item modified'} | ${defaultEditAction} ${'strike'} | ${'<s>striked</s>'} | ${'<s>striked modified</s>'} | ${defaultEditAction}
${'list'} | ${'1. list item'} | ${'1. list item modified'} | ${defaultEditAction} ${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
${'taskList'} | ${'2) [ ] task list item'} | ${'2) [ ] task list item modified'} | ${defaultEditAction} ${'list'} | ${'* list item'} | ${'* list item modified'} | ${defaultEditAction}
${'taskList'} | ${'2) [x] task list item'} | ${'2) [x] task list item modified'} | ${defaultEditAction} ${'list'} | ${'+ list item'} | ${'+ list item modified'} | ${defaultEditAction}
${'list'} | ${'- list item 1\n- list item 2'} | ${'- list item 1\n- list item 2 modified'} | ${defaultEditAction}
${'list'} | ${'2) list item'} | ${'2) list item modified'} | ${defaultEditAction}
${'list'} | ${'1. list item'} | ${'1. list item modified'} | ${defaultEditAction}
${'taskList'} | ${'2) [ ] task list item'} | ${'2) [ ] task list item modified'} | ${defaultEditAction}
${'taskList'} | ${'2) [x] task list item'} | ${'2) [x] task list item modified'} | ${defaultEditAction}
`( `(
'preserves original $mark syntax when sourceMarkdown is available for $content', 'preserves original $mark syntax when sourceMarkdown is available for $markdown',
async ({ markdown, modifiedMarkdown, editAction }) => { async ({ markdown, modifiedMarkdown, editAction }) => {
const { document } = await remarkMarkdownDeserializer().deserialize({ const { document } = await remarkMarkdownDeserializer().deserialize({
schema: tiptapEditor.schema, schema: tiptapEditor.schema,

View File

@ -1062,4 +1062,28 @@ describe('URL utility', () => {
expect(urlUtils.PROMO_URL).toBe(url); expect(urlUtils.PROMO_URL).toBe(url);
}); });
}); });
describe('removeUrlProtocol', () => {
it.each`
input | output
${'http://gitlab.com'} | ${'gitlab.com'}
${'https://gitlab.com'} | ${'gitlab.com'}
${'foo:bar.com'} | ${'bar.com'}
${'gitlab.com'} | ${'gitlab.com'}
`('transforms $input to $output', ({ input, output }) => {
expect(urlUtils.removeUrlProtocol(input)).toBe(output);
});
});
describe('removeLastSlashInUrlPath', () => {
it.each`
input | output
${'https://www.gitlab.com/path/'} | ${'https://www.gitlab.com/path'}
${'https://www.gitlab.com/?query=search'} | ${'https://www.gitlab.com?query=search'}
${'https://www.gitlab.com/#fragment'} | ${'https://www.gitlab.com#fragment'}
${'https://www.gitlab.com/hello'} | ${'https://www.gitlab.com/hello'}
`('transforms $input to $output', ({ input, output }) => {
expect(urlUtils.removeLastSlashInUrlPath(input)).toBe(output);
});
});
}); });

View File

@ -64,7 +64,7 @@ RSpec.describe Mutations::MergeRequests::SetLabels do
end end
context 'when passing operation_mode as REMOVE' do context 'when passing operation_mode as REMOVE' do
subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, label_ids: label_ids, operation_mode: Types::MutationOperationModeEnum.enum[:remove])} subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, label_ids: label_ids, operation_mode: Types::MutationOperationModeEnum.enum[:remove]) }
it 'removes the labels, without removing others' do it 'removes the labels, without removing others' do
merge_request.update!(labels: [label, label2]) merge_request.update!(labels: [label, label2])

View File

@ -11,9 +11,9 @@ RSpec.describe Mutations::Releases::Create do
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
let(:tag) { 'v1.1.0'} let(:tag) { 'v1.1.0' }
let(:ref) { 'master'} let(:ref) { 'master' }
let(:name) { 'Version 1.0'} let(:name) { 'Version 1.0' }
let(:description) { 'The first release :rocket:' } let(:description) { 'The first release :rocket:' }
let(:released_at) { Time.parse('2018-12-10') } let(:released_at) { Time.parse('2018-12-10') }
let(:milestones) { [milestone_12_3.title, milestone_12_4.title] } let(:milestones) { [milestone_12_3.title, milestone_12_4.title] }

View File

@ -8,7 +8,7 @@ RSpec.describe Mutations::Releases::Delete do
let_it_be(:reporter) { create(:user) } let_it_be(:reporter) { create(:user) }
let_it_be(:developer) { create(:user) } let_it_be(:developer) { create(:user) }
let_it_be(:maintainer) { create(:user) } let_it_be(:maintainer) { create(:user) }
let_it_be(:tag) { 'v1.1.0'} let_it_be(:tag) { 'v1.1.0' }
let_it_be(:release) { create(:release, project: project, tag: tag) } let_it_be(:release) { create(:release, project: project, tag: tag) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }

View File

@ -9,8 +9,8 @@ RSpec.describe Mutations::Releases::Update do
let_it_be(:reporter) { create(:user) } let_it_be(:reporter) { create(:user) }
let_it_be(:developer) { create(:user) } let_it_be(:developer) { create(:user) }
let_it_be(:tag) { 'v1.1.0'} let_it_be(:tag) { 'v1.1.0' }
let_it_be(:name) { 'Version 1.0'} let_it_be(:name) { 'Version 1.0' }
let_it_be(:description) { 'The first release :rocket:' } let_it_be(:description) { 'The first release :rocket:' }
let_it_be(:released_at) { Time.parse('2018-12-10').utc } let_it_be(:released_at) { Time.parse('2018-12-10').utc }
let_it_be(:created_at) { Time.parse('2018-11-05').utc } let_it_be(:created_at) { Time.parse('2018-11-05').utc }

View File

@ -12,7 +12,7 @@ RSpec.describe Resolvers::Ci::RunnerJobsResolver do
let!(:build_one) { create(:ci_build, :success, name: 'Build One', runner: runner, pipeline: pipeline) } let!(:build_one) { create(:ci_build, :success, name: 'Build One', runner: runner, pipeline: pipeline) }
let!(:build_two) { create(:ci_build, :success, name: 'Build Two', runner: runner, pipeline: pipeline) } let!(:build_two) { create(:ci_build, :success, name: 'Build Two', runner: runner, pipeline: pipeline) }
let!(:build_three) { create(:ci_build, :failed, name: 'Build Three', runner: runner, pipeline: pipeline) } let!(:build_three) { create(:ci_build, :failed, name: 'Build Three', runner: runner, pipeline: pipeline) }
let!(:irrelevant_build) { create(:ci_build, name: 'Irrelevant Build', pipeline: irrelevant_pipeline)} let!(:irrelevant_build) { create(:ci_build, name: 'Irrelevant Build', pipeline: irrelevant_pipeline) }
let(:args) { {} } let(:args) { {} }
let(:runner) { create(:ci_runner, :project, projects: [project]) } let(:runner) { create(:ci_runner, :project, projects: [project]) }

View File

@ -17,7 +17,7 @@ RSpec.describe Resolvers::GroupMembers::NotificationEmailResolver do
expect(described_class).to have_nullable_graphql_type(GraphQL::Types::String) expect(described_class).to have_nullable_graphql_type(GraphQL::Types::String)
end end
subject { batch_sync { resolve_notification_email(developer.group_members.first, current_user) }} subject { batch_sync { resolve_notification_email(developer.group_members.first, current_user) } }
context 'when current_user is admin' do context 'when current_user is admin' do
let(:current_user) { create(:user, :admin) } let(:current_user) { create(:user, :admin) }

View File

@ -14,7 +14,7 @@ RSpec.describe Resolvers::ProjectJobsResolver do
let_it_be(:failed_build) { create(:ci_build, :failed, name: 'Build Three', pipeline: pipeline) } let_it_be(:failed_build) { create(:ci_build, :failed, name: 'Build Three', pipeline: pipeline) }
let_it_be(:pending_build) { create(:ci_build, :pending, name: 'Build Three', pipeline: pipeline) } let_it_be(:pending_build) { create(:ci_build, :pending, name: 'Build Three', pipeline: pipeline) }
let(:irrelevant_build) { create(:ci_build, name: 'Irrelevant Build', pipeline: irrelevant_pipeline)} let(:irrelevant_build) { create(:ci_build, name: 'Irrelevant Build', pipeline: irrelevant_pipeline) }
let(:args) { {} } let(:args) { {} }
let(:current_user) { create(:user) } let(:current_user) { create(:user) }

View File

@ -7,7 +7,7 @@ RSpec.describe Resolvers::Projects::GrafanaIntegrationResolver do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let_it_be(:grafana_integration) { create(:grafana_integration, project: project)} let_it_be(:grafana_integration) { create(:grafana_integration, project: project) }
describe '#resolve' do describe '#resolve' do
context 'when object is not a project' do context 'when object is not a project' do
@ -19,7 +19,7 @@ RSpec.describe Resolvers::Projects::GrafanaIntegrationResolver do
end end
context 'when object is nil' do context 'when object is nil' do
it { expect(resolve_integration(obj: nil)).to eq nil} it { expect(resolve_integration(obj: nil)).to eq nil }
end end
end end

View File

@ -142,7 +142,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no sort is provided' do context 'when no sort is provided' do
it 'returns projects in descending order by id' do it 'returns projects in descending order by id' do
is_expected.to match_array((visible_projecs + named_projects).sort_by { |p| p[:id]}.reverse ) is_expected.to match_array((visible_projecs + named_projects).sort_by { |p| p[:id] }.reverse )
end end
end end
end end

View File

@ -34,7 +34,7 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json } subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
let(:projects_field) { subject.dig('data', 'project', 'ciJobTokenScope', 'projects', 'nodes') } let(:projects_field) { subject.dig('data', 'project', 'ciJobTokenScope', 'projects', 'nodes') }
let(:returned_project_paths) { projects_field.map { |project| project['path']} } let(:returned_project_paths) { projects_field.map { |project| project['path'] } }
context 'with access to scope' do context 'with access to scope' do
before do before do

View File

@ -167,7 +167,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
shared_examples_for 'does not include private notes' do shared_examples_for 'does not include private notes' do
it "does not return private notes" do it "does not return private notes" do
notes = subject.dig("data", "project", "issue", "notes", 'edges') notes = subject.dig("data", "project", "issue", "notes", 'edges')
notes_body = notes.map {|n| n.dig('node', 'body')} notes_body = notes.map { |n| n.dig('node', 'body') }
expect(notes.size).to eq 1 expect(notes.size).to eq 1
expect(notes_body).not_to include(private_note_body) expect(notes_body).not_to include(private_note_body)
@ -178,7 +178,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
shared_examples_for 'includes private notes' do shared_examples_for 'includes private notes' do
it "returns all notes" do it "returns all notes" do
notes = subject.dig("data", "project", "issue", "notes", 'edges') notes = subject.dig("data", "project", "issue", "notes", 'edges')
notes_body = notes.map {|n| n.dig('node', 'body')} notes_body = notes.map { |n| n.dig('node', 'body') }
expect(notes.size).to eq 2 expect(notes.size).to eq 2
expect(notes_body).to include(private_note_body) expect(notes_body).to include(private_note_body)
@ -209,7 +209,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
end end
describe 'hidden', :enable_admin_mode do describe 'hidden', :enable_admin_mode do
let_it_be(:admin) { create(:user, :admin)} let_it_be(:admin) { create(:user, :admin) }
let_it_be(:banned_user) { create(:user, :banned) } let_it_be(:banned_user) { create(:user, :banned) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) } let_it_be(:project) { create(:project, :public) }

View File

@ -49,7 +49,7 @@ RSpec.describe GitlabSchema.types['User'] do
end end
describe 'name field' do describe 'name field' do
let_it_be(:admin) { create(:user, :admin)} let_it_be(:admin) { create(:user, :admin) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:requested_user) { create(:user, name: 'John Smith') } let_it_be(:requested_user) { create(:user, name: 'John Smith') }
let_it_be(:requested_project_bot) { create(:user, :project_bot, name: 'Project bot') } let_it_be(:requested_project_bot) { create(:user, :project_bot, name: 'Project bot') }

View File

@ -83,6 +83,36 @@ RSpec.describe API::Support::GitAccessActor do
end end
end end
describe '#deploy_key_or_user' do
it 'returns a deploy key when the params contains deploy key' do
key = create(:deploy_key)
params = { key_id: key.id }
expect(described_class.from_params(params).deploy_key_or_user).to eq(key)
end
it 'returns a user when the params contains personal key' do
key = create(:key)
params = { key_id: key.id }
expect(described_class.from_params(params).deploy_key_or_user).to eq(key.user)
end
it 'returns a user when the params contains user id' do
user = create(:user)
params = { user_id: user.id }
expect(described_class.from_params(params).deploy_key_or_user).to eq(user)
end
it 'returns a user when the params contains user name' do
user = create(:user)
params = { username: user.username }
expect(described_class.from_params(params).deploy_key_or_user).to eq(user)
end
end
describe '#username' do describe '#username' do
context 'when initialized with a User' do context 'when initialized with a User' do
let(:user) { build(:user) } let(:user) { build(:user) }

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Audit::DeployKeyAuthor do
describe '#initialize' do
it 'sets correct attributes' do
expect(described_class.new(name: 'Lorem deploy key'))
.to have_attributes(id: -3, name: 'Lorem deploy key')
end
it 'sets default name when it is not provided' do
expect(described_class.new)
.to have_attributes(id: -3, name: 'Deploy Key')
end
end
end

View File

@ -57,6 +57,15 @@ RSpec.describe Gitlab::Audit::NullAuthor do
expect(subject.for(-2, audit_event)).to be_a(Gitlab::Audit::DeployTokenAuthor) expect(subject.for(-2, audit_event)).to be_a(Gitlab::Audit::DeployTokenAuthor)
expect(subject.for(-2, audit_event)).to have_attributes(id: -2, name: 'Test deploy token') expect(subject.for(-2, audit_event)).to have_attributes(id: -2, name: 'Test deploy token')
end end
it 'returns DeployKeyAuthor when id equals -3', :aggregate_failures do
allow(audit_event).to receive(:[]).with(:author_name).and_return('Test deploy key')
allow(audit_event).to receive(:details).and_return({})
allow(audit_event).to receive(:target_type)
expect(subject.for(-3, audit_event)).to be_a(Gitlab::Audit::DeployKeyAuthor)
expect(subject.for(-3, audit_event)).to have_attributes(id: -3, name: 'Test deploy key')
end
end end
describe '#current_sign_in_ip' do describe '#current_sign_in_ip' do

View File

@ -5245,25 +5245,8 @@ RSpec.describe User do
end end
it 'returns number of open merge requests from non-archived projects' do it 'returns number of open merge requests from non-archived projects' do
expect(Rails.cache).not_to receive(:fetch)
expect(user.attention_requested_open_merge_requests_count(force: true)).to eq 1 expect(user.attention_requested_open_merge_requests_count(force: true)).to eq 1
end end
context 'when uncached_mr_attention_requests_count is disabled' do
before do
stub_feature_flags(uncached_mr_attention_requests_count: false)
end
it 'fetches from cache' do
expect(Rails.cache).to receive(:fetch).with(
user.attention_request_cache_key,
force: false,
expires_in: described_class::COUNT_CACHE_VALIDITY_PERIOD
).and_call_original
expect(user.attention_requested_open_merge_requests_count).to eq 1
end
end
end end
describe '#assigned_open_issues_count' do describe '#assigned_open_issues_count' do

View File

@ -61,7 +61,7 @@ RSpec.describe API::Boards do
delete api(url, user) delete api(url, user)
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end.to change {board_parent.boards.count}.by(-1) end.to change { board_parent.boards.count }.by(-1)
end end
end end

View File

@ -201,7 +201,7 @@ RSpec.describe API::Branches do
context 'when sort value is not supported' do context 'when sort value is not supported' do
it_behaves_like '400 response' do it_behaves_like '400 response' do
let(:request) { get api(route, user), params: { sort: 'unknown' }} let(:request) { get api(route, user), params: { sort: 'unknown' } }
end end
end end
end end

View File

@ -158,7 +158,7 @@ RSpec.describe API::Ci::Jobs do
context 'with basic auth header' do context 'with basic auth header' do
let(:personal_access_token) { create(:personal_access_token, user: user) } let(:personal_access_token) { create(:personal_access_token, user: user) }
let(:token) { personal_access_token.token} let(:token) { personal_access_token.token }
include_context 'with auth headers' do include_context 'with auth headers' do
let(:header) { { Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER => token } } let(:header) { { Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER => token } }

View File

@ -29,7 +29,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
describe 'POST /api/v4/jobs/request' do describe 'POST /api/v4/jobs/request' do
let!(:last_update) {} let!(:last_update) {}
let!(:new_update) { } let!(:new_update) {}
let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' } let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' }
before do before do

View File

@ -61,7 +61,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks do
end end
context 'when job has been updated recently' do context 'when job has been updated recently' do
it { expect { patch_the_trace }.not_to change { job.updated_at }} it { expect { patch_the_trace }.not_to change { job.updated_at } }
it "changes the job's trace" do it "changes the job's trace" do
patch_the_trace patch_the_trace
@ -70,7 +70,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks do
end end
context 'when Runner makes a force-patch' do context 'when Runner makes a force-patch' do
it { expect { force_patch_the_trace }.not_to change { job.updated_at }} it { expect { force_patch_the_trace }.not_to change { job.updated_at } }
it "doesn't change the build.trace" do it "doesn't change the build.trace" do
force_patch_the_trace force_patch_the_trace

View File

@ -59,7 +59,7 @@ RSpec.describe API::Ci::SecureFiles do
expect do expect do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.not_to change {project.secure_files.count} end.not_to change { project.secure_files.count }
expect(response).to have_gitlab_http_status(:service_unavailable) expect(response).to have_gitlab_http_status(:service_unavailable)
end end
@ -78,7 +78,7 @@ RSpec.describe API::Ci::SecureFiles do
it 'returns a 201 when uploading a file when the ci_secure_files_read_only feature flag is disabled' do it 'returns a 201 when uploading a file when the ci_secure_files_read_only feature flag is disabled' do
expect do expect do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.to change {project.secure_files.count}.by(1) end.to change { project.secure_files.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
end end
@ -249,7 +249,7 @@ RSpec.describe API::Ci::SecureFiles do
it 'creates a secure file' do it 'creates a secure file' do
expect do expect do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.to change {project.secure_files.count}.by(1) end.to change { project.secure_files.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response['name']).to eq('upload-keystore.jks') expect(json_response['name']).to eq('upload-keystore.jks')

View File

@ -136,8 +136,8 @@ RSpec.describe API::Ci::Triggers do
end end
context 'when triggered from another running job' do context 'when triggered from another running job' do
let!(:trigger) { } let!(:trigger) {}
let!(:trigger_request) { } let!(:trigger_request) {}
context 'when other job is triggered by a user' do context 'when other job is triggered by a user' do
let(:trigger_token) { create(:ci_build, :running, project: project, user: user).token } let(:trigger_token) { create(:ci_build, :running, project: project, user: user).token }
@ -242,7 +242,7 @@ RSpec.describe API::Ci::Triggers do
expect do expect do
post api("/projects/#{project.id}/triggers", user), post api("/projects/#{project.id}/triggers", user),
params: { description: 'trigger' } params: { description: 'trigger' }
end.to change {project.triggers.count}.by(1) end.to change { project.triggers.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response).to include('description' => 'trigger') expect(json_response).to include('description' => 'trigger')
@ -335,7 +335,7 @@ RSpec.describe API::Ci::Triggers do
delete api("/projects/#{project.id}/triggers/#{trigger.id}", user) delete api("/projects/#{project.id}/triggers/#{trigger.id}", user)
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end.to change {project.triggers.count}.by(-1) end.to change { project.triggers.count }.by(-1)
end end
it 'responds with 404 Not Found if requesting non-existing trigger' do it 'responds with 404 Not Found if requesting non-existing trigger' do

View File

@ -116,7 +116,7 @@ RSpec.describe API::Ci::Variables do
it 'creates variable' do it 'creates variable' do
expect do expect do
post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true } post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true }
end.to change {project.variables.count}.by(1) end.to change { project.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['key']).to eq('TEST_VARIABLE_2')
@ -129,7 +129,7 @@ RSpec.describe API::Ci::Variables do
it 'creates variable with optional attributes' do it 'creates variable with optional attributes' do
expect do expect do
post api("/projects/#{project.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' } post api("/projects/#{project.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
end.to change {project.variables.count}.by(1) end.to change { project.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['key']).to eq('TEST_VARIABLE_2')
@ -142,7 +142,7 @@ RSpec.describe API::Ci::Variables do
it 'does not allow to duplicate variable key' do it 'does not allow to duplicate variable key' do
expect do expect do
post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' } post api("/projects/#{project.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
end.to change {project.variables.count}.by(0) end.to change { project.variables.count }.by(0)
expect(response).to have_gitlab_http_status(:bad_request) expect(response).to have_gitlab_http_status(:bad_request)
end end
@ -268,7 +268,7 @@ RSpec.describe API::Ci::Variables do
delete api("/projects/#{project.id}/variables/#{variable.key}", user) delete api("/projects/#{project.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end.to change {project.variables.count}.by(-1) end.to change { project.variables.count }.by(-1)
end end
it 'responds with 404 Not Found if requesting non-existing variable' do it 'responds with 404 Not Found if requesting non-existing variable' do
@ -295,7 +295,7 @@ RSpec.describe API::Ci::Variables do
delete api("/projects/#{project.id}/variables/key1", user), params: { 'filter[environment_scope]': 'production' } delete api("/projects/#{project.id}/variables/key1", user), params: { 'filter[environment_scope]': 'production' }
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end.to change {project.variables.count}.by(-1) end.to change { project.variables.count }.by(-1)
expect(var1.reload).to be_present expect(var1.reload).to be_present
expect { var2.reload }.to raise_error(ActiveRecord::RecordNotFound) expect { var2.reload }.to raise_error(ActiveRecord::RecordNotFound)

View File

@ -101,7 +101,7 @@ RSpec.describe API::Clusters::Agents do
expect do expect do
post(api("/projects/#{project.id}/cluster_agents", user), post(api("/projects/#{project.id}/cluster_agents", user),
params: { name: 'some-agent' }) params: { name: 'some-agent' })
end.to change {project.cluster_agents.count}.by(1) end.to change { project.cluster_agents.count }.by(1)
aggregate_failures "testing response" do aggregate_failures "testing response" do
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
@ -139,7 +139,7 @@ RSpec.describe API::Clusters::Agents do
delete api("/projects/#{project.id}/cluster_agents/#{agent.id}", user) delete api("/projects/#{project.id}/cluster_agents/#{agent.id}", user)
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end.to change {project.cluster_agents.count}.by(-1) end.to change { project.cluster_agents.count }.by(-1)
end end
it 'returns a 404 error when deleting non existent agent' do it 'returns a 404 error when deleting non existent agent' do

View File

@ -988,8 +988,8 @@ RSpec.describe API::Commits do
it 'returns all refs with no scope' do it 'returns all refs with no scope' do
get api(route, current_user), params: { per_page: 100 } get api(route, current_user), params: { per_page: 100 }
refs = project.repository.branch_names_contains(commit_id).map {|name| ['branch', name]} refs = project.repository.branch_names_contains(commit_id).map { |name| ['branch', name] }
refs.concat(project.repository.tag_names_contains(commit_id).map {|name| ['tag', name]}) refs.concat(project.repository.tag_names_contains(commit_id).map { |name| ['tag', name] })
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_limited_pagination_headers expect(response).to include_limited_pagination_headers
@ -1000,8 +1000,8 @@ RSpec.describe API::Commits do
it 'returns all refs' do it 'returns all refs' do
get api(route, current_user), params: { type: 'all', per_page: 100 } get api(route, current_user), params: { type: 'all', per_page: 100 }
refs = project.repository.branch_names_contains(commit_id).map {|name| ['branch', name]} refs = project.repository.branch_names_contains(commit_id).map { |name| ['branch', name] }
refs.concat(project.repository.tag_names_contains(commit_id).map {|name| ['tag', name]}) refs.concat(project.repository.tag_names_contains(commit_id).map { |name| ['tag', name] })
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs) expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs)
@ -1010,7 +1010,7 @@ RSpec.describe API::Commits do
it 'returns the branch refs' do it 'returns the branch refs' do
get api(route, current_user), params: { type: 'branch', per_page: 100 } get api(route, current_user), params: { type: 'branch', per_page: 100 }
refs = project.repository.branch_names_contains(commit_id).map {|name| ['branch', name]} refs = project.repository.branch_names_contains(commit_id).map { |name| ['branch', name] }
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs) expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs)
@ -1019,7 +1019,7 @@ RSpec.describe API::Commits do
it 'returns the tag refs' do it 'returns the tag refs' do
get api(route, current_user), params: { type: 'tag', per_page: 100 } get api(route, current_user), params: { type: 'tag', per_page: 100 }
refs = project.repository.tag_names_contains(commit_id).map {|name| ['tag', name]} refs = project.repository.tag_names_contains(commit_id).map { |name| ['tag', name] }
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs) expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs)
@ -2036,7 +2036,7 @@ RSpec.describe API::Commits do
context 'unsigned commit' do context 'unsigned commit' do
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get api(route, current_user) } let(:request) { get api(route, current_user) }
let(:message) { '404 Signature Not Found'} let(:message) { '404 Signature Not Found' }
end end
end end

View File

@ -94,7 +94,7 @@ RSpec.describe API::ConanInstancePackages do
end end
describe 'DELETE /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel' do describe 'DELETE /api/v4/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel' do
subject { delete api("/packages/conan/v1/conans/#{recipe_path}"), headers: headers} subject { delete api("/packages/conan/v1/conans/#{recipe_path}"), headers: headers }
it_behaves_like 'delete package endpoint' it_behaves_like 'delete package endpoint'
end end

View File

@ -93,7 +93,7 @@ RSpec.describe API::ConanProjectPackages do
end end
describe 'DELETE /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel' do describe 'DELETE /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel' do
subject { delete api("/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}"), headers: headers} subject { delete api("/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}"), headers: headers }
it_behaves_like 'delete package endpoint' it_behaves_like 'delete package endpoint'
end end

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::DependencyProxy, api: true do RSpec.describe API::DependencyProxy, api: true do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:blob) { create(:dependency_proxy_blob )} let_it_be(:blob) { create(:dependency_proxy_blob ) }
let_it_be(:group, reload: true) { blob.group } let_it_be(:group, reload: true) { blob.group }
before do before do

View File

@ -451,7 +451,7 @@ RSpec.describe API::Deployments do
describe 'DELETE /projects/:id/deployments/:deployment_id' do describe 'DELETE /projects/:id/deployments/:deployment_id' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let(:commits) { project.repository.commits(nil, { limit: 2 })} let(:commits) { project.repository.commits(nil, { limit: 2 }) }
let!(:deploy) do let!(:deploy) do
create( create(
:deployment, :deployment,

View File

@ -318,7 +318,7 @@ RSpec.describe API::GoProxy do
context 'with a case sensitive project and versions' do context 'with a case sensitive project and versions' do
let_it_be(:project) { create :project_empty_repo, :public, creator: user, path: 'MyGoLib' } let_it_be(:project) { create :project_empty_repo, :public, creator: user, path: 'MyGoLib' }
let_it_be(:base) { "#{Settings.build_gitlab_go_url}/#{project.full_path}" } let_it_be(:base) { "#{Settings.build_gitlab_go_url}/#{project.full_path}" }
let_it_be(:base_encoded) { base.gsub(/[A-Z]/) { |s| "!#{s.downcase}"} } let_it_be(:base_encoded) { base.gsub(/[A-Z]/) { |s| "!#{s.downcase}" } }
let_it_be(:modules) do let_it_be(:modules) do
create(:go_module_commit, :files, project: project, files: { 'README.md' => "Hi" }) create(:go_module_commit, :files, project: project, files: { 'README.md' => "Hi" })

View File

@ -15,7 +15,7 @@ RSpec.describe 'get board lists' do
let_it_be(:group_label2) { create(:group_label, group: group, name: 'Testing') } let_it_be(:group_label2) { create(:group_label, group: group, name: 'Testing') }
let(:params) { '' } let(:params) { '' }
let(:board) { } let(:board) {}
let(:confidential) { false } let(:confidential) { false }
let(:board_parent_type) { board_parent.class.to_s.downcase } let(:board_parent_type) { board_parent.class.to_s.downcase }
let(:board_data) { graphql_data[board_parent_type]['boards']['nodes'][0] } let(:board_data) { graphql_data[board_parent_type]['boards']['nodes'][0] }

View File

@ -15,7 +15,7 @@ RSpec.describe 'get board lists' do
let_it_be(:group_label2) { create(:group_label, group: group, name: 'Testing') } let_it_be(:group_label2) { create(:group_label, group: group, name: 'Testing') }
let(:params) { '' } let(:params) { '' }
let(:board) { } let(:board) {}
let(:board_parent_type) { board_parent.class.to_s.downcase } let(:board_parent_type) { board_parent.class.to_s.downcase }
let(:board_data) { graphql_data[board_parent_type]['boards']['edges'].first['node'] } let(:board_data) { graphql_data[board_parent_type]['boards']['edges'].first['node'] }
let(:lists_data) { board_data['lists']['edges'] } let(:lists_data) { board_data['lists']['edges'] }

View File

@ -74,7 +74,7 @@ RSpec.describe 'Adding an AwardEmoji' do
end end
describe 'marking Todos as done' do describe 'marking Todos as done' do
let(:user) { current_user} let(:user) { current_user }
subject { post_graphql_mutation(mutation, current_user: user) } subject { post_graphql_mutation(mutation, current_user: user) }

View File

@ -84,7 +84,7 @@ RSpec.describe 'Toggling an AwardEmoji' do
end end
describe 'marking Todos as done' do describe 'marking Todos as done' do
let(:user) { current_user} let(:user) { current_user }
subject { post_graphql_mutation(mutation, current_user: user) } subject { post_graphql_mutation(mutation, current_user: user) }

View File

@ -16,10 +16,10 @@ RSpec.describe 'Creation of a new release' do
let(:mutation_name) { :release_create } let(:mutation_name) { :release_create }
let(:tag_name) { 'v7.12.5'} let(:tag_name) { 'v7.12.5' }
let(:tag_message) { nil } let(:tag_message) { nil }
let(:ref) { 'master'} let(:ref) { 'master' }
let(:name) { 'Version 7.12.5'} let(:name) { 'Version 7.12.5' }
let(:description) { 'Release 7.12.5 :rocket:' } let(:description) { 'Release 7.12.5 :rocket:' }
let(:released_at) { '2018-12-10' } let(:released_at) { '2018-12-10' }
let(:milestones) { [milestone_12_3.title, milestone_12_4.title] } let(:milestones) { [milestone_12_3.title, milestone_12_4.title] }

View File

@ -15,7 +15,7 @@ RSpec.describe 'Updating an existing release' do
let_it_be(:milestone_12_4) { create(:milestone, project: project, title: '12.4') } let_it_be(:milestone_12_4) { create(:milestone, project: project, title: '12.4') }
let_it_be(:tag_name) { 'v1.1.0' } let_it_be(:tag_name) { 'v1.1.0' }
let_it_be(:name) { 'Version 7.12.5'} let_it_be(:name) { 'Version 7.12.5' }
let_it_be(:description) { 'Release 7.12.5 :rocket:' } let_it_be(:description) { 'Release 7.12.5 :rocket:' }
let_it_be(:released_at) { '2018-12-10' } let_it_be(:released_at) { '2018-12-10' }
let_it_be(:created_at) { '2018-11-05' } let_it_be(:created_at) { '2018-11-05' }

View File

@ -12,8 +12,8 @@ RSpec.describe 'Creating a Snippet' do
let(:title) { 'Initial title' } let(:title) { 'Initial title' }
let(:visibility_level) { 'public' } let(:visibility_level) { 'public' }
let(:action) { :create } let(:action) { :create }
let(:file_1) { { filePath: 'example_file1', content: 'This is the example file 1' }} let(:file_1) { { filePath: 'example_file1', content: 'This is the example file 1' } }
let(:file_2) { { filePath: 'example_file2', content: 'This is the example file 2' }} let(:file_2) { { filePath: 'example_file2', content: 'This is the example file 2' } }
let(:actions) { [{ action: action }.merge(file_1), { action: action }.merge(file_2)] } let(:actions) { [{ action: action }.merge(file_1), { action: action }.merge(file_2)] }
let(:project_path) { nil } let(:project_path) { nil }
let(:uploaded_files) { nil } let(:uploaded_files) { nil }
@ -149,7 +149,7 @@ RSpec.describe 'Creating a Snippet' do
end end
context 'when there non ActiveRecord errors' do context 'when there non ActiveRecord errors' do
let(:file_1) { { filePath: 'invalid://file/path', content: 'foobar' }} let(:file_1) { { filePath: 'invalid://file/path', content: 'foobar' } }
it_behaves_like 'a mutation that returns errors in the response', errors: ['Repository Error creating the snippet - Invalid file name'] it_behaves_like 'a mutation that returns errors in the response', errors: ['Repository Error creating the snippet - Invalid file name']
it_behaves_like 'does not create snippet' it_behaves_like 'does not create snippet'

View File

@ -7,7 +7,7 @@ RSpec.describe 'Delete a timelog' do
let_it_be(:author) { create(:user) } let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :public) } let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800) }
let(:current_user) { nil } let(:current_user) { nil }
let(:mutation) { graphql_mutation(:timelogDelete, { 'id' => timelog.to_global_id.to_s }) } let(:mutation) { graphql_mutation(:timelogDelete, { 'id' => timelog.to_global_id.to_s }) }

View File

@ -129,7 +129,7 @@ RSpec.describe 'Create a work item' do
end end
context 'when parent work item is not found' do context 'when parent work item is not found' do
let_it_be(:parent) { build_stubbed(:work_item, id: non_existing_record_id)} let_it_be(:parent) { build_stubbed(:work_item, id: non_existing_record_id) }
it 'returns a top level error' do it 'returns a top level error' do
post_graphql_mutation(mutation, current_user: current_user) post_graphql_mutation(mutation, current_user: current_user)

View File

@ -103,7 +103,7 @@ RSpec.describe 'Update a work item' do
let(:input) { { 'confidential' => true } } let(:input) { { 'confidential' => true } }
it_behaves_like 'toggling confidentiality' do it_behaves_like 'toggling confidentiality' do
let(:values) { { old: false, new: true }} let(:values) { { old: false, new: true } }
end end
end end
@ -115,7 +115,7 @@ RSpec.describe 'Update a work item' do
end end
it_behaves_like 'toggling confidentiality' do it_behaves_like 'toggling confidentiality' do
let(:values) { { old: true, new: false }} let(:values) { { old: true, new: false } }
end end
end end
end end

View File

@ -49,7 +49,7 @@ RSpec.describe 'rendering namespace statistics' do
it_behaves_like 'a working namespace with storage statistics query' it_behaves_like 'a working namespace with storage statistics query'
context 'when the namespace is public' do context 'when the namespace is public' do
let(:group) { create(:group, :public)} let(:group) { create(:group, :public) }
it 'hides statistics for unauthenticated requests' do it 'hides statistics for unauthenticated requests' do
post_graphql(query, current_user: nil) post_graphql(query, current_user: nil)

View File

@ -8,7 +8,7 @@ RSpec.describe 'conan package details' do
let_it_be(:package) { create(:conan_package, project: project) } let_it_be(:package) { create(:conan_package, project: project) }
let(:metadata) { query_graphql_fragment('ConanMetadata') } let(:metadata) { query_graphql_fragment('ConanMetadata') }
let(:package_files_metadata) {query_graphql_fragment('ConanFileMetadata')} let(:package_files_metadata) { query_graphql_fragment('ConanFileMetadata') }
let(:query) do let(:query) do
graphql_query_for(:package, { id: package_global_id }, <<~FIELDS) graphql_query_for(:package, { id: package_global_id }, <<~FIELDS)

View File

@ -7,7 +7,7 @@ RSpec.describe 'helm package details' do
let_it_be(:package) { create(:helm_package, project: project) } let_it_be(:package) { create(:helm_package, project: project) }
let(:package_files_metadata) {query_graphql_fragment('HelmFileMetadata')} let(:package_files_metadata) { query_graphql_fragment('HelmFileMetadata') }
let(:query) do let(:query) do
graphql_query_for(:package, { id: package_global_id }, <<~FIELDS) graphql_query_for(:package, { id: package_global_id }, <<~FIELDS)

View File

@ -18,7 +18,7 @@ RSpec.describe 'package details' do
let(:depth) { 3 } let(:depth) { 3 }
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] } let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
let(:metadata) { query_graphql_fragment('ComposerMetadata') } let(:metadata) { query_graphql_fragment('ComposerMetadata') }
let(:package_files) {all_graphql_fields_for('PackageFile')} let(:package_files) { all_graphql_fields_for('PackageFile') }
let(:package_global_id) { global_id_of(composer_package) } let(:package_global_id) { global_id_of(composer_package) }
let(:package_details) { graphql_data_at(:package) } let(:package_details) { graphql_data_at(:package) }

View File

@ -26,7 +26,7 @@ RSpec.describe 'query Jira service' do
) )
end end
let(:services) { graphql_data.dig('project', 'services', 'nodes')} let(:services) { graphql_data.dig('project', 'services', 'nodes') }
it_behaves_like 'unauthorized users cannot read services' it_behaves_like 'unauthorized users cannot read services'

View File

@ -56,8 +56,8 @@ RSpec.describe 'query Jira import data' do
) )
end end
let(:jira_imports) { graphql_data.dig('project', 'jiraImports', 'nodes')} let(:jira_imports) { graphql_data.dig('project', 'jiraImports', 'nodes') }
let(:jira_import_status) { graphql_data.dig('project', 'jiraImportStatus')} let(:jira_import_status) { graphql_data.dig('project', 'jiraImportStatus') }
context 'when user cannot read Jira import data' do context 'when user cannot read Jira import data' do
before do before do
@ -89,11 +89,11 @@ RSpec.describe 'query Jira import data' do
context 'list of jira imports sorted ascending by scheduledAt time' do context 'list of jira imports sorted ascending by scheduledAt time' do
it 'retuns list of jira imports' do it 'retuns list of jira imports' do
jira_proket_keys = jira_imports.map {|ji| ji['jiraProjectKey']} jira_proket_keys = jira_imports.map { |ji| ji['jiraProjectKey'] }
usernames = jira_imports.map {|ji| ji.dig('scheduledBy', 'username')} usernames = jira_imports.map { |ji| ji.dig('scheduledBy', 'username') }
imported_issues_count = jira_imports.map {|ji| ji.dig('importedIssuesCount')} imported_issues_count = jira_imports.map { |ji| ji.dig('importedIssuesCount') }
failed_issues_count = jira_imports.map {|ji| ji.dig('failedToImportCount')} failed_issues_count = jira_imports.map { |ji| ji.dig('failedToImportCount') }
total_issue_count = jira_imports.map {|ji| ji.dig('totalIssueCount')} total_issue_count = jira_imports.map { |ji| ji.dig('totalIssueCount') }
expect(jira_imports.size).to eq 2 expect(jira_imports.size).to eq 2
expect(jira_proket_keys).to eq %w(BB AA) expect(jira_proket_keys).to eq %w(BB AA)

View File

@ -91,7 +91,7 @@ RSpec.describe API::GroupVariables do
it 'creates variable' do it 'creates variable' do
expect do expect do
post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true } post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true }
end.to change {group.variables.count}.by(1) end.to change { group.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['key']).to eq('TEST_VARIABLE_2')
@ -105,7 +105,7 @@ RSpec.describe API::GroupVariables do
it 'creates variable with optional attributes' do it 'creates variable with optional attributes' do
expect do expect do
post api("/groups/#{group.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' } post api("/groups/#{group.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
end.to change {group.variables.count}.by(1) end.to change { group.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['key']).to eq('TEST_VARIABLE_2')
@ -119,7 +119,7 @@ RSpec.describe API::GroupVariables do
it 'does not allow to duplicate variable key' do it 'does not allow to duplicate variable key' do
expect do expect do
post api("/groups/#{group.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' } post api("/groups/#{group.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
end.to change {group.variables.count}.by(0) end.to change { group.variables.count }.by(0)
expect(response).to have_gitlab_http_status(:bad_request) expect(response).to have_gitlab_http_status(:bad_request)
end end
@ -207,7 +207,7 @@ RSpec.describe API::GroupVariables do
delete api("/groups/#{group.id}/variables/#{variable.key}", user) delete api("/groups/#{group.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end.to change {group.variables.count}.by(-1) end.to change { group.variables.count }.by(-1)
end end
it 'responds with 404 Not Found if requesting non-existing variable' do it 'responds with 404 Not Found if requesting non-existing variable' do

View File

@ -864,7 +864,7 @@ RSpec.describe API::Groups do
end end
describe 'PUT /groups/:id' do describe 'PUT /groups/:id' do
let(:new_group_name) { 'New Group'} let(:new_group_name) { 'New Group' }
let(:file_path) { 'spec/fixtures/dk.png' } let(:file_path) { 'spec/fixtures/dk.png' }
it_behaves_like 'group avatar upload' do it_behaves_like 'group avatar upload' do

View File

@ -26,8 +26,8 @@ RSpec.describe API::Helpers do
} }
end end
let(:header) { } let(:header) {}
let(:request) { Grape::Request.new(env)} let(:request) { Grape::Request.new(env) }
let(:params) { request.params } let(:params) { request.params }
before do before do

View File

@ -1451,7 +1451,7 @@ RSpec.describe API::Internal::Base do
describe 'POST /internal/two_factor_otp_check' do describe 'POST /internal/two_factor_otp_check' do
let(:key_id) { key.id } let(:key_id) { key.id }
let(:otp) { '123456'} let(:otp) { '123456' }
subject do subject do
post api('/internal/two_factor_otp_check'), post api('/internal/two_factor_otp_check'),
@ -1472,7 +1472,7 @@ RSpec.describe API::Internal::Base do
describe 'POST /internal/two_factor_manual_otp_check' do describe 'POST /internal/two_factor_manual_otp_check' do
let(:key_id) { key.id } let(:key_id) { key.id }
let(:otp) { '123456'} let(:otp) { '123456' }
subject do subject do
post api('/internal/two_factor_manual_otp_check'), post api('/internal/two_factor_manual_otp_check'),
@ -1493,7 +1493,7 @@ RSpec.describe API::Internal::Base do
describe 'POST /internal/two_factor_push_otp_check' do describe 'POST /internal/two_factor_push_otp_check' do
let(:key_id) { key.id } let(:key_id) { key.id }
let(:otp) { '123456'} let(:otp) { '123456' }
subject do subject do
post api('/internal/two_factor_push_otp_check'), post api('/internal/two_factor_push_otp_check'),
@ -1514,7 +1514,7 @@ RSpec.describe API::Internal::Base do
describe 'POST /internal/two_factor_manual_otp_check' do describe 'POST /internal/two_factor_manual_otp_check' do
let(:key_id) { key.id } let(:key_id) { key.id }
let(:otp) { '123456'} let(:otp) { '123456' }
subject do subject do
post api('/internal/two_factor_manual_otp_check'), post api('/internal/two_factor_manual_otp_check'),
@ -1534,7 +1534,7 @@ RSpec.describe API::Internal::Base do
describe 'POST /internal/two_factor_push_otp_check' do describe 'POST /internal/two_factor_push_otp_check' do
let(:key_id) { key.id } let(:key_id) { key.id }
let(:otp) { '123456'} let(:otp) { '123456' }
subject do subject do
post api('/internal/two_factor_push_otp_check'), post api('/internal/two_factor_push_otp_check'),

View File

@ -131,7 +131,7 @@ RSpec.describe API::Markdown do
end end
context 'when not logged in' do context 'when not logged in' do
let(:user) { } let(:user) {}
it_behaves_like 'user without proper access' it_behaves_like 'user without proper access'
end end
@ -176,7 +176,7 @@ RSpec.describe API::Markdown do
end end
context 'when not logged in' do context 'when not logged in' do
let(:user) { } let(:user) {}
it_behaves_like 'user without proper access' it_behaves_like 'user without proper access'
end end

View File

@ -34,7 +34,7 @@ RSpec.describe API::MavenPackages do
end end
let(:version) { '1.0-SNAPSHOT' } let(:version) { '1.0-SNAPSHOT' }
let(:param_path) { "#{package_name}/#{version}"} let(:param_path) { "#{package_name}/#{version}" }
before do before do
project.add_developer(user) project.add_developer(user)

View File

@ -187,8 +187,8 @@ RSpec.describe API::Members do
end end
context 'with a subgroup' do context 'with a subgroup' do
let(:group) { create(:group, :private)} let(:group) { create(:group, :private) }
let(:subgroup) { create(:group, :private, parent: group)} let(:subgroup) { create(:group, :private, parent: group) }
let(:project) { create(:project, group: subgroup) } let(:project) { create(:project, group: subgroup) }
before do before do

View File

@ -10,7 +10,7 @@ RSpec.describe API::Metrics::Dashboard::Annotations do
let(:dashboard) { 'config/prometheus/common_metrics.yml' } let(:dashboard) { 'config/prometheus/common_metrics.yml' }
let(:starting_at) { Time.now.iso8601 } let(:starting_at) { Time.now.iso8601 }
let(:ending_at) { 1.hour.from_now.iso8601 } let(:ending_at) { 1.hour.from_now.iso8601 }
let(:params) { attributes_for(:metrics_dashboard_annotation, environment: environment, starting_at: starting_at, ending_at: ending_at, dashboard_path: dashboard)} let(:params) { attributes_for(:metrics_dashboard_annotation, environment: environment, starting_at: starting_at, ending_at: ending_at, dashboard_path: dashboard) }
shared_examples 'POST /:source_type/:id/metrics_dashboard/annotations' do |source_type| shared_examples 'POST /:source_type/:id/metrics_dashboard/annotations' do |source_type|
let(:url) { "/#{source_type.pluralize}/#{source.id}/metrics_dashboard/annotations" } let(:url) { "/#{source_type.pluralize}/#{source.id}/metrics_dashboard/annotations" }

View File

@ -111,7 +111,7 @@ RSpec.describe API::Notes do
system: false system: false
end end
let(:test_url) {"/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes"} let(:test_url) { "/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes" }
shared_examples 'a notes request' do shared_examples 'a notes request' do
it 'is a note array response' do it 'is a note array response' do

View File

@ -307,8 +307,8 @@ RSpec.describe API::NpmProjectPackages do
expect { upload_package_with_token } expect { upload_package_with_token }
.to change { project.packages.count }.by(1) .to change { project.packages.count }.by(1)
.and change { Packages::PackageFile.count }.by(1) .and change { Packages::PackageFile.count }.by(1)
.and change { Packages::Dependency.count}.by(4) .and change { Packages::Dependency.count }.by(4)
.and change { Packages::DependencyLink.count}.by(6) .and change { Packages::DependencyLink.count }.by(6)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
@ -323,8 +323,8 @@ RSpec.describe API::NpmProjectPackages do
expect { upload_package_with_token } expect { upload_package_with_token }
.to change { project.packages.count }.by(1) .to change { project.packages.count }.by(1)
.and change { Packages::PackageFile.count }.by(1) .and change { Packages::PackageFile.count }.by(1)
.and not_change { Packages::Dependency.count} .and not_change { Packages::Dependency.count }
.and change { Packages::DependencyLink.count}.by(6) .and change { Packages::DependencyLink.count }.by(6)
end end
end end
end end

View File

@ -73,7 +73,7 @@ RSpec.describe API::NugetGroupPackages do
let(:include_prereleases) { true } let(:include_prereleases) { true }
let(:query_parameters) { { q: search_term, take: take, skip: skip, prerelease: include_prereleases }.compact } let(:query_parameters) { { q: search_term, take: take, skip: skip, prerelease: include_prereleases }.compact }
subject { get api(url), headers: {}} subject { get api(url), headers: {} }
shared_examples 'handling mixed visibilities' do shared_examples 'handling mixed visibilities' do
where(:group_visibility, :subgroup_visibility, :expected_status) do where(:group_visibility, :subgroup_visibility, :expected_status) do

View File

@ -19,7 +19,7 @@ RSpec.describe API::Pages do
end end
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { delete api("/projects/#{project.id}/pages", admin)} let(:request) { delete api("/projects/#{project.id}/pages", admin) }
end end
end end

View File

@ -19,8 +19,8 @@ RSpec.describe API::PagesDomains do
end end
let(:pages_domain_secure_params) { build(:pages_domain, domain: 'ssl.other-domain.test', project: project).slice(:domain, :certificate, :key) } let(:pages_domain_secure_params) { build(:pages_domain, domain: 'ssl.other-domain.test', project: project).slice(:domain, :certificate, :key) }
let(:pages_domain_secure_key_missmatch_params) {build(:pages_domain, :with_trusted_chain, project: project).slice(:domain, :certificate, :key) } let(:pages_domain_secure_key_missmatch_params) { build(:pages_domain, :with_trusted_chain, project: project).slice(:domain, :certificate, :key) }
let(:pages_domain_secure_missing_chain_params) {build(:pages_domain, :with_missing_chain, project: project).slice(:certificate) } let(:pages_domain_secure_missing_chain_params) { build(:pages_domain, :with_missing_chain, project: project).slice(:certificate) }
let(:route) { "/projects/#{project.id}/pages/domains" } let(:route) { "/projects/#{project.id}/pages/domains" }
let(:route_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain.domain}" } let(:route_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain.domain}" }

View File

@ -34,7 +34,7 @@ RSpec.describe API::PersonalAccessTokens do
context 'logged in as a non-Administrator' do context 'logged in as a non-Administrator' do
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:token) { create(:personal_access_token, user: current_user)} let_it_be(:token) { create(:personal_access_token, user: current_user) }
let_it_be(:other_token) { create(:personal_access_token, user: user) } let_it_be(:other_token) { create(:personal_access_token, user: user) }
let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: current_user) } let_it_be(:token_impersonated) { create(:personal_access_token, impersonation: true, user: current_user) }

View File

@ -77,7 +77,7 @@ RSpec.describe API::ProjectTemplates do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list') expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response.map {|t| t['key']}).to match_array(%w(bug feature_proposal template_test)) expect(json_response.map { |t| t['key'] }).to match_array(%w(bug feature_proposal template_test))
end end
it 'returns merge request templates' do it 'returns merge request templates' do
@ -86,7 +86,7 @@ RSpec.describe API::ProjectTemplates do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list') expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response.map {|t| t['key']}).to match_array(%w(bug feature_proposal template_test)) expect(json_response.map { |t| t['key'] }).to match_array(%w(bug feature_proposal template_test))
end end
it 'returns 400 for an unknown template type' do it 'returns 400 for an unknown template type' do

View File

@ -1093,7 +1093,7 @@ RSpec.describe API::Projects do
it 'does not create new project and respond with 403' do it 'does not create new project and respond with 403' do
allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0) allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
expect { post api('/projects', user2), params: { name: 'foo' } } expect { post api('/projects', user2), params: { name: 'foo' } }
.to change {Project.count}.by(0) .to change { Project.count }.by(0)
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
end end
end end

View File

@ -41,7 +41,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'deploy token for package GET requests' it_behaves_like 'deploy token for package GET requests'
context 'with group path as id' do context 'with group path as id' do
let(:url) { "/groups/#{CGI.escape(group.full_path)}/-/packages/pypi/simple"} let(:url) { "/groups/#{CGI.escape(group.full_path)}/-/packages/pypi/simple" }
it_behaves_like 'deploy token for package GET requests' it_behaves_like 'deploy token for package GET requests'
end end
@ -102,7 +102,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'deploy token for package GET requests' it_behaves_like 'deploy token for package GET requests'
context 'with group path as id' do context 'with group path as id' do
let(:url) { "/groups/#{CGI.escape(group.full_path)}/-/packages/pypi/simple/#{package_name}"} let(:url) { "/groups/#{CGI.escape(group.full_path)}/-/packages/pypi/simple/#{package_name}" }
it_behaves_like 'deploy token for package GET requests' it_behaves_like 'deploy token for package GET requests'
end end

View File

@ -66,7 +66,7 @@ RSpec.describe API::Release::Links do
end end
context 'when release does not exist' do context 'when release does not exist' do
let!(:release) { } let!(:release) {}
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer) } let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", maintainer) }
@ -98,7 +98,7 @@ RSpec.describe API::Release::Links do
end end
context 'when the release does not exists' do context 'when the release does not exists' do
let!(:release) { } let!(:release) {}
it_behaves_like '403 response' do it_behaves_like '403 response' do
let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member) } let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member) }
@ -409,7 +409,7 @@ RSpec.describe API::Release::Links do
end end
context 'when there are no corresponding release link' do context 'when there are no corresponding release link' do
let!(:release_link) { } let!(:release_link) {}
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) do let(:request) do
@ -510,7 +510,7 @@ RSpec.describe API::Release::Links do
end end
context 'when there are no corresponding release link' do context 'when there are no corresponding release link' do
let!(:release_link) { } let!(:release_link) {}
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) do let(:request) do

View File

@ -962,7 +962,7 @@ RSpec.describe API::Releases do
context 'with milestones' do context 'with milestones' do
let(:subject) { post api("/projects/#{project.id}/releases", maintainer), params: params } let(:subject) { post api("/projects/#{project.id}/releases", maintainer), params: params }
let(:milestone) { create(:milestone, project: project, title: 'v1.0') } let(:milestone) { create(:milestone, project: project, title: 'v1.0') }
let(:returned_milestones) { json_response['milestones'].map {|m| m['title']} } let(:returned_milestones) { json_response['milestones'].map { |m| m['title'] } }
before do before do
params.merge!(milestone_params) params.merge!(milestone_params)
@ -1120,7 +1120,7 @@ RSpec.describe API::Releases do
end end
context 'when there are no corresponding releases' do context 'when there are no corresponding releases' do
let!(:release) { } let!(:release) {}
it 'forbids the request' do it 'forbids the request' do
put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
@ -1158,7 +1158,7 @@ RSpec.describe API::Releases do
end end
context 'with milestones' do context 'with milestones' do
let(:returned_milestones) { json_response['milestones'].map {|m| m['title']} } let(:returned_milestones) { json_response['milestones'].map { |m| m['title'] } }
subject { put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params } subject { put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params }
@ -1310,7 +1310,7 @@ RSpec.describe API::Releases do
end end
context 'when there are no corresponding releases' do context 'when there are no corresponding releases' do
let!(:release) { } let!(:release) {}
it 'forbids the request' do it 'forbids the request' do
delete api("/projects/#{project.id}/releases/v0.1", maintainer) delete api("/projects/#{project.id}/releases/v0.1", maintainer)

View File

@ -28,7 +28,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly( expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
public_snippet.id, public_snippet.id,
internal_snippet.id, internal_snippet.id,
private_snippet.id) private_snippet.id)
@ -75,7 +75,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
it 'returns snippets available for user in given time range' do it 'returns snippets available for user in given time range' do
get api(path, personal_access_token: user_token) get api(path, personal_access_token: user_token)
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly( expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
private_snippet_in_time_range1.id, private_snippet_in_time_range1.id,
private_snippet_in_time_range2.id) private_snippet_in_time_range2.id)
end end
@ -99,10 +99,10 @@ RSpec.describe API::Snippets, factory_default: :keep do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly( expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
public_snippet.id, public_snippet.id,
public_snippet_other.id) public_snippet_other.id)
expect(json_response.map { |snippet| snippet['web_url']} ).to contain_exactly( expect(json_response.map { |snippet| snippet['web_url'] } ).to contain_exactly(
"http://localhost/-/snippets/#{public_snippet.id}", "http://localhost/-/snippets/#{public_snippet.id}",
"http://localhost/-/snippets/#{public_snippet_other.id}") "http://localhost/-/snippets/#{public_snippet_other.id}")
expect(json_response[0]['files'].first).to eq snippet_blob_file(public_snippet_other.blobs.first) expect(json_response[0]['files'].first).to eq snippet_blob_file(public_snippet_other.blobs.first)
@ -126,7 +126,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
it 'returns public snippets available to user in given time range' do it 'returns public snippets available to user in given time range' do
get api(path, personal_access_token: user_token) get api(path, personal_access_token: user_token)
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly( expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
public_snippet_in_time_range.id) public_snippet_in_time_range.id)
end end
end end

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