Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b3c8b65ec2
commit
f2c27c6f97
|
@ -15,7 +15,6 @@
|
|||
# SEED_NESTED_GROUPS: "false" # requires network connection
|
||||
|
||||
.run-dev-fixtures-script: &run-dev-fixtures-script
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- run_timed_command "RAILS_ENV=test bundle exec rake db:seed_fu"
|
||||
|
||||
|
|
|
@ -103,7 +103,6 @@ update-yarn-cache:
|
|||
WEBPACK_VENDOR_DLL: "true"
|
||||
script:
|
||||
- run_timed_command "gem install knapsack --no-document"
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source ./scripts/rspec_helpers.sh
|
||||
- rspec_paralellized_job "--tag frontend_fixture"
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
# Only install knapsack after bundle install! Otherwise oddly some native
|
||||
# gems could not be found under some circumstance. No idea why, hours wasted.
|
||||
- run_timed_command "gem install knapsack --no-document"
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source ./scripts/rspec_helpers.sh
|
||||
|
||||
|
@ -150,20 +149,35 @@ setup-test-env:
|
|||
script:
|
||||
- run_timed_command "bundle exec ruby -I. -e 'require \"config/environment\"; TestEnv.init'"
|
||||
- run_timed_command "scripts/gitaly-test-build" # Do not use 'bundle exec' here
|
||||
- rm tmp/tests/gitaly/.ruby-bundle # This file prevents gems from being installed even if vendor/gitaly-ruby is missing
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- config/secrets.yml
|
||||
- tmp/tests/gitaly
|
||||
- tmp/tests/gitlab-elasticsearch-indexer
|
||||
- tmp/tests/gitlab-shell
|
||||
- tmp/tests/gitlab-test-fork
|
||||
- tmp/tests/gitlab-test-fork_bare
|
||||
- tmp/tests/gitlab-test
|
||||
- tmp/tests/gitlab-workhorse
|
||||
- tmp/tests/repositories
|
||||
- tmp/tests/second_storage
|
||||
- tmp/tests/gitaly/config.toml
|
||||
- tmp/tests/gitaly/gitaly
|
||||
- tmp/tests/gitaly/gitaly2.config.toml
|
||||
- tmp/tests/gitaly/gitaly-git2go
|
||||
- tmp/tests/gitaly/gitaly-hooks
|
||||
- tmp/tests/gitaly/gitaly-lfs-smudge
|
||||
- tmp/tests/gitaly/gitaly-ssh
|
||||
- tmp/tests/gitaly/internal/
|
||||
- tmp/tests/gitaly/internal_sockets/
|
||||
- tmp/tests/gitaly/Makefile
|
||||
- tmp/tests/gitaly/praefect
|
||||
- tmp/tests/gitaly/praefect.config.toml
|
||||
- tmp/tests/gitaly/ruby/
|
||||
- tmp/tests/gitlab-elasticsearch-indexer/bin/gitlab-elasticsearch-indexer
|
||||
- tmp/tests/gitlab-shell/
|
||||
- tmp/tests/gitlab-test-fork/
|
||||
- tmp/tests/gitlab-test-fork_bare/
|
||||
- tmp/tests/gitlab-test/
|
||||
- tmp/tests/gitlab-workhorse/gitlab-zip-metadata
|
||||
- tmp/tests/gitlab-workhorse/gitlab-zip-cat
|
||||
- tmp/tests/gitlab-workhorse/gitlab-workhorse
|
||||
- tmp/tests/gitlab-workhorse/gitlab-resize-image
|
||||
- tmp/tests/gitlab-workhorse/config.toml
|
||||
- tmp/tests/repositories/
|
||||
- tmp/tests/second_storage/
|
||||
when: always
|
||||
|
||||
update-rails-cache:
|
||||
|
|
|
@ -166,12 +166,6 @@ Lint/MixedRegexpCaptureTypes:
|
|||
- 'lib/gitlab/slash_commands/issue_new.rb'
|
||||
- 'lib/gitlab/slash_commands/run.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Lint/NonDeterministicRequireOrder:
|
||||
Exclude:
|
||||
- 'rubocop/rubocop.rb'
|
||||
|
||||
# Offense count: 135
|
||||
# Cop supports --auto-correct.
|
||||
Lint/RedundantCopDisableDirective:
|
||||
|
|
|
@ -1 +1 @@
|
|||
01e940cac5cdeaf1b14a18f3f71e0a3c50d1c60c
|
||||
4cc3e803023c9178a2112ac3f6bcd5b6b8660fd1
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -22,7 +22,7 @@ gem 'rugged', '~> 0.28'
|
|||
gem 'grape-path-helpers', '~> 1.5'
|
||||
|
||||
gem 'faraday', '~> 1.0'
|
||||
gem 'marginalia', '~> 1.9.0'
|
||||
gem 'marginalia', '~> 1.10.0'
|
||||
|
||||
# Authentication libraries
|
||||
gem 'devise', '~> 4.7.2'
|
||||
|
|
|
@ -695,7 +695,7 @@ GEM
|
|||
mini_mime (>= 0.1.1)
|
||||
marcel (0.3.3)
|
||||
mimemagic (~> 0.3.2)
|
||||
marginalia (1.9.0)
|
||||
marginalia (1.10.0)
|
||||
actionpack (>= 2.3)
|
||||
activerecord (>= 2.3)
|
||||
memoist (0.16.2)
|
||||
|
@ -1415,7 +1415,7 @@ DEPENDENCIES
|
|||
loofah (~> 2.2)
|
||||
lru_redux
|
||||
mail (= 2.7.1)
|
||||
marginalia (~> 1.9.0)
|
||||
marginalia (~> 1.10.0)
|
||||
memory_profiler (~> 0.9)
|
||||
method_source (~> 1.0)
|
||||
mimemagic (~> 0.3.2)
|
||||
|
|
|
@ -6,20 +6,11 @@ import alertsHelpUrlQuery from '../graphql/queries/alert_help_url.query.graphql'
|
|||
export default {
|
||||
i18n: {
|
||||
emptyState: {
|
||||
opsgenie: {
|
||||
title: s__('AlertManagement|Opsgenie is enabled'),
|
||||
info: s__(
|
||||
'AlertManagement|You have enabled the Opsgenie integration. Your alerts will be visible directly in Opsgenie.',
|
||||
),
|
||||
buttonText: s__('AlertManagement|View alerts in Opsgenie'),
|
||||
},
|
||||
gitlab: {
|
||||
title: s__('AlertManagement|Surface alerts in GitLab'),
|
||||
info: s__(
|
||||
'AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents.',
|
||||
),
|
||||
buttonText: s__('AlertManagement|Authorize external service'),
|
||||
},
|
||||
title: s__('AlertManagement|Surface alerts in GitLab'),
|
||||
info: s__(
|
||||
'AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents.',
|
||||
),
|
||||
buttonText: s__('AlertManagement|Authorize external service'),
|
||||
},
|
||||
moreInformation: s__('AlertManagement|More information'),
|
||||
},
|
||||
|
@ -33,46 +24,27 @@ export default {
|
|||
query: alertsHelpUrlQuery,
|
||||
},
|
||||
},
|
||||
inject: [
|
||||
'enableAlertManagementPath',
|
||||
'userCanEnableAlertManagement',
|
||||
'emptyAlertSvgPath',
|
||||
'opsgenieMvcEnabled',
|
||||
'opsgenieMvcTargetUrl',
|
||||
],
|
||||
inject: ['enableAlertManagementPath', 'userCanEnableAlertManagement', 'emptyAlertSvgPath'],
|
||||
data() {
|
||||
return {
|
||||
alertsHelpUrl: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
emptyState() {
|
||||
return {
|
||||
...(this.opsgenieMvcEnabled
|
||||
? this.$options.i18n.emptyState.opsgenie
|
||||
: this.$options.i18n.emptyState.gitlab),
|
||||
link: this.opsgenieMvcEnabled ? this.opsgenieMvcTargetUrl : this.enableAlertManagementPath,
|
||||
};
|
||||
},
|
||||
alertsCanBeEnabled() {
|
||||
return this.userCanEnableAlertManagement || this.opsgenieMvcEnabled;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<gl-empty-state :title="emptyState.title" :svg-path="emptyAlertSvgPath">
|
||||
<gl-empty-state :title="$options.i18n.emptyState.title" :svg-path="emptyAlertSvgPath">
|
||||
<template #description>
|
||||
<div class="gl-display-block">
|
||||
<span>{{ emptyState.info }}</span>
|
||||
<gl-link v-if="!opsgenieMvcEnabled" :href="alertsHelpUrl" target="_blank">
|
||||
<span>{{ $options.i18n.emptyState.info }}</span>
|
||||
<gl-link :href="alertsHelpUrl" target="_blank">
|
||||
{{ $options.i18n.moreInformation }}
|
||||
</gl-link>
|
||||
</div>
|
||||
<div v-if="alertsCanBeEnabled" class="gl-display-block center gl-pt-4">
|
||||
<gl-button category="primary" variant="success" :href="emptyState.link">
|
||||
{{ emptyState.buttonText }}
|
||||
<div v-if="userCanEnableAlertManagement" class="gl-display-block center gl-pt-4">
|
||||
<gl-button category="primary" variant="success" :href="enableAlertManagementPath">
|
||||
{{ $options.i18n.emptyState.buttonText }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -17,12 +17,10 @@ export default () => {
|
|||
emptyAlertSvgPath,
|
||||
populatingAlertsHelpUrl,
|
||||
alertsHelpUrl,
|
||||
opsgenieMvcTargetUrl,
|
||||
textQuery,
|
||||
assigneeUsernameQuery,
|
||||
alertManagementEnabled,
|
||||
userCanEnableAlertManagement,
|
||||
opsgenieMvcEnabled,
|
||||
} = domEl.dataset;
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
|
@ -57,10 +55,8 @@ export default () => {
|
|||
enableAlertManagementPath,
|
||||
populatingAlertsHelpUrl,
|
||||
emptyAlertSvgPath,
|
||||
opsgenieMvcTargetUrl,
|
||||
alertManagementEnabled: parseBoolean(alertManagementEnabled),
|
||||
userCanEnableAlertManagement: parseBoolean(userCanEnableAlertManagement),
|
||||
opsgenieMvcEnabled: parseBoolean(opsgenieMvcEnabled),
|
||||
},
|
||||
apolloProvider,
|
||||
components: {
|
||||
|
|
|
@ -18,14 +18,11 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
|||
import MappingBuilder from './alert_mapping_builder.vue';
|
||||
import AlertSettingsFormHelpBlock from './alert_settings_form_help_block.vue';
|
||||
import getCurrentIntegrationQuery from '../graphql/queries/get_current_integration.query.graphql';
|
||||
import service from '../services';
|
||||
import {
|
||||
integrationTypesNew,
|
||||
integrationTypes,
|
||||
JSON_VALIDATE_DELAY,
|
||||
targetPrometheusUrlPlaceholder,
|
||||
targetOpsgenieUrlPlaceholder,
|
||||
typeSet,
|
||||
sectionHash,
|
||||
} from '../constants';
|
||||
// Mocks will be removed when integrating with BE is ready
|
||||
// data format is defined and will be the same as mocked (maybe with some minor changes)
|
||||
|
@ -91,20 +88,13 @@ export const i18n = {
|
|||
'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.',
|
||||
),
|
||||
},
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
opsgenie: {
|
||||
label: s__('AlertSettings|2. Add link to your Opsgenie alert list'),
|
||||
info: s__(
|
||||
'AlertSettings|Utilizing this option will link the GitLab Alerts navigation item to your existing Opsgenie instance. By selecting this option, you cannot receive alerts from any other source in GitLab; it will effectively be turning Alerts within GitLab off as a feature.',
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
integrationTypes,
|
||||
placeholders: {
|
||||
prometheus: targetPrometheusUrlPlaceholder,
|
||||
opsgenie: targetOpsgenieUrlPlaceholder,
|
||||
},
|
||||
JSON_VALIDATE_DELAY,
|
||||
typeSet,
|
||||
|
@ -134,10 +124,6 @@ export default {
|
|||
prometheus: {
|
||||
default: {},
|
||||
},
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
opsgenie: {
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
|
@ -149,12 +135,6 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
canManageOpsgenie: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
currentIntegration: {
|
||||
|
@ -163,7 +143,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
selectedIntegration: integrationTypesNew[0].value,
|
||||
selectedIntegration: integrationTypes[0].value,
|
||||
active: false,
|
||||
formVisible: false,
|
||||
integrationTestPayload: {
|
||||
|
@ -174,8 +154,6 @@ export default {
|
|||
customMapping: null,
|
||||
parsingPayload: false,
|
||||
currentIntegration: null,
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
isManagingOpsgenie: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -185,32 +163,12 @@ export default {
|
|||
jsonIsValid() {
|
||||
return this.integrationTestPayload.error === null;
|
||||
},
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
disabledIntegrations() {
|
||||
const options = [];
|
||||
if (this.opsgenie.active) {
|
||||
options.push(typeSet.http, typeSet.prometheus);
|
||||
} else if (!this.canManageOpsgenie) {
|
||||
options.push(typeSet.opsgenie);
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
options() {
|
||||
return integrationTypesNew.map((el) => ({
|
||||
...el,
|
||||
disabled: this.disabledIntegrations.includes(el.value),
|
||||
}));
|
||||
},
|
||||
selectedIntegrationType() {
|
||||
switch (this.selectedIntegration) {
|
||||
case typeSet.http:
|
||||
return this.generic;
|
||||
case typeSet.prometheus:
|
||||
return this.prometheus;
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
case typeSet.opsgenie:
|
||||
return this.opsgenie;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
@ -285,49 +243,17 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
integrationTypeSelect() {
|
||||
if (this.selectedIntegration === integrationTypesNew[0].value) {
|
||||
if (this.selectedIntegration === integrationTypes[0].value) {
|
||||
this.formVisible = false;
|
||||
} else {
|
||||
this.formVisible = true;
|
||||
}
|
||||
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
if (this.canManageOpsgenie && this.selectedIntegration === typeSet.opsgenie) {
|
||||
this.isManagingOpsgenie = true;
|
||||
this.active = this.opsgenie.active;
|
||||
this.integrationForm.apiUrl = this.opsgenie.opsgenieMvcTargetUrl;
|
||||
} else {
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
this.isManagingOpsgenie = false;
|
||||
}
|
||||
},
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
submitWithOpsgenie() {
|
||||
return service
|
||||
.updateGenericActive({
|
||||
endpoint: this.opsgenie.formPath,
|
||||
params: {
|
||||
service: {
|
||||
opsgenie_mvc_target_url: this.integrationForm.apiUrl,
|
||||
opsgenie_mvc_enabled: this.active,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
window.location.hash = sectionHash;
|
||||
window.location.reload();
|
||||
});
|
||||
},
|
||||
submitWithTestPayload() {
|
||||
this.$emit('set-test-alert-payload', this.testAlertPayload);
|
||||
this.submit();
|
||||
},
|
||||
submit() {
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
if (this.isManagingOpsgenie) {
|
||||
return this.submitWithOpsgenie();
|
||||
}
|
||||
|
||||
const { name, apiUrl } = this.integrationForm;
|
||||
const variables =
|
||||
this.selectedIntegration === typeSet.http
|
||||
|
@ -343,7 +269,7 @@ export default {
|
|||
return this.$emit('create-new-integration', integrationPayload);
|
||||
},
|
||||
reset() {
|
||||
this.selectedIntegration = integrationTypesNew[0].value;
|
||||
this.selectedIntegration = integrationTypes[0].value;
|
||||
this.integrationTypeSelect();
|
||||
|
||||
if (this.currentIntegration) {
|
||||
|
@ -360,9 +286,6 @@ export default {
|
|||
error: null,
|
||||
};
|
||||
this.active = false;
|
||||
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
this.isManagingOpsgenie = false;
|
||||
},
|
||||
resetAuthKey() {
|
||||
if (!this.currentIntegration) {
|
||||
|
@ -428,8 +351,8 @@ export default {
|
|||
<gl-form-select
|
||||
v-model="selectedIntegration"
|
||||
:disabled="isSelectDisabled"
|
||||
:class="{ 'gl-bg-gray-100!': isSelectDisabled }"
|
||||
:options="options"
|
||||
class="mw-100"
|
||||
:options="$options.integrationTypes"
|
||||
@change="integrationTypeSelect"
|
||||
/>
|
||||
|
||||
|
@ -441,37 +364,7 @@ export default {
|
|||
</div>
|
||||
</gl-form-group>
|
||||
<gl-collapse v-model="formVisible" class="gl-mt-3">
|
||||
<!-- TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657 -->
|
||||
<div v-if="isManagingOpsgenie">
|
||||
<gl-form-group
|
||||
id="integration-webhook"
|
||||
:label="$options.i18n.integrationFormSteps.opsgenie.label"
|
||||
label-for="integration-webhook"
|
||||
>
|
||||
<span class="gl-my-4">
|
||||
{{ $options.i18n.integrationFormSteps.opsgenie.info }}
|
||||
</span>
|
||||
|
||||
<gl-toggle
|
||||
v-model="active"
|
||||
:is-loading="loading"
|
||||
:label="__('Active')"
|
||||
class="gl-my-4 gl-font-weight-normal"
|
||||
/>
|
||||
|
||||
<gl-form-input
|
||||
id="opsgenie-opsgenieMvcTargetUrl"
|
||||
v-model="integrationForm.apiUrl"
|
||||
type="text"
|
||||
:placeholder="$options.placeholders.opsgenie"
|
||||
/>
|
||||
|
||||
<span class="gl-text-gray-400 gl-my-1">
|
||||
{{ $options.i18n.integrationFormSteps.prometheusFormUrl.help }}
|
||||
</span>
|
||||
</gl-form-group>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<gl-form-group
|
||||
id="name-integration"
|
||||
:label="$options.i18n.integrationFormSteps.step2.label"
|
||||
|
@ -661,9 +554,7 @@ export default {
|
|||
data-testid="integration-form-submit"
|
||||
>{{ s__('AlertSettings|Save integration') }}
|
||||
</gl-button>
|
||||
<!-- TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657 -->
|
||||
<gl-button
|
||||
v-if="!isManagingOpsgenie"
|
||||
data-testid="integration-test-and-submit"
|
||||
:disabled="isSubmitTestPayloadDisabled"
|
||||
category="secondary"
|
||||
|
@ -672,12 +563,7 @@ export default {
|
|||
@click="submitWithTestPayload"
|
||||
>{{ s__('AlertSettings|Save and test payload') }}</gl-button
|
||||
>
|
||||
<gl-button
|
||||
type="reset"
|
||||
class="js-no-auto-disable"
|
||||
:class="{ 'gl-ml-3': isManagingOpsgenie }"
|
||||
>{{ __('Cancel') }}</gl-button
|
||||
>
|
||||
<gl-button type="reset" class="js-no-auto-disable">{{ __('Cancel') }}</gl-button>
|
||||
</div>
|
||||
</gl-collapse>
|
||||
</gl-form>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import createFlash, { FLASH_TYPES } from '~/flash';
|
||||
|
@ -41,10 +40,6 @@ export default {
|
|||
),
|
||||
},
|
||||
components: {
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
GlAlert,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
IntegrationsList,
|
||||
AlertSettingsForm,
|
||||
},
|
||||
|
@ -55,10 +50,6 @@ export default {
|
|||
prometheus: {
|
||||
default: {},
|
||||
},
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
opsgenie: {
|
||||
default: {},
|
||||
},
|
||||
projectPath: {
|
||||
default: '',
|
||||
},
|
||||
|
@ -105,13 +96,6 @@ export default {
|
|||
canAddIntegration() {
|
||||
return this.multiIntegrations || this.integrations?.list?.length < 2;
|
||||
},
|
||||
canManageOpsgenie() {
|
||||
return (
|
||||
this.opsgenie.active ||
|
||||
this.integrations?.list?.every(({ active }) => active === false) ||
|
||||
this.integrations?.list?.length === 0
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
createNewIntegration({ type, variables }) {
|
||||
|
@ -319,27 +303,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<!-- TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657 -->
|
||||
<gl-alert v-if="opsgenie.active" :dismissible="false" variant="tip">
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
'AlertSettings|We will soon be introducing the ability to create multiple unique HTTP endpoints. When this functionality is live, you will be able to configure an integration with Opsgenie to surface Opsgenie alerts in GitLab. This will replace the current Opsgenie integration which will be deprecated. %{linkStart}More Information%{linkEnd}',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #link="{ content }">
|
||||
<gl-link
|
||||
class="gl-display-inline-block"
|
||||
href="https://gitlab.com/gitlab-org/gitlab/-/issues/273657"
|
||||
target="_blank"
|
||||
>{{ content }}</gl-link
|
||||
>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</gl-alert>
|
||||
<integrations-list
|
||||
v-else
|
||||
:integrations="integrations.list"
|
||||
:loading="loading"
|
||||
@edit-integration="editIntegration"
|
||||
|
@ -348,7 +312,6 @@ export default {
|
|||
<alert-settings-form
|
||||
:loading="isUpdating"
|
||||
:can-add-integration="canAddIntegration"
|
||||
:can-manage-opsgenie="canManageOpsgenie"
|
||||
@create-new-integration="createNewIntegration"
|
||||
@update-integration="updateIntegration"
|
||||
@reset-token="resetToken"
|
||||
|
|
|
@ -40,22 +40,15 @@ export const i18n = {
|
|||
integration: s__('AlertSettings|Integration'),
|
||||
};
|
||||
|
||||
// TODO: Delete as part of old form removal in 13.6
|
||||
export const integrationTypes = [
|
||||
{ value: '', text: s__('AlertSettings|Select integration type') },
|
||||
{ value: 'HTTP', text: s__('AlertSettings|HTTP Endpoint') },
|
||||
{ value: 'PROMETHEUS', text: s__('AlertSettings|External Prometheus') },
|
||||
{ value: 'OPSGENIE', text: s__('AlertSettings|Opsgenie') },
|
||||
];
|
||||
|
||||
export const integrationTypesNew = [
|
||||
{ value: '', text: s__('AlertSettings|Select integration type') },
|
||||
...integrationTypes,
|
||||
];
|
||||
|
||||
export const typeSet = {
|
||||
http: 'HTTP',
|
||||
prometheus: 'PROMETHEUS',
|
||||
opsgenie: 'OPSGENIE',
|
||||
};
|
||||
|
||||
export const integrationToDeleteDefault = { id: null, name: '' };
|
||||
|
@ -63,7 +56,6 @@ export const integrationToDeleteDefault = { id: null, name: '' };
|
|||
export const JSON_VALIDATE_DELAY = 250;
|
||||
|
||||
export const targetPrometheusUrlPlaceholder = 'http://prometheus.example.com/';
|
||||
export const targetOpsgenieUrlPlaceholder = 'https://app.opsgenie.com/alert/list/';
|
||||
|
||||
export const sectionHash = 'js-alert-management-settings';
|
||||
|
||||
|
|
|
@ -29,10 +29,6 @@ export default (el) => {
|
|||
formPath,
|
||||
authorizationKey,
|
||||
url,
|
||||
opsgenieMvcAvailable,
|
||||
opsgenieMvcFormPath,
|
||||
opsgenieMvcEnabled,
|
||||
opsgenieMvcTargetUrl,
|
||||
projectPath,
|
||||
multiIntegrations,
|
||||
} = el.dataset;
|
||||
|
@ -56,12 +52,6 @@ export default (el) => {
|
|||
token: authorizationKey,
|
||||
url,
|
||||
},
|
||||
opsgenie: {
|
||||
formPath: opsgenieMvcFormPath,
|
||||
active: parseBoolean(opsgenieMvcEnabled),
|
||||
opsgenieMvcTargetUrl,
|
||||
opsgenieMvcIsAvailable: parseBoolean(opsgenieMvcAvailable),
|
||||
},
|
||||
projectPath,
|
||||
multiIntegrations: parseBoolean(multiIntegrations),
|
||||
},
|
||||
|
|
|
@ -23,7 +23,7 @@ export const KEEP_INFO_TEXT = s__(
|
|||
export const KEEP_N_LABEL = s__('ContainerRegistry|Keep the most recent:');
|
||||
export const NAME_REGEX_KEEP_LABEL = s__('ContainerRegistry|Keep tags matching:');
|
||||
export const NAME_REGEX_KEEP_DESCRIPTION = s__(
|
||||
'ContainerRegistry|Tags with names that match this regex pattern are kept. %{linkStart}More information%{linkEnd}',
|
||||
'ContainerRegistry|Tags with names that match this regex pattern are kept. %{linkStart}View regex examples.%{linkEnd}',
|
||||
);
|
||||
|
||||
export const REMOVE_HEADER_TEXT = s__('ContainerRegistry|Remove these tags');
|
||||
|
@ -34,7 +34,7 @@ export const EXPIRATION_SCHEDULE_LABEL = s__('ContainerRegistry|Remove tags olde
|
|||
export const NAME_REGEX_LABEL = s__('ContainerRegistry|Remove tags matching:');
|
||||
export const NAME_REGEX_PLACEHOLDER = '.*';
|
||||
export const NAME_REGEX_DESCRIPTION = s__(
|
||||
'ContainerRegistry|Tags with names that match this regex pattern are removed. %{linkStart}More information%{linkEnd}',
|
||||
'ContainerRegistry|Tags with names that match this regex pattern are removed. %{linkStart}View regex examples.%{linkEnd}',
|
||||
);
|
||||
|
||||
export const ENABLED_TOGGLE_DESCRIPTION = s__(
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<script>
|
||||
// NOTE! For the first iteration, we are simply copying the implementation of Assignees
|
||||
// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
|
||||
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { n__ } from '~/locale';
|
||||
|
||||
export default {
|
||||
name: 'ReviewerTitle',
|
||||
components: {
|
||||
GlLoadingIcon,
|
||||
GlIcon,
|
||||
},
|
||||
props: {
|
||||
loading: {
|
||||
|
@ -24,11 +23,6 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
showToggle: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
reviewerTitle() {
|
||||
|
@ -52,14 +46,5 @@ export default {
|
|||
>
|
||||
{{ __('Edit') }}
|
||||
</a>
|
||||
<a
|
||||
v-if="showToggle"
|
||||
:aria-label="__('Toggle sidebar')"
|
||||
class="gutter-toggle float-right js-sidebar-toggle"
|
||||
href="#"
|
||||
role="button"
|
||||
>
|
||||
<gl-icon data-hidden="true" name="chevron-double-lg-right" :size="12" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -26,11 +26,6 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
signedIn: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
issuableType: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -98,7 +93,6 @@ export default {
|
|||
:number-of-reviewers="store.reviewers.length"
|
||||
:loading="loading || store.isFetching.reviewers"
|
||||
:editable="store.editable"
|
||||
:show-toggle="!signedIn"
|
||||
/>
|
||||
<reviewers
|
||||
v-if="!store.isFetching.reviewers"
|
||||
|
|
|
@ -77,7 +77,6 @@ function mountReviewersComponent(mediator) {
|
|||
issuableIid: String(iid),
|
||||
projectPath: fullPath,
|
||||
field: el.dataset.field,
|
||||
signedIn: el.hasAttribute('data-signed-in'),
|
||||
issuableType: isInIssuePage() ? 'issue' : 'merge_request',
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -1,19 +1,36 @@
|
|||
<script>
|
||||
/* eslint-disable vue/no-v-html */
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { GlButton, GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { escape } from 'lodash';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import simplePoll from '../../../lib/utils/simple_poll';
|
||||
import eventHub from '../../event_hub';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
import rebaseQuery from '../../queries/states/ready_to_merge.query.graphql';
|
||||
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
|
||||
import { deprecatedCreateFlash as Flash } from '../../../flash';
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
||||
export default {
|
||||
name: 'MRWidgetRebase',
|
||||
apollo: {
|
||||
state: {
|
||||
query: rebaseQuery,
|
||||
skip() {
|
||||
return !this.glFeatures.mergeRequestWidgetGraphql;
|
||||
},
|
||||
variables() {
|
||||
return this.mergeRequestQueryVariables;
|
||||
},
|
||||
update: (data) => data.project.mergeRequest,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
statusIcon,
|
||||
GlButton,
|
||||
GlSkeletonLoader,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
|
@ -26,16 +43,41 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
state: {},
|
||||
isMakingRequest: false,
|
||||
rebasingError: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isLoading() {
|
||||
return this.glFeatures.mergeRequestWidgetGraphql && this.$apollo.queries.state.loading;
|
||||
},
|
||||
rebaseInProgress() {
|
||||
if (this.glFeatures.mergeRequestWidgetGraphql) {
|
||||
return this.state.rebaseInProgress;
|
||||
}
|
||||
|
||||
return this.mr.rebaseInProgress;
|
||||
},
|
||||
canPushToSourceBranch() {
|
||||
if (this.glFeatures.mergeRequestWidgetGraphql) {
|
||||
return this.state.userPermissions.pushToSourceBranch;
|
||||
}
|
||||
|
||||
return this.mr.canPushToSourceBranch;
|
||||
},
|
||||
targetBranch() {
|
||||
if (this.glFeatures.mergeRequestWidgetGraphql) {
|
||||
return this.state.targetBranch;
|
||||
}
|
||||
|
||||
return this.mr.targetBranch;
|
||||
},
|
||||
status() {
|
||||
if (this.mr.rebaseInProgress || this.isMakingRequest) {
|
||||
if (this.rebaseInProgress || this.isMakingRequest) {
|
||||
return 'loading';
|
||||
}
|
||||
if (!this.mr.canPushToSourceBranch && !this.mr.rebaseInProgress) {
|
||||
if (!this.canPushToSourceBranch && !this.rebaseInProgress) {
|
||||
return 'warning';
|
||||
}
|
||||
return 'success';
|
||||
|
@ -49,7 +91,7 @@ export default {
|
|||
'Fast-forward merge is not possible. Rebase the source branch onto %{targetBranch} to allow this merge request to be merged.',
|
||||
),
|
||||
{
|
||||
targetBranch: `<span class="label-branch">${escape(this.mr.targetBranch)}</span>`,
|
||||
targetBranch: `<span class="label-branch">${escape(this.targetBranch)}</span>`,
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
@ -105,17 +147,30 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div class="mr-widget-body media">
|
||||
<status-icon :status="status" :show-disabled-button="showDisabledButton" />
|
||||
<div v-if="isLoading" class="gl-w-full mr-conflict-loader">
|
||||
<gl-skeleton-loader :width="334" :height="30">
|
||||
<rect x="0" y="3" width="24" height="24" rx="4" />
|
||||
<rect x="32" y="5" width="302" height="20" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
</div>
|
||||
<template v-else>
|
||||
<status-icon :status="status" :show-disabled-button="showDisabledButton" />
|
||||
|
||||
<div class="rebase-state-find-class-convention media media-body space-children">
|
||||
<template v-if="mr.rebaseInProgress || isMakingRequest">
|
||||
<span class="bold" data-testid="rebase-message">{{ __('Rebase in progress') }}</span>
|
||||
</template>
|
||||
<template v-if="!mr.rebaseInProgress && !mr.canPushToSourceBranch">
|
||||
<span class="bold" data-testid="rebase-message" v-html="fastForwardMergeText"></span>
|
||||
</template>
|
||||
<template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
|
||||
<div class="rebase-state-find-class-convention media media-body space-children">
|
||||
<span
|
||||
v-if="rebaseInProgress || isMakingRequest"
|
||||
class="gl-font-weight-bold"
|
||||
data-testid="rebase-message"
|
||||
>{{ __('Rebase in progress') }}</span
|
||||
>
|
||||
<span
|
||||
v-if="!rebaseInProgress && !canPushToSourceBranch"
|
||||
class="gl-font-weight-bold"
|
||||
data-testid="rebase-message"
|
||||
v-html="fastForwardMergeText"
|
||||
></span>
|
||||
<div
|
||||
v-if="!rebaseInProgress && canPushToSourceBranch && !isMakingRequest"
|
||||
class="accept-merge-holder clearfix js-toggle-container accept-action media space-children"
|
||||
>
|
||||
<gl-button
|
||||
|
@ -126,14 +181,16 @@ export default {
|
|||
>
|
||||
{{ __('Rebase') }}
|
||||
</gl-button>
|
||||
<span v-if="!rebasingError" class="bold" data-testid="rebase-message">{{
|
||||
<span v-if="!rebasingError" class="gl-font-weight-bold" data-testid="rebase-message">{{
|
||||
__(
|
||||
'Fast-forward merge is not possible. Rebase the source branch onto the target branch.',
|
||||
)
|
||||
}}</span>
|
||||
<span v-else class="bold danger" data-testid="rebase-message">{{ rebasingError }}</span>
|
||||
<span v-else class="gl-font-weight-bold danger" data-testid="rebase-message">{{
|
||||
rebasingError
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
query rebaseQuery($projectPath: ID!, $iid: String!) {
|
||||
project(fullPath: $projectPath) {
|
||||
mergeRequest(iid: $iid) {
|
||||
rebaseInProgress
|
||||
targetBranch
|
||||
userPermissions {
|
||||
pushToSourceBranch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@
|
|||
@import './pages/events';
|
||||
@import './pages/groups';
|
||||
@import './pages/help';
|
||||
@import './pages/incident_management_list';
|
||||
@import './pages/issuable';
|
||||
@import './pages/issues/issue_count_badge';
|
||||
@import './pages/issues';
|
||||
|
|
|
@ -588,6 +588,12 @@ table.code {
|
|||
|
||||
// Merge request diff grid layout
|
||||
.diff-grid {
|
||||
.diff-td {
|
||||
// By default min-width is auto with 1fr which causes some overflow problems
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/296222
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.diff-grid-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
@ -601,27 +607,27 @@ table.code {
|
|||
|
||||
.diff-grid-comments {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.diff-grid-drafts {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
&.inline {
|
||||
.diff-grid-comments {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.diff-grid-drafts {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.diff-grid-row {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.diff-grid-left,
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
@import 'mixins_and_variables_and_functions';
|
||||
|
||||
.incident-management-list {
|
||||
.new-alert {
|
||||
background-color: $issues-today-bg;
|
||||
background-color: var(--green-50, $green-50);
|
||||
}
|
||||
|
||||
// these styles need to be deleted once GlTable component looks in GitLab same as in @gitlab/ui
|
||||
table {
|
||||
@include gl-text-gray-500;
|
||||
color: var(--gray-500, $gray-500);
|
||||
|
||||
tbody {
|
||||
tr:not(.b-table-busy-slot):not(.b-table-empty-row) {
|
||||
|
@ -34,7 +36,8 @@
|
|||
th {
|
||||
@include gl-bg-transparent;
|
||||
@include gl-font-weight-bold;
|
||||
@include gl-text-gray-400;
|
||||
color: var(--gray-400, $gray-400);
|
||||
|
||||
|
||||
&[aria-sort='none']:hover {
|
||||
background-image: url('data:image/svg+xml, %3csvg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="4 0 8 16"%3e %3cpath style="fill: %23BABABA;" fill-rule="evenodd" d="M11.707085,11.7071 L7.999975,15.4142 L4.292875,11.7071 C3.902375,11.3166 3.902375, 10.6834 4.292875,10.2929 C4.683375,9.90237 5.316575,9.90237 5.707075,10.2929 L6.999975, 11.5858 L6.999975,2 C6.999975,1.44771 7.447695,1 7.999975,1 C8.552255,1 8.999975,1.44771 8.999975,2 L8.999975,11.5858 L10.292865,10.2929 C10.683395 ,9.90237 11.316555,9.90237 11.707085,10.2929 C12.097605,10.6834 12.097605,11.3166 11.707085,11.7071 Z"/%3e %3c/svg%3e');
|
||||
|
@ -67,7 +70,7 @@
|
|||
}
|
||||
|
||||
&:hover {
|
||||
@include gl-bg-white;
|
||||
background-color: var(--white, $white);
|
||||
@include gl-border-none;
|
||||
}
|
||||
|
||||
|
@ -80,7 +83,7 @@
|
|||
&.alert-management-table {
|
||||
.table-col {
|
||||
&:last-child {
|
||||
@include gl-bg-gray-10;
|
||||
background-color: var(--gray-10, $gray-10);
|
||||
|
||||
&::before {
|
||||
content: none !important;
|
||||
|
@ -120,12 +123,12 @@
|
|||
@include gl-border-b-0;
|
||||
|
||||
.gl-tab-nav-item {
|
||||
@include gl-text-gray-500;
|
||||
color: var(--gray-500, $gray-500);
|
||||
|
||||
> .gl-tab-counter-badge {
|
||||
@include gl-reset-color;
|
||||
@include gl-font-sm;
|
||||
@include gl-bg-gray-50;
|
||||
background-color: var(--gray-50, $gray-50);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -301,7 +301,8 @@ $mr-widget-min-height: 69px;
|
|||
margin: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
.bold,
|
||||
.gl-font-weight-bold {
|
||||
font-weight: $gl-font-weight-bold;
|
||||
color: $gray-600;
|
||||
margin-left: 10px;
|
||||
|
@ -317,7 +318,8 @@ $mr-widget-min-height: 69px;
|
|||
}
|
||||
|
||||
.spacing,
|
||||
.bold {
|
||||
.bold,
|
||||
.gl-font-weight-bold {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
|
|
@ -1163,8 +1163,8 @@ input {
|
|||
line-height: 18px;
|
||||
margin: 4px 0 4px 2px;
|
||||
}
|
||||
.title-container .badge.badge-pill,
|
||||
.navbar-nav .badge.badge-pill {
|
||||
.title-container .badge.badge-pill:not(.merge-request-badge),
|
||||
.navbar-nav .badge.badge-pill:not(.merge-request-badge) {
|
||||
position: inherit;
|
||||
font-weight: 400;
|
||||
margin-left: -6px;
|
||||
|
|
|
@ -65,6 +65,7 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
|
|||
}
|
||||
|
||||
modules.merge!(build_information_module)
|
||||
modules.merge!(deployment_information_module)
|
||||
|
||||
modules
|
||||
end
|
||||
|
@ -73,17 +74,33 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
|
|||
view_context.image_url('gitlab_logo.png')
|
||||
end
|
||||
|
||||
# See: https://developer.atlassian.com/cloud/jira/software/modules/deployment/
|
||||
def deployment_information_module
|
||||
{
|
||||
jiraDeploymentInfoProvider: common_module_properties.merge(
|
||||
actions: {}, # TODO: list deployments
|
||||
name: { value: "GitLab Deployments" },
|
||||
key: "gitlab-deployments"
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
# See: https://developer.atlassian.com/cloud/jira/software/modules/build/
|
||||
def build_information_module
|
||||
{
|
||||
jiraBuildInfoProvider: {
|
||||
homeUrl: HOME_URL,
|
||||
logoUrl: logo_url,
|
||||
documentationUrl: DOC_URL,
|
||||
jiraBuildInfoProvider: common_module_properties.merge(
|
||||
actions: {},
|
||||
name: { value: "GitLab CI" },
|
||||
key: "gitlab-ci"
|
||||
}
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
def common_module_properties
|
||||
{
|
||||
homeUrl: HOME_URL,
|
||||
logoUrl: logo_url,
|
||||
documentationUrl: DOC_URL
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -34,11 +34,7 @@ module Ci
|
|||
|
||||
pipelines =
|
||||
if merge_request.persisted?
|
||||
if Feature.enabled?(:ci_pipelines_for_merge_request_finder_new_cte, target_project)
|
||||
pipelines_using_cte
|
||||
else
|
||||
pipelines_using_legacy_cte
|
||||
end
|
||||
pipelines_using_cte
|
||||
else
|
||||
triggered_for_branch.for_sha(commit_shas)
|
||||
end
|
||||
|
@ -49,18 +45,6 @@ module Ci
|
|||
|
||||
private
|
||||
|
||||
def pipelines_using_legacy_cte
|
||||
cte = Gitlab::SQL::CTE.new(:shas, merge_request.all_commits.select(:sha))
|
||||
|
||||
source_sha_join = cte.table[:sha].eq(Ci::Pipeline.arel_table[:source_sha])
|
||||
merged_result_pipelines = filter_by(triggered_by_merge_request, cte, source_sha_join)
|
||||
detached_merge_request_pipelines = filter_by_sha(triggered_by_merge_request, cte)
|
||||
pipelines_for_branch = filter_by_sha(triggered_for_branch, cte)
|
||||
|
||||
Ci::Pipeline.with(cte.to_arel) # rubocop: disable CodeReuse/ActiveRecord
|
||||
.from_union([merged_result_pipelines, detached_merge_request_pipelines, pipelines_for_branch])
|
||||
end
|
||||
|
||||
def pipelines_using_cte
|
||||
cte = Gitlab::SQL::CTE.new(:shas, merge_request.all_commits.select(:sha))
|
||||
|
||||
|
|
|
@ -109,6 +109,23 @@ class Deployment < ApplicationRecord
|
|||
Deployments::ExecuteHooksWorker.perform_async(id)
|
||||
end
|
||||
end
|
||||
|
||||
after_transition any => any - [:skipped] do |deployment, transition|
|
||||
next if transition.loopback?
|
||||
next unless Feature.enabled?(:jira_sync_deployments, deployment.project)
|
||||
|
||||
deployment.run_after_commit do
|
||||
::JiraConnect::SyncDeploymentsWorker.perform_async(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
after_create unless: :importing? do |deployment|
|
||||
next unless Feature.enabled?(:jira_sync_deployments, deployment.project)
|
||||
|
||||
run_after_commit do
|
||||
::JiraConnect::SyncDeploymentsWorker.perform_async(deployment.id)
|
||||
end
|
||||
end
|
||||
|
||||
enum status: {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
- page_title _('Alerts')
|
||||
- add_page_specific_style 'page_bundles/incident_management_list'
|
||||
|
||||
#js-alert_management{ data: alert_management_data(@current_user, @project) }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
- page_title _('Incidents')
|
||||
- add_page_specific_style 'page_bundles/incident_management_list'
|
||||
|
||||
#js-incidents{ data: incidents_data(@project, params) }
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _("Save space and find images in the Container Registry. Remove unneeded tags and keep only the ones you want.")
|
||||
= link_to _('More information'), help_page_path('user/packages/container_registry/index', anchor: 'cleanup-policy', target: '_blank', rel: 'noopener noreferrer')
|
||||
= link_to _('How does cleanup work?'), help_page_path('user/packages/container_registry/index', anchor: 'cleanup-policy', target: '_blank', rel: 'noopener noreferrer')
|
||||
.settings-content
|
||||
= render 'projects/registry/settings/index'
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
- return unless can?(current_user, :admin_operations, @project)
|
||||
- expanded = expanded_by_default?
|
||||
- add_page_specific_style 'page_bundles/alert_management_settings'
|
||||
- add_page_specific_style 'page_bundles/incident_management_list'
|
||||
|
||||
%section.settings.no-animate#js-alert-management-settings{ class: ('expanded' if expanded) }
|
||||
.settings-header
|
||||
|
|
|
@ -891,6 +891,14 @@
|
|||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: jira_connect:jira_connect_sync_deployments
|
||||
:feature_category: :integrations
|
||||
:has_external_dependencies: true
|
||||
:urgency: :low
|
||||
:resource_boundary: :unknown
|
||||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: jira_connect:jira_connect_sync_merge_request
|
||||
:feature_category: :integrations
|
||||
:has_external_dependencies: true
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module JiraConnect
|
||||
class SyncDeploymentsWorker
|
||||
include ApplicationWorker
|
||||
|
||||
idempotent!
|
||||
worker_has_external_dependencies!
|
||||
|
||||
queue_namespace :jira_connect
|
||||
feature_category :integrations
|
||||
|
||||
def perform(deployment_id, sequence_id)
|
||||
deployment = Deployment.find_by_id(deployment_id)
|
||||
|
||||
return unless deployment
|
||||
return unless Feature.enabled?(:jira_sync_deployments, deployment.project)
|
||||
|
||||
::JiraConnect::SyncService
|
||||
.new(deployment.project)
|
||||
.execute(deployments: [deployment], update_sequence_id: sequence_id)
|
||||
end
|
||||
|
||||
def self.perform_async(id)
|
||||
seq_id = ::Atlassian::JiraConnect::Client.generate_update_sequence_id
|
||||
super(id, seq_id)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: 'Refactor(opsgenie): remove Opsgenie integration frontend code from Incident
|
||||
management'
|
||||
merge_request: 50525
|
||||
author:
|
||||
type: deprecated
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix duplicated toggle button showing on right sidebar when signed out
|
||||
merge_request: 50892
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Improve the database query performance on the pipeline loading in merge requests
|
||||
merge_request: 50818
|
||||
author:
|
||||
type: performance
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Updated link text to match style guidelines
|
||||
merge_request: 50555
|
||||
author:
|
||||
type: other
|
|
@ -177,6 +177,7 @@ module Gitlab
|
|||
config.assets.precompile << "mailers/*.css"
|
||||
config.assets.precompile << "page_bundles/_mixins_and_variables_and_functions.css"
|
||||
config.assets.precompile << "page_bundles/alert_management_details.css"
|
||||
config.assets.precompile << "page_bundles/alert_management_settings.css"
|
||||
config.assets.precompile << "page_bundles/boards.css"
|
||||
config.assets.precompile << "page_bundles/build.css"
|
||||
config.assets.precompile << "page_bundles/ci_status.css"
|
||||
|
@ -186,29 +187,29 @@ module Gitlab
|
|||
config.assets.precompile << "page_bundles/epics.css"
|
||||
config.assets.precompile << "page_bundles/error_tracking_details.css"
|
||||
config.assets.precompile << "page_bundles/error_tracking_index.css"
|
||||
config.assets.precompile << "page_bundles/signup.css"
|
||||
config.assets.precompile << "page_bundles/ide.css"
|
||||
config.assets.precompile << "page_bundles/import.css"
|
||||
config.assets.precompile << "page_bundles/incident_management_list.css"
|
||||
config.assets.precompile << "page_bundles/issues_list.css"
|
||||
config.assets.precompile << "page_bundles/jira_connect.css"
|
||||
config.assets.precompile << "page_bundles/jira_connect_users.css"
|
||||
config.assets.precompile << "page_bundles/merge_conflicts.css"
|
||||
config.assets.precompile << "page_bundles/merge_requests.css"
|
||||
config.assets.precompile << "page_bundles/milestone.css"
|
||||
config.assets.precompile << "page_bundles/oncall_schedules.css"
|
||||
config.assets.precompile << "page_bundles/pipeline.css"
|
||||
config.assets.precompile << "page_bundles/pipelines.css"
|
||||
config.assets.precompile << "page_bundles/pipeline_schedules.css"
|
||||
config.assets.precompile << "page_bundles/pipelines.css"
|
||||
config.assets.precompile << "page_bundles/productivity_analytics.css"
|
||||
config.assets.precompile << "page_bundles/profile_two_factor_auth.css"
|
||||
config.assets.precompile << "page_bundles/security_dashboard.css"
|
||||
config.assets.precompile << "page_bundles/terminal.css"
|
||||
config.assets.precompile << "page_bundles/todos.css"
|
||||
config.assets.precompile << "page_bundles/reports.css"
|
||||
config.assets.precompile << "page_bundles/roadmap.css"
|
||||
config.assets.precompile << "page_bundles/security_dashboard.css"
|
||||
config.assets.precompile << "page_bundles/signup.css"
|
||||
config.assets.precompile << "page_bundles/terminal.css"
|
||||
config.assets.precompile << "page_bundles/todos.css"
|
||||
config.assets.precompile << "page_bundles/wiki.css"
|
||||
config.assets.precompile << "page_bundles/xterm.css"
|
||||
config.assets.precompile << "page_bundles/alert_management_settings.css"
|
||||
config.assets.precompile << "page_bundles/oncall_schedules.css"
|
||||
config.assets.precompile << "lazy_bundles/cropper.css"
|
||||
config.assets.precompile << "lazy_bundles/select2.css"
|
||||
config.assets.precompile << "performance_bar.css"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: ci_pipelines_for_merge_request_finder_new_cte
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49083
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/291006
|
||||
name: jira_sync_deployments
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49757
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/294034
|
||||
milestone: '13.7'
|
||||
type: development
|
||||
group: group::continuous integration
|
||||
group: group::ecosystem
|
||||
default_enabled: false
|
|
@ -477,7 +477,7 @@ production: &base
|
|||
ee_cron_jobs:
|
||||
# Schedule snapshots for all devops adoption segments
|
||||
analytics_devops_adoption_create_all_snapshots_worker:
|
||||
cron: 0 0 1 * *
|
||||
cron: 0 4 * * *
|
||||
|
||||
# Snapshot active users statistics
|
||||
historical_data_worker:
|
||||
|
|
|
@ -543,7 +543,7 @@ Settings.cron_jobs['manage_evidence_worker']['job_class'] = 'Releases::ManageEvi
|
|||
|
||||
Gitlab.ee do
|
||||
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker']['cron'] ||= '0 0 1 * *'
|
||||
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker']['cron'] ||= '0 4 * * *'
|
||||
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker']['job_class'] = 'Analytics::DevopsAdoption::CreateAllSnapshotsWorker'
|
||||
Settings.cron_jobs['active_user_count_threshold_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['active_user_count_threshold_worker']['cron'] ||= '0 12 * * *'
|
||||
|
|
|
@ -60,7 +60,7 @@ Reference pipeline: <https://gitlab.com/gitlab-org/gitlab/pipelines/135236627>
|
|||
```mermaid
|
||||
graph LR
|
||||
subgraph "No needed jobs";
|
||||
1-1["danger-review (3.5 minutes)"];
|
||||
1-1["danger-review (2.3 minutes)"];
|
||||
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
|
||||
1-50["docs lint (9 minutes)"];
|
||||
click 1-50 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356757&udv=0"
|
||||
|
@ -76,23 +76,23 @@ graph RL;
|
|||
classDef criticalPath fill:#f66;
|
||||
|
||||
subgraph "No needed jobs";
|
||||
1-1["danger-review (3.5 minutes)"];
|
||||
1-1["danger-review (2.3 minutes)"];
|
||||
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
|
||||
1-2["build-qa-image (2.4 minutes)"];
|
||||
1-2["build-qa-image (1.6 minutes)"];
|
||||
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
|
||||
1-3["compile-test-assets (8.5 minutes)"];
|
||||
1-3["compile-test-assets (7 minutes)"];
|
||||
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
|
||||
1-4["compile-test-assets as-if-foss (8.35 minutes)"];
|
||||
1-4["compile-test-assets as-if-foss (7 minutes)"];
|
||||
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
|
||||
1-5["compile-production-assets (19 minutes)"];
|
||||
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
|
||||
1-6["setup-test-env (7.4 minutes)"];
|
||||
1-6["setup-test-env (9 minutes)"];
|
||||
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
|
||||
1-7["review-stop-failed-deployment"];
|
||||
1-8["dependency_scanning"];
|
||||
1-9["qa:internal, qa:internal-as-if-foss"];
|
||||
1-11["qa:selectors, qa:selectors-as-if-foss"];
|
||||
1-14["retrieve-tests-metadata (1.9 minutes)"];
|
||||
1-14["retrieve-tests-metadata (1 minutes)"];
|
||||
click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0"
|
||||
1-15["code_quality"];
|
||||
1-16["brakeman-sast"];
|
||||
|
@ -100,7 +100,7 @@ graph RL;
|
|||
1-18["kubesec-sast"];
|
||||
1-19["nodejs-scan-sast"];
|
||||
1-20["secrets-sast"];
|
||||
1-21["static-analysis (17 minutes)"];
|
||||
1-21["static-analysis (30 minutes)"];
|
||||
click 1-21 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914471&udv=0"
|
||||
|
||||
class 1-3 criticalPath;
|
||||
|
@ -111,26 +111,26 @@ graph RL;
|
|||
click 2_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356715&udv=0"
|
||||
2_1-2["memory-static (4.75 minutes)"];
|
||||
click 2_1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356721&udv=0"
|
||||
2_1-3["run-dev-fixtures (5 minutes)"];
|
||||
2_1-3["run-dev-fixtures (6 minutes)"];
|
||||
click 2_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356729&udv=0"
|
||||
2_1-4["run-dev-fixtures-ee (5 minutes)"];
|
||||
2_1-4["run-dev-fixtures-ee (6.75 minutes)"];
|
||||
click 2_1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356731&udv=0"
|
||||
subgraph "Needs `setup-test-env`";
|
||||
2_1-1 & 2_1-2 & 2_1-3 & 2_1-4 --> 1-6;
|
||||
end
|
||||
|
||||
2_2-2["frontend-fixtures (16.5 minutes)"];
|
||||
2_2-2["rspec frontend_fixture/rspec-ee frontend_fixture (12 minutes)"];
|
||||
class 2_2-2 criticalPath;
|
||||
click 2_2-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910143&udv=0"
|
||||
2_2-4["memory-on-boot (7.19 minutes)"];
|
||||
2_2-4["memory-on-boot (6 minutes)"];
|
||||
click 2_2-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356727&udv=0"
|
||||
2_2-5["webpack-dev-server (6.1 minutes)"];
|
||||
2_2-5["webpack-dev-server (4.5 minutes)"];
|
||||
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
|
||||
subgraph "Needs `setup-test-env` & `compile-test-assets`";
|
||||
2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
|
||||
end
|
||||
|
||||
2_3-1["build-assets-image (2.5 minutes)"];
|
||||
2_3-1["build-assets-image (1.6 minutes)"];
|
||||
subgraph "Needs `compile-production-assets`";
|
||||
2_3-1 --> 1-5
|
||||
end
|
||||
|
@ -153,17 +153,17 @@ graph RL;
|
|||
click 3_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914204&udv=0"
|
||||
3_1-2["karma (4 minutes)"];
|
||||
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914200&udv=0"
|
||||
subgraph "Needs `frontend-fixtures`";
|
||||
subgraph "Needs `rspec frontend_fixture/rspec-ee frontend_fixture`";
|
||||
3_1-1 & 3_1-2 --> 2_2-2;
|
||||
end
|
||||
|
||||
3_2-1["rspec:coverage (7.5 minutes)"];
|
||||
3_2-1["rspec:coverage (4.6 minutes)"];
|
||||
subgraph "Depends on `rspec` jobs";
|
||||
3_2-1 -.->|"(don't use needs because of limitations)"| 2_5-1;
|
||||
click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
|
||||
end
|
||||
|
||||
4_1-1["coverage-frontend (3.6 minutes)"];
|
||||
4_1-1["coverage-frontend (2.75 minutes)"];
|
||||
subgraph "Needs `jest`";
|
||||
4_1-1 --> 3_1-1;
|
||||
class 4_1-1 criticalPath;
|
||||
|
@ -180,23 +180,23 @@ graph RL;
|
|||
classDef criticalPath fill:#f66;
|
||||
|
||||
subgraph "No needed jobs";
|
||||
1-1["danger-review (3.5 minutes)"];
|
||||
1-1["danger-review (2.3 minutes)"];
|
||||
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
|
||||
1-2["build-qa-image (2.4 minutes)"];
|
||||
1-2["build-qa-image (1.6 minutes)"];
|
||||
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
|
||||
1-3["compile-test-assets (8.5 minutes)"];
|
||||
1-3["compile-test-assets (7 minutes)"];
|
||||
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
|
||||
1-4["compile-test-assets as-if-foss (8.35 minutes)"];
|
||||
1-4["compile-test-assets as-if-foss (7 minutes)"];
|
||||
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
|
||||
1-5["compile-production-assets (19 minutes)"];
|
||||
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
|
||||
1-6["setup-test-env (7.4 minutes)"];
|
||||
1-6["setup-test-env (9 minutes)"];
|
||||
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
|
||||
1-7["review-stop-failed-deployment"];
|
||||
1-8["dependency_scanning"];
|
||||
1-9["qa:internal, qa:internal-as-if-foss"];
|
||||
1-11["qa:selectors, qa:selectors-as-if-foss"];
|
||||
1-14["retrieve-tests-metadata (1.9 minutes)"];
|
||||
1-14["retrieve-tests-metadata (1 minutes)"];
|
||||
click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0"
|
||||
1-15["code_quality"];
|
||||
1-16["brakeman-sast"];
|
||||
|
@ -204,7 +204,7 @@ graph RL;
|
|||
1-18["kubesec-sast"];
|
||||
1-19["nodejs-scan-sast"];
|
||||
1-20["secrets-sast"];
|
||||
1-21["static-analysis (17 minutes)"];
|
||||
1-21["static-analysis (30 minutes)"];
|
||||
click 1-21 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914471&udv=0"
|
||||
|
||||
class 1-3 criticalPath;
|
||||
|
@ -216,26 +216,26 @@ graph RL;
|
|||
click 2_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356715&udv=0"
|
||||
2_1-2["memory-static (4.75 minutes)"];
|
||||
click 2_1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356721&udv=0"
|
||||
2_1-3["run-dev-fixtures (5 minutes)"];
|
||||
2_1-3["run-dev-fixtures (6 minutes)"];
|
||||
click 2_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356729&udv=0"
|
||||
2_1-4["run-dev-fixtures-ee (5 minutes)"];
|
||||
2_1-4["run-dev-fixtures-ee (6.75 minutes)"];
|
||||
click 2_1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356731&udv=0"
|
||||
subgraph "Needs `setup-test-env`";
|
||||
2_1-1 & 2_1-2 & 2_1-3 & 2_1-4 --> 1-6;
|
||||
end
|
||||
|
||||
2_2-2["frontend-fixtures (16.5 minutes)"];
|
||||
2_2-2["rspec frontend_fixture/rspec-ee frontend_fixture (12 minutes)"];
|
||||
class 2_2-2 criticalPath;
|
||||
click 2_2-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910143&udv=0"
|
||||
2_2-4["memory-on-boot (7.19 minutes)"];
|
||||
2_2-4["memory-on-boot (6 minutes)"];
|
||||
click 2_2-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356727&udv=0"
|
||||
2_2-5["webpack-dev-server (6.1 minutes)"];
|
||||
2_2-5["webpack-dev-server (4.5 minutes)"];
|
||||
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
|
||||
subgraph "Needs `setup-test-env` & `compile-test-assets`";
|
||||
2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
|
||||
end
|
||||
|
||||
2_3-1["build-assets-image (2.5 minutes)"];
|
||||
2_3-1["build-assets-image (1.6 minutes)"];
|
||||
class 2_3-1 criticalPath;
|
||||
subgraph "Needs `compile-production-assets`";
|
||||
2_3-1 --> 1-5
|
||||
|
@ -266,17 +266,17 @@ graph RL;
|
|||
click 3_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914204&udv=0"
|
||||
3_1-2["karma (4 minutes)"];
|
||||
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914200&udv=0"
|
||||
subgraph "Needs `frontend-fixtures`";
|
||||
subgraph "Needs `rspec frontend_fixture/rspec-ee frontend_fixture`";
|
||||
3_1-1 & 3_1-2 --> 2_2-2;
|
||||
end
|
||||
|
||||
3_2-1["rspec:coverage (7.5 minutes)"];
|
||||
3_2-1["rspec:coverage (4.6 minutes)"];
|
||||
subgraph "Depends on `rspec` jobs";
|
||||
3_2-1 -.->|"(don't use needs because of limitations)"| 2_5-1;
|
||||
click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
|
||||
end
|
||||
|
||||
4_1-1["coverage-frontend (3.6 minutes)"];
|
||||
4_1-1["coverage-frontend (2.75 minutes)"];
|
||||
subgraph "Needs `jest`";
|
||||
4_1-1 --> 3_1-1;
|
||||
class 4_1-1 criticalPath;
|
||||
|
@ -311,23 +311,23 @@ graph RL;
|
|||
classDef criticalPath fill:#f66;
|
||||
|
||||
subgraph "No needed jobs";
|
||||
1-1["danger-review (3.5 minutes)"];
|
||||
1-1["danger-review (2.3 minutes)"];
|
||||
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
|
||||
1-2["build-qa-image (2.4 minutes)"];
|
||||
1-2["build-qa-image (1.6 minutes)"];
|
||||
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
|
||||
1-3["compile-test-assets (8.5 minutes)"];
|
||||
1-3["compile-test-assets (7 minutes)"];
|
||||
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
|
||||
1-4["compile-test-assets as-if-foss (8.35 minutes)"];
|
||||
1-4["compile-test-assets as-if-foss (7 minutes)"];
|
||||
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
|
||||
1-5["compile-production-assets (19 minutes)"];
|
||||
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
|
||||
1-6["setup-test-env (7.4 minutes)"];
|
||||
1-6["setup-test-env (9 minutes)"];
|
||||
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
|
||||
1-7["review-stop-failed-deployment"];
|
||||
1-8["dependency_scanning"];
|
||||
1-9["qa:internal, qa:internal-as-if-foss"];
|
||||
1-11["qa:selectors, qa:selectors-as-if-foss"];
|
||||
1-14["retrieve-tests-metadata (1.9 minutes)"];
|
||||
1-14["retrieve-tests-metadata (1 minutes)"];
|
||||
click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0"
|
||||
1-15["code_quality"];
|
||||
1-16["brakeman-sast"];
|
||||
|
@ -335,7 +335,7 @@ graph RL;
|
|||
1-18["kubesec-sast"];
|
||||
1-19["nodejs-scan-sast"];
|
||||
1-20["secrets-sast"];
|
||||
1-21["static-analysis (17 minutes)"];
|
||||
1-21["static-analysis (30 minutes)"];
|
||||
click 1-21 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914471&udv=0"
|
||||
|
||||
class 1-5 criticalPath;
|
||||
|
@ -347,13 +347,13 @@ graph RL;
|
|||
2_1-1 --> 1-6;
|
||||
end
|
||||
|
||||
2_3-1["build-assets-image (2.5 minutes)"];
|
||||
2_3-1["build-assets-image (1.6 minutes)"];
|
||||
subgraph "Needs `compile-production-assets`";
|
||||
2_3-1 --> 1-5
|
||||
class 2_3-1 criticalPath;
|
||||
end
|
||||
|
||||
2_4-1["package-and-qa (108 minutes)"];
|
||||
2_4-1["package-and-qa (105 minutes)"];
|
||||
subgraph "Needs `build-qa-image` & `build-assets-image`";
|
||||
2_4-1 --> 1-2 & 2_3-1;
|
||||
class 2_4-1 criticalPath;
|
||||
|
@ -504,6 +504,10 @@ request, be sure to start the `dont-interrupt-me` job before pushing.
|
|||
- `update-yarn-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
|
||||
1. These jobs run in merge requests whose title include `UPDATE CACHE`.
|
||||
|
||||
### Artifacts strategy
|
||||
|
||||
We limit the artifacts that are saved and retrieved by jobs to the minimum in order to reduce the upload/download time and costs, as well as the artifacts storage.
|
||||
|
||||
### Pre-clone step
|
||||
|
||||
The `gitlab-org/gitlab` project on GitLab.com uses a [pre-clone step](https://gitlab.com/gitlab-org/gitlab/-/issues/39134)
|
||||
|
|
|
@ -168,7 +168,7 @@ If the existing alert is already `resolved`, GitLab creates a new alert instead.
|
|||
|
||||
![Alert Management List](img/alert_list_v13_1.png)
|
||||
|
||||
## Link to your Opsgenie Alerts
|
||||
## Link to your Opsgenie Alerts (depreciated)
|
||||
|
||||
WARNING:
|
||||
We are building deeper integration with Opsgenie and other alerting tools through
|
||||
|
@ -176,6 +176,10 @@ We are building deeper integration with Opsgenie and other alerting tools throug
|
|||
the GitLab interface. As a result, the previous direct link to Opsgenie Alerts from
|
||||
the GitLab alerts list is scheduled for deprecation following the 13.7 release on December 22, 2020.
|
||||
|
||||
NOTE:
|
||||
This feature has been deprecated in
|
||||
[13.8](https://gitlab.com/gitlab-org/gitlab/-/issues/273657).
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
You can monitor alerts using a GitLab integration with [Opsgenie](https://www.atlassian.com/software/opsgenie).
|
||||
|
|
|
@ -50,7 +50,9 @@ The DevOps Adoption tab shows you which segments of your organization are using
|
|||
- Deploys
|
||||
- Scanning
|
||||
|
||||
Segments are arbitrary collections of GitLab groups that you define. You might define a segment to represent a small team, a large department, or a whole organization. You are limited to creating a maximum of 20 segments, and each segment is limited to a maximum of 20 groups. Buttons to manage your segments appear in the DevOps Adoption section of the page.
|
||||
Segments are arbitrary collections of GitLab groups that you define. You might define a segment to represent a small team, a large department, or a whole organization.
|
||||
You are limited to creating a maximum of 20 segments, and each segment is limited to a maximum of 20 groups.
|
||||
Buttons to manage your segments appear in the DevOps Adoption section of the page.
|
||||
|
||||
DevOps Adoption allows you to:
|
||||
|
||||
|
|
|
@ -16,11 +16,13 @@ module Atlassian
|
|||
common = { project: project, update_sequence_id: update_sequence_id }
|
||||
dev_info = args.slice(:commits, :branches, :merge_requests)
|
||||
build_info = args.slice(:pipelines)
|
||||
deploy_info = args.slice(:deployments)
|
||||
|
||||
responses = []
|
||||
|
||||
responses << store_dev_info(**common, **dev_info) if dev_info.present?
|
||||
responses << store_build_info(**common, **build_info) if build_info.present?
|
||||
responses << store_deploy_info(**common, **deploy_info) if deploy_info.present?
|
||||
raise ArgumentError, 'Invalid arguments' if responses.empty?
|
||||
|
||||
responses.compact
|
||||
|
@ -28,6 +30,17 @@ module Atlassian
|
|||
|
||||
private
|
||||
|
||||
def store_deploy_info(project:, deployments:, **opts)
|
||||
return unless Feature.enabled?(:jira_sync_deployments, project)
|
||||
|
||||
items = deployments.map { |d| Serializers::DeploymentEntity.represent(d, opts) }
|
||||
items.reject! { |d| d.issue_keys.empty? }
|
||||
|
||||
return if items.empty?
|
||||
|
||||
post('/rest/deployments/0.1/bulk', { deployments: items })
|
||||
end
|
||||
|
||||
def store_build_info(project:, pipelines:, update_sequence_id: nil)
|
||||
return unless Feature.enabled?(:jira_sync_builds, project)
|
||||
|
||||
|
|
|
@ -25,8 +25,10 @@ module Atlassian
|
|||
# extract Jira issue keys from either the source branch/ref or the
|
||||
# merge request title.
|
||||
@issue_keys ||= begin
|
||||
src = "#{pipeline.source_ref} #{pipeline.merge_request&.title}"
|
||||
JiraIssueKeyExtractor.new(src).issue_keys
|
||||
pipeline.all_merge_requests.flat_map do |mr|
|
||||
src = "#{mr.source_branch} #{mr.title}"
|
||||
JiraIssueKeyExtractor.new(src).issue_keys
|
||||
end.uniq
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Atlassian
|
||||
module JiraConnect
|
||||
module Serializers
|
||||
class DeploymentEntity < Grape::Entity
|
||||
include Gitlab::Routing
|
||||
|
||||
format_with(:iso8601, &:iso8601)
|
||||
|
||||
expose :schema_version, as: :schemaVersion
|
||||
expose :iid, as: :deploymentSequenceNumber
|
||||
expose :update_sequence_id, as: :updateSequenceNumber
|
||||
expose :display_name, as: :displayName
|
||||
expose :description
|
||||
expose :associations
|
||||
expose :url
|
||||
expose :label
|
||||
expose :state
|
||||
expose :updated_at, as: :lastUpdated, format_with: :iso8601
|
||||
expose :pipeline_entity, as: :pipeline
|
||||
expose :environment_entity, as: :environment
|
||||
|
||||
def issue_keys
|
||||
return [] unless build&.pipeline.present?
|
||||
|
||||
@issue_keys ||= BuildEntity.new(build.pipeline).issue_keys
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :project, :deployable, :environment, :iid, :ref, :short_sha, to: :object
|
||||
alias_method :deployment, :object
|
||||
alias_method :build, :deployable
|
||||
|
||||
def associations
|
||||
keys = issue_keys
|
||||
|
||||
[{ associationType: :issueKeys, values: keys }] if keys.present?
|
||||
end
|
||||
|
||||
def display_name
|
||||
"Deployment #{iid} (#{ref}@#{short_sha}) to #{environment.name}"
|
||||
end
|
||||
|
||||
def label
|
||||
"#{project.full_path}-#{environment.name}-#{iid}-#{short_sha}"
|
||||
end
|
||||
|
||||
def description
|
||||
"Deployment #{deployment.iid} of #{project.name} at #{short_sha} (#{build&.name}) to #{environment.name}"
|
||||
end
|
||||
|
||||
def url
|
||||
# There is no controller action to show a single deployment, so we
|
||||
# link to the build instead
|
||||
project_job_url(project, build) if build
|
||||
end
|
||||
|
||||
def state
|
||||
case deployment.status
|
||||
when 'created' then 'pending'
|
||||
when 'running' then 'in_progress'
|
||||
when 'success' then 'successful'
|
||||
when 'failed' then 'failed'
|
||||
when 'canceled', 'skipped' then 'cancelled'
|
||||
else
|
||||
'unknown'
|
||||
end
|
||||
end
|
||||
|
||||
def schema_version
|
||||
'1.0'
|
||||
end
|
||||
|
||||
def pipeline_entity
|
||||
PipelineEntity.new(build.pipeline) if build&.pipeline.present?
|
||||
end
|
||||
|
||||
def environment_entity
|
||||
EnvironmentEntity.new(environment)
|
||||
end
|
||||
|
||||
def update_sequence_id
|
||||
options[:update_sequence_id] || Client.generate_update_sequence_id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Atlassian
|
||||
module JiraConnect
|
||||
module Serializers
|
||||
class EnvironmentEntity < Grape::Entity
|
||||
format_with(:string, &:to_s)
|
||||
|
||||
expose :id, format_with: :string
|
||||
expose :display_name, as: :displayName
|
||||
expose :type
|
||||
|
||||
private
|
||||
|
||||
alias_method :environment, :object
|
||||
delegate :project, to: :object
|
||||
|
||||
def display_name
|
||||
"#{project.name}/#{environment.name}"
|
||||
end
|
||||
|
||||
def type
|
||||
case environment.name
|
||||
when /prod/i
|
||||
'production'
|
||||
when /test/i
|
||||
'testing'
|
||||
when /staging/i
|
||||
'staging'
|
||||
when /(dev|review)/i
|
||||
'development'
|
||||
else
|
||||
'unmapped'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Atlassian
|
||||
module JiraConnect
|
||||
module Serializers
|
||||
# Both this an BuildEntity represent a Ci::Pipeline
|
||||
class PipelineEntity < Grape::Entity
|
||||
include Gitlab::Routing
|
||||
|
||||
format_with(:string, &:to_s)
|
||||
|
||||
expose :id, format_with: :string
|
||||
expose :display_name, as: :displayName
|
||||
expose :url
|
||||
|
||||
private
|
||||
|
||||
alias_method :pipeline, :object
|
||||
delegate :project, to: :object
|
||||
|
||||
def display_name
|
||||
"#{project.name} pipeline #{pipeline.iid}"
|
||||
end
|
||||
|
||||
def url
|
||||
project_pipeline_url(project, pipeline)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2502,9 +2502,6 @@ msgstr ""
|
|||
msgid "AlertManagement|Open"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|Opsgenie is enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
@ -2568,15 +2565,9 @@ msgstr ""
|
|||
msgid "AlertManagement|Value"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|View alerts in Opsgenie"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|View incident"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|You have enabled the Opsgenie integration. Your alerts will be visible directly in Opsgenie."
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertMappingBuilder|Define fallback"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2604,9 +2595,6 @@ msgstr ""
|
|||
msgid "AlertSettings|1. Select integration type"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|2. Add link to your Opsgenie alert list"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|2. Name integration"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2676,9 +2664,6 @@ msgstr ""
|
|||
msgid "AlertSettings|Learn more about our our upcoming %{linkStart}integrations%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|Opsgenie"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|Proceed with editing"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2748,12 +2733,6 @@ msgstr ""
|
|||
msgid "AlertSettings|Utilize the URL and authorization key below to authorize an external service to send alerts to GitLab. Review your external service's documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint."
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|Utilizing this option will link the GitLab Alerts navigation item to your existing Opsgenie instance. By selecting this option, you cannot receive alerts from any other source in GitLab; it will effectively be turning Alerts within GitLab off as a feature."
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|We will soon be introducing the ability to create multiple unique HTTP endpoints. When this functionality is live, you will be able to configure an integration with Opsgenie to surface Opsgenie alerts in GitLab. This will replace the current Opsgenie integration which will be deprecated. %{linkStart}More Information%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertSettings|Webhook URL"
|
||||
msgstr ""
|
||||
|
||||
|
@ -7677,10 +7656,10 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Tags that match these rules are %{strongStart}removed%{strongEnd}, unless a rule above says to keep them."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Tags with names that match this regex pattern are kept. %{linkStart}More information%{linkEnd}"
|
||||
msgid "ContainerRegistry|Tags with names that match this regex pattern are kept. %{linkStart}View regex examples.%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Tags with names that match this regex pattern are removed. %{linkStart}More information%{linkEnd}"
|
||||
msgid "ContainerRegistry|Tags with names that match this regex pattern are removed. %{linkStart}View regex examples.%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
|
||||
|
@ -14346,6 +14325,9 @@ msgstr ""
|
|||
msgid "Housekeeping, export, path, transfer, remove, archive."
|
||||
msgstr ""
|
||||
|
||||
msgid "How does cleanup work?"
|
||||
msgstr ""
|
||||
|
||||
msgid "How it works"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
"@gitlab/at.js": "1.5.5",
|
||||
"@gitlab/svgs": "1.178.0",
|
||||
"@gitlab/tributejs": "1.0.0",
|
||||
"@gitlab/ui": "25.3.1",
|
||||
"@gitlab/ui": "25.4.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "^6.0.3-4",
|
||||
"@rails/ujs": "^6.0.3-4",
|
||||
|
|
|
@ -4,8 +4,7 @@ module QA
|
|||
RSpec.describe 'Manage', :smoke do
|
||||
describe 'Project creation' do
|
||||
it 'user creates a new project',
|
||||
testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/429',
|
||||
quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/283925', type: :investigating } do
|
||||
testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/429' do
|
||||
Flow::Login.sign_in
|
||||
|
||||
created_project = Resource::Project.fabricate_via_browser_ui! do |project|
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Auto-require all cops under `rubocop/cop/**/*.rb`
|
||||
Dir[File.join(__dir__, 'cop', '**', '*.rb')].each(&method(:require))
|
||||
Dir[File.join(__dir__, 'cop', '**', '*.rb')].sort.each(&method(:require))
|
||||
|
|
|
@ -12,7 +12,7 @@ class GitalyTestBuild
|
|||
include GitalyTest
|
||||
|
||||
def run
|
||||
abort 'gitaly build failed' unless system(env, 'make', chdir: tmp_tests_gitaly_dir)
|
||||
abort 'gitaly build failed' unless build_gitaly
|
||||
|
||||
ensure_gitlab_shell_secret!
|
||||
check_gitaly_config!
|
||||
|
|
|
@ -8,6 +8,7 @@ class GitalyTestSpawn
|
|||
include GitalyTest
|
||||
|
||||
def run
|
||||
install_gitaly_gems if ENV['CI']
|
||||
check_gitaly_config!
|
||||
|
||||
# # Uncomment line below to see all gitaly logs merged into CI trace
|
||||
|
|
|
@ -41,7 +41,7 @@ module GitalyTest
|
|||
'HOME' => File.expand_path('tmp/tests'),
|
||||
'GEM_PATH' => Gem.path.join(':'),
|
||||
'BUNDLE_APP_CONFIG' => File.join(File.dirname(gemfile), '.bundle/config'),
|
||||
'BUNDLE_FLAGS' => "--jobs=4 --retry=3 --quiet",
|
||||
'BUNDLE_FLAGS' => "--jobs=4 --retry=3",
|
||||
'BUNDLE_INSTALL_FLAGS' => nil,
|
||||
'BUNDLE_GEMFILE' => gemfile,
|
||||
'RUBYOPT' => nil,
|
||||
|
@ -78,6 +78,14 @@ module GitalyTest
|
|||
end
|
||||
end
|
||||
|
||||
def install_gitaly_gems
|
||||
system(env, "make #{tmp_tests_gitaly_dir}/.ruby-bundle", chdir: tmp_tests_gitaly_dir) # rubocop:disable GitlabSecurity/SystemCommandInjection
|
||||
end
|
||||
|
||||
def build_gitaly
|
||||
system(env, 'make', chdir: tmp_tests_gitaly_dir) # rubocop:disable GitlabSecurity/SystemCommandInjection
|
||||
end
|
||||
|
||||
def start_gitaly
|
||||
start(:gitaly)
|
||||
end
|
||||
|
|
|
@ -225,24 +225,6 @@ RSpec.describe Ci::PipelinesForMergeRequestFinder do
|
|||
branch_pipeline_2,
|
||||
branch_pipeline])
|
||||
end
|
||||
|
||||
context 'when ci_pipelines_for_merge_request_finder_new_cte feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_pipelines_for_merge_request_finder_new_cte: false)
|
||||
end
|
||||
|
||||
it 'returns only related merge request pipelines' do
|
||||
expect(subject.all)
|
||||
.to eq([detached_merge_request_pipeline,
|
||||
branch_pipeline_2,
|
||||
branch_pipeline])
|
||||
|
||||
expect(described_class.new(merge_request_2, nil).all)
|
||||
.to eq([detached_merge_request_pipeline_2,
|
||||
branch_pipeline_2,
|
||||
branch_pipeline])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when detached merge request pipeline is run on head ref of the merge request' do
|
||||
|
|
|
@ -31,17 +31,5 @@ describe('AlertManagementEmptyState', () => {
|
|||
it('shows empty state', () => {
|
||||
expect(EmptyState().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('show OpsGenie integration state when OpsGenie mcv is true', () => {
|
||||
mountComponent({
|
||||
provide: {
|
||||
alertManagementEnabled: false,
|
||||
userCanEnableAlertManagement: false,
|
||||
opsgenieMvcEnabled: true,
|
||||
opsgenieMvcTargetUrl: 'https://opsgenie-url.com',
|
||||
},
|
||||
});
|
||||
expect(EmptyState().props('title')).toBe('Opsgenie is enabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,7 +7,5 @@
|
|||
"populatingAlertsHelpUrl": "/link",
|
||||
"emptyAlertSvgPath": "/link",
|
||||
"alertManagementEnabled": false,
|
||||
"userCanEnableAlertManagement": false,
|
||||
"opsgenieMvcTargetUrl": "/link",
|
||||
"opsgenieMvcEnabled": false
|
||||
"userCanEnableAlertManagement": false
|
||||
}
|
|
@ -4,11 +4,10 @@ exports[`AlertsSettingsFormNew with default values renders the initial template
|
|||
"<form class=\\"gl-mt-6\\">
|
||||
<h5 class=\\"gl-font-lg gl-my-5\\">Add new integrations</h5>
|
||||
<div id=\\"integration-type\\" role=\\"group\\" class=\\"form-group gl-form-group\\"><label id=\\"integration-type__BV_label_\\" for=\\"integration-type\\" class=\\"d-block col-form-label\\">1. Select integration type</label>
|
||||
<div class=\\"bv-no-focus-ring\\"><select class=\\"gl-form-select custom-select\\" id=\\"__BVID__8\\">
|
||||
<div class=\\"bv-no-focus-ring\\"><select class=\\"gl-form-select mw-100 custom-select\\" id=\\"__BVID__8\\">
|
||||
<option value=\\"\\">Select integration type</option>
|
||||
<option value=\\"HTTP\\">HTTP Endpoint</option>
|
||||
<option value=\\"PROMETHEUS\\">External Prometheus</option>
|
||||
<option value=\\"OPSGENIE\\">Opsgenie</option>
|
||||
</select>
|
||||
<!---->
|
||||
<!---->
|
||||
|
|
|
@ -28,7 +28,6 @@ describe('AlertsSettingsFormNew', () => {
|
|||
propsData: {
|
||||
loading: false,
|
||||
canAddIntegration: true,
|
||||
canManageOpsgenie: true,
|
||||
...props,
|
||||
},
|
||||
provide: {
|
||||
|
|
|
@ -4,7 +4,7 @@ import AxiosMockAdapter from 'axios-mock-adapter';
|
|||
import createMockApollo from 'jest/helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { useMockIntersectionObserver } from 'helpers/mock_dom_observer';
|
||||
import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue';
|
||||
import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form.vue';
|
||||
|
@ -376,17 +376,4 @@ describe('AlertsSettingsWrapper', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Will be removed in 13.7 as part of: https://gitlab.com/gitlab-org/gitlab/-/issues/273657
|
||||
describe('Opsgenie integration', () => {
|
||||
it.each([true, false])('it shows/hides the alert when opsgenie is %s', (active) => {
|
||||
createComponent({
|
||||
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
|
||||
provide: { opsgenie: { active } },
|
||||
loading: false,
|
||||
});
|
||||
|
||||
expect(wrapper.find(GlAlert).exists()).toBe(active);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,12 +19,6 @@ export const defaultAlertSettingsConfig = {
|
|||
url: PROMETHEUS_URL,
|
||||
active: ACTIVE,
|
||||
},
|
||||
opsgenie: {
|
||||
opsgenieMvcIsAvailable: true,
|
||||
formPath: INVALID_URL,
|
||||
active: ACTIVE,
|
||||
opsgenieMvcTargetUrl: GENERIC_URL,
|
||||
},
|
||||
projectPath: '',
|
||||
multiIntegrations: true,
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { getByText } from '@testing-library/dom';
|
||||
import { createStore } from '~/mr_notes/stores';
|
||||
import DiffExpansionCell from '~/diffs/components/diff_expansion_cell.vue';
|
||||
|
@ -59,7 +58,6 @@ describe('DiffExpansionCell', () => {
|
|||
let mockFile;
|
||||
let mockLine;
|
||||
let store;
|
||||
let vm;
|
||||
|
||||
beforeEach(() => {
|
||||
mockFile = cloneDeep(diffFileMockData);
|
||||
|
@ -70,7 +68,6 @@ describe('DiffExpansionCell', () => {
|
|||
});
|
||||
|
||||
const createComponent = (options = {}) => {
|
||||
const cmp = Vue.extend(DiffExpansionCell);
|
||||
const defaults = {
|
||||
fileHash: mockFile.file_hash,
|
||||
contextLinesPath: 'contextLinesPath',
|
||||
|
@ -78,46 +75,46 @@ describe('DiffExpansionCell', () => {
|
|||
isTop: false,
|
||||
isBottom: false,
|
||||
};
|
||||
const props = { ...defaults, ...options };
|
||||
const propsData = { ...defaults, ...options };
|
||||
|
||||
vm = createComponentWithStore(cmp, store, props).$mount();
|
||||
return mount(DiffExpansionCell, { store, propsData });
|
||||
};
|
||||
|
||||
const findExpandUp = () => vm.$el.querySelector(EXPAND_UP_CLASS);
|
||||
const findExpandDown = () => vm.$el.querySelector(EXPAND_DOWN_CLASS);
|
||||
const findExpandAll = () => getByText(vm.$el, 'Show all unchanged lines');
|
||||
const findExpandUp = (wrapper) => wrapper.find(EXPAND_UP_CLASS);
|
||||
const findExpandDown = (wrapper) => wrapper.find(EXPAND_DOWN_CLASS);
|
||||
const findExpandAll = ({ element }) => getByText(element, 'Show all unchanged lines');
|
||||
|
||||
describe('top row', () => {
|
||||
it('should have "expand up" and "show all" option', () => {
|
||||
createComponent({
|
||||
const wrapper = createComponent({
|
||||
isTop: true,
|
||||
});
|
||||
|
||||
expect(findExpandUp()).not.toBe(null);
|
||||
expect(findExpandDown()).toBe(null);
|
||||
expect(findExpandAll()).not.toBe(null);
|
||||
expect(findExpandUp(wrapper).exists()).toBe(true);
|
||||
expect(findExpandDown(wrapper).exists()).toBe(false);
|
||||
expect(findExpandAll(wrapper)).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('middle row', () => {
|
||||
it('should have "expand down", "show all", "expand up" option', () => {
|
||||
createComponent();
|
||||
const wrapper = createComponent();
|
||||
|
||||
expect(findExpandUp()).not.toBe(null);
|
||||
expect(findExpandDown()).not.toBe(null);
|
||||
expect(findExpandAll()).not.toBe(null);
|
||||
expect(findExpandUp(wrapper).exists()).toBe(true);
|
||||
expect(findExpandDown(wrapper).exists()).toBe(true);
|
||||
expect(findExpandAll(wrapper)).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bottom row', () => {
|
||||
it('should have "expand down" and "show all" option', () => {
|
||||
createComponent({
|
||||
const wrapper = createComponent({
|
||||
isBottom: true,
|
||||
});
|
||||
|
||||
expect(findExpandUp()).toBe(null);
|
||||
expect(findExpandDown()).not.toBe(null);
|
||||
expect(findExpandAll()).not.toBe(null);
|
||||
expect(findExpandUp(wrapper).exists()).toBe(false);
|
||||
expect(findExpandDown(wrapper).exists()).toBe(true);
|
||||
expect(findExpandAll(wrapper)).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -144,9 +141,9 @@ describe('DiffExpansionCell', () => {
|
|||
newLineNumber,
|
||||
});
|
||||
|
||||
createComponent();
|
||||
const wrapper = createComponent();
|
||||
|
||||
findExpandAll().click();
|
||||
findExpandAll(wrapper).click();
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
'diffs/loadMoreLines',
|
||||
|
@ -167,9 +164,9 @@ describe('DiffExpansionCell', () => {
|
|||
const oldLineNumber = mockLine.meta_data.old_pos;
|
||||
const newLineNumber = mockLine.meta_data.new_pos;
|
||||
|
||||
createComponent();
|
||||
const wrapper = createComponent();
|
||||
|
||||
findExpandUp().click();
|
||||
findExpandUp(wrapper).trigger('click');
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
'diffs/loadMoreLines',
|
||||
|
@ -195,9 +192,9 @@ describe('DiffExpansionCell', () => {
|
|||
mockLine.meta_data.old_pos = 200;
|
||||
mockLine.meta_data.new_pos = 200;
|
||||
|
||||
createComponent();
|
||||
const wrapper = createComponent();
|
||||
|
||||
findExpandDown().click();
|
||||
findExpandDown(wrapper).trigger('click');
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('diffs/loadMoreLines', {
|
||||
endpoint: 'contextLinesPath',
|
||||
|
|
|
@ -1,33 +1,21 @@
|
|||
import Vue from 'vue';
|
||||
import mountComponent from 'helpers/vue_mount_component_helper';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import FileRowStats from '~/diffs/components/file_row_stats.vue';
|
||||
|
||||
describe('Diff file row stats', () => {
|
||||
let Component;
|
||||
let vm;
|
||||
|
||||
beforeAll(() => {
|
||||
Component = Vue.extend(FileRowStats);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(Component, {
|
||||
const wrapper = mount(FileRowStats, {
|
||||
propsData: {
|
||||
file: {
|
||||
addedLines: 20,
|
||||
removedLines: 10,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
},
|
||||
});
|
||||
|
||||
it('renders added lines count', () => {
|
||||
expect(vm.$el.querySelector('.cgreen').textContent).toContain('+20');
|
||||
expect(wrapper.find('.cgreen').text()).toContain('+20');
|
||||
});
|
||||
|
||||
it('renders removed lines count', () => {
|
||||
expect(vm.$el.querySelector('.cred').textContent).toContain('-10');
|
||||
expect(wrapper.find('.cred').text()).toContain('-10');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -32,7 +32,7 @@ exports[`Settings Form Keep N matches snapshot 1`] = `
|
|||
exports[`Settings Form Keep Regex matches snapshot 1`] = `
|
||||
<expiration-input-stub
|
||||
data-testid="keep-regex-input"
|
||||
description="Tags with names that match this regex pattern are kept. %{linkStart}More information%{linkEnd}"
|
||||
description="Tags with names that match this regex pattern are kept. %{linkStart}View regex examples.%{linkEnd}"
|
||||
error=""
|
||||
label="Keep tags matching:"
|
||||
name="keep-regex"
|
||||
|
@ -54,7 +54,7 @@ exports[`Settings Form OlderThan matches snapshot 1`] = `
|
|||
exports[`Settings Form Remove regex matches snapshot 1`] = `
|
||||
<expiration-input-stub
|
||||
data-testid="remove-regex-input"
|
||||
description="Tags with names that match this regex pattern are removed. %{linkStart}More information%{linkEnd}"
|
||||
description="Tags with names that match this regex pattern are removed. %{linkStart}View regex examples.%{linkEnd}"
|
||||
error=""
|
||||
label="Remove tags matching:"
|
||||
name="remove-regex"
|
||||
|
|
|
@ -41,27 +41,6 @@ describe('ReviewerTitle component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('gutter toggle', () => {
|
||||
it('does not show toggle by default', () => {
|
||||
wrapper = createComponent({
|
||||
numberOfReviewers: 2,
|
||||
editable: false,
|
||||
});
|
||||
|
||||
expect(wrapper.vm.$el.querySelector('.gutter-toggle')).toBeNull();
|
||||
});
|
||||
|
||||
it('shows toggle when showToggle is true', () => {
|
||||
wrapper = createComponent({
|
||||
numberOfReviewers: 2,
|
||||
editable: false,
|
||||
showToggle: true,
|
||||
});
|
||||
|
||||
expect(wrapper.vm.$el.querySelector('.gutter-toggle')).toEqual(expect.any(Object));
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render spinner by default', () => {
|
||||
wrapper = createComponent({
|
||||
numberOfReviewers: 0,
|
||||
|
|
|
@ -1,135 +1,181 @@
|
|||
import Vue from 'vue';
|
||||
import mountComponent from 'helpers/vue_mount_component_helper';
|
||||
import { nextTick } from 'vue';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import eventHub from '~/vue_merge_request_widget/event_hub';
|
||||
import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
|
||||
import WidgetRebase from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
|
||||
|
||||
let wrapper;
|
||||
|
||||
function factory(propsData, mergeRequestWidgetGraphql) {
|
||||
wrapper = shallowMount(WidgetRebase, {
|
||||
propsData,
|
||||
data() {
|
||||
return {
|
||||
state: {
|
||||
rebaseInProgress: propsData.mr.rebaseInProgress,
|
||||
targetBranch: propsData.mr.targetBranch,
|
||||
userPermissions: {
|
||||
pushToSourceBranch: propsData.mr.canPushToSourceBranch,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
provide: { glFeatures: { mergeRequestWidgetGraphql } },
|
||||
mocks: {
|
||||
$apollo: {
|
||||
queries: {
|
||||
state: { loading: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe('Merge request widget rebase component', () => {
|
||||
let Component;
|
||||
let vm;
|
||||
|
||||
const findRebaseMessageEl = () => vm.$el.querySelector('[data-testid="rebase-message"]');
|
||||
const findRebaseMessageElText = () => findRebaseMessageEl().textContent.trim();
|
||||
|
||||
beforeEach(() => {
|
||||
Component = Vue.extend(component);
|
||||
});
|
||||
const findRebaseMessageEl = () => wrapper.find('[data-testid="rebase-message"]');
|
||||
const findRebaseMessageElText = () => findRebaseMessageEl().text();
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
describe('While rebasing', () => {
|
||||
it('should show progress message', () => {
|
||||
vm = mountComponent(Component, {
|
||||
mr: { rebaseInProgress: true },
|
||||
service: {},
|
||||
[true, false].forEach((mergeRequestWidgetGraphql) => {
|
||||
describe(`widget graphql is ${mergeRequestWidgetGraphql ? 'enabled' : 'dislabed'}`, () => {
|
||||
describe('While rebasing', () => {
|
||||
it('should show progress message', () => {
|
||||
factory(
|
||||
{
|
||||
mr: { rebaseInProgress: true },
|
||||
service: {},
|
||||
},
|
||||
mergeRequestWidgetGraphql,
|
||||
);
|
||||
|
||||
expect(findRebaseMessageElText()).toContain('Rebase in progress');
|
||||
});
|
||||
});
|
||||
|
||||
expect(findRebaseMessageElText()).toContain('Rebase in progress');
|
||||
});
|
||||
});
|
||||
|
||||
describe('With permissions', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(Component, {
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: true,
|
||||
},
|
||||
service: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('it should render rebase button and warning message', () => {
|
||||
const text = findRebaseMessageElText();
|
||||
|
||||
expect(text).toContain('Fast-forward merge is not possible.');
|
||||
expect(text.replace(/\s\s+/g, ' ')).toContain(
|
||||
'Rebase the source branch onto the target branch.',
|
||||
);
|
||||
});
|
||||
|
||||
it('it should render error message when it fails', (done) => {
|
||||
vm.rebasingError = 'Something went wrong!';
|
||||
|
||||
Vue.nextTick(() => {
|
||||
expect(findRebaseMessageElText()).toContain('Something went wrong!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Without permissions', () => {
|
||||
it('should render a message explaining user does not have permissions', () => {
|
||||
vm = mountComponent(Component, {
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: false,
|
||||
targetBranch: 'foo',
|
||||
},
|
||||
service: {},
|
||||
});
|
||||
|
||||
const text = findRebaseMessageElText();
|
||||
|
||||
expect(text).toContain('Fast-forward merge is not possible.');
|
||||
expect(text).toContain('Rebase the source branch onto');
|
||||
expect(text).toContain('foo');
|
||||
expect(text.replace(/\s\s+/g, ' ')).toContain('to allow this merge request to be merged.');
|
||||
});
|
||||
|
||||
it('should render the correct target branch name', () => {
|
||||
const targetBranch = 'fake-branch-to-test-with';
|
||||
vm = mountComponent(Component, {
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: false,
|
||||
targetBranch,
|
||||
},
|
||||
service: {},
|
||||
});
|
||||
|
||||
const elem = findRebaseMessageEl();
|
||||
|
||||
expect(elem.innerHTML).toContain(
|
||||
`Fast-forward merge is not possible. Rebase the source branch onto <span class="label-branch">${targetBranch}</span> to allow this merge request to be merged.`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
it('checkRebaseStatus', (done) => {
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
vm = mountComponent(Component, {
|
||||
mr: {},
|
||||
service: {
|
||||
rebase() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
poll() {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
rebase_in_progress: false,
|
||||
merge_error: null,
|
||||
describe('With permissions', () => {
|
||||
it('it should render rebase button and warning message', () => {
|
||||
factory(
|
||||
{
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
service: {},
|
||||
},
|
||||
mergeRequestWidgetGraphql,
|
||||
);
|
||||
|
||||
const text = findRebaseMessageElText();
|
||||
|
||||
expect(text).toContain('Fast-forward merge is not possible.');
|
||||
expect(text.replace(/\s\s+/g, ' ')).toContain(
|
||||
'Rebase the source branch onto the target branch.',
|
||||
);
|
||||
});
|
||||
|
||||
it('it should render error message when it fails', async () => {
|
||||
factory(
|
||||
{
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: true,
|
||||
},
|
||||
service: {},
|
||||
},
|
||||
mergeRequestWidgetGraphql,
|
||||
);
|
||||
|
||||
wrapper.setData({ rebasingError: 'Something went wrong!' });
|
||||
|
||||
await nextTick();
|
||||
expect(findRebaseMessageElText()).toContain('Something went wrong!');
|
||||
});
|
||||
});
|
||||
|
||||
vm.rebase();
|
||||
describe('Without permissions', () => {
|
||||
it('should render a message explaining user does not have permissions', () => {
|
||||
factory(
|
||||
{
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: false,
|
||||
targetBranch: 'foo',
|
||||
},
|
||||
service: {},
|
||||
},
|
||||
mergeRequestWidgetGraphql,
|
||||
);
|
||||
|
||||
const text = findRebaseMessageElText();
|
||||
|
||||
expect(text).toContain('Fast-forward merge is not possible.');
|
||||
expect(text).toContain('Rebase the source branch onto');
|
||||
expect(text).toContain('foo');
|
||||
expect(text.replace(/\s\s+/g, ' ')).toContain(
|
||||
'to allow this merge request to be merged.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render the correct target branch name', () => {
|
||||
const targetBranch = 'fake-branch-to-test-with';
|
||||
factory(
|
||||
{
|
||||
mr: {
|
||||
rebaseInProgress: false,
|
||||
canPushToSourceBranch: false,
|
||||
targetBranch,
|
||||
},
|
||||
service: {},
|
||||
},
|
||||
mergeRequestWidgetGraphql,
|
||||
);
|
||||
|
||||
const elem = findRebaseMessageEl();
|
||||
|
||||
expect(elem.text()).toContain(
|
||||
`Fast-forward merge is not possible. Rebase the source branch onto ${targetBranch} to allow this merge request to be merged.`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
it('checkRebaseStatus', async () => {
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
factory(
|
||||
{
|
||||
mr: {},
|
||||
service: {
|
||||
rebase() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
poll() {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
rebase_in_progress: false,
|
||||
merge_error: null,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
mergeRequestWidgetGraphql,
|
||||
);
|
||||
|
||||
wrapper.vm.rebase();
|
||||
|
||||
// Wait for the rebase request
|
||||
await nextTick();
|
||||
// Wait for the polling request
|
||||
await nextTick();
|
||||
// Wait for the eventHub to be called
|
||||
await nextTick();
|
||||
|
||||
// Wait for the rebase request
|
||||
vm.$nextTick()
|
||||
// Wait for the polling request
|
||||
.then(vm.$nextTick())
|
||||
// Wait for the eventHub to be called
|
||||
.then(vm.$nextTick())
|
||||
.then(() => {
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetRebaseSuccess');
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,15 @@ RSpec.describe Atlassian::JiraConnect::Client do
|
|||
subject { described_class.new('https://gitlab-test.atlassian.net', 'sample_secret') }
|
||||
|
||||
let_it_be(:project) { create_default(:project, :repository) }
|
||||
let_it_be(:mrs_by_title) { create_list(:merge_request, 4, :unique_branches, :jira_title) }
|
||||
let_it_be(:mrs_by_branch) { create_list(:merge_request, 2, :jira_branch) }
|
||||
let_it_be(:red_herrings) { create_list(:merge_request, 1, :unique_branches) }
|
||||
|
||||
let_it_be(:pipelines) do
|
||||
(red_herrings + mrs_by_branch + mrs_by_title).map do |mr|
|
||||
create(:ci_pipeline, merge_request: mr)
|
||||
end
|
||||
end
|
||||
|
||||
around do |example|
|
||||
freeze_time { example.run }
|
||||
|
@ -22,13 +31,19 @@ RSpec.describe Atlassian::JiraConnect::Client do
|
|||
end
|
||||
|
||||
describe '#send_info' do
|
||||
it 'calls store_build_info and store_dev_info as appropriate' do
|
||||
it 'calls store_deploy_info, store_build_info and store_dev_info as appropriate' do
|
||||
expect(subject).to receive(:store_build_info).with(
|
||||
project: project,
|
||||
update_sequence_id: :x,
|
||||
pipelines: :y
|
||||
).and_return(:build_stored)
|
||||
|
||||
expect(subject).to receive(:store_deploy_info).with(
|
||||
project: project,
|
||||
update_sequence_id: :x,
|
||||
deployments: :q
|
||||
).and_return(:deploys_stored)
|
||||
|
||||
expect(subject).to receive(:store_dev_info).with(
|
||||
project: project,
|
||||
update_sequence_id: :x,
|
||||
|
@ -43,10 +58,12 @@ RSpec.describe Atlassian::JiraConnect::Client do
|
|||
commits: :a,
|
||||
branches: :b,
|
||||
merge_requests: :c,
|
||||
pipelines: :y
|
||||
pipelines: :y,
|
||||
deployments: :q
|
||||
}
|
||||
|
||||
expect(subject.send_info(**args)).to contain_exactly(:dev_stored, :build_stored)
|
||||
expect(subject.send_info(**args))
|
||||
.to contain_exactly(:dev_stored, :build_stored, :deploys_stored)
|
||||
end
|
||||
|
||||
it 'only calls methods that we need to call' do
|
||||
|
@ -83,17 +100,65 @@ RSpec.describe Atlassian::JiraConnect::Client do
|
|||
}
|
||||
end
|
||||
|
||||
describe '#store_build_info' do
|
||||
let_it_be(:mrs_by_title) { create_list(:merge_request, 4, :unique_branches, :jira_title) }
|
||||
let_it_be(:mrs_by_branch) { create_list(:merge_request, 2, :jira_branch) }
|
||||
let_it_be(:red_herrings) { create_list(:merge_request, 1, :unique_branches) }
|
||||
|
||||
let_it_be(:pipelines) do
|
||||
(red_herrings + mrs_by_branch + mrs_by_title).map do |mr|
|
||||
create(:ci_pipeline, merge_request: mr)
|
||||
describe '#store_deploy_info' do
|
||||
let_it_be(:environment) { create(:environment, name: 'DEV', project: project) }
|
||||
let_it_be(:deployments) do
|
||||
pipelines.map do |p|
|
||||
build = create(:ci_build, environment: environment.name, pipeline: p, project: project)
|
||||
create(:deployment, deployable: build, environment: environment)
|
||||
end
|
||||
end
|
||||
|
||||
let(:schema) do
|
||||
Atlassian::Schemata.deploy_info_payload
|
||||
end
|
||||
|
||||
let(:body) do
|
||||
matcher = be_valid_json.according_to_schema(schema)
|
||||
|
||||
->(text) { matcher.matches?(text) }
|
||||
end
|
||||
|
||||
before do
|
||||
path = '/rest/deployments/0.1/bulk'
|
||||
stub_full_request('https://gitlab-test.atlassian.net' + path, method: :post)
|
||||
.with(body: body, headers: expected_headers(path))
|
||||
end
|
||||
|
||||
it "calls the API with auth headers" do
|
||||
subject.send(:store_deploy_info, project: project, deployments: deployments)
|
||||
end
|
||||
|
||||
it 'only sends information about relevant MRs' do
|
||||
expect(subject).to receive(:post).with('/rest/deployments/0.1/bulk', { deployments: have_attributes(size: 6) })
|
||||
|
||||
subject.send(:store_deploy_info, project: project, deployments: deployments)
|
||||
end
|
||||
|
||||
it 'does not call the API if there is nothing to report' do
|
||||
expect(subject).not_to receive(:post)
|
||||
|
||||
subject.send(:store_deploy_info, project: project, deployments: deployments.take(1))
|
||||
end
|
||||
|
||||
it 'does not call the API if the feature flag is not enabled' do
|
||||
stub_feature_flags(jira_sync_deployments: false)
|
||||
|
||||
expect(subject).not_to receive(:post)
|
||||
|
||||
subject.send(:store_deploy_info, project: project, deployments: deployments)
|
||||
end
|
||||
|
||||
it 'does call the API if the feature flag enabled for the project' do
|
||||
stub_feature_flags(jira_sync_deployments: project)
|
||||
|
||||
expect(subject).to receive(:post).with('/rest/deployments/0.1/bulk', { deployments: Array })
|
||||
|
||||
subject.send(:store_deploy_info, project: project, deployments: deployments)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#store_build_info' do
|
||||
let(:build_info_payload_schema) do
|
||||
Atlassian::Schemata.build_info_payload
|
||||
end
|
||||
|
@ -143,6 +208,8 @@ RSpec.describe Atlassian::JiraConnect::Client do
|
|||
end
|
||||
|
||||
it 'avoids N+1 database queries' do
|
||||
pending 'https://gitlab.com/gitlab-org/gitlab/-/issues/292818'
|
||||
|
||||
baseline = ActiveRecord::QueryRecorder.new do
|
||||
subject.send(:store_build_info, project: project, pipelines: pipelines)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Atlassian::JiraConnect::Serializers::DeploymentEntity do
|
||||
let_it_be(:user) { create_default(:user) }
|
||||
let_it_be(:project) { create_default(:project, :repository) }
|
||||
let_it_be(:environment) { create(:environment, name: 'prod', project: project) }
|
||||
let_it_be_with_reload(:deployment) { create(:deployment, environment: environment) }
|
||||
|
||||
subject { described_class.represent(deployment) }
|
||||
|
||||
context 'when the deployment does not belong to any Jira issue' do
|
||||
describe '#issue_keys' do
|
||||
it 'is empty' do
|
||||
expect(subject.issue_keys).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_json' do
|
||||
it 'can encode the object' do
|
||||
expect(subject.to_json).to be_valid_json
|
||||
end
|
||||
|
||||
it 'is invalid, since it has no issue keys' do
|
||||
expect(subject.to_json).not_to be_valid_json.according_to_schema(Atlassian::Schemata.deployment_info)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'this is an external deployment' do
|
||||
before do
|
||||
deployment.update!(deployable: nil)
|
||||
end
|
||||
|
||||
it 'does not raise errors when serializing' do
|
||||
expect { subject.to_json }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'returns an empty list of issue keys' do
|
||||
expect(subject.issue_keys).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe 'environment type' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:env_name, :env_type) do
|
||||
'prod' | 'production'
|
||||
'test' | 'testing'
|
||||
'staging' | 'staging'
|
||||
'dev' | 'development'
|
||||
'review/app' | 'development'
|
||||
'something-else' | 'unmapped'
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
environment.update!(name: env_name)
|
||||
end
|
||||
|
||||
let(:exposed_type) { subject.send(:environment_entity).send(:type) }
|
||||
|
||||
it 'has the correct environment type' do
|
||||
expect(exposed_type).to eq(env_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the deployment can be linked to a Jira issue' do
|
||||
let(:pipeline) { create(:ci_pipeline, merge_request: merge_request) }
|
||||
|
||||
before do
|
||||
subject.deployable.update!(pipeline: pipeline)
|
||||
end
|
||||
|
||||
%i[jira_branch jira_title].each do |trait|
|
||||
context "because it belongs to an MR with a #{trait}" do
|
||||
let(:merge_request) { create(:merge_request, trait) }
|
||||
|
||||
describe '#issue_keys' do
|
||||
it 'is not empty' do
|
||||
expect(subject.issue_keys).not_to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_json' do
|
||||
it 'is valid according to the deployment info schema' do
|
||||
expect(subject.to_json).to be_valid_json.according_to_schema(Atlassian::Schemata.deployment_info)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -227,6 +227,56 @@ RSpec.describe Deployment do
|
|||
deployment.skip!
|
||||
end
|
||||
end
|
||||
|
||||
describe 'synching status to Jira' do
|
||||
let(:deployment) { create(:deployment) }
|
||||
|
||||
let(:worker) { ::JiraConnect::SyncDeploymentsWorker }
|
||||
|
||||
it 'calls the worker on creation' do
|
||||
expect(worker).to receive(:perform_async).with(Integer)
|
||||
|
||||
deployment
|
||||
end
|
||||
|
||||
it 'does not call the worker for skipped deployments' do
|
||||
expect(deployment).to be_present # warm-up, ignore the creation trigger
|
||||
|
||||
expect(worker).not_to receive(:perform_async)
|
||||
|
||||
deployment.skip!
|
||||
end
|
||||
|
||||
%i[run! succeed! drop! cancel!].each do |event|
|
||||
context "when we call pipeline.#{event}" do
|
||||
it 'triggers a Jira synch worker' do
|
||||
expect(worker).to receive(:perform_async).with(deployment.id)
|
||||
|
||||
deployment.send(event)
|
||||
end
|
||||
|
||||
context 'the feature is disabled' do
|
||||
it 'does not trigger a worker' do
|
||||
stub_feature_flags(jira_sync_deployments: false)
|
||||
|
||||
expect(worker).not_to receive(:perform_async)
|
||||
|
||||
deployment.send(event)
|
||||
end
|
||||
end
|
||||
|
||||
context 'the feature is enabled for this project' do
|
||||
it 'does trigger a worker' do
|
||||
stub_feature_flags(jira_sync_deployments: deployment.project)
|
||||
|
||||
expect(worker).to receive(:perform_async)
|
||||
|
||||
deployment.send(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#success?' do
|
||||
|
|
|
@ -2,82 +2,185 @@
|
|||
|
||||
module Atlassian
|
||||
module Schemata
|
||||
def self.build_info
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => %w(schemaVersion pipelineId buildNumber updateSequenceNumber displayName url state issueKeys testInfo references),
|
||||
'properties' => {
|
||||
'schemaVersion' => { 'type' => 'string', 'pattern' => '1.0' },
|
||||
'pipelineId' => { 'type' => 'string' },
|
||||
'buildNumber' => { 'type' => 'integer' },
|
||||
'updateSequenceNumber' => { 'type' => 'integer' },
|
||||
'displayName' => { 'type' => 'string' },
|
||||
'url' => { 'type' => 'string' },
|
||||
'state' => {
|
||||
'type' => 'string',
|
||||
'pattern' => '(pending|in_progress|successful|failed|cancelled)'
|
||||
},
|
||||
'issueKeys' => {
|
||||
'type' => 'array',
|
||||
'items' => { 'type' => 'string' },
|
||||
'minItems' => 1
|
||||
},
|
||||
'testInfo' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(totalNumber numberPassed numberFailed numberSkipped),
|
||||
'properties' => {
|
||||
'totalNumber' => { 'type' => 'integer' },
|
||||
'numberFailed' => { 'type' => 'integer' },
|
||||
'numberPassed' => { 'type' => 'integer' },
|
||||
'numberSkipped' => { 'type' => 'integer' }
|
||||
}
|
||||
},
|
||||
'references' => {
|
||||
'type' => 'array',
|
||||
'items' => {
|
||||
class << self
|
||||
def build_info
|
||||
{
|
||||
'type' => 'object',
|
||||
'additionalProperties' => false,
|
||||
'required' => %w(
|
||||
schemaVersion pipelineId buildNumber updateSequenceNumber
|
||||
displayName url state issueKeys testInfo references
|
||||
lastUpdated
|
||||
),
|
||||
'properties' => {
|
||||
'schemaVersion' => schema_version_type,
|
||||
'pipelineId' => { 'type' => 'string' },
|
||||
'buildNumber' => { 'type' => 'integer' },
|
||||
'updateSequenceNumber' => { 'type' => 'integer' },
|
||||
'displayName' => { 'type' => 'string' },
|
||||
'lastUpdated' => { 'type' => 'string' },
|
||||
'url' => { 'type' => 'string' },
|
||||
'state' => state_type,
|
||||
'issueKeys' => issue_keys_type,
|
||||
'testInfo' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(commit ref),
|
||||
'required' => %w(totalNumber numberPassed numberFailed numberSkipped),
|
||||
'properties' => {
|
||||
'commit' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(id repositoryUri),
|
||||
'properties' => {
|
||||
'id' => { 'type' => 'string' },
|
||||
'repositoryUri' => { 'type' => 'string' }
|
||||
}
|
||||
},
|
||||
'ref' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(name uri),
|
||||
'properties' => {
|
||||
'name' => { 'type' => 'string' },
|
||||
'uri' => { 'type' => 'string' }
|
||||
'totalNumber' => { 'type' => 'integer' },
|
||||
'numberFailed' => { 'type' => 'integer' },
|
||||
'numberPassed' => { 'type' => 'integer' },
|
||||
'numberSkipped' => { 'type' => 'integer' }
|
||||
}
|
||||
},
|
||||
'references' => {
|
||||
'type' => 'array',
|
||||
'items' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(commit ref),
|
||||
'properties' => {
|
||||
'commit' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(id repositoryUri),
|
||||
'properties' => {
|
||||
'id' => { 'type' => 'string' },
|
||||
'repositoryUri' => { 'type' => 'string' }
|
||||
}
|
||||
},
|
||||
'ref' => {
|
||||
'type' => 'object',
|
||||
'required' => %w(name uri),
|
||||
'properties' => {
|
||||
'name' => { 'type' => 'string' },
|
||||
'uri' => { 'type' => 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.build_info_payload
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => %w(providerMetadata builds),
|
||||
'properties' => {
|
||||
'providerMetadata' => provider_metadata,
|
||||
'builds' => { 'type' => 'array', 'items' => build_info }
|
||||
def deployment_info
|
||||
{
|
||||
'type' => 'object',
|
||||
'additionalProperties' => false,
|
||||
'required' => %w(
|
||||
deploymentSequenceNumber updateSequenceNumber
|
||||
associations displayName url description lastUpdated
|
||||
state pipeline environment
|
||||
),
|
||||
'properties' => {
|
||||
'deploymentSequenceNumber' => { 'type' => 'integer' },
|
||||
'updateSequenceNumber' => { 'type' => 'integer' },
|
||||
'associations' => {
|
||||
'type' => 'array',
|
||||
'items' => association_type,
|
||||
'minItems' => 1
|
||||
},
|
||||
'displayName' => { 'type' => 'string' },
|
||||
'description' => { 'type' => 'string' },
|
||||
'label' => { 'type' => 'string' },
|
||||
'url' => { 'type' => 'string' },
|
||||
'lastUpdated' => { 'type' => 'string' },
|
||||
'state' => state_type,
|
||||
'pipeline' => pipeline_type,
|
||||
'environment' => environment_type,
|
||||
'schemaVersion' => schema_version_type
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.provider_metadata
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => %w(product),
|
||||
'properties' => { 'product' => { 'type' => 'string' } }
|
||||
}
|
||||
def environment_type
|
||||
{
|
||||
'type' => 'object',
|
||||
'additionalProperties' => false,
|
||||
'required' => %w(id displayName type),
|
||||
'properties' => {
|
||||
'id' => { 'type' => 'string', 'maxLength' => 255 },
|
||||
'displayName' => { 'type' => 'string', 'maxLength' => 255 },
|
||||
'type' => {
|
||||
'type' => 'string',
|
||||
'pattern' => '(unmapped|development|testing|staging|production)'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def pipeline_type
|
||||
{
|
||||
'type' => 'object',
|
||||
'additionalProperties' => false,
|
||||
'required' => %w(id displayName url),
|
||||
'properties' => {
|
||||
'id' => { 'type' => 'string', 'maxLength' => 255 },
|
||||
'displayName' => { 'type' => 'string', 'maxLength' => 255 },
|
||||
'url' => { 'type' => 'string', 'maxLength' => 2000 }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def schema_version_type
|
||||
{ 'type' => 'string', 'pattern' => '1.0' }
|
||||
end
|
||||
|
||||
def state_type
|
||||
{
|
||||
'type' => 'string',
|
||||
'pattern' => '(pending|in_progress|successful|failed|cancelled)'
|
||||
}
|
||||
end
|
||||
|
||||
def association_type
|
||||
{
|
||||
'type' => 'object',
|
||||
'additionalProperties' => false,
|
||||
'required' => %w(associationType values),
|
||||
'properties' => {
|
||||
'associationType' => {
|
||||
'type' => 'string',
|
||||
'pattern' => '(issueKeys|issueIdOrKeys)'
|
||||
},
|
||||
'values' => issue_keys_type
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def issue_keys_type
|
||||
{
|
||||
'type' => 'array',
|
||||
'items' => { 'type' => 'string' },
|
||||
'minItems' => 1,
|
||||
'maxItems' => 100
|
||||
}
|
||||
end
|
||||
|
||||
def deploy_info_payload
|
||||
payload('deployments', deployment_info)
|
||||
end
|
||||
|
||||
def build_info_payload
|
||||
payload('builds', build_info)
|
||||
end
|
||||
|
||||
def payload(key, schema)
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => ['providerMetadata', key],
|
||||
'properties' => {
|
||||
'providerMetadata' => provider_metadata,
|
||||
key => { 'type' => 'array', 'items' => schema }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def provider_metadata
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => %w(product),
|
||||
'properties' => { 'product' => { 'type' => 'string' } }
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,7 +33,7 @@ Capybara.register_server :puma_via_workhorse do |app, port, host, **options|
|
|||
socket_path = file.path
|
||||
file.close! # We just want the filename
|
||||
|
||||
TestEnv.with_workhorse(TestEnv.workhorse_dir, host, port, socket_path) do
|
||||
TestEnv.with_workhorse(host, port, socket_path) do
|
||||
Capybara.servers[:puma].call(app, nil, socket_path, **options)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -284,7 +284,7 @@ module TestEnv
|
|||
@workhorse_path ||= File.join('tmp', 'tests', 'gitlab-workhorse')
|
||||
end
|
||||
|
||||
def with_workhorse(workhorse_dir, host, port, upstream, &blk)
|
||||
def with_workhorse(host, port, upstream, &blk)
|
||||
host = "[#{host}]" if host.include?(':')
|
||||
listen_addr = [host, port].join(':')
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ::JiraConnect::SyncDeploymentsWorker do
|
||||
include AfterNextHelpers
|
||||
include ServicesHelper
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:deployment) { create(:deployment) }
|
||||
|
||||
let(:sequence_id) { Random.random_number(1..10_000) }
|
||||
let(:object_id) { deployment.id }
|
||||
|
||||
subject { described_class.new.perform(object_id, sequence_id) }
|
||||
|
||||
context 'when the object exists' do
|
||||
it 'calls the Jira sync service' do
|
||||
expect_next(::JiraConnect::SyncService, deployment.project)
|
||||
.to receive(:execute).with(deployments: contain_exactly(deployment), update_sequence_id: sequence_id)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the object does not exist' do
|
||||
let(:object_id) { non_existing_record_id }
|
||||
|
||||
it 'does not call the sync service' do
|
||||
expect_next(::JiraConnect::SyncService).not_to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(jira_sync_deployments: false)
|
||||
end
|
||||
|
||||
it 'does not call the sync service' do
|
||||
expect_next(::JiraConnect::SyncService).not_to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature flag is enabled for this project' do
|
||||
before do
|
||||
stub_feature_flags(jira_sync_deployments: deployment.project)
|
||||
end
|
||||
|
||||
it 'calls the sync service' do
|
||||
expect_next(::JiraConnect::SyncService).to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -871,10 +871,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
|
||||
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
|
||||
|
||||
"@gitlab/ui@25.3.1":
|
||||
version "25.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-25.3.1.tgz#7557c810397f8c4b81c5360e4642afc3f8274dfc"
|
||||
integrity sha512-vCl74UZgQ5m1caJk8O067KKYa+DP40ES2XDnM/wAc9mZAMynP0GPpePc3cmTLY8vpfzxx2A2iJr04SLgI2pxjA==
|
||||
"@gitlab/ui@25.4.0":
|
||||
version "25.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-25.4.0.tgz#67bfd2a905097fc4cec0272665c36c722b3475c9"
|
||||
integrity sha512-/dffpdyDcX102wWTbzDQOmOGfAEyDitRWCBOk2U+WRKPJIsWYtZuw40putwNA/gUUE1U08TPHf3sGSLzwIKZPA==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
"@gitlab/vue-toasted" "^1.3.0"
|
||||
|
|
Loading…
Reference in New Issue