diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-28 00:12:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-28 00:12:19 +0300 |
commit | f3d0329fcb9c703757c4859b12d19c5c3fe42c40 (patch) | |
tree | 499c86fad4ab967a9ffdb2cddeead2afe792968c /app | |
parent | 7badd9fd55f9b877f2de8c8d0126c720a57e538d (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
17 files changed, 202 insertions, 12 deletions
diff --git a/app/assets/javascripts/ci/pipeline_details/constants.js b/app/assets/javascripts/ci/pipeline_details/constants.js index 70b758ae6b0..51d0e980e78 100644 --- a/app/assets/javascripts/ci/pipeline_details/constants.js +++ b/app/assets/javascripts/ci/pipeline_details/constants.js @@ -2,7 +2,6 @@ import { __, s__ } from '~/locale'; export const CANCEL_REQUEST = 'CANCEL_REQUEST'; export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source']; -export const SCHEDULE_ORIGIN = 'schedule'; export const NEEDS_PROPERTY = 'needs'; export const EXPLICIT_NEEDS_PROPERTY = 'previousStageJobsOrNeeds'; diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue index 8f45094eb74..237f1a0306a 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue @@ -1,7 +1,7 @@ <script> import { GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui'; import { helpPagePath } from '~/helpers/help_page_helper'; -import { SCHEDULE_ORIGIN } from '~/ci/pipeline_details/constants'; +import { SCHEDULE_ORIGIN, API_ORIGIN } from '../constants'; export default { components: { @@ -50,6 +50,9 @@ export default { autoDevopsHelpPath() { return helpPagePath('topics/autodevops/index.md'); }, + isApi() { + return this.pipeline.source === API_ORIGIN; + }, }, }; </script> @@ -64,7 +67,7 @@ export default { variant="info" size="sm" data-testid="pipeline-url-scheduled" - >{{ __('Scheduled') }}</gl-badge + >{{ __('scheduled') }}</gl-badge > <gl-badge v-if="pipeline.flags.latest" @@ -185,5 +188,14 @@ export default { data-testid="pipeline-url-fork" >{{ __('fork') }}</gl-badge > + <gl-badge + v-if="isApi" + v-gl-tooltip + :title="__('This pipeline was triggered using the api')" + variant="info" + size="sm" + data-testid="pipeline-api-badge" + >{{ s__('Pipeline|api') }}</gl-badge + > </div> </template> diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue index 2a73795db0a..a53c7cacae2 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue @@ -29,9 +29,5 @@ export default { <gl-avatar-link v-if="user" v-gl-tooltip :href="user.path" :title="user.name" class="gl-ml-3"> <gl-avatar :size="32" :src="user.avatar_url" /> </gl-avatar-link> - - <span v-else class="gl-ml-3"> - {{ s__('Pipelines|API') }} - </span> </div> </template> diff --git a/app/assets/javascripts/ci/pipelines_page/constants.js b/app/assets/javascripts/ci/pipelines_page/constants.js index aa6ef8a25ee..a576ce7f4f5 100644 --- a/app/assets/javascripts/ci/pipelines_page/constants.js +++ b/app/assets/javascripts/ci/pipelines_page/constants.js @@ -1,2 +1,4 @@ export const ANY_TRIGGER_AUTHOR = 'Any'; export const FILTER_PIPELINES_SEARCH_DELAY = 200; +export const SCHEDULE_ORIGIN = 'schedule'; +export const API_ORIGIN = 'api'; diff --git a/app/controllers/groups/work_items_controller.rb b/app/controllers/groups/work_items_controller.rb index bd85f12119b..ece279da778 100644 --- a/app/controllers/groups/work_items_controller.rb +++ b/app/controllers/groups/work_items_controller.rb @@ -4,6 +4,13 @@ module Groups class WorkItemsController < Groups::ApplicationController feature_category :team_planning + before_action do + push_force_frontend_feature_flag(:work_items, group&.work_items_feature_flag_enabled?) + push_force_frontend_feature_flag(:work_items_mvc, group&.work_items_mvc_feature_flag_enabled?) + push_force_frontend_feature_flag(:work_items_mvc_2, group&.work_items_mvc_2_feature_flag_enabled?) + push_force_frontend_feature_flag(:linked_work_items, group&.linked_work_items_feature_flag_enabled?) + end + def index not_found unless Feature.enabled?(:namespace_level_work_items, group) end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 83c4efa5a42..72a5c4d3e69 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -36,6 +36,9 @@ class GroupsController < Groups::ApplicationController push_frontend_feature_flag(:or_issuable_queries, group) push_frontend_feature_flag(:frontend_caching, group) push_force_frontend_feature_flag(:work_items, group.work_items_feature_flag_enabled?) + push_force_frontend_feature_flag(:work_items_mvc, group.work_items_mvc_feature_flag_enabled?) + push_force_frontend_feature_flag(:work_items_mvc_2, group.work_items_mvc_2_feature_flag_enabled?) + push_force_frontend_feature_flag(:linked_work_items, group.linked_work_items_feature_flag_enabled?) push_frontend_feature_flag(:issues_grid_view) push_frontend_feature_flag(:group_multi_select_tokens, group) end diff --git a/app/graphql/mutations/container_registry/protection/rule/create.rb b/app/graphql/mutations/container_registry/protection/rule/create.rb new file mode 100644 index 00000000000..cf8416480a2 --- /dev/null +++ b/app/graphql/mutations/container_registry/protection/rule/create.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module Mutations + module ContainerRegistry + module Protection + module Rule + class Create < ::Mutations::BaseMutation + graphql_name 'CreateContainerRegistryProtectionRule' + description 'Creates a protection rule to restrict access to a project\'s container registry. ' \ + 'Available only when feature flag `container_registry_protected_containers` is enabled.' + + include FindsProject + + authorize :admin_container_image + + argument :project_path, + GraphQL::Types::ID, + required: true, + description: 'Full path of the project where a protection rule is located.' + + argument :container_path_pattern, + GraphQL::Types::String, + required: true, + description: + 'ContainerRegistryname protected by the protection rule. For example `@my-scope/my-container-*`. ' \ + 'Wildcard character `*` allowed.' + + argument :push_protected_up_to_access_level, + Types::ContainerRegistry::Protection::RuleAccessLevelEnum, + required: true, + description: + 'Max GitLab access level to prevent from pushing container images to the container registry. ' \ + 'For example `DEVELOPER`, `MAINTAINER`, `OWNER`.' + + argument :delete_protected_up_to_access_level, + Types::ContainerRegistry::Protection::RuleAccessLevelEnum, + required: true, + description: + 'Max GitLab access level to prevent from deleting container images in the container registry. ' \ + 'For example `DEVELOPER`, `MAINTAINER`, `OWNER`.' + + field :container_registry_protection_rule, + Types::ContainerRegistry::Protection::RuleType, + null: true, + description: 'Container registry protection rule after mutation.' + + def resolve(project_path:, **kwargs) + project = authorized_find!(project_path) + + if Feature.disabled?(:container_registry_protected_containers, project) + raise_resource_not_available_error!("'container_registry_protected_containers' feature flag is disabled") + end + + response = ::ContainerRegistry::Protection::CreateRuleService.new(project, current_user, kwargs).execute + + { container_registry_protection_rule: response.payload[:container_registry_protection_rule], + errors: response.errors } + end + end + end + end + end +end diff --git a/app/graphql/types/container_registry/protection/rule_access_level_enum.rb b/app/graphql/types/container_registry/protection/rule_access_level_enum.rb new file mode 100644 index 00000000000..31e8cbe2e49 --- /dev/null +++ b/app/graphql/types/container_registry/protection/rule_access_level_enum.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + module ContainerRegistry + module Protection + class RuleAccessLevelEnum < BaseEnum + graphql_name 'ContainerRegistryProtectionRuleAccessLevel' + description 'Access level of a container registry protection rule resource' + + ::ContainerRegistry::Protection::Rule.push_protected_up_to_access_levels.each_key do |access_level_key| + value access_level_key.upcase, value: access_level_key.to_s, + description: "#{access_level_key.capitalize} access." + end + end + end + end +end diff --git a/app/graphql/types/container_registry/protection/rule_type.rb b/app/graphql/types/container_registry/protection/rule_type.rb new file mode 100644 index 00000000000..387f0202d2d --- /dev/null +++ b/app/graphql/types/container_registry/protection/rule_type.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Types + module ContainerRegistry + module Protection + class RuleType < ::Types::BaseObject + graphql_name 'ContainerRegistryProtectionRule' + description 'A container registry protection rule designed to prevent users with a certain ' \ + 'access level or lower from altering the container registry.' + + authorize :admin_container_image + + field :id, + ::Types::GlobalIDType[::ContainerRegistry::Protection::Rule], + null: false, + description: 'ID of the container registry protection rule.' + + field :container_path_pattern, + GraphQL::Types::String, + null: false, + description: + 'Container repository path pattern protected by the protection rule. ' \ + 'For example `@my-scope/my-container-*`. Wildcard character `*` allowed.' + + field :push_protected_up_to_access_level, + Types::ContainerRegistry::Protection::RuleAccessLevelEnum, + null: false, + description: + 'Max GitLab access level to prevent from pushing container images to the container registry. ' \ + 'For example `DEVELOPER`, `MAINTAINER`, `OWNER`.' + + field :delete_protected_up_to_access_level, + Types::ContainerRegistry::Protection::RuleAccessLevelEnum, + null: false, + description: + 'Max GitLab access level to prevent from pushing container images to the container registry. ' \ + 'For example `DEVELOPER`, `MAINTAINER`, `OWNER`.' + end + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 475066e7279..4ff64d6f60c 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -134,6 +134,7 @@ module Types mount_mutation Mutations::DesignManagement::Move mount_mutation Mutations::DesignManagement::Update mount_mutation Mutations::ContainerExpirationPolicies::Update + mount_mutation Mutations::ContainerRegistry::Protection::Rule::Create, alpha: { milestone: '16.6' } mount_mutation Mutations::ContainerRepositories::Destroy mount_mutation Mutations::ContainerRepositories::DestroyTags mount_mutation Mutations::Ci::Catalog::Resources::Create, alpha: { milestone: '15.11' } diff --git a/app/policies/container_registry/protection/rule_policy.rb b/app/policies/container_registry/protection/rule_policy.rb new file mode 100644 index 00000000000..4dc8dba3276 --- /dev/null +++ b/app/policies/container_registry/protection/rule_policy.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module ContainerRegistry + module Protection + class RulePolicy < BasePolicy + delegate { @subject.project } + end + end +end diff --git a/app/services/container_registry/protection/create_rule_service.rb b/app/services/container_registry/protection/create_rule_service.rb new file mode 100644 index 00000000000..34ec6f42b19 --- /dev/null +++ b/app/services/container_registry/protection/create_rule_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module ContainerRegistry + module Protection + class CreateRuleService < BaseService + ALLOWED_ATTRIBUTES = %i[ + container_path_pattern + push_protected_up_to_access_level + delete_protected_up_to_access_level + ].freeze + + def execute + unless can?(current_user, :admin_container_image, project) + error_message = _('Unauthorized to create a container registry protection rule') + return service_response_error(message: error_message) + end + + container_registry_protection_rule = + project.container_registry_protection_rules.create(params.slice(*ALLOWED_ATTRIBUTES)) + + unless container_registry_protection_rule.persisted? + return service_response_error(message: container_registry_protection_rule.errors.full_messages.to_sentence) + end + + ServiceResponse.success(payload: { container_registry_protection_rule: container_registry_protection_rule }) + rescue StandardError => e + service_response_error(message: e.message) + end + + private + + def service_response_error(message:) + ServiceResponse.error( + message: message, + payload: { container_registry_protection_rule: nil } + ) + end + end + end +end diff --git a/app/views/projects/branch_rules/_show.html.haml b/app/views/projects/branch_rules/_show.html.haml index c16c03953c6..10cb91e35bd 100644 --- a/app/views/projects/branch_rules/_show.html.haml +++ b/app/views/projects/branch_rules/_show.html.haml @@ -3,7 +3,7 @@ - show_status_checks = @project.licensed_feature_available?(:external_status_checks) - show_approvers = @project.licensed_feature_available?(:merge_request_approvers) -%section.settings.no-animate#branch-rules{ class: ('expanded' if expanded), data: { qa_selector: 'branch_rules_content' } } +%section.settings.no-animate#branch-rules{ class: ('expanded' if expanded), data: { testid: 'branch-rules-content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Branch rules') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index 00837ce1c73..1083da5402b 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -3,7 +3,7 @@ - mirror_settings_enabled = can?(current_user, :admin_remote_mirror, @project) - mirror_settings_class = "#{'expanded' if expanded} #{'js-mirror-settings' if mirror_settings_enabled}".strip -%section.settings.project-mirror-settings.no-animate#js-push-remote-settings{ class: mirror_settings_class, data: { qa_selector: 'mirroring_repositories_settings_content' } } +%section.settings.project-mirror-settings.no-animate#js-push-remote-settings{ class: mirror_settings_class, data: { testid: 'mirroring-repositories-settings-content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Mirroring repositories') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do diff --git a/app/views/projects/protected_tags/shared/_index.html.haml b/app/views/projects/protected_tags/shared/_index.html.haml index f71ecc3a7c5..5c810b55bec 100644 --- a/app/views/projects/protected_tags/shared/_index.html.haml +++ b/app/views/projects/protected_tags/shared/_index.html.haml @@ -1,6 +1,6 @@ - expanded = expanded_by_default? -%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_tag_settings_content' } } +%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded), data: { testid: 'protected-tag-settings-content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = s_("ProtectedTag|Protected tags") diff --git a/app/views/protected_branches/shared/_index.html.haml b/app/views/protected_branches/shared/_index.html.haml index 8e72563182c..ce5b58ee189 100644 --- a/app/views/protected_branches/shared/_index.html.haml +++ b/app/views/protected_branches/shared/_index.html.haml @@ -1,7 +1,7 @@ - can_admin_entity = protected_branch_can_admin_entity?(protected_branch_entity) - expanded = expanded_by_default? -%section.settings.no-animate#js-protected-branches-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_branches_settings_content' } } +%section.settings.no-animate#js-protected-branches-settings{ class: ('expanded' if expanded), data: { testid: 'protected-branches-settings-content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only = s_("ProtectedBranch|Protected branches") diff --git a/app/views/shared/deploy_tokens/_index.html.haml b/app/views/shared/deploy_tokens/_index.html.haml index ccffc3ec923..74de71867b8 100644 --- a/app/views/shared/deploy_tokens/_index.html.haml +++ b/app/views/shared/deploy_tokens/_index.html.haml @@ -1,6 +1,6 @@ - expanded = expand_deploy_tokens_section?(@new_deploy_token, @created_deploy_token) -%section.settings.no-animate#js-deploy-tokens{ class: ('expanded' if expanded), data: { qa_selector: 'deploy_tokens_settings_content' } } +%section.settings.no-animate#js-deploy-tokens{ class: ('expanded' if expanded), data: { testid: 'deploy-tokens-settings-content' } } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= s_('DeployTokens|Deploy tokens') = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do |