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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-08 15:09:53 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-08 15:09:53 +0300
commit148b75b329294f6b6ae409bbf8d70590e63c6bc9 (patch)
tree30918a97e353067ff9c99e04fb7e296305d130b7 /app
parent707742e59ca57d1f2ea00d65fa35a7b9a5ded398 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diffs/store/actions.js4
-rw-r--r--app/assets/javascripts/diffs/store/mutation_types.js2
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js9
-rw-r--r--app/assets/javascripts/registry/settings/components/registry_settings_app.vue6
-rw-r--r--app/assets/javascripts/registry/settings/components/settings_form.vue4
-rw-r--r--app/assets/javascripts/registry/settings/constants.js36
-rw-r--r--app/assets/javascripts/registry/settings/utils.js (renamed from app/assets/javascripts/registry/shared/utils.js)15
-rw-r--r--app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue258
-rw-r--r--app/assets/javascripts/registry/shared/constants.js69
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue2
-rw-r--r--app/assets/stylesheets/fontawesome_custom.scss4
-rw-r--r--app/assets/stylesheets/framework/buttons.scss10
-rw-r--r--app/assets/stylesheets/pages/issues.scss8
-rw-r--r--app/assets/stylesheets/pages/projects.scss9
-rw-r--r--app/models/ci/build_dependencies.rb78
-rw-r--r--app/models/identity.rb3
-rw-r--r--app/models/user.rb16
-rw-r--r--app/services/projects/prometheus/alerts/notify_service.rb15
18 files changed, 145 insertions, 403 deletions
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index ee319990290..8c72971682d 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -185,11 +185,11 @@ export const fetchDiffFilesMeta = ({ commit, state }) => {
.get(mergeUrlParams(urlParams, state.endpointMetadata))
.then(({ data }) => {
const strippedData = { ...data };
-
delete strippedData.diff_files;
+
commit(types.SET_LOADING, false);
commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []);
- commit(types.SET_DIFF_DATA, strippedData);
+ commit(types.SET_DIFF_METADATA, strippedData);
worker.postMessage(prepareDiffData(data, state.diffFiles));
diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js
index 25184028799..30097239aaa 100644
--- a/app/assets/javascripts/diffs/store/mutation_types.js
+++ b/app/assets/javascripts/diffs/store/mutation_types.js
@@ -3,7 +3,7 @@ export const SET_LOADING = 'SET_LOADING';
export const SET_BATCH_LOADING = 'SET_BATCH_LOADING';
export const SET_RETRIEVING_BATCHES = 'SET_RETRIEVING_BATCHES';
-export const SET_DIFF_DATA = 'SET_DIFF_DATA';
+export const SET_DIFF_METADATA = 'SET_DIFF_METADATA';
export const SET_DIFF_DATA_BATCH = 'SET_DIFF_DATA_BATCH';
export const SET_DIFF_FILES = 'SET_DIFF_FILES';
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 69ae3f705e3..90940d82226 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -66,17 +66,10 @@ export default {
updateDiffFilesInState(state, files);
},
- [types.SET_DIFF_DATA](state, data) {
- let files = state.diffFiles;
-
- if (window.location.search.indexOf('diff_id') !== -1 && data.diff_files) {
- files = prepareDiffData(data, files);
- }
-
+ [types.SET_DIFF_METADATA](state, data) {
Object.assign(state, {
...convertObjectPropsToCamelCase(data),
});
- updateDiffFilesInState(state, files);
},
[types.SET_DIFF_DATA_BATCH](state, data) {
diff --git a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
index e236834d8e1..ac6a0871153 100644
--- a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
+++ b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
@@ -2,16 +2,16 @@
import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import { isEqual, get, isEmpty } from 'lodash';
import expirationPolicyQuery from '../graphql/queries/get_expiration_policy.graphql';
-import { FETCH_SETTINGS_ERROR_MESSAGE } from '../../shared/constants';
-
-import SettingsForm from './settings_form.vue';
import {
+ FETCH_SETTINGS_ERROR_MESSAGE,
UNAVAILABLE_FEATURE_TITLE,
UNAVAILABLE_FEATURE_INTRO_TEXT,
UNAVAILABLE_USER_FEATURE_TEXT,
UNAVAILABLE_ADMIN_FEATURE_TEXT,
} from '../constants';
+import SettingsForm from './settings_form.vue';
+
export default {
components: {
SettingsForm,
diff --git a/app/assets/javascripts/registry/settings/components/settings_form.vue b/app/assets/javascripts/registry/settings/components/settings_form.vue
index 3eab7e6d038..c46c633d274 100644
--- a/app/assets/javascripts/registry/settings/components/settings_form.vue
+++ b/app/assets/javascripts/registry/settings/components/settings_form.vue
@@ -4,8 +4,6 @@ import Tracking from '~/tracking';
import {
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
-} from '~/registry/shared/constants';
-import {
SET_CLEANUP_POLICY_BUTTON,
KEEP_HEADER_TEXT,
KEEP_INFO_TEXT,
@@ -21,7 +19,7 @@ import {
CADENCE_LABEL,
EXPIRATION_POLICY_FOOTER_NOTE,
} from '~/registry/settings/constants';
-import { formOptionsGenerator } from '~/registry/shared/utils';
+import { formOptionsGenerator } from '~/registry/settings/utils';
import updateContainerExpirationPolicyMutation from '~/registry/settings/graphql/mutations/update_container_expiration_policy.graphql';
import { updateContainerExpirationPolicy } from '~/registry/settings/graphql/utils/cache_update';
import ExpirationDropdown from './expiration_dropdown.vue';
diff --git a/app/assets/javascripts/registry/settings/constants.js b/app/assets/javascripts/registry/settings/constants.js
index 1dd533ce665..21c54299632 100644
--- a/app/assets/javascripts/registry/settings/constants.js
+++ b/app/assets/javascripts/registry/settings/constants.js
@@ -52,4 +52,40 @@ export const EXPIRATION_POLICY_FOOTER_NOTE = s__(
'ContainerRegistry|Note: Any policy update will result in a change to the scheduled run date and time',
);
+export const KEEP_N_OPTIONS = [
+ { key: 'ONE_TAG', variable: 1, default: false },
+ { key: 'FIVE_TAGS', variable: 5, default: false },
+ { key: 'TEN_TAGS', variable: 10, default: true },
+ { key: 'TWENTY_FIVE_TAGS', variable: 25, default: false },
+ { key: 'FIFTY_TAGS', variable: 50, default: false },
+ { key: 'ONE_HUNDRED_TAGS', variable: 100, default: false },
+];
+
+export const CADENCE_OPTIONS = [
+ { key: 'EVERY_DAY', label: __('Every day'), default: true },
+ { key: 'EVERY_WEEK', label: __('Every week'), default: false },
+ { key: 'EVERY_TWO_WEEKS', label: __('Every two weeks'), default: false },
+ { key: 'EVERY_MONTH', label: __('Every month'), default: false },
+ { key: 'EVERY_THREE_MONTHS', label: __('Every three months'), default: false },
+];
+
+export const OLDER_THAN_OPTIONS = [
+ { key: 'SEVEN_DAYS', variable: 7, default: false },
+ { key: 'FOURTEEN_DAYS', variable: 14, default: false },
+ { key: 'THIRTY_DAYS', variable: 30, default: false },
+ { key: 'NINETY_DAYS', variable: 90, default: true },
+];
+
+export const FETCH_SETTINGS_ERROR_MESSAGE = s__(
+ 'ContainerRegistry|Something went wrong while fetching the cleanup policy.',
+);
+
+export const UPDATE_SETTINGS_ERROR_MESSAGE = s__(
+ 'ContainerRegistry|Something went wrong while updating the cleanup policy.',
+);
+
+export const UPDATE_SETTINGS_SUCCESS_MESSAGE = s__(
+ 'ContainerRegistry|Cleanup policy successfully saved.',
+);
+
export const NAME_REGEX_LENGTH = 255;
diff --git a/app/assets/javascripts/registry/shared/utils.js b/app/assets/javascripts/registry/settings/utils.js
index 5c8c505f835..51b4fb6bdb8 100644
--- a/app/assets/javascripts/registry/shared/utils.js
+++ b/app/assets/javascripts/registry/settings/utils.js
@@ -6,21 +6,6 @@ export const findDefaultOption = options => {
return item ? item.key : null;
};
-export const mapComputedToEvent = (list, root) => {
- const result = {};
- list.forEach(e => {
- result[e] = {
- get() {
- return this[root][e];
- },
- set(value) {
- this.$emit('input', { newValue: { ...this[root], [e]: value }, modified: e });
- },
- };
- });
- return result;
-};
-
export const olderThanTranslationGenerator = variable => n__('%d day', '%d days', variable);
export const keepNTranslationGenerator = variable =>
diff --git a/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue b/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
deleted file mode 100644
index 2b8e9f6ff64..00000000000
--- a/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
+++ /dev/null
@@ -1,258 +0,0 @@
-<script>
-import { uniqueId } from 'lodash';
-import { GlFormGroup, GlToggle, GlFormSelect, GlFormTextarea, GlSprintf } from '@gitlab/ui';
-import {
- NAME_REGEX_LENGTH,
- ENABLED_TEXT,
- DISABLED_TEXT,
- TEXT_AREA_INVALID_FEEDBACK,
- EXPIRATION_INTERVAL_LABEL,
- EXPIRATION_SCHEDULE_LABEL,
- KEEP_N_LABEL,
- NAME_REGEX_LABEL,
- NAME_REGEX_PLACEHOLDER,
- NAME_REGEX_DESCRIPTION,
- NAME_REGEX_KEEP_LABEL,
- NAME_REGEX_KEEP_PLACEHOLDER,
- NAME_REGEX_KEEP_DESCRIPTION,
- ENABLE_TOGGLE_LABEL,
- ENABLE_TOGGLE_DESCRIPTION,
-} from '../constants';
-import { mapComputedToEvent } from '../utils';
-
-export default {
- components: {
- GlFormGroup,
- GlToggle,
- GlFormSelect,
- GlFormTextarea,
- GlSprintf,
- },
- props: {
- formOptions: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- apiErrors: {
- type: Object,
- required: false,
- default: null,
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
- value: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- labelCols: {
- type: [Number, String],
- required: false,
- default: 3,
- },
- labelAlign: {
- type: String,
- required: false,
- default: 'right',
- },
- },
- i18n: {
- ENABLE_TOGGLE_LABEL,
- ENABLE_TOGGLE_DESCRIPTION,
- },
- selectList: [
- {
- name: 'expiration-policy-interval',
- label: EXPIRATION_INTERVAL_LABEL,
- model: 'olderThan',
- },
- {
- name: 'expiration-policy-schedule',
- label: EXPIRATION_SCHEDULE_LABEL,
- model: 'cadence',
- },
- {
- name: 'expiration-policy-latest',
- label: KEEP_N_LABEL,
- model: 'keepN',
- },
- ],
- textAreaList: [
- {
- name: 'expiration-policy-name-matching',
- label: NAME_REGEX_LABEL,
- model: 'nameRegex',
- placeholder: NAME_REGEX_PLACEHOLDER,
- description: NAME_REGEX_DESCRIPTION,
- },
- {
- name: 'expiration-policy-keep-name',
- label: NAME_REGEX_KEEP_LABEL,
- model: 'nameRegexKeep',
- placeholder: NAME_REGEX_KEEP_PLACEHOLDER,
- description: NAME_REGEX_KEEP_DESCRIPTION,
- },
- ],
- data() {
- return {
- uniqueId: uniqueId(),
- };
- },
- computed: {
- ...mapComputedToEvent(
- ['enabled', 'cadence', 'olderThan', 'keepN', 'nameRegex', 'nameRegexKeep'],
- 'value',
- ),
- policyEnabledText() {
- return this.enabled ? ENABLED_TEXT : DISABLED_TEXT;
- },
- textAreaValidation() {
- const nameRegexErrors = this.apiErrors?.nameRegex || this.validateRegexLength(this.nameRegex);
- const nameKeepRegexErrors =
- this.apiErrors?.nameRegexKeep || this.validateRegexLength(this.nameRegexKeep);
-
- return {
- /*
- * The state has this form:
- * null: gray border, no message
- * true: green border, no message ( because none is configured)
- * false: red border, error message
- * So in this function we keep null if the are no message otherwise we 'invert' the error message
- */
- nameRegex: {
- state: nameRegexErrors === null ? null : !nameRegexErrors,
- message: nameRegexErrors,
- },
- nameRegexKeep: {
- state: nameKeepRegexErrors === null ? null : !nameKeepRegexErrors,
- message: nameKeepRegexErrors,
- },
- };
- },
- fieldsValidity() {
- return (
- this.textAreaValidation.nameRegex.state !== false &&
- this.textAreaValidation.nameRegexKeep.state !== false
- );
- },
- isFormElementDisabled() {
- return !this.enabled || this.isLoading;
- },
- },
- watch: {
- fieldsValidity: {
- immediate: true,
- handler(valid) {
- if (valid) {
- this.$emit('validated');
- } else {
- this.$emit('invalidated');
- }
- },
- },
- },
- methods: {
- validateRegexLength(value) {
- if (!value) {
- return null;
- }
- return value.length <= NAME_REGEX_LENGTH ? '' : TEXT_AREA_INVALID_FEEDBACK;
- },
- idGenerator(id) {
- return `${id}_${this.uniqueId}`;
- },
- updateModel(value, key) {
- this[key] = value;
- },
- },
-};
-</script>
-
-<template>
- <div ref="form-elements" class="gl-line-height-20">
- <gl-form-group
- :id="idGenerator('expiration-policy-toggle-group')"
- :label-cols="labelCols"
- :label-align="labelAlign"
- :label-for="idGenerator('expiration-policy-toggle')"
- :label="$options.i18n.ENABLE_TOGGLE_LABEL"
- >
- <div class="gl-display-flex">
- <gl-toggle
- :id="idGenerator('expiration-policy-toggle')"
- v-model="enabled"
- :disabled="isLoading"
- />
- <span class="gl-mb-3 gl-ml-3 gl-line-height-20">
- <gl-sprintf :message="$options.i18n.ENABLE_TOGGLE_DESCRIPTION">
- <template #toggleStatus>
- <strong>{{ policyEnabledText }}</strong>
- </template>
- </gl-sprintf>
- </span>
- </div>
- </gl-form-group>
-
- <gl-form-group
- v-for="select in $options.selectList"
- :id="idGenerator(`${select.name}-group`)"
- :key="select.name"
- :label-cols="labelCols"
- :label-align="labelAlign"
- :label-for="idGenerator(select.name)"
- :label="select.label"
- >
- <gl-form-select
- :id="idGenerator(select.name)"
- :value="value[select.model]"
- :disabled="isFormElementDisabled"
- @input="updateModel($event, select.model)"
- >
- <option v-for="option in formOptions[select.model]" :key="option.key" :value="option.key">
- {{ option.label }}
- </option>
- </gl-form-select>
- </gl-form-group>
-
- <gl-form-group
- v-for="textarea in $options.textAreaList"
- :id="idGenerator(`${textarea.name}-group`)"
- :key="textarea.name"
- :label-cols="labelCols"
- :label-align="labelAlign"
- :label-for="idGenerator(textarea.name)"
- :state="textAreaValidation[textarea.model].state"
- :invalid-feedback="textAreaValidation[textarea.model].message"
- >
- <template #label>
- <gl-sprintf :message="textarea.label">
- <template #italic="{content}">
- <i>{{ content }}</i>
- </template>
- </gl-sprintf>
- </template>
- <gl-form-textarea
- :id="idGenerator(textarea.name)"
- :value="value[textarea.model]"
- :placeholder="textarea.placeholder"
- :state="textAreaValidation[textarea.model].state"
- :disabled="isFormElementDisabled"
- trim
- @input="updateModel($event, textarea.model)"
- />
- <template #description>
- <span ref="regex-description">
- <gl-sprintf :message="textarea.description">
- <template #code="{content}">
- <code>{{ content }}</code>
- </template>
- </gl-sprintf>
- </span>
- </template>
- </gl-form-group>
- </div>
-</template>
diff --git a/app/assets/javascripts/registry/shared/constants.js b/app/assets/javascripts/registry/shared/constants.js
deleted file mode 100644
index d1e3d93938b..00000000000
--- a/app/assets/javascripts/registry/shared/constants.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { s__, __ } from '~/locale';
-
-export const FETCH_SETTINGS_ERROR_MESSAGE = s__(
- 'ContainerRegistry|Something went wrong while fetching the cleanup policy.',
-);
-
-export const UPDATE_SETTINGS_ERROR_MESSAGE = s__(
- 'ContainerRegistry|Something went wrong while updating the cleanup policy.',
-);
-
-export const UPDATE_SETTINGS_SUCCESS_MESSAGE = s__(
- 'ContainerRegistry|Cleanup policy successfully saved.',
-);
-
-export const NAME_REGEX_LENGTH = 255;
-
-export const ENABLED_TEXT = __('Enabled');
-export const DISABLED_TEXT = __('Disabled');
-
-export const ENABLE_TOGGLE_LABEL = s__('ContainerRegistry|Cleanup policy:');
-export const ENABLE_TOGGLE_DESCRIPTION = s__(
- 'ContainerRegistry|%{toggleStatus} - Tags matching the patterns defined below will be scheduled for deletion',
-);
-
-export const TEXT_AREA_INVALID_FEEDBACK = s__(
- 'ContainerRegistry|The value of this input should be less than 256 characters',
-);
-
-export const EXPIRATION_INTERVAL_LABEL = s__('ContainerRegistry|Expiration interval:');
-export const EXPIRATION_SCHEDULE_LABEL = s__('ContainerRegistry|Expiration schedule:');
-export const KEEP_N_LABEL = s__('ContainerRegistry|Number of tags to retain:');
-export const NAME_REGEX_LABEL = s__(
- 'ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}',
-);
-export const NAME_REGEX_PLACEHOLDER = '';
-export const NAME_REGEX_DESCRIPTION = s__(
- 'ContainerRegistry|Wildcards such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}',
-);
-export const NAME_REGEX_KEEP_LABEL = s__(
- 'ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}be preserved:%{italicEnd}',
-);
-export const NAME_REGEX_KEEP_PLACEHOLDER = '';
-export const NAME_REGEX_KEEP_DESCRIPTION = s__(
- 'ContainerRegistry|Wildcards such as %{codeStart}.*-master%{codeEnd} or %{codeStart}release-.*%{codeEnd} are supported',
-);
-
-export const KEEP_N_OPTIONS = [
- { variable: 1, key: 'ONE_TAG', default: false },
- { variable: 5, key: 'FIVE_TAGS', default: false },
- { variable: 10, key: 'TEN_TAGS', default: true },
- { variable: 25, key: 'TWENTY_FIVE_TAGS', default: false },
- { variable: 50, key: 'FIFTY_TAGS', default: false },
- { variable: 100, key: 'ONE_HUNDRED_TAGS', default: false },
-];
-
-export const CADENCE_OPTIONS = [
- { key: 'EVERY_DAY', label: __('Every day'), default: true },
- { key: 'EVERY_WEEK', label: __('Every week'), default: false },
- { key: 'EVERY_TWO_WEEKS', label: __('Every two weeks'), default: false },
- { key: 'EVERY_MONTH', label: __('Every month'), default: false },
- { key: 'EVERY_THREE_MONTHS', label: __('Every three months'), default: false },
-];
-
-export const OLDER_THAN_OPTIONS = [
- { key: 'SEVEN_DAYS', variable: 7, default: false },
- { key: 'FOURTEEN_DAYS', variable: 14, default: false },
- { key: 'THIRTY_DAYS', variable: 30, default: false },
- { key: 'NINETY_DAYS', variable: 90, default: true },
-];
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 433dcf2e219..d121daf0aa7 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -464,7 +464,7 @@ export default {
<security-reports-app
v-if="shouldRenderSecurityReport"
:pipeline-id="mr.pipeline.id"
- :project-id="mr.targetProjectId"
+ :project-id="mr.sourceProjectId"
:security-reports-docs-path="mr.securityReportsDocsPath"
/>
diff --git a/app/assets/stylesheets/fontawesome_custom.scss b/app/assets/stylesheets/fontawesome_custom.scss
index a5e357c8fda..693632c3af1 100644
--- a/app/assets/stylesheets/fontawesome_custom.scss
+++ b/app/assets/stylesheets/fontawesome_custom.scss
@@ -27,10 +27,6 @@
font-size: 2em;
}
-.fa-caret-down::before {
- content: '\f0d7';
-}
-
.fa-exclamation-triangle::before {
content: '\f071';
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 1e051b3bcf0..db41d28575f 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -231,16 +231,6 @@
color: $gray-700;
}
- .fa-caret-down {
- margin-left: 5px;
- }
-
- &.dropdown-toggle {
- .fa-caret-down {
- margin-left: 3px;
- }
- }
-
&.btn-text-field {
width: 100%;
text-align: left;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 51870ace23b..1caf62067a6 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -201,14 +201,6 @@ ul.related-merge-requests > li {
}
}
}
-
- .create-merge-request-dropdown-toggle {
- .fa-caret-down {
- pointer-events: none;
- color: inherit;
- margin-left: 0;
- }
- }
}
.discussion-reply-holder {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index e5a9e99b2fb..974f74a4368 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -148,15 +148,6 @@
fill: $layout-link-gray;
}
- .fa-caret-down {
- margin-left: 3px;
- line-height: 0;
-
- &.dropdown-btn-icon {
- margin-left: 0;
- }
- }
-
.notifications-icon {
top: 1px;
margin-right: 0;
diff --git a/app/models/ci/build_dependencies.rb b/app/models/ci/build_dependencies.rb
index 7e690dc413c..2c6a9a63bdb 100644
--- a/app/models/ci/build_dependencies.rb
+++ b/app/models/ci/build_dependencies.rb
@@ -2,6 +2,8 @@
module Ci
class BuildDependencies
+ include ::Gitlab::Utils::StrongMemoize
+
attr_reader :processable
def initialize(processable)
@@ -9,7 +11,7 @@ module Ci
end
def all
- (local + cross_project).uniq
+ (local + cross_pipeline + cross_project).uniq
end
# Dependencies local to the given pipeline
@@ -23,6 +25,14 @@ module Ci
deps
end
+ # Dependencies from the same parent-pipeline hierarchy excluding
+ # the current job's pipeline
+ def cross_pipeline
+ strong_memoize(:cross_pipeline) do
+ fetch_dependencies_in_hierarchy
+ end
+ end
+
# Dependencies that are defined by project and ref
def cross_project
[]
@@ -33,7 +43,7 @@ module Ci
end
def valid?
- valid_local? && valid_cross_project?
+ valid_local? && valid_cross_pipeline? && valid_cross_project?
end
private
@@ -44,6 +54,54 @@ module Ci
::Ci::Build
end
+ def fetch_dependencies_in_hierarchy
+ deps_specifications = specified_cross_pipeline_dependencies
+ return [] if deps_specifications.empty?
+
+ deps_specifications = expand_variables_and_validate(deps_specifications)
+ jobs_in_pipeline_hierarchy(deps_specifications)
+ end
+
+ def jobs_in_pipeline_hierarchy(deps_specifications)
+ all_pipeline_ids = []
+ all_job_names = []
+
+ deps_specifications.each do |spec|
+ all_pipeline_ids << spec[:pipeline]
+ all_job_names << spec[:job]
+ end
+
+ model_class.latest.success
+ .in_pipelines(processable.pipeline.same_family_pipeline_ids)
+ .in_pipelines(all_pipeline_ids.uniq)
+ .by_name(all_job_names.uniq)
+ .select do |dependency|
+ # the query may not return exact matches pipeline-job, so we filter
+ # them separately.
+ deps_specifications.find do |spec|
+ spec[:pipeline] == dependency.pipeline_id &&
+ spec[:job] == dependency.name
+ end
+ end
+ end
+
+ def expand_variables_and_validate(specifications)
+ specifications.map do |spec|
+ pipeline = ExpandVariables.expand(spec[:pipeline].to_s, processable_variables).to_i
+ # current pipeline is not allowed because local dependencies
+ # should be used instead.
+ next if pipeline == processable.pipeline_id
+
+ job = ExpandVariables.expand(spec[:job], processable_variables)
+
+ { job: job, pipeline: pipeline }
+ end.compact
+ end
+
+ def valid_cross_pipeline?
+ cross_pipeline.size == specified_cross_pipeline_dependencies.size
+ end
+
def valid_local?
return true if Feature.enabled?(:ci_disable_validates_dependencies)
@@ -78,6 +136,22 @@ module Ci
scope.where(name: processable.options[:dependencies])
end
+
+ def processable_variables
+ -> { processable.simple_variables_without_dependencies }
+ end
+
+ def specified_cross_pipeline_dependencies
+ strong_memoize(:specified_cross_pipeline_dependencies) do
+ next [] unless Feature.enabled?(:ci_cross_pipeline_artifacts_download, processable.project, default_enabled: false)
+
+ specified_cross_dependencies.select { |dep| dep[:pipeline] && dep[:artifacts] }
+ end
+ end
+
+ def specified_cross_dependencies
+ Array(processable.options[:cross_dependencies])
+ end
end
end
diff --git a/app/models/identity.rb b/app/models/identity.rb
index 40d9f856abf..fc97c68b756 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -18,6 +18,9 @@ class Identity < ApplicationRecord
scope :with_extern_uid, ->(provider, extern_uid) do
iwhere(extern_uid: normalize_uid(provider, extern_uid)).with_provider(provider)
end
+ scope :with_any_extern_uid, ->(provider) do
+ where.not(extern_uid: nil).with_provider(provider)
+ end
def ldap?
Gitlab::Auth::OAuth::Provider.ldap_provider?(provider)
diff --git a/app/models/user.rb b/app/models/user.rb
index 083117ef8ec..4acb287b51c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1045,7 +1045,7 @@ class User < ApplicationRecord
end
def require_personal_access_token_creation_for_git_auth?
- return false if allow_password_authentication_for_git? || ldap_user?
+ return false if allow_password_authentication_for_git? || password_based_omniauth_user?
PersonalAccessTokensFinder.new(user: self, impersonation: false, state: 'active').execute.none?
end
@@ -1063,7 +1063,7 @@ class User < ApplicationRecord
end
def allow_password_authentication_for_git?
- Gitlab::CurrentSettings.password_authentication_enabled_for_git? && !ldap_user?
+ Gitlab::CurrentSettings.password_authentication_enabled_for_git? && !password_based_omniauth_user?
end
def can_change_username?
@@ -1143,6 +1143,18 @@ class User < ApplicationRecord
namespace.find_fork_of(project)
end
+ def password_based_omniauth_user?
+ ldap_user? || crowd_user?
+ end
+
+ def crowd_user?
+ if identities.loaded?
+ identities.find { |identity| identity.provider == 'crowd' && identity.extern_uid.present? }
+ else
+ identities.with_any_extern_uid('crowd').exists?
+ end
+ end
+
def ldap_user?
if identities.loaded?
identities.find { |identity| Gitlab::Auth::OAuth::Provider.ldap_provider?(identity.provider) && !identity.extern_uid.nil? }
diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb
index 8ad4f59373d..1f90263ba4a 100644
--- a/app/services/projects/prometheus/alerts/notify_service.rb
+++ b/app/services/projects/prometheus/alerts/notify_service.rb
@@ -17,10 +17,10 @@ module Projects
SUPPORTED_VERSION = '4'
- def execute(token, _integration = nil)
+ def execute(token, integration = nil)
return bad_request unless valid_payload_size?
return unprocessable_entity unless self.class.processable?(params)
- return unauthorized unless valid_alert_manager_token?(token)
+ return unauthorized unless valid_alert_manager_token?(token, integration)
process_prometheus_alerts
@@ -53,9 +53,9 @@ module Projects
params['alerts']
end
- def valid_alert_manager_token?(token)
+ def valid_alert_manager_token?(token, integration)
valid_for_manual?(token) ||
- valid_for_alerts_endpoint?(token) ||
+ valid_for_alerts_endpoint?(token, integration) ||
valid_for_managed?(token)
end
@@ -70,11 +70,10 @@ module Projects
end
end
- def valid_for_alerts_endpoint?(token)
- return false unless project.alerts_service_activated?
+ def valid_for_alerts_endpoint?(token, integration)
+ return false unless integration&.active?
- # Here we are enforcing the existence of the token
- compare_token(token, project.alerts_service.token)
+ compare_token(token, integration.token)
end
def valid_for_managed?(token)