Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d2199d7493
commit
db19df2373
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
# 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
|
||||
end
|
||||
|
||||
# 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: users).index_by(&:user_id) # rubocop:disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
[emails, users, existing_members]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ SPECIALIZATIONS = {
|
|||
ux: 'UX',
|
||||
docs: 'documentation',
|
||||
qa: 'QA',
|
||||
tooling: 'type::tooling',
|
||||
ci_template: 'ci::templates',
|
||||
feature_flag: 'feature flag'
|
||||
}.freeze
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
NO_SPECS_LABELS = [
|
||||
'type::tooling',
|
||||
'tooling::pipelines',
|
||||
'tooling::workflow',
|
||||
'maintenance::pipelines',
|
||||
'maintenance::workflow',
|
||||
'documentation',
|
||||
'QA'
|
||||
].freeze
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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). |
|
||||
|
|
|
|||
|
|
@ -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 = {})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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 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
|
||||
|
||||
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" } }
|
||||
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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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)
|
||||
it 'supports existing users as expected without user ids passed' do
|
||||
user3 = create(:user)
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// The filestore package has a consumer specific to uploading to local disk storage.
|
||||
package filestore
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue