Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-10-19 12:09:20 +00:00
parent 93e4425400
commit 6559f0ee67
65 changed files with 609 additions and 149 deletions

View file

@ -571,3 +571,9 @@ Gitlab/RailsLogger:
Exclude:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/267606
FactoryBot/InlineAssociation:
Include:
- 'spec/factories/**/*.rb'
- 'ee/spec/factories/**/*.rb'

View file

@ -1278,3 +1278,44 @@ Graphql/IDType:
- 'app/graphql/resolvers/snippets_resolver.rb'
- 'app/graphql/resolvers/user_merge_requests_resolver.rb'
- 'app/graphql/resolvers/user_resolver.rb'
# Offense count: 86
# Cop supports --auto-correct.
FactoryBot/InlineAssociation:
Exclude:
- 'ee/spec/factories/analytics/cycle_analytics/group_stages.rb'
- 'ee/spec/factories/ci/reports/security/findings.rb'
- 'ee/spec/factories/ci/reports/security/reports.rb'
- 'ee/spec/factories/geo/event_log.rb'
- 'ee/spec/factories/groups.rb'
- 'ee/spec/factories/merge_request_blocks.rb'
- 'ee/spec/factories/resource_iteration_event.rb'
- 'ee/spec/factories/resource_weight_events.rb'
- 'ee/spec/factories/vulnerabilities/feedback.rb'
- 'spec/factories/atlassian_identities.rb'
- 'spec/factories/audit_events.rb'
- 'spec/factories/design_management/design_at_version.rb'
- 'spec/factories/design_management/designs.rb'
- 'spec/factories/design_management/versions.rb'
- 'spec/factories/events.rb'
- 'spec/factories/git_wiki_commit_details.rb'
- 'spec/factories/gitaly/commit.rb'
- 'spec/factories/go_module_commits.rb'
- 'spec/factories/go_module_versions.rb'
- 'spec/factories/go_modules.rb'
- 'spec/factories/group_group_links.rb'
- 'spec/factories/import_export_uploads.rb'
- 'spec/factories/merge_requests.rb'
- 'spec/factories/notes.rb'
- 'spec/factories/packages.rb'
- 'spec/factories/packages/package_file.rb'
- 'spec/factories/prometheus_alert.rb'
- 'spec/factories/resource_label_events.rb'
- 'spec/factories/resource_milestone_event.rb'
- 'spec/factories/resource_state_event.rb'
- 'spec/factories/sent_notifications.rb'
- 'spec/factories/serverless/domain.rb'
- 'spec/factories/serverless/domain_cluster.rb'
- 'spec/factories/terraform/state.rb'
- 'spec/factories/uploads.rb'
- 'spec/factories/wiki_pages.rb'

View file

@ -1,4 +1,4 @@
/* eslint-disable no-underscore-dangle, class-methods-use-this */
/* eslint-disable class-methods-use-this */
import { __ } from '~/locale';
import ListLabel from './label';
import ListAssignee from './assignee';
@ -34,7 +34,6 @@ const TYPES = {
class List {
constructor(obj) {
this.id = obj.id;
this._uid = this.guid();
this.position = obj.position;
this.title = (obj.list_type || obj.listType) === 'backlog' ? __('Open') : obj.title;
this.type = obj.list_type || obj.listType;

View file

@ -1,5 +1,7 @@
import Cookies from 'js-cookie';
import { pick } from 'lodash';
import boardListsQuery from 'ee_else_ce/boards/queries/board_lists.query.graphql';
import { __ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
@ -15,7 +17,6 @@ import {
import boardStore from '~/boards/stores/boards_store';
import listsIssuesQuery from '../queries/lists_issues.query.graphql';
import boardListsQuery from '../queries/board_lists.query.graphql';
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
import updateBoardListMutation from '../queries/board_list_update.mutation.graphql';
import issueMoveListMutation from '../queries/issue_move_list.mutation.graphql';
@ -76,10 +77,10 @@ export default {
variables,
})
.then(({ data }) => {
const { lists } = data[boardType]?.board;
const { lists, hideBacklogList } = data[boardType]?.board;
commit(types.RECEIVE_BOARD_LISTS_SUCCESS, formatBoardLists(lists));
// Backlog list needs to be created if it doesn't exist
if (!lists.nodes.find(l => l.listType === ListType.backlog)) {
// Backlog list needs to be created if it doesn't exist and it's not hidden
if (!lists.nodes.find(l => l.listType === ListType.backlog) && !hideBacklogList) {
dispatch('createList', { backlog: true });
}
dispatch('showWelcomeList');

View file

@ -1,10 +1,12 @@
<script>
import { GlButton } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import Dropdown from './dropdown.vue';
export default {
components: {
Dropdown,
GlButton,
},
computed: {
...mapGetters(['activeFile']),
@ -65,9 +67,9 @@ export default {
@click="selectTemplate"
/>
<transition name="fade">
<button v-show="updateSuccess" type="button" class="btn btn-default" @click="undo">
<gl-button v-show="updateSuccess" category="secondary" variant="default" @click="undo">
{{ __('Undo') }}
</button>
</gl-button>
</transition>
</div>
</template>

View file

@ -73,11 +73,9 @@ export function initIde(el, options = {}) {
* @param {Objects} options - Extra options for the IDE (Used by EE).
*/
export function startIde(options) {
document.addEventListener('DOMContentLoaded', () => {
const ideElement = document.getElementById('ide');
if (ideElement) {
resetServiceWorkersPublicPath();
initIde(ideElement, options);
}
});
const ideElement = document.getElementById('ide');
if (ideElement) {
resetServiceWorkersPublicPath();
initIde(ideElement, options);
}
}

View file

@ -1,13 +1,13 @@
import initNotes from '~/init_notes';
import loadAwardsHandler from '~/awards_handler';
import { SnippetShowInit } from '~/snippets';
import SnippetsShow from '~/snippets/components/show.vue';
import SnippetsAppFactory from '~/snippets';
import ZenMode from '~/zen_mode';
document.addEventListener('DOMContentLoaded', () => {
SnippetShowInit();
initNotes();
loadAwardsHandler();
SnippetsAppFactory(document.getElementById('js-snippet-view'), SnippetsShow);
// eslint-disable-next-line no-new
new ZenMode();
});
initNotes();
loadAwardsHandler();
// eslint-disable-next-line no-new
new ZenMode();

View file

@ -8,7 +8,7 @@ import { SNIPPET_LEVELS_MAP, SNIPPET_VISIBILITY_PRIVATE } from '~/snippets/const
Vue.use(VueApollo);
Vue.use(Translate);
function appFactory(el, Component) {
export default function appFactory(el, Component) {
if (!el) {
return false;
}
@ -45,14 +45,6 @@ function appFactory(el, Component) {
});
}
export const SnippetShowInit = () => {
import('./components/show.vue')
.then(({ default: SnippetsShow }) => {
appFactory(document.getElementById('js-snippet-view'), SnippetsShow);
})
.catch(() => {});
};
export const SnippetEditInit = () => {
import('./components/edit.vue')
.then(({ default: SnippetsEdit }) => {

View file

@ -20,6 +20,10 @@ class ProjectRepositoryStorageMove < ApplicationRecord
inclusion: { in: ->(_) { Gitlab.config.repositories.storages.keys } }
validate :project_repository_writable, on: :create
default_value_for(:destination_storage_name, allows_nil: false) do
pick_repository_storage
end
state_machine initial: :initial do
event :schedule do
transition initial: :scheduled
@ -77,6 +81,12 @@ class ProjectRepositoryStorageMove < ApplicationRecord
scope :order_created_at_desc, -> { order(created_at: :desc) }
scope :with_projects, -> { includes(project: :route) }
class << self
def pick_repository_storage
Project.pick_repository_storage
end
end
private
def project_repository_writable

View file

@ -283,8 +283,7 @@ class Snippet < ApplicationRecord
::Gitlab::RepositorySizeChecker.new(
current_size_proc: -> { repository.size.megabytes },
limit: Gitlab::CurrentSettings.snippet_size_limit,
total_repository_size_excess: nil,
additional_purchased_storage: nil
namespace: nil
)
end
end

View file

@ -75,6 +75,7 @@ module Ci
unless live_chunks_pending?
metrics.increment_trace_operation(operation: :finalized)
metrics.observe_migration_duration(pending_state_seconds)
end
::Gitlab::Ci::Trace::Checksum.new(build).then do |checksum|
@ -130,7 +131,15 @@ module Ci
end
def pending_state_outdated?
Time.current - pending_state.created_at > ACCEPT_TIMEOUT
pending_state_duration > ACCEPT_TIMEOUT
end
def pending_state_duration
Time.current - pending_state.created_at
end
def pending_state_seconds
pending_state_duration.seconds
end
def build_state

View file

@ -17,10 +17,10 @@
%p
#{_('Status')}: #{current_user.two_factor_enabled? ? _('Enabled') : _('Disabled')}
- if current_user.two_factor_enabled?
= link_to _('Manage two-factor authentication'), profile_two_factor_auth_path, class: 'btn btn-info'
= link_to _('Manage two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-info'
- else
.gl-mb-3
= link_to _('Enable two-factor authentication'), profile_two_factor_auth_path, class: 'btn btn-success', data: { qa_selector: 'enable_2fa_button' }
= link_to _('Enable two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-success', data: { qa_selector: 'enable_2fa_button' }
%hr
- if display_providers_on_profile?

View file

@ -30,6 +30,6 @@
= link_to(revoke_session_path(active_session),
{ data: { confirm: _('Are you sure? The device will be signed out of GitLab and all remember me tokens revoked.') },
method: :delete,
class: "btn btn-danger gl-ml-3" }) do
class: "gl-button btn btn-danger gl-ml-3" }) do
%span.sr-only= _('Revoke')
= _('Revoke')

View file

@ -24,4 +24,4 @@
= _('Never')
%td
= link_to _('Remove'), profile_chat_name_path(chat_name), method: :delete, class: 'btn btn-danger float-right', data: { confirm: _('Are you sure you want to revoke this nickname?') }
= link_to _('Remove'), profile_chat_name_path(chat_name), method: :delete, class: 'gl-button btn btn-danger float-right', data: { confirm: _('Are you sure you want to revoke this nickname?') }

View file

@ -8,7 +8,7 @@
.actions
= form_tag profile_chat_names_path, method: :post do
= hidden_field_tag :token, @chat_name_token.token
= submit_tag _("Authorize"), class: "btn btn-success wide float-left"
= submit_tag _("Authorize"), class: "gl-button btn btn-success wide float-left"
= form_tag deny_profile_chat_names_path, method: :delete do
= hidden_field_tag :token, @chat_name_token.token
= submit_tag _("Deny"), class: "btn btn-danger gl-ml-3"
= submit_tag _("Deny"), class: "gl-button btn btn-danger gl-ml-3"

View file

@ -15,7 +15,7 @@
= f.label :email, _('Email'), class: 'label-bold'
= f.text_field :email, class: 'form-control', data: { qa_selector: 'email_address_field' }
.gl-mt-3
= f.submit _('Add email address'), class: 'btn btn-success', data: { qa_selector: 'add_email_address_button' }
= f.submit _('Add email address'), class: 'gl-button btn btn-success', data: { qa_selector: 'add_email_address_button' }
%hr
%h4.gl-mt-0
= _('Linked emails (%{email_count})') % { email_count: @emails.load.size + 1 }
@ -56,8 +56,8 @@
%span.badge.badge-info= s_('Profiles|Notification email')
- unless email.confirmed?
- confirm_title = "#{email.confirmation_sent_at ? _('Resend confirmation email') : _('Send confirmation email')}"
= link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'btn btn-sm btn-warning gl-ml-3'
= link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'gl-button btn btn-sm btn-warning gl-ml-3'
= link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'btn btn-sm btn-danger gl-ml-3' do
= link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'gl-button btn btn-sm btn-danger gl-ml-3' do
%span.sr-only= _('Remove')
= sprite_icon('remove')

View file

@ -7,4 +7,4 @@
= f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: _("Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'.")
.gl-mt-3
= f.submit s_('Profiles|Add key'), class: "btn btn-success"
= f.submit s_('Profiles|Add key'), class: "gl-button btn btn-success"

View file

@ -19,9 +19,9 @@
.float-right
%span.key-created-at
= s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago:time_ago_with_tooltip(key.created_at)}
= link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "btn btn-danger gl-ml-3" do
= link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-danger gl-ml-3" do
%span.sr-only= _('Remove')
= sprite_icon('remove')
= link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "btn btn-danger gl-ml-3" do
= link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "gl-button btn btn-danger gl-ml-3" do
%span.sr-only= _('Revoke')
= _('Revoke')

View file

@ -24,4 +24,4 @@
%button.btn.btn-success.js-add-ssh-key-validation-confirm-submit= _("Yes, add it")
.gl-mt-3
= f.submit s_('Profiles|Add key'), class: "btn btn-success js-add-ssh-key-validation-original-submit qa-add-key-button"
= f.submit s_('Profiles|Add key'), class: "gl-button btn btn-success js-add-ssh-key-validation-original-submit qa-add-key-button"

View file

@ -30,6 +30,6 @@
= f.label :password_confirmation, _('Password confirmation'), class: 'label-bold'
= f.password_field :password_confirmation, required: true, class: 'form-control', data: { qa_selector: 'confirm_password_field' }
.gl-mt-3.gl-mb-3
= f.submit _('Save password'), class: "btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' }
= f.submit _('Save password'), class: "gl-button btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' }
- unless @user.password_automatically_set?
= link_to _('I forgot my password'), reset_profile_password_path, method: :put

View file

@ -28,4 +28,4 @@
.col-sm-10
= f.password_field :password_confirmation, required: true, class: 'form-control'
.form-actions
= f.submit _('Set new password'), class: 'btn btn-success'
= f.submit _('Set new password'), class: 'gl-button btn btn-success'

View file

@ -143,4 +143,4 @@
.col-lg-4.profile-settings-sidebar
.col-lg-8
.form-group
= f.submit _('Save changes'), class: 'btn btn-success'
= f.submit _('Save changes'), class: 'gl-button btn btn-success'

View file

@ -36,7 +36,7 @@
.form-text.text-muted= s_("Profiles|The maximum file size allowed is 200KB.")
- if @user.avatar?
%hr
= link_to s_("Profiles|Remove avatar"), profile_avatar_path, data: { confirm: s_("Profiles|Avatar will be removed. Are you sure?") }, method: :delete, class: 'btn btn-danger btn-inverted'
= link_to s_("Profiles|Remove avatar"), profile_avatar_path, data: { confirm: s_("Profiles|Avatar will be removed. Are you sure?") }, method: :delete, class: 'gl-button btn btn-danger btn-inverted'
%hr
.row
@ -46,7 +46,7 @@
.col-lg-8
= f.fields_for :status, @user.status do |status_form|
- emoji_button = button_tag type: :button,
class: 'js-toggle-emoji-menu emoji-menu-toggle-button btn has-tooltip',
class: 'js-toggle-emoji-menu emoji-menu-toggle-button gl-button btn has-tooltip',
title: s_("Profiles|Add status emoji") do
- if @user.status
= emoji_icon @user.status.emoji
@ -56,7 +56,7 @@
= sprite_icon('smile', css_class: 'award-control-icon-super-positive')
- reset_message_button = button_tag type: :button,
id: 'js-clear-user-status-button',
class: 'clear-user-status btn has-tooltip',
class: 'clear-user-status gl-button btn has-tooltip',
title: s_("Profiles|Clear status") do
= sprite_icon("close")
@ -78,7 +78,7 @@
-# TODO: might need an entry in user/profile.md to describe some of these settings
-# https://gitlab.com/gitlab-org/gitlab-foss/issues/60070
%h5= ("Time zone")
= dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown input-lg', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
= dropdown_tag(_("Select a timezone"), options: { toggle_class: 'gl-button btn js-timezone-dropdown input-lg', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
%input.hidden{ :type => 'hidden', :id => 'user_timezone', :name => 'user[timezone]', value: @user.timezone }
%hr
@ -119,8 +119,8 @@
.help-block
= s_("Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information")
.gl-mt-3.gl-mb-3
= f.submit s_("Profiles|Update profile settings"), class: 'btn btn-success'
= link_to _("Cancel"), user_path(current_user), class: 'btn btn-cancel'
= f.submit s_("Profiles|Update profile settings"), class: 'gl-button btn btn-success'
= link_to _("Cancel"), user_path(current_user), class: 'gl-button btn btn-cancel'
.modal.modal-profile-crop{ data: { cropper_css_path: ActionController::Base.helpers.stylesheet_path('lazy_bundles/cropper.css') } }
.modal-dialog

View file

@ -9,5 +9,5 @@
%span.monospace{ data: { qa_selector: 'code_content' } }= code
.d-flex
= link_to _('Proceed'), profile_account_path, class: 'btn btn-success gl-mr-3', data: { qa_selector: 'proceed_button' }
= link_to _('Download codes'), "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'btn btn-default'
= link_to _('Proceed'), profile_account_path, class: 'gl-button btn btn-success gl-mr-3', data: { qa_selector: 'proceed_button' }
= link_to _('Download codes'), "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'gl-button btn btn-default'

View file

@ -20,7 +20,7 @@
= link_to _('Disable two-factor authentication'), profile_two_factor_auth_path,
method: :delete,
data: { confirm: webauthn_enabled ? _('Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices.') : _('Are you sure? This will invalidate your registered applications and U2F devices.') },
class: 'btn btn-danger gl-mr-3'
class: 'gl-button btn btn-danger gl-mr-3'
= form_tag codes_profile_two_factor_auth_path, {style: 'display: inline-block', method: :post} do |f|
= submit_tag _('Regenerate recovery codes'), class: 'btn'
@ -52,7 +52,7 @@
= label_tag :pin_code, _('Pin code'), class: "label-bold"
= text_field_tag :pin_code, nil, class: "form-control", required: true, data: { qa_selector: 'pin_code_field' }
.gl-mt-3
= submit_tag _('Register with two-factor app'), class: 'btn btn-success', data: { qa_selector: 'register_2fa_app_button' }
= submit_tag _('Register with two-factor app'), class: 'gl-button btn btn-success', data: { qa_selector: 'register_2fa_app_button' }
%hr
@ -109,7 +109,7 @@
%span.gl-text-gray-500
= _("no name set")
%td= registration[:created_at].to_date.to_s(:medium)
%td= link_to _('Delete'), registration[:delete_path], method: :delete, class: "btn btn-danger float-right", data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.') }
%td= link_to _('Delete'), registration[:delete_path], method: :delete, class: "gl-button btn btn-danger float-right", data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.') }
- else
.settings-message.text-center

View file

@ -22,4 +22,4 @@
- if partial_exists? "registrations/welcome/button"
= render "registrations/welcome/button"
- else
= f.submit _('Get started!'), class: 'btn-register btn btn-block gl-mb-0 gl-p-3', data: { qa_selector: 'get_started_button' }
= f.submit _('Get started!'), class: 'btn-register gl-button btn btn-block gl-mb-0 gl-p-3', data: { qa_selector: 'get_started_button' }

View file

@ -0,0 +1,5 @@
---
title: Add Middleman Logo for Project Templates
merge_request: 44617
author:
type: added

View file

@ -0,0 +1,5 @@
---
title: Allow automatically selecting repository storage on move
merge_request: 45338
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: Update Cycle Analytics with Value Stream Analytics in University
merge_request: 44244
author: Takuya Noguchi
type: other

View file

@ -0,0 +1,5 @@
---
title: Include PostgreSQL system identifier in usage ping
merge_request: 44972
author:
type: added

View file

@ -1,7 +0,0 @@
---
name: ci_new_artifact_file_reader
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40268
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249588
group: group::pipeline authoring
type: development
default_enabled: true

View file

@ -194,7 +194,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `project_id` | integer | yes | ID of the project |
| `destination_storage_name` | string | yes | Name of the destination storage shard |
| `destination_storage_name` | string | no | Name of the destination storage shard. If not provided the storage will be selected automatically. |
Example request:

View file

@ -130,7 +130,7 @@ become available, you will be able to share job templates like this
Dependencies should be kept to the minimum. The introduction of a new
dependency should be argued in the merge request, as per our [Approval
Guidelines](../code_review.md#approval-guidelines). Both [License
Management](../../user/compliance/license_compliance/index.md)
Scanning](../../user/compliance/license_compliance/index.md)
**(ULTIMATE)** and [Dependency
Scanning](../../user/application_security/dependency_scanning/index.md)
**(ULTIMATE)** should be activated on all projects to ensure new dependencies

View file

@ -750,7 +750,8 @@ The following is example content of the Usage Ping payload.
},
"database": {
"adapter": "postgresql",
"version": "9.6.15"
"version": "9.6.15",
"pg_system_id": 6842684531675334351
},
"avg_cycle_analytics": {
"issue": {
@ -910,6 +911,10 @@ The following is example content of the Usage Ping payload.
}
```
## Notable changes
In GitLab 13.5, `pg_system_id` was added to send the [PostgreSQL system identifier](https://www.2ndquadrant.com/en/blog/support-for-postgresqls-system-identifier-in-barman/).
## Exporting Usage Ping SQL queries and definitions
Two Rake tasks exist to export Usage Ping definitions.

View file

@ -1,3 +1,10 @@
---
stage: Create
group: Source Code
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers"
type: reference, how-to
---
# Kerberos integration **(STARTER ONLY)**
GitLab can integrate with [Kerberos](https://web.mit.edu/kerberos/) as an authentication mechanism.
@ -157,6 +164,13 @@ GitLab users with a linked Kerberos account can also `git pull` and `git push`
using Kerberos tokens, i.e., without having to send their password with each
operation.
DANGER: **Danger:**
There is a [known issue](https://github.com/curl/curl/issues/1261) with `libcurl`
older than version 7.64.1 wherein it won't reuse connections when negotiating.
This leads to authorization issues when push is larger than `http.postBuffer`
config. Ensure that Git is using at least `libcurl` 7.64.1 to avoid this. To
know the `libcurl` version installed, run `curl-config --version`.
### HTTP Git access with Kerberos token (passwordless authentication)
#### Support for Git before 2.4

View file

@ -175,10 +175,10 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
1. [High Availability - Video](https://www.youtube.com/watch?v=36KS808u6bE&index=15&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e)
1. [High Availability Documentation](https://about.gitlab.com/solutions/reference-architectures/)
### 3.8 Cycle Analytics
### 3.8 Value Stream Analytics
1. [GitLab Cycle Analytics Overview](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/)
1. [GitLab Cycle Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/)
1. [GitLab Value Stream Analytics Overview (as of 2016)](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/)
1. [GitLab Value Stream Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/)
### 3.9. Integrations

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -5,7 +5,7 @@ info: "To determine the technical writer assigned to the Stage/Group associated
type: reference, how-to
---
# Wiki
# Wiki **(CORE)**
A separate system for documentation called Wiki, is built right into each
GitLab project. It is enabled by default on all new projects and you can find
@ -130,10 +130,12 @@ be preceded by the slash (`/`) character.
## Viewing a list of all created wiki pages
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17673/) in GitLab 13.5, wiki pages are displayed as a nested tree in the sidebar and pages overview.
Every wiki has a sidebar from which a short list of the created pages can be
found. The list is ordered alphabetically.
![Wiki sidebar](img/wiki_sidebar.png)
![Wiki sidebar](img/wiki_sidebar_v13_5.png)
If you have many pages, not all will be listed in the sidebar. Click on
**View All Pages** to see all of them.

View file

@ -69,7 +69,7 @@ module API
success Entities::ProjectRepositoryStorageMove
end
params do
requires :destination_storage_name, type: String, desc: 'The destination storage shard'
optional :destination_storage_name, type: String, desc: 'The destination storage shard'
end
post ':id/repository_storage_moves' do
storage_move = user_project.repository_storage_moves.build(

View file

@ -45,14 +45,6 @@ module Gitlab
end
def read_zip_file!(file_path)
if ::Gitlab::Ci::Features.new_artifact_file_reader_enabled?(job.project)
read_with_new_artifact_file_reader(file_path)
else
read_with_legacy_artifact_file_reader(file_path)
end
end
def read_with_new_artifact_file_reader(file_path)
job.artifacts_file.use_open_file do |file|
zip_file = Zip::File.new(file, false, true)
entry = zip_file.find_entry(file_path)
@ -69,25 +61,6 @@ module Gitlab
end
end
def read_with_legacy_artifact_file_reader(file_path)
job.artifacts_file.use_file do |archive_path|
Zip::File.open(archive_path) do |zip_file|
entry = zip_file.find_entry(file_path)
unless entry
raise Error, "Path `#{file_path}` does not exist inside the `#{job.name}` artifacts archive!"
end
if entry.name_is_directory?
raise Error, "Path `#{file_path}` was expected to be a file but it was a directory!"
end
zip_file.get_input_stream(entry) do |is|
is.read
end
end
end
end
def max_archive_size_in_mb
ActiveSupport::NumberHelper.number_to_human_size(MAX_ARCHIVE_SIZE)
end

View file

@ -59,10 +59,6 @@ module Gitlab
::Feature.enabled?(:ci_trace_log_invalid_chunks, project, type: :ops, default_enabled: false)
end
def self.new_artifact_file_reader_enabled?(project)
::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: true)
end
def self.one_dimensional_matrix_enabled?
::Feature.enabled?(:one_dimensional_matrix, default_enabled: true)
end

View file

@ -33,6 +33,10 @@ module Gitlab
self.class.trace_bytes.increment({}, size.to_i)
end
def observe_migration_duration(seconds)
self.class.finalize_histogram.observe({}, seconds.to_f)
end
def self.trace_operations
strong_memoize(:trace_operations) do
name = :gitlab_ci_trace_operations_total
@ -50,6 +54,17 @@ module Gitlab
Gitlab::Metrics.counter(name, comment)
end
end
def self.finalize_histogram
strong_memoize(:finalize_histogram) do
name = :gitlab_ci_trace_finalize_duration_seconds
comment = 'Duration of build trace chunks migration to object storage'
buckets = [0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 10.0, 30.0, 60.0, 300.0]
labels = {}
::Gitlab::Metrics.histogram(name, comment, labels, buckets)
end
end
end
end
end

View file

@ -250,6 +250,12 @@ module Gitlab
false
end
def self.system_id
row = connection.execute('SELECT system_identifier FROM pg_control_system()').first
row['system_identifier']
end
def self.get_write_location(ar_connection)
row = ar_connection
.select_all("SELECT pg_current_wal_insert_lsn()::text AS location")

View file

@ -53,7 +53,7 @@ module Gitlab
ProjectTemplate.new('plainhtml', 'Pages/Plain HTML', _('Everything you need to create a GitLab Pages site using plain HTML.'), 'https://gitlab.com/pages/plain-html'),
ProjectTemplate.new('gitbook', 'Pages/GitBook', _('Everything you need to create a GitLab Pages site using GitBook.'), 'https://gitlab.com/pages/gitbook', 'illustrations/logos/gitbook.svg'),
ProjectTemplate.new('hexo', 'Pages/Hexo', _('Everything you need to create a GitLab Pages site using Hexo.'), 'https://gitlab.com/pages/hexo', 'illustrations/logos/hexo.svg'),
ProjectTemplate.new('sse_middleman', 'Static Site Editor/Middleman', _('Middleman project with Static Site Editor support'), 'https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman'),
ProjectTemplate.new('sse_middleman', 'Static Site Editor/Middleman', _('Middleman project with Static Site Editor support'), 'https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman', 'illustrations/logos/middleman.svg'),
ProjectTemplate.new('gitpod_spring_petclinic', 'Gitpod/Spring Petclinic', _('A Gitpod configured Webapplication in Spring and Java'), 'https://gitlab.com/gitlab-org/project-templates/gitpod-spring-petclinic', 'illustrations/logos/gitpod.svg'),
ProjectTemplate.new('nfhugo', 'Netlify/Hugo', _('A Hugo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhugo', 'illustrations/logos/netlify.svg'),
ProjectTemplate.new('nfjekyll', 'Netlify/Jekyll', _('A Jekyll site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfjekyll', 'illustrations/logos/netlify.svg'),

View file

@ -3,14 +3,13 @@
module Gitlab
# Centralized class for repository size related calculations.
class RepositorySizeChecker
attr_reader :limit, :total_repository_size_excess, :additional_purchased_storage
attr_reader :limit
# @param current_size_proc [Proc] returns repository size in bytes
def initialize(current_size_proc:, limit:, total_repository_size_excess:, additional_purchased_storage:, enabled: true)
def initialize(current_size_proc:, limit:, namespace:, enabled: true)
@current_size_proc = current_size_proc
@limit = limit
@total_repository_size_excess = total_repository_size_excess.to_i
@additional_purchased_storage = additional_purchased_storage.to_i
@namespace = namespace
@enabled = enabled && limit != 0
end
@ -44,6 +43,10 @@ module Gitlab
def error_message
@error_message_object ||= ::Gitlab::RepositorySizeErrorMessage.new(self)
end
private
attr_reader :namespace
end
end

View file

@ -4,7 +4,7 @@ module Gitlab
class RepositorySizeErrorMessage
include ActiveSupport::NumberHelper
delegate :current_size, :limit, :total_repository_size_excess, :additional_purchased_storage, :exceeded_size, to: :@checker
delegate :current_size, :limit, :exceeded_size, to: :@checker
# @param checher [RepositorySizeChecker]
def initialize(checker)

View file

@ -303,7 +303,8 @@ module Gitlab
},
database: {
adapter: alt_usage_data { Gitlab::Database.adapter_name },
version: alt_usage_data { Gitlab::Database.version }
version: alt_usage_data { Gitlab::Database.version },
pg_system_id: alt_usage_data { Gitlab::Database.system_id }
},
mail: {
smtp_server: alt_usage_data { ActionMailer::Base.smtp_settings[:address] }

View file

@ -6,6 +6,10 @@ module RuboCop
module Cop
module Migration
# Cop that enforces always adding a limit on text columns
#
# Text columns starting with `encrypted_` are very likely used
# by `attr_encrypted` which controls the text length. Those columns
# should not add a text limit.
class AddLimitToTextColumns < RuboCop::Cop::Cop
include MigrationHelpers
@ -102,6 +106,8 @@ module RuboCop
# Check if there is an `add_text_limit` call for the provided
# table and attribute name
def text_limit_missing?(node, table_name, attribute_name)
return false if encrypted_attribute_name?(attribute_name)
limit_found = false
node.each_descendant(:send) do |send_node|
@ -118,6 +124,10 @@ module RuboCop
!limit_found
end
def encrypted_attribute_name?(attribute_name)
attribute_name.to_s.start_with?('encrypted_')
end
end
end
end

View file

@ -0,0 +1,109 @@
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
module FactoryBot
# This cop encourages the use of inline associations in FactoryBot.
# The explicit use of `create` and `build` is discouraged.
#
# See https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#inline-definition
#
# @example
#
# Context:
#
# Factory.define do
# factory :project, class: 'Project'
# # EXAMPLE below
# end
# end
#
# # bad
# creator { create(:user) }
# creator { create(:user, :admin) }
# creator { build(:user) }
# creator { FactoryBot.build(:user) }
# creator { ::FactoryBot.build(:user) }
# add_attribute(:creator) { build(:user) }
#
# # good
# creator { association(:user) }
# creator { association(:user, :admin) }
# add_attribute(:creator) { association(:user) }
#
# # Accepted
# after(:build) do |instance|
# instance.creator = create(:user)
# end
#
# initialize_with do
# create(:project)
# end
#
# creator_id { create(:user).id }
#
class InlineAssociation < RuboCop::Cop::Cop
MSG = 'Prefer inline `association` over `%{type}`. ' \
'See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories'
REPLACEMENT = 'association'
def_node_matcher :create_or_build, <<~PATTERN
(
send
${ nil? (const { nil? (cbase) } :FactoryBot) }
${ :create :build }
(sym _)
...
)
PATTERN
def_node_matcher :association_definition, <<~PATTERN
(block
{
(send nil? $_)
(send nil? :add_attribute (sym $_))
}
...
)
PATTERN
def_node_matcher :chained_call?, <<~PATTERN
(send _ _)
PATTERN
SKIP_NAMES = %i[initialize_with].to_set.freeze
def on_send(node)
_receiver, type = create_or_build(node)
return unless type
return if chained_call?(node.parent)
return unless inside_assocation_definition?(node)
add_offense(node, message: format(MSG, type: type))
end
def autocorrect(node)
lambda do |corrector|
receiver, type = create_or_build(node)
receiver = "#{receiver.source}." if receiver
expression = "#{receiver}#{type}"
replacement = node.source.sub(expression, REPLACEMENT)
corrector.replace(node.source_range, replacement)
end
end
private
def inside_assocation_definition?(node)
node.each_ancestor(:block).any? do |parent|
name = association_definition(parent)
name && !SKIP_NAMES.include?(name)
end
end
end
end
end
end
end

View file

@ -5,7 +5,6 @@ FactoryBot.define do
project
source_storage_name { 'default' }
destination_storage_name { 'default' }
trait :scheduled do
state { ProjectRepositoryStorageMove.state_machines[:state].states[:scheduled].value }

View file

@ -13,7 +13,7 @@ import actions, { gqlClient } from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import { inactiveId, ListType } from '~/boards/constants';
import issueMoveListMutation from '~/boards/queries/issue_move_list.mutation.graphql';
import { fullBoardId, formatListIssues } from '~/boards/boards_util';
import { fullBoardId, formatListIssues, formatBoardLists } from '~/boards/boards_util';
const expectNotImplemented = action => {
it('is not implemented', () => {
@ -78,6 +78,80 @@ describe('setActiveId', () => {
});
});
describe('fetchLists', () => {
const state = {
endpoints: {
fullPath: 'gitlab-org',
boardId: 1,
},
filterParams: {},
boardType: 'group',
};
let queryResponse = {
data: {
group: {
board: {
hideBacklogList: true,
lists: {
nodes: [mockLists[1]],
},
},
},
},
};
const formattedLists = formatBoardLists(queryResponse.data.group.board.lists);
it('should commit mutations RECEIVE_BOARD_LISTS_SUCCESS on success', done => {
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
actions.fetchLists,
{},
state,
[
{
type: types.RECEIVE_BOARD_LISTS_SUCCESS,
payload: formattedLists,
},
],
[{ type: 'showWelcomeList' }],
done,
);
});
it('dispatch createList action when backlog list does not exist and is not hidden', done => {
queryResponse = {
data: {
group: {
board: {
hideBacklogList: false,
lists: {
nodes: [mockLists[1]],
},
},
},
},
};
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
testAction(
actions.fetchLists,
{},
state,
[
{
type: types.RECEIVE_BOARD_LISTS_SUCCESS,
payload: formattedLists,
},
],
[{ type: 'createList', payload: { backlog: true } }, { type: 'showWelcomeList' }],
done,
);
});
});
describe('showWelcomeList', () => {
it('should dispatch addList action', done => {
const state = {

View file

@ -18,17 +18,6 @@ RSpec.describe Gitlab::Ci::ArtifactFileReader do
expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
end
context 'when FF ci_new_artifact_file_reader is disabled' do
before do
stub_feature_flags(ci_new_artifact_file_reader: false)
end
it 'returns the content at the path' do
is_expected.to be_present
expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
end
end
context 'when path does not exist' do
let(:path) { 'file/does/not/exist.txt' }
let(:expected_error) do

View file

@ -39,6 +39,12 @@ RSpec.describe Gitlab::Database do
end
end
describe '.system_id' do
it 'returns the PostgreSQL system identifier' do
expect(described_class.system_id).to be_an_instance_of(Integer)
end
end
describe '.postgresql?' do
subject { described_class.postgresql? }

View file

@ -3,16 +3,16 @@
require 'spec_helper'
RSpec.describe Gitlab::RepositorySizeChecker do
let_it_be(:namespace) { nil }
let(:current_size) { 0 }
let(:limit) { 50 }
let(:enabled) { true }
subject do
described_class.new(
current_size_proc: -> { current_size },
limit: limit,
total_repository_size_excess: 0,
additional_purchased_storage: 0,
current_size_proc: -> { current_size.megabytes },
limit: limit.megabytes,
namespace: namespace,
enabled: enabled
)
end
@ -20,7 +20,7 @@ RSpec.describe Gitlab::RepositorySizeChecker do
describe '#enabled?' do
context 'when enabled' do
it 'returns true' do
expect(subject.enabled?).to be_truthy
expect(subject.enabled?).to eq(true)
end
end
@ -28,7 +28,7 @@ RSpec.describe Gitlab::RepositorySizeChecker do
let(:limit) { 0 }
it 'returns false' do
expect(subject.enabled?).to be_falsey
expect(subject.enabled?).to eq(false)
end
end
end
@ -37,11 +37,11 @@ RSpec.describe Gitlab::RepositorySizeChecker do
let(:current_size) { 49 }
it 'returns true when changes go over' do
expect(subject.changes_will_exceed_size_limit?(2)).to be_truthy
expect(subject.changes_will_exceed_size_limit?(2.megabytes)).to eq(true)
end
it 'returns false when changes do not go over' do
expect(subject.changes_will_exceed_size_limit?(1)).to be_falsey
expect(subject.changes_will_exceed_size_limit?(1.megabytes)).to eq(false)
end
end

View file

@ -3,11 +3,11 @@
require 'spec_helper'
RSpec.describe Gitlab::RepositorySizeErrorMessage do
let_it_be(:namespace) { build(:namespace) }
let(:checker) do
Gitlab::RepositorySizeChecker.new(
current_size_proc: -> { 15.megabytes },
total_repository_size_excess: 0,
additional_purchased_storage: 0,
namespace: namespace,
limit: 10.megabytes
)
end
@ -15,6 +15,10 @@ RSpec.describe Gitlab::RepositorySizeErrorMessage do
let(:message) { checker.error_message }
let(:base_message) { 'because this repository has exceeded its size limit of 10 MB by 5 MB' }
before do
allow(namespace).to receive(:total_repository_size_excess).and_return(0)
end
describe 'error messages' do
describe '#commit_error' do
it 'returns the correct message' do

View file

@ -723,6 +723,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:git][:version]).to eq(Gitlab::Git.version)
expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name)
expect(subject[:database][:version]).to eq(Gitlab::Database.version)
expect(subject[:database][:pg_system_id]).to eq(Gitlab::Database.system_id)
expect(subject[:mail][:smtp_server]).to eq(ActionMailer::Base.smtp_settings[:address])
expect(subject[:gitaly][:version]).to be_present
expect(subject[:gitaly][:servers]).to be >= 1

View file

@ -43,6 +43,18 @@ RSpec.describe ProjectRepositoryStorageMove, type: :model do
end
end
describe 'defaults' do
context 'destination_storage_name' do
subject { build(:project_repository_storage_move) }
it 'picks storage from ApplicationSetting' do
expect(Gitlab::CurrentSettings).to receive(:pick_repository_storage).and_return('picked').at_least(:once)
expect(subject.destination_storage_name).to eq('picked')
end
end
end
describe 'state transitions' do
let(:project) { create(:project) }

View file

@ -666,8 +666,7 @@ RSpec.describe Snippet do
let(:checker) { subject.repository_size_checker }
let(:current_size) { 60 }
let(:total_repository_size_excess) { 0 }
let(:additional_purchased_storage) { 0 }
let(:namespace) { nil }
before do
allow(subject.repository).to receive(:size).and_return(current_size)

View file

@ -145,10 +145,17 @@ RSpec.describe API::ProjectRepositoryStorageMoves do
context 'destination_storage_name is missing' do
let(:destination_storage_name) { nil }
it 'returns a validation error' do
it 'schedules a project repository storage move' do
create_project_repository_storage_move
expect(response).to have_gitlab_http_status(:bad_request)
storage_move = project.repository_storage_moves.last
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/project_repository_storage_move')
expect(json_response['id']).to eq(storage_move.id)
expect(json_response['state']).to eq('scheduled')
expect(json_response['source_storage_name']).to eq('default')
expect(json_response['destination_storage_name']).to be_present
end
end
end

View file

@ -129,6 +129,28 @@ RSpec.describe RuboCop::Cop::Migration::AddLimitToTextColumns, type: :rubocop do
end
end
context 'when text columns are used for encryption' do
it 'registers no offenses' do
expect_no_offenses(<<~RUBY)
class TestTextLimits < ActiveRecord::Migration[6.0]
DOWNTIME = false
disable_ddl_transaction!
def up
create_table :test_text_limits, id: false do |t|
t.integer :test_id, null: false
t.text :encrypted_name
end
add_column :encrypted_test_text_limits, :encrypted_email, :text
add_column_with_default :encrypted_test_text_limits, :encrypted_role, :text, default: 'default'
change_column_type_concurrently :encrypted_test_text_limits, :encrypted_test_id, :text
end
end
RUBY
end
end
context 'on down' do
it 'registers no offense' do
expect_no_offenses(<<~RUBY)

View file

@ -0,0 +1,132 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rspec-parameterized'
require 'rubocop'
require_relative '../../../../../rubocop/cop/rspec/factory_bot/inline_association'
RSpec.describe RuboCop::Cop::RSpec::FactoryBot::InlineAssociation, type: :rubocop do
include CopHelper
subject(:cop) { described_class.new }
shared_examples 'offense' do |code_snippet, autocorrected|
# We allow `create` or `FactoryBot.create` or `::FactoryBot.create`
let(:type) { code_snippet[/^(?:::)?(?:FactoryBot\.)?(\w+)/, 1] }
let(:offense_marker) { '^' * code_snippet.size }
let(:offense_msg) { msg(type) }
let(:offense) { "#{offense_marker} #{offense_msg}" }
let(:pristine_source) { source.sub(offense, '') }
let(:source) do
<<~RUBY
FactoryBot.define do
factory :project do
attribute { #{code_snippet} }
#{offense}
end
end
RUBY
end
it 'registers an offense' do
expect_offense(source)
end
it 'autocorrects the source' do
corrected = autocorrect_source(pristine_source)
expect(corrected).not_to include(code_snippet)
expect(corrected).to include(autocorrected)
end
end
shared_examples 'no offense' do |code_snippet|
first_line = code_snippet.lines.first.chomp
context "for `#{first_line}`" do
it 'does not register any offenses' do
expect_no_offenses <<~RUBY
FactoryBot.define do
factory :project do
#{code_snippet}
end
end
RUBY
end
end
end
context 'offenses' do
using RSpec::Parameterized::TableSyntax
where(:code_snippet, :autocorrected) do
# create
'create(:user)' | 'association(:user)'
'FactoryBot.create(:user)' | 'association(:user)'
'::FactoryBot.create(:user)' | 'association(:user)'
'create(:user, :admin)' | 'association(:user, :admin)'
'create(:user, name: "any")' | 'association(:user, name: "any")'
# build
'build(:user)' | 'association(:user)'
'FactoryBot.build(:user)' | 'association(:user)'
'::FactoryBot.build(:user)' | 'association(:user)'
'build(:user, :admin)' | 'association(:user, :admin)'
'build(:user, name: "any")' | 'association(:user, name: "any")'
end
with_them do
include_examples 'offense', params[:code_snippet], params[:autocorrected]
end
it 'recognizes `add_attribute`' do
expect_offense <<~RUBY
FactoryBot.define do
factory :project, class: 'Project' do
add_attribute(:method) { create(:user) }
^^^^^^^^^^^^^ #{msg(:create)}
end
end
RUBY
end
it 'recognizes `transient` attributes' do
expect_offense <<~RUBY
FactoryBot.define do
factory :project, class: 'Project' do
transient do
creator { create(:user) }
^^^^^^^^^^^^^ #{msg(:create)}
end
end
end
RUBY
end
end
context 'no offenses' do
include_examples 'no offense', 'association(:user)'
include_examples 'no offense', 'association(:user, :admin)'
include_examples 'no offense', 'association(:user, name: "any")'
include_examples 'no offense', <<~RUBY
after(:build) do |object|
object.user = create(:user)
end
RUBY
include_examples 'no offense', <<~RUBY
initialize_with do
create(:user)
end
RUBY
include_examples 'no offense', <<~RUBY
user_id { create(:user).id }
RUBY
end
def msg(type)
format(described_class::MSG, type: type)
end
end

View file

@ -131,6 +131,18 @@ RSpec.describe Ci::UpdateBuildStateService do
.with(operation: :finalized)
end
it 'records migration duration in a histogram' do
freeze_time do
create(:ci_build_pending_state, build: build, created_at: 0.5.seconds.ago)
execute_with_stubbed_metrics!
end
expect(metrics)
.to have_received(:observe_migration_duration)
.with(0.5)
end
context 'when trace checksum is not valid' do
it 'increments invalid trace metric' do
execute_with_stubbed_metrics!

View file

@ -29,7 +29,7 @@ RSpec.shared_examples 'checker size exceeded' do
let(:current_size) { 51 }
it 'returns zero' do
expect(subject.exceeded_size).to eq(1)
expect(subject.exceeded_size).to eq(1.megabytes)
end
end
@ -37,7 +37,7 @@ RSpec.shared_examples 'checker size exceeded' do
let(:current_size) { 50 }
it 'returns zero' do
expect(subject.exceeded_size(1)).to eq(1)
expect(subject.exceeded_size(1.megabytes)).to eq(1.megabytes)
end
end
@ -45,7 +45,7 @@ RSpec.shared_examples 'checker size exceeded' do
let(:current_size) { 49 }
it 'returns zero' do
expect(subject.exceeded_size(1)).to eq(0)
expect(subject.exceeded_size(1.megabytes)).to eq(0)
end
end
end

View file

@ -4,8 +4,7 @@ RSpec.shared_examples 'size checker for snippet' do |action|
it 'sets up size checker', :aggregate_failures do
expect(checker.current_size).to eq(current_size.megabytes)
expect(checker.limit).to eq(Gitlab::CurrentSettings.snippet_size_limit)
expect(checker.total_repository_size_excess).to eq(total_repository_size_excess)
expect(checker.additional_purchased_storage).to eq(additional_purchased_storage)
expect(checker.enabled?).to eq(true)
expect(checker.instance_variable_get(:@namespace)).to eq(namespace)
end
end