Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue2
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue2
-rw-r--r--app/assets/javascripts/alerts_settings/graphql.js10
-rw-r--r--app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json1
-rw-r--r--app/assets/javascripts/blob/components/table_contents.vue74
-rw-r--r--app/assets/javascripts/grafana_integration/components/grafana_integration.vue50
-rw-r--r--app/assets/javascripts/incidents_settings/components/alerts_form.vue2
-rw-r--r--app/assets/javascripts/incidents_settings/components/pagerduty_form.vue22
-rw-r--r--app/assets/javascripts/incidents_settings/constants.js2
-rw-r--r--app/assets/javascripts/nav/components/top_nav_menu_item.vue10
-rw-r--r--app/assets/javascripts/operation_settings/components/metrics_settings.vue8
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js13
-rw-r--r--app/finders/concerns/packages/finder_helper.rb2
-rw-r--r--app/graphql/mutations/concerns/mutations/resolves_subscription.rb1
-rw-r--r--app/graphql/mutations/issues/set_subscription.rb24
-rw-r--r--app/graphql/mutations/merge_requests/set_subscription.rb24
-rw-r--r--app/helpers/nav/top_nav_helper.rb2
-rw-r--r--app/models/member.rb2
-rw-r--r--app/policies/issue_policy.rb1
-rw-r--r--app/policies/merge_request_policy.rb1
-rw-r--r--app/views/projects/blob/_header_content.html.haml2
-rw-r--r--app/views/projects/settings/operations/_alert_management.html.haml2
-rw-r--r--app/views/projects/settings/operations/_tracing.html.haml22
-rw-r--r--app/views/projects/settings/operations/show.html.haml8
-rw-r--r--changelogs/unreleased/326808-cleanup-feature-flag.yml5
-rw-r--r--changelogs/unreleased/329319-observe-secondary-email-addresses-when-adding-a-member.yml5
-rw-r--r--changelogs/unreleased/330271-remove-support-for-wip-quick-action.yml5
-rw-r--r--changelogs/unreleased/fix_set_subscription_permission.yml6
-rw-r--r--config/feature_flags/development/dast_runner_site_validation.yml (renamed from config/feature_flags/development/packages_finder_helper_deploy_token.yml)12
-rw-r--r--config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml14
-rw-r--r--config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml18
-rw-r--r--doc/development/fe_guide/editor_lite.md1
-rw-r--r--doc/development/usage_ping/dictionary.md10
-rw-r--r--doc/operations/incident_management/integrations.md6
-rw-r--r--doc/user/project/quick_actions.md1
-rw-r--r--lib/api/jobs.rb1
-rw-r--r--lib/gitlab/instrumentation/redis.rb4
-rw-r--r--lib/gitlab/instrumentation/redis_payload.rb6
-rw-r--r--lib/gitlab/metrics/subscribers/active_record.rb4
-rw-r--r--lib/gitlab/metrics/subscribers/external_http.rb2
-rw-r--r--lib/gitlab/nav/top_nav_menu_item.rb3
-rw-r--r--lib/gitlab/quick_actions/merge_request_actions.rb2
-rw-r--r--lib/gitlab/sidekiq_middleware/instrumentation_logger.rb19
-rw-r--r--locale/gitlab.pot33
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb2
-rw-r--r--spec/features/alerts_settings/user_views_alerts_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/user_searches_in_settings_spec.rb2
-rw-r--r--spec/finders/concerns/packages/finder_helper_spec.rb82
-rw-r--r--spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js2
-rw-r--r--spec/frontend/blob/components/table_contents_spec.js67
-rw-r--r--spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap39
-rw-r--r--spec/frontend/grafana_integration/components/grafana_integration_spec.js12
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap2
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap2
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap14
-rw-r--r--spec/frontend/incidents_settings/components/pagerduty_form_spec.js23
-rw-r--r--spec/frontend/nav/components/top_nav_menu_item_spec.js18
-rw-r--r--spec/frontend/operation_settings/components/metrics_settings_spec.js6
-rw-r--r--spec/graphql/mutations/issues/set_subscription_spec.rb36
-rw-r--r--spec/graphql/mutations/merge_requests/set_subscription_spec.rb28
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/instrumentation/redis_base_spec.rb18
-rw-r--r--spec/lib/gitlab/instrumentation/redis_spec.rb40
-rw-r--r--spec/lib/gitlab/nav/top_nav_menu_item_spec.rb1
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/instrumentation_logger_spec.rb54
-rw-r--r--spec/models/member_spec.rb12
-rw-r--r--spec/policies/issue_policy_spec.rb11
-rw-r--r--spec/policies/merge_request_policy_spec.rb5
-rw-r--r--spec/services/members/invite_service_spec.rb14
-rw-r--r--spec/services/merge_requests/create_service_spec.rb2
-rw-r--r--spec/services/notes/create_service_spec.rb4
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb10
-rw-r--r--spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb53
-rw-r--r--spec/views/projects/settings/operations/show.html.haml_spec.rb38
74 files changed, 571 insertions, 474 deletions
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue
index d9e5878b9e3..717d4cb01ab 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue
@@ -155,7 +155,7 @@ export default {
<span v-if="item.active" data-testid="integration-activated-status">
<gl-icon
v-gl-tooltip
- name="check-circle-filled"
+ name="check"
:size="16"
class="gl-text-green-500 gl-hover-cursor-pointer gl-mr-3"
:title="$options.i18n.status.enabled.tooltip"
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
index 3917e4c5fdd..97a3cdbd45a 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
@@ -167,7 +167,7 @@ export default {
if (testAfterSubmit) {
this.viewIntegration(integration, tabIndices.sendTestAlert);
} else {
- this.clearCurrentIntegration(type);
+ this.clearCurrentIntegration({ type });
}
createFlash({
diff --git a/app/assets/javascripts/alerts_settings/graphql.js b/app/assets/javascripts/alerts_settings/graphql.js
index 72817f636ff..15862f4034a 100644
--- a/app/assets/javascripts/alerts_settings/graphql.js
+++ b/app/assets/javascripts/alerts_settings/graphql.js
@@ -1,9 +1,15 @@
+import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import produce from 'immer';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
+import introspectionQueryResultData from './graphql/fragmentTypes.json';
import getCurrentIntegrationQuery from './graphql/queries/get_current_integration.query.graphql';
+const fragmentMatcher = new IntrospectionFragmentMatcher({
+ introspectionQueryResultData,
+});
+
Vue.use(VueApollo);
const resolvers = {
@@ -50,7 +56,9 @@ const resolvers = {
export default new VueApollo({
defaultClient: createDefaultClient(resolvers, {
- cacheConfig: {},
+ cacheConfig: {
+ fragmentMatcher,
+ },
assumeImmutableResults: true,
}),
});
diff --git a/app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json b/app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json
new file mode 100644
index 00000000000..07dfc43aa6c
--- /dev/null
+++ b/app/assets/javascripts/alerts_settings/graphql/fragmentTypes.json
@@ -0,0 +1 @@
+{"__schema":{"types":[{"kind":"UNION","name":"AlertManagementIntegration","possibleTypes":[{"name":"AlertManagementHttpIntegration"},{"name":"AlertManagementPrometheusIntegration"}]}]}}
diff --git a/app/assets/javascripts/blob/components/table_contents.vue b/app/assets/javascripts/blob/components/table_contents.vue
new file mode 100644
index 00000000000..3a0a385d494
--- /dev/null
+++ b/app/assets/javascripts/blob/components/table_contents.vue
@@ -0,0 +1,74 @@
+<script>
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+
+function getHeaderNumber(el) {
+ return parseInt(el.tagName.match(/\d+/)[0], 10);
+}
+
+export default {
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ },
+ data() {
+ return {
+ isHidden: false,
+ items: [],
+ };
+ },
+ mounted() {
+ this.blobViewer = document.querySelector('.blob-viewer[data-type="rich"]');
+
+ this.observer = new MutationObserver(() => {
+ if (this.blobViewer.classList.contains('hidden')) {
+ this.isHidden = true;
+ } else if (this.blobViewer.getAttribute('data-loaded') === 'true') {
+ this.isHidden = false;
+ this.generateHeaders();
+ }
+ });
+
+ if (this.blobViewer) {
+ this.observer.observe(this.blobViewer, {
+ attributes: true,
+ });
+ }
+ },
+ beforeDestroy() {
+ if (this.observer) {
+ this.observer.disconnect();
+ }
+ },
+ methods: {
+ generateHeaders() {
+ const headers = [...this.blobViewer.querySelectorAll('h1,h2,h3,h4,h5,h6')];
+
+ if (headers.length) {
+ const firstHeader = getHeaderNumber(headers[0]);
+
+ headers.forEach((el) => {
+ this.items.push({
+ text: el.textContent.trim(),
+ anchor: el.querySelector('a').getAttribute('id'),
+ spacing: Math.max((getHeaderNumber(el) - firstHeader) * 8, 0),
+ });
+ });
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown v-if="!isHidden && items.length" icon="list-bulleted" class="gl-mr-2">
+ <gl-dropdown-item v-for="(item, index) in items" :key="index" :href="`#${item.anchor}`">
+ <span
+ :style="{ 'padding-left': `${item.spacing}px` }"
+ class="gl-display-block"
+ data-testid="tableContentsLink"
+ >
+ {{ item.text }}
+ </span>
+ </gl-dropdown-item>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
index e941318dce0..3911201457f 100644
--- a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
+++ b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
@@ -1,5 +1,13 @@
<script>
-import { GlButton, GlFormGroup, GlFormInput, GlFormCheckbox, GlIcon, GlLink } from '@gitlab/ui';
+import {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlFormCheckbox,
+ GlIcon,
+ GlLink,
+ GlSprintf,
+} from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { helpPagePath } from '~/helpers/help_page_helper';
@@ -11,6 +19,7 @@ export default {
GlFormInput,
GlIcon,
GlLink,
+ GlSprintf,
},
data() {
return {
@@ -78,13 +87,11 @@ export default {
</div>
<div class="settings-content">
<form>
- <gl-form-checkbox
- id="grafana-integration-enabled"
- v-model="integrationEnabled"
- class="mb-4"
- >
- {{ s__('GrafanaIntegration|Active') }}
- </gl-form-checkbox>
+ <gl-form-group :label="__('Enable authentication')" label-for="grafana-integration-enabled">
+ <gl-form-checkbox id="grafana-integration-enabled" v-model="integrationEnabled">
+ {{ s__('GrafanaIntegration|Active') }}
+ </gl-form-checkbox>
+ </gl-form-group>
<gl-form-group
:label="s__('GrafanaIntegration|Grafana URL')"
label-for="grafana-url"
@@ -95,18 +102,27 @@ export default {
<gl-form-group :label="s__('GrafanaIntegration|API token')" label-for="grafana-token">
<gl-form-input id="grafana-token" v-model="localGrafanaToken" />
<p class="form-text text-muted">
- {{ s__('GrafanaIntegration|Enter the Grafana API token.') }}
- <a
- href="https://grafana.com/docs/http_api/auth/#create-api-token"
- target="_blank"
- rel="noopener noreferrer"
+ <gl-sprintf
+ :message="
+ s__('GrafanaIntegration|Enter the %{docLinkStart}Grafana API token%{docLinkEnd}.')
+ "
>
- {{ __('More information.') }}
- <gl-icon name="external-link" class="vertical-align-middle" />
- </a>
+ <template #docLink="{ content }">
+ <gl-link
+ href="https://grafana.com/docs/http_api/auth/#create-api-token"
+ target="_blank"
+ >{{ content }} <gl-icon name="external-link" class="gl-vertical-align-middle"
+ /></gl-link>
+ </template>
+ </gl-sprintf>
</p>
</gl-form-group>
- <gl-button variant="success" category="primary" @click="updateGrafanaIntegration">
+ <gl-button
+ variant="confirm"
+ category="primary"
+ data-testid="save-grafana-settings-button"
+ @click="updateGrafanaIntegration"
+ >
{{ __('Save changes') }}
</gl-button>
</form>
diff --git a/app/assets/javascripts/incidents_settings/components/alerts_form.vue b/app/assets/javascripts/incidents_settings/components/alerts_form.vue
index e8daad8811e..b22ec6add96 100644
--- a/app/assets/javascripts/incidents_settings/components/alerts_form.vue
+++ b/app/assets/javascripts/incidents_settings/components/alerts_form.vue
@@ -134,7 +134,7 @@ export default {
ref="submitBtn"
data-qa-selector="save_changes_button"
:disabled="loading"
- variant="success"
+ variant="confirm"
type="submit"
class="js-no-auto-disable"
>
diff --git a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
index b56dd66342a..866d2ff399e 100644
--- a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
+++ b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
@@ -11,7 +11,6 @@ import {
GlModal,
GlModalDirective,
} from '@gitlab/ui';
-import { isEqual } from 'lodash';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { I18N_PAGERDUTY_SETTINGS_FORM, CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK } from '../constants';
@@ -50,14 +49,8 @@ export default {
pagerduty_active: this.active,
};
},
- isFormUpdated() {
- return isEqual(this.pagerDutySettings, {
- active: this.active,
- webhookUrl: this.webhookUrl,
- });
- },
isSaveDisabled() {
- return this.isFormUpdated || this.loading || this.resettingWebhook;
+ return this.loading || this.resettingWebhook;
},
webhookUpdateAlertMsg() {
return this.webhookUpdateFailed
@@ -123,13 +116,15 @@ export default {
</template>
</gl-sprintf>
</p>
- <form ref="settingsForm" @submit.prevent="updatePagerDutyIntegrationSettings">
+ <form ref="settingsForm">
<gl-form-group class="col-8 col-md-9 gl-p-0">
<gl-toggle
id="active"
v-model="active"
+ :disabled="isSaveDisabled"
:is-loading="loading"
:label="$options.i18n.activeToggle.label"
+ @change="updatePagerDutyIntegrationSettings"
/>
</gl-form-group>
@@ -166,15 +161,6 @@ export default {
{{ $options.i18n.webhookUrl.restKeyInfo }}
</gl-modal>
</gl-form-group>
- <gl-button
- ref="submitBtn"
- :disabled="isSaveDisabled"
- variant="success"
- type="submit"
- class="js-no-auto-disable"
- >
- {{ $options.i18n.saveBtnLabel }}
- </gl-button>
</form>
</div>
</template>
diff --git a/app/assets/javascripts/incidents_settings/constants.js b/app/assets/javascripts/incidents_settings/constants.js
index d479838b491..d72e2aedee9 100644
--- a/app/assets/javascripts/incidents_settings/constants.js
+++ b/app/assets/javascripts/incidents_settings/constants.js
@@ -23,7 +23,7 @@ export const I18N_INTEGRATION_TABS = {
headerText: s__('IncidentSettings|Incidents'),
expandBtnLabel: __('Expand'),
subHeaderText: s__(
- 'IncidentSettings|Set up integrations with external tools to help better manage incidents.',
+ 'IncidentSettings|Fine-tune incident settings and set up integrations with external tools to help better manage incidents.',
),
};
diff --git a/app/assets/javascripts/nav/components/top_nav_menu_item.vue b/app/assets/javascripts/nav/components/top_nav_menu_item.vue
index a0d92811a6f..067180abd08 100644
--- a/app/assets/javascripts/nav/components/top_nav_menu_item.vue
+++ b/app/assets/javascripts/nav/components/top_nav_menu_item.vue
@@ -1,5 +1,8 @@
<script>
import { GlButton, GlIcon } from '@gitlab/ui';
+import { kebabCase, mapKeys } from 'lodash';
+
+const getDataKey = (key) => `data-${kebabCase(key)}`;
export default {
components: {
@@ -12,6 +15,11 @@ export default {
required: true,
},
},
+ computed: {
+ dataAttrs() {
+ return mapKeys(this.menuItem.data || {}, (value, key) => getDataKey(key));
+ },
+ },
};
</script>
@@ -20,6 +28,8 @@ export default {
category="tertiary"
:href="menuItem.href"
class="top-nav-menu-item gl-display-block"
+ :class="menuItem.css_class"
+ v-bind="dataAttrs"
v-on="$listeners"
>
<span class="gl-display-flex">
diff --git a/app/assets/javascripts/operation_settings/components/metrics_settings.vue b/app/assets/javascripts/operation_settings/components/metrics_settings.vue
index a24612e4680..959fffa2629 100644
--- a/app/assets/javascripts/operation_settings/components/metrics_settings.vue
+++ b/app/assets/javascripts/operation_settings/components/metrics_settings.vue
@@ -34,19 +34,19 @@ export default {
<h4
class="js-section-header settings-title js-settings-toggle js-settings-toggle-trigger-only"
>
- {{ s__('MetricsSettings|Metrics dashboard') }}
+ {{ s__('MetricsSettings|Metrics') }}
</h4>
<gl-button class="js-settings-toggle">{{ __('Expand') }}</gl-button>
<p class="js-section-sub-header">
- {{ s__('MetricsSettings|Manage Metrics Dashboard settings.') }}
- <gl-link :href="helpPage">{{ __('Learn more') }}</gl-link>
+ {{ s__('MetricsSettings|Manage metrics dashboard settings.') }}
+ <gl-link :href="helpPage">{{ __('Learn more.') }}</gl-link>
</p>
</div>
<div class="settings-content">
<form>
<dashboard-timezone />
<external-dashboard />
- <gl-button variant="success" category="primary" @click="saveChanges">
+ <gl-button variant="confirm" category="primary" @click="saveChanges">
{{ __('Save Changes') }}
</gl-button>
</form>
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index 8a8ce70e998..6179586e56c 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import TableOfContents from '~/blob/components/table_contents.vue';
import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue';
import BlobViewer from '~/blob/viewer/index';
import GpgBadges from '~/gpg_badges';
@@ -92,3 +93,15 @@ if (successPipelineEl) {
},
});
}
+
+const tableContentsEl = document.querySelector('.js-table-contents');
+
+if (tableContentsEl) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: tableContentsEl,
+ render(h) {
+ return h(TableOfContents);
+ },
+ });
+}
diff --git a/app/finders/concerns/packages/finder_helper.rb b/app/finders/concerns/packages/finder_helper.rb
index f0ad998cadb..d2784a1d270 100644
--- a/app/finders/concerns/packages/finder_helper.rb
+++ b/app/finders/concerns/packages/finder_helper.rb
@@ -29,7 +29,7 @@ module Packages
end
def projects_visible_to_reporters(user, within_group:)
- if user.is_a?(DeployToken) && Feature.enabled?(:packages_finder_helper_deploy_token, default_enabled: :yaml)
+ if user.is_a?(DeployToken)
user.accessible_projects
else
within_group.all_projects
diff --git a/app/graphql/mutations/concerns/mutations/resolves_subscription.rb b/app/graphql/mutations/concerns/mutations/resolves_subscription.rb
index e26ae7d228c..ed9fb5fceb0 100644
--- a/app/graphql/mutations/concerns/mutations/resolves_subscription.rb
+++ b/app/graphql/mutations/concerns/mutations/resolves_subscription.rb
@@ -3,6 +3,7 @@
module Mutations
module ResolvesSubscription
extend ActiveSupport::Concern
+
included do
argument :subscribed_state,
GraphQL::BOOLEAN_TYPE,
diff --git a/app/graphql/mutations/issues/set_subscription.rb b/app/graphql/mutations/issues/set_subscription.rb
index a04c8f5ba2d..55c9049b7cf 100644
--- a/app/graphql/mutations/issues/set_subscription.rb
+++ b/app/graphql/mutations/issues/set_subscription.rb
@@ -2,10 +2,32 @@
module Mutations
module Issues
- class SetSubscription < Base
+ class SetSubscription < BaseMutation
graphql_name 'IssueSetSubscription'
include ResolvesSubscription
+ include Mutations::ResolvesIssuable
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: "The project the issue to mutate is in."
+
+ argument :iid, GraphQL::STRING_TYPE,
+ required: true,
+ description: "The IID of the issue to mutate."
+
+ field :issue,
+ Types::IssueType,
+ null: true,
+ description: "The issue after mutation."
+
+ authorize :update_subscription
+
+ private
+
+ def find_object(project_path:, iid:)
+ resolve_issuable(type: :issue, parent_path: project_path, iid: iid)
+ end
end
end
end
diff --git a/app/graphql/mutations/merge_requests/set_subscription.rb b/app/graphql/mutations/merge_requests/set_subscription.rb
index 7d3c40185c9..981daa81c28 100644
--- a/app/graphql/mutations/merge_requests/set_subscription.rb
+++ b/app/graphql/mutations/merge_requests/set_subscription.rb
@@ -2,10 +2,32 @@
module Mutations
module MergeRequests
- class SetSubscription < Base
+ class SetSubscription < BaseMutation
graphql_name 'MergeRequestSetSubscription'
include ResolvesSubscription
+ include Mutations::ResolvesIssuable
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: "The project the merge request to mutate is in."
+
+ argument :iid, GraphQL::STRING_TYPE,
+ required: true,
+ description: "The IID of the merge request to mutate."
+
+ field :merge_request,
+ Types::MergeRequestType,
+ null: true,
+ description: "The merge request after mutation."
+
+ authorize :update_subscription
+
+ private
+
+ def find_object(project_path:, iid:)
+ resolve_issuable(type: :merge_request, parent_path: project_path, iid: iid)
+ end
end
end
end
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index c7939b29aa8..16eaab4c7c8 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -132,7 +132,7 @@ module Nav
active: active_nav_link?(controller: 'admin/sessions'),
icon: 'lock-open',
href: destroy_admin_session_path,
- method: :post
+ data: { method: 'post' }
)
elsif current_user.admin?
builder.add_secondary_menu_item(
diff --git a/app/models/member.rb b/app/models/member.rb
index 00255f97f85..0c786cb0f94 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -336,7 +336,7 @@ class Member < ApplicationRecord
return User.find_by(id: user) if user.is_a?(Integer)
- User.find_by(email: user) || user
+ User.find_by_any_email(user) || user
end
def retrieve_member(source, user, existing_members)
diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb
index 6eec03d6d75..6176faec06a 100644
--- a/app/policies/issue_policy.rb
+++ b/app/policies/issue_policy.rb
@@ -38,6 +38,7 @@ class IssuePolicy < IssuablePolicy
rule { ~anonymous & can?(:read_issue) }.policy do
enable :create_todo
+ enable :update_subscription
end
end
diff --git a/app/policies/merge_request_policy.rb b/app/policies/merge_request_policy.rb
index e53a916f3ca..29a7a174759 100644
--- a/app/policies/merge_request_policy.rb
+++ b/app/policies/merge_request_policy.rb
@@ -20,6 +20,7 @@ class MergeRequestPolicy < IssuablePolicy
rule { ~anonymous & can?(:read_merge_request) }.policy do
enable :create_todo
+ enable :update_subscription
end
condition(:can_merge) { @subject.can_be_merged_by?(@user) }
diff --git a/app/views/projects/blob/_header_content.html.haml b/app/views/projects/blob/_header_content.html.haml
index b310939c5a3..95a5d63e07f 100644
--- a/app/views/projects/blob/_header_content.html.haml
+++ b/app/views/projects/blob/_header_content.html.haml
@@ -1,4 +1,6 @@
.file-header-content
+ - if Gitlab::MarkupHelper.gitlab_markdown?(blob.path)
+ .js-table-contents
= blob_icon blob.mode, blob.name
%strong.file-title-name.gl-word-break-all{ data: { qa_selector: 'file_name_content' } }
diff --git a/app/views/projects/settings/operations/_alert_management.html.haml b/app/views/projects/settings/operations/_alert_management.html.haml
index 0418d7df42d..34255af9cc6 100644
--- a/app/views/projects/settings/operations/_alert_management.html.haml
+++ b/app/views/projects/settings/operations/_alert_management.html.haml
@@ -6,7 +6,7 @@
%section.settings.no-animate#js-alert-management-settings{ class: ('expanded' if expanded) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
- = _('Alert integrations')
+ = _('Alerts')
%button.gl-button.btn.btn-default.js-settings-toggle{ type: 'button' }
= _('Expand')
%p
diff --git a/app/views/projects/settings/operations/_tracing.html.haml b/app/views/projects/settings/operations/_tracing.html.haml
index a591fa33096..343fd22c051 100644
--- a/app/views/projects/settings/operations/_tracing.html.haml
+++ b/app/views/projects/settings/operations/_tracing.html.haml
@@ -1,23 +1,13 @@
- setting = tracing_setting
-- has_jaeger_url = setting.external_url.present?
%section.settings.border-0.no-animate
- .settings-header{ :class => "border-top" }
+ .settings-header{ :class => 'border-top' }
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
- = _("Jaeger tracing")
+ = _('Tracing')
%button.btn.btn-default.gl-button.js-settings-toggle{ type: 'button' }
= _('Expand')
%p
- - if has_jaeger_url
- - tracing_link = link_to sanitize(setting.external_url, scrubber: Rails::Html::TextOnlyScrubber.new), target: "_blank", rel: 'noopener noreferrer' do
- %span
- = _('Tracing')
- = sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')
- - else
- - tracing_link = link_to project_tracing_path(@project) do
- %span
- = _('Tracing')
- = _("To open Jaeger from GitLab to view tracing from the %{link} page, add a URL to your Jaeger server.").html_safe % { link: tracing_link }
+ = _('Embed an image of your existing Jaeger server in GitLab.')
= link_to _('Learn more.'), help_page_path('operations/tracing'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
= form_for @project, url: project_settings_operations_path(@project), method: :patch do |f|
@@ -27,8 +17,8 @@
= form.label :external_url, _('Jaeger URL'), class: 'label-bold'
= form.url_field :external_url, class: 'form-control gl-form-input', placeholder: 'https://jaeger.example.com'
%p.form-text.text-muted
- - jaeger_help_url = "https://www.jaegertracing.io/docs/getting-started/"
+ - jaeger_help_url = 'https://www.jaegertracing.io/docs/getting-started/'
- link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url }
- - link_end_tag = "#{sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')}</a>".html_safe
- = _("Learn more about %{link_start_tag}Jaeger configuration%{link_end_tag}.").html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
+ - link_end_tag = "#{sprite_icon('external-link', css_class: 'gl-ml-2 gl-vertical-align-middle')}</a>".html_safe
+ = _('Learn more about %{link_start_tag}Jaeger configuration%{link_end_tag}.').html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
= f.submit _('Save changes'), class: 'gl-button btn btn-confirm'
diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml
index af183046e1e..e2c1a00a587 100644
--- a/app/views/projects/settings/operations/show.html.haml
+++ b/app/views/projects/settings/operations/show.html.haml
@@ -3,11 +3,11 @@
- page_title title
- breadcrumb_title title
+= render 'projects/settings/operations/metrics_dashboard'
+= render 'projects/settings/operations/tracing'
+= render 'projects/settings/operations/error_tracking'
= render 'projects/settings/operations/alert_management'
= render 'projects/settings/operations/incidents'
-= render 'projects/settings/operations/error_tracking'
-= render 'projects/settings/operations/prometheus', service: prometheus_service if Feature.enabled?(:settings_operations_prometheus_service)
-= render 'projects/settings/operations/metrics_dashboard'
= render 'projects/settings/operations/grafana_integration'
-= render 'projects/settings/operations/tracing'
= render_if_exists 'projects/settings/operations/status_page'
+= render 'projects/settings/operations/prometheus', service: prometheus_service if Feature.enabled?(:settings_operations_prometheus_service)
diff --git a/changelogs/unreleased/326808-cleanup-feature-flag.yml b/changelogs/unreleased/326808-cleanup-feature-flag.yml
new file mode 100644
index 00000000000..d16b1e5e231
--- /dev/null
+++ b/changelogs/unreleased/326808-cleanup-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Removed packages_finder_helper_deploy_token feature flag
+merge_request: 62189
+author:
+type: other
diff --git a/changelogs/unreleased/329319-observe-secondary-email-addresses-when-adding-a-member.yml b/changelogs/unreleased/329319-observe-secondary-email-addresses-when-adding-a-member.yml
new file mode 100644
index 00000000000..522d05fae7a
--- /dev/null
+++ b/changelogs/unreleased/329319-observe-secondary-email-addresses-when-adding-a-member.yml
@@ -0,0 +1,5 @@
+---
+title: Observe secondary email addresses when adding a member
+merge_request: 62024
+author:
+type: changed
diff --git a/changelogs/unreleased/330271-remove-support-for-wip-quick-action.yml b/changelogs/unreleased/330271-remove-support-for-wip-quick-action.yml
new file mode 100644
index 00000000000..7fbbd4f022c
--- /dev/null
+++ b/changelogs/unreleased/330271-remove-support-for-wip-quick-action.yml
@@ -0,0 +1,5 @@
+---
+title: Remove support for /wip quick action
+merge_request: 61199
+author:
+type: removed
diff --git a/changelogs/unreleased/fix_set_subscription_permission.yml b/changelogs/unreleased/fix_set_subscription_permission.yml
new file mode 100644
index 00000000000..847586f2528
--- /dev/null
+++ b/changelogs/unreleased/fix_set_subscription_permission.yml
@@ -0,0 +1,6 @@
+---
+title: Fix permission check when setting issue/merge request subscription in GraphQL
+ API.
+merge_request: 61980
+author:
+type: fixed
diff --git a/config/feature_flags/development/packages_finder_helper_deploy_token.yml b/config/feature_flags/development/dast_runner_site_validation.yml
index b847942706a..f8ad90062f6 100644
--- a/config/feature_flags/development/packages_finder_helper_deploy_token.yml
+++ b/config/feature_flags/development/dast_runner_site_validation.yml
@@ -1,8 +1,8 @@
---
-name: packages_finder_helper_deploy_token
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58497
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326808
-milestone: '13.11'
+name: dast_runner_site_validation
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61649
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331082
+milestone: '14.0'
type: development
-group: group::package
-default_enabled: true
+group: group::dynamic analysis
+default_enabled: false
diff --git a/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml b/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml
index b649192d659..8e8f8b9b65b 100644
--- a/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml
+++ b/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml
@@ -1,16 +1,18 @@
---
key_path: redis_hll_counters.pipeline_authoring.o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Monthly unique user count doing commits which contains the CI config file
+product_section: ops
+product_stage: verify
+product_group: group::pipeline authoring
+product_category: pipeline_authoring
value_type: number
status: data_available
time_frame: 28d
data_source: redis_hll
distribution:
+- ee
- ce
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml b/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml
new file mode 100644
index 00000000000..68c75dd579b
--- /dev/null
+++ b/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml
@@ -0,0 +1,18 @@
+---
+key_path: redis_hll_counters.pipeline_authoring.o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly
+description: Weekly unique user count doing commits which contains the CI config file
+product_section: ops
+product_stage: verify
+product_group: group::pipeline authoring
+product_category: pipeline_authoring
+value_type: number
+status: data_available
+time_frame: 7d
+data_source: redis_hll
+distribution:
+- ee
+- ce
+tier:
+- free
+- premium
+- ultimate
diff --git a/doc/development/fe_guide/editor_lite.md b/doc/development/fe_guide/editor_lite.md
index 5ad0c753ced..f28588c23e9 100644
--- a/doc/development/fe_guide/editor_lite.md
+++ b/doc/development/fe_guide/editor_lite.md
@@ -15,6 +15,7 @@ GitLab features use it, including:
- [CI Linter](../../ci/lint.md)
- [Snippets](../../user/snippets.md)
- [Web Editor](../../user/project/repository/web_editor.md)
+- [Security Policies](../../user/application_security/threat_monitoring/index.md)
## How to use Editor Lite
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index c69b9e76103..5ad907d029e 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -12828,21 +12828,21 @@ Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.pipeline_authoring.o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly`
-Missing description
+Monthly unique user count doing commits which contains the CI config file
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml)
-Group: ``
+Group: `group::pipeline authoring`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `redis_hll_counters.pipeline_authoring.o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly`
-Monthly unique user count doing commits which contains the CI config file
+Weekly unique user count doing commits which contains the CI config file
-[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml)
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml)
Group: `group::pipeline authoring`
diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md
index 07ffb92a000..92fde29624c 100644
--- a/doc/operations/incident_management/integrations.md
+++ b/doc/operations/incident_management/integrations.md
@@ -20,7 +20,7 @@ to use this endpoint.
With Maintainer or higher [permissions](../../user/permissions.md),
you can view the list of configured alerts integrations by navigating to **Settings > Operations**
-in your project's sidebar menu, and expanding the **Alert integrations** section. The list displays
+in your project's sidebar menu, and expanding the **Alerts** section. The list displays
the integration name, type, and status (enabled or disabled):
![Current Integrations](img/integrations_list_v13_5.png)
@@ -39,7 +39,7 @@ receive alert payloads in JSON format. You can always
1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
for a project.
1. Navigate to **Settings > Operations** in your project.
-1. Expand the **Alert integrations** section, and in the **Select integration type** dropdown menu,
+1. Expand the **Alerts** section, and in the **Select integration type** dropdown menu,
select **HTTP Endpoint**.
1. Toggle the **Active** alert setting. The URL and Authorization Key for the webhook configuration
are available in the **View credentials** tab after you save the integration. You must also input
@@ -56,7 +56,7 @@ and you can [customize the payload](#customize-the-alert-payload-outside-of-gitl
1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
for a project.
1. Navigate to **Settings > Operations** in your project.
-1. Expand the **Alert integrations** section.
+1. Expand the **Alerts** section.
1. For each endpoint you want to create:
1. Click the **Add new integration** button.
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index e1815785fb5..45cb5e74d6c 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -111,7 +111,6 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/unlock` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Unlock the discussions. |
| `/unsubscribe` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Unsubscribe from notifications. |
| `/weight <value>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set weight. Valid options for `<value>` include `0`, `1`, `2`, and so on. |
-| `/wip` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Toggle the draft status. |
| `/zoom <Zoom URL>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add Zoom meeting to this issue ([introduced in GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16609)). |
## Commit messages
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index cf65bfdfd0e..723a5b0fa3a 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -3,7 +3,6 @@
module API
class Jobs < ::API::Base
include PaginationParams
-
before { authenticate! }
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/gitlab/instrumentation/redis.rb b/lib/gitlab/instrumentation/redis.rb
index d1ac6a55fb7..9a9d3a866b1 100644
--- a/lib/gitlab/instrumentation/redis.rb
+++ b/lib/gitlab/instrumentation/redis.rb
@@ -21,10 +21,6 @@ module Gitlab
nil
end
- def known_payload_keys
- super + STORAGES.flat_map(&:known_payload_keys)
- end
-
def payload
super.merge(*STORAGES.flat_map(&:payload))
end
diff --git a/lib/gitlab/instrumentation/redis_payload.rb b/lib/gitlab/instrumentation/redis_payload.rb
index 69aafffd124..86a6525c8d0 100644
--- a/lib/gitlab/instrumentation/redis_payload.rb
+++ b/lib/gitlab/instrumentation/redis_payload.rb
@@ -5,12 +5,6 @@ module Gitlab
module RedisPayload
include ::Gitlab::Utils::StrongMemoize
- # Fetches payload keys from the lazy payload (this avoids
- # unnecessary processing of the values).
- def known_payload_keys
- to_lazy_payload.keys
- end
-
def payload
to_lazy_payload.transform_values do |value|
result = value.call
diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb
index 3db3317e833..24006d75c4d 100644
--- a/lib/gitlab/metrics/subscribers/active_record.rb
+++ b/lib/gitlab/metrics/subscribers/active_record.rb
@@ -51,10 +51,6 @@ module Gitlab
payload
end
- def self.known_payload_keys
- DB_COUNTERS
- end
-
private
def ignored_query?(payload)
diff --git a/lib/gitlab/metrics/subscribers/external_http.rb b/lib/gitlab/metrics/subscribers/external_http.rb
index 0df64f2897e..60a1b084345 100644
--- a/lib/gitlab/metrics/subscribers/external_http.rb
+++ b/lib/gitlab/metrics/subscribers/external_http.rb
@@ -14,8 +14,6 @@ module Gitlab
COUNTER = :external_http_count
DURATION = :external_http_duration_s
- KNOWN_PAYLOAD_KEYS = [COUNTER, DURATION].freeze
-
def self.detail_store
::Gitlab::SafeRequestStore[DETAIL_STORE] ||= []
end
diff --git a/lib/gitlab/nav/top_nav_menu_item.rb b/lib/gitlab/nav/top_nav_menu_item.rb
index ee11f1f4560..a5f835136fc 100644
--- a/lib/gitlab/nav/top_nav_menu_item.rb
+++ b/lib/gitlab/nav/top_nav_menu_item.rb
@@ -8,14 +8,13 @@ module Gitlab
# this is already :/. We could also take a hash and manually check every
# entry, but it's much more maintainable to do rely on native Ruby.
# rubocop: disable Metrics/ParameterLists
- def self.build(id:, title:, active: false, icon: '', href: '', method: nil, view: '', css_class: '', data: {})
+ def self.build(id:, title:, active: false, icon: '', href: '', view: '', css_class: '', data: {})
{
id: id,
title: title,
active: active,
icon: icon,
href: href,
- method: method,
view: view.to_s,
css_class: css_class,
data: data
diff --git a/lib/gitlab/quick_actions/merge_request_actions.rb b/lib/gitlab/quick_actions/merge_request_actions.rb
index f3c6315cd6a..47c76e98e5c 100644
--- a/lib/gitlab/quick_actions/merge_request_actions.rb
+++ b/lib/gitlab/quick_actions/merge_request_actions.rb
@@ -99,7 +99,7 @@ module Gitlab
# Allow it to mark as WIP on MR creation page _or_ through MR notes.
(quick_action_target.new_record? || current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target))
end
- command :draft, :wip do
+ command :draft do
@updates[:wip_event] = quick_action_target.work_in_progress? ? 'unwip' : 'wip'
end
diff --git a/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb b/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb
index b542aa4fe4c..1f0c63c5fff 100644
--- a/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb
+++ b/lib/gitlab/sidekiq_middleware/instrumentation_logger.rb
@@ -3,24 +3,6 @@
module Gitlab
module SidekiqMiddleware
class InstrumentationLogger
- def self.keys
- @keys ||= [
- :cpu_s,
- :gitaly_calls,
- :gitaly_duration_s,
- :rugged_calls,
- :rugged_duration_s,
- :elasticsearch_calls,
- :elasticsearch_duration_s,
- :elasticsearch_timed_out_count,
- *::Gitlab::Memory::Instrumentation::KEY_MAPPING.values,
- *::Gitlab::Instrumentation::Redis.known_payload_keys,
- *::Gitlab::Metrics::Subscribers::ActiveRecord.known_payload_keys,
- *::Gitlab::Metrics::Subscribers::ExternalHttp::KNOWN_PAYLOAD_KEYS,
- *::Gitlab::Metrics::Subscribers::RackAttack::PAYLOAD_KEYS
- ]
- end
-
def call(worker, job, queue)
::Gitlab::InstrumentationHelper.init_instrumentation_data
@@ -37,7 +19,6 @@ module Gitlab
# https://github.com/mperham/sidekiq/blob/53bd529a0c3f901879925b8390353129c465b1f2/lib/sidekiq/processor.rb#L115-L118
job[:instrumentation] = {}.tap do |instrumentation_values|
::Gitlab::InstrumentationHelper.add_instrumentation_data(instrumentation_values)
- instrumentation_values.slice!(*self.class.keys)
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index ec15cb103e8..34372eb6c90 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2859,9 +2859,6 @@ msgid_plural "Alerts"
msgstr[0] ""
msgstr[1] ""
-msgid "Alert integrations"
-msgstr ""
-
msgid "AlertManagement|Acknowledged"
msgstr ""
@@ -8424,6 +8421,9 @@ msgstr ""
msgid "Configuration"
msgstr ""
+msgid "Configuration help"
+msgstr ""
+
msgid "Configure GitLab runners to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
msgstr ""
@@ -12130,6 +12130,9 @@ msgstr ""
msgid "Embed"
msgstr ""
+msgid "Embed an image of your existing Jaeger server in GitLab."
+msgstr ""
+
msgid "Empty file"
msgstr ""
@@ -12214,6 +12217,9 @@ msgstr ""
msgid "Enable authenticated API request rate limit"
msgstr ""
+msgid "Enable authentication"
+msgstr ""
+
msgid "Enable automatic repository housekeeping (git repack, git gc)"
msgstr ""
@@ -15509,7 +15515,7 @@ msgstr ""
msgid "GrafanaIntegration|Active"
msgstr ""
-msgid "GrafanaIntegration|Enter the Grafana API token."
+msgid "GrafanaIntegration|Enter the %{docLinkStart}Grafana API token%{docLinkEnd}."
msgstr ""
msgid "GrafanaIntegration|Enter the base URL of the Grafana instance."
@@ -17382,6 +17388,9 @@ msgstr ""
msgid "IncidentSettings|Alert integration"
msgstr ""
+msgid "IncidentSettings|Fine-tune incident settings and set up integrations with external tools to help better manage incidents."
+msgstr ""
+
msgid "IncidentSettings|Grafana integration"
msgstr ""
@@ -17397,9 +17406,6 @@ msgstr ""
msgid "IncidentSettings|PagerDuty integration"
msgstr ""
-msgid "IncidentSettings|Set up integrations with external tools to help better manage incidents."
-msgstr ""
-
msgid "IncidentSettings|Time limit"
msgstr ""
@@ -18560,9 +18566,6 @@ msgstr ""
msgid "Jaeger URL"
msgstr ""
-msgid "Jaeger tracing"
-msgstr ""
-
msgid "Jan"
msgstr ""
@@ -20907,10 +20910,10 @@ msgstr ""
msgid "MetricsSettings|External dashboard URL"
msgstr ""
-msgid "MetricsSettings|Manage Metrics Dashboard settings."
+msgid "MetricsSettings|Manage metrics dashboard settings."
msgstr ""
-msgid "MetricsSettings|Metrics dashboard"
+msgid "MetricsSettings|Metrics"
msgstr ""
msgid "MetricsSettings|UTC (Coordinated Universal Time)"
@@ -31126,9 +31129,6 @@ msgstr ""
msgid "StatusPage|Status page URL"
msgstr ""
-msgid "StatusPage|Status page frontend documentation"
-msgstr ""
-
msgid "StatusPage|To publish incidents to an external status page, GitLab stores a JSON file in your Amazon S3 account at a location that your external status page service can access. Make sure to also set up %{docsLink}"
msgstr ""
@@ -34049,9 +34049,6 @@ msgstr ""
msgid "To only use CI/CD features for an external repository, choose %{strong_open}CI/CD for external repo%{strong_close}."
msgstr ""
-msgid "To open Jaeger from GitLab to view tracing from the %{link} page, add a URL to your Jaeger server."
-msgstr ""
-
msgid "To pass variables to the triggered pipeline, add %{code_start}variables[VARIABLE]=VALUE%{code_end} to the API request."
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb
index 7a71d1cfbaf..635313b9fb0 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry_spec.rb
@@ -30,6 +30,8 @@ module QA
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_TLS_VERIFY: 1
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
+ before_script:
+ - until docker info; do sleep 1; done
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_TAG .
diff --git a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
index 6675abd6b42..60f2f776595 100644
--- a/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
+++ b/spec/features/alerts_settings/user_views_alerts_settings_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Alert integrations settings form', :js do
it 'shows the alerts setting form title' do
page.within('#js-alert-management-settings') do
- expect(find('h4')).to have_content('Alert integrations')
+ expect(find('h4')).to have_content('Alerts')
end
end
diff --git a/spec/features/projects/settings/user_searches_in_settings_spec.rb b/spec/features/projects/settings/user_searches_in_settings_spec.rb
index 9b09958bae5..a60743f0e47 100644
--- a/spec/features/projects/settings/user_searches_in_settings_spec.rb
+++ b/spec/features/projects/settings/user_searches_in_settings_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe 'User searches project settings', :js do
visit project_settings_operations_path(project)
end
- it_behaves_like 'can search settings', 'Alert integrations', 'Error tracking'
+ it_behaves_like 'can search settings', 'Alerts', 'Error tracking'
end
context 'in Pages page' do
diff --git a/spec/finders/concerns/packages/finder_helper_spec.rb b/spec/finders/concerns/packages/finder_helper_spec.rb
index bad4c482bc6..e8648d131ff 100644
--- a/spec/finders/concerns/packages/finder_helper_spec.rb
+++ b/spec/finders/concerns/packages/finder_helper_spec.rb
@@ -113,41 +113,22 @@ RSpec.describe ::Packages::FinderHelper do
let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) }
- shared_examples 'handling all conditions' do
- where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both packages'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both packages'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both packages'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both packages'
- end
-
- with_them do
- before do
- project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
- subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
- project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
- group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
- end
-
- it_behaves_like params[:shared_example_name]
- end
- end
-
- context 'with packages_finder_helper_deploy_token enabled' do
- before do
- expect(group).not_to receive(:all_projects)
- end
-
- it_behaves_like 'handling all conditions'
+ where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both packages'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both packages'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both packages'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both packages'
end
- context 'with packages_finder_helper_deploy_token disabled' do
+ with_them do
before do
- stub_feature_flags(packages_finder_helper_deploy_token: false)
- expect(group).to receive(:all_projects).and_call_original
+ project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
+ subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
+ project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
end
- it_behaves_like 'handling all conditions'
+ it_behaves_like params[:shared_example_name]
end
end
end
@@ -236,41 +217,22 @@ RSpec.describe ::Packages::FinderHelper do
let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) }
- shared_examples 'handling all conditions' do
- where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do
- 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both projects'
- 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both projects'
- 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both projects'
- 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both projects'
- end
-
- with_them do
- before do
- project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
- subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
- project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
- group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
- end
-
- it_behaves_like params[:shared_example_name]
- end
- end
-
- context 'with packages_finder_helper_deploy_token enabled' do
- before do
- expect(group).not_to receive(:all_projects)
- end
-
- it_behaves_like 'handling all conditions'
+ where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do
+ 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both projects'
+ 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both projects'
+ 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both projects'
+ 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both projects'
end
- context 'with packages_finder_helper_deploy_token disabled' do
+ with_them do
before do
- stub_feature_flags(packages_finder_helper_deploy_token: false)
- expect(group).to receive(:all_projects).and_call_original
+ project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false))
+ subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false))
+ project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
+ group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false))
end
- it_behaves_like 'handling all conditions'
+ it_behaves_like params[:shared_example_name]
end
end
end
diff --git a/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js b/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js
index c43d78a1cf3..3ffbb7ab60a 100644
--- a/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js
@@ -80,7 +80,7 @@ describe('AlertIntegrationsList', () => {
const cell = finsStatusCell().at(0);
const activatedIcon = cell.find(GlIcon);
expect(cell.text()).toBe(i18n.status.enabled.name);
- expect(activatedIcon.attributes('name')).toBe('check-circle-filled');
+ expect(activatedIcon.attributes('name')).toBe('check');
expect(activatedIcon.attributes('title')).toBe(i18n.status.enabled.tooltip);
});
diff --git a/spec/frontend/blob/components/table_contents_spec.js b/spec/frontend/blob/components/table_contents_spec.js
new file mode 100644
index 00000000000..09633dc5d5d
--- /dev/null
+++ b/spec/frontend/blob/components/table_contents_spec.js
@@ -0,0 +1,67 @@
+import { GlDropdownItem } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import TableContents from '~/blob/components/table_contents.vue';
+
+let wrapper;
+
+function createComponent() {
+ wrapper = shallowMount(TableContents);
+}
+
+async function setLoaded(loaded) {
+ document.querySelector('.blob-viewer').setAttribute('data-loaded', loaded);
+
+ await nextTick();
+}
+
+describe('Markdown table of contents component', () => {
+ beforeEach(() => {
+ setFixtures(`
+ <div class="blob-viewer" data-type="rich" data-loaded="false">
+ <h1><a href="#1"></a>Hello</h1>
+ <h2><a href="#2"></a>World</h2>
+ <h3><a href="#3"></a>Testing</h3>
+ <h2><a href="#4"></a>GitLab</h2>
+ </div>
+ `);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('not loaded', () => {
+ it('does not populate dropdown', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(false);
+ });
+ });
+
+ describe('loaded', () => {
+ it('populates dropdown', async () => {
+ createComponent();
+
+ await setLoaded(true);
+
+ const dropdownItems = wrapper.findAllComponents(GlDropdownItem);
+
+ expect(dropdownItems.exists()).toBe(true);
+ expect(dropdownItems.length).toBe(4);
+ });
+
+ it('sets padding for dropdown items', async () => {
+ createComponent();
+
+ await setLoaded(true);
+
+ const dropdownLinks = wrapper.findAll('[data-testid="tableContentsLink"]');
+
+ expect(dropdownLinks.at(0).element.style.paddingLeft).toBe('0px');
+ expect(dropdownLinks.at(1).element.style.paddingLeft).toBe('8px');
+ expect(dropdownLinks.at(2).element.style.paddingLeft).toBe('16px');
+ expect(dropdownLinks.at(3).element.style.paddingLeft).toBe('8px');
+ });
+ });
+});
diff --git a/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap b/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
index 1d2a5d636bc..7082d652706 100644
--- a/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
+++ b/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
@@ -43,14 +43,18 @@ exports[`grafana integration component default state to match the default snapsh
class="settings-content"
>
<form>
- <gl-form-checkbox-stub
- class="mb-4"
- id="grafana-integration-enabled"
+ <gl-form-group-stub
+ label="Enable authentication"
+ label-for="grafana-integration-enabled"
>
+ <gl-form-checkbox-stub
+ id="grafana-integration-enabled"
+ >
+
+ Active
- Active
-
- </gl-form-checkbox-stub>
+ </gl-form-checkbox-stub>
+ </gl-form-group-stub>
<gl-form-group-stub
description="Enter the base URL of the Grafana instance."
@@ -76,32 +80,19 @@ exports[`grafana integration component default state to match the default snapsh
<p
class="form-text text-muted"
>
-
- Enter the Grafana API token.
-
- <a
- href="https://grafana.com/docs/http_api/auth/#create-api-token"
- rel="noopener noreferrer"
- target="_blank"
- >
-
- More information.
-
- <gl-icon-stub
- class="vertical-align-middle"
- name="external-link"
- size="16"
- />
- </a>
+ <gl-sprintf-stub
+ message="Enter the %{docLinkStart}Grafana API token%{docLinkEnd}."
+ />
</p>
</gl-form-group-stub>
<gl-button-stub
buttontextclasses=""
category="primary"
+ data-testid="save-grafana-settings-button"
icon=""
size="medium"
- variant="success"
+ variant="confirm"
>
Save changes
diff --git a/spec/frontend/grafana_integration/components/grafana_integration_spec.js b/spec/frontend/grafana_integration/components/grafana_integration_spec.js
index f1a8e6fe2dc..d894cc7cc75 100644
--- a/spec/frontend/grafana_integration/components/grafana_integration_spec.js
+++ b/spec/frontend/grafana_integration/components/grafana_integration_spec.js
@@ -1,6 +1,7 @@
import { GlButton } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import GrafanaIntegration from '~/grafana_integration/components/grafana_integration.vue';
import { createStore } from '~/grafana_integration/store';
@@ -51,8 +52,7 @@ describe('grafana integration component', () => {
it('renders as an expand button by default', () => {
wrapper = shallowMount(GrafanaIntegration, { store });
- const button = wrapper.find(GlButton);
-
+ const button = wrapper.findComponent(GlButton);
expect(button.text()).toBe('Expand');
});
});
@@ -70,6 +70,7 @@ describe('grafana integration component', () => {
describe('form', () => {
beforeEach(() => {
jest.spyOn(axios, 'patch').mockImplementation();
+ wrapper = mountExtended(GrafanaIntegration, { store });
});
afterEach(() => {
@@ -77,7 +78,7 @@ describe('grafana integration component', () => {
});
describe('submit button', () => {
- const findSubmitButton = () => wrapper.find('.settings-content form').find(GlButton);
+ const findSubmitButton = () => wrapper.findByTestId('save-grafana-settings-button');
const endpointRequest = [
operationsSettingsEndpoint,
@@ -93,9 +94,7 @@ describe('grafana integration component', () => {
];
it('submits form on click', () => {
- wrapper = mount(GrafanaIntegration, { store });
axios.patch.mockResolvedValue();
-
findSubmitButton(wrapper).trigger('click');
expect(axios.patch).toHaveBeenCalledWith(...endpointRequest);
@@ -104,7 +103,6 @@ describe('grafana integration component', () => {
it('creates flash banner on error', () => {
const message = 'mockErrorMessage';
- wrapper = mount(GrafanaIntegration, { store });
axios.patch.mockRejectedValue({ response: { data: { message } } });
findSubmitButton().trigger('click');
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap
index 85d21f231b1..3d32585a211 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap
@@ -103,7 +103,7 @@ exports[`Alert integration settings form default state should match the default
icon=""
size="medium"
type="submit"
- variant="success"
+ variant="confirm"
>
Save changes
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
index 07f90a12f0f..450b1236015 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
@@ -30,7 +30,7 @@ exports[`IncidentsSettingTabs should render the component 1`] = `
<p>
- Set up integrations with external tools to help better manage incidents.
+ Fine-tune incident settings and set up integrations with external tools to help better manage incidents.
</p>
</div>
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
index 79ad5ad1bb9..a374ac7e4f2 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
@@ -66,20 +66,6 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
</gl-modal-stub>
</gl-form-group-stub>
-
- <gl-button-stub
- buttontextclasses=""
- category="primary"
- class="js-no-auto-disable"
- icon=""
- size="medium"
- type="submit"
- variant="success"
- >
-
- Save changes
-
- </gl-button-stub>
</form>
</div>
`;
diff --git a/spec/frontend/incidents_settings/components/pagerduty_form_spec.js b/spec/frontend/incidents_settings/components/pagerduty_form_spec.js
index 2ffd1292ddc..d2b591d427d 100644
--- a/spec/frontend/incidents_settings/components/pagerduty_form_spec.js
+++ b/spec/frontend/incidents_settings/components/pagerduty_form_spec.js
@@ -1,5 +1,5 @@
-import { GlAlert, GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlAlert, GlModal, GlToggle } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PagerDutySettingsForm from '~/incidents_settings/components/pagerduty_form.vue';
@@ -8,13 +8,13 @@ describe('Alert integration settings form', () => {
const resetWebhookUrl = jest.fn();
const service = { updateSettings: jest.fn().mockResolvedValue(), resetWebhookUrl };
- const findForm = () => wrapper.find({ ref: 'settingsForm' });
- const findWebhookInput = () => wrapper.find('[data-testid="webhook-url"]');
- const findModal = () => wrapper.find(GlModal);
- const findAlert = () => wrapper.find(GlAlert);
+ const findWebhookInput = () => wrapper.findByTestId('webhook-url');
+ const findFormToggle = () => wrapper.findComponent(GlToggle);
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findAlert = () => wrapper.findComponent(GlAlert);
beforeEach(() => {
- wrapper = shallowMount(PagerDutySettingsForm, {
+ wrapper = shallowMountExtended(PagerDutySettingsForm, {
provide: {
service,
pagerDutySettings: {
@@ -27,18 +27,15 @@ describe('Alert integration settings form', () => {
});
afterEach(() => {
- if (wrapper) {
- wrapper.destroy();
- wrapper = null;
- }
+ wrapper.destroy();
});
it('should match the default snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('should call service `updateSettings` on form submit', () => {
- findForm().trigger('submit');
+ it('should call service `updateSettings` on toggle change', () => {
+ findFormToggle().vm.$emit('change', true);
expect(service.updateSettings).toHaveBeenCalledWith(
expect.objectContaining({ pagerduty_active: wrapper.vm.active }),
);
diff --git a/spec/frontend/nav/components/top_nav_menu_item_spec.js b/spec/frontend/nav/components/top_nav_menu_item_spec.js
index 579af13d08a..e2cacba1a68 100644
--- a/spec/frontend/nav/components/top_nav_menu_item_spec.js
+++ b/spec/frontend/nav/components/top_nav_menu_item_spec.js
@@ -7,6 +7,8 @@ const TEST_MENU_ITEM = {
icon: 'search',
href: '/pretty/good/burger',
view: 'burger-view',
+ css_class: 'test-super-crazy test-class',
+ data: { qa_selector: 'not-a-real-selector', method: 'post', testFoo: 'test' },
};
describe('~/nav/components/top_nav_menu_item.vue', () => {
@@ -47,6 +49,22 @@ describe('~/nav/components/top_nav_menu_item.vue', () => {
expect(button.text()).toBe(TEST_MENU_ITEM.title);
});
+ it('renders button classes', () => {
+ const button = findButton();
+
+ expect(button.classes()).toEqual(expect.arrayContaining(TEST_MENU_ITEM.css_class.split(' ')));
+ });
+
+ it('renders button data attributes', () => {
+ const button = findButton();
+
+ expect(button.attributes()).toMatchObject({
+ 'data-qa-selector': TEST_MENU_ITEM.data.qa_selector,
+ 'data-method': TEST_MENU_ITEM.data.method,
+ 'data-test-foo': TEST_MENU_ITEM.data.testFoo,
+ });
+ });
+
it('passes listeners to button', () => {
expect(listener).not.toHaveBeenCalled();
diff --git a/spec/frontend/operation_settings/components/metrics_settings_spec.js b/spec/frontend/operation_settings/components/metrics_settings_spec.js
index 272e9b71f67..9d2530ded1e 100644
--- a/spec/frontend/operation_settings/components/metrics_settings_spec.js
+++ b/spec/frontend/operation_settings/components/metrics_settings_spec.js
@@ -56,7 +56,7 @@ describe('operation settings external dashboard component', () => {
it('renders header text', () => {
mountComponent();
- expect(wrapper.find('.js-section-header').text()).toBe('Metrics dashboard');
+ expect(wrapper.find('.js-section-header').text()).toBe('Metrics');
});
describe('expand/collapse button', () => {
@@ -77,13 +77,13 @@ describe('operation settings external dashboard component', () => {
});
it('renders descriptive text', () => {
- expect(subHeader.text()).toContain('Manage Metrics Dashboard settings.');
+ expect(subHeader.text()).toContain('Manage metrics dashboard settings.');
});
it('renders help page link', () => {
const link = subHeader.find(GlLink);
- expect(link.text()).toBe('Learn more');
+ expect(link.text()).toBe('Learn more.');
expect(link.attributes().href).toBe(helpPage);
});
});
diff --git a/spec/graphql/mutations/issues/set_subscription_spec.rb b/spec/graphql/mutations/issues/set_subscription_spec.rb
index 9e05a136c0b..7e2c3d93c51 100644
--- a/spec/graphql/mutations/issues/set_subscription_spec.rb
+++ b/spec/graphql/mutations/issues/set_subscription_spec.rb
@@ -3,8 +3,38 @@
require 'spec_helper'
RSpec.describe Mutations::Issues::SetSubscription do
- it_behaves_like 'a subscribeable graphql resource' do
- let_it_be(:resource) { create(:issue) }
- let(:permission_name) { :update_issue }
+ let_it_be_with_reload(:project) { create(:project) }
+ let_it_be_with_reload(:resource) { create(:issue, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ specify { expect(described_class).to require_graphql_authorizations(:update_subscription) }
+
+ context 'when user does not have access to the project' do
+ it_behaves_like 'a subscribeable not accessible graphql resource'
+ end
+
+ context 'when user is developer member of the project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'a subscribeable graphql resource'
+ end
+
+ context 'when the project is public' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it_behaves_like 'a subscribeable graphql resource'
+ end
+
+ context 'when the project is public but the issue is confidential' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ resource.update!(confidential: true)
+ end
+
+ it_behaves_like 'a subscribeable not accessible graphql resource'
end
end
diff --git a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
index 600053637c9..377042f068c 100644
--- a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
+++ b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb
@@ -3,8 +3,30 @@
require 'spec_helper'
RSpec.describe Mutations::MergeRequests::SetSubscription do
- it_behaves_like 'a subscribeable graphql resource' do
- let_it_be(:resource) { create(:merge_request) }
- let(:permission_name) { :update_merge_request }
+ let_it_be_with_reload(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ let(:resource) { create(:merge_request, source_project: project, target_project: project) }
+
+ specify { expect(described_class).to require_graphql_authorizations(:update_subscription) }
+
+ context 'when user does not have access to the project' do
+ it_behaves_like 'a subscribeable not accessible graphql resource'
+ end
+
+ context 'when user is developer member of the project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'a subscribeable graphql resource'
+ end
+
+ context 'when the project is public' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it_behaves_like 'a subscribeable graphql resource'
end
end
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
index b73d77a4ea9..b9912171a73 100644
--- a/spec/helpers/nav/top_nav_helper_spec.rb
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -424,7 +424,7 @@ RSpec.describe Nav::TopNavHelper do
title: 'Leave Admin Mode',
icon: 'lock-open',
href: '/admin/session/destroy',
- method: :post
+ data: { method: 'post' }
)
expect(subject[:secondary].last).to eq(expected_leave_admin_mode_item)
end
diff --git a/spec/lib/gitlab/instrumentation/redis_base_spec.rb b/spec/lib/gitlab/instrumentation/redis_base_spec.rb
index 07be0ccf6e9..a7e08b5a9bd 100644
--- a/spec/lib/gitlab/instrumentation/redis_base_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_base_spec.rb
@@ -18,24 +18,6 @@ RSpec.describe Gitlab::Instrumentation::RedisBase, :request_store do
end
end
- describe '.known_payload_keys' do
- it 'returns generated payload keys' do
- expect(instrumentation_class_a.known_payload_keys).to eq([:redis_instance_a_calls,
- :redis_instance_a_duration_s,
- :redis_instance_a_read_bytes,
- :redis_instance_a_write_bytes])
- end
-
- it 'does not call calculation methods' do
- expect(instrumentation_class_a).not_to receive(:get_request_count)
- expect(instrumentation_class_a).not_to receive(:query_time)
- expect(instrumentation_class_a).not_to receive(:read_bytes)
- expect(instrumentation_class_a).not_to receive(:write_bytes)
-
- instrumentation_class_a.known_payload_keys
- end
- end
-
describe '.payload' do
it 'returns values that are higher than 0' do
allow(instrumentation_class_a).to receive(:get_request_count) { 1 }
diff --git a/spec/lib/gitlab/instrumentation/redis_spec.rb b/spec/lib/gitlab/instrumentation/redis_spec.rb
index e927f39cae2..d712d09bdd8 100644
--- a/spec/lib/gitlab/instrumentation/redis_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_spec.rb
@@ -26,46 +26,6 @@ RSpec.describe Gitlab::Instrumentation::Redis do
it_behaves_like 'aggregation of redis storage data', :read_bytes
it_behaves_like 'aggregation of redis storage data', :write_bytes
- describe '.known_payload_keys' do
- it 'returns all known payload keys' do
- expected_keys = [
- :redis_calls,
- :redis_duration_s,
- :redis_read_bytes,
- :redis_write_bytes,
- :redis_action_cable_calls,
- :redis_action_cable_duration_s,
- :redis_action_cable_read_bytes,
- :redis_action_cable_write_bytes,
- :redis_cache_calls,
- :redis_cache_duration_s,
- :redis_cache_read_bytes,
- :redis_cache_write_bytes,
- :redis_queues_calls,
- :redis_queues_duration_s,
- :redis_queues_read_bytes,
- :redis_queues_write_bytes,
- :redis_shared_state_calls,
- :redis_shared_state_duration_s,
- :redis_shared_state_read_bytes,
- :redis_shared_state_write_bytes
- ]
-
- expect(described_class.known_payload_keys).to eq(expected_keys)
- end
-
- it 'does not call storage calculation methods' do
- described_class::STORAGES.each do |storage|
- expect(storage).not_to receive(:get_request_count)
- expect(storage).not_to receive(:query_time)
- expect(storage).not_to receive(:read_bytes)
- expect(storage).not_to receive(:write_bytes)
- end
-
- described_class.known_payload_keys
- end
- end
-
describe '.payload', :request_store do
before do
Gitlab::Redis::Cache.with { |redis| redis.set('cache-test', 321) }
diff --git a/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb b/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb
index 26f9ea3a637..c96bed2284b 100644
--- a/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb
+++ b/spec/lib/gitlab/nav/top_nav_menu_item_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe ::Gitlab::Nav::TopNavMenuItem do
active: true,
icon: 'icon',
href: 'href',
- method: 'method',
view: 'view',
css_class: 'css_class',
data: {}
diff --git a/spec/lib/gitlab/sidekiq_middleware/instrumentation_logger_spec.rb b/spec/lib/gitlab/sidekiq_middleware/instrumentation_logger_spec.rb
index eb9ba50cdcd..8cf65e1be5b 100644
--- a/spec/lib/gitlab/sidekiq_middleware/instrumentation_logger_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/instrumentation_logger_spec.rb
@@ -24,58 +24,10 @@ RSpec.describe Gitlab::SidekiqMiddleware::InstrumentationLogger do
stub_const('TestWorker', worker)
end
- describe '.keys' do
- it 'returns all available payload keys' do
- expected_keys = [
- :cpu_s,
- :gitaly_calls,
- :gitaly_duration_s,
- :rugged_calls,
- :rugged_duration_s,
- :elasticsearch_calls,
- :elasticsearch_duration_s,
- :elasticsearch_timed_out_count,
- :mem_objects,
- :mem_bytes,
- :mem_mallocs,
- :redis_calls,
- :redis_duration_s,
- :redis_read_bytes,
- :redis_write_bytes,
- :redis_action_cable_calls,
- :redis_action_cable_duration_s,
- :redis_action_cable_read_bytes,
- :redis_action_cable_write_bytes,
- :redis_cache_calls,
- :redis_cache_duration_s,
- :redis_cache_read_bytes,
- :redis_cache_write_bytes,
- :redis_queues_calls,
- :redis_queues_duration_s,
- :redis_queues_read_bytes,
- :redis_queues_write_bytes,
- :redis_shared_state_calls,
- :redis_shared_state_duration_s,
- :redis_shared_state_read_bytes,
- :redis_shared_state_write_bytes,
- :db_count,
- :db_write_count,
- :db_cached_count,
- :external_http_count,
- :external_http_duration_s,
- :rack_attack_redis_count,
- :rack_attack_redis_duration_s
- ]
-
- expect(described_class.keys).to include(*expected_keys)
- end
- end
-
describe '#call', :request_store do
let(:instrumentation_values) do
{
cpu_s: 10,
- unknown_attribute: 123,
db_count: 0,
db_cached_count: 0,
db_write_count: 0,
@@ -90,12 +42,10 @@ RSpec.describe Gitlab::SidekiqMiddleware::InstrumentationLogger do
end
end
- it 'merges correct instrumentation data in the job' do
+ it 'merges all instrumentation data in the job' do
expect { |b| subject.call(worker, job, queue, &b) }.to yield_control
- expected_values = instrumentation_values.except(:unknown_attribute)
-
- expect(job[:instrumentation]).to eq(expected_values)
+ expect(job[:instrumentation]).to eq(instrumentation_values)
end
end
end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 72cd028b0b9..b0575b63c8a 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -594,6 +594,18 @@ RSpec.describe Member do
end
end
+ context 'when called with a known user secondary email' do
+ let(:secondary_email) { create(:email, email: 'secondary@example.com', user: user) }
+
+ it 'adds the user as a member' do
+ expect(source.users).not_to include(user)
+
+ described_class.add_user(source, secondary_email.email, :maintainer)
+
+ expect(source.users.reload).to include(user)
+ end
+ end
+
context 'when called with an unknown user email' do
it 'creates an invited member' do
expect(source.users).not_to include(user)
diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb
index 76788ae2cb7..ed0050e8224 100644
--- a/spec/policies/issue_policy_spec.rb
+++ b/spec/policies/issue_policy_spec.rb
@@ -139,13 +139,14 @@ RSpec.describe IssuePolicy do
create(:project_group_link, group: group, project: project)
end
- it 'does not allow guest to create todos' do
+ it 'does not allow anonymous user to create todos' do
expect(permissions(nil, issue)).to be_allowed(:read_issue)
expect(permissions(nil, issue)).to be_disallowed(:create_todo)
+ expect(permissions(nil, issue)).to be_disallowed(:update_subscription)
end
it 'allows guests to read issues' do
- expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid, :create_todo)
+ expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid, :create_todo, :update_subscription)
expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue)
expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
@@ -205,12 +206,18 @@ RSpec.describe IssuePolicy do
it 'forbids visitors from commenting' do
expect(permissions(visitor, issue)).to be_disallowed(:create_note)
end
+ it 'forbids visitors from subscribing' do
+ expect(permissions(visitor, issue)).to be_disallowed(:update_subscription)
+ end
it 'allows guests to view' do
expect(permissions(guest, issue)).to be_allowed(:read_issue)
end
it 'allows guests to comment' do
expect(permissions(guest, issue)).to be_allowed(:create_note)
end
+ it 'allows guests to subscribe' do
+ expect(permissions(guest, issue)).to be_allowed(:update_subscription)
+ end
context 'when admin mode is enabled', :enable_admin_mode do
it 'allows admins to view' do
diff --git a/spec/policies/merge_request_policy_spec.rb b/spec/policies/merge_request_policy_spec.rb
index 744822f58d1..b94df4d4374 100644
--- a/spec/policies/merge_request_policy_spec.rb
+++ b/spec/policies/merge_request_policy_spec.rb
@@ -26,7 +26,8 @@ RSpec.describe MergeRequestPolicy do
read_merge_request
create_todo
approve_merge_request
- create_note].freeze
+ create_note
+ update_subscription].freeze
shared_examples_for 'a denied user' do
let(:perms) { permissions(subject, merge_request) }
@@ -55,7 +56,7 @@ RSpec.describe MergeRequestPolicy do
subject { permissions(nil, merge_request) }
it do
- is_expected.to be_disallowed(:create_todo)
+ is_expected.to be_disallowed(:create_todo, :update_subscription)
end
end
end
diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb
index d7fd7d5b2ca..7007d37ad8d 100644
--- a/spec/services/members/invite_service_spec.rb
+++ b/spec/services/members/invite_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_shared_state, :sidekiq_inline do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
let_it_be(:user) { project.owner }
let_it_be(:project_user) { create(:user) }
let_it_be(:namespace) { project.namespace }
@@ -23,6 +23,18 @@ RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_
it_behaves_like 'records an onboarding progress action', :user_added
end
+ context 'when email belongs to an existing user as a secondary email' do
+ let(:secondary_email) { create(:email, email: 'secondary@example.com', user: project_user) }
+ let(:params) { { email: secondary_email.email } }
+
+ it 'adds an existing user to members', :aggregate_failures do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:success)
+ expect(project.users).to include project_user
+ expect(project.members.last).not_to be_invite
+ end
+ end
+
context 'when email is not a valid email' do
let(:params) { { email: '_bogus_' } }
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index b2351ab53bd..da547716e1e 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
let(:opts) do
{
title: 'Awesome merge_request',
- description: "well this is not done yet\n/wip",
+ description: "well this is not done yet\n/draft",
source_branch: 'feature',
target_branch: 'master',
assignees: [user2]
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 31263feb947..5b4d6188b66 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -307,7 +307,7 @@ RSpec.describe Notes::CreateService do
),
# Set WIP status
QuickAction.new(
- action_text: "/wip",
+ action_text: "/draft",
before_action: -> {
issuable.reload.update!(title: "title")
},
@@ -317,7 +317,7 @@ RSpec.describe Notes::CreateService do
),
# Remove WIP status
QuickAction.new(
- action_text: "/wip",
+ action_text: "/draft",
before_action: -> {
issuable.reload.update!(title: "WIP: title")
},
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index f3ad69bae13..4af76bc65ab 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1202,16 +1202,6 @@ RSpec.describe QuickActions::InterpretService do
end
it_behaves_like 'draft command' do
- let(:content) { '/wip' }
- let(:issuable) { merge_request }
- end
-
- it_behaves_like 'undraft command' do
- let(:content) { '/wip' }
- let(:issuable) { merge_request }
- end
-
- it_behaves_like 'draft command' do
let(:content) { '/draft' }
let(:issuable) { merge_request }
end
diff --git a/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
index ebba312e895..678bb908343 100644
--- a/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/resolves_subscription_shared_examples.rb
@@ -2,44 +2,37 @@
require 'spec_helper'
-RSpec.shared_examples 'a subscribeable graphql resource' do
- let(:project) { resource.project }
- let_it_be(:user) { create(:user) }
-
- subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+RSpec.shared_examples 'a subscribeable not accessible graphql resource' do
+ let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
- specify { expect(described_class).to require_graphql_authorizations(permission_name) }
+ subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: true) }
- describe '#resolve' do
- let(:subscribe) { true }
- let(:mutated_resource) { subject[resource.class.name.underscore.to_sym] }
-
- subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: subscribe) }
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+end
- it 'raises an error if the resource is not accessible to the user' do
- expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
- end
+RSpec.shared_examples 'a subscribeable graphql resource' do
+ let(:mutated_resource) { subject[resource.class.name.underscore.to_sym] }
+ let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+ let(:subscribe) { true }
- context 'when the user can update the resource' do
- before do
- resource.project.add_developer(user)
- end
+ subject { mutation.resolve(project_path: resource.project.full_path, iid: resource.iid, subscribed_state: subscribe) }
- it 'subscribes to the resource' do
- expect(mutated_resource).to eq(resource)
- expect(mutated_resource.subscribed?(user, project)).to eq(true)
- expect(subject[:errors]).to be_empty
- end
+ it 'subscribes to the resource' do
+ expect(mutated_resource).to eq(resource)
+ expect(mutated_resource.subscribed?(user, project)).to eq(true)
+ expect(subject[:errors]).to be_empty
+ end
- context 'when passing subscribe as false' do
- let(:subscribe) { false }
+ context 'when passing subscribe as false' do
+ let(:subscribe) { false }
- it 'unsubscribes from the discussion' do
- resource.subscribe(user, project)
+ it 'unsubscribes from the discussion' do
+ resource.subscribe(user, project)
- expect(mutated_resource.subscribed?(user, project)).to eq(false)
- end
- end
+ expect(mutated_resource.subscribed?(user, project)).to eq(false)
+ expect(subject[:errors]).to be_empty
end
end
end
diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb
index ab868eb78b8..5cf3e6d849c 100644
--- a/spec/views/projects/settings/operations/show.html.haml_spec.rb
+++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'projects/settings/operations/show' do
it 'renders the Operations Settings page' do
render
- expect(rendered).to have_content _('Alert integrations')
+ expect(rendered).to have_content _('Alerts')
expect(rendered).to have_content _('Display alerts from all configured monitoring tools.')
end
end
@@ -77,41 +77,11 @@ RSpec.describe 'projects/settings/operations/show' do
end
describe 'Operations > Tracing' do
- context 'with project.tracing_external_url' do
- it 'links to project.tracing_external_url' do
- render
-
- expect(rendered).to have_link('Tracing', href: tracing_setting.external_url)
- end
-
- context 'with malicious external_url' do
- let(:malicious_tracing_url) { "https://replaceme.com/'><script>alert(document.cookie)</script>" }
- let(:cleaned_url) { "https://replaceme.com/'>" }
-
- before do
- tracing_setting.update_column(:external_url, malicious_tracing_url)
- end
-
- it 'sanitizes external_url' do
- render
-
- expect(tracing_setting.external_url).to eq(malicious_tracing_url)
- expect(rendered).to have_link('Tracing', href: cleaned_url)
- end
- end
- end
-
- context 'without project.tracing_external_url' do
- let(:tracing_setting) { build(:project_tracing_setting, project: project) }
-
- before do
- tracing_setting.external_url = nil
- end
-
- it 'links to Tracing page' do
+ context 'Settings page ' do
+ it 'renders the Tracing Settings page' do
render
- expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
+ expect(rendered).to have_content _('Embed an image of your existing Jaeger server in GitLab.')
end
end
end