diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-05 21:10:31 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-05 21:10:31 +0300 |
commit | 8f4d63426a207611f71bc19dae62eb19765a4cf2 (patch) | |
tree | b5843aaef889b0d1305e669404693f11ce414d22 | |
parent | cf05fd7f3956f0b1a17caf313e89bb7b3315d947 (diff) |
Add latest changes from gitlab-org/gitlab@master
76 files changed, 936 insertions, 305 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 9b41fee9ab9..c63ad882487 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -22,12 +22,14 @@ /doc/administration/reference_architectures/ @axil /doc/administration/snippets/ @aqualls /doc/administration/troubleshooting @axil @marcia @mjang1 +/doc/api/group_activity_analytics.md @msedlakjakubowski /doc/ci/ @marcel.amirault @sselhorn /doc/ci/environments/ @axil /doc/ci/services/ @sselhorn /doc/ci/test_cases/ @msedlakjakubowski /doc/development/ @marcia @mjang1 /doc/development/documentation/ @cnorris +/doc/development/value_stream_analytics.md @msedlakjakubowski /doc/gitlab-basics/ @marcia /doc/install/ @axil /doc/integration/ @aqualls @mjang1 @@ -38,15 +40,18 @@ /doc/topics/autodevops/ @ngaskill @marcia /doc/topics/git/ @aqualls /doc/update/ @axil @marcia -/doc/user/analytics/ @mjang1 @ngaskill +/doc/user/analytics/ @msedlakjakubowski @ngaskill /doc/user/application_security @rdickenson /doc/user/clusters/ @marcia /doc/user/compliance/ @mjang1 @rdickenson -/doc/user/group/ @mjang1 @msedlakjakubowski +/doc/user/group/ @msedlakjakubowski /doc/user/group/bulk_editing/ @msedlakjakubowski +/doc/user/group/devops_adoption/ @msedlakjakubowski /doc/user/group/epics/ @msedlakjakubowski +/doc/user/group/insights/ @msedlakjakubowski /doc/user/group/iterations/ @msedlakjakubowski /doc/user/group/roadmap/ @msedlakjakubowski +/doc/user/group/value_stream_analytics/ @msedlakjakubowski /doc/user/infrastructure/ @marcia /doc/user/packages/ @ngaskill /doc/user/profile/ @mjang1 @msedlakjakubowski @@ -133,7 +138,7 @@ [Docs Growth] /doc/administration/instance_review.md @aqualls /doc/api/invitations.md @aqualls -/doc/api/experiments.md @aqualls +/doc/api/experiments.md @aqualls /doc/development/experiment_guide/ @aqualls /doc/development/snowplow/ @aqualls /doc/development/usage_ping/ @aqualls @@ -181,9 +186,9 @@ Dangerfile @gl-quality/eng-prod .editorconfig @gl-quality/eng-prod [Backend Static Code Analysis] -.rubocop*.yml @dstull @splattael @gl-quality/eng-prod -/rubocop/ @dstull @splattael @gl-quality/eng-prod -/spec/rubocop/ @dstull @splattael @gl-quality/eng-prod +.rubocop*.yml @dstull @splattael @gl-quality/eng-prod +/rubocop/ @dstull @splattael @gl-quality/eng-prod +/spec/rubocop/ @dstull @splattael @gl-quality/eng-prod [End-to-end] /qa/ @gl-quality @@ -291,4 +296,4 @@ Dangerfile @gl-quality/eng-prod /config/dependency_decisions.yml @gitlab-org/legal-reviewers [Workhorse] -/workhorse/ @jacobvosmaer-gitlab @nick.thomas @nolith @patrickbajao +/workhorse/ @jacobvosmaer-gitlab @nick.thomas @nolith @patrickbajao diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index 48a495a0ead..c1285c77e01 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -13,7 +13,6 @@ # WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/322903 Graphql/Descriptions: Exclude: - - 'app/graphql/types/base_enum.rb' - 'app/graphql/types/container_expiration_policy_cadence_enum.rb' - 'app/graphql/types/container_expiration_policy_keep_enum.rb' - 'app/graphql/types/container_expiration_policy_older_than_enum.rb' diff --git a/app/assets/javascripts/issuable/components/csv_export_modal.vue b/app/assets/javascripts/issuable/components/csv_export_modal.vue index 7bdd55ddda3..f17440a4a14 100644 --- a/app/assets/javascripts/issuable/components/csv_export_modal.vue +++ b/app/assets/javascripts/issuable/components/csv_export_modal.vue @@ -21,13 +21,11 @@ export default { props: { exportCsvPath: { type: String, - required: false, - default: '', + required: true, }, issuableCount: { type: Number, - required: false, - default: 0, + required: true, }, modalId: { type: String, diff --git a/app/assets/stylesheets/page_bundles/pipelines.scss b/app/assets/stylesheets/page_bundles/pipelines.scss index 6ef7f912ea9..ace91d197b6 100644 --- a/app/assets/stylesheets/page_bundles/pipelines.scss +++ b/app/assets/stylesheets/page_bundles/pipelines.scss @@ -182,11 +182,6 @@ button.gl-button.btn-link.mini-pipeline-graph-dropdown-toggle { border-bottom-color: $border-color; } - &::after { - margin-top: 1px; - border-bottom-color: $white; - } - /** * Center dropdown menu in mini graph */ diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss index f9e9a7a99b7..abf94c520c3 100644 --- a/app/assets/stylesheets/utilities.scss +++ b/app/assets/stylesheets/utilities.scss @@ -182,3 +182,10 @@ .gl-mb-n3 { margin-bottom: -$gl-spacing-scale-3; } + +// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1408 +$gl-line-height-42: px-to-rem(42px); + +.gl-line-height-42 { + line-height: $gl-line-height-42; +} diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index e85b282050c..e6aae144da6 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -125,14 +125,14 @@ class InvitesController < ApplicationController name: member.source.full_name, url: project_url(member.source), title: _("project"), - path: activity_project_path(member.source) + path: member.source.activity_path } when Group { name: member.source.name, url: group_url(member.source), title: _("group"), - path: activity_group_path(member.source) + path: member.source.activity_path } end end diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb index 89fc1e4aa3c..b50b8597acd 100644 --- a/app/controllers/registrations/welcome_controller.rb +++ b/app/controllers/registrations/welcome_controller.rb @@ -18,8 +18,10 @@ module Registrations if result[:status] == :success return redirect_to new_users_sign_up_group_path if show_signup_onboarding? - if current_user.members.count == 1 - redirect_to path_for_signed_in_user(current_user), notice: helpers.invite_accepted_notice(current_user.members.last) + members = current_user.members + + if members.count == 1 && members.last.source.present? + redirect_to members_activity_path(members), notice: helpers.invite_accepted_notice(members.last) else redirect_to path_for_signed_in_user(current_user) end @@ -52,20 +54,14 @@ module Registrations def path_for_signed_in_user(user) return users_almost_there_path if requires_confirmation?(user) - stored_location_for(user) || members_activity_path(user) + stored_location_for(user) || members_activity_path(user.members) end - def members_activity_path(user) - return dashboard_projects_path unless user.members.count >= 1 + def members_activity_path(members) + return dashboard_projects_path unless members.any? + return dashboard_projects_path unless members.last.source.present? - case user.members.last.source - when Project - activity_project_path(user.members.last.source) - when Group - activity_group_path(user.members.last.source) - else - dashboard_projects_path - end + members.last.source.activity_path end def show_signup_onboarding? diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb index e1a334413f8..0866040d399 100644 --- a/app/finders/issues_finder.rb +++ b/app/finders/issues_finder.rb @@ -25,7 +25,7 @@ # updated_after: datetime # updated_before: datetime # confidential: boolean -# issue_type: array of strings (one of Issue.issue_types) +# issue_types: array of strings (one of Issue.issue_types) # class IssuesFinder < IssuableFinder CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::REPORTER diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb index 518a902a5d7..7ef1cbddbd9 100644 --- a/app/graphql/types/base_enum.rb +++ b/app/graphql/types/base_enum.rb @@ -17,6 +17,9 @@ module Types # declarative_enum MyDeclarativeEnum # end # + # Disabling descriptions rubocop for a false positive here + # rubocop: disable Graphql/Descriptions + # def declarative_enum(enum_mod, use_name: true, use_description: true) graphql_name(enum_mod.name) if use_name description(enum_mod.description) if use_description @@ -25,6 +28,7 @@ module Types value(key.to_s.upcase, **content) end end + # rubocop: enable Graphql/Descriptions # Helper to define an enum member for each element of a Rails AR enum def from_rails_enum(enum, description:) diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb index 0711a6b7e97..b197d8e1f7a 100644 --- a/app/helpers/services_helper.rb +++ b/app/helpers/services_helper.rb @@ -172,6 +172,10 @@ module ServicesHelper name: integration.to_param } end + + def show_service_templates_nav_link? + Feature.disabled?(:disable_service_templates, type: :development, default_enabled: :yaml) + end end ServicesHelper.prepend_if_ee('EE::ServicesHelper') diff --git a/app/models/concerns/enums/ci/commit_status.rb b/app/models/concerns/enums/ci/commit_status.rb index de17f50cd29..a1ebf420819 100644 --- a/app/models/concerns/enums/ci/commit_status.rb +++ b/app/models/concerns/enums/ci/commit_status.rb @@ -22,6 +22,7 @@ module Enums forward_deployment_failure: 13, user_blocked: 14, project_deleted: 15, + ci_quota_exceeded: 16, insufficient_bridge_permissions: 1_001, downstream_bridge_project_not_found: 1_002, invalid_bridge_trigger: 1_003, diff --git a/app/models/group.rb b/app/models/group.rb index a8626ce9ef8..625ecd516a4 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -708,6 +708,10 @@ class Group < Namespace model_name.singular end + def activity_path + Gitlab::Routing.url_helpers.activity_group_path(self) + end + private def update_two_factor_requirement diff --git a/app/models/project.rb b/app/models/project.rb index b21f61ee11f..af203d90e73 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2570,6 +2570,10 @@ class Project < ApplicationRecord Feature.enabled?(:inherited_issuable_templates, self, default_enabled: :yaml) end + def activity_path + Gitlab::Routing.url_helpers.activity_project_path(self) + end + private def set_container_registry_access_level diff --git a/app/presenters/commit_status_presenter.rb b/app/presenters/commit_status_presenter.rb index c8d3457b04a..7b639c709e1 100644 --- a/app/presenters/commit_status_presenter.rb +++ b/app/presenters/commit_status_presenter.rb @@ -23,7 +23,8 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated secrets_provider_not_found: 'The secrets provider can not be found', reached_max_descendant_pipelines_depth: 'You reached the maximum depth of child pipelines', project_deleted: 'The job belongs to a deleted project', - user_blocked: 'The user who created this job is blocked' + user_blocked: 'The user who created this job is blocked', + ci_quota_exceeded: 'No more CI minutes available' }.freeze private_constant :CALLOUT_FAILURE_MESSAGES diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index aa6b0146df7..b71866c9138 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -202,17 +202,18 @@ = render_if_exists 'layouts/nav/sidebar/credentials_link' - = nav_link(controller: :services) do - = link_to admin_application_settings_services_path do - .nav-icon-container - = sprite_icon('template') - %span.nav-item-name - = _('Service Templates') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :services, html_options: { class: "fly-out-top-item" } ) do - = link_to admin_application_settings_services_path do - %strong.fly-out-top-item-name - = _('Service Templates') + - if show_service_templates_nav_link? + = nav_link(controller: :services) do + = link_to admin_application_settings_services_path do + .nav-icon-container + = sprite_icon('template') + %span.nav-item-name + = _('Service Templates') + %ul.sidebar-sub-level-items.is-fly-out-only + = nav_link(controller: :services, html_options: { class: "fly-out-top-item" } ) do + = link_to admin_application_settings_services_path do + %strong.fly-out-top-item-name + = _('Service Templates') = nav_link(controller: :labels) do = link_to admin_labels_path do diff --git a/changelogs/unreleased/extend_branch_support_for_sse.yml b/changelogs/unreleased/extend_branch_support_for_sse.yml new file mode 100644 index 00000000000..df433ec436c --- /dev/null +++ b/changelogs/unreleased/extend_branch_support_for_sse.yml @@ -0,0 +1,5 @@ +--- +title: Extend branch support for Static Site Editor +merge_request: 60848 +author: +type: changed diff --git a/changelogs/unreleased/gmh-ensure-highlighting-limits-are-configurable-and-documented.yml b/changelogs/unreleased/gmh-ensure-highlighting-limits-are-configurable-and-documented.yml new file mode 100644 index 00000000000..0b7d2577528 --- /dev/null +++ b/changelogs/unreleased/gmh-ensure-highlighting-limits-are-configurable-and-documented.yml @@ -0,0 +1,5 @@ +--- +title: Ensure highlighting limits are documented, configurable, and monitorable +merge_request: 60445 +author: +type: added diff --git a/changelogs/unreleased/sy-create-incidents-via-api.yml b/changelogs/unreleased/sy-create-incidents-via-api.yml new file mode 100644 index 00000000000..2752b1849b5 --- /dev/null +++ b/changelogs/unreleased/sy-create-incidents-via-api.yml @@ -0,0 +1,6 @@ +--- +title: Add support for create, updating, and filtering issues based on issue type + in REST API +merge_request: 60687 +author: +type: added diff --git a/config/feature_flags/development/ci_minutes_track_live_consumption.yml b/config/feature_flags/development/ci_minutes_track_live_consumption.yml new file mode 100644 index 00000000000..ddd21f3909e --- /dev/null +++ b/config/feature_flags/development/ci_minutes_track_live_consumption.yml @@ -0,0 +1,8 @@ +--- +name: ci_minutes_track_live_consumption +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59263 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/329197 +milestone: '13.12' +type: development +group: group::continuous integration +default_enabled: false diff --git a/config/feature_flags/development/disable_service_templates.yml b/config/feature_flags/development/disable_service_templates.yml new file mode 100644 index 00000000000..07e52224b98 --- /dev/null +++ b/config/feature_flags/development/disable_service_templates.yml @@ -0,0 +1,8 @@ +--- +name: disable_service_templates +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59098 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327436 +milestone: '13.12' +type: development +group: group::ecosystem +default_enabled: false diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index bd785977462..aee9dd455af 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1270,6 +1270,10 @@ production: &base # matomo_site_id: '_your_matomo_site_id' # matomo_disable_cookies: false + ## Maximum file size for syntax highlighting + ## https://docs.gitlab.com/ee/user/project/highlighting.html + # maximum_text_highlight_size_kilobytes: 512 + rack_attack: git_basic_auth: # Rack Attack IP banning enabled diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 05e9259c106..64ae868735a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -856,6 +856,7 @@ Settings['extra'] ||= Settingslogic.new({}) Settings.extra['matomo_site_id'] ||= Settings.extra['piwik_site_id'] if Settings.extra['piwik_site_id'].present? Settings.extra['matomo_url'] ||= Settings.extra['piwik_url'] if Settings.extra['piwik_url'].present? Settings.extra['matomo_disable_cookies'] = false if Settings.extra['matomo_disable_cookies'].nil? +Settings.extra['maximum_text_highlight_size_kilobytes'] = Settings.extra.fetch('maximum_text_highlight_size_kilobytes', 512).kilobytes # # Rack::Attack settings diff --git a/config/metrics/counts_28d/20210216174956_i_analytics_cohorts_monthly.yml b/config/metrics/counts_28d/20210216174956_i_analytics_cohorts_monthly.yml index 3ac2e608210..dc0d7f35622 100644 --- a/config/metrics/counts_28d/20210216174956_i_analytics_cohorts_monthly.yml +++ b/config/metrics/counts_28d/20210216174956_i_analytics_cohorts_monthly.yml @@ -1,9 +1,9 @@ --- key_path: redis_hll_counters.analytics.i_analytics_cohorts_monthly description: -product_section: dev -product_stage: manage -product_group: group::optimize +product_section: fulfillment +product_stage: fulfillment +product_group: group::utilization product_category: value_type: number status: data_available diff --git a/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb b/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb index a1e1dbbeafe..81fe65c1945 100644 --- a/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb +++ b/db/post_migrate/20210505092746_create_partial_covering_index_for_pending_builds.rb @@ -9,13 +9,16 @@ class CreatePartialCoveringIndexForPendingBuilds < ActiveRecord::Migration[6.0] NEW_INDEX = 'index_ci_builds_runner_id_pending_covering' def up - execute "CREATE INDEX CONCURRENTLY #{NEW_INDEX} ON ci_builds (runner_id, id) INCLUDE (project_id) WHERE status = 'pending' AND type = 'Ci::Build'" unless index_exists_by_name?(:ci_builds, NEW_INDEX) + disable_statement_timeout do + execute "CREATE INDEX CONCURRENTLY #{NEW_INDEX} ON ci_builds (runner_id, id) INCLUDE (project_id) WHERE status = 'pending' AND type = 'Ci::Build'" unless index_exists_by_name?(:ci_builds, NEW_INDEX) + end remove_concurrent_index_by_name :ci_builds, EXISTING_INDEX end def down add_concurrent_index :ci_builds, :runner_id, where: "status = 'pending' AND type = 'Ci::Build'", name: EXISTING_INDEX + remove_concurrent_index_by_name :ci_builds, NEW_INDEX end end diff --git a/doc/administration/application_settings_cache.md b/doc/administration/application_settings_cache.md index b6c09129c79..b3aac932fa8 100644 --- a/doc/administration/application_settings_cache.md +++ b/doc/administration/application_settings_cache.md @@ -4,16 +4,15 @@ group: Memory info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- -# Changing application settings cache expiry interval **(FREE SELF)** +# Change the expiration interval for application cache **(FREE SELF)** -Application settings are cached for 60 seconds by default which should work -for most installations. A higher value would mean a greater delay between -changing an application setting and noticing that change come into effect. -A value of `0` would result in the `application_settings` table being -loaded for every request causing extra load on Redis and/or PostgreSQL. -It is therefore recommended to keep the value above zero. +By default, GitLab caches application settings for 60 seconds. Occasionally, +you may need to increase that interval to have more delay between application +setting changes and when users notice those changes in the application. -## Change the application settings cache expiry +We recommend you set this value to greater than `0` seconds. Setting it to `0` +causes the `application_settings` table to load for every request. This causes +extra load for Redis and PostgreSQL. To change the expiry value: @@ -25,7 +24,8 @@ To change the expiry value: gitlab_rails['application_settings_cache_seconds'] = 60 ``` -1. Save the file, and reconfigure and restart GitLab for the changes to take effect: +1. Save the file, and then reconfigure and restart GitLab for the changes to + take effect: ```shell gitlab-ctl reconfigure @@ -43,5 +43,5 @@ To change the expiry value: application_settings_cache_seconds: 60 ``` -1. Save the file and [restart](restart_gitlab.md#installations-from-source) +1. Save the file, and then [restart](restart_gitlab.md#installations-from-source) GitLab for the changes to take effect. diff --git a/doc/administration/incoming_email.md b/doc/administration/incoming_email.md index 693c22f925c..9aa6bffdb98 100644 --- a/doc/administration/incoming_email.md +++ b/doc/administration/incoming_email.md @@ -185,8 +185,11 @@ Example for Omnibus installs: ```ruby gitlab_rails['incoming_email_enabled'] = true -# The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to. -# The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`). +# The email address including the %{key} placeholder that will be replaced to reference the +# item being replied to. This %{key} should be included in its entirety within the email +# address and not replaced by another value. +# For example: emailaddress+%{key}@gitlab.example.com. +# The placeholder must appear in the "user" part of the address (before the `@`). gitlab_rails['incoming_email_address'] = "incoming+%{key}@gitlab.example.com" # Email account username @@ -223,7 +226,7 @@ incoming_email: # The email address including the %{key} placeholder that will be replaced to reference the # item being replied to. This %{key} should be included in its entirety within the email # address and not replaced by another value. - # For example: emailadress+%{key}@gmail.com. + # For example: emailaddress+%{key}@gitlab.example.com. # The placeholder must appear in the "user" part of the address (before the `@`). address: "incoming+%{key}@gitlab.example.com" @@ -264,8 +267,11 @@ Example for Omnibus installs: ```ruby gitlab_rails['incoming_email_enabled'] = true -# The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to. -# The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`). +# The email address including the %{key} placeholder that will be replaced to reference the +# item being replied to. This %{key} should be included in its entirety within the email +# address and not replaced by another value. +# For example: emailaddress+%{key}@gmail.com. +# The placeholder must appear in the "user" part of the address (before the `@`). gitlab_rails['incoming_email_address'] = "gitlab-incoming+%{key}@gmail.com" # Email account username @@ -299,8 +305,11 @@ Example for source installs: incoming_email: enabled: true - # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to. - # The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`). + # The email address including the %{key} placeholder that will be replaced to reference the + # item being replied to. This %{key} should be included in its entirety within the email + # address and not replaced by another value. + # For example: emailaddress+%{key}@gmail.com. + # The placeholder must appear in the "user" part of the address (before the `@`). address: "gitlab-incoming+%{key}@gmail.com" # Email account username @@ -345,8 +354,11 @@ Example for Omnibus installs: ```ruby gitlab_rails['incoming_email_enabled'] = true -# The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to. -# The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`). +# The email address including the %{key} placeholder that will be replaced to reference the +# item being replied to. This %{key} should be included in its entirety within the email +# address and not replaced by another value. +# For example: emailaddress-%{key}@exchange.example.com. +# The placeholder must appear in the "user" part of the address (before the `@`). # Exchange does not support sub-addressing, so a catch-all mailbox must be used. gitlab_rails['incoming_email_address'] = "incoming-%{key}@exchange.example.com" @@ -370,8 +382,11 @@ Example for source installs: incoming_email: enabled: true - # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to. - # The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`). + # The email address including the %{key} placeholder that will be replaced to reference the + # item being replied to. This %{key} should be included in its entirety within the email + # address and not replaced by another value. + # For example: emailaddress-%{key}@exchange.example.com. + # The placeholder must appear in the "user" part of the address (before the `@`). # Exchange does not support sub-addressing, so a catch-all mailbox must be used. address: "incoming-%{key}@exchange.example.com" @@ -476,9 +491,11 @@ This example for Omnibus GitLab assumes the mailbox `incoming@office365.example. ```ruby gitlab_rails['incoming_email_enabled'] = true -# The email address including the `%{key}` placeholder that will be replaced -# to reference the item being replied to. The placeholder can be omitted, but if -# present, it must appear in the "user" part of the address (before the `@`). +# The email address including the %{key} placeholder that will be replaced to reference the +# item being replied to. This %{key} should be included in its entirety within the email +# address and not replaced by another value. +# For example: emailaddress+%{key}@office365.example.com. +# The placeholder must appear in the "user" part of the address (before the `@`). gitlab_rails['incoming_email_address'] = "incoming+%{key}@office365.example.com" # Email account username @@ -501,9 +518,11 @@ This example for source installs assumes the mailbox `incoming@office365.example incoming_email: enabled: true - # The email address including the `%{key}` placeholder that will be replaced - # to reference the item being replied to. The placeholder can be omitted, but - # if present, it must appear in the "user" part of the address (before the `@`). + # The email address including the %{key} placeholder that will be replaced to reference the + # item being replied to. This %{key} should be included in its entirety within the email + # address and not replaced by another value. + # For example: emailaddress+%{key}@office365.example.com. + # The placeholder must appear in the "user" part of the address (before the `@`). address: "incoming+%{key}@office365.example.comm" # Email account username @@ -527,9 +546,11 @@ This example for Omnibus installs assumes the catch-all mailbox `incoming@office ```ruby gitlab_rails['incoming_email_enabled'] = true -# The email address including the `%{key}` placeholder that will be replaced to -# reference the item being replied to. The placeholder can be omitted, but if present, -# it must appear in the "user" part of the address (before the `@`). +# The email address including the %{key} placeholder that will be replaced to reference the +# item being replied to. This %{key} should be included in its entirety within the email +# address and not replaced by another value. +# For example: emailaddress-%{key}@office365.example.com. +# The placeholder must appear in the "user" part of the address (before the `@`). gitlab_rails['incoming_email_address'] = "incoming-%{key}@office365.example.com" # Email account username @@ -552,9 +573,11 @@ This example for source installs assumes the catch-all mailbox `incoming@office3 incoming_email: enabled: true - # The email address including the `%{key}` placeholder that will be replaced - # to reference the item being replied to. The placeholder can be omitted, but - # if present, it must appear in the "user" part of the address (before the `@`). + # The email address including the %{key} placeholder that will be replaced to reference the + # item being replied to. This %{key} should be included in its entirety within the email + # address and not replaced by another value. + # For example: emailaddress+%{key}@office365.example.com. + # The placeholder must appear in the "user" part of the address (before the `@`). address: "incoming-%{key}@office365.example.com" # Email account username @@ -653,9 +676,11 @@ This example for Omnibus GitLab assumes you're using the following mailbox: `inc ```ruby gitlab_rails['incoming_email_enabled'] = true -# The email address including the `%{key}` placeholder that will be replaced -# to reference the item being replied to. The placeholder can be omitted, but if -# present, it must appear in the "user" part of the address (before the `@`). +# The email address including the %{key} placeholder that will be replaced to reference the +# item being replied to. This %{key} should be included in its entirety within the email +# address and not replaced by another value. +# For example: emailaddress+%{key}@example.onmicrosoft.com. +# The placeholder must appear in the "user" part of the address (before the `@`). gitlab_rails['incoming_email_address'] = "incoming+%{key}@example.onmicrosoft.com" # Email account username diff --git a/doc/api/group_relations_export.md b/doc/api/group_relations_export.md new file mode 100644 index 00000000000..bb19f7f0923 --- /dev/null +++ b/doc/api/group_relations_export.md @@ -0,0 +1,101 @@ +--- +stage: Manage +group: Import +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Group Relations Export API + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59978) in GitLab 13.12. + +With the Group Relations Export API, you can partially export group structure. This API is similar +to [group export](group_import_export.md), +but it exports each top-level relation (for example, milestones/boards/labels) as a separate file +instead of one archive. The group relations export API is primarily used in [group migration](../user/group/index.md). + +## Schedule new export + +Start a new group relations export: + +```plaintext +POST /groups/:id/export_relations +``` + +| Attribute | Type | Required | Description | +| --------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | ID of the group owned by the authenticated user. | + +```shell +curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/export_relations" +``` + +```json +{ + "message": "202 Accepted" +} +``` + +## Export status + +View the status of the relations export: + +```plaintext +GET /groups/:id/export_relations/status +``` + +| Attribute | Type | Required | Description | +| --------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | ID of the group owned by the authenticated user. | + +```shell +curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/export_relations/status" +``` + +The status can be one of the following: + +- `0`: `started` +- `1`: `finished` +- `-1`: `failed` + +- `0` - `started` +- `1` - `finished` +- `-1` - `failed` + +```json +[ + { + "relation": "badges", + "status": 1, + "error": null, + "updated_at": "2021-05-04T11:25:20.423Z" + }, + { + "relation": "boards", + "status": 1, + "error": null, + "updated_at": "2021-05-04T11:25:20.085Z" + } +] +``` + +## Export download + +Download the finished relations export: + +```plaintext +GET /groups/:id/export_relations/download +``` + +| Attribute | Type | Required | Description | +| --------------- | -------------- | -------- | ---------------------------------------- | +| `id` | integer/string | yes | ID of the group owned by the authenticated user. | +| `relation` | string | yes | Name of the group top-level relation to download. | + +```shell +curl --header "PRIVATE-TOKEN: <your_access_token>" --remote-header-name --remote-name "https://gitlab.example.com/api/v4/groups/1/export_relations/download?relation=labels" +``` + +```shell +ls labels.ndjson.gz +labels.ndjson.gz +``` diff --git a/doc/api/groups.md b/doc/api/groups.md index b1e1e2bb6c5..86f44797254 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -1257,7 +1257,9 @@ Read more in the [Group Badges](group_badges.md) documentation. ## Group Import/Export -Read more in the [Group Import/Export](group_import_export.md) documentation. +Read more in the [Group Import/Export](group_import_export.md) +and [Group Relations Export](group_relations_export.md) +documentation. ## Share Groups with Groups diff --git a/doc/api/issues.md b/doc/api/issues.md index 5ed3526cd7f..08521cd2f94 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -62,6 +62,7 @@ GET /issues?state=opened | `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | | `iids[]` | integer array | no | Return only the issues having the given `iid` | | `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` | +| `issue_type` | string | no | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. _(Introduced in [GitLab 13.12](https://gitlab.com/gitlab-org/gitlab/-/issues/260375))_ | | `iteration_id` **(PREMIUM)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. | @@ -158,6 +159,7 @@ Example response: "task_status": "10 of 15 tasks completed", "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links":{ "self":"http://gitlab.example.com/api/v4/projects/1/issues/76", "notes":"http://gitlab.example.com/api/v4/projects/1/issues/76/notes", @@ -267,6 +269,7 @@ GET /groups/:id/issues?state=opened | `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `iids[]` | integer array | no | Return only the issues having the given `iid` | +| `issue_type` | string | no | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. _(Introduced in [GitLab 13.12](https://gitlab.com/gitlab-org/gitlab/-/issues/260375))_ | | `iteration_id` **(PREMIUM)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | @@ -361,6 +364,7 @@ Example response: "task_status": "10 of 15 tasks completed", "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links":{ "self":"http://gitlab.example.com/api/v4/projects/4/issues/41", "notes":"http://gitlab.example.com/api/v4/projects/4/issues/41/notes", @@ -469,6 +473,7 @@ GET /projects/:id/issues?state=opened | `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. _(Introduced in [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/233420))_ | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `iids[]` | integer array | no | Return only the issues having the given `iid` | +| `issue_type` | string | no | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. _(Introduced in [GitLab 13.12](https://gitlab.com/gitlab-org/gitlab/-/issues/260375))_ | | `iteration_id` **(PREMIUM)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | @@ -569,6 +574,7 @@ Example response: "task_status": "10 of 15 tasks completed", "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links":{ "self":"http://gitlab.example.com/api/v4/projects/4/issues/41", "notes":"http://gitlab.example.com/api/v4/projects/4/issues/41/notes", @@ -729,6 +735,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "task_completion_status": { "count": 0, "completed_count": 0 @@ -895,6 +902,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links": { "self": "http://gitlab.example.com/api/v4/projects/1/issues/2", "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes", @@ -985,6 +993,7 @@ POST /projects/:id/issues | `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal in API version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `iid` | integer/string | no | The internal ID of the project's issue (requires administrator or project owner rights) | +| `issue_type` | string | no | The type of issue. One of `issue`, `incident`, or `test_case`. Default is `issue`. | | `labels` | string | no | Comma-separated label names for an issue | | `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This fills out the issue with a default description and mark all discussions as resolved. When passing a description or title, these values take precedence over the default values.| | `milestone_id` | integer | no | The global ID of a milestone to assign issue | @@ -1044,6 +1053,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links": { "self": "http://gitlab.example.com/api/v4/projects/1/issues/2", "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes", @@ -1131,6 +1141,7 @@ At least one of the following parameters is required for the request to be succe - `:description` - `:discussion_locked` - `:due_date` +- `:issue_type` - `:labels` - `:milestone_id` - `:state_event` @@ -1152,6 +1163,7 @@ PUT /projects/:id/issues/:issue_iid | `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal in API version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `issue_iid` | integer | yes | The internal ID of a project's issue | +| `issue_type` | string | no | Updates the type of issue. One of `issue`, `incident`, or `test_case`. | | `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. | | `milestone_id` | integer | no | The global ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.| | `remove_labels`| string | no | Comma-separated label names to remove from an issue. | @@ -1219,6 +1231,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links": { "self": "http://gitlab.example.com/api/v4/projects/1/issues/2", "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes", @@ -1405,6 +1418,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links": { "self": "http://gitlab.example.com/api/v4/projects/1/issues/2", "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes", @@ -1549,6 +1563,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "_links": { "self": "http://gitlab.example.com/api/v4/projects/1/issues/2", "notes": "http://gitlab.example.com/api/v4/projects/1/issues/2/notes", @@ -1680,6 +1695,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "task_completion_status":{ "count":0, "completed_count":0 @@ -1788,6 +1804,7 @@ Example response: }, "confidential": false, "discussion_locked": false, + "issue_type": "issue", "task_completion_status":{ "count":0, "completed_count":0 @@ -2013,7 +2030,7 @@ If the project is private or the issue is confidential, you need to provide cred The preferred way to do this, is by using [personal access tokens](../user/profile/personal_access_tokens.md). ```plaintext -GET /projects/:id/issues/:issue_id/related_merge_requests +GET /projects/:id/issues/:issue_iid/related_merge_requests ``` | Attribute | Type | Required | Description | diff --git a/doc/development/testing_guide/end_to_end/page_objects.md b/doc/development/testing_guide/end_to_end/page_objects.md index b124ac430f6..d9d78a078b2 100644 --- a/doc/development/testing_guide/end_to_end/page_objects.md +++ b/doc/development/testing_guide/end_to_end/page_objects.md @@ -260,7 +260,7 @@ These modules must: These steps ensure the sanity selectors check detect problems properly. For example, `qa/qa/ee/page/merge_request/show.rb` adds EE-specific methods to `qa/qa/page/merge_request/show.rb` (with -`QA::Page::MergeRequest::Show.prepend_if_ee('QA::EE::Page::MergeRequest::Show')`) and following is how it's implemented +`QA::Page::MergeRequest::Show.prepend_if_ee('Page::MergeRequest::Show', namespace: QA)`) and following is how it's implemented (only showing the relevant part and referring to the 4 steps described above with inline comments): ```ruby diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index e4c5e2806ec..def7ac9dee3 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -7466,7 +7466,7 @@ Missing description [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216174956_i_analytics_cohorts_monthly.yml) -Group: `group::optimize` +Group: `group::utilization` Status: `data_available` @@ -7478,7 +7478,7 @@ Missing description [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216174955_i_analytics_cohorts_weekly.yml) -Group: `group::optimize` +Group: `group::utilization` Status: `data_available` diff --git a/doc/integration/jira/development_panel.md b/doc/integration/jira/development_panel.md index cc1a3a96577..378955f5721 100644 --- a/doc/integration/jira/development_panel.md +++ b/doc/integration/jira/development_panel.md @@ -8,55 +8,75 @@ info: To determine the technical writer assigned to the Stage/Group associated w > - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/233149) to GitLab Free in 13.4. -The Jira Development panel integration allows you to reference Jira issues in GitLab, displaying -activity in the [Development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/) -in the issue. +With the Jira Development panel integration, you can reference Jira issues in GitLab. +When configured, activity (such as pipeline, deployment, and feature flags) displays in the Jira issue's +[Development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/). +From the Development panel, you can open a detailed view and +[take various actions](#use-the-integration), including creating a new merge request from a branch: -It complements the [GitLab Jira integration](../../user/project/integrations/jira.md). You may choose -to configure both integrations to take advantage of both sets of features. See a -[feature comparison](index.md#direct-feature-comparison). +![Branch, Commit and Pull Requests links on Jira issue](img/jira_dev_panel_jira_setup_3.png) -## Features +The information displayed in the Jira Development panel depends on where you mention the Jira issue ID: | Your mention of Jira issue ID in GitLab context | Automated effect in Jira issue | |---------------------------------------------------|--------------------------------------------------------------------------------------------------------| | In a merge request | Link to the MR is displayed in Development panel. | | In a branch name | Link to the branch is displayed in Development panel. | | In a commit message | Link to the commit is displayed in Development panel. | -| In a commit message with Jira Smart Commit format | Displays your custom comment or logged time spent and/or performs specified issue transition on merge. | - -With this integration, you can access related GitLab merge requests, branches, and commits directly from a Jira issue, reflecting your work in GitLab. From the Development panel, you can open a detailed view and take actions including creating a new merge request from a branch. For more information, see [Usage](#usage). +| In a commit message with Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html) | Displays your custom comment or logged time spent and/or performs specified issue transition on merge. | This integration connects all GitLab projects to projects in the Jira instance in either: -- A top-level group. A top-level GitLab group is one that does not have any parent group itself. All - the projects of that top-level group, as well as projects of the top-level group's subgroups nesting - down, are connected. -- A personal namespace, which then connects the projects in that personal namespace to Jira. +- A top-level GitLab group: Connects the projects in a group with no parent group, + including the projects in its subgroups. +- A personal namespace: Connects the projects in that personal namespace to Jira. + +This differs from the [Jira integration](../../user/project/integrations/jira.md), +where the mapping is between one GitLab project and the entire Jira instance. +You can install both integrations to take advantage of both sets of features. +A [feature comparison](index.md#direct-feature-comparison) is available. + +## Use the integration + +After the integration is [set up on GitLab and Jira](#configure-the-integration), you can: -This differs from the [Jira integration](../../user/project/integrations/jira.md), where the mapping is between one GitLab project and the entire Jira instance. +- Refer to any Jira issue by its ID (in uppercase) in GitLab branch names, + commit messages, and merge request titles. +- See the linked branches, commits, and merge requests in Jira issues: -Additional features provided by the Jira Development Panel integration include: +Merge requests are called "pull requests" in Jira issues. + +Select the links to see your GitLab repository data. + +![GitLab commits details on a Jira issue](img/jira_dev_panel_jira_setup_4.png) + +![GitLab merge requests details on a Jira issue](img/jira_dev_panel_jira_setup_5.png) -- In a Jira issue, display relevant GitLab information in the [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/), including related branches, commits, and merge requests. -- Use Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html) in GitLab to add Jira comments, log time spent on the issue, or apply any issue transition. -- Showing pipeline, deployment, and feature flags in Jira issues. +### Use Jira Smart Commits -## Configuration +With Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html), +you can use GitLab to add Jira comments, log time spent on the issue, or apply any issue transition. + +For more information about using Jira Smart Commits to track time against an issue, specify +an issue transition, or add a custom comment, read the Atlassian page +[Using Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html). + +## Configure the integration <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> -For an overview of how to configure Jira Development panel integration, see [Agile Management - GitLab Jira Development panel integration](https://www.youtube.com/watch?v=VjVTOmMl85M&feature=youtu.be). +For an overview of how to configure Jira Development panel integration, see +[Agile Management - GitLab Jira Development panel integration](https://www.youtube.com/watch?v=VjVTOmMl85M). -We recommend that a GitLab group maintainer or group owner, or instance administrator (in the case of -self-managed GitLab) set up the integration to simplify administration. +To simplify administration, we recommend that a GitLab group maintainer or group owner +(or instance administrator in the case of self-managed GitLab) set up the integration. -| If you use Jira on: | GitLab.com customers need: | GitLab self-managed customers need: | -|-|-|-| +| Jira usage | GitLab.com customers need | GitLab self-managed customers need | +|------------|---------------------------|------------------------------------| | [Atlassian cloud](https://www.atlassian.com/cloud) | The [GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview) application installed from the [Atlassian Marketplace](https://marketplace.atlassian.com). This offers real-time sync between GitLab and Jira. | The [GitLab.com for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?hosting=cloud&tab=overview), using a workaround process. See the documentation for [installing the GitLab Jira Cloud application for self-managed instances](connect-app.md#install-the-gitlabcom-for-jira-cloud-application-for-self-managed-instances) for more information. | | Your own server | The Jira DVCS (distributed version control system) connector. This syncs data hourly. | The [Jira DVCS Connector](dvcs.md). | -Each GitLab project can be configured to connect to an entire Jira instance. That means one GitLab -project can interact with _all_ Jira projects in that instance, once configured. For: +Each GitLab project can be configured to connect to an entire Jira instance. That means after +configuration, one GitLab project can interact with all Jira projects in that instance. For: - The [view Jira issues](issues.md#view-jira-issues) feature, you must associate a GitLab project with a specific Jira project. @@ -68,88 +88,67 @@ documentation for [central administration of project integrations](../../user/ad To enable the Jira service in GitLab, you must: -1. Configure the project in Jira. -1. Enter the correct values in GitLab. +1. [Configure the project in Jira](dvcs.md#configure-jira-for-dvcs). + The supported Jira versions are `v6.x`, `v7.x`, and `v8.x`. +1. [Enter the correct values in GitLab](#configure-gitlab). ### Configure GitLab -> **Notes:** -> -> - The supported Jira versions are `v6.x`, `v7.x`, and `v8.x`. -> - In order to support Oracle's Access Manager, GitLab sends additional cookies -> to enable Basic Auth. The cookie being added to each request is `OBBasicAuth` with -> a value of `fromDialog`. - -To enable the Jira integration in a project: - -1. Go to the project's [Integrations page](../../user/project/integrations/overview.md#accessing-integrations) and select the - **Jira** service. +To enable the integration in your GitLab project, after you +[configure your Jira project](dvcs.md#configure-jira-for-dvcs): +1. Ensure your GitLab installation does not use a relative URL, as described in + [Limitations](#limitations). +1. Go to your project and select [**Settings > Integrations**](../../user/project/integrations/overview.md#accessing-integrations). +1. Select **Jira**. 1. Select **Enable integration**. - -1. Select **Trigger** actions. - This determines whether a mention of a Jira issue in GitLab commits, merge requests, or both, - should link the Jira issue back to that source commit/MR and transition the Jira issue, if - indicated. - -1. To include a comment on the Jira issue when the above reference is made in GitLab, select +1. Select **Trigger** actions. Your choice determines whether a mention of Jira issue + (in a GitLab commit, merge request, or both) creates a cross-link in Jira back to GitLab. +1. To comment in the Jira issue when a **Trigger** action is made in GitLab, select **Enable comments**. - -1. To transition Jira issues when a [closing reference](../../user/project/issues/managing_issues.md#closing-issues-automatically) is made in GitLab, - select **Enable Jira transitions**. - -1. Enter the further details on the page as described in the following table. - - | Field | Description | - | ----- | ----------- | - | `Web URL` | The base URL to the Jira instance web interface which is being linked to this GitLab project. For example, `https://jira.example.com`. | - | `Jira API URL` | The base URL to the Jira instance API. Web URL value is used if not set. For example, `https://jira-api.example.com`. Leave this field blank (or use the same value of `Web URL`) if using **Jira on Atlassian cloud**. | - | `Username or Email` | Created in [configure Jira](dvcs.md#configure-jira-for-dvcs) step. Use `username` for **Jira Server** or `email` for **Jira on Atlassian cloud**. | - | `Password/API token` | Created in [configure Jira](dvcs.md#configure-jira-for-dvcs) step. Use `password` for **Jira Server** or `API token` for **Jira on Atlassian cloud**. | - +1. To transition Jira issues when a + [closing reference](../../user/project/issues/managing_issues.md#closing-issues-automatically) + is made in GitLab, select **Enable Jira transitions**. +1. Provide Jira configuration information: + - **Web URL**: The base URL to the Jira instance web interface you're linking to + this GitLab project, such as `https://jira.example.com`. + - **Jira API URL**: The base URL to the Jira instance API, such as `https://jira-api.example.com`. + Defaults to the **Web URL** value if not set. Leave blank if using **Jira on Atlassian cloud**. + - **Username or Email**: Created when you [configured Jira](dvcs.md#configure-jira-for-dvcs). + For **Jira Server**, use `username`. For **Jira on Atlassian cloud**, use `email`. + - **Password/API token**: Created when you [configured Jira](dvcs.md#configure-jira-for-dvcs). + Use `password` for **Jira Server** or `API token` for **Jira on Atlassian cloud**. 1. To enable users to view Jira issues inside the GitLab project, select **Enable Jira issues** and enter a Jira project key. **(PREMIUM)** - You can only display issues from a single Jira project within a given GitLab project. + You can display issues only from a single Jira project in a given GitLab project. WARNING: - If you enable Jira issues with the setting above, all users that have access to this GitLab project - are able to view all issues from the specified Jira project. - -1. To enable creation of issues for vulnerabilities, select **Enable Jira issues creation from vulnerabilities**. - - 1. Select the **Jira issue type**. If the dropdown is empty, select refresh (**{retry}**) and try again. + If you enable Jira issues with this setting, all users with access to this GitLab project + can view all issues from the specified Jira project. +1. To enable issue creation for vulnerabilities, select **Enable Jira issues creation from vulnerabilities**. +1. Select the **Jira issue type**. If the dropdown is empty, select refresh (**{retry}**) and try again. 1. To verify the Jira connection is working, select **Test settings**. - 1. Select **Save changes**. Your GitLab project can now interact with all Jira projects in your instance and the project now displays a Jira link that opens the Jira project. -## Usage - -After the integration is set up on GitLab and Jira, you can: - -- Refer to any Jira issue by its ID in GitLab branch names, commit messages, and merge request - titles. -- See the linked branches, commits, and merge requests in Jira issues (merge requests are - called "pull requests" in Jira issues). - -Jira issue IDs must be formatted in uppercase for the integration to work. - -![Branch, Commit and Pull Requests links on Jira issue](img/jira_dev_panel_jira_setup_3.png) +## Limitations -Click the links to see your GitLab repository data. +This integration is not supported on GitLab instances under a +[relative URL](https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab). +For example, `http://example.com/gitlab`. -![GitLab commits details on a Jira issue](img/jira_dev_panel_jira_setup_4.png) +## Related topics -![GitLab merge requests details on a Jira issue](img/jira_dev_panel_jira_setup_5.png) +- [Using Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html) in Jira -For more information on using Jira Smart Commits to track time against an issue, specify an issue transition, or add a custom comment, see the Atlassian page [Using Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html). +## Troubleshooting -## Limitations +### Cookies for Oracle's Access Manager -This integration is not supported on GitLab instances under a -[relative URL](https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab). -For example, `http://example.com/gitlab`. +To support Oracle's Access Manager, GitLab sends additional cookies +to enable Basic Auth. The cookie being added to each request is `OBBasicAuth` with +a value of `fromDialog`. diff --git a/doc/integration/jira/dvcs.md b/doc/integration/jira/dvcs.md index 3099c02ff36..9c6a5dc4386 100644 --- a/doc/integration/jira/dvcs.md +++ b/doc/integration/jira/dvcs.md @@ -99,7 +99,7 @@ it completes, refreshes every 60 minutes: To connect additional GitLab projects from other GitLab top-level groups, or personal namespaces, repeat the previous steps with additional Jira DVCS accounts. -After you configure the integration, read more about [how to test and use it](development_panel.md#usage). +After you configure the integration, read more about [how to test and use it](development_panel.md). ## Refresh data imported to Jira diff --git a/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png b/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png Binary files differindex 73dc867d301..b143fc24355 100644 --- a/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png +++ b/doc/integration/jira/img/jira_dev_panel_jira_setup_5.png diff --git a/doc/integration/jira/issues.md b/doc/integration/jira/issues.md index 1f2ab3d79dc..4fd59c3608e 100644 --- a/doc/integration/jira/issues.md +++ b/doc/integration/jira/issues.md @@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Jira integration issue management **(FREE)** -Integrating issue management with Jira requires you to [configure Jira](development_panel.md#configuration) +Integrating issue management with Jira requires you to [configure Jira](development_panel.md#configure-the-integration) and [enable the Jira service](development_panel.md#configure-gitlab) in GitLab. After you configure and enable the integration, you can reference and close Jira issues by mentioning the Jira ID in GitLab commits and merge requests. diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md index 078a1a0be08..d09dbd2cb04 100644 --- a/doc/operations/incident_management/incidents.md +++ b/doc/operations/incident_management/incidents.md @@ -267,3 +267,19 @@ any other Markdown text field in GitLab by You can embed both [GitLab-hosted metrics](../metrics/embed.md) and [Grafana metrics](../metrics/embed_grafana.md) in incidents and issue templates. + +### Automatically close incidents via recovery alerts + +> - [Introduced for Prometheus Integrations](https://gitlab.com/gitlab-org/gitlab/-/issues/13401) in GitLab 12.5. +> - [Introduced for HTTP Integrations](https://gitlab.com/gitlab-org/gitlab/-/issues/13402) in GitLab 13.4. + +With Maintainer or higher [permissions](../../user/permissions.md), you can enable + GitLab to close an incident automatically when a **Recovery Alert** is received: + +1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**. +1. Check the **Automatically close associated Incident** checkbox. +1. Click **Save changes**. + +When GitLab receives a **Recovery Alert**, it closes the associated incident. +This action is recorded as a system message on the incident indicating that it +was closed automatically by the GitLab Alert bot. diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md index acfab79c0c3..07ffb92a000 100644 --- a/doc/operations/incident_management/integrations.md +++ b/doc/operations/incident_management/integrations.md @@ -97,17 +97,17 @@ to configure alerts for this integration. ## Customize the alert payload outside of GitLab -For all integration types, you can customize the payload by sending the following +For HTTP Endpoints without [custom mappings](#map-fields-in-custom-alerts), you can customize the payload by sending the following parameters. All fields are optional. If the incoming alert does not contain a value for the `Title` field, a default value of `New: Alert` will be applied. | Property | Type | Description | | ------------------------- | --------------- | ----------- | -| `title` | String | The title of the incident. | +| `title` | String | The title of the alert.| | `description` | String | A high-level summary of the problem. | -| `start_time` | DateTime | The time of the incident. If none is provided, a timestamp of the issue is used. | -| `end_time` | DateTime | For existing alerts only. When provided, the alert is resolved and the associated incident is closed. | +| `start_time` | DateTime | The time of the alert. If none is provided, a current time is used. | +| `end_time` | DateTime | The resolution time of the alert. If provided, the alert is resolved. | | `service` | String | The affected service. | -| `monitoring_tool` | String | The name of the associated monitoring tool. | +| `monitoring_tool` | String | The name of the associated monitoring tool. | | `hosts` | String or Array | One or more hosts, as to where this incident occurred. | | `severity` | String | The severity of the alert. Case-insensitive. Can be one of: `critical`, `high`, `medium`, `low`, `info`, `unknown`. Defaults to `critical` if missing or value is not in this list. | | `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. | @@ -189,6 +189,17 @@ If the existing alert is already `resolved`, GitLab creates a new alert instead. ![Alert Management List](img/alert_list_v13_1.png) +## Recovery alerts + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13402) in GitLab 13.4. + +The alert in GitLab will be automatically resolved when an HTTP Endpoint +receives a payload with the end time of the alert set. For HTTP Endpoints +without [custom mappings](#map-fields-in-custom-alerts), the expected +field is `end_time`. With custom mappings, you can select the expected field. + +You can also configure the associated [incident to be closed automatically](../incident_management/incidents.md#automatically-close-incidents-via-recovery-alerts) when the alert resolves. + ## Link to your Opsgenie Alerts > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab Premium 13.2. diff --git a/doc/operations/metrics/alerts.md b/doc/operations/metrics/alerts.md index ff62152363b..09cfea06198 100644 --- a/doc/operations/metrics/alerts.md +++ b/doc/operations/metrics/alerts.md @@ -96,7 +96,6 @@ Prometheus server to use the ## Trigger actions from alerts **(ULTIMATE)** > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4925) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.11. -> - [From GitLab Ultimate 12.5](https://gitlab.com/gitlab-org/gitlab/-/issues/13401), when GitLab receives a recovery alert, it automatically closes the associated issue. Alerts can be used to trigger actions, like opening an issue automatically (disabled by default since `13.1`). To configure the actions: @@ -127,10 +126,6 @@ values extracted from the [`alerts` field in webhook payload](https://prometheus - **Low**: `low`, `s4`, `p4`, `warn`, `warning` - **Info**: `info`, `s5`, `p5`, `debug`, `information`, `notice` -When GitLab receives a **Recovery Alert**, it closes the associated issue. -This action is recorded as a system message on the issue indicating that it -was closed automatically by the GitLab Alert bot. - To further customize the issue, you can add labels, mentions, or any other supported [quick action](../../user/project/quick_actions.md) in the selected issue template, which applies to all incidents. To limit quick actions or other information to @@ -143,3 +138,12 @@ does not yet exist, it is also created automatically. If the metric exceeds the threshold of the alert for over 5 minutes, GitLab sends an email to all [Maintainers and Owners](../../user/permissions.md#project-members-permissions) of the project. + +### Recovery alerts + +> - [From GitLab Ultimate 12.5](https://gitlab.com/gitlab-org/gitlab/-/issues/13401), when GitLab receives a recovery alert, it automatically closes the associated issue. + +The alert in GitLab will be automatically resolved when Prometheus +sends a payload with the field `status` set to `resolved`. + +You can also configure the associated [incident to be closed automatically](../incident_management/incidents.md#automatically-close-incidents-via-recovery-alerts) when the alert resolves. diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md index ca7eb5a11d1..a816fb4b009 100644 --- a/doc/user/project/settings/index.md +++ b/doc/user/project/settings/index.md @@ -356,6 +356,24 @@ to remove a fork relationship. ## Operations settings +### Alerts + +Configure [alert integrations](../../../operations/incident_management/integrations.md#configuration) to triage and manage critical problems in your application as [alerts](../../../operations/incident_management/alerts.md). + +### Incidents + +#### Alert integration + +Automatically [create](../../../operations/incident_management/incidents.md#create-incidents-automatically), [notify on](../../../operations/incident_management/paging.md#email-notifications), and [resolve](../../../operations/incident_management/incidents.md#automatically-close-incidents-via-recovery-alerts) incidents based on GitLab alerts. + +#### PagerDuty integration + +[Create incidents in GitLab for each PagerDuty incident](../../../operations/incident_management/incidents.md#create-incidents-via-the-pagerduty-webhook). + +#### Incident settings + +[Manage Service Level Agreements for incidents](../../../operations/incident_management/incidents.md#service-level-agreement-countdown-timer) with an SLA countdown timer. + ### Error Tracking Configure Error Tracking to discover and view [Sentry errors within GitLab](../../../operations/error_tracking.md). diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index c5249f1377b..33980b38e2b 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -184,6 +184,8 @@ module API .new(job, declared_params(include_missing: false)) service.execute.then do |result| + track_ci_minutes_usage!(job, current_runner) + header 'X-GitLab-Trace-Update-Interval', result.backoff status result.status body result.status.to_s @@ -214,6 +216,8 @@ module API break error!('416 Range Not Satisfiable', 416, { 'Range' => "0-#{result.stream_size}" }) end + track_ci_minutes_usage!(job, current_runner) + status result.status header 'Job-Status', job.status header 'Range', "0-#{result.stream_size}" diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb index a9ec2632ed4..754f8e2b6e4 100644 --- a/lib/api/entities/issue_basic.rb +++ b/lib/api/entities/issue_basic.rb @@ -36,6 +36,7 @@ module API expose :due_date expose :confidential expose :discussion_locked + expose :issue_type expose :web_url do |issue| Gitlab::UrlBuilder.build(issue) diff --git a/lib/api/helpers/issues_helpers.rb b/lib/api/helpers/issues_helpers.rb index 2b1ed479692..452396689f8 100644 --- a/lib/api/helpers/issues_helpers.rb +++ b/lib/api/helpers/issues_helpers.rb @@ -28,7 +28,8 @@ module API :remove_labels, :milestone_id, :state_event, - :title + :title, + :issue_type ] end @@ -47,6 +48,7 @@ module API args[:not][:label_name] ||= args[:not]&.delete(:labels) args[:scope] = args[:scope].underscore if args[:scope] args[:sort] = "#{args[:order_by]}_#{args[:sort]}" + args[:issue_types] ||= args.delete(:issue_type) IssuesFinder.new(current_user, args) end diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb index 688cd2da994..a74fd7de2d8 100644 --- a/lib/api/helpers/runner.rb +++ b/lib/api/helpers/runner.rb @@ -87,6 +87,10 @@ module API project: -> { current_job.project } ) end + + def track_ci_minutes_usage!(_build, _runner) + # noop: overridden in EE + end end end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index c844655f0b3..23366505c4a 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -74,6 +74,7 @@ module API desc: 'Return issues sorted in `asc` or `desc` order.' optional :due_date, type: String, values: %w[0 overdue week month next_month_and_previous_two_weeks] << '', desc: 'Return issues that have no due date (`0`), or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`, `0`' + optional :issue_type, type: String, values: Issue.issue_types.keys, desc: "The type of the issue. Accepts: #{Issue.issue_types.keys.join(', ')}" use :issues_stats_params use :pagination @@ -90,6 +91,7 @@ module API optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY' optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential' optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked" + optional :issue_type, type: String, values: Issue.issue_types.keys, desc: "The type of the issue. Accepts: #{Issue.issue_types.keys.join(', ')}" use :optional_issue_params_ee end diff --git a/lib/gitlab/ci/pipeline/metrics.rb b/lib/gitlab/ci/pipeline/metrics.rb index 35e88ded416..5ac69a21530 100644 --- a/lib/gitlab/ci/pipeline/metrics.rb +++ b/lib/gitlab/ci/pipeline/metrics.rb @@ -63,6 +63,13 @@ module Gitlab Gitlab::Metrics.counter(name, comment) end + + def ci_minutes_exceeded_builds_counter + name = :ci_minutes_exceeded_builds_counter + comment = 'Count of builds dropped due to CI minutes exceeded' + + Gitlab::Metrics.counter(name, comment) + end end end end diff --git a/lib/gitlab/ci/queue/metrics.rb b/lib/gitlab/ci/queue/metrics.rb index 7ecb9a1db16..46e4373ec85 100644 --- a/lib/gitlab/ci/queue/metrics.rb +++ b/lib/gitlab/ci/queue/metrics.rb @@ -10,7 +10,7 @@ module Gitlab QUEUE_ACTIVE_RUNNERS_BUCKETS = [1, 3, 10, 30, 60, 300, 900, 1800, 3600].freeze QUEUE_DEPTH_TOTAL_BUCKETS = [1, 2, 3, 5, 8, 16, 32, 50, 100, 250, 500, 1000, 2000, 5000].freeze QUEUE_SIZE_TOTAL_BUCKETS = [1, 5, 10, 50, 100, 500, 1000, 2000, 5000, 7500, 10000, 15000, 20000].freeze - QUEUE_PROCESSING_DURATION_SECONDS_BUCKETS = [0.01, 0.05, 0.1, 0.3, 0.5, 1, 5, 10, 30, 60, 180, 300].freeze + QUEUE_PROCESSING_DURATION_SECONDS_BUCKETS = [0.01, 0.05, 0.1, 0.3, 0.5, 1, 5, 10, 15, 20, 30, 60].freeze METRICS_SHARD_TAG_PREFIX = 'metrics_shard::' DEFAULT_METRICS_SHARD = 'default' diff --git a/lib/gitlab/ci/status/build/failed.rb b/lib/gitlab/ci/status/build/failed.rb index 787dee3b267..4a9b9dbc52a 100644 --- a/lib/gitlab/ci/status/build/failed.rb +++ b/lib/gitlab/ci/status/build/failed.rb @@ -28,7 +28,8 @@ module Gitlab secrets_provider_not_found: 'secrets provider can not be found', reached_max_descendant_pipelines_depth: 'reached maximum depth of child pipelines', project_deleted: 'pipeline project was deleted', - user_blocked: 'pipeline user was blocked' + user_blocked: 'pipeline user was blocked', + ci_quota_exceeded: 'no more CI minutes available' }.freeze private_constant :REASONS diff --git a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml index 232c320562b..fddfc0deb28 100644 --- a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml @@ -17,7 +17,7 @@ variables: bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python, klar, clair-vulnerabilities-db, license-finder, - dast + dast, api-fuzzing SECURE_BINARIES_DOWNLOAD_IMAGES: "true" SECURE_BINARIES_PUSH_IMAGES: "true" @@ -241,3 +241,12 @@ dast: variables: - $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && $SECURE_BINARIES_ANALYZERS =~ /\bdast\b/ + +api-fuzzing: + extends: .download_images + variables: + SECURE_BINARIES_ANALYZER_VERSION: "1" + only: + variables: + - $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && + $SECURE_BINARIES_ANALYZERS =~ /\bapi-fuzzing\b/ diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 45bc21b9a42..06558e1a212 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -4,7 +4,6 @@ module Gitlab class Highlight TIMEOUT_BACKGROUND = 30.seconds TIMEOUT_FOREGROUND = 1.5.seconds - MAXIMUM_TEXT_HIGHLIGHT_SIZE = 512.kilobytes def self.highlight(blob_name, blob_content, language: nil, plain: false) new(blob_name, blob_content, language: language) @@ -23,7 +22,7 @@ module Gitlab def highlight(text, continue: false, plain: false, context: {}) @context = context - plain ||= text.length > MAXIMUM_TEXT_HIGHLIGHT_SIZE + plain ||= text.length > maximum_text_highlight_size highlighted_text = highlight_text(text, continue: continue, plain: plain) highlighted_text = link_dependencies(text, highlighted_text) if blob_name @@ -78,5 +77,9 @@ module Gitlab def link_dependencies(text, highlighted_text) Gitlab::DependencyLinker.link(blob_name, text, highlighted_text) end + + def maximum_text_highlight_size + Gitlab.config.extra['maximum_text_highlight_size_kilobytes'] + end end end diff --git a/lib/gitlab/static_site_editor/config/generated_config.rb b/lib/gitlab/static_site_editor/config/generated_config.rb index 0a2cee75af7..1555c3469a5 100644 --- a/lib/gitlab/static_site_editor/config/generated_config.rb +++ b/lib/gitlab/static_site_editor/config/generated_config.rb @@ -42,11 +42,11 @@ module Gitlab end def supported_content? - master_branch? && extension_supported? && file_exists? + branch_supported? && extension_supported? && file_exists? end - def master_branch? - ref == 'master' + def branch_supported? + ref.in?(%w[master main]) end def extension_supported? diff --git a/lib/sidebars/projects/menus/infrastructure_menu.rb b/lib/sidebars/projects/menus/infrastructure_menu.rb new file mode 100644 index 00000000000..eccf264873e --- /dev/null +++ b/lib/sidebars/projects/menus/infrastructure_menu.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +module Sidebars + module Projects + module Menus + class InfrastructureMenu < ::Sidebars::Menu + override :configure_menu_items + def configure_menu_items + return false if Feature.disabled?(:sidebar_refactor, context.current_user) + return false unless context.project.feature_available?(:operations, context.current_user) + + add_item(kubernetes_menu_item) + add_item(serverless_menu_item) + add_item(terraform_menu_item) + + true + end + + override :link + def link + project_clusters_path(context.project) + end + + override :extra_container_html_options + def extra_container_html_options + { + class: 'shortcuts-infrastructure' + } + end + + override :title + def title + _('Infrastructure') + end + + override :sprite_icon + def sprite_icon + 'cloud-gear' + end + + private + + def kubernetes_menu_item + return unless can?(context.current_user, :read_cluster, context.project) + + ::Sidebars::MenuItem.new( + title: _('Kubernetes clusters'), + link: project_clusters_path(context.project), + active_routes: { controller: [:cluster_agents, :clusters] }, + container_html_options: { class: 'shortcuts-kubernetes' }, + hint_html_options: kubernetes_hint_html_options, + item_id: :kubernetes + ) + end + + def kubernetes_hint_html_options + return {} unless context.show_cluster_hint + + { disabled: true, + data: { trigger: 'manual', + container: 'body', + placement: 'right', + highlight: UserCalloutsHelper::GKE_CLUSTER_INTEGRATION, + highlight_priority: UserCallout.feature_names[:GKE_CLUSTER_INTEGRATION], + dismiss_endpoint: user_callouts_path, + auto_devops_help_path: help_page_path('topics/autodevops/index.md') } } + end + + def serverless_menu_item + return unless can?(context.current_user, :read_cluster, context.project) + + ::Sidebars::MenuItem.new( + title: _('Serverless platform'), + link: project_serverless_functions_path(context.project), + active_routes: { controller: :functions }, + item_id: :serverless + ) + end + + def terraform_menu_item + return unless can?(context.current_user, :read_terraform_state, context.project) + + ::Sidebars::MenuItem.new( + title: _('Terraform'), + link: project_terraform_index_path(context.project), + active_routes: { controller: :terraform }, + item_id: :terraform + ) + end + end + end + end +end diff --git a/lib/sidebars/projects/menus/operations_menu.rb b/lib/sidebars/projects/menus/operations_menu.rb index adfb5fd2016..7678dedde24 100644 --- a/lib/sidebars/projects/menus/operations_menu.rb +++ b/lib/sidebars/projects/menus/operations_menu.rb @@ -47,7 +47,7 @@ module Sidebars override :sprite_icon def sprite_icon - 'cloud-gear' + Feature.enabled?(:sidebar_refactor, context.current_user) ? 'monitor' : 'cloud-gear' end override :active_routes @@ -127,6 +127,7 @@ module Sidebars end def serverless_menu_item + return if Feature.enabled?(:sidebar_refactor, context.current_user) return unless can?(context.current_user, :read_cluster, context.project) ::Sidebars::MenuItem.new( @@ -138,6 +139,7 @@ module Sidebars end def terraform_menu_item + return if Feature.enabled?(:sidebar_refactor, context.current_user) return unless can?(context.current_user, :read_terraform_state, context.project) ::Sidebars::MenuItem.new( @@ -149,6 +151,7 @@ module Sidebars end def kubernetes_menu_item + return if Feature.enabled?(:sidebar_refactor, context.current_user) return unless can?(context.current_user, :read_cluster, context.project) ::Sidebars::MenuItem.new( diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb index 8d81c197f71..f8320fe1acf 100644 --- a/lib/sidebars/projects/panel.rb +++ b/lib/sidebars/projects/panel.rb @@ -17,6 +17,7 @@ module Sidebars add_menu(Sidebars::Projects::Menus::CiCdMenu.new(context)) add_menu(Sidebars::Projects::Menus::SecurityComplianceMenu.new(context)) add_menu(Sidebars::Projects::Menus::OperationsMenu.new(context)) + add_menu(Sidebars::Projects::Menus::InfrastructureMenu.new(context)) add_menu(Sidebars::Projects::Menus::PackagesRegistriesMenu.new(context)) add_menu(Sidebars::Projects::Menus::AnalyticsMenu.new(context)) end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 2097a1b5661..7ce3232567a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5597,6 +5597,9 @@ msgid_plural "CICDAnalytics|Releases" msgstr[0] "" msgstr[1] "" +msgid "CICDAnalytics|Release statistics" +msgstr "" + msgid "CICDAnalytics|Releases" msgstr "" @@ -17338,6 +17341,9 @@ msgstr "" msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}." msgstr "" +msgid "Infrastructure" +msgstr "" + msgid "Infrastructure Registry" msgstr "" @@ -18789,6 +18795,9 @@ msgstr "" msgid "Kubernetes cluster was successfully updated." msgstr "" +msgid "Kubernetes clusters" +msgstr "" + msgid "Kubernetes deployment not found" msgstr "" @@ -29116,6 +29125,9 @@ msgstr "" msgid "Serverless domain" msgstr "" +msgid "Serverless platform" +msgstr "" + msgid "ServerlessDetails|Function invocation metrics require Prometheus to be installed first." msgstr "" diff --git a/package.json b/package.json index 47ca621611a..c677eb4ee26 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "codesandbox-api": "0.0.23", "compression-webpack-plugin": "^5.0.2", "copy-webpack-plugin": "^6.4.1", - "core-js": "^3.11.2", + "core-js": "^3.11.3", "cron-validator": "^1.1.1", "cropper": "^2.3.0", "css-loader": "^2.1.1", diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb index b2b37fcd424..8c0b3da6004 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb @@ -9,7 +9,7 @@ module QA Flow::Login.sign_in end - it 'creates an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1167' do + it 'creates an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1793' do issue = Resource::Issue.fabricate_via_browser_ui! Page::Project::Menu.perform(&:click_issues) @@ -19,7 +19,7 @@ module QA end end - it 'closes an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1085' do + it 'closes an issue', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1792' do closed_issue.visit! Page::Project::Issue::Show.perform do |issue_page| diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb index b67e0e54aa0..9d90ff189c6 100644 --- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb @@ -71,7 +71,7 @@ module QA snippet.remove_via_api! end - it 'clones, pushes, and pulls a project snippet over SSH, deletes via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/832' do + it 'clones, pushes, and pulls a project snippet over SSH, deletes via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1794' do Resource::Repository::Push.fabricate! do |push| push.repository_ssh_uri = repository_uri_ssh push.ssh_key = ssh_key diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb index 008259a8bfa..6d34b56df09 100644 --- a/spec/controllers/registrations/welcome_controller_spec.rb +++ b/spec/controllers/registrations/welcome_controller_spec.rb @@ -77,6 +77,30 @@ RSpec.describe Registrations::WelcomeController do it { is_expected.to redirect_to(dashboard_projects_path)} + context 'when the new user already has any accepted group membership' do + let!(:member1) { create(:group_member, user: user) } + + it 'redirects to the group activity page' do + expect(subject).to redirect_to(activity_group_path(member1.source)) + end + + context 'when the new user already has more than 1 accepted group membership' do + it 'redirects to the most recent membership group activty page' do + member2 = create(:group_member, user: user) + + expect(subject).to redirect_to(activity_group_path(member2.source)) + end + end + + context 'when the member has an orphaned source at the time of the welcome' do + it 'redirects to the project dashboard page' do + member1.source.delete + + expect(subject).to redirect_to(dashboard_projects_path) + end + end + end + context 'when the user opted in' do let(:email_opted_in) { '1' } diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 4f17260f87d..0a7113a5559 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -251,41 +251,62 @@ RSpec.describe 'Admin updates settings' do end end - context 'when the Slack Notifications Service template is active' do + context 'when Service Templates are enabled' do before do - create(:service, :template, type: 'SlackService', active: true) - + stub_feature_flags(disable_service_templates: false) visit general_admin_application_settings_path end - it 'change Slack Notifications Service template settings', :js do - first(:link, 'Service Templates').click - click_link 'Slack notifications' - fill_in 'Webhook', with: 'http://localhost' - fill_in 'Username', with: 'test_user' - fill_in 'service[push_channel]', with: '#test_channel' - page.check('Notify only broken pipelines') - page.select 'All branches', from: 'Branches to be notified' - page.select 'Match any of the labels', from: 'Labels to be notified behavior' + it 'shows Service Templates link' do + expect(page).to have_link('Service Templates') + end - check_all_events - click_button 'Save changes' + context 'when the Slack Notifications Service template is active' do + before do + create(:service, :template, type: 'SlackService', active: true) - expect(page).to have_content 'Application settings saved successfully' + visit general_admin_application_settings_path + end - click_link 'Slack notifications' + it 'change Slack Notifications Service template settings', :js do + first(:link, 'Service Templates').click + click_link 'Slack notifications' + fill_in 'Webhook', with: 'http://localhost' + fill_in 'Username', with: 'test_user' + fill_in 'service[push_channel]', with: '#test_channel' + page.check('Notify only broken pipelines') + page.select 'All branches', from: 'Branches to be notified' + page.select 'Match any of the labels', from: 'Labels to be notified behavior' + + check_all_events + click_button 'Save changes' + + expect(page).to have_content 'Application settings saved successfully' - expect(page.all('input[type=checkbox]')).to all(be_checked) - expect(find_field('Webhook').value).to eq 'http://localhost' - expect(find_field('Username').value).to eq 'test_user' - expect(find('[name="service[push_channel]"]').value).to eq '#test_channel' + click_link 'Slack notifications' + + expect(page.all('input[type=checkbox]')).to all(be_checked) + expect(find_field('Webhook').value).to eq 'http://localhost' + expect(find_field('Username').value).to eq 'test_user' + expect(find('[name="service[push_channel]"]').value).to eq '#test_channel' + end + + it 'defaults Deployment events to false for chat notification template settings', :js do + first(:link, 'Service Templates').click + click_link 'Slack notifications' + + expect(find_field('Deployment')).not_to be_checked + end end + end - it 'defaults Deployment events to false for chat notification template settings', :js do - first(:link, 'Service Templates').click - click_link 'Slack notifications' + context 'When Service templates are disabled' do + before do + stub_feature_flags(disable_service_templates: true) + end - expect(find_field('Deployment')).not_to be_checked + it 'does not show Service Templates link' do + expect(page).not_to have_link('Service Templates') end end diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 5ab75a6b914..d01e4aa85ab 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -72,6 +72,20 @@ RSpec.describe 'Project navbar' do end context 'when sidebar refactor feature flag is on' do + let(:operations_menu_items) do + [ + _('Metrics'), + _('Logs'), + _('Tracing'), + _('Error Tracking'), + _('Alerts'), + _('Incidents'), + _('Environments'), + _('Feature Flags'), + _('Product Analytics') + ] + end + before do stub_feature_flags(sidebar_refactor: true) stub_config(registry: { enabled: true }) @@ -84,6 +98,18 @@ RSpec.describe 'Project navbar' do new_sub_nav_item_name: _('Packages & Registries') ) + insert_after_nav_item( + _('Operations'), + new_nav_item: { + nav_item: _('Infrastructure'), + nav_sub_items: [ + _('Kubernetes clusters'), + _('Serverless platform'), + _('Terraform') + ] + } + ) + visit project_path(project) end diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb index b6fde19e0d4..b73a1f6b9fa 100644 --- a/spec/features/projects/user_uses_shortcuts_spec.rb +++ b/spec/features/projects/user_uses_shortcuts_spec.rb @@ -182,11 +182,25 @@ RSpec.describe 'User uses shortcuts', :js do expect(page).to have_active_sub_navigation('Environments') end + context 'when feature flag :sidebar_refactor is disabled' do + it 'redirects to the Kubernetes page with active Operations' do + stub_feature_flags(sidebar_refactor: false) + + find('body').native.send_key('g') + find('body').native.send_key('k') + + expect(page).to have_active_navigation('Operations') + expect(page).to have_active_sub_navigation('Kubernetes') + end + end + end + + context 'when navigating to the Infrastructure pages' do it 'redirects to the Kubernetes page' do find('body').native.send_key('g') find('body').native.send_key('k') - expect(page).to have_active_navigation('Operations') + expect(page).to have_active_navigation('Infrastructure') expect(page).to have_active_sub_navigation('Kubernetes') end end diff --git a/spec/frontend/issuable/components/csv_export_modal_spec.js b/spec/frontend/issuable/components/csv_export_modal_spec.js index a327da2d63a..7eb85a946ae 100644 --- a/spec/frontend/issuable/components/csv_export_modal_spec.js +++ b/spec/frontend/issuable/components/csv_export_modal_spec.js @@ -13,6 +13,8 @@ describe('CsvExportModal', () => { mount(CsvExportModal, { propsData: { modalId: 'csv-export-modal', + exportCsvPath: 'export/csv/path', + issuableCount: 1, ...props, }, provide: { diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js index 48d575ac0f6..85bdd87abc6 100644 --- a/spec/frontend/jobs/mock_data.js +++ b/spec/frontend/jobs/mock_data.js @@ -1464,8 +1464,8 @@ export const mockJobsQueryResponse = { __typename: 'DetailedStatus', }, id: 'gid://gitlab/Ci::Build/2336', - refName: 'master', - refPath: '/root/ci-project/-/commits/master', + refName: 'main', + refPath: '/root/ci-project/-/commits/main', tags: [], shortSha: '4408fa2a', commitPath: '/root/ci-project/-/commit/4408fa2a27aaadfdf42d8dda3d6a9c01ce6cad78', diff --git a/spec/frontend/pipeline_new/mock_data.js b/spec/frontend/pipeline_new/mock_data.js index 3f49ffe9664..3174b73098a 100644 --- a/spec/frontend/pipeline_new/mock_data.js +++ b/spec/frontend/pipeline_new/mock_data.js @@ -46,16 +46,16 @@ export const mockTagRefs = ['1.0.0', '1.1.0', '1.2.0']; export const mockVariables = [ { - uniqueId: 'var-refs/heads/master2', + uniqueId: 'var-refs/heads/main2', variable_type: 'env_var', key: 'var_without_value', value: '', }, { - uniqueId: 'var-refs/heads/master3', + uniqueId: 'var-refs/heads/main3', variable_type: 'env_var', key: 'var_with_value', value: 'test_value', }, - { uniqueId: 'var-refs/heads/master4', variable_type: 'env_var', key: '', value: '' }, + { uniqueId: 'var-refs/heads/main4', variable_type: 'env_var', key: '', value: '' }, ]; diff --git a/spec/frontend/projects/compare/components/app_legacy_spec.js b/spec/frontend/projects/compare/components/app_legacy_spec.js index 93e96c8b9f7..6fdf4014575 100644 --- a/spec/frontend/projects/compare/components/app_legacy_spec.js +++ b/spec/frontend/projects/compare/components/app_legacy_spec.js @@ -7,7 +7,7 @@ jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); const projectCompareIndexPath = 'some/path'; const refsProjectPath = 'some/refs/path'; -const paramsFrom = 'master'; +const paramsFrom = 'main'; const paramsTo = 'some-other-branch'; describe('CompareApp component', () => { diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js index ca208395e82..38e13dc5462 100644 --- a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js +++ b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js @@ -9,7 +9,7 @@ const defaultProps = { refsProjectPath: 'some/refs/path', revisionText: 'Target', paramsName: 'from', - paramsBranch: 'master', + paramsBranch: 'main', }; jest.mock('~/flash'); diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 1a929373716..5dcee1ff724 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -47,8 +47,9 @@ RSpec.describe Gitlab::Highlight do end it 'returns plain version for long content' do - stub_const('Gitlab::Highlight::MAXIMUM_TEXT_HIGHLIGHT_SIZE', 1) - result = described_class.highlight(file_name, content) + stub_config(extra: { 'maximum_text_highlight_size_kilobytes' => 0.0001 } ) # 1.024 bytes + + result = described_class.highlight(file_name, content) # content is 44 bytes expect(result).to eq(%[<span id="LC1" class="line" lang="">(make-pathname :defaults name</span>\n<span id="LC2" class="line" lang="">:type "assem")</span>]) end diff --git a/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb b/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb index 0b2055d3db5..8cd3feba339 100644 --- a/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb +++ b/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb @@ -54,13 +54,14 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do path, '', message: 'message', - branch_name: 'master' + branch_name: ref ) end + let(:ref) { 'main' } let(:path) { 'README.md.erb' } - it { is_expected.to include(is_supported_content: true) } + it { is_expected.to include(branch: ref, is_supported_content: true) } end context 'when file path is nested' do @@ -69,7 +70,7 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do it { is_expected.to include(base_url: '/namespace/project/-/sse/master%2Flib%2FREADME.md') } end - context 'when branch is not master' do + context 'when branch is not master or main' do let(:ref) { 'my-branch' } it { is_expected.to include(is_supported_content: false) } diff --git a/spec/lib/sidebars/projects/menus/operations_menu_spec.rb b/spec/lib/sidebars/projects/menus/operations_menu_spec.rb index f8b4fc3757d..6e764dbb83a 100644 --- a/spec/lib/sidebars/projects/menus/operations_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/operations_menu_spec.rb @@ -131,36 +131,66 @@ RSpec.describe Sidebars::Projects::Menus::OperationsMenu do describe 'Serverless' do let(:item_id) { :serverless } - specify { is_expected.not_to be_nil } + context 'when feature flag :sidebar_refactor is enabled' do + specify { is_expected.to be_nil } + end - describe 'when the user does not have access' do - let(:user) { nil } + context 'when feature flag :sidebar_refactor is disabled' do + before do + stub_feature_flags(sidebar_refactor: false) + end - specify { is_expected.to be_nil } + specify { is_expected.not_to be_nil } + + describe 'when the user does not have access' do + let(:user) { nil } + + specify { is_expected.to be_nil } + end end end describe 'Terraform' do let(:item_id) { :terraform } - specify { is_expected.not_to be_nil } + context 'when feature flag :sidebar_refactor is enabled' do + specify { is_expected.to be_nil } + end - describe 'when the user does not have access' do - let(:user) { nil } + context 'when feature flag :sidebar_refactor is disabled' do + before do + stub_feature_flags(sidebar_refactor: false) + end - specify { is_expected.to be_nil } + specify { is_expected.not_to be_nil } + + describe 'when the user does not have access' do + let(:user) { nil } + + specify { is_expected.to be_nil } + end end end describe 'Kubernetes' do let(:item_id) { :kubernetes } - specify { is_expected.not_to be_nil } + context 'when feature flag :sidebar_refactor is enabled' do + specify { is_expected.to be_nil } + end - describe 'when the user does not have access' do - let(:user) { nil } + context 'when feature flag :sidebar_refactor is disabled' do + before do + stub_feature_flags(sidebar_refactor: false) + end - specify { is_expected.to be_nil } + specify { is_expected.not_to be_nil } + + describe 'when the user does not have access' do + let(:user) { nil } + + specify { is_expected.to be_nil } + end end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 7c02029fa40..abb0b3d0b6f 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -2398,4 +2398,12 @@ RSpec.describe Group do expect(group.to_ability_name).to eq('group') end end + + describe '#activity_path' do + it 'returns the group activity_path' do + expected_path = "/groups/#{group.name}/-/activity" + + expect(group.activity_path).to eq(expected_path) + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 55b13128c17..bf47e75cc7a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -6890,6 +6890,14 @@ RSpec.describe Project, factory_default: :keep do end end end + + describe '#activity_path' do + it 'returns the project activity_path' do + expected_path = "/#{project.namespace.path}/#{project.name}/activity" + + expect(project.activity_path).to eq(expected_path) + end + end end describe '#default_branch_or_main' do diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb index 8f10de59526..125db58ed69 100644 --- a/spec/requests/api/issues/issues_spec.rb +++ b/spec/requests/api/issues/issues_spec.rb @@ -115,6 +115,7 @@ RSpec.describe API::Issues do expect(response).to have_gitlab_http_status(:ok) expect(json_response.dig('author', 'id')).to eq(issue.author.id) expect(json_response['description']).to eq(issue.description) + expect(json_response['issue_type']).to eq('issue') end end @@ -378,6 +379,14 @@ RSpec.describe API::Issues do expect_paginated_array_response([issue.id, closed_issue.id]) end + it 'returns issues with a given issue_type' do + issue2 = create(:incident, project: project) + + get api('/issues', user), params: { issue_type: 'incident' } + + expect_paginated_array_response(issue2.id) + end + it 'returns issues matching given search string for title' do get api('/issues', user), params: { search: issue.title } @@ -939,7 +948,17 @@ RSpec.describe API::Issues do end end - describe 'PUT /projects/:id/issues/:issue_id' do + describe "POST /projects/:id/issues" do + it 'creates a new project issue' do + post api("/projects/#{project.id}/issues", user), params: { title: 'new issue' } + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['title']).to eq('new issue') + expect(json_response['issue_type']).to eq('issue') + end + end + + describe 'PUT /projects/:id/issues/:issue_iid' do it_behaves_like 'issuable update endpoint' do let(:entity) { issue } end @@ -971,6 +990,14 @@ RSpec.describe API::Issues do expect(ResourceLabelEvent.last.created_at).to be_like_time(fixed_time) end end + + describe 'issue_type param' do + it 'allows issue type to be converted' do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { issue_type: 'incident' } + + expect(issue.reload.incident?).to be(true) + end + end end describe 'DELETE /projects/:id/issues/:issue_iid' do diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb index 65528f3900f..37f18e52449 100644 --- a/spec/support/shared_contexts/navbar_structure_context.rb +++ b/spec/support/shared_contexts/navbar_structure_context.rb @@ -24,6 +24,23 @@ RSpec.shared_context 'project navbar structure' do } end + let(:operations_menu_items) do + [ + _('Metrics'), + _('Logs'), + _('Tracing'), + _('Error Tracking'), + _('Alerts'), + _('Incidents'), + _('Serverless'), + _('Terraform'), + _('Kubernetes'), + _('Environments'), + _('Feature Flags'), + _('Product Analytics') + ] + end + let(:structure) do [ { @@ -75,20 +92,7 @@ RSpec.shared_context 'project navbar structure' do security_and_compliance_nav_item, { nav_item: _('Operations'), - nav_sub_items: [ - _('Metrics'), - _('Logs'), - _('Tracing'), - _('Error Tracking'), - _('Alerts'), - _('Incidents'), - _('Serverless'), - _('Terraform'), - _('Kubernetes'), - _('Environments'), - _('Feature Flags'), - _('Product Analytics') - ] + nav_sub_items: operations_menu_items }, analytics_nav_item, { diff --git a/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb b/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb index ded381fd402..a3378d4619b 100644 --- a/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/issuable_update_shared_examples.rb @@ -3,7 +3,7 @@ RSpec.shared_examples 'issuable update endpoint' do let(:area) { entity.class.name.underscore.pluralize } - describe 'PUT /projects/:id/issues/:issue_id' do + describe 'PUT /projects/:id/issues/:issue_iid' do let(:url) { "/projects/#{project.id}/#{area}/#{entity.iid}" } it 'clears labels when labels param is nil' do diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb index d5320b2d044..7bb9570e90a 100644 --- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb @@ -471,56 +471,71 @@ RSpec.describe 'layouts/nav/sidebar/_project' do end end - describe 'Serverless' do - it 'has a link to the serverless page' do - render - - expect(rendered).to have_link('Serverless', href: project_serverless_functions_path(project)) + context 'when feature flag :sidebar_refactor is disabled' do + before do + stub_feature_flags(sidebar_refactor: false) end - describe 'when the user does not have access' do - let(:user) { nil } - - it 'does not have a link to the serverless page' do + describe 'Serverless' do + it 'has a link to the serverless page' do render - expect(rendered).not_to have_link('Serverless') + page = Nokogiri::HTML.parse(rendered) + + expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Serverless"]')).not_to be_empty + expect(rendered).to have_link('Serverless', href: project_serverless_functions_path(project)) end - end - end - describe 'Terraform' do - it 'has a link to the terraform page' do - render + describe 'when the user does not have access' do + let(:user) { nil } - expect(rendered).to have_link('Terraform', href: project_terraform_index_path(project)) - end + it 'does not have a link to the serverless page' do + render - describe 'when the user does not have access' do - let(:user) { nil } + expect(rendered).not_to have_link('Serverless') + end + end + end - it 'does not have a link to the terraform page' do + describe 'Terraform' do + it 'has a link to the terraform page' do render - expect(rendered).not_to have_link('Terraform') + page = Nokogiri::HTML.parse(rendered) + + expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Terraform"]')).not_to be_empty + expect(rendered).to have_link('Terraform', href: project_terraform_index_path(project)) end - end - end - describe 'Kubernetes' do - it 'has a link to the kubernetes page' do - render + describe 'when the user does not have access' do + let(:user) { nil } - expect(rendered).to have_link('Kubernetes', href: project_clusters_path(project)) - end + it 'does not have a link to the terraform page' do + render - describe 'when the user does not have access' do - let(:user) { nil } + expect(rendered).not_to have_link('Terraform') + end + end + end - it 'does not have a link to the kubernetes page' do + describe 'Kubernetes' do + it 'has a link to the kubernetes page' do render - expect(rendered).not_to have_link('Kubernetes') + page = Nokogiri::HTML.parse(rendered) + + expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Kubernetes"]')).not_to be_empty + expect(rendered).to have_link('Kubernetes', href: project_clusters_path(project)) + end + + describe 'when the user does not have access' do + let(:user) { nil } + + it 'does not have a link to the kubernetes page' do + render + + expect(rendered).not_to have_link('Kubernetes') + end end end end @@ -580,6 +595,62 @@ RSpec.describe 'layouts/nav/sidebar/_project' do end end + describe 'Infrastructure' do + describe 'Serverless platform' do + it 'has a link to the serverless page' do + render + + expect(rendered).to have_link('Serverless platform', href: project_serverless_functions_path(project)) + end + + describe 'when the user does not have access' do + let(:user) { nil } + + it 'does not have a link to the serverless page' do + render + + expect(rendered).not_to have_link('Serverless platform') + end + end + end + + describe 'Terraform' do + it 'has a link to the terraform page' do + render + + expect(rendered).to have_link('Terraform', href: project_terraform_index_path(project)) + end + + describe 'when the user does not have access' do + let(:user) { nil } + + it 'does not have a link to the terraform page' do + render + + expect(rendered).not_to have_link('Terraform') + end + end + end + + describe 'Kubernetes clusters' do + it 'has a link to the kubernetes page' do + render + + expect(rendered).to have_link('Kubernetes clusters', href: project_clusters_path(project)) + end + + describe 'when the user does not have access' do + let(:user) { nil } + + it 'does not have a link to the kubernetes page' do + render + + expect(rendered).not_to have_link('Kubernetes clusters') + end + end + end + end + describe 'Packages and Registries' do let(:registry_enabled) { true } let(:packages_enabled) { true } diff --git a/yarn.lock b/yarn.lock index e510df1873c..ef5ed4520e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3605,10 +3605,10 @@ core-js-pure@^3.0.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== -core-js@^3.1.3, core-js@^3.11.2: - version "3.11.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.2.tgz#af087a43373fc6e72942917c4a4c3de43ed574d6" - integrity sha512-3tfrrO1JpJSYGKnd9LKTBPqgUES/UYiCzMKeqwR1+jF16q4kD1BY2NvqkfuzXwQ6+CIWm55V9cjD7PQd+hijdw== +core-js@^3.1.3, core-js@^3.11.3: + version "3.11.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.3.tgz#2835b1f4d10f6d0400bf820cfe6fe64ad067dd3f" + integrity sha512-DFEW9BllWw781Op5KdYGtXfj3s9Cmykzt16bY6elaVuqXHCUwF/5pv0H3IJ7/I3BGjK7OeU+GrjD1ChCkBJPuA== core-js@~2.3.0: version "2.3.0" |