Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-16 15:07:32 +00:00
parent d2199d7493
commit db19df2373
35 changed files with 244 additions and 179 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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": {

View File

@ -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"

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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?

View File

@ -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'

View File

@ -9,7 +9,6 @@ SPECIALIZATIONS = {
ux: 'UX',
docs: 'documentation',
qa: 'QA',
tooling: 'type::tooling',
ci_template: 'ci::templates',
feature_flag: 'feature flag'
}.freeze

View File

@ -1,9 +1,8 @@
# frozen_string_literal: true
NO_SPECS_LABELS = [
'type::tooling',
'tooling::pipelines',
'tooling::workflow',
'maintenance::pipelines',
'maintenance::workflow',
'documentation',
'QA'
].freeze

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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:

View File

@ -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:

View File

@ -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). |

View File

@ -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 = {})

View File

@ -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

View File

@ -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 ""

View File

@ -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', () => {

View File

@ -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)

View File

@ -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 }

View File

@ -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

View File

@ -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)
}

View File

@ -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 (

View File

@ -1,3 +1,4 @@
// The filestore package has a consumer specific to uploading to local disk storage.
package filestore
import (

View File

@ -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