summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 18:09:10 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 18:09:10 +0000
commita3764262c04bafcd6a54aff635541d73a8a630fd (patch)
treeea54444857967f08b7601886b47d15819990b6cf
parent049d16d168fdee408b78f5f38619c092fd3b2265 (diff)
downloadgitlab-ce-a3764262c04bafcd6a54aff635541d73a8a630fd.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.rubocop_todo/gitlab/json.yml6
-rw-r--r--.rubocop_todo/layout/line_length.yml2
-rw-r--r--.rubocop_todo/style/if_unless_modifier.yml2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum4
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/issuable/components/related_issuable_item.vue1
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue106
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue6
-rw-r--r--app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql5
-rw-r--r--app/controllers/jira_connect/subscriptions_controller.rb2
-rw-r--r--app/models/namespace.rb6
-rw-r--r--app/models/personal_access_token.rb33
-rw-r--r--app/views/admin/application_settings/general.html.haml2
-rw-r--r--app/views/ci/variables/_url_query_variable_row.html.haml28
-rw-r--r--app/views/shared/access_tokens/_created_container.html.haml12
-rw-r--r--app/views/shared/access_tokens/_table.html.haml51
-rw-r--r--config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml8
-rw-r--r--db/docs/software_license_policies.yml2
-rw-r--r--db/docs/software_licenses.yml2
-rw-r--r--db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb19
-rw-r--r--db/schema_migrations/202210132158321
-rw-r--r--doc/api/remote_mirrors.md31
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/index.md13
-rw-r--r--doc/ci/pipelines/downstream_pipelines.md5
-rw-r--r--doc/ci/testing/unit_test_report_examples.md3
-rw-r--r--doc/development/sidekiq/worker_attributes.md2
-rw-r--r--lib/api/integrations/jira_connect/subscriptions.rb2
-rw-r--r--lib/gitlab/ci/variables/collection.rb3
-rw-r--r--lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb50
-rw-r--r--lib/tasks/gitlab/gitaly.rake2
-rw-r--r--lib/tasks/gitlab/tw/codeowners.rake4
-rw-r--r--locale/gitlab.pot18
-rw-r--r--qa/qa/page/component/access_tokens.rb8
-rw-r--r--qa/qa/specs/features/api/1_manage/project_access_token_spec.rb8
-rw-r--r--spec/features/issues/user_sorts_issues_spec.rb2
-rw-r--r--spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js50
-rw-r--r--spec/lib/gitlab/ci/variables/collection_spec.rb3
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb161
-rw-r--r--spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb49
-rw-r--r--spec/models/namespace_spec.rb6
-rw-r--r--spec/models/personal_access_token_spec.rb55
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb3
-rw-r--r--spec/requests/api/integrations/jira_connect/subscriptions_spec.rb2
-rw-r--r--spec/requests/jira_connect/subscriptions_controller_spec.rb4
-rw-r--r--spec/support/rspec_order_todo.yml2
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb8
-rw-r--r--spec/views/admin/application_settings/general.html.haml_spec.rb4
-rw-r--r--spec/views/shared/access_tokens/_table.html.haml_spec.rb151
50 files changed, 517 insertions, 440 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 689c05f4874..3d2f32a0390 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -127,7 +127,7 @@ variables:
# Run with decomposed databases by default
DECOMPOSED_DB: "true"
- DOCS_REVIEW_APPS_DOMAIN: "35.193.151.162.nip.io"
+ DOCS_REVIEW_APPS_DOMAIN: "docs.gitlab-review-app"
DOCS_GITLAB_REPO_SUFFIX: "ee"
REVIEW_APPS_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/ruby-3.0:gcloud-383-kubectl-1.23-helm-3.5"
diff --git a/.rubocop_todo/gitlab/json.yml b/.rubocop_todo/gitlab/json.yml
index 9a946f11f84..ec48c04f3ed 100644
--- a/.rubocop_todo/gitlab/json.yml
+++ b/.rubocop_todo/gitlab/json.yml
@@ -1,5 +1,5 @@
---
-# Cop supports --auto-correct.
+# Cop supports --autocorrect.
Gitlab/Json:
Details: grace period
Exclude:
@@ -247,6 +247,7 @@ Gitlab/Json:
- 'lib/gitlab/database/background_migration/batched_migration.rb'
- 'lib/gitlab/database/background_migration_job.rb'
- 'lib/gitlab/database/migration_helpers.rb'
+ - 'lib/gitlab/database/migrations/batched_background_migration_helpers.rb'
- 'lib/gitlab/database/migrations/instrumentation.rb'
- 'lib/gitlab/database/migrations/runner.rb'
- 'lib/gitlab/database/postgres_hll/buckets.rb'
@@ -284,6 +285,7 @@ Gitlab/Json:
- 'lib/microsoft_teams/notifier.rb'
- 'lib/tasks/gitlab/background_migrations.rake'
- 'lib/version_check.rb'
+ - 'spec/commands/diagnostic_reports/uploader_smoke_spec.rb'
- 'spec/controllers/admin/integrations_controller_spec.rb'
- 'spec/controllers/concerns/product_analytics_tracking_spec.rb'
- 'spec/controllers/groups/settings/integrations_controller_spec.rb'
@@ -417,7 +419,9 @@ Gitlab/Json:
- 'spec/requests/api/merge_requests_spec.rb'
- 'spec/requests/api/namespaces_spec.rb'
- 'spec/requests/api/project_snapshots_spec.rb'
+ - 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- 'spec/requests/projects/incident_management/pagerduty_incidents_spec.rb'
+ - 'spec/requests/projects/settings/access_tokens_controller_spec.rb'
- 'spec/requests/users_controller_spec.rb'
- 'spec/requests/whats_new_controller_spec.rb'
- 'spec/scripts/pipeline_test_report_builder_spec.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index fe9c0593f7d..eaa8e6485be 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -2855,7 +2855,6 @@ Layout/LineLength:
- 'ee/spec/views/registrations/welcome/show.html.haml_spec.rb'
- 'ee/spec/views/shared/_mirror_status.html.haml_spec.rb'
- 'ee/spec/views/shared/_namespace_user_cap_reached_alert.html.haml_spec.rb'
- - 'ee/spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'ee/spec/views/shared/billings/_eoa_bronze_plan_banner.html.haml_spec.rb'
- 'ee/spec/views/shared/billings/_trial_status.html.haml_spec.rb'
- 'ee/spec/views/shared/credentials_inventory/personal_access_tokens/_personal_access_token.html.haml_spec.rb'
@@ -5968,7 +5967,6 @@ Layout/LineLength:
- 'spec/views/projects/tags/index.html.haml_spec.rb'
- 'spec/views/projects/tree/show.html.haml_spec.rb'
- 'spec/views/search/_results.html.haml_spec.rb'
- - 'spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'spec/views/shared/milestones/_issuable.html.haml_spec.rb'
- 'spec/views/shared/projects/_project.html.haml_spec.rb'
- 'spec/views/shared/snippets/_snippet.html.haml_spec.rb'
diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml
index 8e295c68623..16d163ebdfc 100644
--- a/.rubocop_todo/style/if_unless_modifier.yml
+++ b/.rubocop_todo/style/if_unless_modifier.yml
@@ -743,7 +743,6 @@ Style/IfUnlessModifier:
- 'ee/spec/support/http_io/http_io_helpers.rb'
- 'ee/spec/support/shared_examples/requests/api/graphql/geo/registries_shared_examples.rb'
- 'ee/spec/views/layouts/header/help_dropdown/_cross_stage_fdm.html.haml_spec.rb'
- - 'ee/spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'ee/spec/workers/elastic/migration_worker_spec.rb'
- 'lib/api/api_guard.rb'
- 'lib/api/boards_responses.rb'
@@ -1202,7 +1201,6 @@ Style/IfUnlessModifier:
- 'spec/views/groups/edit.html.haml_spec.rb'
- 'spec/views/profiles/keys/_key.html.haml_spec.rb'
- 'spec/views/projects/edit.html.haml_spec.rb'
- - 'spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'spec/workers/analytics/usage_trends/counter_job_worker_spec.rb'
- 'tooling/danger/product_intelligence.rb'
- 'tooling/lib/tooling/find_codeowners.rb'
diff --git a/Gemfile b/Gemfile
index 3cd30bb4599..ad032aa0119 100644
--- a/Gemfile
+++ b/Gemfile
@@ -428,7 +428,7 @@ group :development, :test do
end
group :development, :test, :danger do
- gem 'gitlab-dangerfiles', '~> 3.5.2', require: false
+ gem 'gitlab-dangerfiles', '~> 3.6.1', require: false
end
group :development, :test, :coverage do
diff --git a/Gemfile.checksum b/Gemfile.checksum
index c145415591b..74500a24d73 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -151,7 +151,7 @@
{"name":"faraday-em_http","version":"1.0.0","platform":"ruby","checksum":"7a3d4c7079789121054f57e08cd4ef7e40ad1549b63101f38c7093a9d6c59689"},
{"name":"faraday-em_synchrony","version":"1.0.0","platform":"ruby","checksum":"460dad1c30cc692d6e77d4c391ccadb4eca4854b315632cd7e560f74275cf9ed"},
{"name":"faraday-excon","version":"1.1.0","platform":"ruby","checksum":"b055c842376734d7f74350fe8611542ae2000c5387348d9ba9708109d6e40940"},
-{"name":"faraday-http-cache","version":"2.4.0","platform":"ruby","checksum":"388f901d63bd5903b470c5696bc886ed94fab0c4206b25c3761e7b9bdbbf6c90"},
+{"name":"faraday-http-cache","version":"2.4.1","platform":"ruby","checksum":"fb51b2e9ee72f89e81cc277ee574dbc5940f3db95431b3533de9882f92635ee3"},
{"name":"faraday-httpclient","version":"1.0.1","platform":"ruby","checksum":"4c8ff1f0973ff835be8d043ef16aaf54f47f25b7578f6d916deee8399a04d33b"},
{"name":"faraday-multipart","version":"1.0.4","platform":"ruby","checksum":"9012021ab57790f7d712f590b48d5f948b19b43cfa11ca83e6459f06090b0725"},
{"name":"faraday-net_http","version":"1.0.1","platform":"ruby","checksum":"3245ce406ebb77b40e17a77bfa66191dda04be2fd4e13a78d8a4305854d328ba"},
@@ -202,7 +202,7 @@
{"name":"github-markup","version":"1.7.0","platform":"ruby","checksum":"97eb27c70662d9cc1d5997cd6c99832026fae5d4913b5dce1ce6c9f65078e69d"},
{"name":"gitlab","version":"4.16.1","platform":"ruby","checksum":"13fd7059cbdad5a1a21b15fa2cf9070b97d92e27f8c688581fe3d84dc038074f"},
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
-{"name":"gitlab-dangerfiles","version":"3.5.2","platform":"ruby","checksum":"fae28a55b83b6c7f8298b9b1d90354ae73636729fd829ad58326bef46bd2f01f"},
+{"name":"gitlab-dangerfiles","version":"3.6.1","platform":"ruby","checksum":"f7b69b093d52acb89095d411cb7b8849f5f3b9e76f8baa4c99b5671f1564865f"},
{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
{"name":"gitlab-fog-azure-rm","version":"1.3.0","platform":"ruby","checksum":"2fef5317d6515f95f803099afa860fe3019ce6e1907bf49f66b5e06468a617b5"},
{"name":"gitlab-labkit","version":"0.24.0","platform":"ruby","checksum":"8f16e5aa4e0a05be58958fe880bdd53c84b659a081ea9981d2b510922a4a0548"},
diff --git a/Gemfile.lock b/Gemfile.lock
index d2b6d367ae4..8d2b983cf00 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -448,7 +448,7 @@ GEM
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
- faraday-http-cache (2.4.0)
+ faraday-http-cache (2.4.1)
faraday (>= 0.8)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
@@ -555,7 +555,7 @@ GEM
terminal-table (~> 1.5, >= 1.5.1)
gitlab-chronic (0.10.5)
numerizer (~> 0.2)
- gitlab-dangerfiles (3.5.2)
+ gitlab-dangerfiles (3.6.1)
danger (>= 8.4.5)
danger-gitlab (>= 8.0.0)
rake
@@ -1627,7 +1627,7 @@ DEPENDENCIES
gitaly (~> 15.4.0.pre.rc2)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
- gitlab-dangerfiles (~> 3.5.2)
+ gitlab-dangerfiles (~> 3.6.1)
gitlab-experiment (~> 0.7.1)
gitlab-fog-azure-rm (~> 1.3.0)
gitlab-labkit (~> 0.24.0)
diff --git a/app/assets/javascripts/issuable/components/related_issuable_item.vue b/app/assets/javascripts/issuable/components/related_issuable_item.vue
index 8894e8f63b8..254248ef1d4 100644
--- a/app/assets/javascripts/issuable/components/related_issuable_item.vue
+++ b/app/assets/javascripts/issuable/components/related_issuable_item.vue
@@ -141,6 +141,7 @@ export default {
<gl-link
:href="computedPath"
class="sortable-link gl-font-weight-normal"
+ target="_blank"
@click="handleTitleClick"
>
{{ title }}
diff --git a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
index 4a08a82275a..b055b89c528 100644
--- a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
+++ b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
@@ -1,6 +1,8 @@
<script>
-import { GlAlert, GlLoadingIcon, GlModal } from '@gitlab/ui';
+import { GlAlert, GlBadge, GlButton, GlLoadingIcon, GlModal, GlTabs, GlTab } from '@gitlab/ui';
import { s__, __ } from '~/locale';
+import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
+import { queryToObject } from '~/lib/utils/url_utility';
import deletePipelineScheduleMutation from '../graphql/mutations/delete_pipeline_schedule.mutation.graphql';
import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql';
import PipelineSchedulesTable from './table/pipeline_schedules_table.vue';
@@ -11,6 +13,7 @@ export default {
scheduleDeleteError: s__(
'PipelineSchedules|There was a problem deleting the pipeline schedule.',
),
+ newSchedule: s__('PipelineSchedules|New schedule'),
},
modal: {
id: 'delete-pipeline-schedule-modal',
@@ -28,8 +31,12 @@ export default {
},
components: {
GlAlert,
+ GlBadge,
+ GlButton,
GlLoadingIcon,
GlModal,
+ GlTabs,
+ GlTab,
PipelineSchedulesTable,
},
inject: {
@@ -43,10 +50,16 @@ export default {
variables() {
return {
projectPath: this.fullPath,
+ status: this.scope,
};
},
- update({ project }) {
- return project?.pipelineSchedules?.nodes || [];
+ update(data) {
+ const { pipelineSchedules: { nodes: list = [], count } = {} } = data.project || {};
+
+ return {
+ list,
+ count,
+ };
},
error() {
this.reportError(this.$options.i18n.schedulesFetchError);
@@ -54,18 +67,58 @@ export default {
},
},
data() {
+ const { scope } = queryToObject(window.location.search);
return {
- schedules: [],
+ schedules: {
+ list: [],
+ },
+ scope,
hasError: false,
errorMessage: '',
scheduleToDeleteId: null,
showModal: false,
+ count: 0,
};
},
computed: {
isLoading() {
return this.$apollo.queries.schedules.loading;
},
+ schedulesCount() {
+ return this.schedules.count;
+ },
+ tabs() {
+ return [
+ {
+ text: s__('PipelineSchedules|All'),
+ count: limitedCounterWithDelimiter(this.count),
+ scope: null,
+ showBadge: true,
+ attrs: { 'data-testid': 'pipeline-schedules-all-tab' },
+ },
+ {
+ text: s__('PipelineSchedules|Active'),
+ scope: 'ACTIVE',
+ showBadge: false,
+ attrs: { 'data-testid': 'pipeline-schedules-active-tab' },
+ },
+ {
+ text: s__('PipelineSchedules|Inactive'),
+ scope: 'INACTIVE',
+ showBadge: false,
+ attrs: { 'data-testid': 'pipeline-schedules-inactive-tab' },
+ },
+ ];
+ },
+ },
+ watch: {
+ // this watcher ensures that the count on the all tab
+ // is not updated when switching to other tabs
+ schedulesCount(newCount) {
+ if (!this.scope) {
+ this.count = newCount;
+ }
+ },
},
methods: {
reportError(error) {
@@ -100,6 +153,10 @@ export default {
this.reportError(this.$options.i18n.scheduleDeleteError);
}
},
+ fetchPipelineSchedulesByStatus(scope) {
+ this.scope = scope;
+ this.$apollo.queries.schedules.refetch();
+ },
},
};
</script>
@@ -110,12 +167,45 @@ export default {
{{ errorMessage }}
</gl-alert>
- <gl-loading-icon v-if="isLoading" size="lg" />
+ <template v-else>
+ <gl-tabs
+ sync-active-tab-with-query-params
+ query-param-name="scope"
+ nav-class="gl-flex-grow-1 gl-align-items-center"
+ >
+ <gl-tab
+ v-for="tab in tabs"
+ :key="tab.text"
+ :title-link-attributes="tab.attrs"
+ :query-param-value="tab.scope"
+ @click="fetchPipelineSchedulesByStatus(tab.scope)"
+ >
+ <template #title>
+ <span>{{ tab.text }}</span>
- <!-- Tabs will be addressed in #371989 -->
+ <template v-if="tab.showBadge">
+ <gl-loading-icon v-if="tab.scope === scope && isLoading" class="gl-ml-2" />
- <template v-else>
- <pipeline-schedules-table :schedules="schedules" @showDeleteModal="showDeleteModal" />
+ <gl-badge v-else-if="tab.count" size="sm" class="gl-tab-counter-badge">
+ {{ tab.count }}
+ </gl-badge>
+ </template>
+ </template>
+
+ <gl-loading-icon v-if="isLoading" size="lg" />
+ <pipeline-schedules-table
+ v-else
+ :schedules="schedules.list"
+ @showDeleteModal="showDeleteModal"
+ />
+ </gl-tab>
+
+ <template #tabs-end>
+ <gl-button variant="confirm" class="gl-ml-auto" data-testid="new-schedule-button">
+ {{ $options.i18n.newSchedule }}
+ </gl-button>
+ </template>
+ </gl-tabs>
<gl-modal
:visible="showModal"
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue b/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
index d54008b81b2..da2157a8851 100644
--- a/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
+++ b/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
@@ -12,31 +12,37 @@ export default {
{
key: 'description',
label: s__('PipelineSchedules|Description'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-40p',
},
{
key: 'target',
label: s__('PipelineSchedules|Target'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-10p',
},
{
key: 'pipeline',
label: s__('PipelineSchedules|Last Pipeline'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-10p',
},
{
key: 'next',
label: s__('PipelineSchedules|Next Run'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-15p',
},
{
key: 'owner',
label: s__('PipelineSchedules|Owner'),
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-10p',
},
{
key: 'actions',
label: '',
+ thClass: 'gl-border-t-none!',
columnClass: 'gl-w-15p',
},
],
diff --git a/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql b/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
index 7d9d658b1b6..9f6cb429cca 100644
--- a/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
+++ b/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
@@ -1,7 +1,8 @@
-query getPipelineSchedulesQuery($projectPath: ID!) {
+query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStatus) {
project(fullPath: $projectPath) {
id
- pipelineSchedules {
+ pipelineSchedules(status: $status) {
+ count
nodes {
id
description
diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb
index 9305f46c39e..751481f78e2 100644
--- a/app/controllers/jira_connect/subscriptions_controller.rb
+++ b/app/controllers/jira_connect/subscriptions_controller.rb
@@ -64,7 +64,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
private
def allow_self_managed_content_security_policy
- return unless Feature.enabled?(:jira_connect_oauth_self_managed)
+ return unless Feature.enabled?(:jira_connect_oauth_self_managed_setting)
return unless current_jira_installation.instance_url?
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 42f362876bb..12b96f34316 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -40,9 +40,9 @@ class Namespace < ApplicationRecord
PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
- # The first date in https://docs.gitlab.com/ee/user/usage_quotas.html#namespace-storage-limit-enforcement-schedule
- # Determines when we start enforcing namespace storage
- MIN_STORAGE_ENFORCEMENT_DATE = Date.new(2022, 10, 19)
+ # This date is just a placeholder until namespace storage enforcement timeline is confirmed at which point
+ # this should be replaced, see https://about.gitlab.com/pricing/faq-efficient-free-tier/#user-limits-on-gitlab-saas-free-tier
+ MIN_STORAGE_ENFORCEMENT_DATE = 3.months.from_now.to_date
# https://gitlab.com/gitlab-org/gitlab/-/issues/367531
MIN_STORAGE_ENFORCEMENT_USAGE = 5.gigabytes
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index f0ed1822da6..3126dba9d6d 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -11,8 +11,6 @@ class PersonalAccessToken < ApplicationRecord
add_authentication_token_field :token, digest: true
- REDIS_EXPIRY_TIME = 3.minutes
-
# PATs are 20 characters + optional configurable settings prefix (0..20)
TOKEN_LENGTH_RANGE = (20..40).freeze
@@ -34,8 +32,6 @@ class PersonalAccessToken < ApplicationRecord
scope :for_user, -> (user) { where(user: user) }
scope :for_users, -> (users) { where(user: users) }
scope :preload_users, -> { preload(:user) }
- scope :order_expires_at_asc, -> { reorder(expires_at: :asc) }
- scope :order_expires_at_desc, -> { reorder(expires_at: :desc) }
scope :order_expires_at_asc_id_desc, -> { reorder(expires_at: :asc, id: :desc) }
scope :project_access_token, -> { includes(:user).where(user: { user_type: :project_bot }) }
scope :owner_is_human, -> { includes(:user).where(user: { user_type: :human }) }
@@ -55,35 +51,10 @@ class PersonalAccessToken < ApplicationRecord
!revoked? && !expired?
end
- def self.redis_getdel(user_id)
- Gitlab::Redis::SharedState.with do |redis|
- redis_key = redis_shared_state_key(user_id)
- encrypted_token = redis.get(redis_key)
- redis.del(redis_key)
-
- begin
- Gitlab::CryptoHelper.aes256_gcm_decrypt(encrypted_token)
- rescue StandardError => e
- logger.warn "Failed to decrypt #{self.name} value stored in Redis for key ##{redis_key}: #{e.class}"
- encrypted_token
- end
- end
- end
-
- def self.redis_store!(user_id, token)
- encrypted_token = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
-
- Gitlab::Redis::SharedState.with do |redis|
- redis.set(redis_shared_state_key(user_id), encrypted_token, ex: REDIS_EXPIRY_TIME)
- end
- end
-
override :simple_sorts
def self.simple_sorts
super.merge(
{
- 'expires_at_asc' => -> { order_expires_at_asc },
- 'expires_at_desc' => -> { order_expires_at_desc },
'expires_at_asc_id_desc' => -> { order_expires_at_asc_id_desc }
}
)
@@ -121,10 +92,6 @@ class PersonalAccessToken < ApplicationRecord
self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty?
end
-
- def self.redis_shared_state_key(user_id)
- "gitlab:personal_access_token:#{user_id}"
- end
end
PersonalAccessToken.prepend_mod_with('PersonalAccessToken')
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index ec5d1ef4a34..db407ae35c4 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -123,4 +123,4 @@
= render 'admin/application_settings/eks'
= render 'admin/application_settings/floc'
= render_if_exists 'admin/application_settings/add_license'
-= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth, current_user)
+= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth_self_managed_setting, current_user)
diff --git a/app/views/ci/variables/_url_query_variable_row.html.haml b/app/views/ci/variables/_url_query_variable_row.html.haml
deleted file mode 100644
index 77bcacdb94b..00000000000
--- a/app/views/ci/variables/_url_query_variable_row.html.haml
+++ /dev/null
@@ -1,28 +0,0 @@
-- form_field = local_assigns.fetch(:form_field, nil)
-- variable = local_assigns.fetch(:variable, nil)
-
-- key = variable[0]
-- value = variable[1]
-- variable_type = variable[2] || "env_var"
-
-- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
-- variable_type_input_name = "#{form_field}[variables_attributes][][variable_type]"
-- key_input_name = "#{form_field}[variables_attributes][][key]"
-- value_input_name = "#{form_field}[variables_attributes][][secret_value]"
-
-%li.js-row.ci-variable-row
- .ci-variable-row-body.border-bottom
- %input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
- %select.js-ci-variable-input-variable-type.ci-variable-body-item.form-control.select-control.custom-select.table-section.section-15{ name: variable_type_input_name }
- = options_for_select(ci_variable_type_options, variable_type)
- %input.js-ci-variable-input-key.ci-variable-body-item.form-control.table-section.section-15{ type: "text",
- name: key_input_name,
- value: key,
- placeholder: s_('CiVariables|Input variable key') }
- .ci-variable-body-item.gl-show-field-errors.table-section.section-15.border-top-0.p-0
- %textarea.js-ci-variable-input-value.js-secret-value.form-control{ rows: 1,
- name: value_input_name,
- placeholder: s_('CiVariables|Input variable value') }
- = value
- %button.gl-button.btn.btn-default.btn-icon.btn-item-remove.js-row-remove-button.ci-variable-row-remove-button.table-section{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
- = sprite_icon('close')
diff --git a/app/views/shared/access_tokens/_created_container.html.haml b/app/views/shared/access_tokens/_created_container.html.haml
deleted file mode 100644
index c0aaa46e761..00000000000
--- a/app/views/shared/access_tokens/_created_container.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-.created-personal-access-token-container
- %h5.gl-mt-0
- = _('Your new %{type}') % { type: type }
- .form-group
- .input-group
- = text_field_tag 'created-personal-access-token', new_token_value, readonly: true, class: 'form-control js-select-on-focus', data: { qa_selector: 'created_access_token_field' }, 'aria-describedby' => 'created-token-help-block'
- %span.input-group-append
- = clipboard_button(text: new_token_value, title: _('Copy %{type}') % { type: type }, placement: 'left', class: 'input-group-text btn-default btn-clipboard')
- %span#created-token-help-block.form-text.text-muted.text-danger
- = _("Make sure you save it - you won't be able to access it again.")
-
-%hr
diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml
deleted file mode 100644
index 53c6800f93d..00000000000
--- a/app/views/shared/access_tokens/_table.html.haml
+++ /dev/null
@@ -1,51 +0,0 @@
-- no_active_tokens_message = local_assigns.fetch(:no_active_tokens_message, _('This user has no active %{type}.') % { type: type_plural })
-- impersonation = local_assigns.fetch(:impersonation, false)
-- resource = local_assigns.fetch(:resource, false)
-
-%hr
-
-%h5
- = _('Active %{type} (%{token_length})') % { type: type_plural, token_length: active_tokens.length }
-
-- if impersonation
- %p.profile-settings-content
- = _("To see all the user's personal access tokens you must impersonate them first.")
-
-- if active_tokens.present?
- .table-responsive
- %table.table.active-tokens
- %thead
- %tr
- %th= _('Token name')
- %th= _('Scopes')
- %th= s_('AccessTokens|Created')
- %th
- = _('Last Used')
- = link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'view-the-last-time-a-token-was-used'), target: '_blank', rel: 'noopener noreferrer'
- %th= _('Expires')
- - if resource
- %th= _('Role')
- %th
- %tbody
- - active_tokens.each do |token|
- %tr
- %td= token.name
- %td= token.scopes.present? ? token.scopes.join(', ') : _('no scopes selected')
- %td= token.created_at.to_date.to_s(:medium)
- %td
- - if token.last_used_at?
- %span.token-last-used-label= _(time_ago_with_tooltip(token.last_used_at))
- - else
- %span.token-never-used-label= _('Never')
- %td
- - if token.expires?
- %span{ class: ('text-warning' if token.expires_soon?) }
- = time_ago_with_tooltip(token.expires_at)
- - else
- %span.token-never-expires-label= _('Never')
- - if resource
- %td= resource.member(token.user).human_access
- %td= link_to _('Revoke'), revoke_route_helper.call(token), method: :put, class: "gl-button btn btn-danger btn-sm float-right #{'btn-danger-secondary' unless token.expires?}", aria: { label: _('Revoke') }, data: { confirm: _('Are you sure you want to revoke this %{type}? This action cannot be undone.') % { type: type }, 'confirm-btn-variant': 'danger', qa_selector: 'revoke_button' }
-- else
- .settings-message.text-center
- = no_active_tokens_message
diff --git a/config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml b/config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml
new file mode 100644
index 00000000000..05232d0f80a
--- /dev/null
+++ b/config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml
@@ -0,0 +1,8 @@
+---
+name: jira_connect_oauth_self_managed_setting
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100725
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377679
+milestone: '15.6'
+type: development
+group: group::integrations
+default_enabled: false
diff --git a/db/docs/software_license_policies.yml b/db/docs/software_license_policies.yml
index 478c68d8c59..615ae644985 100644
--- a/db/docs/software_license_policies.yml
+++ b/db/docs/software_license_policies.yml
@@ -3,7 +3,7 @@ table_name: software_license_policies
classes:
- SoftwareLicensePolicy
feature_categories:
-- license_compliance
+- security_policy_management
description: Allows user to approve or deny the use certain software licenses in their project.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6246
milestone: '11.2'
diff --git a/db/docs/software_licenses.yml b/db/docs/software_licenses.yml
index 48e78c8ca02..67ebd697fa8 100644
--- a/db/docs/software_licenses.yml
+++ b/db/docs/software_licenses.yml
@@ -3,7 +3,7 @@ table_name: software_licenses
classes:
- SoftwareLicense
feature_categories:
-- license_compliance
+- security_policy_management
description: Normalized software licenses to use in conjunction with License Compliance features (like software license policies)
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6246
milestone: '11.2'
diff --git a/db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb b/db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb
new file mode 100644
index 00000000000..a81a80deb25
--- /dev/null
+++ b/db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CleanupVulnerabilityStateTransitionsWithSameFromStateToState < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ class VulnerabilityStateTransition < MigrationRecord
+ self.table_name = 'vulnerability_state_transitions'
+ end
+
+ def up
+ VulnerabilityStateTransition.where('from_state = to_state').delete_all
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20221013215832 b/db/schema_migrations/20221013215832
new file mode 100644
index 00000000000..106cb540d6e
--- /dev/null
+++ b/db/schema_migrations/20221013215832
@@ -0,0 +1 @@
+2ab913b0b479fc29d939d03b5df95dc2a8c5a155f1b35a606e300802cb3aa9d3 \ No newline at end of file
diff --git a/doc/api/remote_mirrors.md b/doc/api/remote_mirrors.md
index 1013ffb49fb..bd59aa64e45 100644
--- a/doc/api/remote_mirrors.md
+++ b/doc/api/remote_mirrors.md
@@ -8,15 +8,15 @@ type: reference, api
# Project remote mirrors API **(FREE)**
[Push mirrors](../user/project/repository/mirror/push.md)
-defined on a project's repository settings are called "remote mirrors", and the
-state of these mirrors can be queried and modified via the remote mirror API
-outlined below.
+defined on a project's repository settings are called "remote mirrors". You
+can query and modify the state of these mirrors with the remote mirror API.
-## List a project's remote mirrors
+For security reasons, the `url` attribute in the API response is always scrubbed of username
+and password information.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38121) in GitLab 12.9.
+## List a project's remote mirrors
-Returns an Array of remote mirrors and their statuses:
+Returns an array of remote mirrors and their statuses:
```plaintext
GET /projects/:id/remote_mirrors
@@ -47,10 +47,6 @@ Example response:
]
```
-NOTE:
-For security reasons, the `url` attribute is always scrubbed of username
-and password information.
-
## Get a single project's remote mirror
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82770) in GitLab 14.10.
@@ -84,19 +80,14 @@ Example response:
}
```
-NOTE:
-For security reasons, the `url` attribute is always scrubbed of username
-and password information.
-
## Create a pull mirror
Learn how to [configure a pull mirror](projects.md#configure-pull-mirroring-for-a-project) using the Projects API.
## Create a push mirror
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24189) in GitLab 12.9.
-
-Push mirroring is disabled by default. You can enable it by including the optional parameter `enabled` when creating it:
+Push mirroring is disabled by default. To enable it, include the optional parameter
+`enabled` when you create the mirror:
```plaintext
POST /projects/:id/remote_mirrors
@@ -106,8 +97,8 @@ POST /projects/:id/remote_mirrors
| :---------- | :----- | :--------- | :------------ |
| `url` | String | yes | The target URL to which the repository is mirrored. |
| `enabled` | Boolean | no | Determines if the mirror is enabled. |
-| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
| `keep_divergent_refs` | Boolean | no | Determines if divergent refs are skipped. |
+| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
Example request:
@@ -135,8 +126,6 @@ Example response:
## Update a remote mirror's attributes
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38121) in GitLab 12.9.
-
Toggle a remote mirror on or off, or change which types of branches are
mirrored:
@@ -148,8 +137,8 @@ PUT /projects/:id/remote_mirrors/:mirror_id
| :---------- | :----- | :--------- | :------------ |
| `mirror_id` | Integer | yes | The remote mirror ID. |
| `enabled` | Boolean | no | Determines if the mirror is enabled. |
-| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
| `keep_divergent_refs` | Boolean | no | Determines if divergent refs are skipped. |
+| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
Example request:
diff --git a/doc/architecture/blueprints/ci_pipeline_components/index.md b/doc/architecture/blueprints/ci_pipeline_components/index.md
index 115f6909d2d..6e5ab8040ae 100644
--- a/doc/architecture/blueprints/ci_pipeline_components/index.md
+++ b/doc/architecture/blueprints/ci_pipeline_components/index.md
@@ -115,21 +115,22 @@ while encapsulating and isolating implementation details.
Components allow a pipeline to be assembled by using abstractions instead of having all the details defined in one place.
When using a component in a pipeline, a user shouldn't need to know the implementation details of the component and should
-only rely on the provided interface. The interface will have a version / revision, so that users understand which revision they are interfacing with.
+only rely on the provided interface.
A pipeline component defines its type which indicates in which context of the pipeline configuration the component can be used.
For example, a component of type X can only be used according to the type X use-case.
-For best experience with any systems made of components it's fundamental that components are single purpose,
-isolated, reusable and resolvable.
+For best experience with any systems made of components it's fundamental that components:
- **Single purpose**: a component must focus on a single goal and the scope be as small as possible.
-- **Isolation**: when a component is used in a pipeline, its implementation details should not leak outside the
+- **Isolated**: when a component is used in a pipeline, its implementation details should not leak outside the
component itself and into the main pipeline.
-- **Reusability:** a component is designed to be used in different pipelines.
+- **Reusable**: a component is designed to be used in different pipelines.
Depending on the assumptions it's built on a component can be more or less generic.
Generic components are more reusable but may require more customization.
-- **Resolvable:** When a component depends on another component, this dependency must be explicit and trackable.
+- **Versioned**: when using a component we must specify the version we are interested in.
+ The version identifies the exact interface and behavior of the component.
+- **Resolvable**: when a component depends on another component, this dependency must be explicit and trackable.
## Proposal
diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md
index 0b1963e1874..c6fffa0ec59 100644
--- a/doc/ci/pipelines/downstream_pipelines.md
+++ b/doc/ci/pipelines/downstream_pipelines.md
@@ -170,7 +170,10 @@ Use:
- The `project` keyword to specify the full path to a downstream project.
In [GitLab 15.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/367660), variable expansion is
supported.
-- The `branch` keyword to specify the name of a branch in the project specified by `project`.
+- The `branch` keyword to specify the name of a branch or [tag](../../topics/git/tags.md)
+ in the project specified by `project`. If you use a tag when a branch exists with the same
+ name, the downstream pipeline fails to create with the error: `downstream pipeline can not be created, Ref is ambiguous`.
+
In [GitLab 12.4 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/10126), variable expansion is
supported.
diff --git a/doc/ci/testing/unit_test_report_examples.md b/doc/ci/testing/unit_test_report_examples.md
index c14e4eedd7c..5d4cfa88d88 100644
--- a/doc/ci/testing/unit_test_report_examples.md
+++ b/doc/ci/testing/unit_test_report_examples.md
@@ -18,7 +18,10 @@ Use the following job in `.gitlab-ci.yml`. This includes the `artifacts:paths` k
```yaml
## Use https://github.com/sj26/rspec_junit_formatter to generate a JUnit report format XML file with rspec
ruby:
+ image: ruby:3.0.4
stage: test
+ before_script:
+ - apt-get update -y && apt-get install -y bundler
script:
- bundle install
- bundle exec rspec --format progress --format RspecJunitFormatter --out rspec.xml
diff --git a/doc/development/sidekiq/worker_attributes.md b/doc/development/sidekiq/worker_attributes.md
index 48a222d65a0..4fcd8e33d5c 100644
--- a/doc/development/sidekiq/worker_attributes.md
+++ b/doc/development/sidekiq/worker_attributes.md
@@ -277,7 +277,7 @@ they prefer read replicas and will wait for replicas to catch up:
| **Data Consistency** | **Description** |
|--------------|-----------------------------|
-| `:always` | The job is required to use the primary database (default). It should be used for workers that primarily perform writes or that have strict requirements around data consistency when reading their own writes. |
+| `:always` | The job is required to use the primary database (default). It should be used for workers that primarily perform writes, have strict requirements around data consistency when reading their own writes, or are cron jobs. |
| `:sticky` | The job prefers replicas, but switches to the primary for writes or when encountering replication lag. It should be used for jobs that require to be executed as fast as possible but can sustain a small initial queuing delay. |
| `:delayed` | The job prefers replicas, but switches to the primary for writes. When encountering replication lag before the job starts, the job is retried once. If the replica is still not up to date on the next retry, it switches to the primary. It should be used for jobs where delaying execution further typically does not matter, such as cache expiration or web hooks execution. |
diff --git a/lib/api/integrations/jira_connect/subscriptions.rb b/lib/api/integrations/jira_connect/subscriptions.rb
index a6e931ba7bb..87d6985cead 100644
--- a/lib/api/integrations/jira_connect/subscriptions.rb
+++ b/lib/api/integrations/jira_connect/subscriptions.rb
@@ -17,7 +17,7 @@ module API
requires :namespace_path, type: String, desc: 'Path for the namespace that should be subscribed'
end
post do
- not_found! unless Feature.enabled?(:jira_connect_oauth, current_user)
+ not_found! unless Feature.enabled?(:jira_connect_oauth_self_managed, current_user)
jwt = Atlassian::JiraConnect::Jwt::Symmetric.new(params[:jwt])
installation = JiraConnectInstallation.find_by_client_key(jwt.iss_claim)
diff --git a/lib/gitlab/ci/variables/collection.rb b/lib/gitlab/ci/variables/collection.rb
index b6d6e1a3e5f..1dbe5481807 100644
--- a/lib/gitlab/ci/variables/collection.rb
+++ b/lib/gitlab/ci/variables/collection.rb
@@ -94,7 +94,8 @@ module Gitlab
# when the variables are sent to Runner.
Gitlab::AppJsonLogger.info(
event: 'file_variable_is_referenced_in_another_variable',
- project_id: project.id
+ project_id: project.id,
+ variable: variable_name
)
end
diff --git a/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb b/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb
index 15b542cf089..eb7f62395d0 100644
--- a/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb
+++ b/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb
@@ -7,6 +7,8 @@ module Gitlab
include Gitlab::Database::MigrationHelpers
include Gitlab::Database::SchemaHelpers
+ DuplicatedIndexesError = Class.new(StandardError)
+
ERROR_SCOPE = 'index'
# Concurrently creates a new index on a partitioned table. In concept this works similarly to
@@ -92,6 +94,42 @@ module Gitlab
.map { |_, indexes| indexes.map { |index| index['index_name'] } }
end
+ # Retrieves a hash of index names for a given table and schema, by index
+ # definition.
+ #
+ # Example:
+ #
+ # indexes_by_definition_for_table('table_name_goes_here')
+ #
+ # Returns:
+ #
+ # {
+ # "CREATE _ btree (created_at)" => "index_on_created_at"
+ # }
+ def indexes_by_definition_for_table(table_name, schema_name: connection.current_schema)
+ duplicate_indexes = find_duplicate_indexes(table_name, schema_name: schema_name)
+
+ unless duplicate_indexes.empty?
+ raise DuplicatedIndexesError, "#{table_name} has duplicate indexes: #{duplicate_indexes}"
+ end
+
+ find_indexes(table_name, schema_name: schema_name)
+ .each_with_object({}) { |row, hash| hash[row['index_id']] = row['index_name'] }
+ end
+
+ # Renames indexes for a given table and schema, mapping by index
+ # definition, to a hash of new index names.
+ #
+ # Example:
+ #
+ # index_names = indexes_by_definition_for_table('source_table_name_goes_here')
+ # drop_table('source_table_name_goes_here')
+ # rename_indexes_for_table('destination_table_name_goes_here', index_names)
+ def rename_indexes_for_table(table_name, new_index_names, schema_name: connection.current_schema)
+ current_index_names = indexes_by_definition_for_table(table_name, schema_name: schema_name)
+ rename_indexes(current_index_names, new_index_names, schema_name: schema_name)
+ end
+
private
def find_indexes(table_name, schema_name: connection.current_schema)
@@ -124,6 +162,18 @@ module Gitlab
def generated_index_name(partition_name, index_name)
object_name("#{partition_name}_#{index_name}", 'index')
end
+
+ def rename_indexes(from, to, schema_name: connection.current_schema)
+ indexes_to_rename = from.select { |index_id, _| to.has_key?(index_id) }
+ statements = indexes_to_rename.map do |index_id, index_name|
+ <<~SQL
+ ALTER INDEX #{connection.quote_table_name("#{schema_name}.#{connection.quote_column_name(index_name)}")}
+ RENAME TO #{connection.quote_column_name(to[index_id])}
+ SQL
+ end
+
+ connection.execute(statements.join(';'))
+ end
end
end
end
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 960d0e51a47..e814d59aaf9 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -34,7 +34,7 @@ Usage: rake "gitlab:gitaly:install[/installation/dir,/storage/path]")
env["BUNDLE_DEPLOYMENT"] = 'false'
end
- output, status = Gitlab::Popen.popen([make_cmd, 'clean-build', 'all', 'git'], nil, env)
+ output, status = Gitlab::Popen.popen([make_cmd, 'clean-build', 'all'], nil, env)
raise "Gitaly failed to compile: #{output}" unless status&.zero?
end
end
diff --git a/lib/tasks/gitlab/tw/codeowners.rake b/lib/tasks/gitlab/tw/codeowners.rake
index 2d06792d656..19337f50f1b 100644
--- a/lib/tasks/gitlab/tw/codeowners.rake
+++ b/lib/tasks/gitlab/tw/codeowners.rake
@@ -48,7 +48,7 @@ namespace :tw do
CodeOwnerRule.new('Infrastructure', '@sselhorn'),
CodeOwnerRule.new('Integrations', '@ashrafkhamis'),
CodeOwnerRule.new('Knowledge', '@aqualls'),
- CodeOwnerRule.new('Application Performance', '@sselhorn'),
+ CodeOwnerRule.new('Application Performance', '@jglassman1'),
CodeOwnerRule.new('Monitor', '@msedlakjakubowski'),
CodeOwnerRule.new('Observability', 'msedlakjakubowski'),
CodeOwnerRule.new('Optimize', '@lciutacu'),
@@ -67,7 +67,7 @@ namespace :tw do
CodeOwnerRule.new('Release', '@rdickenson'),
CodeOwnerRule.new('Respond', '@msedlakjakubowski'),
CodeOwnerRule.new('Runner', '@sselhorn'),
- CodeOwnerRule.new('Pods', '@sselhorn'),
+ CodeOwnerRule.new('Pods', '@jglassman1'),
CodeOwnerRule.new('Security Policies', '@claytoncornell'),
CodeOwnerRule.new('Source Code', '@aqualls'),
CodeOwnerRule.new('Static Analysis', '@rdickenson'),
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index f5fb7306a9d..7b4956c8e45 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2125,9 +2125,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -5215,9 +5212,6 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr ""
-
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
@@ -10782,9 +10776,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -29693,6 +29684,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -41750,9 +41744,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -47024,9 +47015,6 @@ msgstr ""
msgid "Your new %{accessTokenType} has been created."
msgstr ""
-msgid "Your new %{type}"
-msgstr ""
-
msgid "Your new comment"
msgstr ""
diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb
index 3c8a608cdc2..8723f6619d9 100644
--- a/qa/qa/page/component/access_tokens.rb
+++ b/qa/qa/page/component/access_tokens.rb
@@ -18,19 +18,11 @@ module QA
element :expiry_date_field
end
- base.view 'app/views/shared/access_tokens/_created_container.html.haml' do
- element :created_access_token_field
- end
-
base.view 'app/views/shared/access_tokens/_form.html.haml' do
element :access_token_name_field
element :create_token_button
end
- base.view 'app/views/shared/access_tokens/_table.html.haml' do
- element :revoke_button
- end
-
base.view 'app/views/shared/tokens/_scopes_form.html.haml' do
element :api_label, '#{scope}_label' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck
end
diff --git a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
index c4be90d3759..756bbe2164a 100644
--- a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'Project access token', :reliable do
+ describe 'Project access token' do
before(:all) do
@project_access_token = QA::Resource::ProjectAccessToken.fabricate_via_api! do |pat|
pat.project = Resource::ReusableProject.fabricate_via_api!
@@ -12,7 +12,7 @@ module QA
end
context 'for the same project' do
- it 'can be used to create a file via the project API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347858' do
+ it 'can be used to create a file via the project API', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347858' do
expect do
Resource::File.fabricate_via_api! do |file|
file.api_client = @user_api_client
@@ -44,7 +44,7 @@ module QA
@different_project = Resource::Project.fabricate!
end
- it 'cannot be used to create a file via the project API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347860' do
+ it 'cannot be used to create a file via the project API', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347860' do
expect do
Resource::File.fabricate_via_api! do |file|
file.api_client = @user_api_client
@@ -57,7 +57,7 @@ module QA
end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden/)
end
- it 'cannot be used to commit via the API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347861' do
+ it 'cannot be used to commit via the API', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347861' do
expect do
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.api_client = @user_api_client
diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb
index 7add6c782f7..2716d742be3 100644
--- a/spec/features/issues/user_sorts_issues_spec.rb
+++ b/spec/features/issues/user_sorts_issues_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "User sorts issues" do
sign_in(user)
end
- it 'keeps the sort option', :js do
+ it 'keeps the sort option', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378184' do
visit(project_issues_path(project))
click_button 'Created date'
diff --git a/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js b/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js
index cce8f480928..2a7ccce1092 100644
--- a/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js
+++ b/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js
@@ -1,9 +1,10 @@
-import { GlAlert, GlLoadingIcon, GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlAlert, GlLoadingIcon, GlModal, GlTabs } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
+import { trimText } from 'helpers/text_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import PipelineSchedules from '~/pipeline_schedules/components/pipeline_schedules.vue';
import PipelineSchedulesTable from '~/pipeline_schedules/components/table/pipeline_schedules_table.vue';
import deletePipelineScheduleMutation from '~/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql';
@@ -32,7 +33,7 @@ describe('Pipeline schedules app', () => {
};
const createComponent = (requestHandlers) => {
- wrapper = shallowMount(PipelineSchedules, {
+ wrapper = mountExtended(PipelineSchedules, {
provide: {
fullPath: 'gitlab-org/gitlab',
},
@@ -44,17 +45,24 @@ describe('Pipeline schedules app', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findModal = () => wrapper.findComponent(GlModal);
+ const findTabs = () => wrapper.findComponent(GlTabs);
+ const findNewButton = () => wrapper.findByTestId('new-schedule-button');
+ const findAllTab = () => wrapper.findByTestId('pipeline-schedules-all-tab');
+ const findActiveTab = () => wrapper.findByTestId('pipeline-schedules-active-tab');
+ const findInactiveTab = () => wrapper.findByTestId('pipeline-schedules-inactive-tab');
afterEach(() => {
wrapper.destroy();
});
- it('displays table', async () => {
+ it('displays table, tabs and new button', async () => {
createComponent();
await waitForPromises();
expect(findTable().exists()).toBe(true);
+ expect(findNewButton().exists()).toBe(true);
+ expect(findTabs().exists()).toBe(true);
expect(findAlert().exists()).toBe(false);
});
@@ -158,4 +166,38 @@ describe('Pipeline schedules app', () => {
expect(findModal().props('visible')).toBe(false);
});
+
+ describe('tabs', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('displays All tab with count', () => {
+ expect(trimText(findAllTab().text())).toBe(`All ${mockPipelineScheduleNodes.length}`);
+ });
+
+ it('displays Active tab with no count', () => {
+ expect(findActiveTab().text()).toBe('Active');
+ });
+
+ it('displays Inactive tab with no count', () => {
+ expect(findInactiveTab().text()).toBe('Inactive');
+ });
+ });
+
+ it('should refetch the schedules query on a tab click', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch').mockImplementation(jest.fn());
+
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalledTimes(0);
+
+ await findAllTab().trigger('click');
+
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalledTimes(1);
+ });
});
diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb
index 7d4a1eef70b..4710698fd95 100644
--- a/spec/lib/gitlab/ci/variables/collection_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection_spec.rb
@@ -601,7 +601,8 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
it 'logs file_variable_is_referenced_in_another_variable once for VAR5' do
expect(Gitlab::AppJsonLogger).to receive(:info).with(
event: 'file_variable_is_referenced_in_another_variable',
- project_id: project.id
+ project_id: project.id,
+ variable: 'FILEVAR4'
).once
sort_and_expand_all
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
index 7465f69b87c..5d02266e8a2 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
@@ -231,4 +231,165 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::IndexHelpers do
end
end
end
+
+ describe '#indexes_by_definition_for_table' do
+ context 'when a partitioned table has indexes' do
+ subject do
+ migration.indexes_by_definition_for_table(table_name)
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE INDEX #{index_name} ON #{table_name} (#{column_name});
+ SQL
+ end
+
+ it 'captures partitioned index names by index definition' do
+ expect(subject).to match(a_hash_including({ "CREATE _ btree (#{column_name})" => index_name }))
+ end
+ end
+
+ context 'when a non-partitioned table has indexes' do
+ let(:regular_table_name) { '_test_regular_table' }
+ let(:regular_index_name) { '_test_regular_index_name' }
+
+ subject do
+ migration.indexes_by_definition_for_table(regular_table_name)
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{regular_table_name} (
+ #{column_name} timestamptz NOT NULL
+ );
+
+ CREATE INDEX #{regular_index_name} ON #{regular_table_name} (#{column_name});
+ SQL
+ end
+
+ it 'captures index names by index definition' do
+ expect(subject).to match(a_hash_including({ "CREATE _ btree (#{column_name})" => regular_index_name }))
+ end
+ end
+
+ context 'when a non-partitioned table has duplicate indexes' do
+ let(:regular_table_name) { '_test_regular_table' }
+ let(:regular_index_name) { '_test_regular_index_name' }
+ let(:duplicate_index_name) { '_test_duplicate_index_name' }
+
+ subject do
+ migration.indexes_by_definition_for_table(regular_table_name)
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{regular_table_name} (
+ #{column_name} timestamptz NOT NULL
+ );
+
+ CREATE INDEX #{regular_index_name} ON #{regular_table_name} (#{column_name});
+ CREATE INDEX #{duplicate_index_name} ON #{regular_table_name} (#{column_name});
+ SQL
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error { described_class::DuplicatedIndexesError }
+ end
+ end
+ end
+
+ describe '#rename_indexes_for_table' do
+ let(:original_table_name) { '_test_rename_indexes_table' }
+ let(:first_partition_name) { '_test_rename_indexes_table_1' }
+ let(:transient_table_name) { '_test_rename_indexes_table_child' }
+ let(:custom_column_name) { 'created_at' }
+ let(:generated_column_name) { 'updated_at' }
+ let(:custom_index_name) { 'index_test_rename_indexes_table_on_created_at' }
+ let(:custom_index_name_regenerated) { '_test_rename_indexes_table_created_at_idx' }
+ let(:generated_index_name) { '_test_rename_indexes_table_updated_at_idx' }
+ let(:generated_index_name_collided) { '_test_rename_indexes_table_updated_at_idx1' }
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{original_table_name} (
+ #{custom_column_name} timestamptz NOT NULL,
+ #{generated_column_name} timestamptz NOT NULL
+ );
+
+ CREATE INDEX #{custom_index_name} ON #{original_table_name} (#{custom_column_name});
+ CREATE INDEX ON #{original_table_name} (#{generated_column_name});
+ SQL
+ end
+
+ context 'when changing a table within the current schema' do
+ let!(:identifiers) { migration.indexes_by_definition_for_table(original_table_name) }
+
+ before do
+ connection.execute(<<~SQL)
+ ALTER TABLE #{original_table_name} RENAME TO #{first_partition_name};
+ CREATE TABLE #{original_table_name} (LIKE #{first_partition_name} INCLUDING ALL);
+ DROP TABLE #{first_partition_name};
+ SQL
+ end
+
+ it 'maps index names after they are changed' do
+ migration.rename_indexes_for_table(original_table_name, identifiers)
+
+ expect_index_to_exist(custom_index_name)
+ expect_index_to_exist(generated_index_name)
+ end
+
+ it 'does not rename an index which does not exist in the to_hash' do
+ partial_identifiers = identifiers.reject { |_, name| name == custom_index_name }
+
+ migration.rename_indexes_for_table(original_table_name, partial_identifiers)
+
+ expect_index_not_to_exist(custom_index_name)
+ expect_index_to_exist(generated_index_name)
+ end
+ end
+
+ context 'when partitioning an existing table' do
+ before do
+ connection.execute(<<~SQL)
+ /* Create new parent table */
+ CREATE TABLE #{first_partition_name} (LIKE #{original_table_name} INCLUDING ALL);
+ SQL
+ end
+
+ it 'renames indexes across schemas' do
+ # Capture index names generated by postgres
+ generated_index_names = migration.indexes_by_definition_for_table(first_partition_name)
+
+ # Capture index names from original table
+ original_index_names = migration.indexes_by_definition_for_table(original_table_name)
+
+ connection.execute(<<~SQL)
+ /* Rename original table out of the way */
+ ALTER TABLE #{original_table_name} RENAME TO #{transient_table_name};
+
+ /* Rename new parent table to original name */
+ ALTER TABLE #{first_partition_name} RENAME TO #{original_table_name};
+
+ /* Move original table to gitlab_partitions_dynamic schema */
+ ALTER TABLE #{transient_table_name} SET SCHEMA #{partition_schema};
+
+ /* Rename original table to be the first partition */
+ ALTER TABLE #{partition_schema}.#{transient_table_name} RENAME TO #{first_partition_name};
+ SQL
+
+ # Apply index names generated by postgres to first partition
+ migration.rename_indexes_for_table(first_partition_name, generated_index_names, schema_name: partition_schema)
+
+ expect_index_to_exist('_test_rename_indexes_table_1_created_at_idx')
+ expect_index_to_exist('_test_rename_indexes_table_1_updated_at_idx')
+
+ # Apply index names from original table to new parent table
+ migration.rename_indexes_for_table(original_table_name, original_index_names)
+
+ expect_index_to_exist(custom_index_name)
+ expect_index_to_exist(generated_index_name)
+ end
+ end
+ end
end
diff --git a/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb b/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb
new file mode 100644
index 00000000000..92ece81ffc8
--- /dev/null
+++ b/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe CleanupVulnerabilityStateTransitionsWithSameFromStateToState, :migration do
+ let_it_be(:namespace) { table(:namespaces).create!(name: 'namespace', type: 'Group', path: 'namespace') }
+ let_it_be(:user) { table(:users).create!(email: 'author@example.com', username: 'author', projects_limit: 10) }
+ let_it_be(:project) do
+ table(:projects).create!(
+ path: 'project',
+ namespace_id: namespace.id,
+ project_namespace_id: namespace.id
+ )
+ end
+
+ let_it_be(:vulnerability) do
+ table(:vulnerabilities).create!(
+ project_id: project.id,
+ author_id: user.id,
+ title: 'test',
+ severity: 7,
+ confidence: 7,
+ report_type: 0
+ )
+ end
+
+ let_it_be(:state_transitions) { table(:vulnerability_state_transitions) }
+
+ let!(:state_transition_with_no_state_change) do
+ state_transitions.create!(
+ vulnerability_id: vulnerability.id,
+ from_state: 2,
+ to_state: 2
+ )
+ end
+
+ let!(:state_transition_with_state_change) do
+ state_transitions.create!(
+ vulnerability_id: vulnerability.id,
+ from_state: 1,
+ to_state: 2
+ )
+ end
+
+ it 'deletes state transitions with no state change' do
+ expect { migrate! }.to change(state_transitions, :count).from(2).to(1)
+ end
+end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index c6d028af22d..838e5d700c1 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -2356,7 +2356,7 @@ RSpec.describe Namespace do
end
end
- describe 'storage_enforcement_date' do
+ describe 'storage_enforcement_date', :freeze_time do
let_it_be(:namespace) { create(:group) }
before do
@@ -2364,7 +2364,7 @@ RSpec.describe Namespace do
end
it 'returns correct date' do
- expect(namespace.storage_enforcement_date).to eql(Date.new(2022, 10, 19))
+ expect(namespace.storage_enforcement_date).to eql(3.months.from_now.to_date)
end
context 'when :storage_banner_bypass_date_check is enabled' do
@@ -2372,7 +2372,7 @@ RSpec.describe Namespace do
stub_feature_flags(namespace_storage_limit_bypass_date_check: true)
end
- it 'returns the current date', :freeze_time do
+ it 'returns the current date' do
expect(namespace.storage_enforcement_date).to eq(Date.current)
end
end
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 67e7d444d25..73ec51ea801 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -194,47 +194,6 @@ RSpec.describe PersonalAccessToken do
end
end
- describe 'Redis storage' do
- let(:user_id) { 123 }
- let(:token) { 'KS3wegQYXBLYhQsciwsj' }
-
- context 'reading encrypted data' do
- before do
- subject.redis_store!(user_id, token)
- end
-
- it 'returns stored data' do
- expect(subject.redis_getdel(user_id)).to eq(token)
- end
- end
-
- context 'reading unencrypted data' do
- before do
- Gitlab::Redis::SharedState.with do |redis|
- redis.set(described_class.redis_shared_state_key(user_id),
- token,
- ex: PersonalAccessToken::REDIS_EXPIRY_TIME)
- end
- end
-
- it 'returns stored data unmodified' do
- expect(subject.redis_getdel(user_id)).to eq(token)
- end
- end
-
- context 'after deletion' do
- before do
- subject.redis_store!(user_id, token)
-
- expect(subject.redis_getdel(user_id)).to eq(token)
- end
-
- it 'token is removed' do
- expect(subject.redis_getdel(user_id)).to be_nil
- end
- end
- end
-
context "validations" do
let(:personal_access_token) { build(:personal_access_token) }
@@ -365,7 +324,7 @@ RSpec.describe PersonalAccessToken do
describe '.simple_sorts' do
it 'includes overridden keys' do
- expect(described_class.simple_sorts.keys).to include(*%w(expires_at_asc expires_at_desc expires_at_asc_id_desc))
+ expect(described_class.simple_sorts.keys).to include(*%w(expires_at_asc_id_desc))
end
end
@@ -373,18 +332,6 @@ RSpec.describe PersonalAccessToken do
let_it_be(:earlier_token) { create(:personal_access_token, expires_at: 2.days.ago) }
let_it_be(:later_token) { create(:personal_access_token, expires_at: 1.day.ago) }
- describe '.order_expires_at_asc' do
- it 'returns ordered list in asc order of expiry date' do
- expect(described_class.order_expires_at_asc).to match [earlier_token, later_token]
- end
- end
-
- describe '.order_expires_at_desc' do
- it 'returns ordered list in desc order of expiry date' do
- expect(described_class.order_expires_at_desc).to match [later_token, earlier_token]
- end
- end
-
describe '.order_expires_at_asc_id_desc' do
let_it_be(:earlier_token_2) { create(:personal_access_token, expires_at: 2.days.ago) }
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index 396fe7843ba..8d6278ab1d7 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -353,7 +353,8 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'logs file_variable_is_referenced_in_another_variable' do
expect(Gitlab::AppJsonLogger).to receive(:info).with(
event: 'file_variable_is_referenced_in_another_variable',
- project_id: project.id
+ project_id: project.id,
+ variable: 'file_var'
).once
runner_variables
diff --git a/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb b/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb
index 8a222a99b34..6b26eaad2f3 100644
--- a/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb
+++ b/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe API::Integrations::JiraConnect::Subscriptions do
context 'with feature flag disabled' do
before do
- stub_feature_flags(jira_connect_oauth: false)
+ stub_feature_flags(jira_connect_oauth_self_managed: false)
end
let(:jwt) { '123' }
diff --git a/spec/requests/jira_connect/subscriptions_controller_spec.rb b/spec/requests/jira_connect/subscriptions_controller_spec.rb
index f407ea09250..ee5c26295fd 100644
--- a/spec/requests/jira_connect/subscriptions_controller_spec.rb
+++ b/spec/requests/jira_connect/subscriptions_controller_spec.rb
@@ -28,9 +28,9 @@ RSpec.describe JiraConnect::SubscriptionsController do
it { is_expected.not_to include('http://self-managed-gitlab.com/api/') }
end
- context 'with jira_connect_oauth_self_managed feature disabled' do
+ context 'with jira_connect_oauth_self_managed_setting feature disabled' do
before do
- stub_feature_flags(jira_connect_oauth_self_managed: false)
+ stub_feature_flags(jira_connect_oauth_self_managed_setting: false)
end
it { is_expected.not_to include('http://self-managed-gitlab.com/-/jira_connect/') }
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 0558bfd51c3..b8fe8412d55 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -3379,7 +3379,6 @@
- './ee/spec/views/registrations/welcome/continuous_onboarding_getting_started.html.haml_spec.rb'
- './ee/spec/views/registrations/welcome/show.html.haml_spec.rb'
- './ee/spec/views/search/_category.html.haml_spec.rb'
-- './ee/spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plan_actions.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plan.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plans.html.haml_spec.rb'
@@ -10767,7 +10766,6 @@
- './spec/views/registrations/welcome/show.html.haml_spec.rb'
- './spec/views/search/_results.html.haml_spec.rb'
- './spec/views/search/show.html.haml_spec.rb'
-- './spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- './spec/views/shared/deploy_tokens/_form.html.haml_spec.rb'
- './spec/views/shared/groups/_dropdown.html.haml_spec.rb'
- './spec/views/shared/issuable/_sidebar.html.haml_spec.rb'
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index e57021f749b..d2f4fa0b8ef 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
.with(%w[which gmake])
.and_return(['/usr/bin/gmake', 0])
expect(Gitlab::Popen).to receive(:popen)
- .with(%w[gmake clean-build all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
+ .with(%w[gmake clean-build all], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
.and_return(['ok', 0])
subject
@@ -78,7 +78,7 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
.with(%w[which gmake])
.and_return(['/usr/bin/gmake', 0])
expect(Gitlab::Popen).to receive(:popen)
- .with(%w[gmake clean-build all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
+ .with(%w[gmake clean-build all], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
.and_return(['output', 1])
expect { subject }.to raise_error /Gitaly failed to compile: output/
@@ -95,14 +95,14 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
it 'calls make in the gitaly directory' do
expect(Gitlab::Popen).to receive(:popen)
- .with(%w[make clean-build all git], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
+ .with(%w[make clean-build all], nil, { "BUNDLE_GEMFILE" => nil, "RUBYOPT" => nil })
.and_return(['output', 0])
subject
end
context 'when Rails.env is test' do
- let(:command) { %w[make clean-build all git] }
+ let(:command) { %w[make clean-build all] }
before do
stub_rails_env('test')
diff --git a/spec/views/admin/application_settings/general.html.haml_spec.rb b/spec/views/admin/application_settings/general.html.haml_spec.rb
index c7d156cde39..a9c470e49df 100644
--- a/spec/views/admin/application_settings/general.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/general.html.haml_spec.rb
@@ -76,9 +76,9 @@ RSpec.describe 'admin/application_settings/general.html.haml' do
expect(rendered).to have_css('#js-jira_connect-settings')
end
- context 'when the jira_connect_oauth feature flag is disabled' do
+ context 'when the jira_connect_oauth_self_managed_setting feature flag is disabled' do
before do
- stub_feature_flags(jira_connect_oauth: false)
+ stub_feature_flags(jira_connect_oauth_self_managed_setting: false)
end
it 'does not show the jira connect application key section' do
diff --git a/spec/views/shared/access_tokens/_table.html.haml_spec.rb b/spec/views/shared/access_tokens/_table.html.haml_spec.rb
deleted file mode 100644
index 74de9e12d04..00000000000
--- a/spec/views/shared/access_tokens/_table.html.haml_spec.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'shared/access_tokens/_table.html.haml' do
- let(:type) { 'token' }
- let(:type_plural) { 'tokens' }
- let(:empty_message) { nil }
- let(:impersonation) { false }
-
- let_it_be(:user) { create(:user) }
- let_it_be(:tokens) { [create(:personal_access_token, user: user)] }
- let_it_be(:resource) { false }
-
- before do
- if resource
- resource.add_maintainer(user)
- end
-
- # Forcibly removing scopes from one token as it's not possible to do with the current modal on creation
- # But the check exists in the template (it may be there for legacy reasons), so we should test the outcome
- if tokens.size > 1
- tokens[1].scopes = []
- end
-
- locals = {
- type: type,
- type_plural: type_plural,
- active_tokens: tokens,
- resource: resource,
- impersonation: impersonation,
- revoke_route_helper: ->(token) { 'path/' }
- }
-
- if empty_message
- locals[:no_active_tokens_message] = empty_message
- end
-
- render partial: 'shared/access_tokens/table', locals: locals
- end
-
- context 'if personal' do
- it 'does not show non-personal content', :aggregate_failures do
- expect(rendered).not_to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
- expect(rendered).not_to have_selector 'th', text: 'Role'
- end
- end
-
- context 'if impersonation' do
- let(:impersonation) { true }
-
- it 'shows the impersonation content', :aggregate_failures do
- expect(rendered).to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
-
- expect(rendered).not_to have_content 'Personal access tokens are not revoked upon expiration.'
- expect(rendered).not_to have_selector 'th', text: 'Role'
- end
- end
-
- context 'if resource is project' do
- let_it_be(:resource) { create(:project) }
-
- it 'shows the project content', :aggregate_failures do
- expect(rendered).to have_selector 'th', text: 'Role'
- expect(rendered).to have_selector 'td', text: 'Maintainer'
-
- expect(rendered).not_to have_content 'Personal access tokens are not revoked upon expiration.'
- expect(rendered).not_to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
- end
- end
-
- context 'if resource is group' do
- let_it_be(:resource) { create(:group) }
-
- it 'shows the group content', :aggregate_failures do
- expect(rendered).to have_selector 'th', text: 'Role'
- expect(rendered).to have_selector 'td', text: 'Maintainer'
-
- expect(rendered).not_to have_content 'Personal access tokens are not revoked upon expiration.'
- expect(rendered).not_to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
- end
- end
-
- context 'without tokens' do
- let_it_be(:tokens) { [] }
-
- it 'has the correct content', :aggregate_failures do
- expect(rendered).to have_content 'Active tokens (0)'
- expect(rendered).to have_content 'This user has no active tokens.'
- end
-
- context 'with a custom empty text' do
- let(:empty_message) { 'Custom empty message' }
-
- it 'shows the custom empty text' do
- expect(rendered).to have_content empty_message
- end
- end
- end
-
- context 'with tokens' do
- let_it_be(:tokens) do
- [
- create(:personal_access_token, user: user, name: 'Access token', last_used_at: 4.days.from_now, expires_at: nil, scopes: [:read_api, :read_user]),
- create(:personal_access_token, user: user, expires_at: 1.day.from_now, scopes: [:read_api, :read_user])
- ]
- end
-
- let_it_be(:expired_token) { build(:personal_access_token, name: "Expired token", expires_at: 2.days.ago).tap { |t| t.save!(validate: false) } }
-
- it 'has the correct content', :aggregate_failures do
- # Heading content
- expect(rendered).to have_content 'Active tokens (2)'
-
- # Table headers
- expect(rendered).to have_selector 'th', text: 'Token name'
- expect(rendered).to have_selector 'th', text: 'Scopes'
- expect(rendered).to have_selector 'th', text: 'Created'
- expect(rendered).to have_selector 'th', text: 'Last Used'
- expect(rendered).to have_selector 'th', text: 'Expires'
-
- # Table contents
- expect(rendered).to have_content 'Access token'
- expect(rendered).not_to have_content 'Expired token'
- expect(rendered).to have_content 'read_api, read_user'
- expect(rendered).to have_content 'no scopes selected'
- expect(rendered).to have_content Time.now.to_date.to_s(:medium)
- expect(rendered).to have_content l(4.days.from_now, format: "%b %d, %Y")
-
- # Revoke buttons
- expect(rendered).to have_link 'Revoke', href: 'path/', class: 'btn-danger-secondary', count: 1
- expect(rendered).to have_link 'Revoke', href: 'path/', count: 2
- end
-
- context 'without the last used time' do
- let_it_be(:tokens) { [create(:personal_access_token, user: user, expires_at: 5.days.ago)] }
-
- it 'shows the last used empty text' do
- expect(rendered).to have_content 'Never'
- end
- end
-
- context 'without expired at' do
- let_it_be(:tokens) { [create(:personal_access_token, user: user, expires_at: nil, last_used_at: 1.day.ago)] }
-
- it 'shows the expired at empty text' do
- expect(rendered).to have_content 'Never'
- end
- end
- end
-end