+
+
+
+ {{ $options.DESCRIPTION_SECRET }}
+
+
+
+ {{
+ $options.RENEW_SECRET
+ }}
+
+
+ {{ $options.CONFIRM_MODAL }}
+
+
+
diff --git a/app/assets/javascripts/oauth_application/constants.js b/app/assets/javascripts/oauth_application/constants.js
new file mode 100644
index 00000000000..5eaacadda78
--- /dev/null
+++ b/app/assets/javascripts/oauth_application/constants.js
@@ -0,0 +1,20 @@
+import { __, s__ } from '~/locale';
+
+export const CONFIRM_MODAL = s__(
+ 'AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab.',
+);
+export const CONFIRM_MODAL_TITLE = s__('AuthorizedApplication|Renew secret?');
+export const COPY_SECRET = __('Copy secret');
+export const DESCRIPTION_SECRET = __(
+ 'This is the only time the secret is accessible. Copy the secret and store it securely.',
+);
+export const RENEW_SECRET = s__('AuthorizedApplication|Renew secret');
+export const RENEW_SECRET_FAILURE = s__(
+ 'AuthorizedApplication|There was an error trying to renew the application secret. Please try again.',
+);
+export const RENEW_SECRET_SUCCESS = s__(
+ 'AuthorizedApplication|Application secret was successfully renewed.',
+);
+export const WARNING_NO_SECRET = __(
+ 'The secret is only available when you create the application or renew the secret.',
+);
diff --git a/app/assets/javascripts/oauth_application/index.js b/app/assets/javascripts/oauth_application/index.js
new file mode 100644
index 00000000000..f8f1f647a15
--- /dev/null
+++ b/app/assets/javascripts/oauth_application/index.js
@@ -0,0 +1,21 @@
+import Vue from 'vue';
+import OAuthSecret from './components/oauth_secret.vue';
+
+export const initOAuthApplicationSecret = () => {
+ const el = document.querySelector('#js-oauth-application-secret');
+
+ if (!el) {
+ return null;
+ }
+
+ const { initialSecret, renewPath } = el.dataset;
+
+ return new Vue({
+ el,
+ name: 'OAuthSecretRoot',
+ provide: { initialSecret, renewPath },
+ render(h) {
+ return h(OAuthSecret);
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/admin/applications/index.js b/app/assets/javascripts/pages/admin/applications/index.js
index 3397b02aeba..df9e38431b0 100644
--- a/app/assets/javascripts/pages/admin/applications/index.js
+++ b/app/assets/javascripts/pages/admin/applications/index.js
@@ -1,3 +1,5 @@
import initApplicationDeleteButtons from '~/admin/applications';
+import { initOAuthApplicationSecret } from '~/oauth_application';
initApplicationDeleteButtons();
+initOAuthApplicationSecret();
diff --git a/app/assets/javascripts/pages/groups/settings/applications/index.js b/app/assets/javascripts/pages/groups/settings/applications/index.js
new file mode 100644
index 00000000000..4dee5433ec9
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/settings/applications/index.js
@@ -0,0 +1,3 @@
+import { initOAuthApplicationSecret } from '~/oauth_application';
+
+initOAuthApplicationSecret();
diff --git a/app/assets/javascripts/pages/oauth/applications/index.js b/app/assets/javascripts/pages/oauth/applications/index.js
new file mode 100644
index 00000000000..4dee5433ec9
--- /dev/null
+++ b/app/assets/javascripts/pages/oauth/applications/index.js
@@ -0,0 +1,3 @@
+import { initOAuthApplicationSecret } from '~/oauth_application';
+
+initOAuthApplicationSecret();
diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb
index 76564981c9b..d97fcc5df74 100644
--- a/app/controllers/admin/applications_controller.rb
+++ b/app/controllers/admin/applications_controller.rb
@@ -47,10 +47,9 @@ class Admin::ApplicationsController < Admin::ApplicationController
@application.renew_secret
if @application.save
- flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
- render :show
+ render json: { secret: @application.plaintext_secret }
else
- redirect_to admin_application_url(@application)
+ render json: { errors: @application.errors }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/groups/settings/applications_controller.rb b/app/controllers/groups/settings/applications_controller.rb
index 2bf5c95937b..3ae1ae824a0 100644
--- a/app/controllers/groups/settings/applications_controller.rb
+++ b/app/controllers/groups/settings/applications_controller.rb
@@ -46,10 +46,9 @@ module Groups
@application.renew_secret
if @application.save
- flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
- render :show
+ render json: { secret: @application.plaintext_secret }
else
- redirect_to group_settings_application_url(@group, @application)
+ render json: { errors: @application.errors }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
index 7a31738188a..2d5421f9f74 100644
--- a/app/controllers/oauth/applications_controller.rb
+++ b/app/controllers/oauth/applications_controller.rb
@@ -45,10 +45,9 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
@application.renew_secret
if @application.save
- flash.now[:notice] = s_('AuthorizedApplication|Application secret was successfully updated.')
- render :show
+ render json: { secret: @application.plaintext_secret }
else
- redirect_to oauth_application_url(@application)
+ render json: { errors: @application.errors }, status: :unprocessable_entity
end
end
diff --git a/app/graphql/types/ci/catalog/resource_type.rb b/app/graphql/types/ci/catalog/resource_type.rb
new file mode 100644
index 00000000000..b5947826fa1
--- /dev/null
+++ b/app/graphql/types/ci/catalog/resource_type.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ module Catalog
+ # rubocop: disable Graphql/AuthorizeTypes
+ class ResourceType < BaseObject
+ graphql_name 'CiCatalogResource'
+
+ connection_type_class(Types::CountableConnectionType)
+
+ field :id, GraphQL::Types::ID, null: false, description: 'ID of the catalog resource.',
+ alpha: { milestone: '15.11' }
+
+ field :name, GraphQL::Types::String, null: true, description: 'Name of the catalog resource.',
+ alpha: { milestone: '15.11' }
+
+ field :description, GraphQL::Types::String, null: true, description: 'Description of the catalog resource.',
+ alpha: { milestone: '15.11' }
+
+ field :icon, GraphQL::Types::String, null: true, description: 'Icon for the catalog resource.',
+ method: :avatar_path, alpha: { milestone: '15.11' }
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/models/ci/catalog/resource.rb b/app/models/ci/catalog/resource.rb
index 40ec41de6fe..837f1352b4d 100644
--- a/app/models/ci/catalog/resource.rb
+++ b/app/models/ci/catalog/resource.rb
@@ -13,6 +13,8 @@ module Ci
belongs_to :project
scope :for_projects, ->(project_ids) { where(project_id: project_ids) }
+
+ delegate :avatar_path, :description, :name, to: :project
end
end
end
diff --git a/app/views/shared/doorkeeper/applications/_show.html.haml b/app/views/shared/doorkeeper/applications/_show.html.haml
index 19f4c971c1d..6bebbe94a55 100644
--- a/app/views/shared/doorkeeper/applications/_show.html.haml
+++ b/app/views/shared/doorkeeper/applications/_show.html.haml
@@ -15,16 +15,7 @@
%td
= _('Secret')
%td
- - if @application.plaintext_secret
- = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
- = c.body do
- = _('This is the only time the secret is accessible. Copy the secret and store it securely.')
- = clipboard_button(clipboard_text: @application.plaintext_secret, button_text: _('Copy'), title: _("Copy secret"), class: "btn btn-default btn-md gl-button")
- - else
- = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-5'}) do |c|
- = c.body do
- = _('The secret is only available when you create the application or renew the secret.')
- = render 'shared/doorkeeper/applications/update_form', path: renew_path
+ #js-oauth-application-secret{ data: { initial_secret: @application.plaintext_secret, renew_path: renew_path } }
%tr
%td
diff --git a/app/views/shared/doorkeeper/applications/_update_form.html.haml b/app/views/shared/doorkeeper/applications/_update_form.html.haml
deleted file mode 100644
index 1bee3288639..00000000000
--- a/app/views/shared/doorkeeper/applications/_update_form.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-- path = local_assigns.fetch(:path)
-= form_for(@application, url: path, html: {class: 'gl-display-inline-block', method: "put"}) do |f|
- = submit_tag s_('AuthorizedApplication|Renew secret'), data: { confirm: s_("AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab."), confirm_btn_variant: "danger" }, aria: { label: s_('AuthorizedApplication|Renew secret') }, class: 'gl-button btn btn-md btn-default'
diff --git a/db/docs/merge_trains.yml b/db/docs/merge_trains.yml
index 3b666322d3b..7d0310236e9 100644
--- a/db/docs/merge_trains.yml
+++ b/db/docs/merge_trains.yml
@@ -1,10 +1,10 @@
---
table_name: merge_trains
classes:
-- MergeTrain
+- MergeTrains::Car
feature_categories:
- continuous_integration
-description: TODO
+description: Each record represents a single merge request which is or was part of a merge train.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/827fc3ccb9335aa29fba0fc532b70015ec4c5186
milestone: '11.11'
gitlab_schema: gitlab_main
diff --git a/db/docs/schema_inconsistencies.yml b/db/docs/schema_inconsistencies.yml
index 85a2681a523..af95f26accb 100644
--- a/db/docs/schema_inconsistencies.yml
+++ b/db/docs/schema_inconsistencies.yml
@@ -5,4 +5,6 @@ feature_categories:
description: The schema_inconsistencies table contains a list of database schema inconsistencies.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114876
milestone: '15.11'
+classes:
+- Gitlab::Database::SchemaValidation::SchemaInconsistency
gitlab_schema: gitlab_main
diff --git a/db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb b/db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb
new file mode 100644
index 00000000000..b9efdd8234d
--- /dev/null
+++ b/db/post_migrate/20230329091107_truncate_p_ci_runner_machine_builds.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class TruncatePCiRunnerMachineBuilds < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ return unless Gitlab::Database.gitlab_schemas_for_connection(connection).include?(:gitlab_ci)
+
+ execute('TRUNCATE TABLE p_ci_runner_machine_builds')
+ end
+
+ # no-op
+ def down; end
+end
diff --git a/db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb b/db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb
new file mode 100644
index 00000000000..ad40ed118b1
--- /dev/null
+++ b/db/post_migrate/20230329091300_swap_ci_runner_machine_builds_primary_key_v2.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+class SwapCiRunnerMachineBuildsPrimaryKeyV2 < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :p_ci_runner_machine_builds
+ BUILDS_TABLE = :ci_builds
+
+ def up
+ reorder_primary_key_columns([:build_id, :partition_id])
+ end
+
+ def down
+ reorder_primary_key_columns([:partition_id, :build_id])
+ end
+
+ private
+
+ def reorder_primary_key_columns(columns)
+ with_lock_retries(raise_on_exhaustion: true) do
+ connection.execute(<<~SQL)
+ LOCK TABLE #{BUILDS_TABLE}, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE;
+ SQL
+
+ partitions = Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME).to_a
+ partitions.each { |partition| drop_table partition.identifier }
+
+ execute <<~SQL
+ ALTER TABLE #{TABLE_NAME}
+ DROP CONSTRAINT p_ci_runner_machine_builds_pkey CASCADE;
+
+ ALTER TABLE #{TABLE_NAME}
+ ADD PRIMARY KEY (#{columns.join(', ')});
+ SQL
+
+ partitions.each do |partition|
+ connection.execute(<<~SQL)
+ CREATE TABLE IF NOT EXISTS #{partition.identifier}
+ PARTITION OF #{partition.parent_identifier} #{partition.condition};
+ SQL
+ end
+ end
+ end
+end
diff --git a/db/schema_migrations/20230329091107 b/db/schema_migrations/20230329091107
new file mode 100644
index 00000000000..658d90e662f
--- /dev/null
+++ b/db/schema_migrations/20230329091107
@@ -0,0 +1 @@
+4ca98e9c93245a8fc1f4124d00d47d73d12b961affde1d53b7262ffc93582d83
\ No newline at end of file
diff --git a/db/schema_migrations/20230329091300 b/db/schema_migrations/20230329091300
new file mode 100644
index 00000000000..4a4be644126
--- /dev/null
+++ b/db/schema_migrations/20230329091300
@@ -0,0 +1 @@
+a85e3139d843295e666867129575818f61983a8b16eaa73f9b470e394d9c5476
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 06e4541147b..6c71c7d17ce 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -27376,7 +27376,7 @@ ALTER TABLE ONLY operations_user_lists
ADD CONSTRAINT operations_user_lists_pkey PRIMARY KEY (id);
ALTER TABLE ONLY p_ci_runner_machine_builds
- ADD CONSTRAINT p_ci_runner_machine_builds_pkey PRIMARY KEY (partition_id, build_id);
+ ADD CONSTRAINT p_ci_runner_machine_builds_pkey PRIMARY KEY (build_id, partition_id);
ALTER TABLE ONLY packages_build_infos
ADD CONSTRAINT packages_build_infos_pkey PRIMARY KEY (id);
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 916c01958ca..958436b3c8a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -55,6 +55,26 @@ CI related settings that apply to the entire instance.
Returns [`CiApplicationSettings`](#ciapplicationsettings).
+### `Query.ciCatalogResources`
+
+CI Catalog resources visible to the current user.
+
+WARNING:
+**Introduced** in 15.11.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Returns [`CiCatalogResourceConnection`](#cicatalogresourceconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+|