Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-04-13 12:11:32 +00:00
parent 37974ac0b1
commit 7ad147d6b8
69 changed files with 580 additions and 507 deletions

View File

@ -1 +1 @@
4ea88e921af65ba0577c40f8b54830c97adaa56c
996add2f4e011cec8e9317912978cf1fa59e66c1

View File

@ -0,0 +1,38 @@
import { CodeBlockHighlight as BaseCodeBlockHighlight } from 'tiptap-extensions';
export default class GlCodeBlockHighlight extends BaseCodeBlockHighlight {
get schema() {
const baseSchema = super.schema;
return {
...baseSchema,
attrs: {
params: {
default: null,
},
},
parseDOM: [
{
tag: 'pre',
preserveWhitespace: 'full',
getAttrs: (node) => {
const code = node.querySelector('code');
if (!code) {
return null;
}
return {
/* `params` is the name of the attribute that
prosemirror-markdown uses to extract the language
of a codeblock.
https://github.com/ProseMirror/prosemirror-markdown/blob/master/src/to_markdown.js#L62
*/
params: code.getAttribute('lang'),
};
},
},
],
};
}
}

View File

@ -1,7 +1,20 @@
import { isFunction, isString } from 'lodash';
import { Editor } from 'tiptap';
import { Bold, Code } from 'tiptap-extensions';
import {
Bold,
Italic,
Code,
Link,
Image,
Heading,
Blockquote,
HorizontalRule,
BulletList,
OrderedList,
ListItem,
} from 'tiptap-extensions';
import { PROVIDE_SERIALIZER_OR_RENDERER_ERROR } from '../constants';
import CodeBlockHighlight from '../extensions/code_block_highlight';
import createMarkdownSerializer from './markdown_serializer';
const createEditor = async ({ content, renderMarkdown, serializer: customSerializer } = {}) => {
@ -10,7 +23,20 @@ const createEditor = async ({ content, renderMarkdown, serializer: customSeriali
}
const editor = new Editor({
extensions: [new Bold(), new Code()],
extensions: [
new Bold(),
new Italic(),
new Code(),
new Link(),
new Image(),
new Heading({ levels: [1, 2, 3, 4, 5, 6] }),
new Blockquote(),
new HorizontalRule(),
new BulletList(),
new ListItem(),
new OrderedList(),
new CodeBlockHighlight(),
],
});
const serializer = customSerializer || createMarkdownSerializer({ render: renderMarkdown });

View File

@ -60,9 +60,12 @@ const create = ({ render = () => null }) => {
// creates a bold alias for the strong mark converter
...defaultMarkdownSerializer.marks.strong,
},
italic: { open: '_', close: '_', mixable: true, expelEnclosingWhitespace: true },
});
return serializer.serialize(document);
return serializer.serialize(document, {
tightLists: true,
});
},
};
};

View File

@ -184,12 +184,7 @@ export default {
'viewDiffsFileByFile',
'mrReviews',
]),
...mapGetters('diffs', [
'whichCollapsedTypes',
'isParallelView',
'currentDiffIndex',
'fileCodequalityDiff',
]),
...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']),
...mapGetters(['isNotesFetched', 'getNoteableData']),
diffs() {
if (!this.viewDiffsFileByFile) {
@ -287,7 +282,6 @@ export default {
endpointMetadata: this.endpointMetadata,
endpointBatch: this.endpointBatch,
endpointCoverage: this.endpointCoverage,
endpointCodequality: this.endpointCodequality,
endpointUpdateUser: this.endpointUpdateUser,
projectPath: this.projectPath,
dismissEndpoint: this.dismissEndpoint,
@ -297,6 +291,10 @@ export default {
mrReviews: this.rehydratedMrReviews,
});
if (this.endpointCodequality) {
this.setCodequalityEndpoint(this.endpointCodequality);
}
if (this.shouldShow) {
this.fetchData();
}
@ -341,6 +339,7 @@ export default {
...mapActions('diffs', [
'moveToNeighboringCommit',
'setBaseConfig',
'setCodequalityEndpoint',
'fetchDiffFilesMeta',
'fetchDiffFilesBatch',
'fetchCoverageFiles',
@ -532,7 +531,6 @@ export default {
:help-page-path="helpPagePath"
:can-current-user-fork="canCurrentUserFork"
:view-diffs-file-by-file="viewDiffsFileByFile"
:codequality-diff="fileCodequalityDiff(file.file_path)"
/>
<div
v-if="showFileByFileNavigation"

View File

@ -67,11 +67,6 @@ export default {
type: Boolean,
required: true,
},
codequalityDiff: {
type: Array,
required: false,
default: () => [],
},
},
data() {
return {
@ -85,7 +80,7 @@ export default {
genericError: GENERIC_ERROR,
},
computed: {
...mapState('diffs', ['currentDiffFileId']),
...mapState('diffs', ['currentDiffFileId', 'codequalityDiff']),
...mapGetters(['isNotesFetched']),
...mapGetters('diffs', ['getDiffFileDiscussions']),
viewBlobHref() {
@ -154,7 +149,9 @@ export default {
return loggedIn && featureOn;
},
hasCodequalityChanges() {
return this.codequalityDiff.length > 0;
return (
this.codequalityDiff?.files && this.codequalityDiff?.files[this.file.file_path]?.length > 0
);
},
},
watch: {

View File

@ -1,5 +1,4 @@
import Cookies from 'js-cookie';
import Visibility from 'visibilityjs';
import Vue from 'vue';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { diffViewerModes } from '~/ide/constants';
@ -53,15 +52,12 @@ import {
prepareLineForRenamedFile,
} from './utils';
let eTagPoll;
export const setBaseConfig = ({ commit }, options) => {
const {
endpoint,
endpointMetadata,
endpointBatch,
endpointCoverage,
endpointCodequality,
endpointUpdateUser,
projectPath,
dismissEndpoint,
@ -75,7 +71,6 @@ export const setBaseConfig = ({ commit }, options) => {
endpointMetadata,
endpointBatch,
endpointCoverage,
endpointCodequality,
endpointUpdateUser,
projectPath,
dismissEndpoint,
@ -238,48 +233,6 @@ export const fetchCoverageFiles = ({ commit, state }) => {
coveragePoll.makeRequest();
};
export const clearEtagPoll = () => {
eTagPoll = null;
};
export const stopCodequalityPolling = () => {
if (eTagPoll) eTagPoll.stop();
};
export const restartCodequalityPolling = () => {
if (eTagPoll) eTagPoll.restart();
};
export const fetchCodequality = ({ commit, state, dispatch }) => {
eTagPoll = new Poll({
resource: {
getCodequalityDiffReports: (endpoint) => axios.get(endpoint),
},
data: state.endpointCodequality,
method: 'getCodequalityDiffReports',
successCallback: ({ status, data }) => {
if (status === httpStatusCodes.OK) {
commit(types.SET_CODEQUALITY_DATA, data);
eTagPoll.stop();
}
},
errorCallback: () => createFlash(__('Something went wrong on our end. Please try again!')),
});
if (!Visibility.hidden()) {
eTagPoll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
dispatch('restartCodequalityPolling');
} else {
dispatch('stopCodequalityPolling');
}
});
};
export const setHighlightedRow = ({ commit }, lineCode) => {
const fileHash = lineCode.split('_')[0];
commit(types.SET_HIGHLIGHTED_ROW, lineCode);

View File

@ -135,16 +135,6 @@ export const fileLineCoverage = (state) => (file, line) => {
return {};
};
/**
* Returns the codequality diff data for a given file
* @param {string} filePath
* @returns {Array}
*/
export const fileCodequalityDiff = (state) => (filePath) => {
if (!state.codequalityDiff.files || !state.codequalityDiff.files[filePath]) return [];
return state.codequalityDiff.files[filePath];
};
/**
* Returns index of a currently selected diff in diffFiles
* @returns {number}

View File

@ -29,7 +29,6 @@ export default () => ({
startVersion: null, // Null unless a target diff is selected for comparison that is not the "base" diff
diffFiles: [],
coverageFiles: {},
codequalityDiff: {},
mergeRequestDiffs: [],
mergeRequestDiff: null,
diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType,

View File

@ -1,7 +1,7 @@
import * as actions from '../actions';
import * as actions from 'ee_else_ce/diffs/store/actions';
import createState from 'ee_else_ce/diffs/store/modules/diff_state';
import mutations from 'ee_else_ce/diffs/store/mutations';
import * as getters from '../getters';
import mutations from '../mutations';
import createState from './diff_state';
export default () => ({
namespaced: true,

View File

@ -11,7 +11,6 @@ export const SET_MR_FILE_REVIEWS = 'SET_MR_FILE_REVIEWS';
export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE';
export const SET_COVERAGE_DATA = 'SET_COVERAGE_DATA';
export const SET_CODEQUALITY_DATA = 'SET_CODEQUALITY_DATA';
export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS';
export const TOGGLE_LINE_HAS_FORM = 'TOGGLE_LINE_HAS_FORM';
export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES';

View File

@ -33,7 +33,6 @@ export default {
endpointMetadata,
endpointBatch,
endpointCoverage,
endpointCodequality,
endpointUpdateUser,
projectPath,
dismissEndpoint,
@ -47,7 +46,6 @@ export default {
endpointMetadata,
endpointBatch,
endpointCoverage,
endpointCodequality,
endpointUpdateUser,
projectPath,
dismissEndpoint,
@ -91,10 +89,6 @@ export default {
Object.assign(state, { coverageFiles });
},
[types.SET_CODEQUALITY_DATA](state, codequalityDiffData) {
Object.assign(state, { codequalityDiff: codequalityDiffData });
},
[types.RENDER_FILE](state, file) {
renderFile(file);
},

View File

@ -1,5 +1,6 @@
<script>
import { GlButton, GlCard, GlSprintf } from '@gitlab/ui';
import ExperimentTracking from '~/experimentation/experiment_tracking';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { s__, sprintf } from '~/locale';
import { HELLO_WORLD_TEMPLATE_KEY } from '../../constants';
@ -10,6 +11,7 @@ export default {
GlCard,
GlSprintf,
},
HELLO_WORLD_TEMPLATE_KEY,
i18n: {
cta: s__('Pipelines|Use template'),
testTemplates: {
@ -51,6 +53,14 @@ export default {
),
};
},
methods: {
trackEvent(template) {
const tracking = new ExperimentTracking('pipeline_empty_state_templates', {
label: template,
});
tracking.event('template_clicked');
},
},
};
</script>
<template>
@ -82,6 +92,7 @@ export default {
variant="confirm"
:href="helloWorldTemplateUrl"
data-testid="test-template-link"
@click="trackEvent($options.HELLO_WORLD_TEMPLATE_KEY)"
>
{{ $options.i18n.cta }}
</gl-button>
@ -121,6 +132,7 @@ export default {
variant="confirm"
:href="template.link"
data-testid="template-link"
@click="trackEvent(template.name)"
>
{{ $options.i18n.cta }}
</gl-button>

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
module MergeRequests
class ResolveTodosService
include BaseServiceUtility
def initialize(merge_request, user)
@merge_request = merge_request
@user = user
end
def async_execute
if Feature.enabled?(:resolve_merge_request_todos_async, merge_request.target_project, default_enabled: :yaml)
MergeRequests::ResolveTodosWorker.perform_async(merge_request.id, user.id)
else
execute
end
end
def execute
todo_service.resolve_todos_for_target(merge_request, user)
end
private
attr_reader :merge_request, :user
end
end

View File

@ -147,7 +147,11 @@ module MergeRequests
def resolve_todos(merge_request, old_labels, old_assignees, old_reviewers)
return unless has_changes?(merge_request, old_labels: old_labels, old_assignees: old_assignees, old_reviewers: old_reviewers)
todo_service.resolve_todos_for_target(merge_request, current_user)
service_user = current_user
merge_request.run_after_commit_or_now do
::MergeRequests::ResolveTodosService.new(merge_request, service_user).async_execute
end
end
def handle_target_branch_change(merge_request)

View File

@ -20,20 +20,20 @@
.float-right
- if impersonation_enabled? && @user != current_user && @user.can?(:log_in)
= link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-info gl-button btn-grouped", data: { qa_selector: 'impersonate_user_link' }
= link_to _('Impersonate'), impersonate_admin_user_path(@user), method: :post, class: "btn btn-info gl-button btn-grouped", data: { qa_selector: 'impersonate_user_link' }
= link_to edit_admin_user_path(@user), class: "btn btn-default gl-button btn-grouped" do
= sprite_icon('pencil-square', css_class: 'gl-icon gl-button-icon')
= _('Edit')
%hr
%ul.nav-links.nav.nav-tabs
= nav_link(path: 'users#show') do
= link_to "Account", admin_user_path(@user)
= link_to _("Account"), admin_user_path(@user)
= nav_link(path: 'users#projects') do
= link_to "Groups and projects", projects_admin_user_path(@user)
= link_to _("Groups and projects"), projects_admin_user_path(@user)
= nav_link(path: 'users#keys') do
= link_to "SSH keys", keys_admin_user_path(@user)
= link_to _("SSH keys"), keys_admin_user_path(@user)
= nav_link(controller: :identities) do
= link_to "Identities", admin_user_identities_path(@user)
= link_to _("Identities"), admin_user_identities_path(@user)
= nav_link(controller: :impersonation_tokens) do
= link_to "Impersonation Tokens", admin_user_impersonation_tokens_path(@user)
= link_to _("Impersonation Tokens"), admin_user_impersonation_tokens_path(@user)
.gl-mb-3

View File

@ -3,16 +3,16 @@
.table-mobile-header{ role: 'rowheader' }= _('Type')
.table-mobile-content
- if runner.group_type?
%span.badge.badge-success
%span.badge.badge-pill.gl-badge.sm.badge-success
= _('group')
- else
%span.badge.badge-info
%span.badge.badge-pill.gl-badge.sm.badge-info
= _('specific')
- if runner.locked?
%span.badge.badge-warning
%span.badge.badge-pill.gl-badge.sm.badge-warning
= _('locked')
- unless runner.active?
%span.badge.badge-danger
%span.badge.badge-pill.gl-badge.sm.badge-danger
= _('paused')
.table-section.section-10

View File

@ -19,7 +19,7 @@
.float-right
%span.key-created-at
= s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago: time_ago_with_tooltip(key.created_at) }
= link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-danger gl-ml-3" do
= link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-icon btn-danger gl-ml-3" do
%span.sr-only= _('Remove')
= sprite_icon('remove')
= link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "gl-button btn btn-danger gl-ml-3" do

View File

@ -1908,6 +1908,14 @@
:weight: 1
:idempotent: true
:tags: []
- :name: merge_requests_resolve_todos
:feature_category: :code_review
:has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
- :name: metrics_dashboard_prune_old_annotations
:feature_category: :metrics
:has_external_dependencies:

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class MergeRequests::ResolveTodosWorker
include ApplicationWorker
feature_category :code_review
urgency :high
deduplicate :until_executed
idempotent!
def perform(merge_request_id, user_id)
merge_request = MergeRequest.find(merge_request_id)
user = User.find(user_id)
MergeRequests::ResolveTodosService.new(merge_request, user).execute
rescue ActiveRecord::RecordNotFound
end
end

View File

@ -0,0 +1,5 @@
---
title: Resolve merge request todos asynchronously on update
merge_request: 58647
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Externalise strings in admin/users/_head.html.haml
merge_request: 58101
author: nuwe1
type: other

View File

@ -0,0 +1,5 @@
---
title: Add user index on spam logs
merge_request: 59151
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Add btn-icon class for GPG key delete button
merge_request: 57974
author: Yogi (@yo)
type: changed

View File

@ -0,0 +1,5 @@
---
title: Update metric definition under verify testing group
merge_request: 59028
author:
type: other

View File

@ -0,0 +1,8 @@
---
name: resolve_merge_request_todos_async
introduced_by_url:
rollout_issue_url:
milestone: '13.11'
type: development
group: group::code review
default_enabled: false

View File

@ -17,4 +17,3 @@ tier:
- free
- premium
- ultimate
skip_validation: true

View File

@ -1,20 +0,0 @@
---
key_path: redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_monthly
description: Internal Tracking to count number of unit tests parsed for planning of
future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0)
product_section: ops
product_stage: verify
product_group: group::testing
product_category: code_testing
value_type: number
status: data_available
time_frame: 28d
data_source: redis_hll
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
skip_validation: true

View File

@ -1,16 +0,0 @@
---
key_path: counts_monthly.aggregated_metrics.i_testing_paid_monthly_active_user_total
description: ''
product_section: ''
product_stage: ''
product_group: ''
product_category: ''
value_type: number
status: data_available
time_frame: 28d
data_source: database
distribution:
- ce
tier:
- free
skip_validation: true

View File

@ -6,11 +6,10 @@ product_stage: ''
product_group: ''
product_category: ''
value_type: number
status: data_available
status: removed
time_frame: 28d
data_source: redis_hll
distribution:
- ce
tier:
- free
skip_validation: true

View File

@ -17,4 +17,3 @@ tier:
- free
- premium
- ultimate
skip_validation: true

View File

@ -1,20 +0,0 @@
---
key_path: redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_weekly
description: Internal Tracking to count number of unit tests parsed for planning of
future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0)
product_section: ops
product_stage: verify
product_group: group::testing
product_category: code_testing
value_type: number
status: data_available
time_frame: 7d
data_source: redis_hll
distribution:
- ee
- ce
tier:
- free
- premium
- ultimate
skip_validation: true

View File

@ -218,6 +218,8 @@
- 1
- - merge_requests_handle_assignees_change
- 1
- - merge_requests_resolve_todos
- 1
- - metrics_dashboard_prune_old_annotations
- 1
- - metrics_dashboard_sync_dashboards

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddUserIndexOnSpamLogs < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
INDEX_NAME = 'index_spam_logs_on_user_id'
def up
add_concurrent_index :spam_logs, :user_id, name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :spam_logs, INDEX_NAME
end
end

View File

@ -6,13 +6,13 @@ class BackfillEventsIdForBigintConversion < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
return unless Gitlab.dev_env_or_com?
return unless should_run?
backfill_conversion_of_integer_to_bigint :events, :id, batch_size: 15000, sub_batch_size: 100
end
def down
return unless Gitlab.dev_env_or_com?
return unless should_run?
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
@ -20,4 +20,10 @@ class BackfillEventsIdForBigintConversion < ActiveRecord::Migration[6.0]
.where('job_arguments = ?', %w[id id_convert_to_bigint].to_json)
.delete_all
end
private
def should_run?
Gitlab.dev_or_test_env? || Gitlab.com?
end
end

View File

@ -6,14 +6,14 @@ class BackfillPushEventPayloadEventIdForBigintConversion < ActiveRecord::Migrati
DOWNTIME = false
def up
return unless Gitlab.dev_env_or_com?
return unless should_run?
backfill_conversion_of_integer_to_bigint :push_event_payloads, :event_id, primary_key: :event_id,
batch_size: 15000, sub_batch_size: 100
end
def down
return unless Gitlab.dev_env_or_com?
return unless should_run?
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
@ -21,4 +21,10 @@ class BackfillPushEventPayloadEventIdForBigintConversion < ActiveRecord::Migrati
.where('job_arguments = ?', %w[event_id event_id_convert_to_bigint].to_json)
.delete_all
end
private
def should_run?
Gitlab.dev_or_test_env? || Gitlab.com?
end
end

View File

@ -0,0 +1 @@
4a1435a56b8e5cddd83b844f84374bca91810bbfc5f44faf2a53fd41f93be69c

View File

@ -23942,6 +23942,8 @@ CREATE UNIQUE INDEX index_sop_configs_on_project_id ON security_orchestration_po
CREATE INDEX index_sop_configurations_project_id_policy_project_id ON security_orchestration_policy_configurations USING btree (security_policy_management_project_id, project_id);
CREATE INDEX index_spam_logs_on_user_id ON spam_logs USING btree (user_id);
CREATE INDEX index_sprints_iterations_cadence_id ON sprints USING btree (iterations_cadence_id);
CREATE INDEX index_sprints_on_description_trigram ON sprints USING gin (description gin_trgm_ops);

View File

@ -281,7 +281,6 @@ WARNING:
This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place.
- Pushing directly to a **secondary** node redirects (for HTTP) or proxies (for SSH) the request to the **primary** node instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381), except when using Git over HTTP with credentials embedded within the URI. For example, `https://user:password@secondary.tld`.
- Cloning, pulling, or pushing repositories that exist on the **primary** node but not on the **secondary** nodes where [selective synchronization](replication/configuration.md#selective-synchronization) does not include the project is not supported over SSH [but support is planned](https://gitlab.com/groups/gitlab-org/-/epics/2562). HTTP(S) is supported.
- The **primary** node has to be online for OAuth login to happen. Existing sessions and Git are not affected. Support for the **secondary** node to use an OAuth provider independent from the primary is [being planned](https://gitlab.com/gitlab-org/gitlab/-/issues/208465).
- The installation takes multiple manual steps that together can take about an hour depending on circumstances. We are working on improving this experience. See [Omnibus GitLab issue #2978](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/2978) for details.
- Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** node.
@ -289,6 +288,7 @@ This list of limitations only reflects the latest version of GitLab. If you are
- Object pools for forked project deduplication work only on the **primary** node, and are duplicated on the **secondary** node.
- GitLab Runners cannot register with a **secondary** node. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294).
- Geo **secondary** nodes can not be configured to [use high-availability configurations of PostgreSQL](https://gitlab.com/groups/gitlab-org/-/epics/2536).
- [Selective synchronization](replication/configuration.md#selective-synchronization) only limits what repositories are replicated. The entire PostgreSQL data is still replicated. Selective synchronization is not built to accomodate compliance / export control use cases.
### Limitations on replication/verification

View File

@ -332,12 +332,13 @@ can see it.
## Run the spec
Before running the spec, confirm:
Before running the spec, make sure that:
- The GDK is installed.
- The GDK is running on port 3000 locally.
- GDK is installed.
- GDK is running locally on port 3000.
- No additional [RSpec metadata tags](rspec_metadata_tests.md) have been applied.
- Your working directory is `qa/` within your GDK GitLab installation.
- Your GitLab instance-level settings are default. If you changed the default settings, some tests might have unexpected results.
To run the spec, run the following command:

View File

@ -6106,15 +6106,15 @@ Tiers: `free`
### `counts_monthly.aggregated_metrics.i_testing_paid_monthly_active_user_total`
Missing description
Aggregated count of users who have engaged with a Premium or Ultimate tier testing feature per month.
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml)
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml)
Group: ``
Group: `group::testing`
Status: `data_available`
Tiers: `free`
Tiers: `premium`, `ultimate`
### `counts_monthly.aggregated_metrics.incident_management_alerts_total_unique_counts`
@ -6274,15 +6274,15 @@ Tiers:
### `counts_weekly.aggregated_metrics.i_testing_paid_monthly_active_user_total`
Missing description
Aggregated count of users who have engaged with a Premium or Ultimate tier testing feature per week.
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216183219_i_testing_paid_monthly_active_user_total.yml)
Group: ``
Group: `group::testing`
Status: `data_available`
Tiers:
Tiers: `premium`, `ultimate`
### `counts_weekly.aggregated_metrics.incident_management_alerts_total_unique_counts`
@ -13654,7 +13654,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_full_code_quality_report_total_weekly`
Count of unique users per week|month who visit the full code quality report
Count of unique users per week who visit the full code quality report
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182145_i_testing_full_code_quality_report_total_weekly.yml)
@ -13666,7 +13666,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_group_code_coverage_project_click_total_monthly`
Count of unique users per week|month who click on a project link in the group code coverage table
Aggregated count of unique users who have clicked from group code coverage page to an individual project page each month.
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182153_i_testing_group_code_coverage_project_click_total_monthly.yml)
@ -13678,19 +13678,19 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_group_code_coverage_project_click_total_weekly`
Missing description
Aggregated count of unique users who have clicked from group code coverage page to an individual project page each week.
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216184132_i_testing_group_code_coverage_project_click_total_weekly.yml)
Group: ``
Group: `group::testing`
Status: `data_available`
Tiers:
Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_group_code_coverage_visit_total_monthly`
Count of unique users per week|month who visited the group code coverage page
Count of unique users per month who visited the group code coverage page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182143_i_testing_group_code_coverage_visit_total_monthly.yml)
@ -13702,7 +13702,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_group_code_coverage_visit_total_weekly`
Count of unique users per week|month who visited the group code coverage page
Count of unique users per week who visited the group code coverage page
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182141_i_testing_group_code_coverage_visit_total_weekly.yml)
@ -13714,7 +13714,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_load_performance_widget_total_monthly`
Count of unique users per week|month who expanded the load performance report MR widget
Count of unique users per month who expanded the load performance report MR widget
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182156_i_testing_load_performance_widget_total_monthly.yml)
@ -13726,7 +13726,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_load_performance_widget_total_weekly`
Count of unique users per week|month who expanded the load performance report MR widget
Count of unique users per week who expanded the load performance report MR widget
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182154_i_testing_load_performance_widget_total_weekly.yml)
@ -13738,31 +13738,31 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_monthly`
Internal Tracking to count number of unit tests parsed for planning of future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0)
Tracks number of metrics reports uploaded monthly.
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml)
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml)
Group: `group::testing`
Status: `data_available`
Tiers: `free`, `premium`, `ultimate`
Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_weekly`
Internal Tracking to count number of unit tests parsed for planning of future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0)
Count of unique users per week who trigger a pipeline that uploads a metrics report.
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml)
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml)
Group: `group::testing`
Status: `data_available`
Tiers: `free`, `premium`, `ultimate`
Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_metrics_report_widget_total_monthly`
Count of unique users per week|month who expanded the metrics report MR widget
Count of unique users per month who expanded the metrics report MR widget
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182139_i_testing_metrics_report_widget_total_monthly.yml)
@ -13774,7 +13774,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_metrics_report_widget_total_weekly`
Count of unique users per week|month who expanded the metrics report MR widget
Count of unique users per week who expanded the metrics report MR widget
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182138_i_testing_metrics_report_widget_total_weekly.yml)
@ -13810,7 +13810,7 @@ Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_web_performance_widget_total_monthly`
Count of unique users per week|month who expanded the browser performance report MR widget
Count of unique users per month who expanded the browser performance report MR widget
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182151_i_testing_web_performance_widget_total_monthly.yml)
@ -13822,7 +13822,7 @@ Tiers: `premium`, `ultimate`
### `redis_hll_counters.testing.i_testing_web_performance_widget_total_weekly`
Count of unique users per week|month who expanded the browser performance report MR widget
Count of unique users per week who expanded the browser performance report MR widget
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182149_i_testing_web_performance_widget_total_weekly.yml)
@ -13840,7 +13840,7 @@ Missing description
Group: ``
Status: `data_available`
Status: `removed`
Tiers: `free`
@ -13852,9 +13852,9 @@ Missing description
Group: ``
Status: `data_available`
Status: `removed`
Tiers:
Tiers: `premium`, `ultimate`
### `redis_hll_counters.user_packages.i_package_composer_user_monthly`

View File

@ -36,7 +36,7 @@ The following table describes the version types and their release cadence:
| Version type | Description | Cadence |
|:-------------|:------------|:--------|
| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 14.0 on May 22, 2021. Subsequent major releases will be scheduled for May 22 each year, by default. |
| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 14.0 on June 22, 2021 (one month later than typical, details in [this issue](https://gitlab.com/gitlab-com/Product/-/issues/2337)). Subsequent major releases will be scheduled for May 22 each year, by default. |
| Minor | For when new backward-compatible functionality is introduced to the public API, a minor feature is introduced, or when a set of smaller features is rolled out. | Monthly on the 22nd. |
| Patch | For backward-compatible bug fixes that fix incorrect behavior. See [Patch releases](#patch-releases). | As needed. |

View File

@ -323,14 +323,6 @@ in a comment or description field.
Assignees in the sidebar are updated in real time. This feature is **disabled by default**.
To enable it, you need to enable [ActionCable in-app mode](https://docs.gitlab.com/omnibus/settings/actioncable.html).
## Cached issue count **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/243753) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/323493) in GitLab 13.11.
In a group, the sidebar displays the total count of open issues and this value is cached if higher
than 1000. The cached value is rounded to thousands (or millions) and updated every 24 hours.
## Similar issues
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22866) in GitLab 11.6.

View File

@ -5,7 +5,7 @@ group: Release
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Create a Pages website from a new project template
# Create a Pages website from a template
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47857) in GitLab 11.8.

View File

@ -49,7 +49,7 @@ To create a GitLab Pages website:
| [Create a `gitlab-ci.yml` file from scratch](getting_started/pages_from_scratch.md) | Add a Pages site to an existing project. Learn how to create and configure your own CI file. |
| [Use a `.gitlab-ci.yml` template](getting_started/pages_ci_cd_template.md) | Add a Pages site to an existing project. Use a pre-populated CI template file. |
| [Fork a sample project](getting_started/pages_forked_sample_project.md) | Create a new project with Pages already configured by forking a sample project. |
| [Use a new project template](getting_started/pages_new_project_template.md) | Create a new project with Pages already configured by using a new project template. |
| [Use a project template](getting_started/pages_new_project_template.md) | Create a new project with Pages already configured by using a template. |
To update a GitLab Pages website:

View File

@ -142,14 +142,10 @@ module Gitlab
end
def job_variables
return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
variables_value.to_h
end
def root_variables_inheritance
return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
inherit_entry&.variables_entry&.value
end

View File

@ -44,7 +44,7 @@ module Gitlab
name: name,
instance: instance,
variables: variables, # https://gitlab.com/gitlab-org/gitlab/-/issues/300581
job_variables: job_variables,
job_variables: variables,
parallel: { total: total }
}.compact
end
@ -61,12 +61,6 @@ module Gitlab
private
attr_reader :job_name, :instance, :variables, :total
def job_variables
return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
variables
end
end
end
end

View File

@ -11,7 +11,7 @@ module Gitlab
def perform!
raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result
if ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
if ::Feature.enabled?(:ci_workflow_rules_variables, pipeline.project, default_enabled: :yaml)
raise ArgumentError, 'missing workflow rules result' unless @command.workflow_rules_result
end
@ -51,7 +51,7 @@ module Gitlab
end
def root_variables
if ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
if ::Feature.enabled?(:ci_workflow_rules_variables, pipeline.project, default_enabled: :yaml)
::Gitlab::Ci::Variables::Helpers.merge_variables(
@command.yaml_processor_result.root_variables, @command.workflow_rules_result.variables
)

View File

@ -213,7 +213,7 @@ module Gitlab
end
def recalculate_yaml_variables!
return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
return unless ::Feature.enabled?(:ci_workflow_rules_variables, @pipeline.project, default_enabled: :yaml)
@seed_attributes[:yaml_variables] = Gitlab::Ci::Variables::Helpers.inherit_yaml_variables(
from: @context.root_variables, to: @job_variables, inheritance: @root_variables_inheritance

View File

@ -190,11 +190,7 @@ module Gitlab
migration_status = batch_max_value.nil? ? :finished : :active
batch_max_value ||= batch_min_value
# We keep track of the estimated number of tuples to reason later
# about the overall progress of a migration.
total_tuple_count = Gitlab::Database::PgClass.for_table(batch_table_name)&.cardinality_estimate
Gitlab::Database::BackgroundMigration::BatchedMigration.create!(
migration = Gitlab::Database::BackgroundMigration::BatchedMigration.create!(
job_class_name: job_class_name,
table_name: batch_table_name,
column_name: batch_column_name,
@ -205,8 +201,18 @@ module Gitlab
batch_size: batch_size,
sub_batch_size: sub_batch_size,
job_arguments: job_arguments,
status: migration_status,
total_tuple_count: total_tuple_count)
status: migration_status)
# This guard is necessary since #total_tuple_count was only introduced schema-wise,
# after this migration helper had been used for the first time.
return migration unless migration.respond_to?(:total_tuple_count)
# We keep track of the estimated number of tuples to reason later
# about the overall progress of a migration.
migration.total_tuple_count = Gitlab::Database::PgClass.for_table(batch_table_name)&.cardinality_estimate
migration.save!
migration
end
def perform_background_migration_inline?

View File

@ -55,7 +55,7 @@ module Gitlab
{
tag_list: tags || [],
yaml_variables: yaml_variables, # https://gitlab.com/gitlab-org/gitlab/-/issues/300581
job_variables: job_variables,
job_variables: yaml_variables,
options: {
image: image_value,
services: services_value,
@ -74,12 +74,6 @@ module Gitlab
end
end
end
def job_variables
return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml)
yaml_variables
end
end
end
end

View File

@ -16044,6 +16044,9 @@ msgstr ""
msgid "ImageViewerDimensions|W"
msgstr ""
msgid "Impersonate"
msgstr ""
msgid "Impersonation Tokens"
msgstr ""
@ -27173,6 +27176,9 @@ msgstr ""
msgid "SSH key"
msgstr ""
msgid "SSH keys"
msgstr ""
msgid "SSH keys allow you to establish a secure connection between your computer and GitLab."
msgstr ""
@ -27669,7 +27675,7 @@ msgstr ""
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
msgid "SecurityOrchestration|A security policy project can be used enforce policies for a given project, group, or instance. It allows you to speficy security policies that are important to you and enforce them with every commit."
msgid "SecurityOrchestration|A security policy project can be used enforce policies for a given project, group, or instance. It allows you to specify security policies that are important to you and enforce them with every commit."
msgstr ""
msgid "SecurityOrchestration|Create a policy"
@ -29017,6 +29023,9 @@ msgstr ""
msgid "Something went wrong on our end"
msgstr ""
msgid "Something went wrong on our end while loading the code quality diff."
msgstr ""
msgid "Something went wrong on our end."
msgstr ""
@ -30988,7 +30997,7 @@ msgstr ""
msgid "The merge request can now be merged."
msgstr ""
msgid "The merge request has been updated, and the number of code quality violations in this file has changed."
msgid "The merge request has made changes to this file that affect the number of code quality violations in it."
msgstr ""
msgid "The metric must be one of %{metrics}."

View File

@ -176,11 +176,11 @@
"commander": "^2.18.0",
"custom-jquery-matchers": "^2.1.0",
"docdash": "^1.0.2",
"eslint": "7.21.0",
"eslint": "7.24.0",
"eslint-import-resolver-jest": "3.0.0",
"eslint-import-resolver-webpack": "0.13.0",
"eslint-plugin-jasmine": "4.1.2",
"eslint-plugin-no-jquery": "2.5.0",
"eslint-plugin-no-jquery": "2.6.0",
"gettext-extractor": "^3.5.3",
"gettext-extractor-vue": "^5.0.0",
"glob": "^7.1.6",

View File

@ -225,6 +225,10 @@ module QA
)
end
def health_check_failure_message?(msg)
['error when pinging healthcheck', 'failed checking node health'].include?(msg)
end
def wait_for_no_praefect_storage_error
# If a healthcheck error was the last message to be logged, we'll keep seeing that message even if it's no longer a problem
# That is, there's no message shown in the Praefect logs when the healthcheck succeeds
@ -241,7 +245,7 @@ module QA
QA::Runtime::Logger.debug(line.chomp)
log = JSON.parse(line)
break true if log['msg'] != 'error when pinging healthcheck'
break true unless health_check_failure_message?(log['msg'])
rescue JSON::ParserError
# Ignore lines that can't be parsed as JSON
end
@ -302,7 +306,7 @@ module QA
QA::Runtime::Logger.debug(line.chomp)
log = JSON.parse(line)
log['msg'] == 'error when pinging healthcheck' && log['storage'] == node
health_check_failure_message?(log['msg']) && log['storage'] == node
rescue JSON::ParserError
# Ignore lines that can't be parsed as JSON
end

View File

@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
context 'Gitaly', :orchestrated, :mtls, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/324622', type: :investigating } do
context 'Gitaly', :orchestrated, :mtls do
describe 'Using mTLS' do
let(:intial_commit_message) { 'Initial commit' }
let(:first_added_commit_message) { 'commit over git' }

View File

@ -52,7 +52,8 @@ module GitalyTest
'RUBYOPT' => nil,
# Git hooks can't run during tests as the internal API is not running.
'GITALY_TESTING_NO_GIT_HOOKS' => "1"
'GITALY_TESTING_NO_GIT_HOOKS' => "1",
'GITALY_TESTING_ENABLE_ALL_FEATURE_FLAGS' => "true"
}
env_hash

View File

@ -17,9 +17,6 @@ import {
fetchDiffFilesBatch,
fetchDiffFilesMeta,
fetchCoverageFiles,
clearEtagPoll,
stopCodequalityPolling,
fetchCodequality,
assignDiscussionsToDiff,
removeDiscussionsFromDiff,
startRenderDiffsQueue,
@ -101,7 +98,6 @@ describe('DiffsStoreActions', () => {
const endpointMetadata = '/diffs/set/endpoint/metadata';
const endpointBatch = '/diffs/set/endpoint/batch';
const endpointCoverage = '/diffs/set/coverage_reports';
const endpointCodequality = '/diffs/set/codequality_diff';
const projectPath = '/root/project';
const dismissEndpoint = '/-/user_callouts';
const showSuggestPopover = false;
@ -113,7 +109,6 @@ describe('DiffsStoreActions', () => {
endpointBatch,
endpointMetadata,
endpointCoverage,
endpointCodequality,
projectPath,
dismissEndpoint,
showSuggestPopover,
@ -123,7 +118,6 @@ describe('DiffsStoreActions', () => {
endpointBatch: '',
endpointMetadata: '',
endpointCoverage: '',
endpointCodequality: '',
projectPath: '',
dismissEndpoint: '',
showSuggestPopover: true,
@ -136,7 +130,6 @@ describe('DiffsStoreActions', () => {
endpointMetadata,
endpointBatch,
endpointCoverage,
endpointCodequality,
projectPath,
dismissEndpoint,
showSuggestPopover,
@ -306,47 +299,6 @@ describe('DiffsStoreActions', () => {
});
});
describe('fetchCodequality', () => {
let mock;
const endpointCodequality = '/fetch';
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
stopCodequalityPolling();
clearEtagPoll();
});
it('should commit SET_CODEQUALITY_DATA with received response', (done) => {
const data = {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
};
mock.onGet(endpointCodequality).reply(200, { data });
testAction(
fetchCodequality,
{},
{ endpointCodequality },
[{ type: types.SET_CODEQUALITY_DATA, payload: { data } }],
[],
done,
);
});
it('should show flash on API error', (done) => {
mock.onGet(endpointCodequality).reply(400);
testAction(fetchCodequality, {}, { endpointCodequality }, [], [], () => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(expect.stringMatching('Something went wrong'));
done();
});
});
});
describe('setHighlightedRow', () => {
it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => {
testAction(setHighlightedRow, 'ABC_123', {}, [

View File

@ -376,26 +376,6 @@ describe('Diffs Module Getters', () => {
});
});
describe('fileCodequalityDiff', () => {
beforeEach(() => {
Object.assign(localState.codequalityDiff, {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
});
});
it('returns empty array when no codequality data is available', () => {
Object.assign(localState.codequalityDiff, {});
expect(getters.fileCodequalityDiff(localState)('test.js')).toEqual([]);
});
it('returns array when codequality data is available for given file', () => {
expect(getters.fileCodequalityDiff(localState)('app.js')).toEqual([
{ line: 1, description: 'Unexpected alert.', severity: 'minor' },
]);
});
});
describe('suggestionCommitMessage', () => {
let rootState;

View File

@ -115,19 +115,6 @@ describe('DiffsStoreMutations', () => {
});
});
describe('SET_CODEQUALITY_DATA', () => {
it('should set codequality data', () => {
const state = { codequalityDiff: {} };
const codequality = {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
};
mutations[types.SET_CODEQUALITY_DATA](state, codequality);
expect(state.codequalityDiff).toEqual(codequality);
});
});
describe('SET_DIFF_VIEW_TYPE', () => {
it('should set diff view type properly', () => {
const state = {};

View File

@ -4,5 +4,47 @@
---
- name: bold
markdown: '**bold**'
- name: code
- name: emphasis
markdown: '_emphasized text_'
- name: inline_code
markdown: '`code`'
- name: link
markdown: '[GitLab](https://gitlab.com)'
- name: code_block
markdown: |-
```javascript
console.log('hello world')
```
- name: headings
markdown: |-
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
- name: blockquote
markdown: |-
> This is a blockquote
>
> This is another one
- name: thematic_break
markdown: |-
---
- name: bullet_list
markdown: |-
* list item 1
* list item 2
* embedded list item 3
- name: ordered_list
markdown: |-
1. list item 1
2. list item 2
3. list item 3
- name: image
markdown: '![alt text](https://gitlab.com/logo.png)'

View File

@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import ExperimentTracking from '~/experimentation/experiment_tracking';
import PipelinesCiTemplate from '~/pipelines/components/pipelines_list/pipelines_ci_templates.vue';
const addCiYmlPath = "/-/new/master?commit_message='Add%20.gitlab-ci.yml'";
@ -8,6 +9,8 @@ const suggestedCiTemplates = [
{ name: 'C++', logo: '/assets/illustrations/logos/c_plus_plus.svg' },
];
jest.mock('~/experimentation/experiment_tracking');
describe('Pipelines CI Templates', () => {
let wrapper;
@ -81,4 +84,28 @@ describe('Pipelines CI Templates', () => {
);
});
});
describe('tracking', () => {
beforeEach(() => {
wrapper = createWrapper();
});
it('sends an event when template is clicked', () => {
findTemplateLinks().at(0).vm.$emit('click');
expect(ExperimentTracking).toHaveBeenCalledWith('pipeline_empty_state_templates', {
label: 'Android',
});
expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith('template_clicked');
});
it('sends an event when Hello-World template is clicked', () => {
findTestTemplateLinks().at(0).vm.$emit('click');
expect(ExperimentTracking).toHaveBeenCalledWith('pipeline_empty_state_templates', {
label: 'Hello-World',
});
expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith('template_clicked');
});
});
});

View File

@ -389,20 +389,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
end
end
context 'when FF ci_workflow_rules_variables is disabled' do
before do
stub_feature_flags(ci_workflow_rules_variables: false)
end
it 'does not return job_variables and root_variables_inheritance' do
expect(entry.value).to include(
variables: { 'A' => 'job', 'B' => 'job' }
)
expect(entry.value).not_to have_key(:job_variables)
expect(entry.value).not_to have_key(:root_variables_inheritance)
end
end
context 'when root yaml variables are used' do
let(:variables) do
Gitlab::Ci::Config::Entry::Variables.new(
@ -520,21 +506,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
root_variables_inheritance: true
)
end
context 'when FF ci_workflow_rules_variables is disabled' do
before do
stub_feature_flags(ci_workflow_rules_variables: false)
end
it 'does not return job_variables and root_variables_inheritance' do
expect(entry.value).to eq(
name: :rspec,
stage: 'test',
only: { refs: %w[branches tags] },
variables: {}
)
end
end
end
end
end

View File

@ -107,54 +107,5 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
['test: [aws, app1]', 'test: [aws, app2]', 'test: [gcp, app]', 'test: [ovh, app]']
)
end
context 'when the FF ci_workflow_rules_variables is disabled' do
before do
stub_feature_flags(ci_workflow_rules_variables: false)
end
it 'excludes job_variables' do
expect(subject.map(&:attributes)).to match_array(
[
{
name: 'test: [aws, app1]',
instance: 1,
parallel: { total: 4 },
variables: {
'PROVIDER' => 'aws',
'STACK' => 'app1'
}
},
{
name: 'test: [aws, app2]',
instance: 2,
parallel: { total: 4 },
variables: {
'PROVIDER' => 'aws',
'STACK' => 'app2'
}
},
{
name: 'test: [ovh, app]',
instance: 3,
parallel: { total: 4 },
variables: {
'PROVIDER' => 'ovh',
'STACK' => 'app'
}
},
{
name: 'test: [gcp, app]',
instance: 4,
parallel: { total: 4 },
variables: {
'PROVIDER' => 'gcp',
'STACK' => 'app'
}
}
]
)
end
end
end
end

View File

@ -151,26 +151,6 @@ RSpec.describe Gitlab::WebIde::Config::Entry::Terminal do
}
)
end
context 'when FF ci_workflow_rules_variables is disabled' do
before do
stub_feature_flags(ci_workflow_rules_variables: false)
end
it 'returns correct value without job_variables' do
expect(entry.value)
.to eq(
tag_list: ['webide'],
yaml_variables: [{ key: 'KEY', value: 'value', public: true }],
options: {
image: { name: "ruby:2.5" },
services: [{ name: "mysql" }],
before_script: %w[ls pwd],
script: ['sleep 100']
}
)
end
end
end
end
end

View File

@ -2,30 +2,28 @@
require 'spec_helper'
RSpec.describe Milestone, 'Milestoneish' do
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:non_member) { create(:user) }
let(:member) { create(:user) }
let(:guest) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:project, :public) }
let(:milestone) { create(:milestone, project: project) }
let(:label1) { create(:label, project: project) }
let(:label2) { create(:label, project: project) }
let!(:issue) { create(:issue, project: project, milestone: milestone, assignees: [member], labels: [label1]) }
let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone, labels: [label2]) }
let!(:security_issue_2) { create(:issue, :confidential, project: project, assignees: [assignee], milestone: milestone) }
let!(:closed_issue_1) { create(:issue, :closed, project: project, milestone: milestone) }
let!(:closed_issue_2) { create(:issue, :closed, project: project, milestone: milestone) }
let!(:closed_security_issue_1) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
let!(:closed_security_issue_2) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) }
let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
let(:label_3) { create(:label, title: 'label_3', project: project) }
RSpec.describe Milestone, 'Milestoneish', factory_default: :keep do
let_it_be(:author) { create(:user) }
let_it_be(:assignee) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:member) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be(:project, reload: true) { create_default(:project, :public, :empty_repo).freeze }
let_it_be(:milestone, refind: true) { create_default(:milestone, project: project) }
let_it_be(:label1) { create(:label) }
let_it_be(:label2) { create(:label) }
let_it_be(:issue, reload: true) { create(:issue, milestone: milestone, assignees: [member], labels: [label1]) }
let_it_be(:security_issue_1, reload: true) { create(:issue, :confidential, author: author, milestone: milestone, labels: [label2]) }
let_it_be(:security_issue_2, reload: true) { create(:issue, :confidential, assignees: [assignee], milestone: milestone) }
let_it_be(:closed_issue_1, reload: true) { create(:issue, :closed, milestone: milestone) }
let_it_be(:closed_issue_2, reload: true) { create(:issue, :closed, milestone: milestone) }
let_it_be(:closed_security_issue_1, reload: true) { create(:issue, :confidential, :closed, author: author, milestone: milestone) }
let_it_be(:closed_security_issue_2, reload: true) { create(:issue, :confidential, :closed, assignees: [assignee], milestone: milestone) }
let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
let_it_be(:label_1) { create(:label, title: 'label_1', priority: 1) }
let_it_be(:label_2) { create(:label, title: 'label_2', priority: 2) }
let_it_be(:label_3) { create(:label, title: 'label_3') }
before do
project.add_developer(member)
@ -63,7 +61,7 @@ RSpec.describe Milestone, 'Milestoneish' do
end
end
context 'attributes visibility' do
context 'with attributes visibility' do
using RSpec::Parameterized::TableSyntax
let(:users) do
@ -167,8 +165,6 @@ RSpec.describe Milestone, 'Milestoneish' do
end
describe '#merge_requests_visible_to_user' do
let(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) }
context 'when project is private' do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
@ -211,10 +207,11 @@ RSpec.describe Milestone, 'Milestoneish' do
end
context 'when milestone is at parent level group' do
let(:parent_group) { create(:group) }
let(:group) { create(:group, parent: parent_group) }
let(:project) { create(:project, namespace: group) }
let(:milestone) { create(:milestone, group: parent_group) }
let_it_be(:parent_group) { create(:group) }
let_it_be(:group) { create(:group, parent: parent_group) }
let_it_be(:project) { create(:project, :empty_repo, namespace: group) }
let_it_be(:milestone) { create(:milestone, group: parent_group) }
let_it_be(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) }
it 'does not return any merge request for a non member' do
merge_requests = milestone.merge_requests_visible_to_user(non_member)
@ -243,7 +240,7 @@ RSpec.describe Milestone, 'Milestoneish' do
end
describe '#percent_complete', :use_clean_rails_memory_store_caching do
context 'division by zero' do
context 'with division by zero' do
let(:new_milestone) { build_stubbed(:milestone) }
it { expect(new_milestone.percent_complete).to eq(0) }
@ -252,13 +249,13 @@ RSpec.describe Milestone, 'Milestoneish' do
describe '#closed_issues_count' do
it 'counts all closed issues including confidential' do
expect(milestone.closed_issues_count).to eq 6
expect(milestone.closed_issues_count).to eq 4
end
end
describe '#total_issues_count' do
it 'counts all issues including confidential' do
expect(milestone.total_issues_count).to eq 9
expect(milestone.total_issues_count).to eq 7
end
end

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe MergeRequests::ResolveTodosService do
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:user) { create(:user) }
let(:service) { described_class.new(merge_request, user) }
describe '#async_execute' do
def async_execute
service.async_execute
end
it 'performs MergeRequests::ResolveTodosWorker asynchronously' do
expect(MergeRequests::ResolveTodosWorker)
.to receive(:perform_async)
.with(
merge_request.id,
user.id
)
async_execute
end
context 'when resolve_merge_request_todos_async feature is disabled' do
before do
stub_feature_flags(resolve_merge_request_todos_async: false)
end
it 'calls #execute' do
expect(service).to receive(:execute)
async_execute
end
end
end
describe '#execute' do
it 'marks pending todo as done' do
pending_todo = create(:todo, :pending, user: user, project: merge_request.project, target: merge_request)
service.execute
expect(pending_todo.reload).to be_done
end
end
end

View File

@ -590,48 +590,54 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
let!(:pending_todo) { create(:todo, :assigned, user: user, project: project, target: merge_request, author: user2) }
context 'when the title change' do
before do
it 'calls MergeRequest::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
update_merge_request({ title: 'New title' })
end
it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
end
it 'does not create any new todos' do
update_merge_request({ title: 'New title' })
expect(Todo.count).to eq(1)
end
end
context 'when the description change' do
before do
it 'calls MergeRequest::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
update_merge_request({ description: "Also please fix #{user2.to_reference} #{user3.to_reference}" })
end
it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
end
it 'creates only 1 new todo' do
update_merge_request({ description: "Also please fix #{user2.to_reference} #{user3.to_reference}" })
expect(Todo.count).to eq(2)
end
end
context 'when is reassigned' do
before do
update_merge_request({ assignee_ids: [user2.id] })
end
it 'calls MergeRequest::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
it 'marks previous assignee pending todos as done' do
expect(pending_todo.reload).to be_done
update_merge_request({ assignee_ids: [user2.id] })
end
end
context 'when reviewers gets changed' do
it 'marks pending todo as done' do
update_merge_request({ reviewer_ids: [user2.id] })
it 'calls MergeRequest::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
expect(pending_todo.reload).to be_done
update_merge_request({ reviewer_ids: [user2.id] })
end
it 'creates a pending todo for new review request' do
@ -709,10 +715,12 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
end
it 'marks pending todos as done' do
update_merge_request({ milestone: create(:milestone, project: project) })
it 'calls MergeRequests::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
expect(pending_todo.reload).to be_done
update_merge_request({ milestone: create(:milestone, project: project) })
end
it 'sends notifications for subscribers of changed milestone', :sidekiq_might_not_need_inline do
@ -726,17 +734,19 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
context 'when the labels change' do
before do
travel_to(1.minute.from_now) do
update_merge_request({ label_ids: [label.id] })
it 'calls MergeRequests::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
end
it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
update_merge_request({ label_ids: [label.id] })
end
it 'updates updated_at' do
travel_to(1.minute.from_now) do
update_merge_request({ label_ids: [label.id] })
end
expect(merge_request.reload.updated_at).to be > Time.current
end
end
@ -751,24 +761,26 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
context 'when the target branch change' do
before do
update_merge_request({ target_branch: 'target' })
end
it 'calls MergeRequests::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
update_merge_request({ target_branch: 'target' })
end
end
context 'when auto merge is enabled and target branch changed' do
before do
AutoMergeService.new(project, user, { sha: merge_request.diff_head_sha }).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS)
update_merge_request({ target_branch: 'target' })
end
it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
it 'calls MergeRequests::ResolveTodosService#async_execute' do
expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service|
expect(service).to receive(:async_execute)
end
update_merge_request({ target_branch: 'target' })
end
end
end

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe MergeRequests::ResolveTodosWorker do
include AfterNextHelpers
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:user) { create(:user) }
let(:worker) { described_class.new }
it_behaves_like 'an idempotent worker' do
let(:job_args) { [merge_request.id, user.id] }
end
describe '#perform' do
it 'calls MergeRequests::ResolveTodosService#execute' do
expect_next(::MergeRequests::ResolveTodosService, merge_request, user)
.to receive(:execute)
worker.perform(merge_request.id, user.id)
end
context 'with a non-existing merge request' do
it 'does nothing' do
expect(::MergeRequests::ResolveTodosService).not_to receive(:new)
worker.perform(non_existing_record_id, user.id)
end
end
context 'with a non-existing user' do
it 'does nothing' do
expect(::MergeRequests::ResolveTodosService).not_to receive(:new)
worker.perform(merge_request.id, non_existing_record_id)
end
end
end
end

View File

@ -4703,10 +4703,10 @@ eslint-plugin-jest@^23.8.2:
dependencies:
"@typescript-eslint/experimental-utils" "^2.5.0"
eslint-plugin-no-jquery@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.5.0.tgz#6c12e3aae172bfd3363b7ac8c3f3e944704867f4"
integrity sha512-RrQ380mUJJKdjgpQ/tZAJ3B3W1n3LbVmULooS2Pv5pUDcc5uVHVSJMTdUlsbvQyfo6hWP2LJ4FbOoDzENWcF7A==
eslint-plugin-no-jquery@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.6.0.tgz#7892cb7c086f7813156bca6bc48429825428e9eb"
integrity sha512-xC7pbNHJMdyxqhzcNMRrmC5/tbt1T4KCKXjOqUpKm/CaRryGKS5iWztzWPrL0KwyI3R3ub6goHFmIQS19f+mZA==
eslint-plugin-promise@^4.2.1:
version "4.2.1"
@ -4761,10 +4761,10 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
eslint@7.21.0:
version "7.21.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.21.0.tgz#4ecd5b8c5b44f5dedc9b8a110b01bbfeb15d1c83"
integrity sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==
eslint@7.24.0:
version "7.24.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a"
integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.0"
@ -4783,7 +4783,7 @@ eslint@7.21.0:
file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.0.0"
globals "^12.1.0"
globals "^13.6.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
@ -4791,7 +4791,7 @@ eslint@7.21.0:
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
lodash "^4.17.20"
lodash "^4.17.21"
minimatch "^3.0.4"
natural-compare "^1.4.0"
optionator "^0.9.1"
@ -5619,6 +5619,13 @@ globals@^12.1.0:
dependencies:
type-fest "^0.8.1"
globals@^13.6.0:
version "13.8.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.8.0.tgz#3e20f504810ce87a8d72e55aecf8435b50f4c1b3"
integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==
dependencies:
type-fest "^0.20.2"
globby@^11.0.2:
version "11.0.2"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83"
@ -7833,10 +7840,10 @@ lodash.values@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.10:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.10:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@^2.1.0:
version "2.2.0"
@ -11781,6 +11788,11 @@ type-fest@^0.18.0:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type-fest@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"