Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8c2d06cba7
commit
a16398e10f
|
@ -1 +1 @@
|
|||
0fa08d953e0d5497fe5366836d0ed54b9ff557d8
|
||||
31ea786fbf0a7874b44efcb1f8b43bc4536d9b7e
|
||||
|
|
|
@ -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 = {};
|
||||
|
||||
|
@ -72,6 +72,21 @@ function createSourceMapAttributes(hastNode, markdown) {
|
|||
: {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that resolves the attributes
|
||||
* of a ProseMirror node based on a hast node.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
const getAttrsFactory = ({ attributeTransformer, markdown }) =>
|
||||
/**
|
||||
* Compute ProseMirror node’s attributes from a Hast node.
|
||||
* By default, this function includes sourcemap position
|
||||
|
@ -80,21 +95,25 @@ function createSourceMapAttributes(hastNode, markdown) {
|
|||
* 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 {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 file’s content
|
||||
*
|
||||
* @returns An object that contains a ProseMirror node’s attributes
|
||||
*/
|
||||
function getAttrs(proseMirrorNodeSpec, hastNode, hastParents, markdown) {
|
||||
function getAttrs(proseMirrorNodeSpec, hastNode, hastParents) {
|
||||
const { getAttrs: specGetAttrs } = proseMirrorNodeSpec;
|
||||
|
||||
return {
|
||||
const attributes = {
|
||||
...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) => {
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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%;
|
||||
}
|
|
@ -66,4 +66,9 @@ class DeployKey < Key
|
|||
|
||||
query
|
||||
end
|
||||
|
||||
# This is used for the internal logic of AuditEvents::BuildService.
|
||||
def impersonated?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -1809,14 +1809,10 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def attention_requested_open_merge_requests_count(force: false)
|
||||
if Feature.enabled?(:uncached_mr_attention_requests_count, self)
|
||||
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
|
||||
|
||||
def assigned_open_issues_count(force: false)
|
||||
Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force, expires_in: COUNT_CACHE_VALIDITY_PERIOD) do
|
||||
|
|
|
@ -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
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12731,6 +12731,9 @@ msgid_plural "Deploys"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Deploy Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "Deploy Keys"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 };
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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',
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1223,7 +1223,7 @@ paragraph
|
|||
${'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'} | ${'<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}
|
||||
|
@ -1232,6 +1232,11 @@ paragraph
|
|||
${'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}
|
||||
|
@ -1248,7 +1253,7 @@ paragraph
|
|||
${'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,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -66,7 +66,7 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
|
|||
.with(%w[which gmake])
|
||||
.and_return(['/usr/bin/gmake', 0])
|
||||
expect(Gitlab::Popen).to receive(:popen)
|
||||
.with(%w[gmake all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
|
||||
.with(%w[gmake clean-build all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
|
||||
.and_return(['ok', 0])
|
||||
|
||||
subject
|
||||
|
@ -78,7 +78,7 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
|
|||
.with(%w[which gmake])
|
||||
.and_return(['/usr/bin/gmake', 0])
|
||||
expect(Gitlab::Popen).to receive(:popen)
|
||||
.with(%w[gmake all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
|
||||
.with(%w[gmake clean-build all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
|
||||
.and_return(['output', 1])
|
||||
|
||||
expect { subject }.to raise_error /Gitaly failed to compile: output/
|
||||
|
@ -95,14 +95,14 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
|
|||
|
||||
it 'calls make in the gitaly directory' do
|
||||
expect(Gitlab::Popen).to receive(:popen)
|
||||
.with(%w[make all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
|
||||
.with(%w[make clean-build all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
|
||||
.and_return(['output', 0])
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
context 'when Rails.env is test' do
|
||||
let(:command) { %w[make all git] }
|
||||
let(:command) { %w[make clean-build all git] }
|
||||
|
||||
before do
|
||||
stub_rails_env('test')
|
||||
|
|
|
@ -3458,11 +3458,6 @@ co@^4.6.0:
|
|||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
|
||||
|
||||
codemirror@^5.48.4:
|
||||
version "5.53.2"
|
||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.53.2.tgz#9799121cf8c50809cca487304e9de3a74d33f428"
|
||||
integrity sha512-wvSQKS4E+P8Fxn/AQ+tQtJnF1qH5UOlxtugFLpubEZ5jcdH2iXTVinb+Xc/4QjshuOxRm4fUsU2QPF1JJKiyXA==
|
||||
|
||||
codesandbox-api@0.0.23:
|
||||
version "0.0.23"
|
||||
resolved "https://registry.yarnpkg.com/codesandbox-api/-/codesandbox-api-0.0.23.tgz#bf650a21b5f3c2369e03f0c19d10b4e2ba255b4f"
|
||||
|
|
Loading…
Reference in New Issue