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

View File

@ -125,6 +125,7 @@ const factorySpecs = {
selector: 'img',
getAttrs: (hastNode) => ({
src: hastNode.properties.src,
canonicalSrc: hastNode.properties.src,
title: hastNode.properties.title,
alt: hastNode.properties.alt,
}),
@ -154,6 +155,7 @@ const factorySpecs = {
type: 'mark',
selector: 'a',
getAttrs: (hastNode) => ({
canonicalSrc: hastNode.properties.href,
href: hastNode.properties.href,
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 () => {
return {
deserialize: async ({ schema, markdown }) => {
@ -193,6 +220,7 @@ export default () => {
factorySpecs,
tree,
wrappableTags,
attributeTransformer,
markdown,
}),
skipRendering: ['footnoteReference', 'footnoteDefinition', 'code', 'definition'],

View File

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

View File

@ -669,3 +669,27 @@ export function constructWebIDEPath({
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
end
# This is used for the internal logic of AuditEvents::BuildService.
def impersonated?
false
end
end

View File

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

View File

@ -1809,12 +1809,8 @@ class User < ApplicationRecord
end
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
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

View File

@ -1,8 +1,8 @@
---
name: uncached_mr_attention_requests_count
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84145
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/357480
milestone: '14.10'
name: audit_event_streaming_git_operations_deploy_key_event
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93160
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368765
milestone: '15.3'
type: development
group: group::code review
group: group::release
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.
> - [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.
> - [Added `details.author_class` field](https://gitlab.com/gitlab-org/gitlab/-/issues/363876) in GitLab 15.3.
FLAG:
On self-managed GitLab, by default this feature is available. To hide the
@ -377,6 +378,7 @@ Fetch:
"entity_type": "Project",
"details": {
"author_name": "Administrator",
"author_class": "User",
"target_id": 29,
"target_type": "Project",
"target_details": "example-project",
@ -408,6 +410,7 @@ Push:
"entity_type": "Project",
"details": {
"author_name": "Administrator",
"author_class": "User",
"target_id": 29,
"target_type": "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
Fetch:
@ -441,6 +480,7 @@ Fetch:
"entity_type": "Project",
"details": {
"author_name": "Administrator",
"author_class": "User",
"target_id": 29,
"target_type": "Project",
"target_details": "example-project",
@ -472,6 +512,7 @@ Push:
"entity_type": "Project",
"details": {
"author_name": "Administrator",
"author_class": "User",
"target_id": 29,
"target_type": "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
Fetch:
@ -506,6 +581,7 @@ Fetch:
"details": {
"custom_message": "Repository Download Started",
"author_name": "example_username",
"author_class": "User",
"target_id": 29,
"target_type": "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
[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
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 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
- [Group wikis](../project/wiki/index.md)

View File

@ -380,6 +380,17 @@ To disable group mentions:
1. Select **Disable group mentions**.
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
> [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
end
def deploy_key_or_user
key.instance_of?(DeployKey) ? key : user
end
def username
user&.username
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)
elsif id == -2
Gitlab::Audit::DeployTokenAuthor.new(name: name)
elsif id == -3
Gitlab::Audit::DeployKeyAuthor.new(name: name)
else
Gitlab::Audit::DeletedAuthor.new(id: id, name: name)
end

View File

@ -20,13 +20,24 @@ namespace :contracts do
Pact::VerificationTask.new(:get_pipeline_header_data) do |pact|
pact.uri(
"#{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
desc 'Run all pipeline contract tests'
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
rescue StandardError, SystemExit
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'
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?
end
end

View File

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

View File

@ -98,7 +98,6 @@
"cache-loader": "^4.1.0",
"canvas-confetti": "^1.4.0",
"clipboard": "^2.0.8",
"codemirror": "^5.48.4",
"codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2",
"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,
});
}
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 { 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_LOG = '../logs/consumer.log';
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
pactWith(
{
consumer: CONSUMER_NAME,
provider: PROVIDER_NAME,
provider: GET_PIPELINE_HEADER_DATA_PROVIDER_NAME,
log: CONSUMER_LOG,
dir: CONTRACT_DIR,
},
(provider) => {
describe(PROVIDER_NAME, () => {
describe(GET_PIPELINE_HEADER_DATA_PROVIDER_NAME, () => {
beforeEach(async () => {
const query = await extractGraphQLQuery(
'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 */

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
require_relative '../../../spec_helper'
require_relative '../../../states/project/pipeline/pipeline_state'
require_relative '../../../../spec_helper'
require_relative '../../../../states/project/pipeline/pipeline_state'
module Provider
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(
paragraph(
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(
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(
{
...source('[GitLab](https://gitlab.com "Go to GitLab")'),
href: 'https://gitlab.com',
href: 'https://gitlab.com/',
canonicalSrc: 'https://gitlab.com',
title: 'Go to GitLab',
},
'GitLab',
@ -305,7 +316,8 @@ describe('Client side Markdown processing', () => {
link(
{
...source('[GitLab](https://gitlab.com "Go to GitLab")'),
href: 'https://gitlab.com',
href: 'https://gitlab.com/',
canonicalSrc: 'https://gitlab.com',
title: 'Go to GitLab',
},
'GitLab',
@ -322,7 +334,8 @@ describe('Client side Markdown processing', () => {
link(
{
...source('www.commonmark.org'),
href: 'http://www.commonmark.org',
canonicalSrc: 'http://www.commonmark.org',
href: 'http://www.commonmark.org/',
},
'www.commonmark.org',
),
@ -338,6 +351,7 @@ describe('Client side Markdown processing', () => {
link(
{
...source('www.commonmark.org/help'),
canonicalSrc: 'http://www.commonmark.org/help',
href: 'http://www.commonmark.org/help',
},
'www.commonmark.org/help',
@ -355,6 +369,7 @@ describe('Client side Markdown processing', () => {
link(
{
...source('hello+xyz@mail.example'),
canonicalSrc: 'mailto:hello+xyz@mail.example',
href: 'mailto:hello+xyz@mail.example',
},
'hello+xyz@mail.example',
@ -373,7 +388,8 @@ describe('Client side Markdown processing', () => {
{
sourceMapKey: null,
sourceMarkdown: null,
href: 'https://gitlab.com',
canonicalSrc: 'https://gitlab.com',
href: 'https://gitlab.com/',
},
'https://gitlab.com',
),
@ -402,6 +418,7 @@ hard line break`,
image({
...source('![GitLab Logo](https://gitlab.com/logo.png "GitLab Logo")'),
alt: 'GitLab Logo',
canonicalSrc: 'https://gitlab.com/logo.png',
src: 'https://gitlab.com/logo.png',
title: 'GitLab Logo',
}),
@ -595,7 +612,12 @@ two
paragraph(
source('List item with an image ![bar](foo.png)'),
'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(
source('[![moon](moon.jpg)](/uri)'),
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)~'),
strike(
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)~'),
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(
source('[GitLab][gitlab-url]'),
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',
),
),

View File

@ -1213,42 +1213,47 @@ paragraph
};
it.each`
mark | markdown | modifiedMarkdown | editAction
${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
${'bold'} | ${'<strong>bold</strong>'} | ${'<strong>bold modified</strong>'} | ${defaultEditAction}
${'bold'} | ${'<b>bold</b>'} | ${'<b>bold modified</b>'} | ${defaultEditAction}
${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
${'italic'} | ${'<em>italic</em>'} | ${'<em>italic modified</em>'} | ${defaultEditAction}
${'italic'} | ${'<i>italic</i>'} | ${'<i>italic modified</i>'} | ${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'} | ${'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(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>](https://www.gitlab.com%3E)'} | ${prependContentEditAction}
${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction}
${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
${'code'} | ${'<code>code</code>'} | ${'<code>code modified</code>'} | ${defaultEditAction}
${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
${'strike'} | ${'<del>striked</del>'} | ${'<del>striked modified</del>'} | ${defaultEditAction}
${'strike'} | ${'<strike>striked</strike>'} | ${'<strike>striked modified</strike>'} | ${defaultEditAction}
${'strike'} | ${'<s>striked</s>'} | ${'<s>striked modified</s>'} | ${defaultEditAction}
${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
${'list'} | ${'* list item'} | ${'* 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}
mark | markdown | modifiedMarkdown | editAction
${'bold'} | ${'**bold**'} | ${'**bold modified**'} | ${defaultEditAction}
${'bold'} | ${'__bold__'} | ${'__bold modified__'} | ${defaultEditAction}
${'bold'} | ${'<strong>bold</strong>'} | ${'<strong>bold modified</strong>'} | ${defaultEditAction}
${'bold'} | ${'<b>bold</b>'} | ${'<b>bold modified</b>'} | ${defaultEditAction}
${'italic'} | ${'_italic_'} | ${'_italic modified_'} | ${defaultEditAction}
${'italic'} | ${'*italic*'} | ${'*italic modified*'} | ${defaultEditAction}
${'italic'} | ${'<em>italic</em>'} | ${'<em>italic modified</em>'} | ${defaultEditAction}
${'italic'} | ${'<i>italic</i>'} | ${'<i>italic modified</i>'} | ${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'} | ${'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(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>](https://www.gitlab.com%3E)'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com/path'} | ${'modified link https://www.gitlab.com/path'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com?query=search'} | ${'modified link https://www.gitlab.com?query=search'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com/#fragment'} | ${'modified link https://www.gitlab.com/#fragment'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com/?query=search'} | ${'modified link https://www.gitlab.com/?query=search'} | ${prependContentEditAction}
${'link'} | ${'link https://www.gitlab.com#fragment'} | ${'modified link https://www.gitlab.com#fragment'} | ${prependContentEditAction}
${'link'} | ${'link **https://www.gitlab.com]**'} | ${'modified link [**https://www.gitlab.com\\]**](https://www.gitlab.com%5D)'} | ${prependContentEditAction}
${'code'} | ${'`code`'} | ${'`code modified`'} | ${defaultEditAction}
${'code'} | ${'<code>code</code>'} | ${'<code>code modified</code>'} | ${defaultEditAction}
${'strike'} | ${'~~striked~~'} | ${'~~striked modified~~'} | ${defaultEditAction}
${'strike'} | ${'<del>striked</del>'} | ${'<del>striked modified</del>'} | ${defaultEditAction}
${'strike'} | ${'<strike>striked</strike>'} | ${'<strike>striked modified</strike>'} | ${defaultEditAction}
${'strike'} | ${'<s>striked</s>'} | ${'<s>striked modified</s>'} | ${defaultEditAction}
${'list'} | ${'- list item'} | ${'- list item modified'} | ${defaultEditAction}
${'list'} | ${'* list item'} | ${'* 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 }) => {
const { document } = await remarkMarkdownDeserializer().deserialize({
schema: tiptapEditor.schema,

View File

@ -1062,4 +1062,28 @@ describe('URL utility', () => {
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
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
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(:tag) { 'v1.1.0'}
let(:ref) { 'master'}
let(:name) { 'Version 1.0'}
let(:tag) { 'v1.1.0' }
let(:ref) { 'master' }
let(:name) { 'Version 1.0' }
let(:description) { 'The first release :rocket:' }
let(:released_at) { Time.parse('2018-12-10') }
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(:developer) { 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(: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(:developer) { create(:user) }
let_it_be(:tag) { 'v1.1.0'}
let_it_be(:name) { 'Version 1.0'}
let_it_be(:tag) { 'v1.1.0' }
let_it_be(:name) { 'Version 1.0' }
let_it_be(:description) { 'The first release :rocket:' }
let_it_be(:released_at) { Time.parse('2018-12-10').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_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!(: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(: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)
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
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(: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(: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(: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
context 'when object is not a project' do
@ -19,7 +19,7 @@ RSpec.describe Resolvers::Projects::GrafanaIntegrationResolver do
end
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

View File

@ -142,7 +142,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no sort is provided' 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

View File

@ -34,7 +34,7 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
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
before do

View File

@ -167,7 +167,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
shared_examples_for 'does not include private notes' do
it "does not return private notes" do
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_body).not_to include(private_note_body)
@ -178,7 +178,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
shared_examples_for 'includes private notes' do
it "returns all notes" do
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_body).to include(private_note_body)
@ -209,7 +209,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
end
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(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }

View File

@ -49,7 +49,7 @@ RSpec.describe GitlabSchema.types['User'] do
end
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(:requested_user) { create(:user, name: 'John Smith') }
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
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
context 'when initialized with a User' do
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 have_attributes(id: -2, name: 'Test deploy token')
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
describe '#current_sign_in_ip' do

View File

@ -5245,25 +5245,8 @@ RSpec.describe User do
end
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
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
describe '#assigned_open_issues_count' do

View File

@ -61,7 +61,7 @@ RSpec.describe API::Boards do
delete api(url, user)
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

View File

@ -201,7 +201,7 @@ RSpec.describe API::Branches do
context 'when sort value is not supported' 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

View File

@ -158,7 +158,7 @@ RSpec.describe API::Ci::Jobs do
context 'with basic auth header' do
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
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
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)' }
before do

View File

@ -61,7 +61,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks do
end
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
patch_the_trace
@ -70,7 +70,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks do
end
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
force_patch_the_trace

View File

@ -59,7 +59,7 @@ RSpec.describe API::Ci::SecureFiles do
expect do
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)
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
expect do
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)
end
@ -249,7 +249,7 @@ RSpec.describe API::Ci::SecureFiles do
it 'creates a secure file' do
expect do
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(json_response['name']).to eq('upload-keystore.jks')

View File

@ -136,8 +136,8 @@ RSpec.describe API::Ci::Triggers do
end
context 'when triggered from another running job' do
let!(:trigger) { }
let!(:trigger_request) { }
let!(:trigger) {}
let!(:trigger_request) {}
context 'when other job is triggered by a user' do
let(:trigger_token) { create(:ci_build, :running, project: project, user: user).token }
@ -242,7 +242,7 @@ RSpec.describe API::Ci::Triggers do
expect do
post api("/projects/#{project.id}/triggers", user),
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(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)
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
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
expect do
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(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
expect do
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(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
expect do
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)
end
@ -268,7 +268,7 @@ RSpec.describe API::Ci::Variables do
delete api("/projects/#{project.id}/variables/#{variable.key}", user)
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
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' }
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 { var2.reload }.to raise_error(ActiveRecord::RecordNotFound)

View File

@ -101,7 +101,7 @@ RSpec.describe API::Clusters::Agents do
expect do
post(api("/projects/#{project.id}/cluster_agents", user),
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
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)
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
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
get api(route, current_user), params: { per_page: 100 }
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 = project.repository.branch_names_contains(commit_id).map { |name| ['branch', 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 include_limited_pagination_headers
@ -1000,8 +1000,8 @@ RSpec.describe API::Commits do
it 'returns all refs' do
get api(route, current_user), params: { type: 'all', per_page: 100 }
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 = project.repository.branch_names_contains(commit_id).map { |name| ['branch', name] }
refs.concat(project.repository.tag_names_contains(commit_id).map { |name| ['tag', name] })
expect(response).to have_gitlab_http_status(:ok)
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
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(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
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(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
it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
let(:message) { '404 Signature Not Found'}
let(:message) { '404 Signature Not Found' }
end
end

View File

@ -94,7 +94,7 @@ RSpec.describe API::ConanInstancePackages do
end
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'
end

View File

@ -93,7 +93,7 @@ RSpec.describe API::ConanProjectPackages do
end
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'
end

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::DependencyProxy, api: true do
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 }
before do

View File

@ -451,7 +451,7 @@ RSpec.describe API::Deployments do
describe 'DELETE /projects/:id/deployments/:deployment_id' do
let(:project) { create(:project, :repository) }
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
create(
:deployment,

View File

@ -318,7 +318,7 @@ RSpec.describe API::GoProxy 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(: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
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(:params) { '' }
let(:board) { }
let(:board) {}
let(:confidential) { false }
let(:board_parent_type) { board_parent.class.to_s.downcase }
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(:params) { '' }
let(:board) { }
let(:board) {}
let(:board_parent_type) { board_parent.class.to_s.downcase }
let(:board_data) { graphql_data[board_parent_type]['boards']['edges'].first['node'] }
let(:lists_data) { board_data['lists']['edges'] }

View File

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

View File

@ -84,7 +84,7 @@ RSpec.describe 'Toggling an AwardEmoji' do
end
describe 'marking Todos as done' do
let(:user) { current_user}
let(:user) { current_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(:tag_name) { 'v7.12.5'}
let(:tag_name) { 'v7.12.5' }
let(:tag_message) { nil }
let(:ref) { 'master'}
let(:name) { 'Version 7.12.5'}
let(:ref) { 'master' }
let(:name) { 'Version 7.12.5' }
let(:description) { 'Release 7.12.5 :rocket:' }
let(:released_at) { '2018-12-10' }
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(: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(:released_at) { '2018-12-10' }
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(:visibility_level) { 'public' }
let(:action) { :create }
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_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(:actions) { [{ action: action }.merge(file_1), { action: action }.merge(file_2)] }
let(:project_path) { nil }
let(:uploaded_files) { nil }
@ -149,7 +149,7 @@ RSpec.describe 'Creating a Snippet' do
end
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 '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(:project) { create(:project, :public) }
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(: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
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
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 } }
it_behaves_like 'toggling confidentiality' do
let(:values) { { old: false, new: true }}
let(:values) { { old: false, new: true } }
end
end
@ -115,7 +115,7 @@ RSpec.describe 'Update a work item' do
end
it_behaves_like 'toggling confidentiality' do
let(:values) { { old: true, new: false }}
let(:values) { { old: true, new: false } }
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'
context 'when the namespace is public' do
let(:group) { create(:group, :public)}
let(:group) { create(:group, :public) }
it 'hides statistics for unauthenticated requests' do
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(:metadata) { query_graphql_fragment('ConanMetadata') }
let(:package_files_metadata) {query_graphql_fragment('ConanFileMetadata')}
let(:package_files_metadata) { query_graphql_fragment('ConanFileMetadata') }
let(:query) do
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(:package_files_metadata) {query_graphql_fragment('HelmFileMetadata')}
let(:package_files_metadata) { query_graphql_fragment('HelmFileMetadata') }
let(:query) do
graphql_query_for(:package, { id: package_global_id }, <<~FIELDS)

View File

@ -18,7 +18,7 @@ RSpec.describe 'package details' do
let(:depth) { 3 }
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
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_details) { graphql_data_at(:package) }

View File

@ -26,7 +26,7 @@ RSpec.describe 'query Jira service' do
)
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'

View File

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

View File

@ -91,7 +91,7 @@ RSpec.describe API::GroupVariables do
it 'creates variable' do
expect do
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(json_response['key']).to eq('TEST_VARIABLE_2')
@ -105,7 +105,7 @@ RSpec.describe API::GroupVariables do
it 'creates variable with optional attributes' do
expect do
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(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
expect do
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)
end
@ -207,7 +207,7 @@ RSpec.describe API::GroupVariables do
delete api("/groups/#{group.id}/variables/#{variable.key}", user)
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
it 'responds with 404 Not Found if requesting non-existing variable' do

View File

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

View File

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

View File

@ -1451,7 +1451,7 @@ RSpec.describe API::Internal::Base do
describe 'POST /internal/two_factor_otp_check' do
let(:key_id) { key.id }
let(:otp) { '123456'}
let(:otp) { '123456' }
subject do
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
let(:key_id) { key.id }
let(:otp) { '123456'}
let(:otp) { '123456' }
subject do
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
let(:key_id) { key.id }
let(:otp) { '123456'}
let(:otp) { '123456' }
subject do
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
let(:key_id) { key.id }
let(:otp) { '123456'}
let(:otp) { '123456' }
subject do
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
let(:key_id) { key.id }
let(:otp) { '123456'}
let(:otp) { '123456' }
subject do
post api('/internal/two_factor_push_otp_check'),

View File

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

View File

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

View File

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

View File

@ -10,7 +10,7 @@ RSpec.describe API::Metrics::Dashboard::Annotations do
let(:dashboard) { 'config/prometheus/common_metrics.yml' }
let(:starting_at) { Time.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|
let(:url) { "/#{source_type.pluralize}/#{source.id}/metrics_dashboard/annotations" }

View File

@ -111,7 +111,7 @@ RSpec.describe API::Notes do
system: false
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
it 'is a note array response' do

View File

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

View File

@ -73,7 +73,7 @@ RSpec.describe API::NugetGroupPackages do
let(:include_prereleases) { true }
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
where(:group_visibility, :subgroup_visibility, :expected_status) do

View File

@ -19,7 +19,7 @@ RSpec.describe API::Pages do
end
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

View File

@ -19,8 +19,8 @@ RSpec.describe API::PagesDomains do
end
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_missing_chain_params) {build(:pages_domain, :with_missing_chain, project: project).slice(:certificate) }
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(:route) { "/projects/#{project.id}/pages/domains" }
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
let_it_be(:current_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(: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 include_pagination_headers
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
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 include_pagination_headers
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
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
allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
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)
end
end

View File

@ -41,7 +41,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'deploy token for package GET requests'
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'
end
@ -102,7 +102,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'deploy token for package GET requests'
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'
end

View File

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

View File

@ -962,7 +962,7 @@ RSpec.describe API::Releases do
context 'with milestones' do
let(:subject) { post api("/projects/#{project.id}/releases", maintainer), params: params }
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
params.merge!(milestone_params)
@ -1120,7 +1120,7 @@ RSpec.describe API::Releases do
end
context 'when there are no corresponding releases' do
let!(:release) { }
let!(:release) {}
it 'forbids the request' do
put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
@ -1158,7 +1158,7 @@ RSpec.describe API::Releases do
end
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 }
@ -1310,7 +1310,7 @@ RSpec.describe API::Releases do
end
context 'when there are no corresponding releases' do
let!(:release) { }
let!(:release) {}
it 'forbids the request' do
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 include_pagination_headers
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,
internal_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
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_range2.id)
end
@ -99,10 +99,10 @@ RSpec.describe API::Snippets, factory_default: :keep do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
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_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_other.id}")
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
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)
end
end

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