summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-07 15:09:49 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-07 15:09:49 +0000
commit84f9f0cb8137637708a41152347e7754c1e9fb83 (patch)
tree6db9d8931bdb3c5b932b36345373936e2a543126 /app
parent75f809a2ff829574ab91628407993187d55e14a4 (diff)
downloadgitlab-ce-84f9f0cb8137637708a41152347e7754c1e9fb83.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/analytics/shared/components/metric_popover.vue35
-rw-r--r--app/assets/javascripts/analytics/shared/constants.js2
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue2
-rw-r--r--app/assets/javascripts/editor/schema/ci.json16
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/app.vue53
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/constants.js22
-rw-r--r--app/assets/stylesheets/page_bundles/settings.scss2
-rw-r--r--app/models/ci/job_artifact.rb7
-rw-r--r--app/models/environment.rb10
-rw-r--r--app/services/ci/components/fetch_service.rb54
10 files changed, 166 insertions, 37 deletions
diff --git a/app/assets/javascripts/analytics/shared/components/metric_popover.vue b/app/assets/javascripts/analytics/shared/components/metric_popover.vue
index 8d90e7b2392..373a7fac6f7 100644
--- a/app/assets/javascripts/analytics/shared/components/metric_popover.vue
+++ b/app/assets/javascripts/analytics/shared/components/metric_popover.vue
@@ -1,5 +1,6 @@
<script>
import { GlPopover, GlLink, GlIcon } from '@gitlab/ui';
+import { METRIC_POPOVER_LABEL } from '../constants';
export default {
name: 'MetricPopover',
@@ -19,34 +20,34 @@ export default {
},
},
computed: {
- metricLinks() {
- return this.metric.links?.filter((link) => !link.docs_link) || [];
+ metricLink() {
+ return this.metric.links?.find((link) => !link.docs_link);
},
docsLink() {
return this.metric.links?.find((link) => link.docs_link);
},
},
+ metricPopoverLabel: METRIC_POPOVER_LABEL,
};
</script>
<template>
- <gl-popover :target="target" placement="bottom">
+ <gl-popover :target="target" placement="top">
<template #title>
- <span class="gl-display-block gl-text-left" data-testid="metric-label">{{
- metric.label
- }}</span>
+ <div
+ class="gl-display-flex gl-justify-content-space-between gl-text-right gl-py-1 gl-align-items-center"
+ >
+ <span data-testid="metric-label">{{ metric.label }}</span>
+ <gl-link
+ v-if="metricLink"
+ :href="metricLink.url"
+ class="gl-font-sm gl-font-weight-normal"
+ data-testid="metric-link"
+ >{{ $options.metricPopoverLabel }}
+ <gl-icon name="chart" />
+ </gl-link>
+ </div>
</template>
- <div
- v-for="(link, idx) in metricLinks"
- :key="`link-${idx}`"
- class="gl-display-flex gl-justify-content-space-between gl-text-right gl-py-1"
- data-testid="metric-link"
- >
- <span>{{ link.label }}</span>
- <gl-link :href="link.url" class="gl-font-sm">
- {{ link.name }}
- </gl-link>
- </div>
<span v-if="metric.description" data-testid="metric-description">{{ metric.description }}</span>
<gl-link
v-if="docsLink"
diff --git a/app/assets/javascripts/analytics/shared/constants.js b/app/assets/javascripts/analytics/shared/constants.js
index a82633035b5..7ced658f483 100644
--- a/app/assets/javascripts/analytics/shared/constants.js
+++ b/app/assets/javascripts/analytics/shared/constants.js
@@ -13,6 +13,8 @@ export const dateFormats = {
month: 'mmmm',
};
+export const METRIC_POPOVER_LABEL = s__('ValueStreamAnalytics|View details');
+
export const KEY_METRICS = {
LEAD_TIME: 'lead_time',
CYCLE_TIME: 'cycle_time',
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
index 84c29e48114..7368d1a3a91 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
@@ -52,7 +52,7 @@ export default {
};
</script>
<template>
- <div class="gl-mb-4">
+ <div class="gl-mb-4 gl-display-flex gl-flex-wrap gl-gap-3">
<gl-button
v-if="showFileTreeToggle"
id="file-tree-toggle"
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 324acb177b0..57477a993c5 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -417,6 +417,20 @@
"type": "object",
"additionalProperties": false,
"properties": {
+ "component": {
+ "description": "Local path to component directory or full path to external component directory.",
+ "type": "string",
+ "format": "uri-reference"
+ }
+ },
+ "required": [
+ "component"
+ ]
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
"remote": {
"description": "URL to a `yaml`/`yml` template file using HTTP/HTTPS.",
"type": "string",
@@ -1955,4 +1969,4 @@
"additionalProperties": false
}
}
-} \ No newline at end of file
+}
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
index 9b669024a8b..f3d392a0ec4 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
@@ -1,23 +1,22 @@
<script>
-import { s__ } from '~/locale';
+import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
import { createAlert } from '~/flash';
import branchRulesQuery from 'ee_else_ce/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql';
+import { expandSection } from '~/settings_panels';
+import { scrollToElement } from '~/lib/utils/common_utils';
import BranchRule from './components/branch_rule.vue';
-
-export const i18n = {
- queryError: s__(
- 'ProtectedBranch|An error occurred while loading branch rules. Please try again.',
- ),
- emptyState: s__(
- 'ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured.',
- ),
-};
+import { I18N, PROTECTED_BRANCHES_ANCHOR, BRANCH_PROTECTION_MODAL_ID } from './constants';
export default {
name: 'BranchRules',
- i18n,
+ i18n: I18N,
components: {
BranchRule,
+ GlButton,
+ GlModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
},
apollo: {
branchRules: {
@@ -36,20 +35,27 @@ export default {
},
},
inject: {
- projectPath: {
- default: '',
- },
+ projectPath: { default: '' },
},
data() {
return {
branchRules: [],
};
},
+ methods: {
+ showProtectedBranches() {
+ // Protected branches section is on the same page as the branch rules section.
+ expandSection(this.$options.protectedBranchesAnchor);
+ scrollToElement(this.$options.protectedBranchesAnchor);
+ },
+ },
+ modalId: BRANCH_PROTECTION_MODAL_ID,
+ protectedBranchesAnchor: PROTECTED_BRANCHES_ANCHOR,
};
</script>
<template>
- <div class="settings-content">
+ <div class="settings-content gl-mb-0">
<branch-rule
v-for="(rule, index) in branchRules"
:key="`${rule.name}-${index}`"
@@ -61,6 +67,21 @@ export default {
:matching-branches-count="rule.matchingBranchesCount"
/>
- <span v-if="!branchRules.length" data-testid="empty">{{ $options.i18n.emptyState }}</span>
+ <div v-if="!branchRules.length" data-testid="empty">{{ $options.i18n.emptyState }}</div>
+
+ <gl-button v-gl-modal="$options.modalId" class="gl-mt-5" category="secondary" variant="info">{{
+ $options.i18n.addBranchRule
+ }}</gl-button>
+
+ <gl-modal
+ :ref="$options.modalId"
+ :modal-id="$options.modalId"
+ :title="$options.i18n.addBranchRule"
+ :ok-title="$options.i18n.createProtectedBranch"
+ @ok="showProtectedBranches"
+ >
+ <p>{{ $options.i18n.branchRuleModalDescription }}</p>
+ <p>{{ $options.i18n.branchRuleModalContent }}</p>
+ </gl-modal>
</div>
</template>
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/constants.js b/app/assets/javascripts/projects/settings/repository/branch_rules/constants.js
new file mode 100644
index 00000000000..4413d8eab4e
--- /dev/null
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/constants.js
@@ -0,0 +1,22 @@
+import { s__ } from '~/locale';
+
+export const I18N = {
+ queryError: s__(
+ 'ProtectedBranch|An error occurred while loading branch rules. Please try again.',
+ ),
+ emptyState: s__(
+ 'ProtectedBranch|After you configure a protected branch, merge request approval, or status check, it appears here.',
+ ),
+ addBranchRule: s__('BranchRules|Add branch rule'),
+ branchRuleModalDescription: s__(
+ 'BranchRules|To create a branch rule, you first need to create a protected branch.',
+ ),
+ branchRuleModalContent: s__(
+ 'BranchRules|After a protected branch is created, it will show up in the list as a branch rule.',
+ ),
+ createProtectedBranch: s__('BranchRules|Create protected branch'),
+};
+
+export const PROTECTED_BRANCHES_ANCHOR = '#js-protected-branches-settings';
+
+export const BRANCH_PROTECTION_MODAL_ID = 'addBranchRuleModal';
diff --git a/app/assets/stylesheets/page_bundles/settings.scss b/app/assets/stylesheets/page_bundles/settings.scss
index 9037eb7ae62..8978b8d798b 100644
--- a/app/assets/stylesheets/page_bundles/settings.scss
+++ b/app/assets/stylesheets/page_bundles/settings.scss
@@ -71,6 +71,7 @@
animation: collapseMaxHeight 300ms ease-out;
// Keep the section from expanding when we scroll over it
pointer-events: none;
+ margin-bottom: $gl-spacing-scale-5;
.settings.expanded & {
max-height: none;
@@ -101,7 +102,6 @@
display: block;
height: 1px;
overflow: hidden;
- margin-top: 20px;
}
.sub-section {
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 0dca5b18a24..b5622959c75 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -141,8 +141,11 @@ module Ci
before_save :set_size, if: :file_changed?
after_save :store_file_in_transaction!, unless: :store_after_commit?
+
after_commit :store_file_after_transaction!, on: [:create, :update], if: :store_after_commit?
+ after_destroy_commit :log_destroy
+
validates :job, presence: true
validates :file_format, presence: true, unless: :trace?, on: :create
validate :validate_file_format!, unless: :trace?, on: :create
@@ -384,6 +387,10 @@ module Ci
# Use job.project to avoid extra DB query for project
job.project.pending_delete?
end
+
+ def log_destroy
+ Gitlab::Ci::Artifacts::Logger.log_deleted(self, __method__)
+ end
end
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 7d99f10822d..7febafc2cca 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -74,7 +74,11 @@ class Environment < ApplicationRecord
# Currently, the tier presence is validaed for newly created environments.
# After the `BackfillEnvironmentTiers` background migration has been completed, we should remove `on: :create`.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/385253.
- validates :tier, presence: true, on: :create
+ # Todo: Remove along with FF `validate_environment_tier_presence`.
+ validates :tier, presence: true, on: :create, unless: :validate_environment_tier_present?
+
+ validates :tier, presence: true, if: :validate_environment_tier_present?
+
validate :safe_external_url
validate :merge_request_not_changed
@@ -600,6 +604,10 @@ class Environment < ApplicationRecord
self.class.tiers[:other]
end
end
+
+ def validate_environment_tier_present?
+ Feature.enabled?(:validate_environment_tier_presence, self.project)
+ end
end
Environment.prepend_mod_with('Environment')
diff --git a/app/services/ci/components/fetch_service.rb b/app/services/ci/components/fetch_service.rb
new file mode 100644
index 00000000000..45abb415174
--- /dev/null
+++ b/app/services/ci/components/fetch_service.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Ci
+ module Components
+ class FetchService
+ include Gitlab::Utils::StrongMemoize
+
+ TEMPLATE_FILE = 'template.yml'
+
+ COMPONENT_PATHS = [
+ ::Gitlab::Ci::Components::InstancePath
+ ].freeze
+
+ def initialize(address:, current_user:)
+ @address = address
+ @current_user = current_user
+ end
+
+ def execute
+ unless component_path_class
+ return ServiceResponse.error(
+ message: "#{error_prefix} the component path is not supported",
+ reason: :unsupported_path)
+ end
+
+ component_path = component_path_class.new(address: address, content_filename: TEMPLATE_FILE)
+ content = component_path.fetch_content!(current_user: current_user)
+
+ if content.present?
+ ServiceResponse.success(payload: { content: content, path: component_path })
+ else
+ ServiceResponse.error(message: "#{error_prefix} content not found", reason: :content_not_found)
+ end
+ rescue Gitlab::Access::AccessDeniedError
+ ServiceResponse.error(
+ message: "#{error_prefix} project does not exist or you don't have sufficient permissions",
+ reason: :not_allowed)
+ end
+
+ private
+
+ attr_reader :current_user, :address
+
+ def component_path_class
+ COMPONENT_PATHS.find { |klass| klass.match?(address) }
+ end
+ strong_memoize_attr :component_path_class
+
+ def error_prefix
+ "component '#{address}' -"
+ end
+ end
+ end
+end