Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d2675fa4de
commit
f8b0e661f8
|
@ -52,7 +52,6 @@ qa:nightly-auto-quarantine-dequarantine:
|
|||
- bundle exec confiner -r .confiner/nightly.yml
|
||||
allow_failure: true
|
||||
|
||||
|
||||
qa:selectors-as-if-foss:
|
||||
extends:
|
||||
- qa:selectors
|
||||
|
@ -68,6 +67,30 @@ update-qa-cache:
|
|||
script:
|
||||
- echo "Cache has been updated and ready to be uploaded."
|
||||
|
||||
populate-qa-tests-var:
|
||||
extends:
|
||||
- .qa:rules:package-and-qa
|
||||
image: ${GITLAB_DEPENDENCY_PROXY}ruby:2.7-alpine
|
||||
stage: prepare
|
||||
script:
|
||||
- tooling/bin/qa/check_if_qa_only_spec_changes ${CHANGES_FILE} ${ONLY_QA_CHANGES_FILE}
|
||||
- '[ -f $ONLY_QA_CHANGES_FILE ] && export QA_TESTS="`cat $ONLY_QA_CHANGES_FILE`"'
|
||||
- 'echo "QA_TESTS=$QA_TESTS" >> qa_tests_var.env'
|
||||
- 'echo "QA_TESTS: $QA_TESTS"'
|
||||
artifacts:
|
||||
expire_in: 2d
|
||||
reports:
|
||||
dotenv: qa_tests_var.env
|
||||
paths:
|
||||
- ${CHANGES_FILE}
|
||||
- ${ONLY_QA_CHANGES_FILE}
|
||||
- qa_tests_var.env
|
||||
variables:
|
||||
CHANGES_FILE: tmp/changed_files.txt
|
||||
ONLY_QA_CHANGES_FILE: tmp/qa_only_changed_files.txt
|
||||
needs:
|
||||
- detect-tests
|
||||
|
||||
.package-and-qa-base:
|
||||
image: ${GITLAB_DEPENDENCY_PROXY}ruby:2.7-alpine
|
||||
stage: qa
|
||||
|
@ -77,8 +100,6 @@ update-qa-cache:
|
|||
- install_gitlab_gem
|
||||
- tooling/bin/find_change_diffs ${CHANGES_DIFFS_DIR}
|
||||
script:
|
||||
- tooling/bin/qa/check_if_qa_only_spec_changes ${CHANGES_FILE} ${ONLY_QA_CHANGES_FILE}
|
||||
- '[ -f $ONLY_QA_CHANGES_FILE ] && export QA_TESTS="`cat $ONLY_QA_CHANGES_FILE`"'
|
||||
- 'echo "QA_TESTS: $QA_TESTS"'
|
||||
- exit_code=0 && tooling/bin/qa/package_and_qa_check ${CHANGES_DIFFS_DIR} || exit_code=$?
|
||||
- echo $exit_code
|
||||
|
@ -99,16 +120,13 @@ update-qa-cache:
|
|||
artifacts: false
|
||||
- job: build-assets-image
|
||||
artifacts: false
|
||||
- job: populate-qa-tests-var
|
||||
- detect-tests
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- ${CHANGES_FILE}
|
||||
- ${ONLY_QA_CHANGES_FILE}
|
||||
- ${CHANGES_DIFFS_DIR}/*
|
||||
variables:
|
||||
CHANGES_FILE: tmp/changed_files.txt
|
||||
ONLY_QA_CHANGES_FILE: tmp/qa_only_changed_files.txt
|
||||
CHANGES_DIFFS_DIR: tmp/diffs
|
||||
ALLURE_JOB_NAME: $CI_JOB_NAME
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@ import JobItem from './job_item.vue';
|
|||
export default {
|
||||
i18n: {
|
||||
stage: __('Stage:'),
|
||||
loadingTextLineOne: __('Loading, please wait.'),
|
||||
loadingTextLineTwo: __('Cue dramatic background music...'),
|
||||
loadingText: __('Loading, please wait.'),
|
||||
},
|
||||
dropdownPopperOpts: {
|
||||
placement: 'bottom',
|
||||
|
@ -138,14 +137,11 @@ export default {
|
|||
</template>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="gl-display-flex gl-justify-content-center gl-p-3"
|
||||
class="gl-display-flex gl-justify-content-center gl-p-2"
|
||||
data-testid="pipeline-stage-loading-state"
|
||||
>
|
||||
<gl-loading-icon size="sm" class="gl-mr-3" />
|
||||
<div>
|
||||
<p class="gl-mb-0">{{ $options.i18n.loadingTextLineOne }}</p>
|
||||
<p class="gl-mb-0">{{ $options.i18n.loadingTextLineTwo }}</p>
|
||||
</div>
|
||||
<p class="gl-mb-0">{{ $options.i18n.loadingText }}</p>
|
||||
</div>
|
||||
<ul
|
||||
v-else
|
||||
|
|
|
@ -104,7 +104,7 @@ export default {
|
|||
@selectRevision="onSelectRevision"
|
||||
/>
|
||||
<div
|
||||
class="compare-ellipsis gl-display-flex gl-justify-content-center gl-align-items-center gl-my-4 gl-md-my-0"
|
||||
class="compare-ellipsis gl-display-flex gl-justify-content-center gl-align-items-center gl-align-self-end gl-my-4 gl-md-my-0"
|
||||
data-testid="ellipsis"
|
||||
>
|
||||
...
|
||||
|
@ -121,7 +121,7 @@ export default {
|
|||
@selectRevision="onSelectRevision"
|
||||
/>
|
||||
</div>
|
||||
<div class="gl-mt-4">
|
||||
<div class="gl-mt-6">
|
||||
<gl-button category="primary" variant="confirm" @click="onSubmit">
|
||||
{{ s__('CompareRevisions|Compare') }}
|
||||
</gl-button>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import { GlCard } from '@gitlab/ui';
|
||||
import RepoDropdown from './repo_dropdown.vue';
|
||||
import RevisionDropdown from './revision_dropdown.vue';
|
||||
|
||||
|
@ -7,7 +6,6 @@ export default {
|
|||
components: {
|
||||
RepoDropdown,
|
||||
RevisionDropdown,
|
||||
GlCard,
|
||||
},
|
||||
props: {
|
||||
refsProjectPath: {
|
||||
|
@ -41,10 +39,10 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-card header-class="gl-py-2 gl-px-3 gl-font-weight-bold" body-class="gl-px-3">
|
||||
<template #header>
|
||||
<div class="revision-card gl-flex-basis-half">
|
||||
<h2 class="gl-font-size-h2">
|
||||
{{ s__(`CompareRevisions|${revisionText}`) }}
|
||||
</template>
|
||||
</h2>
|
||||
<div class="gl-sm-display-flex gl-align-items-center">
|
||||
<repo-dropdown
|
||||
class="gl-sm-w-half"
|
||||
|
@ -61,5 +59,5 @@ export default {
|
|||
v-on="$listeners"
|
||||
/>
|
||||
</div>
|
||||
</gl-card>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<script>
|
||||
import {
|
||||
GlFormGroup,
|
||||
GlDropdown,
|
||||
GlDropdownForm,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
} from '@gitlab/ui';
|
||||
import { GlDropdown, GlDropdownForm, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
|
||||
import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
|
||||
|
@ -17,10 +11,8 @@ export default {
|
|||
showInstallationInstructions: s__(
|
||||
'Runners|Show runner installation and registration instructions',
|
||||
),
|
||||
registrationToken: s__('Runners|Registration token'),
|
||||
},
|
||||
components: {
|
||||
GlFormGroup,
|
||||
GlDropdown,
|
||||
GlDropdownForm,
|
||||
GlDropdownItem,
|
||||
|
@ -92,9 +84,7 @@ export default {
|
|||
</gl-dropdown-item>
|
||||
<gl-dropdown-divider />
|
||||
<gl-dropdown-form class="gl-p-4!">
|
||||
<gl-form-group class="gl-mb-0" :label="$options.i18n.registrationToken">
|
||||
<registration-token :value="currentRegistrationToken" />
|
||||
</gl-form-group>
|
||||
<registration-token input-id="token-value" :value="currentRegistrationToken" />
|
||||
</gl-dropdown-form>
|
||||
<gl-dropdown-divider />
|
||||
<registration-token-reset-dropdown-item :type="type" @tokenReset="onTokenReset" />
|
||||
|
|
|
@ -6,7 +6,14 @@ export default {
|
|||
components: {
|
||||
InputCopyToggleVisibility,
|
||||
},
|
||||
i18n: {
|
||||
registrationToken: s__('Runners|Registration token'),
|
||||
},
|
||||
props: {
|
||||
inputId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -16,7 +23,7 @@ export default {
|
|||
computed: {
|
||||
formInputGroupProps() {
|
||||
return {
|
||||
name: 'token-value',
|
||||
id: this.inputId,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -33,6 +40,8 @@ export default {
|
|||
<input-copy-toggle-visibility
|
||||
class="gl-m-0"
|
||||
:value="value"
|
||||
:label="$options.i18n.registrationToken"
|
||||
:label-for="inputId"
|
||||
:copy-button-title="$options.I18N_COPY_BUTTON_TITLE"
|
||||
:form-input-group-props="formInputGroupProps"
|
||||
@copy="onCopy"
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
import { GlButton, GlTable } from '@gitlab/ui';
|
||||
import { __, s__ } from '~/locale';
|
||||
|
||||
const defaultTableClasses = {
|
||||
thClass: 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1!',
|
||||
};
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
emptyText: s__('CI/CD|No projects have been added to the scope'),
|
||||
|
@ -15,14 +11,12 @@ export default {
|
|||
key: 'project',
|
||||
label: __('Projects that can be accessed'),
|
||||
tdClass: 'gl-p-5!',
|
||||
...defaultTableClasses,
|
||||
columnClass: 'gl-w-85p',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
tdClass: 'gl-p-5! gl-text-right',
|
||||
...defaultTableClasses,
|
||||
columnClass: 'gl-w-15p',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
= content_tag tag, {**@button_options, **base_attributes, class: button_class, href: @href, target: @target } do
|
||||
- if @loading
|
||||
= gl_loading_icon(inline: true, css_class: 'gl-button-icon gl-button-loading-indicator')
|
||||
- if @icon && (!@loading || content)
|
||||
= sprite_icon(@icon, css_class: "gl-icon gl-button-icon #{@icon_classes}")
|
||||
- if content
|
||||
%span.gl-button-text{ class: @button_text_classes }
|
||||
= content
|
|
@ -0,0 +1,114 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Pajamas
|
||||
class ButtonComponent < Pajamas::Component
|
||||
# @param [Symbol] category
|
||||
# @param [Symbol] variant
|
||||
# @param [Symbol] size
|
||||
# @param [Boolean] disabled
|
||||
# @param [Boolean] loading
|
||||
# @param [Boolean] block
|
||||
# @param [Boolean] selected
|
||||
# @param [String] icon
|
||||
# @param [String] href
|
||||
# @param [String] target
|
||||
# @param [Hash] button_options
|
||||
# @param [String] button_text_classes
|
||||
# @param [String] icon_classes
|
||||
def initialize(
|
||||
category: :primary,
|
||||
variant: :default,
|
||||
size: :medium,
|
||||
disabled: false,
|
||||
loading: false,
|
||||
block: false,
|
||||
selected: false,
|
||||
icon: nil,
|
||||
href: nil,
|
||||
target: nil,
|
||||
button_options: {},
|
||||
button_text_classes: nil,
|
||||
icon_classes: nil
|
||||
)
|
||||
@category = filter_attribute(category.to_sym, CATEGORY_OPTIONS)
|
||||
@variant = filter_attribute(variant.to_sym, VARIANT_OPTIONS)
|
||||
@size = filter_attribute(size.to_sym, SIZE_OPTIONS)
|
||||
@disabled = disabled
|
||||
@loading = loading
|
||||
@block = block
|
||||
@selected = selected
|
||||
@icon = icon
|
||||
@href = href
|
||||
@target = filter_attribute(target, TARGET_OPTIONS)
|
||||
@button_options = button_options
|
||||
@button_text_classes = button_text_classes
|
||||
@icon_classes = icon_classes
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def button_class
|
||||
classes = ['gl-button btn']
|
||||
classes.push('disabled') if @disabled || @loading
|
||||
classes.push('selected') if @selected
|
||||
classes.push('btn-block') if @block
|
||||
classes.push('btn-icon') if @icon && !content
|
||||
|
||||
classes.push(SIZE_CLASSES[@size])
|
||||
|
||||
classes.push(VARIANT_CLASSES[@variant])
|
||||
|
||||
unless NON_CATEGORY_VARIANTS.include?(@variant) || @category == :primary
|
||||
classes.push(VARIANT_CLASSES[@variant] + '-' + CATEGORY_CLASSES[@category])
|
||||
end
|
||||
|
||||
classes.push(@button_options[:class])
|
||||
|
||||
classes.join(' ')
|
||||
end
|
||||
|
||||
CATEGORY_OPTIONS = [:primary, :secondary, :tertiary].freeze
|
||||
VARIANT_OPTIONS = [:default, :confirm, :danger, :dashed, :link, :reset].freeze
|
||||
SIZE_OPTIONS = [:small, :medium].freeze
|
||||
TARGET_OPTIONS = %w[_self _blank _parent _top].freeze
|
||||
|
||||
CATEGORY_CLASSES = {
|
||||
primary: '',
|
||||
secondary: 'secondary',
|
||||
tertiary: 'tertiary'
|
||||
}.freeze
|
||||
|
||||
VARIANT_CLASSES = {
|
||||
default: 'btn-default',
|
||||
confirm: 'btn-confirm',
|
||||
danger: 'btn-danger',
|
||||
dashed: 'btn-dashed',
|
||||
link: 'btn-link',
|
||||
reset: 'btn-gl-reset'
|
||||
}.freeze
|
||||
|
||||
NON_CATEGORY_VARIANTS = [:dashed, :link, :reset].freeze
|
||||
|
||||
SIZE_CLASSES = {
|
||||
small: 'btn-sm',
|
||||
medium: 'btn-md'
|
||||
}.freeze
|
||||
|
||||
delegate :sprite_icon, to: :helpers
|
||||
delegate :gl_loading_icon, to: :helpers
|
||||
|
||||
def tag
|
||||
@href ? 'a' : 'button'
|
||||
end
|
||||
|
||||
def base_attributes
|
||||
attributes = {}
|
||||
|
||||
attributes['disabled'] = '' if @disabled || @loading
|
||||
attributes['aria-disabled'] = true if @disabled || @loading
|
||||
attributes['type'] = 'button' unless @href
|
||||
|
||||
attributes
|
||||
end
|
||||
end
|
||||
end
|
|
@ -90,6 +90,7 @@ class User < ApplicationRecord
|
|||
include ForcedEmailConfirmation
|
||||
|
||||
MINIMUM_INACTIVE_DAYS = 90
|
||||
MINIMUM_DAYS_CREATED = 7
|
||||
|
||||
# Override Devise::Models::Trackable#update_tracked_fields!
|
||||
# to limit database writes to at most once every hour
|
||||
|
@ -479,7 +480,7 @@ class User < ApplicationRecord
|
|||
scope :order_oldest_last_activity, -> { reorder(arel_table[:last_activity_on].asc.nulls_first) }
|
||||
scope :by_id_and_login, ->(id, login) { where(id: id).where('username = LOWER(:login) OR email = LOWER(:login)', login: login) }
|
||||
scope :dormant, -> { with_state(:active).human_or_service_user.where('last_activity_on <= ?', MINIMUM_INACTIVE_DAYS.day.ago.to_date) }
|
||||
scope :with_no_activity, -> { with_state(:active).human_or_service_user.where(last_activity_on: nil) }
|
||||
scope :with_no_activity, -> { with_state(:active).human_or_service_user.where(last_activity_on: nil).where('created_at <= ?', MINIMUM_DAYS_CREATED.day.ago.to_date) }
|
||||
scope :by_provider_and_extern_uid, ->(provider, extern_uid) { joins(:identities).merge(Identity.with_extern_uid(provider, extern_uid)) }
|
||||
scope :by_ids_or_usernames, -> (ids, usernames) { where(username: usernames).or(where(id: ids)) }
|
||||
scope :without_forbidden_states, -> { where.not(state: FORBIDDEN_SEARCH_STATES) }
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Visibility and access controls')
|
||||
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
|
||||
= expanded_by_default? ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Set default and restrict visibility levels. Configure import sources and git access protocol.')
|
||||
|
@ -118,4 +118,4 @@
|
|||
= render 'admin/application_settings/eks'
|
||||
= render 'admin/application_settings/floc'
|
||||
= render_if_exists 'admin/application_settings/add_license'
|
||||
= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth)
|
||||
= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth, current_user)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
%h1.page-title.gl-font-size-h-display
|
||||
= _("Compare Git revisions")
|
||||
.sub-header-block
|
||||
%div
|
||||
- example_branch = capture do
|
||||
%code.ref-name= @project.default_branch_or_main
|
||||
- example_sha = capture do
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
paginate_diffs: true,
|
||||
paginate_diffs_per_page: Projects::CompareController::COMMIT_DIFFS_PER_PAGE
|
||||
- else
|
||||
.card.bg-light
|
||||
.card.gl-bg-gray-50.gl-border-none.gl-p-2
|
||||
.center
|
||||
%h4
|
||||
= s_("CompareBranches|There isn't anything to compare.")
|
||||
|
|
|
@ -13,8 +13,11 @@
|
|||
- else
|
||||
= yield
|
||||
- if dismissable && !preview
|
||||
%button.btn.gl-close-btn-color-inherit.gl-broadcast-message-dismiss.btn-default.btn-sm.gl-button.btn-default-tertiary.btn-icon.js-dismiss-current-broadcast-notification{ 'aria-label' => _('Close'), :type => 'button', data: { id: message.id, expire_date: message.ends_at.iso8601 } }
|
||||
= sprite_icon('close', size: 16, css_class: "gl-icon gl-mx-3! gl-text-white")
|
||||
= render Pajamas::ButtonComponent.new(category: :tertiary,
|
||||
icon: 'close',
|
||||
size: :small,
|
||||
button_options: { class: 'gl-close-btn-color-inherit gl-broadcast-message-dismiss js-dismiss-current-broadcast-notification', 'aria-label': _('Close'), data: { id: message.id, expire_date: message.ends_at.iso8601 } },
|
||||
icon_classes: 'gl-mx-3! gl-text-white')
|
||||
- else
|
||||
- notification_class = "js-broadcast-notification-#{message.id}"
|
||||
- notification_class << ' preview' if preview
|
||||
|
@ -25,5 +28,8 @@
|
|||
- else
|
||||
= yield
|
||||
- if !preview
|
||||
%button.js-dismiss-current-broadcast-notification.btn.btn-link.gl-button{ 'aria-label' => _('Close'), :type => 'button', data: { id: message.id, expire_date: message.ends_at.iso8601 } }
|
||||
= sprite_icon('close', size: 16, css_class: "gl-icon gl-mx-3! gl-text-gray-700")
|
||||
= render Pajamas::ButtonComponent.new(variant: :link,
|
||||
icon: 'close',
|
||||
size: :small,
|
||||
button_options: { class: 'js-dismiss-current-broadcast-notification', 'aria-label': _('Close'), data: { id: message.id, expire_date: message.ends_at.iso8601 } },
|
||||
icon_classes: 'gl-mx-3! gl-text-gray-700')
|
||||
|
|
|
@ -400,7 +400,7 @@ module Gitlab
|
|||
resource oauth_path,
|
||||
headers: %w(Authorization),
|
||||
credentials: false,
|
||||
methods: %i(post)
|
||||
methods: %i(post options)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -411,7 +411,7 @@ module Gitlab
|
|||
resource '/oauth/userinfo',
|
||||
headers: %w(Authorization),
|
||||
credentials: false,
|
||||
methods: %i(get head post)
|
||||
methods: %i(get head post options)
|
||||
end
|
||||
|
||||
%w(/oauth/discovery/keys /.well-known/openid-configuration /.well-known/webfinger).each do |openid_path|
|
||||
|
|
|
@ -14659,7 +14659,7 @@ Represents vulnerability finding of a security report on the pipeline.
|
|||
| <a id="pipelinesecurityreportfindingidentifiers"></a>`identifiers` | [`[VulnerabilityIdentifier!]!`](#vulnerabilityidentifier) | Identifiers of the vulnerability finding. |
|
||||
| <a id="pipelinesecurityreportfindinglinks"></a>`links` | [`[VulnerabilityLink!]`](#vulnerabilitylink) | List of links associated with the vulnerability. |
|
||||
| <a id="pipelinesecurityreportfindinglocation"></a>`location` | [`VulnerabilityLocation`](#vulnerabilitylocation) | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability. |
|
||||
| <a id="pipelinesecurityreportfindingname"></a>`name` | [`String`](#string) | Name of the vulnerability finding. |
|
||||
| <a id="pipelinesecurityreportfindingname"></a>`name` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.1. Use `title`. |
|
||||
| <a id="pipelinesecurityreportfindingproject"></a>`project` | [`Project`](#project) | Project on which the vulnerability finding was found. |
|
||||
| <a id="pipelinesecurityreportfindingprojectfingerprint"></a>`projectFingerprint` | [`String`](#string) | Name of the vulnerability finding. |
|
||||
| <a id="pipelinesecurityreportfindingreporttype"></a>`reportType` | [`VulnerabilityReportType`](#vulnerabilityreporttype) | Type of the security report that found the vulnerability finding. |
|
||||
|
|
|
@ -246,7 +246,7 @@ page](https://go.dev/dl).
|
|||
# Remove former Go installation folder
|
||||
sudo rm -rf /usr/local/go
|
||||
|
||||
curl --remote-name --location --progress-bar "https://go.dev/dl/go1.17.10.linux-amd64.tar.gz""
|
||||
curl --remote-name --location --progress-bar "https://go.dev/dl/go1.17.10.linux-amd64.tar.gz"
|
||||
echo '87fc728c9c731e2f74e4a999ef53cf07302d7ed3504b0839027bd9c10edaa3fd go1.17.10.linux-amd64.tar.gz' | shasum -a256 -c - && \
|
||||
sudo tar -C /usr/local -xzf go1.17.10.linux-amd64.tar.gz
|
||||
sudo ln -sf /usr/local/go/bin/{go,gofmt} /usr/local/bin/
|
||||
|
|
|
@ -171,8 +171,12 @@ Users can also be deactivated using the [GitLab API](../../api/users.md#deactiva
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/320875) in GitLab 14.0.
|
||||
|
||||
Administrators can enable automatic deactivation of users who have not signed in, or have no activity
|
||||
in the last 90 days. To do this:
|
||||
Administrators can enable automatic deactivation of users who either:
|
||||
|
||||
- Were created more than a week ago and have not signed in.
|
||||
- Have no activity in the last 90 days.
|
||||
|
||||
To do this:
|
||||
|
||||
1. On the top bar, select **Menu > Admin**.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
|
|
|
@ -9,6 +9,22 @@ module BulkImports
|
|||
relation_name 'releases'
|
||||
|
||||
extractor ::BulkImports::Common::Extractors::NdjsonExtractor, relation: relation
|
||||
|
||||
def after_run(_context)
|
||||
super
|
||||
|
||||
portable.releases.find_each do |release|
|
||||
create_release_evidence(release)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_release_evidence(release)
|
||||
return if release.historical_release? || release.upcoming_release?
|
||||
|
||||
::Releases::CreateEvidenceWorker.perform_async(release.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10933,9 +10933,6 @@ msgstr ""
|
|||
msgid "CsvParser|Unable to auto-detect delimiter; defaulted to \",\""
|
||||
msgstr ""
|
||||
|
||||
msgid "Cue dramatic background music..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Current"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
# frozen_string_literal: true
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Pajamas::ButtonComponent, type: :component do
|
||||
subject do
|
||||
described_class.new(**options)
|
||||
end
|
||||
|
||||
let(:content) { "Button content" }
|
||||
let(:options) { {} }
|
||||
|
||||
describe 'basic usage' do
|
||||
before do
|
||||
render_inline(subject) do |c|
|
||||
content
|
||||
end
|
||||
end
|
||||
|
||||
it 'renders its content' do
|
||||
expect(rendered_component).to have_text content
|
||||
end
|
||||
|
||||
it 'adds default styling' do
|
||||
expect(rendered_component).to have_css ".btn.btn-default.btn-md.gl-button"
|
||||
end
|
||||
|
||||
describe 'button_options' do
|
||||
let(:options) { { button_options: { id: 'baz', data: { foo: 'bar' } } } }
|
||||
|
||||
it 'are added to the button' do
|
||||
expect(rendered_component).to have_css ".gl-button#baz[data-foo='bar']"
|
||||
end
|
||||
|
||||
context 'with custom classes' do
|
||||
let(:options) { { variant: :danger, category: :tertiary, button_options: { class: 'custom-class' } } }
|
||||
|
||||
it 'don\'t conflict with internal button_classes' do
|
||||
expect(rendered_component).to have_css '.gl-button.btn-danger.btn-danger-tertiary.custom-class'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'button_text_classes' do
|
||||
let(:options) { { button_text_classes: 'custom-text-class' } }
|
||||
|
||||
it 'is added to the button text' do
|
||||
expect(rendered_component).to have_css ".gl-button-text.custom-text-class"
|
||||
end
|
||||
end
|
||||
|
||||
describe 'disabled' do
|
||||
context 'by default (false)' do
|
||||
it 'does not have disabled styling and behavior' do
|
||||
expect(rendered_component).not_to have_css ".disabled[disabled='disabled'][aria-disabled='true']"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when set to true' do
|
||||
let(:options) { { disabled: true } }
|
||||
|
||||
it 'has disabled styling and behavior' do
|
||||
expect(rendered_component).to have_css ".disabled[disabled='disabled'][aria-disabled='true']"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'loading' do
|
||||
context 'by default (false)' do
|
||||
it 'is not disabled' do
|
||||
expect(rendered_component).not_to have_css ".disabled[disabled='disabled']"
|
||||
end
|
||||
|
||||
it 'does not render a spinner' do
|
||||
expect(rendered_component).not_to have_css ".gl-spinner[aria-label='Loading']"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when set to true' do
|
||||
let(:options) { { loading: true } }
|
||||
|
||||
it 'is disabled' do
|
||||
expect(rendered_component).to have_css ".disabled[disabled='disabled']"
|
||||
end
|
||||
|
||||
it 'renders a spinner' do
|
||||
expect(rendered_component).to have_css ".gl-spinner[aria-label='Loading']"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'block' do
|
||||
context 'by default (false)' do
|
||||
it 'is inline' do
|
||||
expect(rendered_component).not_to have_css ".btn-block"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when set to true' do
|
||||
let(:options) { { block: true } }
|
||||
|
||||
it 'is block element' do
|
||||
expect(rendered_component).to have_css ".btn-block"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'selected' do
|
||||
context 'by default (false)' do
|
||||
it 'does not have selected styling and behavior' do
|
||||
expect(rendered_component).not_to have_css ".selected"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when set to true' do
|
||||
let(:options) { { selected: true } }
|
||||
|
||||
it 'has selected styling and behavior' do
|
||||
expect(rendered_component).to have_css ".selected"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'category & variant' do
|
||||
context 'with category variants' do
|
||||
where(:variant) { [:default, :confirm, :danger] }
|
||||
|
||||
let(:options) { { variant: variant, category: :tertiary } }
|
||||
|
||||
with_them do
|
||||
it 'renders the button in correct variant && category' do
|
||||
expect(rendered_component).to have_css(".#{described_class::VARIANT_CLASSES[variant]}")
|
||||
expect(rendered_component).to have_css(".#{described_class::VARIANT_CLASSES[variant]}-tertiary")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non-category variants' do
|
||||
where(:variant) { [:dashed, :link, :reset] }
|
||||
|
||||
let(:options) { { variant: variant, category: :tertiary } }
|
||||
|
||||
with_them do
|
||||
it 'renders the button in correct variant && category' do
|
||||
expect(rendered_component).to have_css(".#{described_class::VARIANT_CLASSES[variant]}")
|
||||
expect(rendered_component).not_to have_css(".#{described_class::VARIANT_CLASSES[variant]}-tertiary")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with primary category' do
|
||||
where(:variant) { [:default, :confirm, :danger] }
|
||||
|
||||
let(:options) { { variant: variant, category: :primary } }
|
||||
|
||||
with_them do
|
||||
it 'renders the button in correct variant && category' do
|
||||
expect(rendered_component).to have_css(".#{described_class::VARIANT_CLASSES[variant]}")
|
||||
expect(rendered_component).not_to have_css(".#{described_class::VARIANT_CLASSES[variant]}-primary")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'size' do
|
||||
context 'by default (medium)' do
|
||||
it 'applies medium class' do
|
||||
expect(rendered_component).to have_css ".btn-md"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when set to small' do
|
||||
let(:options) { { size: :small } }
|
||||
|
||||
it "applies the small class to the button" do
|
||||
expect(rendered_component).to have_css ".btn-sm"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'icon' do
|
||||
it 'has none by default' do
|
||||
expect(rendered_component).not_to have_css ".gl-icon"
|
||||
end
|
||||
|
||||
context 'with icon' do
|
||||
let(:options) { { icon: 'star-o', icon_classes: 'custom-icon' } }
|
||||
|
||||
it 'renders an icon with custom CSS class' do
|
||||
expect(rendered_component).to have_css "svg.gl-icon.gl-button-icon.custom-icon[data-testid='star-o-icon']"
|
||||
expect(rendered_component).not_to have_css ".btn-icon"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with icon only and no content' do
|
||||
let(:content) { nil }
|
||||
let(:options) { { icon: 'star-o' } }
|
||||
|
||||
it 'adds a "btn-icon" CSS class' do
|
||||
expect(rendered_component).to have_css ".btn.btn-icon"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with icon only and when loading' do
|
||||
let(:content) { nil }
|
||||
let(:options) { { icon: 'star-o', loading: true } }
|
||||
|
||||
it 'renders only a loading icon' do
|
||||
expect(rendered_component).not_to have_css "svg.gl-icon.gl-button-icon.custom-icon[data-testid='star-o-icon']"
|
||||
expect(rendered_component).to have_css ".gl-spinner[aria-label='Loading']"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'link button' do
|
||||
it 'renders a button tag with type="button" when "href" is not set' do
|
||||
expect(rendered_component).to have_css "button[type='button']"
|
||||
end
|
||||
|
||||
context 'when "href" is provided' do
|
||||
let(:options) { { href: 'https://gitlab.com', target: '_blank' } }
|
||||
|
||||
it "renders a link instead of the button" do
|
||||
expect(rendered_component).not_to have_css "button[type='button']"
|
||||
expect(rendered_component).to have_css "a[href='https://gitlab.com'][target='_blank']"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -78,10 +78,8 @@ describe('Pipelines stage component', () => {
|
|||
});
|
||||
|
||||
it('displays loading state while jobs are being fetched', () => {
|
||||
const expectedLoadingText = `${PipelineStage.i18n.loadingTextLineOne} ${PipelineStage.i18n.loadingTextLineTwo}`;
|
||||
|
||||
expect(findLoadingState().exists()).toBe(true);
|
||||
expect(findLoadingState().text()).toBe(expectedLoadingText);
|
||||
expect(findLoadingState().text()).toBe(PipelineStage.i18n.loadingText);
|
||||
});
|
||||
|
||||
it('does not display loading state after jobs have been fetched', async () => {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { GlCard } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import RepoDropdown from '~/projects/compare/components/repo_dropdown.vue';
|
||||
import RevisionCard from '~/projects/compare/components/revision_card.vue';
|
||||
|
@ -14,9 +13,6 @@ describe('RepoDropdown component', () => {
|
|||
...defaultProps,
|
||||
...props,
|
||||
},
|
||||
stubs: {
|
||||
GlCard,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -29,8 +25,10 @@ describe('RepoDropdown component', () => {
|
|||
createComponent();
|
||||
});
|
||||
|
||||
const RevisionCardWrapper = () => wrapper.find('.revision-card');
|
||||
|
||||
it('displays revision text', () => {
|
||||
expect(wrapper.find(GlCard).text()).toContain(defaultProps.revisionText);
|
||||
expect(RevisionCardWrapper().text()).toContain(defaultProps.revisionText);
|
||||
});
|
||||
|
||||
it('renders RepoDropdown component', () => {
|
||||
|
|
|
@ -34,7 +34,8 @@ describe('RegistrationDropdown', () => {
|
|||
const findRegistrationInstructionsDropdownItem = () => wrapper.findComponent(GlDropdownItem);
|
||||
const findTokenDropdownItem = () => wrapper.findComponent(GlDropdownForm);
|
||||
const findRegistrationToken = () => wrapper.findComponent(RegistrationToken);
|
||||
const findRegistrationTokenInput = () => wrapper.find('[name=token-value]');
|
||||
const findRegistrationTokenInput = () =>
|
||||
wrapper.findByLabelText(RegistrationToken.i18n.registrationToken);
|
||||
const findTokenResetDropdownItem = () =>
|
||||
wrapper.findComponent(RegistrationTokenResetDropdownItem);
|
||||
const findModal = () => wrapper.findComponent(GlModal);
|
||||
|
@ -172,10 +173,10 @@ describe('RegistrationDropdown', () => {
|
|||
await nextTick();
|
||||
};
|
||||
|
||||
it('Updates token in input', async () => {
|
||||
it('Updates token input', async () => {
|
||||
createComponent({}, mount);
|
||||
|
||||
expect(findRegistrationTokenInput().props('value')).not.toBe(newToken);
|
||||
expect(findRegistrationToken().props('value')).not.toBe(newToken);
|
||||
|
||||
await resetToken();
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ describe('RegistrationToken', () => {
|
|||
wrapper = mountFn(RegistrationToken, {
|
||||
propsData: {
|
||||
value: mockToken,
|
||||
inputId: 'token-value',
|
||||
...props,
|
||||
},
|
||||
localVue,
|
||||
|
|
|
@ -45,11 +45,11 @@ RSpec.describe BulkImports::Projects::Pipelines::ReleasesPipeline do
|
|||
allow_next_instance_of(BulkImports::Common::Extractors::NdjsonExtractor) do |extractor|
|
||||
allow(extractor).to receive(:extract).and_return(BulkImports::Pipeline::ExtractedData.new(data: [with_index]))
|
||||
end
|
||||
|
||||
pipeline.run
|
||||
end
|
||||
|
||||
it 'imports release into destination project' do
|
||||
pipeline.run
|
||||
|
||||
expect(project.releases.count).to eq(1)
|
||||
|
||||
imported_release = project.releases.last
|
||||
|
@ -78,6 +78,8 @@ RSpec.describe BulkImports::Projects::Pipelines::ReleasesPipeline do
|
|||
let(:attributes) {{ 'links' => [link] }}
|
||||
|
||||
it 'restores release links' do
|
||||
pipeline.run
|
||||
|
||||
release_link = project.releases.last.links.first
|
||||
|
||||
aggregate_failures do
|
||||
|
@ -105,6 +107,8 @@ RSpec.describe BulkImports::Projects::Pipelines::ReleasesPipeline do
|
|||
let(:attributes) {{ 'milestone_releases' => [{ 'milestone' => milestone }] }}
|
||||
|
||||
it 'restores release milestone' do
|
||||
pipeline.run
|
||||
|
||||
release_milestone = project.releases.last.milestone_releases.first.milestone
|
||||
|
||||
aggregate_failures do
|
||||
|
@ -118,5 +122,33 @@ RSpec.describe BulkImports::Projects::Pipelines::ReleasesPipeline do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'evidences' do
|
||||
it 'creates release evidence' do
|
||||
expect(::Releases::CreateEvidenceWorker).to receive(:perform_async)
|
||||
|
||||
pipeline.run
|
||||
end
|
||||
|
||||
context 'when release is historical' do
|
||||
let(:attributes) {{ 'released_at' => '2018-12-26T10:17:14.621Z' }}
|
||||
|
||||
it 'does not create release evidence' do
|
||||
expect(::Releases::CreateEvidenceWorker).not_to receive(:perform_async)
|
||||
|
||||
pipeline.run
|
||||
end
|
||||
end
|
||||
|
||||
context 'when release is upcoming' do
|
||||
let(:attributes) {{ 'released_at' => Time.zone.now + 30.days }}
|
||||
|
||||
it 'does not create release evidence' do
|
||||
expect(::Releases::CreateEvidenceWorker).not_to receive(:perform_async)
|
||||
|
||||
pipeline.run
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6637,8 +6637,10 @@ RSpec.describe User do
|
|||
describe '.with_no_activity' do
|
||||
it 'returns users with no activity' do
|
||||
freeze_time do
|
||||
not_that_long_ago = (described_class::MINIMUM_INACTIVE_DAYS - 1).days.ago.to_date
|
||||
too_long_ago = described_class::MINIMUM_INACTIVE_DAYS.days.ago.to_date
|
||||
active_not_that_long_ago = (described_class::MINIMUM_INACTIVE_DAYS - 1).days.ago.to_date
|
||||
active_too_long_ago = described_class::MINIMUM_INACTIVE_DAYS.days.ago.to_date
|
||||
created_recently = (described_class::MINIMUM_DAYS_CREATED - 1).days.ago.to_date
|
||||
created_not_recently = described_class::MINIMUM_DAYS_CREATED.days.ago.to_date
|
||||
|
||||
create(:user, :deactivated, last_activity_on: nil)
|
||||
|
||||
|
@ -6646,12 +6648,13 @@ RSpec.describe User do
|
|||
create(:user, state: :active, user_type: user_type, last_activity_on: nil)
|
||||
end
|
||||
|
||||
create(:user, last_activity_on: not_that_long_ago)
|
||||
create(:user, last_activity_on: too_long_ago)
|
||||
create(:user, last_activity_on: active_not_that_long_ago)
|
||||
create(:user, last_activity_on: active_too_long_ago)
|
||||
create(:user, last_activity_on: nil, created_at: created_recently)
|
||||
|
||||
user_with_no_activity = create(:user, last_activity_on: nil)
|
||||
old_enough_user_with_no_activity = create(:user, last_activity_on: nil, created_at: created_not_recently)
|
||||
|
||||
expect(described_class.with_no_activity).to contain_exactly(user_with_no_activity)
|
||||
expect(described_class.with_no_activity).to contain_exactly(old_enough_user_with_no_activity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,11 +6,12 @@ RSpec.describe Oauth::TokensController do
|
|||
let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
|
||||
let(:other_headers) { {} }
|
||||
let(:headers) { cors_request_headers.merge(other_headers)}
|
||||
let(:allowed_methods) { 'POST, OPTIONS' }
|
||||
|
||||
shared_examples 'cross-origin POST request' do
|
||||
it 'allows cross-origin requests' do
|
||||
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
|
||||
expect(response.headers['Access-Control-Allow-Methods']).to eq 'POST'
|
||||
expect(response.headers['Access-Control-Allow-Methods']).to eq allowed_methods
|
||||
expect(response.headers['Access-Control-Allow-Headers']).to be_nil
|
||||
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
|
||||
end
|
||||
|
@ -23,7 +24,7 @@ RSpec.describe Oauth::TokensController do
|
|||
|
||||
it 'allows cross-origin requests' do
|
||||
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
|
||||
expect(response.headers['Access-Control-Allow-Methods']).to eq 'POST'
|
||||
expect(response.headers['Access-Control-Allow-Methods']).to eq allowed_methods
|
||||
expect(response.headers['Access-Control-Allow-Headers']).to eq 'Authorization'
|
||||
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
|
||||
end
|
||||
|
|
|
@ -98,7 +98,7 @@ RSpec.describe 'OpenID Connect requests' do
|
|||
shared_examples 'cross-origin GET and POST request' do
|
||||
it 'allows cross-origin request' do
|
||||
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
|
||||
expect(response.headers['Access-Control-Allow-Methods']).to eq 'GET, HEAD, POST'
|
||||
expect(response.headers['Access-Control-Allow-Methods']).to eq 'GET, HEAD, POST, OPTIONS'
|
||||
expect(response.headers['Access-Control-Allow-Headers']).to be_nil
|
||||
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
|
||||
end
|
||||
|
|
|
@ -7,7 +7,8 @@ RSpec.describe Users::DeactivateDormantUsersWorker do
|
|||
|
||||
describe '#perform' do
|
||||
let_it_be(:dormant) { create(:user, last_activity_on: User::MINIMUM_INACTIVE_DAYS.days.ago.to_date) }
|
||||
let_it_be(:inactive) { create(:user, last_activity_on: nil) }
|
||||
let_it_be(:inactive) { create(:user, last_activity_on: nil, created_at: User::MINIMUM_DAYS_CREATED.days.ago.to_date) }
|
||||
let_it_be(:inactive_recently_created) { create(:user, last_activity_on: nil, created_at: (User::MINIMUM_DAYS_CREATED - 1).days.ago.to_date) }
|
||||
|
||||
subject(:worker) { described_class.new }
|
||||
|
||||
|
@ -71,6 +72,12 @@ RSpec.describe Users::DeactivateDormantUsersWorker do
|
|||
expect(human_user.reload.state).to eq('blocked')
|
||||
expect(service_user.reload.state).to eq('blocked')
|
||||
end
|
||||
|
||||
it 'does not deactivate recently created users' do
|
||||
worker.perform
|
||||
|
||||
expect(inactive_recently_created.reload.state).to eq('active')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when automatic deactivation of dormant users is disabled' do
|
||||
|
|
Loading…
Reference in New Issue