Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-12-02 00:17:32 +00:00
parent 7b78125a38
commit ef615776bf
49 changed files with 744 additions and 149 deletions

View File

@ -519,10 +519,26 @@ rspec:coverage:
paths: paths:
- coverage/index.html - coverage/index.html
- coverage/assets/ - coverage/assets/
- coverage/lcov/
- tmp/memory_test/ - tmp/memory_test/
reports: reports:
cobertura: coverage/coverage.xml cobertura: coverage/coverage.xml
rspec:undercoverage:
extends:
- .coverage-base
- .rails:rules:rspec-undercoverage
stage: post-test
needs: ["rspec:coverage"]
script:
- if [ -n "$CI_MERGE_REQUEST_SOURCE_BRANCH_SHA" ]; then
echo "Checking out \$CI_MERGE_REQUEST_SOURCE_BRANCH_SHA ($CI_MERGE_REQUEST_SOURCE_BRANCH_SHA) instead of \$CI_COMMIT_SHA (merge result commit $CI_COMMIT_SHA) so we can use $CI_MERGE_REQUEST_DIFF_BASE_SHA for undercoverage in this merged result pipeline";
git checkout -f ${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA};
else
echo "Using \$CI_COMMIT_SHA ($CI_COMMIT_SHA) for this non-merge result pipeline.";
fi;
- run_timed_command "scripts/undercoverage"
rspec:feature-flags: rspec:feature-flags:
extends: extends:
- .coverage-base - .coverage-base

View File

@ -67,6 +67,9 @@
.if-merge-request-labels-run-review-app: &if-merge-request-labels-run-review-app .if-merge-request-labels-run-review-app: &if-merge-request-labels-run-review-app
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-review-app/' if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-review-app/'
.if-merge-request-labels-skip-undercoverage: &if-merge-request-labels-skip-undercoverage
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:skip-undercoverage/'
.if-security-merge-request: &if-security-merge-request .if-security-merge-request: &if-security-merge-request
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID' if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
@ -1359,6 +1362,17 @@
- <<: *if-merge-request-labels-run-all-rspec - <<: *if-merge-request-labels-run-all-rspec
when: always when: always
.rails:rules:rspec-undercoverage:
rules:
- <<: *if-not-ee
when: never
- <<: *if-merge-request-labels-skip-undercoverage
allow_failure: true
- <<: *if-merge-request-labels-run-all-rspec
- <<: *if-merge-request-approved
- <<: *if-merge-request
changes: *backend-patterns
.rails:rules:default-branch-schedule-nightly--code-backstage: .rails:rules:default-branch-schedule-nightly--code-backstage:
rules: rules:
- <<: *if-default-branch-schedule-nightly - <<: *if-default-branch-schedule-nightly

View File

@ -1 +1 @@
4dd8bfe1307ffcc5a2a3f4eb70da7977a7c1d915 a191a5d10f0772ae2ed6ec869001ddde6d277827

View File

@ -405,7 +405,9 @@ end
group :development, :test, :coverage do group :development, :test, :coverage do
gem 'simplecov', '~> 0.18.5', require: false gem 'simplecov', '~> 0.18.5', require: false
gem 'simplecov-lcov', '~> 0.8.0', require: false
gem 'simplecov-cobertura', '~> 1.3.1', require: false gem 'simplecov-cobertura', '~> 1.3.1', require: false
gem 'undercover', '~> 0.4.4', require: false
end end
# Gems required in omnibus-gitlab pipeline # Gems required in omnibus-gitlab pipeline

View File

@ -645,6 +645,8 @@ GEM
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.8.0) i18n_data (0.8.0)
icalendar (2.4.1) icalendar (2.4.1)
imagen (0.1.8)
parser (>= 2.5, != 2.5.1.1)
invisible_captcha (1.1.0) invisible_captcha (1.1.0)
rails (>= 4.2) rails (>= 4.2)
ipaddress (0.8.3) ipaddress (0.8.3)
@ -1197,6 +1199,7 @@ GEM
simplecov-cobertura (1.3.1) simplecov-cobertura (1.3.1)
simplecov (~> 0.8) simplecov (~> 0.8)
simplecov-html (0.12.3) simplecov-html (0.12.3)
simplecov-lcov (0.8.0)
sixarm_ruby_unaccent (1.2.0) sixarm_ruby_unaccent (1.2.0)
slack-messenger (2.3.4) slack-messenger (2.3.4)
snowplow-tracker (0.6.1) snowplow-tracker (0.6.1)
@ -1312,6 +1315,10 @@ GEM
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
u2f (0.2.1) u2f (0.2.1)
uber (0.1.0) uber (0.1.0)
undercover (0.4.4)
imagen (>= 0.1.8)
rainbow (>= 2.1, < 4.0)
rugged (>= 0.27, < 1.3)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.7) unf_ext (0.0.7.7)
@ -1626,6 +1633,7 @@ DEPENDENCIES
simple_po_parser (~> 1.1.2) simple_po_parser (~> 1.1.2)
simplecov (~> 0.18.5) simplecov (~> 0.18.5)
simplecov-cobertura (~> 1.3.1) simplecov-cobertura (~> 1.3.1)
simplecov-lcov (~> 0.8.0)
slack-messenger (~> 2.3.4) slack-messenger (~> 2.3.4)
snowplow-tracker (~> 0.6.1) snowplow-tracker (~> 0.6.1)
solargraph (~> 0.43) solargraph (~> 0.43)
@ -1648,6 +1656,7 @@ DEPENDENCIES
toml-rb (~> 2.0) toml-rb (~> 2.0)
truncato (~> 0.7.11) truncato (~> 0.7.11)
u2f (~> 0.2.1) u2f (~> 0.2.1)
undercover (~> 0.4.4)
unf (~> 0.1.4) unf (~> 0.1.4)
unleash (~> 3.2.2) unleash (~> 3.2.2)
valid_email (~> 0.1) valid_email (~> 0.1)

View File

@ -0,0 +1,21 @@
import { mergeAttributes, Node } from '@tiptap/core';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
export default Node.create({
name: 'footnoteDefinition',
content: 'paragraph',
group: 'block',
parseHTML() {
return [
{ tag: 'section.footnotes li' },
{ tag: '.footnote-backref', priority: PARSE_HTML_PRIORITY_HIGHEST, ignore: true },
];
},
renderHTML({ HTMLAttributes }) {
return ['li', mergeAttributes(HTMLAttributes), 0];
},
});

View File

@ -0,0 +1,37 @@
import { Node, mergeAttributes } from '@tiptap/core';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
export default Node.create({
name: 'footnoteReference',
inline: true,
group: 'inline',
atom: true,
draggable: true,
selectable: true,
addAttributes() {
return {
footnoteId: {
default: null,
parseHTML: (element) => element.querySelector('a').getAttribute('id'),
},
footnoteNumber: {
default: null,
parseHTML: (element) => element.textContent,
},
};
},
parseHTML() {
return [{ tag: 'sup.footnote-ref', priority: PARSE_HTML_PRIORITY_HIGHEST }];
},
renderHTML({ HTMLAttributes: { footnoteNumber, footnoteId, ...HTMLAttributes } }) {
return ['sup', mergeAttributes(HTMLAttributes), footnoteNumber];
},
});

View File

@ -0,0 +1,19 @@
import { mergeAttributes, Node } from '@tiptap/core';
export default Node.create({
name: 'footnotesSection',
content: 'footnoteDefinition+',
group: 'block',
isolating: true,
parseHTML() {
return [{ tag: 'section.footnotes > ol' }];
},
renderHTML({ HTMLAttributes }) {
return ['ol', mergeAttributes(HTMLAttributes, { class: 'footnotes gl-font-sm' }), 0];
},
});

View File

@ -19,6 +19,9 @@ import Dropcursor from '../extensions/dropcursor';
import Emoji from '../extensions/emoji'; import Emoji from '../extensions/emoji';
import Figure from '../extensions/figure'; import Figure from '../extensions/figure';
import FigureCaption from '../extensions/figure_caption'; import FigureCaption from '../extensions/figure_caption';
import FootnoteDefinition from '../extensions/footnote_definition';
import FootnoteReference from '../extensions/footnote_reference';
import FootnotesSection from '../extensions/footnotes_section';
import Frontmatter from '../extensions/frontmatter'; import Frontmatter from '../extensions/frontmatter';
import Gapcursor from '../extensions/gapcursor'; import Gapcursor from '../extensions/gapcursor';
import HardBreak from '../extensions/hard_break'; import HardBreak from '../extensions/hard_break';
@ -94,6 +97,9 @@ export const createContentEditor = ({
Emoji, Emoji,
Figure, Figure,
FigureCaption, FigureCaption,
FootnoteDefinition,
FootnoteReference,
FootnotesSection,
Frontmatter, Frontmatter,
Gapcursor, Gapcursor,
HardBreak, HardBreak,

View File

@ -17,6 +17,9 @@ import Division from '../extensions/division';
import Emoji from '../extensions/emoji'; import Emoji from '../extensions/emoji';
import Figure from '../extensions/figure'; import Figure from '../extensions/figure';
import FigureCaption from '../extensions/figure_caption'; import FigureCaption from '../extensions/figure_caption';
import FootnotesSection from '../extensions/footnotes_section';
import FootnoteDefinition from '../extensions/footnote_definition';
import FootnoteReference from '../extensions/footnote_reference';
import Frontmatter from '../extensions/frontmatter'; import Frontmatter from '../extensions/frontmatter';
import HardBreak from '../extensions/hard_break'; import HardBreak from '../extensions/hard_break';
import Heading from '../extensions/heading'; import Heading from '../extensions/heading';
@ -156,6 +159,15 @@ const defaultSerializerConfig = {
state.write(`:${name}:`); state.write(`:${name}:`);
}, },
[FootnoteDefinition.name]: (state, node) => {
state.renderInline(node);
},
[FootnoteReference.name]: (state, node) => {
state.write(`[^${node.attrs.footnoteNumber}]`);
},
[FootnotesSection.name]: (state, node) => {
state.renderList(node, '', (index) => `[^${index + 1}]: `);
},
[Frontmatter.name]: (state, node) => { [Frontmatter.name]: (state, node) => {
const { language } = node.attrs; const { language } = node.attrs;
const syntax = { const syntax = {

View File

@ -63,7 +63,7 @@ export default {
class="ide-sidebar-link js-ide-review-mode" class="ide-sidebar-link js-ide-review-mode"
@click.prevent="changedActivityView($event, $options.leftSidebarViews.review.name)" @click.prevent="changedActivityView($event, $options.leftSidebarViews.review.name)"
> >
<gl-icon name="file-modified" /> <gl-icon name="review-list" />
</button> </button>
</li> </li>
<li> <li>

View File

@ -0,0 +1,27 @@
import InputCopyToggleVisibility from './input_copy_toggle_visibility.vue';
export default {
component: InputCopyToggleVisibility,
title: 'vue_shared/components/form/input_copy_toggle_visibility',
};
const defaultProps = {
value: 'hR8x1fuJbzwu5uFKLf9e',
formInputGroupProps: { class: 'gl-form-input-xl' },
};
const Template = (args, { argTypes }) => ({
components: { InputCopyToggleVisibility },
props: Object.keys(argTypes),
template: `<input-copy-toggle-visibility
:value="value"
:initial-visibility="initialVisibility"
:show-toggle-visibility-button="showToggleVisibilityButton"
:show-copy-button="showCopyButton"
:form-input-group-props="formInputGroupProps"
:copy-button-title="copyButtonTitle"
/>`,
});
export const Default = Template.bind({});
Default.args = defaultProps;

View File

@ -0,0 +1,124 @@
<script>
import { GlFormInputGroup, GlFormGroup, GlButton, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default {
name: 'InputCopyToggleVisibility',
i18n: {
toggleVisibilityLabelHide: __('Click to hide'),
toggleVisibilityLabelReveal: __('Click to reveal'),
},
components: {
GlFormInputGroup,
GlFormGroup,
GlButton,
ClipboardButton,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
value: {
type: String,
required: false,
default: '',
},
initialVisibility: {
type: Boolean,
required: false,
default: false,
},
showToggleVisibilityButton: {
type: Boolean,
required: false,
default: true,
},
showCopyButton: {
type: Boolean,
required: false,
default: true,
},
copyButtonTitle: {
type: String,
required: false,
default: __('Copy'),
},
formInputGroupProps: {
type: Object,
required: false,
default() {
return {};
},
},
},
data() {
return {
valueIsVisible: this.initialVisibility,
};
},
computed: {
toggleVisibilityLabel() {
return this.valueIsVisible
? this.$options.i18n.toggleVisibilityLabelHide
: this.$options.i18n.toggleVisibilityLabelReveal;
},
toggleVisibilityIcon() {
return this.valueIsVisible ? 'eye-slash' : 'eye';
},
computedValueIsVisible() {
return !this.showToggleVisibilityButton || this.valueIsVisible;
},
displayedValue() {
return this.computedValueIsVisible ? this.value : '*'.repeat(this.value.length || 20);
},
},
methods: {
handleToggleVisibilityButtonClick() {
this.valueIsVisible = !this.valueIsVisible;
this.$emit('visibility-change', this.valueIsVisible);
},
handleCopyButtonClick() {
this.$emit('copy');
},
handleFormInputCopy(event) {
if (this.computedValueIsVisible) {
return;
}
event.clipboardData.setData('text/plain', this.value);
event.preventDefault();
},
},
};
</script>
<template>
<gl-form-group v-bind="$attrs">
<gl-form-input-group
:value="displayedValue"
input-class="gl-font-monospace! gl-cursor-default!"
select-on-click
readonly
v-bind="formInputGroupProps"
@copy="handleFormInputCopy"
>
<template v-if="showToggleVisibilityButton || showCopyButton" #append>
<gl-button
v-if="showToggleVisibilityButton"
v-gl-tooltip.hover="toggleVisibilityLabel"
:aria-label="toggleVisibilityLabel"
:icon="toggleVisibilityIcon"
@click="handleToggleVisibilityButtonClick"
/>
<clipboard-button
v-if="showCopyButton"
:text="value"
:title="copyButtonTitle"
@click="handleCopyButtonClick"
/>
</template>
</gl-form-input-group>
</gl-form-group>
</template>

View File

@ -1084,16 +1084,6 @@ module Ci
runner&.instance_type? runner&.instance_type?
end end
def job_variables_attributes
strong_memoize(:job_variables_attributes) do
job_variables.map do |variable|
variable.attributes.except('id', 'job_id', 'encrypted_value', 'encrypted_value_iv').tap do |attrs|
attrs[:value] = variable.value
end
end
end
end
protected protected
def run_status_commit_hooks! def run_status_commit_hooks!

View File

@ -7,7 +7,7 @@ module Ci
allow_failure stage stage_id stage_idx trigger_request allow_failure stage stage_id stage_idx trigger_request
yaml_variables when environment coverage_regex yaml_variables when environment coverage_regex
description tag_list protected needs_attributes description tag_list protected needs_attributes
resource_group scheduling_type job_variables_attributes].freeze resource_group scheduling_type].freeze
end end
def self.extra_accessors def self.extra_accessors

View File

@ -1,8 +0,0 @@
---
name: drop_detached_partitions
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67056
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337155
milestone: '14.2'
type: development
group: group::database
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: partition_pruning
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67056
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337153
milestone: '14.2'
type: development
group: group::database
default_enabled: false

View File

@ -10,5 +10,4 @@ link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
level: suggestion level: suggestion
ignorecase: true ignorecase: true
swap: swap:
button: 'if possible, rewrite to not use' button: 'if possible, rewrite to remove'
area: 'use "section" instead of'

View File

@ -252,6 +252,7 @@ Example response:
"finished_at": "2016-01-11T10:15:10.506Z", "finished_at": "2016-01-11T10:15:10.506Z",
"duration": 97.0, "duration": 97.0,
"status": "failed", "status": "failed",
"failure_reason": "script_failure",
"tag": false, "tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/42", "web_url": "https://example.com/foo/bar/-/jobs/42",
"user": null "user": null

View File

@ -71,6 +71,7 @@ Example of response
"runner": null, "runner": null,
"stage": "test", "stage": "test",
"status": "failed", "status": "failed",
"failure_reason": "script_failure",
"tag": false, "tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/7", "web_url": "https://example.com/foo/bar/-/jobs/7",
"user": { "user": {
@ -126,6 +127,7 @@ Example of response
"runner": null, "runner": null,
"stage": "test", "stage": "test",
"status": "failed", "status": "failed",
"failure_reason": "stuck_or_timeout_failure",
"tag": false, "tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/6", "web_url": "https://example.com/foo/bar/-/jobs/6",
"user": { "user": {
@ -207,6 +209,7 @@ Example of response
"runner": null, "runner": null,
"stage": "test", "stage": "test",
"status": "failed", "status": "failed",
"failure_reason": "stuck_or_timeout_failure",
"tag": false, "tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/6", "web_url": "https://example.com/foo/bar/-/jobs/6",
"user": { "user": {
@ -271,6 +274,7 @@ Example of response
"runner": null, "runner": null,
"stage": "test", "stage": "test",
"status": "failed", "status": "failed",
"failure_reason": "script_failure",
"tag": false, "tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/7", "web_url": "https://example.com/foo/bar/-/jobs/7",
"user": { "user": {
@ -443,6 +447,7 @@ Example of response
"runner": null, "runner": null,
"stage": "test", "stage": "test",
"status": "failed", "status": "failed",
"failure_reason": "script_failure",
"tag": false, "tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/8", "web_url": "https://example.com/foo/bar/-/jobs/8",
"user": { "user": {

View File

@ -145,6 +145,6 @@ PUT /projects/:id/external_status_checks/:check_id
| `external_url` | string | no | URL of external status check resource | | `external_url` | string | no | URL of external status check resource |
| `protected_branch_ids` | `array<Integer>` | no | IDs of protected branches to scope the rule by | | `protected_branch_ids` | `array<Integer>` | no | IDs of protected branches to scope the rule by |
## Related links ## Related topics
- [External status checks](../user/project/merge_requests/status_checks.md). - [External status checks](../user/project/merge_requests/status_checks.md).

View File

@ -11,7 +11,7 @@ The GitLab API v3 was [removed](https://gitlab.com/gitlab-org/gitlab-foss/-/issu
For information about the current version of the GitLab API, read the [API documentation](index.md). For information about the current version of the GitLab API, read the [API documentation](index.md).
## Related links ## Related topics
- [GitLab v3 API documentation](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/8-16-stable/doc/api/index.md) - [GitLab v3 API documentation](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/8-16-stable/doc/api/index.md)
- [Migration guide](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/11-0-stable/doc/api/v3_to_v4.md) from - [Migration guide](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/11-0-stable/doc/api/v3_to_v4.md) from

View File

@ -199,8 +199,10 @@ use `include:file`. You can use `include:file` in combination with `include:proj
**Keyword type**: Global keyword. **Keyword type**: Global keyword.
**Possible inputs**: A full path, relative to the root directory (`/`). **Possible inputs**:
The YAML file must have the extension `.yml` or `.yaml`.
- A full path, relative to the root directory (`/`). The YAML file must have the
extension `.yml` or `.yaml`.
**Example of `include:file`**: **Example of `include:file`**:
@ -255,10 +257,10 @@ Use `include:remote` with a full URL to include a file from a different location
**Keyword type**: Global keyword. **Keyword type**: Global keyword.
**Possible inputs**: A public URL accessible by an HTTP/HTTPS `GET` request. **Possible inputs**:
Authentication with the remote URL is not supported.
The YAML file must have the extension `.yml` or `.yaml`. - A public URL accessible by an HTTP/HTTPS `GET` request. Authentication with the
remote URL is not supported. The YAML file must have the extension `.yml` or `.yaml`.
**Example of `include:remote`**: **Example of `include:remote`**:
@ -281,7 +283,9 @@ Use `include:template` to include [`.gitlab-ci.yml` templates](https://gitlab.co
**Keyword type**: Global keyword. **Keyword type**: Global keyword.
**Possible inputs**: [`.gitlab-ci.yml` templates](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates). **Possible inputs**:
- [`.gitlab-ci.yml` templates](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates).
**Example of `include:template`**: **Example of `include:template`**:
@ -556,7 +560,9 @@ The default value for `allow_failure` is:
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: `true` or `false`. **Possible inputs**:
- `true` or `false`.
**Example of `allow_failure`**: **Example of `allow_failure`**:
@ -894,7 +900,9 @@ included templates in jobs.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: See list of available [artifacts reports types](artifacts_reports.md). **Possible inputs**:
- See list of available [artifacts reports types](artifacts_reports.md).
**Example of `artifacts:reports`**: **Example of `artifacts:reports`**:
@ -1024,14 +1032,15 @@ Use the `cache:paths` keyword to choose which files or directories to cache.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: An array of paths relative to the project directory (`$CI_PROJECT_DIR`). **Possible inputs**:
You can use wildcards that use [glob](https://en.wikipedia.org/wiki/Glob_(programming))
patterns:
- In [GitLab Runner 13.0 and later](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2620), - An array of paths relative to the project directory (`$CI_PROJECT_DIR`).
[`doublestar.Glob`](https://pkg.go.dev/github.com/bmatcuk/doublestar@v1.2.2?tab=doc#Match). You can use wildcards that use [glob](https://en.wikipedia.org/wiki/Glob_(programming))
- In GitLab Runner 12.10 and earlier, patterns:
[`filepath.Match`](https://pkg.go.dev/path/filepath#Match). - In [GitLab Runner 13.0 and later](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2620),
[`doublestar.Glob`](https://pkg.go.dev/github.com/bmatcuk/doublestar@v1.2.2?tab=doc#Match).
- In GitLab Runner 12.10 and earlier,
[`filepath.Match`](https://pkg.go.dev/path/filepath#Match).
**Example of `cache:paths`**: **Example of `cache:paths`**:
@ -1114,7 +1123,9 @@ which speeds up subsequent pipeline runs.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: An array of one or two file paths. **Possible inputs**:
- An array of one or two file paths.
**Example of `cache:key:files`**: **Example of `cache:key:files`**:
@ -1190,7 +1201,9 @@ Use `untracked: true` to cache all files that are untracked in your Git reposito
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: `true` or `false` (default). **Possible inputs**:
- `true` or `false` (default).
**Example of `cache:untracked`**: **Example of `cache:untracked`**:
@ -1303,7 +1316,9 @@ line in the job output matches the regular expression.
To extract the code coverage value in the matching line, GitLab uses this To extract the code coverage value in the matching line, GitLab uses this
regular expression: `\d+(\.\d+)?`. regular expression: `\d+(\.\d+)?`.
**Possible inputs**: A regular expression. Must start and end with `/`. **Possible inputs**:
- A regular expression. Must start and end with `/`.
**Example of `coverage`**: **Example of `coverage`**:
@ -1811,7 +1826,9 @@ where each shell token is a separate string in the array.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: A string. **Possible inputs**:
- A string.
**Example of `image:entrypoint`**: **Example of `image:entrypoint`**:
@ -1918,7 +1935,9 @@ You can't cancel subsequent jobs after a job with `interruptible: false` starts.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: `true` or `false` (default). **Possible inputs**:
- `true` or `false` (default).
**Example of `interruptible`**: **Example of `interruptible`**:
@ -2411,7 +2430,9 @@ to a pipeline, based on the status of [CI/CD variables](../variables/index.md).
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: An array of [CI/CD variable expressions](../jobs/job_control.md#cicd-variable-expressions). **Possible inputs**:
- An array of [CI/CD variable expressions](../jobs/job_control.md#cicd-variable-expressions).
**Example of `only:variables`**: **Example of `only:variables`**:
@ -2490,7 +2511,9 @@ when the Kubernetes service is active in the project.
**Keyword type**: Job-specific. You can use it only as part of a job. **Keyword type**: Job-specific. You can use it only as part of a job.
**Possible inputs**: The `kubernetes` strategy accepts only the `active` keyword. **Possible inputs**:
- The `kubernetes` strategy accepts only the `active` keyword.
**Example of `only:kubernetes`**: **Example of `only:kubernetes`**:
@ -2546,7 +2569,9 @@ Parallel jobs are named sequentially from `job_name 1/N` to `job_name N/N`.
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: A numeric value from `2` to `50`. **Possible inputs**:
- A numeric value from `2` to `50`.
**Example of `parallel`**: **Example of `parallel`**:
@ -2579,7 +2604,9 @@ Multiple runners must exist, or a single runner must be configured to run multip
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: A numeric value from `2` to `50`. **Possible inputs**:
- A numeric value from `2` to `50`.
**Example of `parallel:matrix`**: **Example of `parallel:matrix`**:
@ -2699,7 +2726,9 @@ New tags use the SHA associated with the pipeline.
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: A tag name. Can use [CI/CD variables](../variables/index.md). **Possible inputs**:
- A tag name. Can use [CI/CD variables](../variables/index.md).
**Example of `release:tag_name`**: **Example of `release:tag_name`**:
@ -2738,7 +2767,9 @@ The release name. If omitted, it is populated with the value of `release: tag_na
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: A text string. **Possible inputs**:
- A text string.
**Example of `release:name`**: **Example of `release:name`**:
@ -2843,8 +2874,10 @@ can be deployed to, but only one deployment can occur per device at any given ti
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: Only letters, digits, `-`, `_`, `/`, `$`, `{`, `}`, `.`, and spaces. **Possible inputs**:
It can't start or end with `/`.
- Only letters, digits, `-`, `_`, `/`, `$`, `{`, `}`, `.`, and spaces.
It can't start or end with `/`.
**Example of `resource_group`**: **Example of `resource_group`**:
@ -2875,7 +2908,9 @@ to select which failures to retry on.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: `0` (default), `1`, or `2`. **Possible inputs**:
- `0` (default), `1`, or `2`.
**Example of `retry`**: **Example of `retry`**:
@ -2894,7 +2929,9 @@ Use `retry:when` with `retry:max` to retry jobs for only specific failure cases.
**Keyword type**: Job keyword. You can use it only as part of a job or in the **Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default). [`default` section](#default).
**Possible inputs**: A single failure type, or an array of one or more failure types: **Possible inputs**:
- A single failure type, or an array of one or more failure types:
<!-- <!--
If you change any of the values below, make sure to update the `RETRY_WHEN_IN_DOCUMENTATION` If you change any of the values below, make sure to update the `RETRY_WHEN_IN_DOCUMENTATION`
@ -3002,7 +3039,9 @@ or [custom CI/CD variables](../variables/index.md#custom-cicd-variables).
**Keyword type**: Job-specific and pipeline-specific. You can use it as part of a job **Keyword type**: Job-specific and pipeline-specific. You can use it as part of a job
to configure the job behavior, or with [`workflow`](#workflow) to configure the pipeline behavior. to configure the job behavior, or with [`workflow`](#workflow) to configure the pipeline behavior.
**Possible inputs**: A [CI/CD variable expression](../jobs/job_control.md#cicd-variable-expressions). **Possible inputs**:
- A [CI/CD variable expression](../jobs/job_control.md#cicd-variable-expressions).
**Example of `rules:if`**: **Example of `rules:if`**:
@ -3048,8 +3087,9 @@ branch or merge request pipelines.
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: An array of file paths. In GitLab 13.6 and later, **Possible inputs**:
[file paths can include variables](../jobs/job_control.md#variables-in-ruleschanges).
- An array of file paths. In GitLab 13.6 and later, [file paths can include variables](../jobs/job_control.md#variables-in-ruleschanges).
**Example of `rules:changes`**: **Example of `rules:changes`**:
@ -3083,8 +3123,10 @@ Use `exists` to run a job when certain files exist in the repository.
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: An array of file paths. Paths are relative to the project directory (`$CI_PROJECT_DIR`) **Possible inputs**:
and can't directly link outside it. File paths can use glob patterns.
- An array of file paths. Paths are relative to the project directory (`$CI_PROJECT_DIR`)
and can't directly link outside it. File paths can use glob patterns.
**Example of `rules:exists`**: **Example of `rules:exists`**:
@ -3122,7 +3164,9 @@ job to run before continuing.
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: `true` or `false`. Defaults to `false` if not defined. **Possible inputs**:
- `true` or `false`. Defaults to `false` if not defined.
**Example of `rules:allow_failure`**: **Example of `rules:allow_failure`**:
@ -3151,7 +3195,9 @@ Use [`variables`](#variables) in `rules` to define variables for specific condit
**Keyword type**: Job-specific. You can use it only as part of a job. **Keyword type**: Job-specific. You can use it only as part of a job.
**Possible inputs**: A hash of variables in the format `VARIABLE-NAME: value`. **Possible inputs**:
- A hash of variables in the format `VARIABLE-NAME: value`.
**Example of `rules:variables`**: **Example of `rules:variables`**:
@ -3286,7 +3332,9 @@ the secret value directly in the variable.
**Keyword type**: Job keyword. You can use it only as part of a job. **Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: `true` (default) or `false`. **Possible inputs**:
- `true` (default) or `false`.
**Example of `secrets:file`**: **Example of `secrets:file`**:
@ -3682,7 +3730,9 @@ Must be used with `value`, for the variable value.
**Keyword type**: Global keyword. You cannot set job-level variables to be pre-filled when you run a pipeline manually. **Keyword type**: Global keyword. You cannot set job-level variables to be pre-filled when you run a pipeline manually.
**Possible inputs**: A string. **Possible inputs**:
- A string.
**Example of `variables:description`**: **Example of `variables:description`**:

View File

@ -134,7 +134,7 @@ After configuring GitLab for the two databases, create the new CI/CD database:
and run any pending migrations: and run any pending migrations:
```shell ```shell
bundle exec rails rails db:create db:schema:load:ci db:migrate bundle exec rails db:create db:schema:load:ci db:migrate
``` ```
1. Restart GDK: 1. Restart GDK:

View File

@ -220,6 +220,20 @@ The `* as-if-jh` jobs are run in addition to the regular EE-context jobs. The `j
The intent is to ensure that a change doesn't introduce a failure after the `gitlab-org/gitlab` project is synced to The intent is to ensure that a change doesn't introduce a failure after the `gitlab-org/gitlab` project is synced to
the `gitlab-jh/gitlab` project. the `gitlab-jh/gitlab` project.
## `undercover` RSpec test
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74859) in GitLab 14.6.
The `rspec:undercoverage` job runs [`undercover`](https://rubygems.org/gems/undercover)
to detect, and fail if any changes introduced in the merge request has zero coverage.
The `rsepc:undercoverage` job obtains coverage data from the `rspec:coverage`
job.
In the event of an emergency, or false positive from this job, add the
`pipeline:skip-undercoverage` label to the merge request to allow this job to
fail.
## PostgreSQL versions testing ## PostgreSQL versions testing
Our test suite runs against PG12 as GitLab.com runs on PG12 and Our test suite runs against PG12 as GitLab.com runs on PG12 and

View File

@ -46,6 +46,6 @@ project, group, or instance level:
When the integration sends data, you can view it in the [CI Visibility](https://app.datadoghq.com/ci) When the integration sends data, you can view it in the [CI Visibility](https://app.datadoghq.com/ci)
section of your Datadog account. section of your Datadog account.
## Related links ## Related topics
- [Datadog's CI Visibility](https://docs.datadoghq.com/continuous_integration/) documentation. - [Datadog's CI Visibility](https://docs.datadoghq.com/continuous_integration/) documentation.

View File

@ -74,7 +74,7 @@ into a different branch (`stable`):
git cherry-pick <SHA> git cherry-pick <SHA>
``` ```
## Related links ## Related topics
- Cherry-pick commits with [the Commits API](../../api/commits.md#cherry-pick-a-commit) - Cherry-pick commits with [the Commits API](../../api/commits.md#cherry-pick-a-commit)
- Git documentation [for cherry-picks](https://git-scm.com/docs/git-cherry-pick) - Git documentation [for cherry-picks](https://git-scm.com/docs/git-cherry-pick)

View File

@ -88,7 +88,7 @@ sees in the project's search results respectively.
|:---------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------| |:---------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|
| ![Confidential issues search by maintainer](img/confidential_issues_search_master.png) | ![Confidential issues search by guest](img/confidential_issues_search_guest.png) | | ![Confidential issues search by maintainer](img/confidential_issues_search_master.png) | ![Confidential issues search by guest](img/confidential_issues_search_guest.png) |
## Related links ## Related topics
- [Merge requests for confidential issues](../merge_requests/confidential.md) - [Merge requests for confidential issues](../merge_requests/confidential.md)
- [Make an epic confidential](../../group/epics/manage_epics.md#make-an-epic-confidential) - [Make an epic confidential](../../group/epics/manage_epics.md#make-an-epic-confidential)

View File

@ -105,7 +105,7 @@ Without the approvals, the work cannot merge. Required approvals enable multiple
- [Require approval from a security team](../../../application_security/index.md#security-approvals-in-merge-requests) - [Require approval from a security team](../../../application_security/index.md#security-approvals-in-merge-requests)
before merging code that could introduce a vulnerability. **(ULTIMATE)** before merging code that could introduce a vulnerability. **(ULTIMATE)**
## Related links ## Related topics
- [Merge request approvals API](../../../../api/merge_request_approvals.md) - [Merge request approvals API](../../../../api/merge_request_approvals.md)
- [Instance-level approval rules](../../../admin_area/merge_requests_approvals.md) for self-managed installations - [Instance-level approval rules](../../../admin_area/merge_requests_approvals.md) for self-managed installations

View File

@ -157,7 +157,7 @@ You can also enforce merge request approval settings:
If the settings are inherited by a group or project, they cannot be changed in the group or project If the settings are inherited by a group or project, they cannot be changed in the group or project
that inherited them. that inherited them.
## Related links ## Related topics
- [Instance-level merge request approval settings](../../../admin_area/merge_requests_approvals.md) - [Instance-level merge request approval settings](../../../admin_area/merge_requests_approvals.md)
- [Compliance report](../../../compliance/compliance_report/index.md) - [Compliance report](../../../compliance/compliance_report/index.md)

View File

@ -79,7 +79,7 @@ merge request is from a fork:
1. (Optional) Select **Start a new merge request** if you're ready to create a merge request. 1. (Optional) Select **Start a new merge request** if you're ready to create a merge request.
1. Click **Cherry-pick**. 1. Click **Cherry-pick**.
## Related links ## Related topics
- The [Commits API](../../../api/commits.md) enables you to add custom messages - The [Commits API](../../../api/commits.md) enables you to add custom messages
to changes you cherry-pick through the API. to changes you cherry-pick through the API.

View File

@ -70,7 +70,7 @@ Open a merge request
- You are satisfied the problem is resolved in your private fork. - You are satisfied the problem is resolved in your private fork.
- You are ready to make the confidential commits public. - You are ready to make the confidential commits public.
## Related links ## Related topics
- [Confidential issues](../issues/confidential_issues.md) - [Confidential issues](../issues/confidential_issues.md)
- [Make an epic confidential](../../group/epics/manage_epics.md#make-an-epic-confidential) - [Make an epic confidential](../../group/epics/manage_epics.md#make-an-epic-confidential)

View File

@ -144,6 +144,6 @@ to your branch to address your reviewers' requests.
WARNING: WARNING:
Suggestions applied from multiple authors creates a commit authored by the user applying the suggestions. Suggestions applied from multiple authors creates a commit authored by the user applying the suggestions.
## Related links ## Related topics
- [Suggestions API](../../../../api/suggestions.md) - [Suggestions API](../../../../api/suggestions.md)

View File

@ -181,6 +181,6 @@ You should:
- Check the [GitLab status page](https://status.gitlab.com/) if the problem persists, - Check the [GitLab status page](https://status.gitlab.com/) if the problem persists,
to see if there is a wider outage. to see if there is a wider outage.
## Related links ## Related topics
- [External status checks API](../../../api/status_checks.md) - [External status checks API](../../../api/status_checks.md)

View File

@ -248,9 +248,19 @@ When you [rename a user](../../profile/index.md#change-your-username),
- The redirects are available as long as the original path is not claimed by - The redirects are available as long as the original path is not claimed by
another group, user, or project. another group, user, or project.
## Related links ## Related topics
- [GitLab Workflow VS Code extension](vscode.md) - [GitLab Workflow VS Code extension](vscode.md).
- To lock files and prevent change conflicts, use [file locking](../file_lock.md).
- [Repository API](../../../api/repositories.md).
- [Find files](file_finder.md) in a repository.
- [Branches](branches/index.md).
- [File templates](web_editor.md#template-dropdowns).
- [Create a directory](web_editor.md#create-a-directory).
- [Start a merge request](web_editor.md#tips).
- [Find file history](git_history.md).
- [Identify changes by line (Git blame)](git_blame.md).
- [Use Jupyter notebooks with GitLab](jupyter_notebooks/index.md).
## Troubleshooting ## Troubleshooting
@ -287,16 +297,3 @@ The same approach should also allow misidentified file types to be fixed.
``` ```
`*.txt` files have an entry in the heuristics file. This example prevents parsing of these files. `*.txt` files have an entry in the heuristics file. This example prevents parsing of these files.
## Related topics
- To lock files and prevent change conflicts, use [file locking](../file_lock.md).
- [Repository API](../../../api/repositories.md).
- [Find files](file_finder.md) in a repository.
- [Branches](branches/index.md).
- [File templates](web_editor.md#template-dropdowns).
- [Create a directory](web_editor.md#create-a-directory).
- [Start a merge request](web_editor.md#tips).
- [Find file history](git_history.md).
- [Identify changes by line (Git blame)](git_blame.md).
- [Use Jupyter notebooks with GitLab](jupyter_notebooks/index.md).

View File

@ -123,7 +123,7 @@ To do so:
With this option enabled, `75h` is displayed instead of `1w 4d 3h`. With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
## Related links ## Related topics
- [Time tracking solutions page](https://about.gitlab.com/solutions/time-tracking/) - [Time tracking solutions page](https://about.gitlab.com/solutions/time-tracking/)
- Time tracking GraphQL references: - Time tracking GraphQL references:

View File

@ -13,6 +13,7 @@ module API
expose :user, with: ::API::Entities::User expose :user, with: ::API::Entities::User
expose :commit, with: ::API::Entities::Commit expose :commit, with: ::API::Entities::Commit
expose :pipeline, with: ::API::Entities::Ci::PipelineBasic expose :pipeline, with: ::API::Entities::Ci::PipelineBasic
expose :failure_reason, if: -> (job) { job.failed? }
expose :web_url do |job, _options| expose :web_url do |job, _options|
Gitlab::Routing.url_helpers.project_job_url(job.project, job) Gitlab::Routing.url_helpers.project_job_url(job.project, job)

View File

@ -4,8 +4,6 @@ module Gitlab
module Partitioning module Partitioning
class DetachedPartitionDropper class DetachedPartitionDropper
def perform def perform
return unless Feature.enabled?(:drop_detached_partitions, default_enabled: :yaml)
Gitlab::AppLogger.info(message: "Checking for previously detached partitions to drop") Gitlab::AppLogger.info(message: "Checking for previously detached partitions to drop")
Postgresql::DetachedPartition.ready_to_drop.find_each do |detached_partition| Postgresql::DetachedPartition.ready_to_drop.find_each do |detached_partition|

View File

@ -25,11 +25,9 @@ module Gitlab
partitions_to_create = missing_partitions partitions_to_create = missing_partitions
create(partitions_to_create) unless partitions_to_create.empty? create(partitions_to_create) unless partitions_to_create.empty?
if Feature.enabled?(:partition_pruning, default_enabled: :yaml)
partitions_to_detach = extra_partitions partitions_to_detach = extra_partitions
detach(partitions_to_detach) unless partitions_to_detach.empty? detach(partitions_to_detach) unless partitions_to_detach.empty?
end end
end
rescue StandardError => e rescue StandardError => e
Gitlab::AppLogger.error(message: "Failed to create / detach partition(s)", Gitlab::AppLogger.error(message: "Failed to create / detach partition(s)",
table_name: model.table_name, table_name: model.table_name,

View File

@ -19,7 +19,7 @@ module QA
end end
def image def image
@image || 'gitlab/gitlab-runner:alpine' @image || 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine'
end end
def executor def executor

3
scripts/undercoverage Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
bundle exec undercover -c "${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$(git merge-base origin/master HEAD)}"

View File

@ -429,6 +429,38 @@
</figcaption> </figcaption>
</figure> </figure>
- name: footnotes
substitutions:
# NOTE: We don't care about verifying specific attribute values here, that should be the
# responsibility of unit tests. These tests are about the structure of the HTML.
fn_href_substitution:
- regex: '(href)(=")(.+?)(")'
replacement: '\1\2REF\4'
footnote_id_substitution:
- regex: '(id)(=")(.+?)(")'
replacement: '\1\2ID\4'
pending:
backend: https://gitlab.com/gitlab-org/gitlab/-/issues/346591
markdown: |-
A footnote reference tag looks like this: [^1]
This reference tag is a mix of letters and numbers. [^2]
[^1]: This is the text inside a footnote.
[^2]: This is another footnote.
html: |-
<p data-sourcepos="1:1-1:46" dir="auto">A footnote reference tag looks like this: <sup class="footnote-ref"><a href="#fn-1-2717" id="fnref-1-2717" data-footnote-ref="">1</a></sup></p>
<p data-sourcepos="3:1-3:56" dir="auto">This reference tag is a mix of letters and numbers. <sup class="footnote-ref"><a href="#fn-2-2717" id="fnref-2-2717" data-footnote-ref="">2</a></sup></p>
<section class="footnotes" data-footnotes><ol>
<li id="fn-1-2717">
<p data-sourcepos="5:7-5:41">This is the text inside a footnote. <a href="#fnref-1-2717" aria-label="Back to content" class="footnote-backref" data-footnote-backref=""><gl-emoji title="leftwards arrow with hook" data-name="leftwards_arrow_with_hook" data-unicode-version="1.1">↩</gl-emoji></a></p>
</li>
<li id="fn-2-2717">
<p data-sourcepos="6:7-6:31">This is another footnote. <a href="#fnref-2-2717" aria-label="Back to content" class="footnote-backref" data-footnote-backref=""><gl-emoji title="leftwards arrow with hook" data-name="leftwards_arrow_with_hook" data-unicode-version="1.1">↩</gl-emoji></a></p>
</li>
</ol></section>
- name: frontmatter_json - name: frontmatter_json
markdown: |- markdown: |-
;;; ;;;

View File

@ -11,6 +11,9 @@ import Division from '~/content_editor/extensions/division';
import Emoji from '~/content_editor/extensions/emoji'; import Emoji from '~/content_editor/extensions/emoji';
import Figure from '~/content_editor/extensions/figure'; import Figure from '~/content_editor/extensions/figure';
import FigureCaption from '~/content_editor/extensions/figure_caption'; import FigureCaption from '~/content_editor/extensions/figure_caption';
import FootnoteDefinition from '~/content_editor/extensions/footnote_definition';
import FootnoteReference from '~/content_editor/extensions/footnote_reference';
import FootnotesSection from '~/content_editor/extensions/footnotes_section';
import HardBreak from '~/content_editor/extensions/hard_break'; import HardBreak from '~/content_editor/extensions/hard_break';
import Heading from '~/content_editor/extensions/heading'; import Heading from '~/content_editor/extensions/heading';
import HorizontalRule from '~/content_editor/extensions/horizontal_rule'; import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
@ -46,6 +49,9 @@ const tiptapEditor = createTestEditor({
DetailsContent, DetailsContent,
Division, Division,
Emoji, Emoji,
FootnoteDefinition,
FootnoteReference,
FootnotesSection,
Figure, Figure,
FigureCaption, FigureCaption,
HardBreak, HardBreak,
@ -81,6 +87,9 @@ const {
descriptionItem, descriptionItem,
descriptionList, descriptionList,
emoji, emoji,
footnoteDefinition,
footnoteReference,
footnotesSection,
figure, figure,
figureCaption, figureCaption,
heading, heading,
@ -117,6 +126,9 @@ const {
emoji: { markType: Emoji.name }, emoji: { markType: Emoji.name },
figure: { nodeType: Figure.name }, figure: { nodeType: Figure.name },
figureCaption: { nodeType: FigureCaption.name }, figureCaption: { nodeType: FigureCaption.name },
footnoteDefinition: { nodeType: FootnoteDefinition.name },
footnoteReference: { nodeType: FootnoteReference.name },
footnotesSection: { nodeType: FootnotesSection.name },
hardBreak: { nodeType: HardBreak.name }, hardBreak: { nodeType: HardBreak.name },
heading: { nodeType: Heading.name }, heading: { nodeType: Heading.name },
horizontalRule: { nodeType: HorizontalRule.name }, horizontalRule: { nodeType: HorizontalRule.name },
@ -1105,4 +1117,22 @@ there
`.trim(), `.trim(),
); );
}); });
it('correctly serializes footnotes', () => {
expect(
serialize(
paragraph(
'Oranges are orange ',
footnoteReference({ footnoteId: '1', footnoteNumber: '1' }),
),
footnotesSection(footnoteDefinition(paragraph('Oranges are fruits'))),
),
).toBe(
`
Oranges are orange [^1]
[^1]: Oranges are fruits
`.trim(),
);
});
}); });

View File

@ -0,0 +1,220 @@
import { merge } from 'lodash';
import { GlFormInputGroup } from '@gitlab/ui';
import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
describe('InputCopyToggleVisibility', () => {
let wrapper;
afterEach(() => {
wrapper.destroy();
});
const valueProp = 'hR8x1fuJbzwu5uFKLf9e';
const createComponent = (options = {}) => {
wrapper = mountExtended(
InputCopyToggleVisibility,
merge({}, options, {
directives: {
GlTooltip: createMockDirective(),
},
}),
);
};
const findFormInputGroup = () => wrapper.findComponent(GlFormInputGroup);
const findFormInput = () => findFormInputGroup().find('input');
const findRevealButton = () =>
wrapper.findByRole('button', {
name: InputCopyToggleVisibility.i18n.toggleVisibilityLabelReveal,
});
const findHideButton = () =>
wrapper.findByRole('button', {
name: InputCopyToggleVisibility.i18n.toggleVisibilityLabelHide,
});
const findCopyButton = () => wrapper.findComponent(ClipboardButton);
const createCopyEvent = () => {
const event = new Event('copy', { cancelable: true });
Object.assign(event, { preventDefault: jest.fn(), clipboardData: { setData: jest.fn() } });
return event;
};
const itDoesNotModifyCopyEvent = () => {
it('does not modify copy event', () => {
const event = createCopyEvent();
findFormInput().element.dispatchEvent(event);
expect(event.clipboardData.setData).not.toHaveBeenCalled();
expect(event.preventDefault).not.toHaveBeenCalled();
});
};
describe('when `value` prop is passed', () => {
beforeEach(() => {
createComponent({
propsData: {
value: valueProp,
},
});
});
it('displays value as hidden', () => {
expect(findFormInputGroup().props('value')).toBe('********************');
});
it('saves actual value to clipboard when manually copied', () => {
const event = createCopyEvent();
findFormInput().element.dispatchEvent(event);
expect(event.clipboardData.setData).toHaveBeenCalledWith('text/plain', valueProp);
expect(event.preventDefault).toHaveBeenCalled();
});
describe('visibility toggle button', () => {
it('renders a reveal button', () => {
const revealButton = findRevealButton();
expect(revealButton.exists()).toBe(true);
const tooltip = getBinding(revealButton.element, 'gl-tooltip');
expect(tooltip.value).toBe(InputCopyToggleVisibility.i18n.toggleVisibilityLabelReveal);
});
describe('when clicked', () => {
beforeEach(async () => {
await findRevealButton().trigger('click');
});
it('displays value', () => {
expect(findFormInputGroup().props('value')).toBe(valueProp);
});
it('renders a hide button', () => {
const hideButton = findHideButton();
expect(hideButton.exists()).toBe(true);
const tooltip = getBinding(hideButton.element, 'gl-tooltip');
expect(tooltip.value).toBe(InputCopyToggleVisibility.i18n.toggleVisibilityLabelHide);
});
it('emits `visibility-change` event', () => {
expect(wrapper.emitted('visibility-change')[0]).toEqual([true]);
});
});
});
describe('copy button', () => {
it('renders button with correct props passed', () => {
expect(findCopyButton().props()).toMatchObject({
text: valueProp,
title: 'Copy',
});
});
describe('when clicked', () => {
beforeEach(async () => {
await findCopyButton().trigger('click');
});
it('emits `copy` event', () => {
expect(wrapper.emitted('copy')[0]).toEqual([]);
});
});
});
});
describe('when `value` prop is not passed', () => {
beforeEach(() => {
createComponent();
});
it('displays value as hidden with 20 asterisks', () => {
expect(findFormInputGroup().props('value')).toBe('********************');
});
});
describe('when `initialVisibility` prop is `true`', () => {
beforeEach(() => {
createComponent({
propsData: {
value: valueProp,
initialVisibility: true,
},
});
});
it('displays value', () => {
expect(findFormInputGroup().props('value')).toBe(valueProp);
});
itDoesNotModifyCopyEvent();
});
describe('when `showToggleVisibilityButton` is `false`', () => {
beforeEach(() => {
createComponent({
propsData: {
value: valueProp,
showToggleVisibilityButton: false,
},
});
});
it('does not render visibility toggle button', () => {
expect(findRevealButton().exists()).toBe(false);
expect(findHideButton().exists()).toBe(false);
});
it('displays value', () => {
expect(findFormInputGroup().props('value')).toBe(valueProp);
});
itDoesNotModifyCopyEvent();
});
describe('when `showCopyButton` is `false`', () => {
beforeEach(() => {
createComponent({
propsData: {
showCopyButton: false,
},
});
});
it('does not render copy button', () => {
expect(findCopyButton().exists()).toBe(false);
});
});
it('passes `formInputGroupProps` prop to `GlFormInputGroup`', () => {
createComponent({
propsData: {
formInputGroupProps: {
label: 'Foo bar',
},
},
});
expect(findFormInputGroup().props('label')).toBe('Foo bar');
});
it('passes `copyButtonTitle` prop to `ClipboardButton`', () => {
createComponent({
propsData: {
copyButtonTitle: 'Copy token',
},
});
expect(findCopyButton().props('title')).toBe('Copy token');
});
});

View File

@ -90,18 +90,6 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
expect(table_oid('test_partition')).to be_nil expect(table_oid('test_partition')).to be_nil
end end
context 'when the drop_detached_partitions feature flag is disabled' do
before do
stub_feature_flags(drop_detached_partitions: false)
end
it 'does not drop the partition' do
dropper.perform
expect(table_oid('test_partition')).not_to be_nil
end
end
context 'removing foreign keys' do context 'removing foreign keys' do
it 'removes foreign keys from the table before dropping it' do it 'removes foreign keys from the table before dropping it' do
expect(dropper).to receive(:drop_detached_partition).and_wrap_original do |drop_method, partition_name| expect(dropper).to receive(:drop_detached_partition).and_wrap_original do |drop_method, partition_name|

View File

@ -101,11 +101,6 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
] ]
end end
context 'with the partition_pruning feature flag enabled' do
before do
stub_feature_flags(partition_pruning: true)
end
it 'detaches each extra partition' do it 'detaches each extra partition' do
extra_partitions.each { |p| expect(manager).to receive(:detach_one_partition).with(p) } extra_partitions.each { |p| expect(manager).to receive(:detach_one_partition).with(p) }
@ -113,19 +108,6 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
end end
end end
context 'with the partition_pruning feature flag disabled' do
before do
stub_feature_flags(partition_pruning: false)
end
it 'returns immediately' do
expect(manager).not_to receive(:detach)
sync_partitions
end
end
end
describe '#detach_partitions' do describe '#detach_partitions' do
around do |ex| around do |ex|
travel_to(Date.parse('2021-06-23')) do travel_to(Date.parse('2021-06-23')) do

View File

@ -428,6 +428,26 @@ RSpec.describe API::Ci::Jobs do
end end
end end
context 'when job succeeded' do
it 'does not return failure_reason' do
get api("/projects/#{project.id}/jobs/#{job.id}", api_user)
expect(json_response).not_to include('failure_reason')
end
end
context 'when job failed' do
let(:job) do
create(:ci_build, :failed, :tags, pipeline: pipeline)
end
it 'returns failure_reason' do
get api("/projects/#{project.id}/jobs/#{job.id}", api_user)
expect(json_response).to include('failure_reason')
end
end
context 'when trace artifact record exists with no stored file', :skip_before_request do context 'when trace artifact record exists with no stored file', :skip_before_request do
before do before do
create(:ci_job_artifact, :unarchived_trace_artifact, job: job, project: job.project) create(:ci_job_artifact, :unarchived_trace_artifact, job: job, project: job.project)

View File

@ -125,14 +125,6 @@ RSpec.describe Ci::RetryBuildService do
expect(new_build.needs_attributes).to match(build.needs_attributes) expect(new_build.needs_attributes).to match(build.needs_attributes)
expect(new_build.needs).not_to match(build.needs) expect(new_build.needs).not_to match(build.needs)
end end
it 'clones only the job variables attributes' do
expect(new_build.job_variables.exists?).to be_truthy
expect(build.job_variables.exists?).to be_truthy
expect(new_build.job_variables_attributes).to match(build.job_variables_attributes)
expect(new_build.job_variables).not_to match(build.job_variables)
end
end end
describe 'reject accessors' do describe 'reject accessors' do
@ -155,7 +147,7 @@ RSpec.describe Ci::RetryBuildService do
Ci::Build.attribute_names.map(&:to_sym) + Ci::Build.attribute_names.map(&:to_sym) +
Ci::Build.attribute_aliases.keys.map(&:to_sym) + Ci::Build.attribute_aliases.keys.map(&:to_sym) +
Ci::Build.reflect_on_all_associations.map(&:name) + Ci::Build.reflect_on_all_associations.map(&:name) +
[:tag_list, :needs_attributes, :job_variables_attributes] - [:tag_list, :needs_attributes] -
# ee-specific accessors should be tested in ee/spec/services/ci/retry_build_service_spec.rb instead # ee-specific accessors should be tested in ee/spec/services/ci/retry_build_service_spec.rb instead
described_class.extra_accessors - described_class.extra_accessors -
[:dast_site_profiles_build, :dast_scanner_profiles_build] # join tables [:dast_site_profiles_build, :dast_scanner_profiles_build] # join tables

View File

@ -2,6 +2,7 @@
require 'simplecov' require 'simplecov'
require 'simplecov-cobertura' require 'simplecov-cobertura'
require 'simplecov-lcov'
require_relative '../lib/gitlab/utils' require_relative '../lib/gitlab/utils'
module SimpleCovEnv module SimpleCovEnv
@ -18,10 +19,13 @@ module SimpleCovEnv
end end
def configure_formatter def configure_formatter
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::SimpleFormatter, SimpleCov::Formatter::SimpleFormatter,
SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::HTMLFormatter,
SimpleCov::Formatter::CoberturaFormatter SimpleCov::Formatter::CoberturaFormatter,
SimpleCov::Formatter::LcovFormatter
]) ])
end end