diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-16 18:07:32 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-16 18:07:32 +0300 |
commit | db19df23733c768c564534a09de2e6718097ec95 (patch) | |
tree | f148eb0723f20a2442e0274089d567e1810ee8d2 | |
parent | d2199d74936cd5cb9f45f569f723a5370ae5013e (diff) |
Add latest changes from gitlab-org/gitlab@master
35 files changed, 242 insertions, 177 deletions
diff --git a/.gitlab/issue_templates/Refactoring.md b/.gitlab/issue_templates/Refactoring.md index df18dcf7656..453ae743237 100644 --- a/.gitlab/issue_templates/Refactoring.md +++ b/.gitlab/issue_templates/Refactoring.md @@ -42,8 +42,9 @@ please list them here. Please select the appropriate label from the following: ~"feature::addition" ~"type::maintenance" - ~"tooling::pipelines" - ~"tooling::workflow" + ~"maintenance::refactor" + ~"maintenance::pipelines" + ~"maintenance::workflow" --> /label ~"type::maintenance" diff --git a/.gitlab/merge_request_templates/Pipeline Configuration.md b/.gitlab/merge_request_templates/Pipeline Configuration.md index a0b8d1cb8e4..336988d8bdf 100644 --- a/.gitlab/merge_request_templates/Pipeline Configuration.md +++ b/.gitlab/merge_request_templates/Pipeline Configuration.md @@ -35,4 +35,4 @@ This will help keep track of expected cost increases to the [GitLab project aver - [ ] Consider communicating these changes to the broader team following the [communication guideline for pipeline changes](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/#pipeline-changes) -/label ~"type::tooling" ~"tooling::pipelines" ~"Engineering Productivity" +/label ~"maintenance::pipelines" ~"Engineering Productivity" @@ -403,7 +403,7 @@ group :development, :test do end group :development, :test, :danger do - gem 'gitlab-dangerfiles', '~> 2.10.2', require: false + gem 'gitlab-dangerfiles', '~> 2.11.0', require: false end group :development, :test, :coverage do diff --git a/Gemfile.lock b/Gemfile.lock index a8a01945085..2b0057d353d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -463,8 +463,8 @@ GEM terminal-table (~> 1.5, >= 1.5.1) gitlab-chronic (0.10.5) numerizer (~> 0.2) - gitlab-dangerfiles (2.10.2) - danger (>= 8.3.1) + gitlab-dangerfiles (2.11.0) + danger (>= 8.4.5) danger-gitlab (>= 8.0.0) gitlab-experiment (0.7.0) activesupport (>= 3.0) @@ -1494,7 +1494,7 @@ DEPENDENCIES gitaly (~> 14.9.0.pre.rc4) github-markup (~> 1.7.0) gitlab-chronic (~> 0.10.5) - gitlab-dangerfiles (~> 2.10.2) + gitlab-dangerfiles (~> 2.11.0) gitlab-experiment (~> 0.7.0) gitlab-fog-azure-rm (~> 1.2.0) gitlab-labkit (~> 0.22.0) diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index 4d9fe6ff851..84220d59205 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -423,37 +423,34 @@ "description": "Defines secrets to be injected as environment variables", "additionalProperties": { "type": "object", - "additionalProperties": { - "type": "object", - "description": "Environment variable name", - "properties": { - "vault": { - "oneOf": [ - { - "type": "string", - "description": "The secret to be fetched from Vault (e.g. 'production/db/password@ops' translates to secret 'ops/data/production/db', field `password`)" - }, - { - "type": "object", - "properties": { - "engine": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "path": { "type": "string" } - }, - "required": ["name", "path"] + "description": "Environment variable name", + "properties": { + "vault": { + "oneOf": [ + { + "type": "string", + "description": "The secret to be fetched from Vault (e.g. 'production/db/password@ops' translates to secret 'ops/data/production/db', field `password`)" + }, + { + "type": "object", + "properties": { + "engine": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" } }, - "path": { "type": "string" }, - "field": { "type": "string" } + "required": ["name", "path"] }, - "required": ["engine", "path", "field"] - } - ] - } - }, - "required": ["vault"] - } + "path": { "type": "string" }, + "field": { "type": "string" } + }, + "required": ["engine", "path", "field"] + } + ] + } + }, + "required": ["vault"] } }, "before_script": { diff --git a/app/assets/javascripts/runner/components/runner_pause_button.vue b/app/assets/javascripts/runner/components/runner_pause_button.vue index a1901c55e61..c88634bfbd9 100644 --- a/app/assets/javascripts/runner/components/runner_pause_button.vue +++ b/app/assets/javascripts/runner/components/runner_pause_button.vue @@ -3,7 +3,7 @@ import { GlButton, GlTooltipDirective } from '@gitlab/ui'; import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql'; import { createAlert } from '~/flash'; import { captureException } from '~/runner/sentry_utils'; -import { I18N_PAUSE, I18N_RESUME } from '../constants'; +import { I18N_PAUSE, I18N_PAUSE_TOOLTIP, I18N_RESUME, I18N_RESUME_TOOLTIP } from '../constants'; export default { name: 'RunnerPauseButton', @@ -52,11 +52,10 @@ export default { return null; }, tooltip() { - // Only show tooltip when compact. - // Also prevent a "sticky" tooltip: If this button is - // disabled, mouseout listeners don't run leaving the tooltip stuck - if (this.compact && !this.updating) { - return this.label; + // Prevent a "sticky" tooltip: If this button is disabled, + // mouseout listeners don't run leaving the tooltip stuck + if (!this.updating) { + return this.isActive ? I18N_PAUSE_TOOLTIP : I18N_RESUME_TOOLTIP; } return ''; }, @@ -102,7 +101,7 @@ export default { <template> <gl-button - v-gl-tooltip.hover.viewport="tooltip" + v-gl-tooltip="tooltip" v-bind="$attrs" :aria-label="ariaLabel" :icon="icon" diff --git a/app/assets/javascripts/runner/components/runner_paused_badge.vue b/app/assets/javascripts/runner/components/runner_paused_badge.vue index d1e6fa05e4d..27618290ce6 100644 --- a/app/assets/javascripts/runner/components/runner_paused_badge.vue +++ b/app/assets/javascripts/runner/components/runner_paused_badge.vue @@ -1,6 +1,6 @@ <script> import { GlBadge, GlTooltipDirective } from '@gitlab/ui'; -import { I18N_PAUSED_RUNNER_DESCRIPTION } from '../constants'; +import { I18N_PAUSED_DESCRIPTION } from '../constants'; export default { components: { @@ -9,17 +9,11 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, - i18n: { - I18N_PAUSED_RUNNER_DESCRIPTION, - }, + I18N_PAUSED_DESCRIPTION, }; </script> <template> - <gl-badge - v-gl-tooltip="$options.i18n.I18N_PAUSED_RUNNER_DESCRIPTION" - variant="danger" - v-bind="$attrs" - > + <gl-badge v-gl-tooltip="$options.I18N_PAUSED_DESCRIPTION" variant="danger" v-bind="$attrs"> {{ s__('Runners|paused') }} </gl-badge> </template> diff --git a/app/assets/javascripts/runner/constants.js b/app/assets/javascripts/runner/constants.js index 7ac19210fb1..bd5be2175ad 100644 --- a/app/assets/javascripts/runner/constants.js +++ b/app/assets/javascripts/runner/constants.js @@ -37,13 +37,18 @@ export const I18N_STALE_RUNNER_DESCRIPTION = s__( // Actions export const I18N_EDIT = __('Edit'); + export const I18N_PAUSE = __('Pause'); +export const I18N_PAUSE_TOOLTIP = s__('Runners|Pause from accepting jobs'); +export const I18N_PAUSED_DESCRIPTION = s__('Runners|Not accepting jobs'); + export const I18N_RESUME = __('Resume'); +export const I18N_RESUME_TOOLTIP = s__('Runners|Resume accepting jobs'); + export const I18N_DELETE_RUNNER = s__('Runners|Delete runner'); export const I18N_DELETED_TOAST = s__('Runners|Runner %{name} was deleted'); export const I18N_LOCKED_RUNNER_DESCRIPTION = s__('Runners|You cannot assign to other projects'); -export const I18N_PAUSED_RUNNER_DESCRIPTION = s__('Runners|Not available to run jobs'); // Runner details diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 3453518fea8..c7aad7ff861 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -657,7 +657,17 @@ class ApplicationSetting < ApplicationRecord users_count >= INSTANCE_REVIEW_MIN_USERS end + Recursion = Class.new(RuntimeError) + def self.create_from_defaults + # this is posssible if calls to create the record depend on application + # settings themselves. This was seen in the case of a feature flag called by + # `transaction` that ended up requiring application settings to determine metrics behavior. + # If something like that happens, we break the loop here, and let the caller decide how to manage it. + raise Recursion if Thread.current[:application_setting_create_from_defaults] + + Thread.current[:application_setting_create_from_defaults] = true + check_schema! transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions @@ -666,6 +676,8 @@ class ApplicationSetting < ApplicationRecord rescue ActiveRecord::RecordNotUnique # We already have an ApplicationSetting record, so just return it. current_without_cache + ensure + Thread.current[:application_setting_create_from_defaults] = nil end def self.find_or_create_without_cache diff --git a/app/models/integrations/zentao.rb b/app/models/integrations/zentao.rb index 0d437d335e9..c33df465fde 100644 --- a/app/models/integrations/zentao.rb +++ b/app/models/integrations/zentao.rb @@ -11,7 +11,6 @@ module Integrations validates :api_token, presence: true, if: :activated? validates :zentao_product_xid, presence: true, if: :activated? - # License Level: EEP_FEATURES def self.issues_license_available?(project) project&.licensed_feature_available?(:zentao_issues_integration) end diff --git a/app/services/concerns/members/bulk_create_users.rb b/app/services/concerns/members/bulk_create_users.rb index 9cfef96311e..3f8971dde74 100644 --- a/app/services/concerns/members/bulk_create_users.rb +++ b/app/services/concerns/members/bulk_create_users.rb @@ -47,16 +47,15 @@ module Members end end - if user_ids.present? - # we should handle the idea of existing members where users are passed as users - https://gitlab.com/gitlab-org/gitlab/-/issues/352617 - # the below will automatically discard invalid user_ids - users.concat(User.id_in(user_ids)) + # the below will automatically discard invalid user_ids + users.concat(User.id_in(user_ids)) if user_ids.present? + users.uniq! # de-duplicate just in case as there is no controlling if user records and ids are sent multiple times + + if users.present? # helps not have to perform another query per user id to see if the member exists later on when fetching - existing_members = source.members_and_requesters.where(user_id: user_ids).index_by(&:user_id) # rubocop:disable CodeReuse/ActiveRecord + existing_members = source.members_and_requesters.where(user_id: users).index_by(&:user_id) # rubocop:disable CodeReuse/ActiveRecord end - users.uniq! # de-duplicate just in case as there is no controlling if user records and ids are sent multiple times - [emails, users, existing_members] end end diff --git a/app/views/groups/runners/_runner.html.haml b/app/views/groups/runners/_runner.html.haml index 3297d3c473f..b2d8b9668e7 100644 --- a/app/views/groups/runners/_runner.html.haml +++ b/app/views/groups/runners/_runner.html.haml @@ -9,7 +9,7 @@ - if runner.locked? = gl_badge_tag s_('Runners|locked'), variant: :warning, size: :sm - unless runner.active? - = gl_badge_tag s_('Runners|paused'), variant: :danger, size: :sm + = gl_badge_tag s_('Runners|paused'), { variant: :danger, size: :sm }, { title: s_('Runners|Not accepting jobs'), data: { toggle: 'tooltip', container: 'body' } } .table-section.section-30 .table-mobile-header{ role: 'rowheader' }= s_('Runners|Runner') @@ -64,10 +64,10 @@ = sprite_icon('pencil', css_class: 'gl-icon') .btn-group - if runner.active? - = link_to pause_group_runner_path(@group, runner), method: :post, class: 'gl-button btn btn-default btn-icon has-tooltip', title: _('Pause'), ref: 'tooltip', aria: { label: _('Pause') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do + = link_to pause_group_runner_path(@group, runner), method: :post, class: 'gl-button btn btn-default btn-icon', title: s_('Runners|Pause from accepting jobs'), ref: 'tooltip', aria: { label: _('Pause') }, data: { toggle: 'tooltip', container: 'body', confirm: _('Are you sure?') } do = sprite_icon('pause', css_class: 'gl-icon') - else - = link_to resume_group_runner_path(@group, runner), method: :post, class: 'gl-button btn btn-default btn-icon has-tooltip', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do + = link_to resume_group_runner_path(@group, runner), method: :post, class: 'gl-button btn btn-default btn-icon', title: s_('Runners|Resume accepting jobs'), ref: 'tooltip', aria: { label: _('Resume') }, data: { toggle: 'tooltip', container: 'body'} do = sprite_icon('play', css_class: 'gl-icon') - if runner.belongs_to_more_than_one_project? - delete_runner_tooltip = _('Multi-project Runners cannot be removed') diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml index 4837f829568..02b5fe00ad0 100644 --- a/app/views/projects/commits/_commits.html.haml +++ b/app/views/projects/commits/_commits.html.haml @@ -34,10 +34,11 @@ = render partial: 'projects/commits/commit', collection: context_commits, locals: { project: project, ref: ref, merge_request: merge_request } - if hidden > 0 - %li.gl-alert.gl-alert-warning - .gl-alert-container - = sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title') - .gl-alert-content + %li + = render 'shared/global_alert', + variant: :warning, + dismissible: false do + .gl-alert-body = n_('%s additional commit has been omitted to prevent performance issues.', '%s additional commits have been omitted to prevent performance issues.', hidden) % number_with_delimiter(hidden) - if can_update_merge_request && context_commits&.empty? diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml index 28e5618f8b0..5eaf6c9d22b 100644 --- a/app/views/projects/runners/_runner.html.haml +++ b/app/views/projects/runners/_runner.html.haml @@ -16,10 +16,10 @@ = link_to edit_project_runner_path(@project, runner), class: 'btn gl-button btn-icon', title: _('Edit'), aria: { label: _('Edit') }, data: { testid: 'edit-runner-link', toggle: 'tooltip', placement: 'top', container: 'body' } do = sprite_icon('pencil') - if runner.active? - = link_to pause_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: _('Pause'), aria: { label: _('Pause') }, data: { toggle: 'tooltip', placement: 'top', container: 'body', confirm: _("Are you sure?") } do + = link_to pause_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: s_('Runners|Pause from accepting jobs'), aria: { label: _('Pause') }, data: { toggle: 'tooltip', container: 'body', confirm: _("Are you sure?") } do = sprite_icon('pause') - else - = link_to resume_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: _('Resume'), aria: { label: _('Resume') }, data: { toggle: 'tooltip', placement: 'top', container: 'body' } do + = link_to resume_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: s_('Runners|Resume accepting jobs'), aria: { label: _('Resume') }, data: { toggle: 'tooltip', container: 'body' } do = sprite_icon('play') - if runner.belongs_to_one_project? = link_to _('Remove runner'), project_runner_path(@project, runner), data: { confirm: _("Are you sure?") }, method: :delete, class: 'btn gl-button btn-danger' diff --git a/danger/specialization_labels/Dangerfile b/danger/specialization_labels/Dangerfile index b3520e7af7e..f161c470f36 100644 --- a/danger/specialization_labels/Dangerfile +++ b/danger/specialization_labels/Dangerfile @@ -9,7 +9,6 @@ SPECIALIZATIONS = { ux: 'UX', docs: 'documentation', qa: 'QA', - tooling: 'type::tooling', ci_template: 'ci::templates', feature_flag: 'feature flag' }.freeze diff --git a/danger/specs/Dangerfile b/danger/specs/Dangerfile index c4f609f5806..8ef046f7bc1 100644 --- a/danger/specs/Dangerfile +++ b/danger/specs/Dangerfile @@ -1,9 +1,8 @@ # frozen_string_literal: true NO_SPECS_LABELS = [ - 'type::tooling', - 'tooling::pipelines', - 'tooling::workflow', + 'maintenance::pipelines', + 'maintenance::workflow', 'documentation', 'QA' ].freeze diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md index c303dc1fd19..8ea4ad9019e 100644 --- a/doc/administration/object_storage.md +++ b/doc/administration/object_storage.md @@ -598,6 +598,7 @@ See the following additional guides: 1. Configure [database lookup of SSH keys](operations/fast_ssh_key_lookup.md) to eliminate the need for a shared `authorized_keys` file. 1. [Prevent local disk usage for job logs](job_logs.md#prevent-local-disk-usage). +1. [Disable Pages local storage](pages/index.md#disable-pages-local-storage). ## Warnings, limitations, and known issues diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index f000824711f..be1ec290c95 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -547,6 +547,7 @@ archive. You can modify the cache behavior by changing the following configurati | `zip_cache_cleanup` | The interval at which archives are cleaned from memory if they have already expired. Default is 30s. | | `zip_cache_refresh` | The time interval in which an archive is extended in memory if accessed before `zip_cache_expiration`. This works together with `zip_cache_expiration` to determine if an archive is extended in memory. See the [example below](#zip-cache-refresh-example) for important details. Default is 30s. | | `zip_open_timeout` | The maximum time allowed to open a ZIP archive. Increase this time for big archives or slow network connections, as doing so may affect the latency of serving Pages. Default is 30s. | +| `zip_http_client_timeout` | The maximum time for the ZIP HTTP client. Default is 30m. | #### ZIP cache refresh example diff --git a/doc/api/index.md b/doc/api/index.md index 40b3fd4e22a..6cdf64a01af 100644 --- a/doc/api/index.md +++ b/doc/api/index.md @@ -8,9 +8,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w Use the GitLab APIs to automate GitLab. -NOTE: -We've launched our first API user survey! Do you use GitLab APIs? How can we improve? [Contribute your feedback today](https://gitlab.fra1.qualtrics.com/jfe/form/SV_cD9wcDYMcVDruSy) and make sure your voice is heard! - ## REST API A REST API is available in GitLab. diff --git a/doc/ci/environments/deployment_approvals.md b/doc/ci/environments/deployment_approvals.md index 12090443e61..e42cde031ad 100644 --- a/doc/ci/environments/deployment_approvals.md +++ b/doc/ci/environments/deployment_approvals.md @@ -11,7 +11,7 @@ description: Require approvals prior to deploying to a Protected Environment > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/347342) in GitLab 14.8. WARNING: -This feature is in an [Alpha](../../policy/alpha-beta-support.md#alpha-features) stage and subject to change without prior notice. +This feature is in a [Beta](../../policy/alpha-beta-support.md#beta-features) stage and subject to change without prior notice. It may be useful to require additional approvals before deploying to certain protected environments (for example, production). This pre-deployment approval requirement is useful to accommodate testing, security, or compliance processes that must happen before each deployment. diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md index ad8403d242c..4db686b9b1e 100644 --- a/doc/development/contributing/issue_workflow.md +++ b/doc/development/contributing/issue_workflow.md @@ -45,7 +45,7 @@ scheduling into milestones. Labeling is a task for everyone. (For some projects, Most issues will have labels for at least one of the following: -- Type. For example: `~"type::feature"`, `~"type::bug"`, or `~"type::tooling"`. +- Type. For example: `~"type::feature"`, `~"type::bug"`, or `~"type::maintenance"`. - Stage. For example: `~"devops::plan"` or `~"devops::create"`. - Group. For example: `~"group::source code"`, `~"group::knowledge"`, or `~"group::editor"`. - Category. For example: `~"Category:Code Analytics"`, `~"Category:DevOps Reports"`, or `~"Category:Templates"`. @@ -72,19 +72,7 @@ labels, you can _always_ add the type, stage, group, and often the category/feat Type labels are very important. They define what kind of issue this is. Every issue should have one and only one. -The current type labels are: - -- `~"type::feature"` - - `~"feature::addition"` - - `~"feature::enhancement"` -- `~"type::maintenance"` -- `~"type::bug"` -- `~"type::tooling"` - - `~"tooling::pipelines"` - - `~"tooling::workflow"` -- `~"support request"` -- `~meta` -- `~documentation` +The current type labels are [available in the handbook](https://about.gitlab.com/handbook/engineering/metrics/#work-type-classification) A number of type labels have a priority assigned to them, which automatically makes them float to the top, depending on their importance. diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md index a8745b974b9..2c97b5e2aff 100644 --- a/doc/development/documentation/testing.md +++ b/doc/development/documentation/testing.md @@ -313,6 +313,9 @@ To configure Vale in your editor, install one of the following as appropriate: - Visual Studio Code [`errata-ai.vale-server` extension](https://marketplace.visualstudio.com/items?itemName=errata-ai.vale-server). You can configure the plugin to [display only a subset of alerts](#show-subset-of-vale-alerts). - Vim [ALE plugin](https://github.com/dense-analysis/ale). +- Jetbrains IDEs - No plugin exists, but + [this issue comment](https://github.com/errata-ai/vale-server/issues/39#issuecomment-751714451) + contains tips for configuring an external tool. - Emacs [Flycheck extension](https://github.com/flycheck/flycheck). This requires some configuration: diff --git a/doc/development/licensed_feature_availability.md b/doc/development/licensed_feature_availability.md index 629d0027ffe..0de3f94cf70 100644 --- a/doc/development/licensed_feature_availability.md +++ b/doc/development/licensed_feature_availability.md @@ -17,9 +17,8 @@ feature such as [Related issues](../user/project/issues/related_issues.md) or [Service Desk](../user/project/service_desk.md), it should be restricted on namespace scope. -1. Add the feature symbol on `EES_FEATURES`, `EEP_FEATURES`, or `EEU_FEATURES` constants in - `ee/app/models/license.rb`. Note that the prefix `EES` signifies Starter, `EEP` signifies - Premium, and `EEU` signifies Ultimate. +1. Add the feature symbol on `STARTER_FEATURES`, `PREMIUM_FEATURES`, or `ULTIMATE_FEATURES` constants in + `ee/app/models/gitlab_subscriptions/features.rb`. 1. Check using: ```ruby @@ -33,8 +32,8 @@ However, for features such as [Geo](../administration/geo/index.md) and to only a subset of projects or namespaces, the check is made directly in the instance license. -1. Add the feature symbol on `EES_FEATURES`, `EEP_FEATURES` or `EEU_FEATURES` constants in - `ee/app/models/license.rb`. +1. Add the feature symbol to `STARTER_FEATURES`, `PREMIUM_FEATURES` or `ULTIMATE_FEATURES` constants in + `ee/app/models/gitlab_subscriptions/features.rb`. 1. Add the same feature symbol to `GLOBAL_FEATURES`. 1. Check using: diff --git a/doc/development/service_ping/metrics_dictionary.md b/doc/development/service_ping/metrics_dictionary.md index 588453be002..6884844da3f 100644 --- a/doc/development/service_ping/metrics_dictionary.md +++ b/doc/development/service_ping/metrics_dictionary.md @@ -49,7 +49,7 @@ Each metric is defined in a separate YAML file consisting of a number of fields: | `tier` | yes | `array`; may contain one or a combination of `free`, `premium` or `ultimate`. The [tier]( https://about.gitlab.com/handbook/marketing/strategic-marketing/tiers/) where the tracked feature is available. This should be verbose and contain all tiers where a metric is available. | | `milestone` | no | The milestone when the metric is introduced and when it's available to self-managed instances with the official GitLab release. | | `milestone_removed` | no | The milestone when the metric is removed. | -| `introduced_by_url` | no | The URL to the merge request that introduced the metric. | +| `introduced_by_url` | no | The URL to the merge request that introduced the metric to be available for self-managed instances. | | `repair_issue_url` | no | The URL of the issue that was created to repair a metric with a `broken` status. | | `options` | no | `object`: options information needed to calculate the metric value. | | `skip_validation` | no | This should **not** be set. [Used for imported metrics until we review, update and make them valid](https://gitlab.com/groups/gitlab-org/-/epics/5425). | diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 0d6767ad564..8ef4977177a 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -70,6 +70,8 @@ module Gitlab else ::ApplicationSetting.create_from_defaults end + rescue ::ApplicationSetting::Recursion + in_memory_application_settings end def fake_application_settings(attributes = {}) diff --git a/lib/security/ci_configuration/base_build_action.rb b/lib/security/ci_configuration/base_build_action.rb index 9c2670144e3..8f0765a35c2 100644 --- a/lib/security/ci_configuration/base_build_action.rb +++ b/lib/security/ci_configuration/base_build_action.rb @@ -6,7 +6,7 @@ module Security def initialize(auto_devops_enabled, existing_gitlab_ci_content, ci_config_path = ::Ci::Pipeline::DEFAULT_CONFIG_PATH) @auto_devops_enabled = auto_devops_enabled @existing_gitlab_ci_content = existing_gitlab_ci_content || {} - @ci_config_path = ci_config_path || ::Ci::Pipeline::DEFAULT_CONFIG_PATH + @ci_config_path = ci_config_path.presence || ::Ci::Pipeline::DEFAULT_CONFIG_PATH end def generate diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 989c38161be..d1e24d7ea43 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -31912,7 +31912,7 @@ msgstr "" msgid "Runners|No recent contact from this runner; last contact was %{timeAgo}" msgstr "" -msgid "Runners|Not available to run jobs" +msgid "Runners|Not accepting jobs" msgstr "" msgid "Runners|Offline" @@ -31927,6 +31927,9 @@ msgstr "" msgid "Runners|Online runners" msgstr "" +msgid "Runners|Pause from accepting jobs" +msgstr "" + msgid "Runners|Paused" msgstr "" @@ -31963,6 +31966,9 @@ msgstr "" msgid "Runners|Reset token" msgstr "" +msgid "Runners|Resume accepting jobs" +msgstr "" + msgid "Runners|Revision" msgstr "" diff --git a/spec/frontend/runner/components/runner_pause_button_spec.js b/spec/frontend/runner/components/runner_pause_button_spec.js index c69bae05e45..3d9df03977e 100644 --- a/spec/frontend/runner/components/runner_pause_button_spec.js +++ b/spec/frontend/runner/components/runner_pause_button_spec.js @@ -8,6 +8,12 @@ import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_ac import waitForPromises from 'helpers/wait_for_promises'; import { captureException } from '~/runner/sentry_utils'; import { createAlert } from '~/flash'; +import { + I18N_PAUSE, + I18N_PAUSE_TOOLTIP, + I18N_RESUME, + I18N_RESUME_TOOLTIP, +} from '~/runner/constants'; import RunnerPauseButton from '~/runner/components/runner_pause_button.vue'; import { runnersData } from '../mock_data'; @@ -74,10 +80,10 @@ describe('RunnerPauseButton', () => { describe('Pause/Resume action', () => { describe.each` - runnerState | icon | content | isActive | newActiveValue - ${'paused'} | ${'play'} | ${'Resume'} | ${false} | ${true} - ${'active'} | ${'pause'} | ${'Pause'} | ${true} | ${false} - `('When the runner is $runnerState', ({ icon, content, isActive, newActiveValue }) => { + runnerState | icon | content | tooltip | isActive | newActiveValue + ${'paused'} | ${'play'} | ${I18N_RESUME} | ${I18N_RESUME_TOOLTIP} | ${false} | ${true} + ${'active'} | ${'pause'} | ${I18N_PAUSE} | ${I18N_PAUSE_TOOLTIP} | ${true} | ${false} + `('When the runner is $runnerState', ({ icon, content, tooltip, isActive, newActiveValue }) => { beforeEach(() => { createComponent({ props: { @@ -91,7 +97,11 @@ describe('RunnerPauseButton', () => { it(`Displays a ${icon} button`, () => { expect(findBtn().props('loading')).toBe(false); expect(findBtn().props('icon')).toBe(icon); + }); + + it('Displays button content', () => { expect(findBtn().text()).toBe(content); + expect(getTooltip()).toBe(tooltip); }); it('Does not display redundant text for screen readers', () => { @@ -218,8 +228,8 @@ describe('RunnerPauseButton', () => { }); it('Display correctly for screen readers', () => { - expect(findBtn().attributes('aria-label')).toBe('Pause'); - expect(getTooltip()).toBe('Pause'); + expect(findBtn().attributes('aria-label')).toBe(I18N_PAUSE); + expect(getTooltip()).toBe(I18N_PAUSE_TOOLTIP); }); describe('Immediately after the button is clicked', () => { diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb index 73540a9b0f3..fda3b07eb82 100644 --- a/spec/lib/gitlab/current_settings_spec.rb +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -179,6 +179,21 @@ RSpec.describe Gitlab::CurrentSettings do expect(settings).to have_attributes(settings_from_defaults) end + context 'when we hit a recursive loop' do + before do + expect(ApplicationSetting).to receive(:create_from_defaults) do + raise ApplicationSetting::Recursion + end + end + + it 'recovers and returns in-memory settings' do + settings = described_class.current_application_settings + + expect(settings).to be_a(ApplicationSetting) + expect(settings).not_to be_persisted + end + end + context 'when ApplicationSettings does not have a primary key' do before do allow(ApplicationSetting.connection).to receive(:primary_key).with('application_settings').and_return(nil) diff --git a/spec/lib/security/ci_configuration/sast_iac_build_action_spec.rb b/spec/lib/security/ci_configuration/sast_iac_build_action_spec.rb index 4c459058368..7b2a0d22918 100644 --- a/spec/lib/security/ci_configuration/sast_iac_build_action_spec.rb +++ b/spec/lib/security/ci_configuration/sast_iac_build_action_spec.rb @@ -7,12 +7,13 @@ RSpec.describe Security::CiConfiguration::SastIacBuildAction do let(:params) { {} } - context 'with existing .gitlab-ci.yml' do - let(:auto_devops_enabled) { false } + shared_examples 'existing .gitlab-ci.yml tests' do + context 'with existing .gitlab-ci.yml' do + let(:auto_devops_enabled) { false } - context 'sast iac has not been included' do - let(:expected_yml) do - <<-CI_YML.strip_heredoc + context 'sast iac has not been included' do + let(:expected_yml) do + <<-CI_YML.strip_heredoc # You can override the included template(s) by including variable overrides # SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings # Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings @@ -28,39 +29,39 @@ RSpec.describe Security::CiConfiguration::SastIacBuildAction do include: - template: existing.yml - template: Security/SAST-IaC.latest.gitlab-ci.yml - CI_YML - end - - context 'template includes are an array' do - let(:gitlab_ci_content) do - { "stages" => %w(test security), - "variables" => { "RANDOM" => "make sure this persists" }, - "include" => [{ "template" => "existing.yml" }] } + CI_YML end - it 'generates the correct YML' do - expect(result[:action]).to eq('update') - expect(result[:content]).to eq(expected_yml) - end - end - - context 'template include is not an array' do - let(:gitlab_ci_content) do - { "stages" => %w(test security), - "variables" => { "RANDOM" => "make sure this persists" }, - "include" => { "template" => "existing.yml" } } + context 'template includes are an array' do + let(:gitlab_ci_content) do + { "stages" => %w(test security), + "variables" => { "RANDOM" => "make sure this persists" }, + "include" => [{ "template" => "existing.yml" }] } + end + + it 'generates the correct YML' do + expect(result[:action]).to eq('update') + expect(result[:content]).to eq(expected_yml) + end end - it 'generates the correct YML' do - expect(result[:action]).to eq('update') - expect(result[:content]).to eq(expected_yml) + context 'template include is not an array' do + let(:gitlab_ci_content) do + { "stages" => %w(test security), + "variables" => { "RANDOM" => "make sure this persists" }, + "include" => { "template" => "existing.yml" } } + end + + it 'generates the correct YML' do + expect(result[:action]).to eq('update') + expect(result[:content]).to eq(expected_yml) + end end end - end - context 'secret_detection has been included' do - let(:expected_yml) do - <<-CI_YML.strip_heredoc + context 'secret_detection has been included' do + let(:expected_yml) do + <<-CI_YML.strip_heredoc # You can override the included template(s) by including variable overrides # SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings # Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings @@ -74,37 +75,50 @@ RSpec.describe Security::CiConfiguration::SastIacBuildAction do RANDOM: make sure this persists include: - template: Security/SAST-IaC.latest.gitlab-ci.yml - CI_YML - end - - context 'secret_detection template include are an array' do - let(:gitlab_ci_content) do - { "stages" => %w(test), - "variables" => { "RANDOM" => "make sure this persists" }, - "include" => [{ "template" => "Security/SAST-IaC.latest.gitlab-ci.yml" }] } + CI_YML end - it 'generates the correct YML' do - expect(result[:action]).to eq('update') - expect(result[:content]).to eq(expected_yml) - end - end - - context 'secret_detection template include is not an array' do - let(:gitlab_ci_content) do - { "stages" => %w(test), - "variables" => { "RANDOM" => "make sure this persists" }, - "include" => { "template" => "Security/SAST-IaC.latest.gitlab-ci.yml" } } + context 'secret_detection template include are an array' do + let(:gitlab_ci_content) do + { "stages" => %w(test), + "variables" => { "RANDOM" => "make sure this persists" }, + "include" => [{ "template" => "Security/SAST-IaC.latest.gitlab-ci.yml" }] } + end + + it 'generates the correct YML' do + expect(result[:action]).to eq('update') + expect(result[:content]).to eq(expected_yml) + end end - it 'generates the correct YML' do - expect(result[:action]).to eq('update') - expect(result[:content]).to eq(expected_yml) + context 'secret_detection template include is not an array' do + let(:gitlab_ci_content) do + { "stages" => %w(test), + "variables" => { "RANDOM" => "make sure this persists" }, + "include" => { "template" => "Security/SAST-IaC.latest.gitlab-ci.yml" } } + end + + it 'generates the correct YML' do + expect(result[:action]).to eq('update') + expect(result[:content]).to eq(expected_yml) + end end end end end + context 'with existing .gitlab-ci.yml and when the ci config file configuration was not set' do + subject(:result) { described_class.new(auto_devops_enabled, gitlab_ci_content).generate } + + it_behaves_like 'existing .gitlab-ci.yml tests' + end + + context 'with existing .gitlab-ci.yml and when the ci config file configuration was deleted' do + subject(:result) { described_class.new(auto_devops_enabled, gitlab_ci_content, ci_config_path: '').generate } + + it_behaves_like 'existing .gitlab-ci.yml tests' + end + context 'with no .gitlab-ci.yml' do let(:gitlab_ci_content) { nil } diff --git a/spec/support/shared_examples/models/member_shared_examples.rb b/spec/support/shared_examples/models/member_shared_examples.rb index f7e09cfca62..17026f085bb 100644 --- a/spec/support/shared_examples/models/member_shared_examples.rb +++ b/spec/support/shared_examples/models/member_shared_examples.rb @@ -371,8 +371,7 @@ RSpec.shared_examples_for "bulk member creation" do it 'returns a Member objects' do members = described_class.add_users(source, [user1, user2], :maintainer) - expect(members).to be_a Array - expect(members.size).to eq(2) + expect(members.map(&:user)).to contain_exactly(user1, user2) expect(members).to all(be_a(member_type)) expect(members).to all(be_persisted) end @@ -394,20 +393,18 @@ RSpec.shared_examples_for "bulk member creation" do end context 'with de-duplication' do - it 'with the same user by id and user' do + it 'has the same user by id and user' do members = described_class.add_users(source, [user1.id, user1, user1.id, user2, user2.id, user2], :maintainer) - expect(members).to be_a Array - expect(members.size).to eq(2) + expect(members.map(&:user)).to contain_exactly(user1, user2) expect(members).to all(be_a(member_type)) expect(members).to all(be_persisted) end - it 'with the same user sent more than once' do + it 'has the same user sent more than once' do members = described_class.add_users(source, [user1, user1], :maintainer) - expect(members).to be_a Array - expect(members.size).to eq(1) + expect(members.map(&:user)).to contain_exactly(user1) expect(members).to all(be_a(member_type)) expect(members).to all(be_persisted) end @@ -418,15 +415,35 @@ RSpec.shared_examples_for "bulk member creation" do source.add_user(user1, :developer) end - it 'supports existing users as expected' do + it 'has the same user sent more than once with the member already existing' do + expect do + members = described_class.add_users(source, [user1, user1, user2], :maintainer) + expect(members.map(&:user)).to contain_exactly(user1, user2) + expect(members).to all(be_a(member_type)) + expect(members).to all(be_persisted) + end.to change { Member.count }.by(1) + end + + it 'supports existing users as expected with user_ids passed' do user3 = create(:user) - members = described_class.add_users(source, [user1.id, user2, user3.id], :maintainer) + expect do + members = described_class.add_users(source, [user1.id, user2, user3.id], :maintainer) + expect(members.map(&:user)).to contain_exactly(user1, user2, user3) + expect(members).to all(be_a(member_type)) + expect(members).to all(be_persisted) + end.to change { Member.count }.by(2) + end + + it 'supports existing users as expected without user ids passed' do + user3 = create(:user) - expect(members).to be_a Array - expect(members.size).to eq(3) - expect(members).to all(be_a(member_type)) - expect(members).to all(be_persisted) + expect do + members = described_class.add_users(source, [user1, user2, user3], :maintainer) + expect(members.map(&:user)).to contain_exactly(user1, user2, user3) + expect(members).to all(be_a(member_type)) + expect(members).to all(be_persisted) + end.to change { Member.count }.by(2) end end diff --git a/spec/tooling/danger/datateam_spec.rb b/spec/tooling/danger/datateam_spec.rb index 3bcef3ac886..e6698dd8970 100644 --- a/spec/tooling/danger/datateam_spec.rb +++ b/spec/tooling/danger/datateam_spec.rb @@ -62,28 +62,28 @@ RSpec.describe Tooling::Danger::Datateam do 'with metric file changes and no performance indicator changes and other label' => { modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml), changed_lines: ['-product_stage: growth'], - mr_labels: ['type::tooling'], + mr_labels: ['type::maintenance'], impacted: false, impacted_files: [] }, 'with performance indicator changes and other label' => { modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), changed_lines: ['+-gmau'], - mr_labels: ['type::tooling'], + mr_labels: ['type::maintenance'], impacted: true, impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) }, 'with performance indicator changes, Data Warehouse::Impact Check and other label' => { modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), changed_lines: ['+-gmau'], - mr_labels: ['type::tooling', 'Data Warehouse::Impact Check'], + mr_labels: ['type::maintenance', 'Data Warehouse::Impact Check'], impacted: false, impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) }, 'with performance indicator changes and other labels' => { modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), changed_lines: ['+-gmau'], - mr_labels: ['type::tooling', 'Data Warehouse::Impacted'], + mr_labels: ['type::maintenance', 'Data Warehouse::Impacted'], impacted: false, impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) } diff --git a/workhorse/internal/upload/destination/destination.go b/workhorse/internal/upload/destination/destination.go index df0d67aea30..7a030e59a64 100644 --- a/workhorse/internal/upload/destination/destination.go +++ b/workhorse/internal/upload/destination/destination.go @@ -1,3 +1,6 @@ +// The destination package handles uploading to a specific destination (delegates +// to filestore or objectstore packages) based on options from the pre-authorization +// API and finalizing the upload. package destination import ( diff --git a/workhorse/internal/upload/destination/filestore/filestore.go b/workhorse/internal/upload/destination/filestore/filestore.go index f593cc30aeb..2d88874bf25 100644 --- a/workhorse/internal/upload/destination/filestore/filestore.go +++ b/workhorse/internal/upload/destination/filestore/filestore.go @@ -1,3 +1,4 @@ +// The filestore package has a consumer specific to uploading to local disk storage. package filestore import ( diff --git a/workhorse/internal/upload/destination/objectstore/doc.go b/workhorse/internal/upload/destination/objectstore/doc.go new file mode 100644 index 00000000000..00f98f230ec --- /dev/null +++ b/workhorse/internal/upload/destination/objectstore/doc.go @@ -0,0 +1,3 @@ +// The objectstore package consists of a number of consumers specific to uploading +// to object storage providers that are S3 compatible (e.g. AWS S3, GCP, Azure). +package objectstore |