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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-05-11 06:07:57 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-05-11 06:07:57 +0300
commitdefc424997d8329613ef3951ab30adf6b3b94f01 (patch)
treeef253b2f77b033e38f7ef8d80b50cf112e9e0d6f
parentcb2494484e33a0d3c750625908e8b4dda69ab7b4 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo.yml7
-rw-r--r--.rubocop_todo/style/string_literals_in_interpolation.yml69
-rw-r--r--app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue6
-rw-r--r--app/assets/javascripts/pipeline_editor/components/file_tree/container.vue38
-rw-r--r--app/assets/javascripts/pipeline_editor/components/file_tree/file_item.vue31
-rw-r--r--app/assets/javascripts/pipeline_editor/constants.js1
-rw-r--r--app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.query.graphql6
-rw-r--r--app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue9
-rw-r--r--app/assets/stylesheets/page_bundles/pipeline_editor.scss13
-rw-r--r--app/controllers/concerns/dependency_proxy/group_access.rb4
-rw-r--r--app/controllers/groups/dependency_proxies_controller.rb1
-rw-r--r--app/graphql/queries/burndown_chart/burnup.iteration.query.graphql40
-rw-r--r--app/graphql/queries/burndown_chart/burnup.milestone.query.graphql36
-rw-r--r--app/graphql/queries/burndown_chart/burnup.query.graphql75
-rw-r--r--app/graphql/types/dependency_proxy/group_setting_type.rb2
-rw-r--r--app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb2
-rw-r--r--app/policies/group_policy.rb2
-rw-r--r--app/views/registrations/welcome/show.html.haml2
-rw-r--r--app/workers/deployments/hooks_worker.rb3
-rw-r--r--config/routes/user.rb2
-rw-r--r--doc/ci/cloud_services/index.md3
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md45
-rw-r--r--doc/ci/secrets/index.md12
-rw-r--r--doc/ci/variables/predefined_variables.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md14
-rw-r--r--doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md2
-rw-r--r--doc/user/permissions.md3
-rw-r--r--package.json2
-rw-r--r--spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js19
-rw-r--r--spec/frontend/pipeline_editor/components/file-tree/constants.js1
-rw-r--r--spec/frontend/pipeline_editor/components/file-tree/container_spec.js115
-rw-r--r--spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js25
-rw-r--r--spec/frontend/pipeline_editor/mock_data.js34
-rw-r--r--spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb2
-rw-r--r--spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb4
-rw-r--r--spec/graphql/types/dependency_proxy/group_setting_type_spec.rb6
-rw-r--r--spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb2
-rw-r--r--spec/policies/group_policy_spec.rb9
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb12
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb2
-rw-r--r--spec/services/dependency_proxy/group_settings/update_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb6
-rw-r--r--spec/workers/deployments/hooks_worker_spec.rb10
-rw-r--r--vendor/project_templates/cluster_management.tar.gzbin17708 -> 14705 bytes
-rw-r--r--yarn.lock8
47 files changed, 501 insertions, 202 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index d0e08e04927..3f495ef85b2 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -242,10 +242,3 @@ Style/SingleArgumentDig:
# Cop supports --auto-correct.
Style/StringConcatenation:
Enabled: false
-
-# Offense count: 109
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: single_quotes, double_quotes
-Style/StringLiteralsInInterpolation:
- Enabled: false
diff --git a/.rubocop_todo/style/string_literals_in_interpolation.yml b/.rubocop_todo/style/string_literals_in_interpolation.yml
new file mode 100644
index 00000000000..3f3cb007306
--- /dev/null
+++ b/.rubocop_todo/style/string_literals_in_interpolation.yml
@@ -0,0 +1,69 @@
+---
+# Cop supports --auto-correct.
+Style/StringLiteralsInInterpolation:
+ # Offense count: 119
+ # Temporarily disabled due to too many offenses
+ Enabled: false
+ Exclude:
+ - 'app/graphql/mutations/base_mutation.rb'
+ - 'app/helpers/colors_helper.rb'
+ - 'app/helpers/todos_helper.rb'
+ - 'app/models/application_setting_implementation.rb'
+ - 'app/models/ci/namespace_mirror.rb'
+ - 'app/models/integrations/campfire.rb'
+ - 'app/models/integrations/jira.rb'
+ - 'app/models/serverless/domain.rb'
+ - 'app/services/draft_notes/publish_service.rb'
+ - 'app/services/projects/create_service.rb'
+ - 'app/validators/nested_attributes_duplicates_validator.rb'
+ - 'app/views/events/_event.atom.builder'
+ - 'app/workers/concerns/application_worker.rb'
+ - 'config/initializers/validate_database_config.rb'
+ - 'db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb'
+ - 'ee/app/helpers/ee/merge_requests_helper.rb'
+ - 'ee/app/models/license.rb'
+ - 'ee/app/services/epics/tree_reorder_service.rb'
+ - 'ee/lib/gitlab/elastic/helper.rb'
+ - 'ee/lib/pseudonymizer/pager.rb'
+ - 'ee/spec/features/admin/admin_settings_spec.rb'
+ - 'lib/api/helpers/snippets_helpers.rb'
+ - 'lib/api/validations/validators/check_assignees_count.rb'
+ - 'lib/banzai/filter/references/abstract_reference_filter.rb'
+ - 'lib/generators/gitlab/usage_metric_definition_generator.rb'
+ - 'lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb'
+ - 'lib/gitlab/ci/config/entry/job.rb'
+ - 'lib/gitlab/ci/yaml_processor.rb'
+ - 'lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb'
+ - 'lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb'
+ - 'lib/gitlab/doctor/secrets.rb'
+ - 'lib/gitlab/endpoint_attributes/config.rb'
+ - 'lib/gitlab/graphql/queries.rb'
+ - 'lib/gitlab/quick_actions/extractor.rb'
+ - 'lib/gitlab/sanitizers/exif.rb'
+ - 'lib/gitlab/sidekiq_signals.rb'
+ - 'lib/gitlab/tracking/destinations/snowplow.rb'
+ - 'lib/tasks/gitlab/info.rake'
+ - 'lib/tasks/gitlab/sidekiq.rake'
+ - 'lib/tasks/gitlab/tw/codeowners.rake'
+ - 'qa/qa/ee/page/component/secure_report.rb'
+ - 'qa/qa/ee/page/group/secure/show.rb'
+ - 'qa/qa/resource/events/base.rb'
+ - 'qa/qa/service/cluster_provider/base.rb'
+ - 'qa/qa/service/cluster_provider/gcloud.rb'
+ - 'qa/qa/service/docker_run/gitlab_runner.rb'
+ - 'qa/qa/specs/helpers/context_selector.rb'
+ - 'qa/qa/tools/generate_perf_testdata.rb'
+ - 'rubocop/cop/migration/prevent_index_creation.rb'
+ - 'spec/controllers/projects/serverless/functions_controller_spec.rb'
+ - 'spec/features/commits_spec.rb'
+ - 'spec/features/dashboard/merge_requests_spec.rb'
+ - 'spec/features/users/login_spec.rb'
+ - 'spec/finders/serverless_domain_finder_spec.rb'
+ - 'spec/lib/banzai/filter/references/commit_reference_filter_spec.rb'
+ - 'spec/lib/banzai/filter/references/issue_reference_filter_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb'
+ - 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
+ - 'spec/lib/object_storage/direct_upload_spec.rb'
+ - 'spec/models/serverless/domain_spec.rb'
+ - 'spec/requests/api/keys_spec.rb'
+ - 'spec/support/database/prevent_cross_joins.rb'
diff --git a/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue b/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
index 998db653e0c..58df98d0fb7 100644
--- a/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
+++ b/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
@@ -2,7 +2,7 @@
import { GlButton } from '@gitlab/ui';
import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { EDITOR_APP_STATUS_EMPTY } from '../../constants';
+import { EDITOR_APP_STATUS_EMPTY, EDITOR_APP_STATUS_LOADING } from '../../constants';
import FileTreePopover from '../popovers/file_tree_popover.vue';
import BranchSwitcher from './branch_switcher.vue';
@@ -39,6 +39,9 @@ export default {
},
},
computed: {
+ isAppLoading() {
+ return this.appStatus === EDITOR_APP_STATUS_LOADING;
+ },
showFileTreeToggle() {
return (
this.glFeatures.pipelineEditorFileTree &&
@@ -62,6 +65,7 @@ export default {
icon="file-tree"
data-testid="file-tree-toggle"
:aria-label="__('File Tree')"
+ :loading="isAppLoading"
@click="onFileTreeBtnClick"
/>
<file-tree-popover v-if="showFileTreeToggle" />
diff --git a/app/assets/javascripts/pipeline_editor/components/file_tree/container.vue b/app/assets/javascripts/pipeline_editor/components/file_tree/container.vue
index d1ff70ad518..8bffb281211 100644
--- a/app/assets/javascripts/pipeline_editor/components/file_tree/container.vue
+++ b/app/assets/javascripts/pipeline_editor/components/file_tree/container.vue
@@ -1,6 +1,8 @@
<script>
-import { GlAlert } from '@gitlab/ui';
+import { GlAlert, GlTooltipDirective } from '@gitlab/ui';
import { __, s__ } from '~/locale';
+import FileIcon from '~/vue_shared/components/file_icon.vue';
+import { FILE_TREE_TIP_DISMISSED_KEY } from '../../constants';
import FileItem from './file_item.vue';
const i18n = {
@@ -15,27 +17,55 @@ export default {
i18n,
name: 'PipelineEditorFileTreeContainer',
components: {
+ FileIcon,
FileItem,
GlAlert,
},
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
inject: ['ciConfigPath'],
+ props: {
+ includes: {
+ type: Array,
+ required: true,
+ },
+ },
data() {
return {
- showTip: true,
+ canShowTip: localStorage.getItem(FILE_TREE_TIP_DISMISSED_KEY) !== 'true',
};
},
+ computed: {
+ showTip() {
+ return this.includes.length === 0 && this.canShowTip;
+ },
+ },
methods: {
dismissTip() {
- this.showTip = false;
+ this.canShowTip = false;
+ localStorage.setItem(FILE_TREE_TIP_DISMISSED_KEY, 'true');
},
},
};
</script>
<template>
<aside class="file-tree-container gl-mr-5 gl-mb-5">
- <file-item class="gl-mb-3 gl-bg-gray-50" :file-name="ciConfigPath" />
+ <div
+ v-gl-tooltip
+ :title="ciConfigPath"
+ class="gl-bg-gray-50 gl-py-2 gl-px-3 gl-mb-3 gl-rounded-base"
+ >
+ <span class="file-row-name gl-str-truncated" :title="ciConfigPath">
+ <file-icon class="file-row-icon" :file-name="ciConfigPath" />
+ <span data-testid="current-config-filename">{{ ciConfigPath }}</span>
+ </span>
+ </div>
<gl-alert v-if="showTip" variant="tip" :title="$options.i18n.tipTitle" @dismiss="dismissTip">
{{ $options.i18n.tipDescription }}
</gl-alert>
+ <div class="gl-overflow-y-auto">
+ <file-item v-for="file in includes" :key="file.location" :file="file" />
+ </div>
</aside>
</template>
diff --git a/app/assets/javascripts/pipeline_editor/components/file_tree/file_item.vue b/app/assets/javascripts/pipeline_editor/components/file_tree/file_item.vue
index d51a2874c9e..786d483b5b9 100644
--- a/app/assets/javascripts/pipeline_editor/components/file_tree/file_item.vue
+++ b/app/assets/javascripts/pipeline_editor/components/file_tree/file_item.vue
@@ -1,24 +1,45 @@
<script>
+import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
import FileIcon from '~/vue_shared/components/file_icon.vue';
export default {
name: 'PipelineEditorFileItem',
components: {
FileIcon,
+ GlIcon,
+ GlLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
},
props: {
- fileName: {
- type: String,
+ file: {
+ type: Object,
required: true,
},
},
+ computed: {
+ fileName() {
+ return this.file.location;
+ },
+ filePath() {
+ return this.file.blob || this.file.raw;
+ },
+ },
};
</script>
<template>
- <div class="gl-py-2 gl-px-3 gl-rounded-base">
- <span class="file-row-name" :title="fileName">
+ <gl-link
+ v-gl-tooltip
+ :href="filePath"
+ :title="fileName"
+ target="_blank"
+ class="file-tree-includes-link gl-display-flex gl-justify-content-space-between gl-hover-bg-gray-50 gl-text-body gl-hover-text-gray-900 gl-hover-text-decoration-none gl-py-2 gl-px-3 gl-rounded-base"
+ >
+ <span class="file-row-name gl-str-truncated" :title="fileName">
<file-icon class="file-row-icon" :file-name="fileName" />
<span>{{ fileName }}</span>
</span>
- </div>
+ <gl-icon class="gl-display-none gl-relative gl-text-gray-500" name="external-link" />
+ </gl-link>
</template>
diff --git a/app/assets/javascripts/pipeline_editor/constants.js b/app/assets/javascripts/pipeline_editor/constants.js
index 0484da8641d..ff7c742f588 100644
--- a/app/assets/javascripts/pipeline_editor/constants.js
+++ b/app/assets/javascripts/pipeline_editor/constants.js
@@ -51,6 +51,7 @@ export const SOURCE_EDITOR_DEBOUNCE = 500;
export const FILE_TREE_DISPLAY_KEY = 'pipeline_editor_file_tree_display';
export const FILE_TREE_POPOVER_DISMISSED_KEY = 'pipeline_editor_file_tree_popover_dismissed';
+export const FILE_TREE_TIP_DISMISSED_KEY = 'pipeline_editor_file_tree_tip_dismissed';
export const STARTER_TEMPLATE_NAME = 'Getting-Started';
diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.query.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.query.graphql
index df7de6a1f54..5354ed7c2d5 100644
--- a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.query.graphql
+++ b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.query.graphql
@@ -3,6 +3,12 @@
query getCiConfigData($projectPath: ID!, $sha: String, $content: String!) {
ciConfig(projectPath: $projectPath, sha: $sha, content: $content) {
errors
+ includes {
+ location
+ type
+ blob
+ raw
+ }
mergedYaml
status
stages {
diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
index f5277fdbcca..59022a91322 100644
--- a/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
+++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
@@ -73,6 +73,9 @@ export default {
showCommitForm() {
return this.currentTab === CREATE_TAB;
},
+ includesFiles() {
+ return this.ciConfigData?.includes || [];
+ },
isFileTreeVisible() {
return this.showFileTree && this.glFeatures.pipelineEditorFileTree;
},
@@ -136,7 +139,11 @@ export default {
v-on="$listeners"
/>
<div class="gl-display-flex gl-w-full gl-sm-flex-direction-column">
- <pipeline-editor-file-tree v-if="isFileTreeVisible" class="gl-flex-shrink-0" />
+ <pipeline-editor-file-tree
+ v-if="isFileTreeVisible"
+ class="gl-flex-shrink-0"
+ :includes="includesFiles"
+ />
<div class="gl-flex-grow-1 gl-min-w-0">
<pipeline-editor-header
:ci-config-data="ciConfigData"
diff --git a/app/assets/stylesheets/page_bundles/pipeline_editor.scss b/app/assets/stylesheets/page_bundles/pipeline_editor.scss
index 8e4cff2d167..e167052a3e1 100644
--- a/app/assets/stylesheets/page_bundles/pipeline_editor.scss
+++ b/app/assets/stylesheets/page_bundles/pipeline_editor.scss
@@ -7,3 +7,16 @@
width: 300px;
}
}
+
+.file-tree-container > div.gl-overflow-y-auto {
+ max-height: 220px;
+
+ @media (min-width: $breakpoint-md) {
+ max-height: 700px;
+ }
+}
+
+.file-tree-includes-link:hover > svg {
+ @include gl-display-block;
+ top: 2px;
+}
diff --git a/app/controllers/concerns/dependency_proxy/group_access.rb b/app/controllers/concerns/dependency_proxy/group_access.rb
index 44611641529..45392625e45 100644
--- a/app/controllers/concerns/dependency_proxy/group_access.rb
+++ b/app/controllers/concerns/dependency_proxy/group_access.rb
@@ -18,9 +18,5 @@ module DependencyProxy
def authorize_read_dependency_proxy!
access_denied! unless can?(auth_user, :read_dependency_proxy, group)
end
-
- def authorize_admin_dependency_proxy!
- access_denied! unless can?(auth_user, :admin_dependency_proxy, group)
- end
end
end
diff --git a/app/controllers/groups/dependency_proxies_controller.rb b/app/controllers/groups/dependency_proxies_controller.rb
index afa2af0d173..8e134529c34 100644
--- a/app/controllers/groups/dependency_proxies_controller.rb
+++ b/app/controllers/groups/dependency_proxies_controller.rb
@@ -4,7 +4,6 @@ module Groups
class DependencyProxiesController < Groups::ApplicationController
include ::DependencyProxy::GroupAccess
- before_action :authorize_admin_dependency_proxy!, only: :update
before_action :verify_dependency_proxy_enabled!
feature_category :dependency_proxy
diff --git a/app/graphql/queries/burndown_chart/burnup.iteration.query.graphql b/app/graphql/queries/burndown_chart/burnup.iteration.query.graphql
new file mode 100644
index 00000000000..ff50c34ade3
--- /dev/null
+++ b/app/graphql/queries/burndown_chart/burnup.iteration.query.graphql
@@ -0,0 +1,40 @@
+query BurnupTimesSeriesIterationData(
+ $iterationId: IterationID!
+ $weight: Boolean = false
+ $fullPath: String
+) {
+ iteration(id: $iterationId) {
+ __typename
+ id
+ title
+ report(fullPath: $fullPath) {
+ __typename
+ burnupTimeSeries {
+ __typename
+ date
+ completedCount @skip(if: $weight)
+ scopeCount @skip(if: $weight)
+ completedWeight @include(if: $weight)
+ scopeWeight @include(if: $weight)
+ }
+ stats {
+ __typename
+ total {
+ __typename
+ count @skip(if: $weight)
+ weight @include(if: $weight)
+ }
+ complete {
+ __typename
+ count @skip(if: $weight)
+ weight @include(if: $weight)
+ }
+ incomplete {
+ __typename
+ count @skip(if: $weight)
+ weight @include(if: $weight)
+ }
+ }
+ }
+ }
+}
diff --git a/app/graphql/queries/burndown_chart/burnup.milestone.query.graphql b/app/graphql/queries/burndown_chart/burnup.milestone.query.graphql
new file mode 100644
index 00000000000..18e59249500
--- /dev/null
+++ b/app/graphql/queries/burndown_chart/burnup.milestone.query.graphql
@@ -0,0 +1,36 @@
+query BurnupTimesSeriesMilestoneData($milestoneId: MilestoneID!, $weight: Boolean = false) {
+ milestone(id: $milestoneId) {
+ __typename
+ id
+ title
+ report {
+ __typename
+ burnupTimeSeries {
+ __typename
+ date
+ completedCount @skip(if: $weight)
+ scopeCount @skip(if: $weight)
+ completedWeight @include(if: $weight)
+ scopeWeight @include(if: $weight)
+ }
+ stats {
+ __typename
+ total {
+ __typename
+ count @skip(if: $weight)
+ weight @include(if: $weight)
+ }
+ complete {
+ __typename
+ count @skip(if: $weight)
+ weight @include(if: $weight)
+ }
+ incomplete {
+ __typename
+ count @skip(if: $weight)
+ weight @include(if: $weight)
+ }
+ }
+ }
+ }
+}
diff --git a/app/graphql/queries/burndown_chart/burnup.query.graphql b/app/graphql/queries/burndown_chart/burnup.query.graphql
deleted file mode 100644
index 0795645f8b7..00000000000
--- a/app/graphql/queries/burndown_chart/burnup.query.graphql
+++ /dev/null
@@ -1,75 +0,0 @@
-query BurnupTimesSeriesData(
- $id: ID!
- $isIteration: Boolean = false
- $weight: Boolean = false
- $fullPath: String
-) {
- milestone(id: $id) @skip(if: $isIteration) {
- __typename
- id
- title
- report {
- __typename
- burnupTimeSeries {
- __typename
- date
- completedCount @skip(if: $weight)
- scopeCount @skip(if: $weight)
- completedWeight @include(if: $weight)
- scopeWeight @include(if: $weight)
- }
- stats {
- __typename
- total {
- __typename
- count @skip(if: $weight)
- weight @include(if: $weight)
- }
- complete {
- __typename
- count @skip(if: $weight)
- weight @include(if: $weight)
- }
- incomplete {
- __typename
- count @skip(if: $weight)
- weight @include(if: $weight)
- }
- }
- }
- }
- iteration(id: $id) @include(if: $isIteration) {
- __typename
- id
- title
- report(fullPath: $fullPath) {
- __typename
- burnupTimeSeries {
- __typename
- date
- completedCount @skip(if: $weight)
- scopeCount @skip(if: $weight)
- completedWeight @include(if: $weight)
- scopeWeight @include(if: $weight)
- }
- stats {
- __typename
- total {
- __typename
- count @skip(if: $weight)
- weight @include(if: $weight)
- }
- complete {
- __typename
- count @skip(if: $weight)
- weight @include(if: $weight)
- }
- incomplete {
- __typename
- count @skip(if: $weight)
- weight @include(if: $weight)
- }
- }
- }
- }
-}
diff --git a/app/graphql/types/dependency_proxy/group_setting_type.rb b/app/graphql/types/dependency_proxy/group_setting_type.rb
index 8b8b8572aa9..6c6f848d019 100644
--- a/app/graphql/types/dependency_proxy/group_setting_type.rb
+++ b/app/graphql/types/dependency_proxy/group_setting_type.rb
@@ -6,7 +6,7 @@ module Types
description 'Group-level Dependency Proxy settings'
- authorize :read_dependency_proxy
+ authorize :admin_dependency_proxy
field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether the dependency proxy is enabled for the group.'
end
diff --git a/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb b/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb
index 9ab7c50998d..b8c178539a0 100644
--- a/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb
+++ b/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb
@@ -6,7 +6,7 @@ module Types
description 'Group-level Dependency Proxy TTL policy settings'
- authorize :read_dependency_proxy
+ authorize :admin_dependency_proxy
field :created_at, Types::TimeType, null: true, description: 'Timestamp of creation.'
field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether the policy is enabled or disabled.'
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index f6932d30ce2..d397d77bc1a 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -251,7 +251,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
rule { dependency_proxy_access_allowed & dependency_proxy_available }
.enable :read_dependency_proxy
- rule { developer & dependency_proxy_available }.policy do
+ rule { maintainer & dependency_proxy_available }.policy do
enable :admin_dependency_proxy
end
diff --git a/app/views/registrations/welcome/show.html.haml b/app/views/registrations/welcome/show.html.haml
index 1f6976d4f38..62499f1a6b6 100644
--- a/app/views/registrations/welcome/show.html.haml
+++ b/app/views/registrations/welcome/show.html.haml
@@ -17,7 +17,7 @@
%p.gl-text-center= html_escape(_('%{gitlab_experience_text}. We won\'t share this information with anyone.')) % { gitlab_experience_text: gitlab_experience_text }
- else
%p.gl-text-center= html_escape(_('%{gitlab_experience_text}. Don\'t worry, this information isn\'t shared outside of your self-managed GitLab instance.')) % { gitlab_experience_text: gitlab_experience_text }
- = gitlab_ui_form_for(current_user, url: users_sign_up_welcome_path, html: { class: 'card gl-w-full! gl-p-5', 'aria-live' => 'assertive' }) do |f|
+ = gitlab_ui_form_for(current_user, url: users_sign_up_welcome_path, html: { class: 'card gl-w-full! gl-p-5 js-users-signup-welcome', 'aria-live' => 'assertive' }) do |f|
.devise-errors
= render 'devise/shared/error_messages', resource: current_user
.row
diff --git a/app/workers/deployments/hooks_worker.rb b/app/workers/deployments/hooks_worker.rb
index 31c57e5c001..608601b4eb9 100644
--- a/app/workers/deployments/hooks_worker.rb
+++ b/app/workers/deployments/hooks_worker.rb
@@ -13,6 +13,9 @@ module Deployments
params = params.with_indifferent_access
if (deploy = Deployment.find_by_id(params[:deployment_id]))
+ log_extra_metadata_on_done(:deployment_project_id, deploy.project.id)
+ log_extra_metadata_on_done(:deployment_id, params[:deployment_id])
+
deploy.execute_hooks(params[:status_changed_at].to_time)
end
end
diff --git a/config/routes/user.rb b/config/routes/user.rb
index 64dc56e18ec..ccacf817cc5 100644
--- a/config/routes/user.rb
+++ b/config/routes/user.rb
@@ -27,7 +27,7 @@ devise_controllers = { omniauth_callbacks: :omniauth_callbacks,
sessions: :sessions,
confirmations: :confirmations }
-if ::Gitlab.ee? && ::Gitlab::Geo.connected? && ::Gitlab::Geo.secondary?
+if ::Gitlab.ee? && ::Gitlab::Geo.secondary?(infer_without_database: true)
devise_for :users, controllers: devise_controllers, path_names: { sign_in: 'auth/geo/sign_in',
sign_out: 'auth/geo/sign_out' }
# When using Geo, the other type of routes should be present as well, as browsers
diff --git a/doc/ci/cloud_services/index.md b/doc/ci/cloud_services/index.md
index 0f404927694..1493a930099 100644
--- a/doc/ci/cloud_services/index.md
+++ b/doc/ci/cloud_services/index.md
@@ -25,6 +25,9 @@ review for the pipeline, focusing on the additional access. You can use the [sof
as a starting point, and for more information about supply chain attacks, see
[How a DevOps Platform helps protect against supply chain attacks](https://about.gitlab.com/blog/2021/04/28/devops-platform-supply-chain-attacks/).
+WARNING:
+The `CI_JOB_JWT_V2` variable is under development [(alpha)](../../policy/alpha-beta-support.md#alpha-features) and is not yet suitable for production use.
+
## Use cases
- Removes the need to store secrets in your GitLab group or project. Temporary credentials can be retrieved from your cloud provider through OIDC.
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index a2d8738bda3..389429f3f0f 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -22,14 +22,14 @@ This tutorial assumes you are familiar with GitLab CI/CD and Vault.
To follow along, you must have:
- An account on GitLab.
-- Access to a running Vault server (at least v1.2.0) to configure authentication and to create roles and policies. You can use Open Source or Enterprise version of HashiCorp Vault.
+- Access to a running Vault server (at least v1.2.0) to configure authentication and to create roles and policies. For HashiCorp Vaults, this can be the Open Source or Enterprise version.
NOTE:
You must replace the `vault.example.com` URL below with the URL of your Vault server, and `gitlab.example.com` with the URL of your GitLab instance.
## How it works
-Each job has JSON Web Token (JWT) provided as CI/CD variable named `CI_JOB_JWT` or `CI_JOB_JWT_V2`. This JWT can be used to authenticate with Vault using the [JWT Auth](https://www.vaultproject.io/docs/auth/jwt#jwt-authentication) method.
+Each job has JSON Web Token (JWT) provided as CI/CD variable named `CI_JOB_JWT`. This JWT can be used to authenticate with Vault using the [JWT Auth](https://www.vaultproject.io/docs/auth/jwt#jwt-authentication) method.
The following fields are included in the JWT:
@@ -40,8 +40,7 @@ The following fields are included in the JWT:
| `iat` | Always | Issued at |
| `nbf` | Always | Not valid before |
| `exp` | Always | Expires at |
-| `sub` | Always | `project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}` |
-| `aud` | Always | Issuer, the domain of your GitLab instance |
+| `sub` | Always | Subject (job ID) |
| `namespace_id` | Always | Use this to scope to group or user level namespace by ID |
| `namespace_path` | Always | Use this to scope to group or user level namespace by path |
| `project_id` | Always | Use this to scope to project by ID |
@@ -63,12 +62,11 @@ Example JWT payload:
```json
{
"jti": "c82eeb0c-5c6f-4a33-abf5-4c474b92b558",
- "iss": "https://gitlab.example.com",
- "aud": "https://gitlab.example.com",
+ "iss": "gitlab.example.com",
"iat": 1585710286,
"nbf": 1585798372,
"exp": 1585713886,
- "sub": "project_path:mygroup/myproject:ref_type:branch:ref:main",
+ "sub": "job_1212",
"namespace_id": "1",
"namespace_path": "mygroup",
"project_id": "22",
@@ -93,8 +91,6 @@ You can use this JWT and your instance's JWKS endpoint (`https://gitlab.example.
When configuring roles in Vault, you can use [bound_claims](https://www.vaultproject.io/docs/auth/jwt#bound-claims) to match against the JWT's claims and restrict which secrets each CI job has access to.
-You must use `bound_audiences` to match against the JWT's audience claim.
-
To communicate with Vault, you can use either its CLI client or perform API requests (using `curl` or another client).
## Example
@@ -158,8 +154,7 @@ $ vault write auth/jwt/role/myproject-staging - <<EOF
"project_id": "22",
"ref": "master",
"ref_type": "branch"
- },
- "bound_audiences": "https://gitlab.example.com"
+ }
}
EOF
```
@@ -179,8 +174,7 @@ $ vault write auth/jwt/role/myproject-production - <<EOF
"ref_protected": "true",
"ref_type": "branch",
"ref": "auto-deploy-*"
- },
- "bound_audiences": "https://gitlab.example.com"
+ }
}
EOF
```
@@ -217,7 +211,7 @@ Role example to support the templated policy above, mapping the claim field `pro
}
```
-For the full list of options, see the Vault [Create Role documentation](https://www.vaultproject.io/api/auth/jwt#create-role).
+For the full list of options, see Vault's [Create Role documentation](https://www.vaultproject.io/api/auth/jwt#create-role).
WARNING:
Always restrict your roles to project or namespace by using one of the provided claims (for example, `project_id` or `namespace_id`). Otherwise any JWT generated by this instance may be allowed to authenticate using this role.
@@ -227,12 +221,12 @@ Now, configure the JWT Authentication method:
```shell
$ vault write auth/jwt/config \
jwks_url="https://gitlab.example.com/-/jwks" \
- bound_issuer="https://gitlab.example.com"
+ bound_issuer="gitlab.example.com"
```
-[`bound_issuer`](https://www.vaultproject.io/api/auth/jwt#inlinecode-bound_issuer) specifies that only a JWT with the issuer (that is, the `iss` claim) set to `https://gitlab.example.com` can use this method to authenticate, and that the JWKS endpoint (`https://gitlab.example.com/-/jwks`) should be used to validate the token.
+[bound_issuer](https://www.vaultproject.io/api/auth/jwt#inlinecode-bound_issuer) specifies that only a JWT with the issuer (that is, the `iss` claim) set to `gitlab.example.com` can use this method to authenticate, and that the JWKS endpoint (`https://gitlab.example.com/-/jwks`) should be used to validate the token.
-For the full list of available configuration options, see the Vault [API documentation](https://www.vaultproject.io/api/auth/jwt#configure).
+For the full list of available configuration options, see Vault's [API documentation](https://www.vaultproject.io/api/auth/jwt#configure).
The following job, when run for the default branch, is able to read secrets under `secret/myproject/staging/`, but not the secrets under `secret/myproject/production/`:
@@ -247,7 +241,7 @@ read_secrets:
- export VAULT_ADDR=http://vault.example.com:8200
# Authenticate and get token. Token expiry time and other properties can be configured
# when configuring JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1
- - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-staging jwt=$CI_JOB_JWT_V2)"
+ - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-staging jwt=$CI_JOB_JWT)"
# Now use the VAULT_TOKEN to read the secret and store it in an environment variable
- export PASSWORD="$(vault kv get -field=password secret/myproject/staging/db)"
# Use the secret
@@ -275,7 +269,7 @@ read_secrets:
- export VAULT_ADDR=http://vault.example.com:8200
# Authenticate and get token. Token expiry time and other properties can be configured
# when configuring JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1
- - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT_V2)"
+ - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT)"
# Now use the VAULT_TOKEN to read the secret and store it in environment variable
- export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"
# Use the secret
@@ -286,7 +280,7 @@ read_secrets:
### Limit token access to Vault secrets
-You can control `CI_JOB_JWT_V2` access to Vault secrets by using Vault protections
+You can control `CI_JOB_JWT` access to Vault secrets by using Vault protections
and GitLab features. For example, restrict the token by:
- Using Vault [bound_claims](https://www.vaultproject.io/docs/auth/jwt#bound-claims)
@@ -299,14 +293,3 @@ and GitLab features. For example, restrict the token by:
that are restricted to a subset of project users.
- Scoping the JWT to [GitLab projected tags](../../../user/project/protected_tags.md),
that are restricted to a subset of project users.
-
-## Troubleshooting
-
-### `Code: 400. Errors: audience claim found in JWT but no audiences bound to the role`
-
-This issue occurs because you are using a JWT V2 token and your role on Vault is missing a value for `bound_audiences`.
-
-### `Code: 400. Errors: error validating claims: validation failed, invalid issuer claim (iss)`
-
-The issuer in Vault must match the issuer defined in a JWT V2 token.
-In Vault, ensure you're using `https` in your issuer.
diff --git a/doc/ci/secrets/index.md b/doc/ci/secrets/index.md
index 7fcdafe17be..ba395108966 100644
--- a/doc/ci/secrets/index.md
+++ b/doc/ci/secrets/index.md
@@ -25,7 +25,8 @@ as the first supported secrets engine.
GitLab authenticates using Vault's
[JSON Web Token (JWT) authentication method](https://www.vaultproject.io/docs/auth/jwt#jwt-authentication), using
-the [JSON Web Token](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) (`CI_JOB_JWT_V2`).
+the [JSON Web Token](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) (`CI_JOB_JWT`)
+introduced in GitLab 12.10.
You must [configure your Vault server](#configure-your-vault-server) before you
can use [use Vault secrets in a CI job](#use-vault-secrets-in-a-ci-job).
@@ -33,7 +34,7 @@ can use [use Vault secrets in a CI job](#use-vault-secrets-in-a-ci-job).
The flow for using GitLab with HashiCorp Vault
is summarized by this diagram:
-![Flow between GitLab and HashiCorp](../img/gitlab_vault_workflow_v13_4.png "How GitLab CI_JOB_JWT_V2 works with HashiCorp Vault")
+![Flow between GitLab and HashiCorp](../img/gitlab_vault_workflow_v13_4.png "How GitLab CI_JOB_JWT works with HashiCorp Vault")
1. Configure your vault and secrets.
1. Generate your JWT and provide it to your CI job.
@@ -63,7 +64,7 @@ To configure your Vault server:
$ vault write auth/jwt/config \
jwks_url="https://gitlab.example.com/-/jwks" \
- bound_issuer="https://gitlab.example.com"
+ bound_issuer="gitlab.example.com"
```
1. Configure policies on your Vault server to grant or forbid access to certain
@@ -166,8 +167,7 @@ $ vault write auth/jwt/role/myproject-production - <<EOF
"ref_protected": "true",
"ref_type": "tag",
"ref": "auto-deploy-*"
- },
- "bound_audiences": "https://gitlab.example.com"
+ }
}
EOF
```
@@ -177,7 +177,7 @@ Always restrict your roles to a project or namespace by using one of the provide
claims like `project_id` or `namespace_id`. Without these restrictions, any JWT
generated by this GitLab instance may be allowed to authenticate using this role.
-For a full list of `CI_JOB_JWT_V2` claims, read the
+For a full list of `CI_JOB_JWT` claims, read the
[How it works](../examples/authenticating-with-hashicorp-vault/index.md#how-it-works) section of the
[Authenticating and Reading Secrets With HashiCorp Vault](../examples/authenticating-with-hashicorp-vault/index.md) tutorial.
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 8a09745b675..f8f775a6df4 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -62,7 +62,7 @@ There are also a number of [variables you can use to configure runner behavior](
| `CI_JOB_IMAGE` | 12.9 | 12.9 | The name of the Docker image running the job. |
| `CI_JOB_JWT` | 12.10 | all | A RS256 JSON web token to authenticate with third party systems that support JWT authentication, for example [HashiCorp's Vault](../secrets/index.md). |
| `CI_JOB_JWT_V1` | 14.6 | all | The same value as `CI_JOB_JWT`. |
-| `CI_JOB_JWT_V2` | 14.6 | all | A newly formatted RS256 JSON web token to increase compatibility. Similar to `CI_JOB_JWT`, except the issuer (`iss`) claim is changed from `gitlab.com` to `https://gitlab.com`, `sub` has changed from `job_id` to a string that contains the project path, and an `aud` claim is added. Format is subject to change. Be aware, the `aud` field is a constant value. Trusting JWTs in multiple relying parties can lead to [one RP sending a JWT to another one and acting maliciously as a job](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72555#note_769112331). |
+| `CI_JOB_JWT_V2` | 14.6 | all | [**alpha:**](../../policy/alpha-beta-support.md#alpha-features) A newly formatted RS256 JSON web token to increase compatibility. Similar to `CI_JOB_JWT`, except the issuer (`iss`) claim is changed from `gitlab.com` to `https://gitlab.com`, `sub` has changed from `job_id` to a string that contains the project path, and an `aud` claim is added. Format is subject to change. Be aware, the `aud` field is a constant value. Trusting JWTs in multiple relying parties can lead to [one RP sending a JWT to another one and acting maliciously as a job](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72555#note_769112331). |
| `CI_JOB_MANUAL` | 8.12 | all | `true` if a job was started manually. |
| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job. |
| `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the job's stage. |
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index e6ef72bef4d..5e31cca51bd 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -434,15 +434,15 @@ variation of this file (for example, `requirements.pip` or `requires.txt`).
#### Java and Scala
-We only execute one build in the directory where a build file has been detected, such as `build.sbt` or `build.gradle`.
-Please note, we support the following types of Java project structures:
+We only execute one build in the directory where a build file has been detected. For large projects that include
+multiple Gradle, Maven, or sbt builds, or any combination of these, `gemnasium-maven` only analyzes dependencies for the first build file
+that is detected. Build files are searched for in the following order:
-- [multi-project sbt builds](https://www.scala-sbt.org/1.x/docs/Multi-Project.html)
-- [multi-project Gradle builds](https://docs.gradle.org/current/userguide/intro_multi_project_builds.html)
-- [multi-module maven projects](https://maven.apache.org/pom.html#Aggregation)
+1. `build.gradle` or `build.gradle.kts` for single or [multi-project](https://docs.gradle.org/current/userguide/intro_multi_project_builds.html) Gradle builds.
+1. `pom.xml` for single or [multi-module](https://maven.apache.org/pom.html#Aggregation) Maven projects.
+1. `build.sbt` for single or [multi-project](https://www.scala-sbt.org/1.x/docs/Multi-Project.html) sbt builds.
-We do not support multiple lockfiles for Java and Scala. When multiple lockfiles exist, `gemnasium-maven`
-analyzes the first file in the list of package managers detected.
+The search begins with the root directory and then continues with subdirectories if no builds are found in the root directory. Consequently an sbt build file in the root directory would be detected before a Gradle build file in a subdirectory.
#### JavaScript
diff --git a/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md b/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md
index cd04d2e696b..839684da875 100644
--- a/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md
+++ b/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md
@@ -26,6 +26,8 @@ image or tag from Docker Hub.
## Cleanup policies
+> [Required permissions](https://gitlab.com/gitlab-org/gitlab/-/issues/350682) changed from developer to maintainer in GitLab 15.0.
+
### Enable cleanup policies from within GitLab
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340777) in GitLab 14.6
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index f2077cc92ca..56474796b8c 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -400,8 +400,9 @@ The following table lists group permissions available for each role:
| Create/edit/delete group milestones | | ✓ | ✓ | ✓ | ✓ |
| Create/edit/delete iterations | | ✓ | ✓ | ✓ | ✓ |
| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
-| Enable/disable a dependency proxy | | | ✓ | ✓ | ✓ |
+| Enable/disable a dependency proxy | | | | ✓ | ✓ |
| Purge the dependency proxy for a group | | | | | ✓ |
+| Create/edit/delete dependency proxy [cleanup policies](packages/dependency_proxy/reduce_dependency_proxy_storage.md#cleanup-policies) | | | | ✓ | ✓ |
| Use [security dashboard](application_security/security_dashboard/index.md) | | | ✓ | ✓ | ✓ |
| View group Audit Events | | | ✓ (7) | ✓ (7) | ✓ |
| Create subgroup | | | | ✓ (1) | ✓ |
diff --git a/package.json b/package.json
index c99770122fc..f5642506772 100644
--- a/package.json
+++ b/package.json
@@ -109,7 +109,7 @@
"codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
- "core-js": "^3.22.4",
+ "core-js": "^3.22.5",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropper": "^2.3.0",
diff --git a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
index cbd9c86aabd..a61796dbed2 100644
--- a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
+++ b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js
@@ -7,7 +7,11 @@ import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switche
import PipelineEditorFileNav from '~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue';
import FileTreePopover from '~/pipeline_editor/components/popovers/file_tree_popover.vue';
import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
-import { EDITOR_APP_STATUS_EMPTY, EDITOR_APP_STATUS_VALID } from '~/pipeline_editor/constants';
+import {
+ EDITOR_APP_STATUS_EMPTY,
+ EDITOR_APP_STATUS_LOADING,
+ EDITOR_APP_STATUS_VALID,
+} from '~/pipeline_editor/constants';
Vue.use(VueApollo);
@@ -109,6 +113,19 @@ describe('Pipeline editor file nav', () => {
});
});
+ describe('when app is in a global loading state', () => {
+ it('renders the file tree button with a loading icon', () => {
+ createComponent({
+ appStatus: EDITOR_APP_STATUS_LOADING,
+ isNewCiConfigFile: false,
+ pipelineEditorFileTree: true,
+ });
+
+ expect(findFileTreeBtn().exists()).toBe(true);
+ expect(findFileTreeBtn().attributes('loading')).toBe('true');
+ });
+ });
+
describe('when editor has a non-empty config file open', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/pipeline_editor/components/file-tree/constants.js b/spec/frontend/pipeline_editor/components/file-tree/constants.js
deleted file mode 100644
index 2f0ea978c2b..00000000000
--- a/spec/frontend/pipeline_editor/components/file-tree/constants.js
+++ /dev/null
@@ -1 +0,0 @@
-export const MOCK_DEFAULT_CI_FILE = '.gitlab-ci.yml';
diff --git a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
index e449a7e5753..615a3eaac47 100644
--- a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
+++ b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
@@ -1,26 +1,39 @@
import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils';
import { GlAlert } from '@gitlab/ui';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { createMockDirective } from 'helpers/vue_mock_directive';
import PipelineEditorFileTreeContainer from '~/pipeline_editor/components/file_tree/container.vue';
import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue';
-import { MOCK_DEFAULT_CI_FILE } from './constants';
+import { FILE_TREE_TIP_DISMISSED_KEY } from '~/pipeline_editor/constants';
+import { mockCiConfigPath, mockIncludes } from '../../mock_data';
describe('Pipeline editor file nav', () => {
let wrapper;
- const createComponent = ({ stubs } = {}) => {
- wrapper = shallowMount(PipelineEditorFileTreeContainer, {
- provide: {
- ciConfigPath: MOCK_DEFAULT_CI_FILE,
- },
- stubs,
- });
+ const createComponent = ({ includes = mockIncludes, stubs } = {}) => {
+ wrapper = extendedWrapper(
+ shallowMount(PipelineEditorFileTreeContainer, {
+ provide: {
+ ciConfigPath: mockCiConfigPath,
+ },
+ propsData: {
+ includes,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ stubs,
+ }),
+ );
};
const findTip = () => wrapper.findComponent(GlAlert);
- const fileTreeItem = () => wrapper.findComponent(PipelineEditorFileTreeItem);
+ const findCurrentConfigFilename = () => wrapper.findByTestId('current-config-filename');
+ const fileTreeItems = () => wrapper.findAll(PipelineEditorFileTreeItem);
afterEach(() => {
+ localStorage.clear();
wrapper.destroy();
});
@@ -30,27 +43,91 @@ describe('Pipeline editor file nav', () => {
});
it('renders config file as a file item', () => {
- expect(fileTreeItem().exists()).toBe(true);
- expect(fileTreeItem().props('fileName')).toBe(MOCK_DEFAULT_CI_FILE);
+ expect(findCurrentConfigFilename().text()).toBe(mockCiConfigPath);
});
+ });
+
+ describe('when includes list is empty', () => {
+ describe('when dismiss state is not saved in local storage', () => {
+ beforeEach(() => {
+ createComponent({
+ includes: [],
+ stubs: { GlAlert },
+ });
+ });
+
+ it('does not render filenames', () => {
+ expect(fileTreeItems().exists()).toBe(false);
+ });
+
+ it('renders alert tip', async () => {
+ expect(findTip().exists()).toBe(true);
+ });
+
+ it('can dismiss the tip', async () => {
+ expect(findTip().exists()).toBe(true);
- it('renders tip', () => {
- expect(findTip().exists()).toBe(true);
+ findTip().vm.$emit('dismiss');
+ await nextTick();
+
+ expect(findTip().exists()).toBe(false);
+ });
+ });
+
+ describe('when dismiss state is saved in local storage', () => {
+ beforeEach(() => {
+ localStorage.setItem(FILE_TREE_TIP_DISMISSED_KEY, 'true');
+ createComponent({
+ includes: [],
+ stubs: { GlAlert },
+ });
+ });
+
+ it('does not render alert tip', async () => {
+ expect(findTip().exists()).toBe(false);
+ });
+ });
+
+ describe('when component receives new props with includes files', () => {
+ beforeEach(() => {
+ createComponent({ includes: [] });
+ });
+
+ it('hides tip and renders list of files', async () => {
+ expect(findTip().exists()).toBe(true);
+ expect(fileTreeItems()).toHaveLength(0);
+
+ await wrapper.setProps({ includes: mockIncludes });
+
+ expect(findTip().exists()).toBe(false);
+ expect(fileTreeItems()).toHaveLength(mockIncludes.length);
+ });
});
});
- describe('alert tip', () => {
+ describe('when there are includes files', () => {
beforeEach(() => {
createComponent({ stubs: { GlAlert } });
});
- it('can dismiss the tip', async () => {
- expect(findTip().exists()).toBe(true);
+ it('does not render alert tip', () => {
+ expect(findTip().exists()).toBe(false);
+ });
+
+ it('renders the list of files', () => {
+ expect(fileTreeItems()).toHaveLength(mockIncludes.length);
+ });
- findTip().vm.$emit('dismiss');
- await nextTick();
+ describe('when component receives new props with empty includes', () => {
+ it('shows tip and does not render list of files', async () => {
+ expect(findTip().exists()).toBe(false);
+ expect(fileTreeItems()).toHaveLength(mockIncludes.length);
- expect(findTip().exists()).toBe(false);
+ await wrapper.setProps({ includes: [] });
+
+ expect(findTip().exists()).toBe(true);
+ expect(fileTreeItems()).toHaveLength(0);
+ });
});
});
});
diff --git a/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js b/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js
index ec496b01f9a..f12ac14c6be 100644
--- a/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js
+++ b/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js
@@ -1,20 +1,22 @@
+import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue';
-import { MOCK_DEFAULT_CI_FILE } from './constants';
+import { mockIncludesWithBlob, mockDefaultIncludes } from '../../mock_data';
describe('Pipeline editor file nav', () => {
let wrapper;
- const createComponent = () => {
+ const createComponent = ({ file = mockDefaultIncludes } = {}) => {
wrapper = shallowMount(PipelineEditorFileTreeItem, {
propsData: {
- fileName: MOCK_DEFAULT_CI_FILE,
+ file,
},
});
};
const fileIcon = () => wrapper.findComponent(FileIcon);
+ const link = () => wrapper.findComponent(GlLink);
afterEach(() => {
wrapper.destroy();
@@ -27,11 +29,24 @@ describe('Pipeline editor file nav', () => {
it('renders file icon', () => {
expect(fileIcon().exists()).toBe(true);
- expect(fileIcon().props('fileName')).toBe(MOCK_DEFAULT_CI_FILE);
});
it('renders file name', () => {
- expect(wrapper.text()).toBe(MOCK_DEFAULT_CI_FILE);
+ expect(wrapper.text()).toBe(mockDefaultIncludes.location);
+ });
+
+ it('links to raw path by default', () => {
+ expect(link().attributes('href')).toBe(mockDefaultIncludes.raw);
+ });
+ });
+
+ describe('when file has blob link', () => {
+ beforeEach(() => {
+ createComponent({ file: mockIncludesWithBlob });
+ });
+
+ it('links to blob path', () => {
+ expect(link().attributes('href')).toBe(mockIncludesWithBlob.blob);
});
});
});
diff --git a/spec/frontend/pipeline_editor/mock_data.js b/spec/frontend/pipeline_editor/mock_data.js
index f02f6870653..748519dfbae 100644
--- a/spec/frontend/pipeline_editor/mock_data.js
+++ b/spec/frontend/pipeline_editor/mock_data.js
@@ -82,12 +82,46 @@ const mockJobFields = {
__typename: 'CiConfigJob',
};
+export const mockIncludesWithBlob = {
+ location: 'test-include.yml',
+ type: 'local',
+ blob:
+ 'http://gdk.test:3000/root/upstream/-/blob/dd54f00bb3645f8ddce7665d2ffb3864540399cb/test-include.yml',
+ raw:
+ 'http://gdk.test:3000/root/upstream/-/raw/dd54f00bb3645f8ddce7665d2ffb3864540399cb/test-include.yml',
+ __typename: 'CiConfigInclude',
+};
+
+export const mockDefaultIncludes = {
+ location: 'npm.gitlab-ci.yml',
+ type: 'template',
+ blob: null,
+ raw:
+ 'https://gitlab.com/gitlab-org/gitlab/-/raw/master/lib/gitlab/ci/templates/npm.gitlab-ci.yml',
+ __typename: 'CiConfigInclude',
+};
+
+export const mockIncludes = [
+ mockDefaultIncludes,
+ mockIncludesWithBlob,
+ {
+ location: 'a_really_really_long_name_for_includes_file.yml',
+ type: 'local',
+ blob:
+ 'http://gdk.test:3000/root/upstream/-/blob/dd54f00bb3645f8ddce7665d2ffb3864540399cb/a_really_really_long_name_for_includes_file.yml',
+ raw:
+ 'http://gdk.test:3000/root/upstream/-/raw/dd54f00bb3645f8ddce7665d2ffb3864540399cb/a_really_really_long_name_for_includes_file.yml',
+ __typename: 'CiConfigInclude',
+ },
+];
+
// Mock result of the graphql query at:
// app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql
export const mockCiConfigQueryResponse = {
data: {
ciConfig: {
errors: [],
+ includes: mockIncludes,
mergedYaml: mockCiYml,
status: CI_CONFIG_STATUS_VALID,
stages: {
diff --git a/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
index 35d3224d5ba..ae368e4d37e 100644
--- a/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
+++ b/spec/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe Mutations::DependencyProxy::GroupSettings::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the dependency proxy group settings'
- :developer | 'updating the dependency proxy group settings'
+ :developer | 'denying access to dependency proxy group settings'
:reporter | 'denying access to dependency proxy group settings'
:guest | 'denying access to dependency proxy group settings'
:anonymous | 'denying access to dependency proxy group settings'
diff --git a/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
index 792e87f0d25..1e5059d7ef7 100644
--- a/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
+++ b/spec/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe Mutations::DependencyProxy::ImageTtlGroupPolicy::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the dependency proxy image ttl policy'
- :developer | 'updating the dependency proxy image ttl policy'
+ :developer | 'denying access to dependency proxy image ttl policy'
:reporter | 'denying access to dependency proxy image ttl policy'
:guest | 'denying access to dependency proxy image ttl policy'
:anonymous | 'denying access to dependency proxy image ttl policy'
@@ -92,7 +92,7 @@ RSpec.describe Mutations::DependencyProxy::ImageTtlGroupPolicy::Update do
where(:user_role, :shared_examples_name) do
:maintainer | 'creating the dependency proxy image ttl policy'
- :developer | 'creating the dependency proxy image ttl policy'
+ :developer | 'denying access to dependency proxy image ttl policy'
:reporter | 'denying access to dependency proxy image ttl policy'
:guest | 'denying access to dependency proxy image ttl policy'
:anonymous | 'denying access to dependency proxy image ttl policy'
diff --git a/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb b/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb
index 7c6d7b8aece..cd648cf4b4d 100644
--- a/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb
+++ b/spec/graphql/types/dependency_proxy/group_setting_type_spec.rb
@@ -10,4 +10,10 @@ RSpec.describe GitlabSchema.types['DependencyProxySetting'] do
expect(described_class).to include_graphql_fields(*expected_fields)
end
+
+ it { expect(described_class).to require_graphql_authorizations(:admin_dependency_proxy) }
+
+ it { expect(described_class.graphql_name).to eq('DependencyProxySetting') }
+
+ it { expect(described_class.description).to eq('Group-level Dependency Proxy settings') }
end
diff --git a/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb b/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb
index 46347e0434f..af0f91a844e 100644
--- a/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb
+++ b/spec/graphql/types/dependency_proxy/image_ttl_group_policy_type_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['DependencyProxyImageTtlGroupPolicy'] do
it { expect(described_class.description).to eq('Group-level Dependency Proxy TTL policy settings') }
- it { expect(described_class).to require_graphql_authorizations(:read_dependency_proxy) }
+ it { expect(described_class).to require_graphql_authorizations(:admin_dependency_proxy) }
it 'includes dependency proxy image ttl policy fields' do
expected_fields = %w[enabled ttl created_at updated_at]
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index e8d3f165fb9..d64b59282a2 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -914,12 +914,21 @@ RSpec.describe GroupPolicy do
context 'reporter' do
let(:current_user) { reporter }
+ it { is_expected.to be_allowed(:read_dependency_proxy) }
it { is_expected.to be_disallowed(:admin_dependency_proxy) }
end
context 'developer' do
let(:current_user) { developer }
+ it { is_expected.to be_allowed(:read_dependency_proxy) }
+ it { is_expected.to be_disallowed(:admin_dependency_proxy) }
+ end
+
+ context 'maintainer' do
+ let(:current_user) { maintainer }
+
+ it { is_expected.to be_allowed(:read_dependency_proxy) }
it { is_expected.to be_allowed(:admin_dependency_proxy) }
end
end
diff --git a/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
index de3dbc5c324..d21c3046c1a 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
@@ -47,14 +47,14 @@ RSpec.describe 'getting dependency proxy settings for a group' do
context 'with different permissions' do
where(:group_visibility, :role, :access_granted) do
:private | :maintainer | true
- :private | :developer | true
- :private | :reporter | true
- :private | :guest | true
+ :private | :developer | false
+ :private | :reporter | false
+ :private | :guest | false
:private | :anonymous | false
:public | :maintainer | true
- :public | :developer | true
- :public | :reporter | true
- :public | :guest | true
+ :public | :developer | false
+ :public | :reporter | false
+ :public | :guest | false
:public | :anonymous | false
end
diff --git a/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
index c8797d84906..40f4b082072 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
@@ -46,14 +46,14 @@ RSpec.describe 'getting dependency proxy image ttl policy for a group' do
context 'with different permissions' do
where(:group_visibility, :role, :access_granted) do
:private | :maintainer | true
- :private | :developer | true
- :private | :reporter | true
- :private | :guest | true
+ :private | :developer | false
+ :private | :reporter | false
+ :private | :guest | false
:private | :anonymous | false
:public | :maintainer | true
- :public | :developer | true
- :public | :reporter | true
- :public | :guest | true
+ :public | :developer | false
+ :public | :reporter | false
+ :public | :guest | false
:public | :anonymous | false
end
diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
index f05bf23ad27..9eb13e534ac 100644
--- a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe 'Updating the dependency proxy group settings' do
context 'with permission' do
before do
- group.add_developer(user)
+ group.add_maintainer(user)
end
it 'returns the updated dependency proxy settings', :aggregate_failures do
diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
index c9e9a22ee0b..31ba7ecdf0e 100644
--- a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe 'Updating the dependency proxy image ttl policy' do
context 'with permission' do
before do
- group.add_developer(user)
+ group.add_maintainer(user)
end
it 'returns the updated dependency proxy image ttl policy', :aggregate_failures do
diff --git a/spec/services/dependency_proxy/group_settings/update_service_spec.rb b/spec/services/dependency_proxy/group_settings/update_service_spec.rb
index 6f8c55daa8d..4954d9ec267 100644
--- a/spec/services/dependency_proxy/group_settings/update_service_spec.rb
+++ b/spec/services/dependency_proxy/group_settings/update_service_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe ::DependencyProxy::GroupSettings::UpdateService do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the dependency proxy group settings'
- :developer | 'updating the dependency proxy group settings'
+ :developer | 'denying access to dependency proxy group settings'
:reporter | 'denying access to dependency proxy group settings'
:guest | 'denying access to dependency proxy group settings'
:anonymous | 'denying access to dependency proxy group settings'
diff --git a/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb b/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb
index ceac8985c8e..3a6ba2cca71 100644
--- a/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb
+++ b/spec/services/dependency_proxy/image_ttl_group_policies/update_service_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe ::DependencyProxy::ImageTtlGroupPolicies::UpdateService do
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the dependency proxy image ttl policy'
- :developer | 'updating the dependency proxy image ttl policy'
+ :developer | 'denying access to dependency proxy image ttl policy'
:reporter | 'denying access to dependency proxy image ttl policy'
:guest | 'denying access to dependency proxy image ttl policy'
:anonymous | 'denying access to dependency proxy image ttl policy'
@@ -92,7 +92,7 @@ RSpec.describe ::DependencyProxy::ImageTtlGroupPolicies::UpdateService do
where(:user_role, :shared_examples_name) do
:maintainer | 'creating the dependency proxy image ttl policy'
- :developer | 'creating the dependency proxy image ttl policy'
+ :developer | 'denying access to dependency proxy image ttl policy'
:reporter | 'denying access to dependency proxy image ttl policy'
:guest | 'denying access to dependency proxy image ttl policy'
:anonymous | 'denying access to dependency proxy image ttl policy'
@@ -108,7 +108,7 @@ RSpec.describe ::DependencyProxy::ImageTtlGroupPolicies::UpdateService do
context 'when the policy is not found' do
before do
- group.add_developer(user)
+ group.add_maintainer(user)
expect(group).to receive(:dependency_proxy_image_ttl_policy).and_return nil
end
diff --git a/spec/workers/deployments/hooks_worker_spec.rb b/spec/workers/deployments/hooks_worker_spec.rb
index 29b3e8d3ee4..a9240b45360 100644
--- a/spec/workers/deployments/hooks_worker_spec.rb
+++ b/spec/workers/deployments/hooks_worker_spec.rb
@@ -10,6 +10,16 @@ RSpec.describe Deployments::HooksWorker do
allow(ProjectServiceWorker).to receive(:perform_async)
end
+ it 'logs deployment and project IDs as metadata' do
+ deployment = create(:deployment, :running)
+ project = deployment.project
+
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:deployment_project_id, project.id)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:deployment_id, deployment.id)
+
+ worker.perform(deployment_id: deployment.id, status_changed_at: Time.current)
+ end
+
it 'executes project services for deployment_hooks' do
deployment = create(:deployment, :running)
project = deployment.project
diff --git a/vendor/project_templates/cluster_management.tar.gz b/vendor/project_templates/cluster_management.tar.gz
index 843a8a355f1..97e18dc859b 100644
--- a/vendor/project_templates/cluster_management.tar.gz
+++ b/vendor/project_templates/cluster_management.tar.gz
Binary files differ
diff --git a/yarn.lock b/yarn.lock
index 4a7759b86d6..54aa0ac7550 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3893,10 +3893,10 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^3.22.4:
- version "3.22.4"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.4.tgz#f4b3f108d45736935aa028444a69397e40d8c531"
- integrity sha512-1uLykR+iOfYja+6Jn/57743gc9n73EWiOnSJJ4ba3B4fOEYDBv25MagmEZBxTp5cWq4b/KPx/l77zgsp28ju4w==
+core-js@^3.22.5:
+ version "3.22.5"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.5.tgz#a5f5a58e663d5c0ebb4e680cd7be37536fb2a9cf"
+ integrity sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA==
core-js@~2.3.0:
version "2.3.0"