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:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_create_form.vue4
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_form_fields.vue210
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_update_form.vue137
-rw-r--r--app/assets/javascripts/ci/runner/group_new_runner/group_new_runner_app.vue2
-rw-r--r--app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue2
-rw-r--r--app/assets/javascripts/contextual_sidebar.js22
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_agent_info.vue52
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_overview.vue23
-rw-r--r--app/assets/javascripts/environments/components/new_environment_item.vue41
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql19
-rw-r--r--app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql15
-rw-r--r--app/assets/javascripts/layout_nav.js32
-rw-r--r--app/assets/javascripts/pages/groups/group_members/index.js4
-rw-r--r--app/assets/javascripts/pages/groups/shared/group_details.js2
-rw-r--r--app/assets/javascripts/pages/projects/project_members/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/work_items/index.js2
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js4
-rw-r--r--app/assets/stylesheets/notify_enhanced.scss4
-rw-r--r--app/helpers/application_settings_helper.rb4
-rw-r--r--app/helpers/form_helper.rb2
-rw-r--r--app/models/analytics/cycle_analytics/value_stream.rb1
-rw-r--r--app/models/packages/nuget/metadatum.rb12
-rw-r--r--app/policies/project_policy.rb10
-rw-r--r--app/presenters/packages/nuget/presenter_helpers.rb10
-rw-r--r--app/presenters/packages/nuget/search_results_presenter.rb4
-rw-r--r--app/services/ci/runners/assign_runner_service.rb4
-rw-r--r--app/services/issues/base_service.rb4
-rw-r--r--app/services/issues/close_service.rb5
-rw-r--r--app/services/issues/reopen_service.rb6
-rw-r--r--app/services/packages/nuget/metadata_extraction_service.rb26
-rw-r--r--app/services/packages/nuget/sync_metadatum_service.rb47
-rw-r--r--app/services/packages/nuget/update_package_from_metadata_service.rb36
-rw-r--r--app/views/projects/mirrors/_branch_filter.html.haml4
-rw-r--r--app/views/projects/mirrors/_mirror_repos_push.html.haml4
-rw-r--r--app/views/projects/network/show.html.haml2
-rw-r--r--app/views/shared/_new_merge_request_checkbox.html.haml2
-rw-r--r--app/views/shared/issuable/form/_metadata.html.haml4
-rw-r--r--app/workers/new_issue_worker.rb10
40 files changed, 366 insertions, 416 deletions
diff --git a/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue b/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
index 4ec41381045..f0a41a5949e 100644
--- a/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
+++ b/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
@@ -60,7 +60,7 @@ export default {
<hr aria-hidden="true" />
- <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ <h2 class="gl-font-size-h2 gl-my-5">
{{ s__('Runners|Platform') }}
</h2>
<runner-platforms-radio-group v-model="platform" />
diff --git a/app/assets/javascripts/ci/runner/components/runner_create_form.vue b/app/assets/javascripts/ci/runner/components/runner_create_form.vue
index d6db15a1996..040e42fa938 100644
--- a/app/assets/javascripts/ci/runner/components/runner_create_form.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_create_form.vue
@@ -83,13 +83,13 @@ export default {
if (errors?.length) {
this.$emit('error', new Error(errors.join(' ')));
+ this.saving = false;
} else {
this.onSuccess(runner);
}
} catch (error) {
captureException({ error, component: this.$options.name });
this.$emit('error', error);
- } finally {
this.saving = false;
}
},
@@ -103,7 +103,7 @@ export default {
<gl-form @submit.prevent="onSubmit">
<runner-form-fields v-model="runner" />
- <div class="gl-display-flex">
+ <div class="gl-display-flex gl-mt-6">
<gl-button type="submit" variant="confirm" class="js-no-auto-disable" :loading="saving">
{{ s__('Runners|Create runner') }}
</gl-button>
diff --git a/app/assets/javascripts/ci/runner/components/runner_form_fields.vue b/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
index 880d217e344..180c41e7ed6 100644
--- a/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
@@ -1,5 +1,14 @@
<script>
-import { GlFormGroup, GlFormCheckbox, GlFormInput, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import { isEqual } from 'lodash';
+import {
+ GlFormGroup,
+ GlFormCheckbox,
+ GlFormInput,
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ GlSkeletonLoader,
+} from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
@@ -12,6 +21,7 @@ export default {
GlIcon,
GlLink,
GlSprintf,
+ GlSkeletonLoader,
RunnerMaintenanceNoteField: () =>
import('ee_component/ci/runner/components/runner_maintenance_note_field.vue'),
},
@@ -21,12 +31,15 @@ export default {
default: null,
required: false,
},
+ loading: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
},
data() {
return {
- model: {
- ...this.value,
- },
+ model: null,
};
},
computed: {
@@ -35,6 +48,15 @@ export default {
},
},
watch: {
+ value: {
+ handler(newVal, oldVal) {
+ // update only when values change, avoids infinite loop
+ if (!isEqual(newVal, oldVal)) {
+ this.model = { ...newVal };
+ }
+ },
+ immediate: true,
+ },
model: {
handler() {
this.$emit('input', this.model);
@@ -51,107 +73,115 @@ export default {
</script>
<template>
<div>
- <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ <h2 class="gl-font-size-h2 gl-my-5">
{{ s__('Runners|Details') }}
{{ __('(optional)') }}
</h2>
- <gl-form-group :label="s__('Runners|Runner description')" label-for="runner-description">
- <gl-form-input id="runner-description" v-model="model.description" name="description" />
- </gl-form-group>
- <runner-maintenance-note-field v-model="model.maintenanceNote" class="gl-mt-5" />
+ <gl-skeleton-loader v-if="loading" :lines="9" />
+ <template v-else-if="model">
+ <gl-form-group :label="s__('Runners|Runner description')" label-for="runner-description">
+ <gl-form-input id="runner-description" v-model="model.description" name="description" />
+ </gl-form-group>
+ <runner-maintenance-note-field v-model="model.maintenanceNote" class="gl-mt-5" />
+ </template>
<hr aria-hidden="true" />
- <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ <h2 class="gl-font-size-h2 gl-my-5">
{{ s__('Runners|Configuration') }}
{{ __('(optional)') }}
</h2>
- <div class="gl-mb-5">
- <gl-form-checkbox v-model="model.paused" name="paused">
- {{ __('Paused') }}
- <template #help>
- {{ s__('Runners|Stop the runner from accepting new jobs.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox
- v-model="model.accessLevel"
- name="protected"
- :value="$options.ACCESS_LEVEL_REF_PROTECTED"
- :unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
- >
- {{ __('Protected') }}
- <template #help>
- {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox v-model="model.runUntagged" name="run-untagged">
- {{ __('Run untagged jobs') }}
- <template #help>
- {{ s__('Runners|Use the runner for jobs without tags in addition to tagged jobs.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox v-if="canBeLockedToProject" v-model="model.locked" name="locked">
- {{ __('Lock to current projects') }} <gl-icon name="lock" />
- <template #help>
- {{
- s__(
- 'Runners|Use the runner for the currently assigned projects only. Only administrators can change the assigned projects.',
- )
- }}
- </template>
- </gl-form-checkbox>
- </div>
+ <gl-skeleton-loader v-if="loading" :lines="27" />
+ <template v-else-if="model">
+ <div class="gl-mb-5">
+ <gl-form-checkbox v-model="model.paused" name="paused">
+ {{ __('Paused') }}
+ <template #help>
+ {{ s__('Runners|Stop the runner from accepting new jobs.') }}
+ </template>
+ </gl-form-checkbox>
- <gl-form-group :label="__('Tags')" label-for="runner-tags">
- <template #description>
- <gl-sprintf
- :message="
- s__('Runners|Multiple tags must be separated by a comma. For example, %{example}.')
- "
+ <gl-form-checkbox
+ v-model="model.accessLevel"
+ name="protected"
+ :value="$options.ACCESS_LEVEL_REF_PROTECTED"
+ :unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
>
- <template #example>
- <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
- <code>macos, shared</code>
+ {{ __('Protected') }}
+ <template #help>
+ {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
</template>
- </gl-sprintf>
- </template>
- <template #label-description>
- <gl-sprintf
- :message="
- s__(
- 'Runners|Add tags for the types of jobs the runner processes to ensure that the runner only runs jobs that you intend it to. %{helpLinkStart}Learn more.%{helpLinkEnd}',
- )
- "
- >
- <template #helpLink="{ content }">
- <gl-link :href="$options.HELP_LABELS_PAGE_PATH" target="_blank">{{ content }}</gl-link>
+ </gl-form-checkbox>
+
+ <gl-form-checkbox v-model="model.runUntagged" name="run-untagged">
+ {{ __('Run untagged jobs') }}
+ <template #help>
+ {{ s__('Runners|Use the runner for jobs without tags in addition to tagged jobs.') }}
</template>
- </gl-sprintf>
- </template>
- <gl-form-input id="runner-tags" v-model="model.tagList" name="tags" />
- </gl-form-group>
+ </gl-form-checkbox>
- <gl-form-group
- :label="__('Maximum job timeout')"
- :label-description="
- s__(
- 'Runners|Maximum amount of time the runner can run before it terminates. If a project has a shorter job timeout period, the job timeout period of the instance runner is used instead.',
- )
- "
- label-for="runner-max-timeout"
- :description="s__('Runners|Enter the number of seconds.')"
- >
- <gl-form-input
- id="runner-max-timeout"
- v-model.number="model.maximumTimeout"
- name="max-timeout"
- type="number"
- />
- </gl-form-group>
+ <gl-form-checkbox v-if="canBeLockedToProject" v-model="model.locked" name="locked">
+ {{ __('Lock to current projects') }} <gl-icon name="lock" />
+ <template #help>
+ {{
+ s__(
+ 'Runners|Use the runner for the currently assigned projects only. Only administrators can change the assigned projects.',
+ )
+ }}
+ </template>
+ </gl-form-checkbox>
+ </div>
+
+ <gl-form-group :label="__('Tags')" label-for="runner-tags">
+ <template #description>
+ <gl-sprintf
+ :message="
+ s__('Runners|Multiple tags must be separated by a comma. For example, %{example}.')
+ "
+ >
+ <template #example>
+ <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
+ <code>macos, shared</code>
+ </template>
+ </gl-sprintf>
+ </template>
+ <template #label-description>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|Add tags for the types of jobs the runner processes to ensure that the runner only runs jobs that you intend it to. %{helpLinkStart}Learn more.%{helpLinkEnd}',
+ )
+ "
+ >
+ <template #helpLink="{ content }">
+ <gl-link :href="$options.HELP_LABELS_PAGE_PATH" target="_blank">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+ <gl-form-input id="runner-tags" v-model="model.tagList" name="tags" />
+ </gl-form-group>
+
+ <gl-form-group
+ :label="__('Maximum job timeout')"
+ :label-description="
+ s__(
+ 'Runners|Maximum amount of time the runner can run before it terminates. If a project has a shorter job timeout period, the job timeout period of the instance runner is used instead.',
+ )
+ "
+ label-for="runner-max-timeout"
+ :description="s__('Runners|Enter the number of seconds.')"
+ >
+ <gl-form-input
+ id="runner-max-timeout"
+ v-model.number="model.maximumTimeout"
+ name="max-timeout"
+ type="number"
+ />
+ </gl-form-group>
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/ci/runner/components/runner_update_form.vue b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
index aebddc70646..bc044b609a3 100644
--- a/app/assets/javascripts/ci/runner/components/runner_update_form.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
@@ -1,23 +1,16 @@
<script>
-import {
- GlButton,
- GlIcon,
- GlForm,
- GlFormCheckbox,
- GlFormGroup,
- GlFormInputGroup,
- GlSkeletonLoader,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import {
- modelToUpdateMutationVariables,
- runnerToModel,
-} from 'ee_else_ce/ci/runner/runner_update_form_utils';
+import { GlButton, GlForm } from '@gitlab/ui';
+import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { visitUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import { captureException } from '~/ci/runner/sentry_utils';
-import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
+
+import {
+ modelToUpdateMutationVariables,
+ runnerToModel,
+} from 'ee_else_ce/ci/runner/runner_update_form_utils';
+import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED } from '../constants';
import runnerUpdateMutation from '../graphql/edit/runner_update.mutation.graphql';
import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage';
@@ -25,20 +18,11 @@ export default {
name: 'RunnerUpdateForm',
components: {
GlButton,
- GlIcon,
GlForm,
- GlFormCheckbox,
- GlFormGroup,
- GlFormInputGroup,
- GlSkeletonLoader,
- RunnerMaintenanceNoteField: () =>
- import('ee_component/ci/runner/components/runner_maintenance_note_field.vue'),
+ RunnerFormFields,
RunnerUpdateCostFactorFields: () =>
import('ee_component/ci/runner/components/runner_update_cost_factor_fields.vue'),
},
- directives: {
- GlTooltip: GlTooltipDirective,
- },
props: {
runner: {
type: Object,
@@ -59,19 +43,12 @@ export default {
data() {
return {
saving: false,
- model: runnerToModel(this.runner),
+ model: null,
};
},
- computed: {
- canBeLockedToProject() {
- return this.runner?.runnerType === PROJECT_TYPE;
- },
- },
watch: {
- runner(newVal, oldVal) {
- if (oldVal === null) {
- this.model = runnerToModel(newVal);
- }
+ runner(val) {
+ this.model = runnerToModel(val);
},
},
methods: {
@@ -114,94 +91,8 @@ export default {
</script>
<template>
<gl-form @submit.prevent="onSubmit">
- <h4 class="gl-font-lg gl-my-5">{{ s__('Runners|Details') }}</h4>
-
- <gl-skeleton-loader v-if="loading" />
-
- <template v-else>
- <gl-form-group :label="__('Description')" data-testid="runner-field-description">
- <gl-form-input-group v-model="model.description" />
- </gl-form-group>
- <runner-maintenance-note-field v-model="model.maintenanceNote" />
- </template>
-
- <hr />
-
- <h4 class="gl-font-lg gl-my-5">{{ s__('Runners|Configuration') }}</h4>
-
- <template v-if="loading">
- <gl-skeleton-loader v-for="i in 3" :key="i" />
- </template>
- <template v-else>
- <div class="gl-mb-5">
- <gl-form-checkbox v-model="model.paused" data-testid="runner-field-paused">
- {{ __('Paused') }}
- <template #help>
- {{ s__('Runners|Stop the runner from accepting new jobs.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox
- v-model="model.accessLevel"
- data-testid="runner-field-protected"
- :value="$options.ACCESS_LEVEL_REF_PROTECTED"
- :unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
- >
- {{ __('Protected') }}
- <template #help>
- {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox v-model="model.runUntagged" data-testid="runner-field-run-untagged">
- {{ __('Run untagged jobs') }}
- <template #help>
- {{ s__('Runners|Use the runner for jobs without tags, in addition to tagged jobs.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox
- v-if="canBeLockedToProject"
- v-model="model.locked"
- data-testid="runner-field-locked"
- >
- {{ __('Lock to current projects') }} <gl-icon name="lock" />
- <template #help>
- {{
- s__(
- 'Runners|Use the runner for the currently assigned projects only. Only administrators can change the assigned projects.',
- )
- }}
- </template>
- </gl-form-checkbox>
- </div>
-
- <gl-form-group
- data-testid="runner-field-max-timeout"
- :label="__('Maximum job timeout')"
- :description="
- s__(
- 'Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project.',
- )
- "
- >
- <gl-form-input-group v-model.number="model.maximumTimeout" type="number" />
- </gl-form-group>
-
- <gl-form-group
- data-testid="runner-field-tags"
- :label="__('Tags')"
- :description="
- __(
- 'You can set up jobs to only use runners with specific tags. Separate tags with commas.',
- )
- "
- >
- <gl-form-input-group v-model="model.tagList" />
- </gl-form-group>
-
- <runner-update-cost-factor-fields v-model="model" />
- </template>
+ <runner-form-fields v-model="model" :loading="loading" />
+ <runner-update-cost-factor-fields v-model="model" />
<div class="gl-mt-6">
<gl-button
diff --git a/app/assets/javascripts/ci/runner/group_new_runner/group_new_runner_app.vue b/app/assets/javascripts/ci/runner/group_new_runner/group_new_runner_app.vue
index 5965330c4eb..2e1706ddae9 100644
--- a/app/assets/javascripts/ci/runner/group_new_runner/group_new_runner_app.vue
+++ b/app/assets/javascripts/ci/runner/group_new_runner/group_new_runner_app.vue
@@ -66,7 +66,7 @@ export default {
<hr aria-hidden="true" />
- <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ <h2 class="gl-font-size-h2 gl-my-5">
{{ s__('Runners|Platform') }}
</h2>
<runner-platforms-radio-group v-model="platform" />
diff --git a/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue b/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue
index 715b0c28148..51f5a9ce8d9 100644
--- a/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue
+++ b/app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue
@@ -66,7 +66,7 @@ export default {
<hr aria-hidden="true" />
- <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ <h2 class="gl-font-size-h2 gl-my-5">
{{ s__('Runners|Platform') }}
</h2>
<runner-platforms-radio-group v-model="platform" />
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js
index ea444b5c146..ab5f01227fb 100644
--- a/app/assets/javascripts/contextual_sidebar.js
+++ b/app/assets/javascripts/contextual_sidebar.js
@@ -108,27 +108,5 @@ export default class ContextualSidebar {
const collapse = parseBoolean(getCookie('sidebar_collapsed'));
this.toggleCollapsedSidebar(collapse, true);
}
-
- const modalEl = document.querySelector('.js-invite-members-modal');
- if (modalEl) {
- import(
- /* webpackChunkName: 'initInviteMembersModal' */ '~/invite_members/init_invite_members_modal'
- )
- .then(({ default: initInviteMembersModal }) => {
- initInviteMembersModal();
- })
- .catch(() => {});
-
- const inviteTriggers = document.querySelectorAll('.js-invite-members-trigger');
- if (inviteTriggers) {
- import(
- /* webpackChunkName: 'initInviteMembersTrigger' */ '~/invite_members/init_invite_members_trigger'
- )
- .then(({ default: initInviteMembersTrigger }) => {
- initInviteMembersTrigger();
- })
- .catch(() => {});
- }
- }
}
}
diff --git a/app/assets/javascripts/environments/components/kubernetes_agent_info.vue b/app/assets/javascripts/environments/components/kubernetes_agent_info.vue
index 7660912f93a..03bde8d64ac 100644
--- a/app/assets/javascripts/environments/components/kubernetes_agent_info.vue
+++ b/app/assets/javascripts/environments/components/kubernetes_agent_info.vue
@@ -1,68 +1,37 @@
<script>
-import { GlIcon, GlLink, GlSprintf, GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getAgentLastContact, getAgentStatus } from '~/clusters_list/clusters_util';
import { AGENT_STATUSES } from '~/clusters_list/constants';
import { s__ } from '~/locale';
-import getK8sClusterAgentQuery from '../graphql/queries/k8s_cluster_agent.query.graphql';
export default {
components: {
GlIcon,
GlLink,
GlSprintf,
- GlLoadingIcon,
TimeAgoTooltip,
- GlAlert,
},
props: {
- agentName: {
- required: true,
- type: String,
- },
- agentId: {
- required: true,
- type: String,
- },
- agentProjectPath: {
- required: true,
- type: String,
- },
- },
- apollo: {
clusterAgent: {
- query: getK8sClusterAgentQuery,
- variables() {
- return {
- agentName: this.agentName,
- projectPath: this.agentProjectPath,
- };
- },
- update: (data) => data?.project?.clusterAgent,
- error() {
- this.clusterAgent = null;
- },
+ required: true,
+ type: Object,
},
},
- data() {
- return {
- clusterAgent: null,
- };
- },
computed: {
- isLoading() {
- return this.$apollo.queries.clusterAgent.loading;
- },
agentLastContact() {
return getAgentLastContact(this.clusterAgent.tokens.nodes);
},
agentStatus() {
return getAgentStatus(this.agentLastContact);
},
+ agentId() {
+ return getIdFromGraphQLId(this.clusterAgent.id);
+ },
},
methods: {},
i18n: {
- loadingError: s__('ClusterAgents|An error occurred while loading your agent'),
agentId: s__('ClusterAgents|Agent ID #%{agentId}'),
neverConnectedText: s__('ClusterAgents|Never'),
},
@@ -70,8 +39,7 @@ export default {
};
</script>
<template>
- <gl-loading-icon v-if="isLoading" inline />
- <div v-else-if="clusterAgent" class="gl-text-gray-900">
+ <div class="gl-text-gray-900">
<gl-icon name="kubernetes-agent" class="gl-text-gray-500" />
<gl-link :href="clusterAgent.webPath" class="gl-mr-3">
<gl-sprintf :message="$options.i18n.agentId"
@@ -92,8 +60,4 @@ export default {
<span v-else>{{ $options.i18n.neverConnectedText }}</span>
</span>
</div>
-
- <gl-alert v-else variant="danger" :dismissible="false">
- {{ $options.i18n.loadingError }}
- </gl-alert>
</template>
diff --git a/app/assets/javascripts/environments/components/kubernetes_overview.vue b/app/assets/javascripts/environments/components/kubernetes_overview.vue
index 1f15c4daa2f..a849adfc755 100644
--- a/app/assets/javascripts/environments/components/kubernetes_overview.vue
+++ b/app/assets/javascripts/environments/components/kubernetes_overview.vue
@@ -2,7 +2,7 @@
import { GlCollapse, GlButton, GlAlert } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import csrf from '~/lib/utils/csrf';
-import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import KubernetesAgentInfo from './kubernetes_agent_info.vue';
import KubernetesPods from './kubernetes_pods.vue';
import KubernetesTabs from './kubernetes_tabs.vue';
@@ -18,17 +18,9 @@ export default {
},
inject: ['kasTunnelUrl'],
props: {
- agentName: {
+ clusterAgent: {
required: true,
- type: String,
- },
- agentId: {
- required: true,
- type: String,
- },
- agentProjectPath: {
- required: true,
- type: String,
+ type: Object,
},
namespace: {
required: false,
@@ -50,8 +42,7 @@ export default {
return this.isVisible ? this.$options.i18n.collapse : this.$options.i18n.expand;
},
gitlabAgentId() {
- const id = isGid(this.agentId) ? getIdFromGraphQLId(this.agentId) : this.agentId;
- return id.toString();
+ return getIdFromGraphQLId(this.clusterAgent.id).toString();
},
k8sAccessConfiguration() {
return {
@@ -91,11 +82,7 @@ export default {
</p>
<gl-collapse :visible="isVisible" class="gl-md-pl-7 gl-md-pr-5 gl-mt-4">
<template v-if="isVisible">
- <kubernetes-agent-info
- :agent-name="agentName"
- :agent-id="agentId"
- :agent-project-path="agentProjectPath"
- class="gl-mb-5" />
+ <kubernetes-agent-info :cluster-agent="clusterAgent" class="gl-mb-5" />
<gl-alert v-if="error" variant="danger" :dismissible="false" class="gl-mb-5">
{{ error }}
diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue
index 9ad31688329..72323c0e43e 100644
--- a/app/assets/javascripts/environments/components/new_environment_item.vue
+++ b/app/assets/javascripts/environments/components/new_environment_item.vue
@@ -13,6 +13,7 @@ import { truncate } from '~/lib/utils/text_utility';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import isLastDeployment from '../graphql/queries/is_last_deployment.query.graphql';
+import getEnvironmentClusterAgent from '../graphql/queries/environment_cluster_agent.query.graphql';
import ExternalUrl from './environment_external_url.vue';
import Actions from './environment_actions.vue';
import StopComponent from './environment_stop.vue';
@@ -51,7 +52,7 @@ export default {
GlTooltip,
},
mixins: [glFeatureFlagsMixin()],
- inject: ['helpPagePath'],
+ inject: ['helpPagePath', 'projectPath'],
props: {
environment: {
required: true,
@@ -81,7 +82,7 @@ export default {
tierTooltip: s__('Environment|Deployment tier'),
},
data() {
- return { visible: false };
+ return { visible: false, clusterAgent: null };
},
computed: {
icon() {
@@ -163,23 +164,33 @@ export default {
rolloutStatus() {
return this.environment?.rolloutStatus;
},
- agent() {
- return this.environment?.agent || {};
- },
isKubernetesOverviewAvailable() {
return this.glFeatures?.kasUserAccessProject;
},
- hasRequiredAgentData() {
- const { project, id, name } = this.agent || {};
- return project && id && name;
- },
showKubernetesOverview() {
- return this.isKubernetesOverviewAvailable && this.hasRequiredAgentData;
+ return Boolean(this.isKubernetesOverviewAvailable && this.clusterAgent);
},
},
methods: {
- toggleCollapse() {
+ toggleEnvironmentCollapse() {
this.visible = !this.visible;
+
+ if (this.visible) {
+ this.getClusterAgent();
+ }
+ },
+ getClusterAgent() {
+ if (!this.isKubernetesOverviewAvailable || this.clusterAgent) return;
+
+ this.$apollo.addSmartQuery('environmentClusterAgent', {
+ variables() {
+ return { environmentName: this.environment.name, projectFullPath: this.projectPath };
+ },
+ query: getEnvironmentClusterAgent,
+ update(data) {
+ this.clusterAgent = data?.project?.environment?.clusterAgent;
+ },
+ });
},
},
deploymentClasses: [
@@ -222,7 +233,7 @@ export default {
:aria-label="label"
size="small"
category="secondary"
- @click="toggleCollapse"
+ @click="toggleEnvironmentCollapse"
/>
<gl-link
v-gl-tooltip
@@ -359,10 +370,8 @@ export default {
</div>
<div v-if="showKubernetesOverview" :class="$options.kubernetesOverviewClasses">
<kubernetes-overview
- :agent-project-path="agent.project"
- :agent-name="agent.name"
- :agent-id="agent.id"
- :namespace="agent.kubernetesNamespace"
+ :cluster-agent="clusterAgent"
+ :namespace="environment.kubernetesNamespace"
/>
</div>
<div v-if="rolloutStatus" :class="$options.deployBoardClasses">
diff --git a/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql
new file mode 100644
index 00000000000..760f1fba897
--- /dev/null
+++ b/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql
@@ -0,0 +1,19 @@
+query getEnvironmentClusterAgent($projectFullPath: ID!, $environmentName: String) {
+ project(fullPath: $projectFullPath) {
+ id
+ environment(name: $environmentName) {
+ id
+ clusterAgent {
+ id
+ name
+ webPath
+ tokens {
+ nodes {
+ id
+ lastUsedAt
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql b/app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql
deleted file mode 100644
index bd45d2dba2f..00000000000
--- a/app/assets/javascripts/environments/graphql/queries/k8s_cluster_agent.query.graphql
+++ /dev/null
@@ -1,15 +0,0 @@
-query getK8sClusterAgentQuery($projectPath: ID!, $agentName: String!) {
- project(fullPath: $projectPath) {
- id
- clusterAgent(name: $agentName) {
- id
- webPath
- tokens {
- nodes {
- id
- lastUsedAt
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/layout_nav.js b/app/assets/javascripts/layout_nav.js
index 63a1ba89fff..42682d9b79f 100644
--- a/app/assets/javascripts/layout_nav.js
+++ b/app/assets/javascripts/layout_nav.js
@@ -64,9 +64,31 @@ export function initScrollingTabs() {
});
}
-function initDeferred() {
- initScrollingTabs();
+function initInviteMembers() {
+ const modalEl = document.querySelector('.js-invite-members-modal');
+ if (!modalEl) return;
+
+ import(
+ /* webpackChunkName: 'initInviteMembersModal' */ '~/invite_members/init_invite_members_modal'
+ )
+ .then(({ default: initInviteMembersModal }) => {
+ initInviteMembersModal();
+ })
+ .catch(() => {});
+ const inviteTriggers = document.querySelectorAll('.js-invite-members-trigger');
+ if (!inviteTriggers) return;
+
+ import(
+ /* webpackChunkName: 'initInviteMembersTrigger' */ '~/invite_members/init_invite_members_trigger'
+ )
+ .then(({ default: initInviteMembersTrigger }) => {
+ initInviteMembersTrigger();
+ })
+ .catch(() => {});
+}
+
+function initWhatsNewComponent() {
const appEl = document.getElementById('whats-new-app');
if (!appEl) return;
@@ -84,6 +106,12 @@ function initDeferred() {
});
}
+function initDeferred() {
+ initScrollingTabs();
+ initWhatsNewComponent();
+ initInviteMembers();
+}
+
export default function initLayoutNav() {
if (!gon.use_new_navigation) {
const contextualSidebar = new ContextualSidebar();
diff --git a/app/assets/javascripts/pages/groups/group_members/index.js b/app/assets/javascripts/pages/groups/group_members/index.js
index 2e71eced66f..df6ca8eab96 100644
--- a/app/assets/javascripts/pages/groups/group_members/index.js
+++ b/app/assets/javascripts/pages/groups/group_members/index.js
@@ -1,8 +1,6 @@
import { groupMemberRequestFormatter } from '~/groups/members/utils';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
import initInviteGroupsModal from '~/invite_members/init_invite_groups_modal';
-import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
-import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { s__ } from '~/locale';
import { initMembersApp } from '~/members';
import { MEMBER_TYPES, EE_APP_OPTIONS } from 'ee_else_ce/members/constants';
@@ -60,7 +58,5 @@ const APP_OPTIONS = {
initMembersApp(document.querySelector('.js-group-members-list-app'), APP_OPTIONS);
-initInviteMembersModal();
initInviteGroupsModal();
-initInviteMembersTrigger();
initInviteGroupTrigger();
diff --git a/app/assets/javascripts/pages/groups/shared/group_details.js b/app/assets/javascripts/pages/groups/shared/group_details.js
index dba65c7e791..5d9eafe5672 100644
--- a/app/assets/javascripts/pages/groups/shared/group_details.js
+++ b/app/assets/javascripts/pages/groups/shared/group_details.js
@@ -1,6 +1,5 @@
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initInviteMembersBanner from '~/groups/init_invite_members_banner';
-import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initNotificationsDropdown from '~/notifications';
import ProjectsList from '~/projects_list';
@@ -12,5 +11,4 @@ export default function initGroupDetails() {
new ProjectsList(); // eslint-disable-line no-new
initInviteMembersBanner();
- initInviteMembersModal();
}
diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js
index 79a4ed0f9c3..1e9111a3cc6 100644
--- a/app/assets/javascripts/pages/projects/project_members/index.js
+++ b/app/assets/javascripts/pages/projects/project_members/index.js
@@ -1,9 +1,7 @@
import initImportProjectMembersTrigger from '~/invite_members/init_import_project_members_trigger';
import initImportProjectMembersModal from '~/invite_members/init_import_project_members_modal';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
-import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteGroupsModal from '~/invite_members/init_invite_groups_modal';
-import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { s__ } from '~/locale';
import { initMembersApp } from '~/members';
import { MEMBER_TYPES } from '~/members/constants';
@@ -11,9 +9,7 @@ import { groupLinkRequestFormatter } from '~/members/utils';
import { projectMemberRequestFormatter } from '~/projects/members/utils';
initImportProjectMembersModal();
-initInviteMembersModal();
initInviteGroupsModal();
-initInviteMembersTrigger();
initInviteGroupTrigger();
initImportProjectMembersTrigger();
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index 33d4090011f..e17f5255c54 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -1,7 +1,5 @@
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
-import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
-import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import initClustersDeprecationAlert from '~/projects/clusters_deprecation_alert';
import leaveByUrl from '~/namespaces/leave_by_url';
import initVueNotificationsDropdown from '~/notifications';
@@ -42,8 +40,6 @@ initVueNotificationsDropdown();
new ShortcutsNavigation(); // eslint-disable-line no-new
initUploadFileTrigger();
-initInviteMembersModal();
-initInviteMembersTrigger();
initClustersDeprecationAlert();
initTerraformNotification();
diff --git a/app/assets/javascripts/pages/projects/work_items/index.js b/app/assets/javascripts/pages/projects/work_items/index.js
index 6eef2352e2c..11c257611f0 100644
--- a/app/assets/javascripts/pages/projects/work_items/index.js
+++ b/app/assets/javascripts/pages/projects/work_items/index.js
@@ -1,5 +1,3 @@
import { initWorkItemsRoot } from '~/work_items/index';
-import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
initWorkItemsRoot();
-initInviteMembersModal();
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 74843bcc006..67e76b575e0 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -2,8 +2,6 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { TYPENAME_ISSUE, TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
-import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST, WORKSPACE_PROJECT } from '~/issues/constants';
import { gqlClient } from '~/issues/list/graphql';
import {
@@ -805,8 +803,6 @@ const isAssigneesWidgetShown =
(isInIssuePage() || isInDesignPage() || isInMRPage()) && gon.features.issueAssigneesWidget;
export function mountSidebar(mediator, store) {
- initInviteMembersModal();
- initInviteMembersTrigger();
mountSidebarTodoWidget();
if (isAssigneesWidgetShown) {
mountSidebarAssigneesWidget();
diff --git a/app/assets/stylesheets/notify_enhanced.scss b/app/assets/stylesheets/notify_enhanced.scss
index b331d997a97..a3e02dabe0e 100644
--- a/app/assets/stylesheets/notify_enhanced.scss
+++ b/app/assets/stylesheets/notify_enhanced.scss
@@ -32,6 +32,10 @@ body {
font-size: inherit;
}
+pre {
+ font-size: 14px;
+}
+
.gl-mb-5 {
@include gl-mb-5;
}
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 1c988b9767f..bf8dea15c58 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -99,11 +99,11 @@ module ApplicationSettingsHelper
checked_value: level,
unchecked_value: nil
) do |c|
- c.label do
+ c.with_label do
visibility_level_icon(level) + content_tag(:span, label, { class: 'gl-ml-2' })
end
- c.help_text do
+ c.with_help_text do
restricted_visibility_levels_help_text.fetch(level)
end
end
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
index ed8cca20241..3d0b899e867 100644
--- a/app/helpers/form_helper.rb
+++ b/app/helpers/form_helper.rb
@@ -37,7 +37,7 @@ module FormHelper
dismissible: false,
alert_options: { id: 'error_explanation', class: 'gl-mb-5' }
) do |c|
- c.body do
+ c.with_body do
tag.ul(class: 'gl-pl-5 gl-mb-0') do
messages
end
diff --git a/app/models/analytics/cycle_analytics/value_stream.rb b/app/models/analytics/cycle_analytics/value_stream.rb
index 59c68393d74..31e06075bcb 100644
--- a/app/models/analytics/cycle_analytics/value_stream.rb
+++ b/app/models/analytics/cycle_analytics/value_stream.rb
@@ -21,6 +21,7 @@ module Analytics
scope :preload_associated_models, -> {
includes(:namespace, stages: [:namespace, :end_event_label, :start_event_label])
}
+ scope :order_by_name_asc, -> { order(arel_table[:name].lower.asc) }
after_save :ensure_aggregation_record_presence
diff --git a/app/models/packages/nuget/metadatum.rb b/app/models/packages/nuget/metadatum.rb
index 1db8c0eddbf..08276f87568 100644
--- a/app/models/packages/nuget/metadatum.rb
+++ b/app/models/packages/nuget/metadatum.rb
@@ -1,24 +1,22 @@
# frozen_string_literal: true
class Packages::Nuget::Metadatum < ApplicationRecord
+ MAX_AUTHORS_LENGTH = 255
+ MAX_DESCRIPTION_LENGTH = 4000
+
belongs_to :package, -> { where(package_type: :nuget) }, inverse_of: :nuget_metadatum
validates :package, presence: true
validates :license_url, public_url: { allow_blank: true }
validates :project_url, public_url: { allow_blank: true }
validates :icon_url, public_url: { allow_blank: true }
+ validates :authors, presence: true, length: { maximum: MAX_AUTHORS_LENGTH }
+ validates :description, presence: true, length: { maximum: MAX_DESCRIPTION_LENGTH }
- validate :ensure_at_least_one_field_supplied
validate :ensure_nuget_package_type
private
- def ensure_at_least_one_field_supplied
- return if license_url? || project_url? || icon_url?
-
- errors.add(:base, _('Nuget metadatum must have at least license_url, project_url or icon_url set'))
- end
-
def ensure_nuget_package_type
return if package&.nuget?
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 15f91cae86b..c70dc288710 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -163,6 +163,11 @@ class ProjectPolicy < BasePolicy
condition(:service_desk_enabled) { @subject.service_desk_enabled? }
with_scope :subject
+ condition(:model_experiments_enabled) do
+ Feature.enabled?(:ml_experiment_tracking, @subject) && @subject.feature_available?(:model_experiments, @user)
+ end
+
+ with_scope :subject
condition(:model_registry_enabled) { Feature.enabled?(:model_registry, @subject) }
with_scope :subject
@@ -223,6 +228,7 @@ class ProjectPolicy < BasePolicy
feature_flags
releases
infrastructure
+ model_experiments
]
features.each do |f|
@@ -899,6 +905,10 @@ class ProjectPolicy < BasePolicy
enable :read_model_registry
end
+ rule { model_experiments_enabled }.policy do
+ enable :read_model_experiments
+ end
+
private
def user_is_user?
diff --git a/app/presenters/packages/nuget/presenter_helpers.rb b/app/presenters/packages/nuget/presenter_helpers.rb
index 82ed80d8372..ea8558c54f4 100644
--- a/app/presenters/packages/nuget/presenter_helpers.rb
+++ b/app/presenters/packages/nuget/presenter_helpers.rb
@@ -5,7 +5,6 @@ module Packages
module PresenterHelpers
include ::API::Helpers::RelatedResourcesHelpers
- BLANK_STRING = ''
PACKAGE_DEPENDENCY_GROUP = 'PackageDependencyGroup'
PACKAGE_DEPENDENCY = 'PackageDependency'
@@ -45,14 +44,13 @@ module Packages
def catalog_entry_for(package)
{
json_url: json_url_for(package),
- authors: BLANK_STRING,
dependency_groups: dependency_groups_for(package),
package_name: package.name,
package_version: package.version,
archive_url: archive_url_for(package),
- summary: BLANK_STRING,
tags: tags_for(package),
- metadatum: metadatum_for(package)
+ metadatum: metadatum_for(package),
+ published: package.created_at.iso8601
}
end
@@ -98,8 +96,8 @@ module Packages
metadatum = package.nuget_metadatum
return {} unless metadatum
- metadatum.slice(:project_url, :license_url, :icon_url)
- .compact
+ metadatum.slice(:authors, :description, :project_url, :license_url, :icon_url)
+ .compact
end
def base_path_for(package)
diff --git a/app/presenters/packages/nuget/search_results_presenter.rb b/app/presenters/packages/nuget/search_results_presenter.rb
index 311296d576c..45c2c5170ae 100644
--- a/app/presenters/packages/nuget/search_results_presenter.rb
+++ b/app/presenters/packages/nuget/search_results_presenter.rb
@@ -20,11 +20,9 @@ module Packages
{
type: 'Package',
- authors: '',
name: package_name,
version: latest_version,
versions: build_package_versions(packages),
- summary: '',
total_downloads: 0,
verified: true,
tags: tags_for(latest_package),
@@ -48,7 +46,7 @@ module Packages
def latest_version(packages)
versions = packages.map(&:version).compact
- VersionSorter.sort(versions).last # rubocop: disable Style/RedundantSort
+ VersionSorter.sort(versions).last
end
end
end
diff --git a/app/services/ci/runners/assign_runner_service.rb b/app/services/ci/runners/assign_runner_service.rb
index 290f945cc72..4e7b08bdd7a 100644
--- a/app/services/ci/runners/assign_runner_service.rb
+++ b/app/services/ci/runners/assign_runner_service.rb
@@ -17,6 +17,10 @@ module Ci
return ServiceResponse.error(message: 'user not allowed to assign runner', http_status: :forbidden)
end
+ unless @user.can?(:register_project_runners, @project)
+ return ServiceResponse.error(message: 'user not allowed to add runners to project', http_status: :forbidden)
+ end
+
if @runner.assign_to(@project, @user)
ServiceResponse.success
else
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index efe42fb29d5..f982d66eb08 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -124,6 +124,10 @@ module Issues
def update_project_counter_caches?(issue)
super || issue.confidential_changed?
end
+
+ def log_audit_event(issue, user, event_type, message)
+ # defined in EE
+ end
end
end
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index e45033f2b91..f848a8db12a 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -28,6 +28,11 @@ module Issues
event_service.close_issue(issue, current_user)
create_note(issue, closed_via) if system_note
+ if current_user.project_bot?
+ log_audit_event(issue, current_user, "#{issue.issue_type}_closed_by_project_bot",
+ "Closed #{issue.issue_type.humanize(capitalize: false)} #{issue.title}")
+ end
+
closed_via = _("commit %{commit_id}") % { commit_id: closed_via.id } if closed_via.is_a?(Commit)
notification_service.async.close_issue(issue, current_user, { closed_via: closed_via }) if notifications
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index f4d229ecec7..d71ba4e3414 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -7,6 +7,12 @@ module Issues
if issue.reopen
event_service.reopen_issue(issue, current_user)
+
+ if current_user.project_bot?
+ log_audit_event(issue, current_user, "#{issue.issue_type}_reopened_by_project_bot",
+ "Reopened #{issue.issue_type.humanize(capitalize: false)} #{issue.title}")
+ end
+
create_note(issue, 'reopened')
notification_service.async.reopen_issue(issue, current_user)
perform_incident_management_actions(issue)
diff --git a/app/services/packages/nuget/metadata_extraction_service.rb b/app/services/packages/nuget/metadata_extraction_service.rb
index 02086b2a282..3b92d977c79 100644
--- a/app/services/packages/nuget/metadata_extraction_service.rb
+++ b/app/services/packages/nuget/metadata_extraction_service.rb
@@ -7,18 +7,22 @@ module Packages
ExtractionError = Class.new(StandardError)
+ ROOT_XPATH = '//xmlns:package/xmlns:metadata/xmlns'
+
XPATHS = {
- package_name: '//xmlns:package/xmlns:metadata/xmlns:id',
- package_version: '//xmlns:package/xmlns:metadata/xmlns:version',
- license_url: '//xmlns:package/xmlns:metadata/xmlns:licenseUrl',
- project_url: '//xmlns:package/xmlns:metadata/xmlns:projectUrl',
- icon_url: '//xmlns:package/xmlns:metadata/xmlns:iconUrl'
+ package_name: "#{ROOT_XPATH}:id",
+ package_version: "#{ROOT_XPATH}:version",
+ authors: "#{ROOT_XPATH}:authors",
+ description: "#{ROOT_XPATH}:description",
+ license_url: "#{ROOT_XPATH}:licenseUrl",
+ project_url: "#{ROOT_XPATH}:projectUrl",
+ icon_url: "#{ROOT_XPATH}:iconUrl"
}.freeze
- XPATH_DEPENDENCIES = '//xmlns:package/xmlns:metadata/xmlns:dependencies/xmlns:dependency'
- XPATH_DEPENDENCY_GROUPS = '//xmlns:package/xmlns:metadata/xmlns:dependencies/xmlns:group'
- XPATH_TAGS = '//xmlns:package/xmlns:metadata/xmlns:tags'
- XPATH_PACKAGE_TYPES = '//xmlns:package/xmlns:metadata/xmlns:packageTypes/xmlns:packageType'
+ XPATH_DEPENDENCIES = "#{ROOT_XPATH}:dependencies/xmlns:dependency".freeze
+ XPATH_DEPENDENCY_GROUPS = "#{ROOT_XPATH}:dependencies/xmlns:group".freeze
+ XPATH_TAGS = "#{ROOT_XPATH}:tags".freeze
+ XPATH_PACKAGE_TYPES = "#{ROOT_XPATH}:packageTypes/xmlns:packageType".freeze
MAX_FILE_SIZE = 4.megabytes.freeze
@@ -40,10 +44,6 @@ module Packages
end
end
- def project
- package_file.package.project
- end
-
def valid_package_file?
package_file &&
package_file.package&.nuget? &&
diff --git a/app/services/packages/nuget/sync_metadatum_service.rb b/app/services/packages/nuget/sync_metadatum_service.rb
index ca9cc4d5b78..189b972c156 100644
--- a/app/services/packages/nuget/sync_metadatum_service.rb
+++ b/app/services/packages/nuget/sync_metadatum_service.rb
@@ -15,6 +15,8 @@ module Packages
metadatum.destroy! if metadatum.persisted?
else
metadatum.update!(
+ authors: authors,
+ description: description,
license_url: license_url,
project_url: project_url,
icon_url: icon_url
@@ -24,26 +26,57 @@ module Packages
private
+ attr_reader :package, :metadata
+
def metadatum
- strong_memoize(:metadatum) do
- @package.nuget_metadatum || @package.build_nuget_metadatum
- end
+ package.nuget_metadatum || package.build_nuget_metadatum
end
+ strong_memoize_attr :metadatum
def blank_metadata?
- project_url.blank? && license_url.blank? && icon_url.blank?
+ [authors, description, project_url, license_url, icon_url].all?(&:blank?)
+ end
+
+ def authors
+ truncate_value(:authors, ::Packages::Nuget::Metadatum::MAX_AUTHORS_LENGTH)
end
+ strong_memoize_attr :authors
+
+ def description
+ truncate_value(:description, ::Packages::Nuget::Metadatum::MAX_DESCRIPTION_LENGTH)
+ end
+ strong_memoize_attr :description
def project_url
- @metadata[:project_url]
+ metadata[:project_url]
end
def license_url
- @metadata[:license_url]
+ metadata[:license_url]
end
def icon_url
- @metadata[:icon_url]
+ metadata[:icon_url]
+ end
+
+ def truncate_value(field, max_length)
+ return unless metadata[field]
+
+ if metadata[field].size > max_length
+ log_info("#{field.capitalize} is too long (maximum is #{max_length} characters)", field)
+ end
+
+ metadata[field].truncate(max_length)
+ end
+
+ def log_info(message, field)
+ Gitlab::AppLogger.info(
+ class: self.class.name,
+ message: message,
+ package_id: package.id,
+ project_id: package.project_id,
+ field => metadata[field]
+ )
end
end
end
diff --git a/app/services/packages/nuget/update_package_from_metadata_service.rb b/app/services/packages/nuget/update_package_from_metadata_service.rb
index 5456ad4cad7..7153a9035b8 100644
--- a/app/services/packages/nuget/update_package_from_metadata_service.rb
+++ b/app/services/packages/nuget/update_package_from_metadata_service.rb
@@ -17,7 +17,7 @@ module Packages
end
def execute
- raise InvalidMetadataError, 'package name and/or package version not found in metadata' unless valid_metadata?
+ raise InvalidMetadataError, 'package name, version, authors and/or description not found in metadata' unless valid_metadata?
try_obtain_lease do
@package_file.transaction do
@@ -55,17 +55,19 @@ module Packages
return if symbol_package?
::Packages::Nuget::SyncMetadatumService
- .new(package, metadata.slice(:project_url, :license_url, :icon_url))
+ .new(package, metadata.slice(:authors, :description, :project_url, :license_url, :icon_url))
.execute
+
::Packages::UpdateTagsService
.new(package, package_tags)
.execute
+
rescue StandardError => e
raise InvalidMetadataError, e.message
end
def valid_metadata?
- package_name.present? && package_version.present?
+ [package_name, package_version, package_authors, package_description].all?(&:present?)
end
def link_to_existing_package
@@ -93,15 +95,14 @@ module Packages
end
def existing_package
- strong_memoize(:existing_package) do
- @package_file.project.packages
- .nuget
- .with_name(package_name)
- .with_version(package_version)
- .not_pending_destruction
- .first
- end
+ @package_file.project.packages
+ .nuget
+ .with_name(package_name)
+ .with_version(package_version)
+ .not_pending_destruction
+ .first
end
+ strong_memoize_attr :existing_package
def package_name
metadata[:package_name]
@@ -123,15 +124,22 @@ module Packages
metadata.fetch(:package_types, [])
end
+ def package_authors
+ metadata[:authors]
+ end
+
+ def package_description
+ metadata[:description]
+ end
+
def symbol_package?
package_types.include?(SYMBOL_PACKAGE_IDENTIFIER)
end
def metadata
- strong_memoize(:metadata) do
- ::Packages::Nuget::MetadataExtractionService.new(@package_file.id).execute
- end
+ ::Packages::Nuget::MetadataExtractionService.new(@package_file.id).execute
end
+ strong_memoize_attr :metadata
def package_filename
"#{package_name.downcase}.#{package_version.downcase}.#{symbol_package? ? 'snupkg' : 'nupkg'}"
diff --git a/app/views/projects/mirrors/_branch_filter.html.haml b/app/views/projects/mirrors/_branch_filter.html.haml
index 49b0f8c39c8..7d90906bfe8 100644
--- a/app/views/projects/mirrors/_branch_filter.html.haml
+++ b/app/views/projects/mirrors/_branch_filter.html.haml
@@ -2,8 +2,8 @@
= render Pajamas::CheckboxTagComponent.new(name: :only_protected_branches,
checkbox_options: { class: 'js-mirror-protected' },
label_options: { class: 'gl-mb-0!' }) do |c|
- = c.label do
+ - c.with_label do
= _('Mirror only protected branches')
- = c.help_text do
+ - c.with_help_text do
= _('If enabled, only protected branches will be mirrored.')
= link_to _('Learn more.'), help_page_path('user/project/repository/mirror/index.md', anchor: 'mirror-only-protected-branches'), target: '_blank', rel: 'noopener noreferrer'
diff --git a/app/views/projects/mirrors/_mirror_repos_push.html.haml b/app/views/projects/mirrors/_mirror_repos_push.html.haml
index 0947359a753..5b02d650989 100644
--- a/app/views/projects/mirrors/_mirror_repos_push.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos_push.html.haml
@@ -12,8 +12,8 @@
= render Pajamas::CheckboxTagComponent.new(name: :keep_divergent_refs,
checkbox_options: { class: 'js-mirror-keep-divergent-refs' },
label_options: { class: 'gl-mb-0!' }) do |c|
- = c.label do
+ - c.with_label do
= _('Keep divergent refs')
- = c.help_text do
+ - c.with_help_text do
- link_opening_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe
= html_escape(_('Do not force push over diverged refs. After the mirror is created, this setting can only be modified using the API. %{mirroring_docs_link_start}Learn more about this option%{link_closing_tag} and %{mirroring_api_docs_link_start}the API.%{link_closing_tag}')) % { mirroring_docs_link_start: link_opening_tag % {url: help_page_path('user/project/repository/mirror/push.md', anchor: 'keep-divergent-refs')}, mirroring_api_docs_link_start: link_opening_tag % {url: help_page_path('api/remote_mirrors')}, link_closing_tag: '</a>'.html_safe }
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index b31e8919832..c4630eec168 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -10,7 +10,7 @@
= render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, icon: 'search')
.form-group{ class: 'gl-ml-5 gl-mb-n3!' }
= render Pajamas::CheckboxTagComponent.new(name: :filter_ref, checked: @options[:filter_ref]) do |c|
- = c.label do
+ - c.with_label do
= _("Begin with the selected commit")
- if @commit
diff --git a/app/views/shared/_new_merge_request_checkbox.html.haml b/app/views/shared/_new_merge_request_checkbox.html.haml
index 75289e2e6a5..fb3dfba2691 100644
--- a/app/views/shared/_new_merge_request_checkbox.html.haml
+++ b/app/views/shared/_new_merge_request_checkbox.html.haml
@@ -3,7 +3,7 @@
= render Pajamas::CheckboxTagComponent.new(name: 'create_merge_request',
checked: true,
checkbox_options: { class: 'js-create-merge-request', id: "create_merge_request-#{nonce}" }) do |c|
- = c.label do
+ - c.with_label do
- translation_variables = { new_merge_request: "<strong>#{_('new merge request')}</strong>" }
- translation = _('Start a %{new_merge_request} with these changes') % translation_variables
#{ translation.html_safe }
diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml
index 1dc24d205d0..1da0b82b634 100644
--- a/app/views/shared/issuable/form/_metadata.html.haml
+++ b/app/views/shared/issuable/form/_metadata.html.haml
@@ -7,10 +7,10 @@
- if @add_related_issue
.form-group
= render Pajamas::CheckboxTagComponent.new(name: :add_related_issue, value: @add_related_issue.iid, checked: true) do |c|
- = c.label do
+ - c.with_label do
- add_related_issue_link = link_to "\##{@add_related_issue.iid}", issue_path(@add_related_issue), class: ['has-tooltip'], title: @add_related_issue.title
#{_('Relate to %{issuable_type} %{add_related_issue_link}').html_safe % { issuable_type: @add_related_issue.issue_type, add_related_issue_link: add_related_issue_link }}
- = c.help_text do
+ - c.with_help_text do
= _('Adds this %{issuable_type} as related to the %{issuable_type} it was created from') % { issuable_type: @add_related_issue.issue_type }
- if issuable.respond_to?(:confidential) && can?(current_user, :set_confidentiality, issuable)
diff --git a/app/workers/new_issue_worker.rb b/app/workers/new_issue_worker.rb
index 07699a50e36..0e7f11debd2 100644
--- a/app/workers/new_issue_worker.rb
+++ b/app/workers/new_issue_worker.rb
@@ -28,5 +28,15 @@ class NewIssueWorker # rubocop:disable Scalability/IdempotentWorker
Issues::AfterCreateService
.new(container: issuable.project, current_user: user)
.execute(issuable)
+
+ log_audit_event if user.project_bot?
+ end
+
+ private
+
+ def log_audit_event
+ # defined in EE
end
end
+
+NewIssueWorker.prepend_mod