Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-01 18:08:33 +00:00
parent a0fdcfcdd5
commit 24d67ec554
61 changed files with 680 additions and 501 deletions

View File

@ -466,7 +466,7 @@ gem 'benchmark-memory', '~> 0.1', require: false
gem 'activerecord-explain-analyze', '~> 0.1', require: false
# OAuth
gem 'oauth2', '~> 1.4'
gem 'oauth2', '~> 2.0'
# Health check
gem 'health_check', '~> 3.0'

View File

@ -826,12 +826,13 @@ GEM
shellany (~> 0.0)
numerizer (0.2.0)
oauth (0.5.6)
oauth2 (1.4.7)
faraday (>= 0.8, < 2.0)
oauth2 (2.0.3)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
rash_alt (>= 0.4, < 1)
version_gem (~> 1.0)
octokit (4.20.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
@ -1050,6 +1051,8 @@ GEM
rainbow (3.1.1)
rake (13.0.6)
randexp (0.1.7)
rash_alt (0.4.12)
hashie (>= 3.4)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
@ -1408,6 +1411,7 @@ GEM
validates_hostname (1.0.11)
activerecord (>= 3.0)
activesupport (>= 3.0)
version_gem (1.0.0)
version_sorter (2.2.4)
view_component (2.50.0)
activesupport (>= 5.0.0, < 8.0)
@ -1612,7 +1616,7 @@ DEPENDENCIES
net-ldap (~> 0.16.3)
net-ntp
nokogiri (~> 1.13.6)
oauth2 (~> 1.4)
oauth2 (~> 2.0)
octokit (~> 4.15)
ohai (~> 16.10)
oj (~> 3.10.6)

View File

@ -0,0 +1,15 @@
<script>
import { s__ } from '~/locale';
export default {
name: 'IncludedInTrialIndicator',
i18n: {
trialOnly: s__('LearnGitlab|- Included in trial'),
},
};
</script>
<template>
<span class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only">
{{ $options.i18n.trialOnly }}
</span>
</template>

View File

@ -38,14 +38,16 @@ export default {
actionsData: this.actions,
};
},
maxValue: Object.keys(ACTION_LABELS).length,
actionSections: Object.keys(ACTION_SECTIONS),
computed: {
maxValue() {
return Object.keys(this.actionsData).length;
},
progressValue() {
return Object.values(this.actionsData).filter((a) => a.completed).length;
},
progressPercentage() {
return Math.round((this.progressValue / this.$options.maxValue) * 100);
return Math.round((this.progressValue / this.maxValue) * 100);
},
},
mounted() {
@ -125,7 +127,7 @@ export default {
<template #percentSymbol>%</template>
</gl-sprintf>
</p>
<gl-progress-bar :value="progressValue" :max="$options.maxValue" />
<gl-progress-bar :value="progressValue" :max="maxValue" />
</div>
<div class="row">
<div

View File

@ -1,70 +0,0 @@
<script>
import { GlLink, GlCard, GlIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
name: 'LearnGitlabInfoCard',
components: { GlLink, GlCard, GlIcon },
i18n: {
trial: s__('Learn GitLab|Trial only'),
},
props: {
title: {
required: true,
type: String,
},
description: {
required: true,
type: String,
},
actionLabel: {
required: true,
type: String,
},
url: {
required: true,
type: String,
},
completed: {
required: true,
type: Boolean,
},
svg: {
required: true,
type: String,
},
trialRequired: {
default: false,
required: false,
type: Boolean,
},
},
};
</script>
<template>
<gl-card class="gl-pt-0">
<div class="gl-text-right gl-h-5">
<gl-icon
v-if="completed"
name="check-circle-filled"
class="gl-text-green-500"
:size="16"
data-testid="completed-icon"
/>
<span
v-else-if="trialRequired"
class="gl-text-gray-500 gl-font-sm gl-font-style-italic"
data-testid="trial-only"
>{{ $options.i18n.trial }}</span
>
</div>
<div
class="gl-text-center gl-display-flex gl-justify-content-center gl-align-items-center gl-flex-direction-column learn-gitlab-info-card-content"
>
<img :src="svg" :alt="actionLabel" />
<h6>{{ title }}</h6>
<p class="gl-font-sm gl-text-gray-700">{{ description }}</p>
<gl-link :href="url" target="_blank" rel="noopener noreferrer" />
</div>
</gl-card>
</template>

View File

@ -6,6 +6,7 @@ import { isExperimentVariant } from '~/experimentation/utils';
import eventHub from '~/invite_members/event_hub';
import { s__, __ } from '~/locale';
import { ACTION_LABELS } from '../constants';
import IncludedInTrialIndicator from './included_in_trial_indicator.vue';
export default {
name: 'LearnGitlabSectionLink',
@ -15,12 +16,12 @@ export default {
GlButton,
GlPopover,
GitlabExperiment,
IncludedInTrialIndicator,
},
directives: {
GlTooltip,
},
i18n: {
trialOnly: s__('LearnGitlab|Trial only'),
contactAdmin: s__('LearnGitlab|Contact your administrator to start a free Ultimate trial.'),
viewAdminList: s__('LearnGitlab|View administrator list'),
watchHow: __('Watch how'),
@ -41,12 +42,6 @@ export default {
};
},
computed: {
linkTitle() {
return ACTION_LABELS[this.action].title;
},
trialOnly() {
return ACTION_LABELS[this.action].trialRequired;
},
showInviteModalLink() {
return (
this.action === 'userAdded' && isExperimentVariant('invite_for_help_continuous_onboarding')
@ -55,49 +50,51 @@ export default {
openInNewTab() {
return ACTION_LABELS[this.action]?.openInNewTab === true || this.value.openInNewTab === true;
},
linkToVideoTutorial() {
return ACTION_LABELS[this.action].videoTutorial;
},
},
methods: {
openModal() {
eventHub.$emit('openModal', { source: 'learn_gitlab' });
},
actionLabelValue(value) {
return ACTION_LABELS[this.action][value];
},
},
};
</script>
<template>
<div class="gl-mb-4">
<div v-if="trialOnly" class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only">
{{ $options.i18n.trialOnly }}
</div>
<div class="flex align-items-center">
<span v-if="value.completed" class="gl-text-green-500">
<gl-icon name="check-circle-filled" :size="16" data-testid="completed-icon" />
{{ linkTitle }}
{{ actionLabelValue('title') }}
<included-in-trial-indicator v-if="actionLabelValue('trialRequired')" />
</span>
<gl-link
v-else-if="showInviteModalLink"
data-track-action="click_link"
:data-track-label="linkTitle"
data-track-property="Growth::Activation::Experiment::InviteForHelpContinuousOnboarding"
data-testid="invite-for-help-continuous-onboarding-experiment-link"
@click="openModal"
>
{{ linkTitle }}
</gl-link>
<gl-link
v-else-if="value.enabled"
:target="openInNewTab ? '_blank' : '_self'"
:href="value.url"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
:data-track-label="linkTitle"
>
{{ linkTitle }}
</gl-link>
<div v-else-if="showInviteModalLink">
<gl-link
data-track-action="click_link"
:data-track-label="actionLabelValue('trackLabel')"
data-track-property="Growth::Activation::Experiment::InviteForHelpContinuousOnboarding"
data-testid="invite-for-help-continuous-onboarding-experiment-link"
@click="openModal"
>{{ actionLabelValue('title') }}</gl-link
>
<included-in-trial-indicator v-if="actionLabelValue('trialRequired')" />
</div>
<div v-else-if="value.enabled">
<gl-link
:target="openInNewTab ? '_blank' : '_self'"
:href="value.url"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
:data-track-label="actionLabelValue('trackLabel')"
>{{ actionLabelValue('title') }}</gl-link
>
<included-in-trial-indicator v-if="actionLabelValue('trialRequired')" />
</div>
<template v-else>
<div data-testid="disabled-learn-gitlab-link">{{ linkTitle }}</div>
<div data-testid="disabled-learn-gitlab-link">{{ actionLabelValue('title') }}</div>
<gl-button
:id="popoverId"
category="tertiary"
@ -127,19 +124,19 @@ export default {
<template #control></template>
<template #candidate>
<gl-button
v-if="linkToVideoTutorial"
v-if="actionLabelValue('videoTutorial')"
v-gl-tooltip
category="tertiary"
icon="live-preview"
:title="$options.i18n.watchHow"
:aria-label="$options.i18n.watchHow"
:href="linkToVideoTutorial"
:href="actionLabelValue('videoTutorial')"
target="_blank"
class="ml-auto"
size="small"
data-testid="video-tutorial-link"
data-track-action="click_video_link"
:data-track-label="linkTitle"
:data-track-label="actionLabelValue('trackLabel')"
data-track-property="Growth::Conversion::Experiment::LearnGitLab"
data-track-experiment="video_tutorials_continuous_onboarding"
/>

View File

@ -2,9 +2,10 @@ import { s__ } from '~/locale';
export const ACTION_LABELS = {
gitWrite: {
title: s__('LearnGitLab|Create or import a repository'),
actionLabel: s__('LearnGitLab|Create or import a repository'),
title: s__('LearnGitLab|Create a repository'),
actionLabel: s__('LearnGitLab|Create a repository'),
description: s__('LearnGitLab|Create or import your first repository into your new project.'),
trackLabel: 'create_a_repository',
section: 'workspace',
position: 1,
},
@ -14,20 +15,23 @@ export const ACTION_LABELS = {
description: s__(
'LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features.',
),
trackLabel: 'invite_your_colleagues',
section: 'workspace',
position: 0,
},
pipelineCreated: {
title: s__('LearnGitLab|Set up CI/CD'),
actionLabel: s__('LearnGitLab|Set-up CI/CD'),
title: s__("LearnGitLab|Set up your first project's CI/CD"),
actionLabel: s__('LearnGitLab|Set up CI/CD'),
description: s__('LearnGitLab|Save time by automating your integration and deployment tasks.'),
trackLabel: 'set_up_your_first_project_s_ci_cd',
section: 'workspace',
position: 2,
},
trialStarted: {
title: s__('LearnGitLab|Start a free Ultimate trial'),
title: s__('LearnGitLab|Start a free trial of GitLab Ultimate'),
actionLabel: s__('LearnGitLab|Try GitLab Ultimate for free'),
description: s__('LearnGitLab|Try all GitLab features for 30 days, no credit card required.'),
trackLabel: 'start_a_free_trial_of_gitlab_ultimate',
section: 'workspace',
position: 3,
openInNewTab: true,
@ -38,6 +42,7 @@ export const ACTION_LABELS = {
description: s__(
'LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths.',
),
trackLabel: 'add_code_owners',
trialRequired: true,
section: 'workspace',
position: 4,
@ -45,9 +50,10 @@ export const ACTION_LABELS = {
videoTutorial: 'https://vimeo.com/670896787',
},
requiredMrApprovalsEnabled: {
title: s__('LearnGitLab|Add merge request approval'),
title: s__('LearnGitLab|Enable require merge approvals'),
actionLabel: s__('LearnGitLab|Enable require merge approvals'),
description: s__('LearnGitLab|Route code reviews to the right reviewers, every time.'),
trackLabel: 'enable_require_merge_approvals',
trialRequired: true,
section: 'workspace',
position: 5,
@ -55,28 +61,52 @@ export const ACTION_LABELS = {
videoTutorial: 'https://vimeo.com/670904904',
},
mergeRequestCreated: {
title: s__('LearnGitLab|Submit a merge request'),
title: s__('LearnGitLab|Submit a merge request (MR)'),
actionLabel: s__('LearnGitLab|Submit a merge request (MR)'),
description: s__('LearnGitLab|Review and edit proposed changes to source code.'),
trackLabel: 'submit_a_merge_request_mr',
section: 'plan',
position: 1,
},
securityScanEnabled: {
title: s__('LearnGitLab|Run a Security scan using CI/CD'),
actionLabel: s__('LearnGitLab|Run a Security scan using CI/CD'),
description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'),
section: 'deploy',
position: 1,
},
issueCreated: {
title: s__('LearnGitLab|Create an issue'),
actionLabel: s__('LearnGitLab|Create an issue'),
description: s__(
'LearnGitLab|Create/import issues (tickets) to collaborate on ideas and plan work.',
),
trackLabel: 'create_an_issue',
section: 'plan',
position: 0,
},
securityScanEnabled: {
title: s__('LearnGitLab|Run a Security scan using CI/CD'),
actionLabel: s__('LearnGitLab|Run a Security scan using CI/CD'),
description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'),
trackLabel: 'run_a_security_scan_using_ci_cd',
section: 'deploy',
position: 1,
},
licenseScanningRun: {
title: s__('LearnGitLab|Scan dependencies for licenses'),
trackLabel: 'scan_dependencies_for_licenses',
trialRequired: true,
section: 'deploy',
position: 2,
},
secureDependencyScanningRun: {
title: s__('LearnGitLab|Scan dependencies for vulnerabilities'),
trackLabel: 'scan_dependencies_for_vulnerabilities',
trialRequired: true,
section: 'deploy',
position: 3,
},
secureDastRun: {
title: s__('LearnGitLab|Analyze your application for vulnerabilities with DAST'),
trackLabel: 'analyze_your_application_for_vulnerabilities_with_dast',
trialRequired: true,
section: 'deploy',
position: 4,
},
};
export const ACTION_SECTIONS = {

View File

@ -1,6 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import createTestReportsStore from '../../stores/test_reports';
import EmptyState from './empty_state.vue';
import TestSuiteTable from './test_suite_table.vue';
import TestSummary from './test_summary.vue';
@ -15,9 +16,10 @@ export default {
TestSummary,
TestSummaryTable,
},
inject: ['blobPath', 'summaryEndpoint', 'suiteEndpoint'],
computed: {
...mapState(['isLoading', 'selectedSuiteIndex', 'testReports']),
...mapGetters(['getSelectedSuite']),
...mapState('testReports', ['isLoading', 'selectedSuiteIndex', 'testReports']),
...mapGetters('testReports', ['getSelectedSuite']),
showSuite() {
return this.selectedSuiteIndex !== null;
},
@ -27,10 +29,19 @@ export default {
},
},
created() {
this.$store.registerModule(
'testReports',
createTestReportsStore({
blobPath: this.blobPath,
summaryEndpoint: this.summaryEndpoint,
suiteEndpoint: this.suiteEndpoint,
}),
);
this.fetchSummary();
},
methods: {
...mapActions([
...mapActions('testReports', [
'fetchTestSuite',
'fetchSummary',
'setSelectedSuiteIndex',

View File

@ -51,14 +51,18 @@ export default {
},
},
computed: {
...mapState(['pageInfo']),
...mapGetters(['getSuiteTests', 'getSuiteTestCount', 'getSuiteArtifactsExpired']),
...mapState('testReports', ['pageInfo']),
...mapGetters('testReports', [
'getSuiteTests',
'getSuiteTestCount',
'getSuiteArtifactsExpired',
]),
hasSuites() {
return this.getSuiteTests.length > 0;
},
},
methods: {
...mapActions(['setPage']),
...mapActions('testReports', ['setPage']),
},
wrapSymbols: ['::', '#', '.', '_', '-', '/', '\\'],
i18n,

View File

@ -19,7 +19,7 @@ export default {
},
},
computed: {
...mapGetters(['getTestSuites']),
...mapGetters('testReports', ['getTestSuites']),
hasSuites() {
return this.getTestSuites.length > 0;
},

View File

@ -1,9 +1,10 @@
import Vue from 'vue';
import Vuex from 'vuex';
import { parseBoolean } from '~/lib/utils/common_utils';
import Translate from '~/vue_shared/translate';
import TestReports from './components/test_reports/test_reports.vue';
import createTestReportsStore from './stores/test_reports';
Vue.use(Vuex);
Vue.use(Translate);
export const createTestDetails = (selector) => {
@ -16,11 +17,6 @@ export const createTestDetails = (selector) => {
suiteEndpoint,
artifactsExpiredImagePath,
} = el?.dataset || {};
const testReportsStore = createTestReportsStore({
blobPath,
summaryEndpoint,
suiteEndpoint,
});
// eslint-disable-next-line no-new
new Vue({
@ -32,8 +28,11 @@ export const createTestDetails = (selector) => {
emptyStateImagePath,
artifactsExpiredImagePath,
hasTestReport: parseBoolean(hasTestReport),
blobPath,
summaryEndpoint,
suiteEndpoint,
},
store: testReportsStore,
store: new Vuex.Store(),
render(createElement) {
return createElement('test-reports');
},

View File

@ -1,16 +1,14 @@
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
Vue.use(Vuex);
export default (initialState) =>
new Vuex.Store({
export default (initialState) => {
return {
namespaced: true,
actions,
getters,
mutations,
state: state(initialState),
});
};
};

View File

@ -206,6 +206,7 @@ export default {
<template #features>
<feature-card
v-for="feature in augmentedSecurityFeatures"
:id="feature.anchor"
:key="feature.type"
data-testid="security-testing-card"
:feature="feature"

View File

@ -194,6 +194,7 @@ export const securityFeatures = [
helpPath: DAST_HELP_PATH,
configurationHelpPath: DAST_CONFIG_HELP_PATH,
type: REPORT_TYPE_DAST,
anchor: 'dast',
},
{
name: DEPENDENCY_SCANNING_NAME,
@ -201,6 +202,7 @@ export const securityFeatures = [
helpPath: DEPENDENCY_SCANNING_HELP_PATH,
configurationHelpPath: DEPENDENCY_SCANNING_CONFIG_HELP_PATH,
type: REPORT_TYPE_DEPENDENCY_SCANNING,
anchor: 'dependency-scanning',
},
{
name: CONTAINER_SCANNING_NAME,

View File

@ -53,7 +53,9 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
def set_index_vars
@applications = current_user.oauth_applications.load
@authorized_tokens = current_user.oauth_authorized_tokens.preload(:application).order(created_at: :desc).load # rubocop: disable CodeReuse/ActiveRecord
@authorized_tokens = current_user.oauth_authorized_tokens
.latest_per_application
.preload_application
# Don't overwrite a value possibly set by `create`
@application ||= Doorkeeper::Application.new

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class SecurityActionsContinuousOnboardingExperiment < ApplicationExperiment
def control_behavior
end
def candidate_behavior
end
end

View File

@ -216,7 +216,7 @@ module IntegrationsHelper
end
def fields_for_integration(integration)
Integrations::FieldSerializer.new(integration: integration).represent(integration.global_fields).to_json
Integrations::FieldSerializer.new(integration: integration).represent(integration.form_fields).to_json
end
def integration_level(integration)

View File

@ -4,6 +4,7 @@ module LearnGitlabHelper
IMAGE_PATH_PLAN = "learn_gitlab/section_plan.svg"
IMAGE_PATH_DEPLOY = "learn_gitlab/section_deploy.svg"
IMAGE_PATH_WORKSPACE = "learn_gitlab/section_workspace.svg"
LICENSE_SCANNING_RUN_URL = 'https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html'
def learn_gitlab_enabled?(project)
return false unless current_user
@ -64,7 +65,7 @@ module LearnGitlabHelper
git_write: project_path(project),
merge_request_created: project_merge_requests_path(project),
user_added: project_members_url(project),
security_scan_enabled: project_security_configuration_path(project)
**deploy_section_action_urls(project)
)
end
@ -72,6 +73,23 @@ module LearnGitlabHelper
LearnGitlab::Onboarding::ACTION_ISSUE_IDS.transform_values { |id| project_issue_url(learn_gitlab_project, id) }
end
def deploy_section_action_urls(project)
experiment(:security_actions_continuous_onboarding,
namespace: project.namespace,
user: current_user,
sticky_to: current_user
) do |e|
e.control { { security_scan_enabled: project_security_configuration_path(project) } }
e.candidate do
{
license_scanning_run: LICENSE_SCANNING_RUN_URL,
secure_dependency_scanning_run: project_security_configuration_path(project, anchor: 'dependency-scanning'),
secure_dast_run: project_security_configuration_path(project, anchor: 'dast')
}
end
end.run
end
def learn_gitlab_project
@learn_gitlab_project ||= LearnGitlab::Project.new(current_user).project
end

View File

@ -29,10 +29,6 @@ module Ci
return_exit_code: -> (build) { build.exit_codes_defined? }
}.freeze
DEFAULT_RETRIES = {
scheduler_failure: 2
}.freeze
DEGRADATION_THRESHOLD_VARIABLE_NAME = 'DEGRADATION_THRESHOLD'
RUNNERS_STATUS_CACHE_EXPIRATION = 1.minute

View File

@ -27,8 +27,6 @@ module Ci
DEFAULT_CONFIG_PATH = CONFIG_EXTENSION
CANCELABLE_STATUSES = (Ci::HasStatus::CANCELABLE_STATUSES + ['manual']).freeze
BridgeStatusError = Class.new(StandardError)
paginates_per 15
sha_attribute :source_sha

View File

@ -505,8 +505,8 @@ class Integration < ApplicationRecord
fields.reject { _1[:type] == 'password' }.pluck(:name)
end
def global_fields
fields
def form_fields
fields.reject { _1[:api_only] == true }
end
def configurable_events

View File

@ -139,8 +139,8 @@ module Integrations
supported_events.map { |event| event_channel_name(event) }
end
def global_fields
fields.reject { |field| field[:name].end_with?('channel') }
def form_fields
super.reject { |field| field[:name].end_with?('channel') }
end
def default_channel_placeholder

View File

@ -71,11 +71,12 @@ module Integrations
non_empty_password_help: -> { s_('JiraService|Leave blank to use your current password or API token.') },
help: -> { s_('JiraService|Use a password for server version and an API token for cloud version.') }
field :jira_issue_transition_id, api_only: true
# TODO: we can probably just delegate as part of
# https://gitlab.com/gitlab-org/gitlab/issues/29404
# These fields are API only, so no field definition is required.
data_field :jira_issue_transition_automatic
data_field :jira_issue_transition_id
data_field :project_key
data_field :issues_enabled
data_field :vulnerabilities_enabled

View File

@ -7,6 +7,8 @@ class OauthAccessToken < Doorkeeper::AccessToken
alias_attribute :user, :resource_owner
scope :distinct_resource_owner_counts, ->(applications) { where(application: applications).distinct.group(:application_id).count(:resource_owner_id) }
scope :latest_per_application, -> { select('distinct on(application_id) *').order(application_id: :desc, created_at: :desc) }
scope :preload_application, -> { preload(:application) }
def scopes=(value)
if value.is_a?(Array)

View File

@ -1626,7 +1626,7 @@ class User < ApplicationRecord
end
def oauth_authorized_tokens
Doorkeeper::AccessToken.where(resource_owner_id: id, revoked_at: nil)
OauthAccessToken.where(resource_owner_id: id, revoked_at: nil)
end
# Returns the projects a user contributed to in the last year.

View File

@ -10,24 +10,12 @@ module Ci
return pull_request_not_open_error unless pull_request.open?
return pull_request_branch_error unless pull_request.actual_branch_head?
create_pipeline_for(pull_request)
end
private
def create_pipeline_for(pull_request)
Ci::ExternalPullRequests::CreatePipelineWorker.perform_async(
project.id, current_user.id, pull_request.id
)
end
def create_params(pull_request)
{
ref: pull_request.source_ref,
source_sha: pull_request.source_sha,
target_sha: pull_request.target_sha
}
end
private
def pull_request_not_open_error
ServiceResponse.error(message: 'The pull request is not opened', payload: nil)

View File

@ -5,8 +5,6 @@ module Ci
class CreateService < ::BaseService
include Gitlab::Utils::UsageData
ArtifactsExistError = Class.new(StandardError)
LSIF_ARTIFACT_TYPE = 'lsif'
METRICS_REPORT_UPLOAD_EVENT_NAME = 'i_testing_metrics_report_artifact_uploaders'
@ -74,10 +72,6 @@ module Ci
Ci::JobArtifact.max_artifact_size(type: type, project: project)
end
def forbidden_type_error(type)
error("#{type} artifacts are forbidden", :forbidden)
end
def too_large_error
error('file size has reached maximum size limit', :payload_too_large)
end

View File

@ -0,0 +1,8 @@
---
name: security_actions_continuous_onboarding
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82274
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345176
milestone: '15.2'
type: experiment
group: group::acquisition
default_enabled: false

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class AddPartialIndexOnOauthAccessTokensRevokedAtWithOrder < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
INDEX_NAME = 'partial_index_user_id_app_id_created_at_token_not_revoked'
EXISTING_INDEX_NAME = 'partial_index_resource_owner_id_created_at_token_not_revoked'
def up
add_concurrent_index :oauth_access_tokens, [:resource_owner_id, :application_id, :created_at],
name: INDEX_NAME, where: 'revoked_at IS NULL'
remove_concurrent_index :oauth_access_tokens, [:resource_owner_id, :created_at], name: EXISTING_INDEX_NAME
end
def down
add_concurrent_index :oauth_access_tokens, [:resource_owner_id, :created_at],
name: EXISTING_INDEX_NAME, where: 'revoked_at IS NULL'
remove_concurrent_index :oauth_access_tokens, [:resource_owner_id, :application_id, :created_at], name: INDEX_NAME
end
end

View File

@ -0,0 +1 @@
5b12e0fbebef2979cfc31aab16ce78988a2f94662dbe1048791413347edb3c99

View File

@ -30172,14 +30172,14 @@ CREATE INDEX partial_index_deployments_for_legacy_successful_deployments ON depl
CREATE INDEX partial_index_deployments_for_project_id_and_tag ON deployments USING btree (project_id) WHERE (tag IS TRUE);
CREATE INDEX partial_index_resource_owner_id_created_at_token_not_revoked ON oauth_access_tokens USING btree (resource_owner_id, created_at) WHERE (revoked_at IS NULL);
CREATE INDEX partial_index_slack_integrations_with_bot_user_id ON slack_integrations USING btree (id) WHERE (bot_user_id IS NOT NULL);
CREATE UNIQUE INDEX partial_index_sop_configs_on_namespace_id ON security_orchestration_policy_configurations USING btree (namespace_id) WHERE (namespace_id IS NOT NULL);
CREATE UNIQUE INDEX partial_index_sop_configs_on_project_id ON security_orchestration_policy_configurations USING btree (project_id) WHERE (project_id IS NOT NULL);
CREATE INDEX partial_index_user_id_app_id_created_at_token_not_revoked ON oauth_access_tokens USING btree (resource_owner_id, application_id, created_at) WHERE (revoked_at IS NULL);
CREATE UNIQUE INDEX snippet_user_mentions_on_snippet_id_and_note_id_index ON snippet_user_mentions USING btree (snippet_id, note_id);
CREATE UNIQUE INDEX snippet_user_mentions_on_snippet_id_index ON snippet_user_mentions USING btree (snippet_id) WHERE (note_id IS NULL);

View File

@ -148,6 +148,7 @@ This method should return an array of hashes for each field, where the keys can
| `title:` | string | false | Capitalized value of `name:` | The label for the form field.
| `placeholder:` | string | false | | A placeholder for the form field.
| `help:` | string | false | | A help text that displays below the form field.
| `api_only:` | boolean | false | `false` | Specify if the field should only be available through the API, and excluded from the frontend form.
#### Additional keys for `type: 'checkbox'`

View File

@ -61,3 +61,13 @@ before_action do
push_licensed_feature(:feature_symbol, project)
end
```
## Allow use of licensed EE features
To enable plans per namespace turn on the `Allow use of licensed EE features` option from the settings page.
This will make licensed EE features available to projects only if the project namespace's plan includes the feature
or if the project is public. To enable it:
1. If you are developing locally, follow the steps in [simulate SaaS](ee_features.md#act-as-saas) to make the option available.
1. Visit Admin > Settings > General > "Account and limit" and
enabling "Allow use of licensed EE features".

View File

@ -86,7 +86,7 @@ To create an application for your GitLab instance:
When creating application in the **Admin Area** , you can mark it as _trusted_.
The user authorization step is automatically skipped for this application.
## Expiring access tokens
## Access token expiration
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21745) in GitLab 14.3, with the ability to opt out.
> - Ability to opt-out of expiring access token [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/340848) in GitLab 15.0.
@ -97,12 +97,7 @@ in GitLab 14.3 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/34084
existing integrations must be updated to support access token refresh.
Access tokens expire in two hours which means that integrations that use them must support generating new access
tokens at least every two hours. Existing:
- Applications can have expiring access tokens:
1. Edit the application.
1. Select **Expire access tokens**.
- Tokens must be [revoked](../api/oauth2.md#revoke-a-token) or they don't expire.
tokens at least every two hours.
When applications are deleted, all grants and tokens associated with the application are also deleted.

View File

@ -28,6 +28,9 @@ You can [check the status of existing migrations](../../../update/index.md#batch
## Enable or disable batched background migrations
WARNING:
If you disable this feature flag, GitLab upgrades may fail.
Batched background migrations are under development but ready for production use.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)

View File

@ -34,7 +34,7 @@ To view value stream analytics for your project:
1. On the top bar, select **Menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > Value stream**.
1. To view metrics for each stage, above the **Filter results** text box, select a stage.
1. To view metrics for a particular stage, select a stage below the **Filter results** text box.
1. Optional. Filter the results:
1. Select the **Filter results** text box.
1. Select a parameter.

View File

@ -37,7 +37,7 @@ To view value stream analytics for your group:
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Analytics > Value stream**.
1. To view metrics for each stage, above the **Filter results** text box, select a stage.
1. To view metrics for a particular stage, select a stage below the **Filter results** text box.
1. Optional. Filter the results:
1. Select the **Filter results** text box.
1. Select a parameter.

View File

@ -3,6 +3,7 @@
module LearnGitlab
class Onboarding
include Gitlab::Utils::StrongMemoize
include Gitlab::Experiment::Dsl
ACTION_ISSUE_IDS = {
pipeline_created: 7,
@ -15,12 +16,12 @@ module LearnGitlab
:issue_created,
:git_write,
:merge_request_created,
:user_added,
:security_scan_enabled
:user_added
].freeze
def initialize(namespace)
def initialize(namespace, current_user = nil)
@namespace = namespace
@current_user = current_user
end
def completed_percentage
@ -49,9 +50,20 @@ module LearnGitlab
end
def tracked_actions
ACTION_ISSUE_IDS.keys + ACTION_PATHS
ACTION_ISSUE_IDS.keys + ACTION_PATHS + deploy_section_tracked_actions
end
attr_reader :namespace
def deploy_section_tracked_actions
experiment(:security_actions_continuous_onboarding,
namespace: namespace,
user: current_user,
sticky_to: current_user
) do |e|
e.control { [:security_scan_enabled] }
e.candidate { [:license_scanning_run, :secure_dependency_scanning_run, :secure_dast_run] }
end.run
end
attr_reader :namespace, :current_user
end
end

View File

@ -29,7 +29,10 @@ module Sidebars
override :pill_count
def pill_count
strong_memoize(:pill_count) do
percentage = LearnGitlab::Onboarding.new(context.project.namespace).completed_percentage
percentage = LearnGitlab::Onboarding.new(
context.project.namespace,
context.current_user
).completed_percentage
"#{percentage}%"
end

View File

@ -22824,9 +22824,6 @@ msgstr ""
msgid "Learn GitLab - Ultimate trial"
msgstr ""
msgid "Learn GitLab|Trial only"
msgstr ""
msgid "Learn More"
msgstr ""
@ -22902,21 +22899,21 @@ msgstr ""
msgid "LearnGitLab|Add code owners"
msgstr ""
msgid "LearnGitLab|Add merge request approval"
msgid "LearnGitLab|Analyze your application for vulnerabilities with DAST"
msgstr ""
msgid "LearnGitLab|Complete these tasks first so you can enjoy GitLab's features to their fullest:"
msgstr ""
msgid "LearnGitLab|Create a repository"
msgstr ""
msgid "LearnGitLab|Create a workflow for your new workspace, and learn how GitLab features work together:"
msgstr ""
msgid "LearnGitLab|Create an issue"
msgstr ""
msgid "LearnGitLab|Create or import a repository"
msgstr ""
msgid "LearnGitLab|Create or import your first repository into your new project."
msgstr ""
@ -22959,22 +22956,25 @@ msgstr ""
msgid "LearnGitLab|Save time by automating your integration and deployment tasks."
msgstr ""
msgid "LearnGitLab|Scan dependencies for licenses"
msgstr ""
msgid "LearnGitLab|Scan dependencies for vulnerabilities"
msgstr ""
msgid "LearnGitLab|Scan your code to uncover vulnerabilities before deploying."
msgstr ""
msgid "LearnGitLab|Set up CI/CD"
msgstr ""
msgid "LearnGitLab|Set up your first project's CI/CD"
msgstr ""
msgid "LearnGitLab|Set up your workspace"
msgstr ""
msgid "LearnGitLab|Set-up CI/CD"
msgstr ""
msgid "LearnGitLab|Start a free Ultimate trial"
msgstr ""
msgid "LearnGitLab|Submit a merge request"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr ""
msgid "LearnGitLab|Submit a merge request (MR)"
@ -22992,6 +22992,9 @@ msgstr ""
msgid "LearnGitLab|Your team is growing! You've successfully invited new team members to the %{projectName} project."
msgstr ""
msgid "LearnGitlab|- Included in trial"
msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
@ -23001,9 +23004,6 @@ msgstr ""
msgid "LearnGitlab|Ok, let's go"
msgstr ""
msgid "LearnGitlab|Trial only"
msgstr ""
msgid "LearnGitlab|View administrator list"
msgstr ""

View File

@ -382,10 +382,17 @@ module QA
#
# @return [Regex]
def created_by_pattern
@created_by_pattern ||= /\n\n \*By gitlab-migration on \S+ \(imported from GitLab\)\*/
@created_by_pattern ||= /\n\n \*By #{importer_username_pattern} on \S+ \(imported from GitLab\)\*/
end
# Remove added prefixes and legacy diff format from comments
# Username of importer user for removal from comments and descriptions
#
# @return [String]
def importer_username_pattern
@importer_username_pattern ||= ENV['QA_LARGE_IMPORT_USER_PATTERN'] || "(gitlab-migration|GitLab QA Bot)"
end
# Remove added prefixes from comments
#
# @param [String] body
# @return [String]

View File

@ -65,7 +65,7 @@ RSpec.describe Import::BitbucketController do
.with(hash_including(
'grant_type' => 'authorization_code',
'code' => code,
redirect_uri: users_import_bitbucket_callback_url),
'redirect_uri' => users_import_bitbucket_callback_url),
{})
.and_return(access_token)
stub_omniauth_provider('bitbucket')

View File

@ -45,10 +45,12 @@ RSpec.describe 'Profile > Applications' do
let(:anonymous_token) { create(:oauth_access_token, resource_owner: user) }
context 'with multiple access token types and multiple owners' do
let!(:token2) { create(:oauth_access_token, application: application, resource_owner: user) }
let!(:other_user_token) { create(:oauth_access_token, application: application, resource_owner: other_user) }
before do
token.update_column(:created_at, created_at)
token2.update_column(:created_at, created_at - 1.day)
anonymous_token.update_columns(application_id: nil, created_at: 1.day.ago)
end

View File

@ -85,8 +85,6 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
@ -105,7 +103,8 @@ exports[`Learn GitLab renders correctly 1`] = `
</svg>
Invite your colleagues
<!---->
</span>
<!---->
@ -114,8 +113,6 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
@ -133,8 +130,9 @@ exports[`Learn GitLab renders correctly 1`] = `
/>
</svg>
Create or import a repository
Create a repository
<!---->
</span>
<!---->
@ -143,48 +141,23 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Set up CI/CD"
href="http://example.com/"
target="_self"
>
Set up CI/CD
</a>
<!---->
</div>
</div>
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Start a free Ultimate trial"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Start a free Ultimate trial
</a>
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="set_up_your_first_project_s_ci_cd"
href="http://example.com/"
target="_self"
>
Set up your first project's CI/CD
</a>
<!---->
</div>
<!---->
</div>
@ -192,31 +165,24 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<div
class="gl-font-style-italic gl-text-gray-500"
data-testid="trial-only"
>
Trial only
</div>
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Add code owners"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Add code owners
</a>
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="start_a_free_trial_of_gitlab_ultimate"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Start a free trial of GitLab Ultimate
</a>
<!---->
</div>
<!---->
</div>
@ -225,30 +191,62 @@ exports[`Learn GitLab renders correctly 1`] = `
class="gl-mb-4"
>
<div
class="gl-font-style-italic gl-text-gray-500"
data-testid="trial-only"
class="flex align-items-center"
>
Trial only
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="add_code_owners"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Add code owners
</a>
<span
class="gl-font-style-italic gl-text-gray-500"
data-testid="trial-only"
>
- Included in trial
</span>
</div>
<!---->
</div>
</div>
<div
class="gl-mb-4"
>
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Add merge request approval"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Add merge request approval
</a>
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="enable_require_merge_approvals"
href="http://example.com/"
rel="noopener noreferrer"
target="_blank"
>
Enable require merge approvals
</a>
<span
class="gl-font-style-italic gl-text-gray-500"
data-testid="trial-only"
>
- Included in trial
</span>
</div>
<!---->
</div>
@ -290,23 +288,23 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Create an issue"
href="http://example.com/"
target="_self"
>
Create an issue
</a>
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="create_an_issue"
href="http://example.com/"
target="_self"
>
Create an issue
</a>
<!---->
</div>
<!---->
</div>
@ -314,23 +312,23 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Submit a merge request"
href="http://example.com/"
target="_self"
>
Submit a merge request
</a>
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="submit_a_merge_request_mr"
href="http://example.com/"
target="_self"
>
Submit a merge request (MR)
</a>
<!---->
</div>
<!---->
</div>
@ -372,24 +370,24 @@ exports[`Learn GitLab renders correctly 1`] = `
<div
class="gl-mb-4"
>
<!---->
<div
class="flex align-items-center"
>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="Run a Security scan using CI/CD"
href="https://docs.gitlab.com/ee/foobar/"
rel="noopener noreferrer"
target="_blank"
>
Run a Security scan using CI/CD
</a>
<div>
<a
class="gl-link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="run_a_security_scan_using_ci_cd"
href="https://docs.gitlab.com/ee/foobar/"
rel="noopener noreferrer"
target="_blank"
>
Run a Security scan using CI/CD
</a>
<!---->
</div>
<!---->
</div>

View File

@ -1,57 +0,0 @@
import { shallowMount } from '@vue/test-utils';
import LearnGitlabInfoCard from '~/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue';
const defaultProps = {
title: 'Create Repository',
description: 'Some description',
actionLabel: 'Create Repository now',
url: 'https://example.com',
completed: false,
svg: 'https://example.com/illustration.svg',
};
describe('Learn GitLab Info Card', () => {
let wrapper;
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const createWrapper = (props = {}) => {
wrapper = shallowMount(LearnGitlabInfoCard, {
propsData: { ...defaultProps, ...props },
});
};
it('renders no icon when not completed', () => {
createWrapper({ completed: false });
expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(false);
});
it('renders the completion icon when completed', () => {
createWrapper({ completed: true });
expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(true);
});
it('renders no trial only when it is not required', () => {
createWrapper();
expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(false);
});
it('renders trial only when trial is required', () => {
createWrapper({ trialRequired: true });
expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(true);
});
it('renders completion icon when completed a trial-only feature', () => {
createWrapper({ trialRequired: true, completed: true });
expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(false);
expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(true);
});
});

View File

@ -119,7 +119,7 @@ describe('Learn GitLab Section Link', () => {
findUncompletedLink().trigger('click');
expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_link', {
label: 'Run a Security scan using CI/CD',
label: 'run_a_security_scan_using_ci_cd',
});
unmockTracking();
@ -164,7 +164,7 @@ describe('Learn GitLab Section Link', () => {
triggerEvent(openInviteMembesrModalLink().element);
expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_link', {
label: 'Invite your colleagues',
label: 'invite_your_colleagues',
property: 'Growth::Activation::Experiment::InviteForHelpContinuousOnboarding',
});
@ -203,7 +203,7 @@ describe('Learn GitLab Section Link', () => {
videoTutorialLink().trigger('click');
expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_video_link', {
label: 'Add code owners',
label: 'add_code_owners',
property: 'Growth::Conversion::Experiment::LearnGitLab',
context: {
data: {

View File

@ -0,0 +1,12 @@
import { shallowMount } from '@vue/test-utils';
import IncludedInTrialIndicator from '~/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue';
describe('Learn GitLab Trial Card', () => {
it('renders correctly', () => {
const wrapper = shallowMount(IncludedInTrialIndicator);
expect(wrapper.text()).toEqual('- Included in trial');
wrapper.destroy();
});
});

View File

@ -31,18 +31,30 @@ describe('Test reports app', () => {
const createComponent = ({ state = {} } = {}) => {
store = new Vuex.Store({
state: {
isLoading: false,
selectedSuiteIndex: null,
testReports,
...state,
modules: {
testReports: {
namespaced: true,
state: {
isLoading: false,
selectedSuiteIndex: null,
testReports,
...state,
},
actions: actionSpies,
getters,
},
},
actions: actionSpies,
getters,
});
jest.spyOn(store, 'registerModule').mockReturnValue(null);
wrapper = extendedWrapper(
shallowMount(TestReports, {
provide: {
blobPath: '/blob/path',
summaryEndpoint: '/summary.json',
suiteEndpoint: '/suite.json',
},
store,
}),
);

View File

@ -34,22 +34,32 @@ describe('Test reports suite table', () => {
const createComponent = ({ suite = testSuite, perPage = 20, errorMessage } = {}) => {
store = new Vuex.Store({
state: {
blobPath,
modules: {
testReports: {
test_suites: [suite],
namespaced: true,
state: {
blobPath,
testReports: {
test_suites: [suite],
},
selectedSuiteIndex: 0,
pageInfo: {
page: 1,
perPage,
},
errorMessage,
},
getters,
},
selectedSuiteIndex: 0,
pageInfo: {
page: 1,
perPage,
},
errorMessage,
},
getters,
});
wrapper = shallowMountExtended(SuiteTable, {
provide: {
blobPath: '/blob/path',
summaryEndpoint: '/summary.json',
suiteEndpoint: '/suite.json',
},
store,
stubs: { GlFriendlyWrap },
});

View File

@ -20,13 +20,23 @@ describe('Test reports summary table', () => {
const createComponent = (reports = null) => {
store = new Vuex.Store({
state: {
testReports: reports || testReports,
modules: {
testReports: {
namespaced: true,
state: {
testReports: reports || testReports,
},
getters,
},
},
getters,
});
wrapper = mount(SummaryTable, {
provide: {
blobPath: '/blob/path',
summaryEndpoint: '/summary.json',
suiteEndpoint: '/suite.json',
},
propsData: defaultProps,
store,
});

View File

@ -92,38 +92,6 @@ RSpec.describe LearnGitlabHelper do
it_behaves_like 'has all data'
it 'sets correct paths' do
expect(onboarding_actions_data).to match({
trial_started: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/issues/2\z})
),
pipeline_created: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/issues/7\z})
),
code_owners_enabled: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/issues/10\z})
),
required_mr_approvals_enabled: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/issues/11\z})
),
issue_created: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/issues\z})
),
git_write: a_hash_including(
url: a_string_matching(%r{/learn_gitlab\z})
),
user_added: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/project_members\z})
),
merge_request_created: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/merge_requests\z})
),
security_scan_enabled: a_hash_including(
url: a_string_matching(%r{/learn_gitlab/-/security/configuration\z})
)
})
end
it 'sets correct completion statuses' do
expect(onboarding_actions_data).to match({
issue_created: a_hash_including(completed: false),
@ -137,5 +105,58 @@ RSpec.describe LearnGitlabHelper do
security_scan_enabled: a_hash_including(completed: false)
})
end
describe 'security_actions_continuous_onboarding experiment' do
let(:base_paths) do
{
trial_started: a_hash_including(url: %r{/learn_gitlab/-/issues/2\z}),
pipeline_created: a_hash_including(url: %r{/learn_gitlab/-/issues/7\z}),
code_owners_enabled: a_hash_including(url: %r{/learn_gitlab/-/issues/10\z}),
required_mr_approvals_enabled: a_hash_including(url: %r{/learn_gitlab/-/issues/11\z}),
issue_created: a_hash_including(url: %r{/learn_gitlab/-/issues\z}),
git_write: a_hash_including(url: %r{/learn_gitlab\z}),
user_added: a_hash_including(url: %r{/learn_gitlab/-/project_members\z}),
merge_request_created: a_hash_including(url: %r{/learn_gitlab/-/merge_requests\z})
}
end
context 'when control' do
before do
stub_experiments(security_actions_continuous_onboarding: :control)
end
it 'sets correct paths' do
expect(onboarding_actions_data).to match(
base_paths.merge(
security_scan_enabled: a_hash_including(
url: %r{/learn_gitlab/-/security/configuration\z}
)
)
)
end
end
context 'when candidate' do
before do
stub_experiments(security_actions_continuous_onboarding: :candidate)
end
it 'sets correct paths' do
expect(onboarding_actions_data).to match(
base_paths.merge(
license_scanning_run: a_hash_including(
url: described_class::LICENSE_SCANNING_RUN_URL
),
secure_dependency_scanning_run: a_hash_including(
url: project_security_configuration_path(project, anchor: 'dependency-scanning')
),
secure_dast_run: a_hash_including(
url: project_security_configuration_path(project, anchor: 'dast')
)
)
)
end
end
end
end
end

View File

@ -21,8 +21,8 @@ RSpec.describe Gitlab::GitlabImport::Importer do
'name' => 'John Doe'
}
}
])
stub_request('issues/3/notes', [])
].to_json)
stub_request('issues/3/notes', [].to_json)
end
it 'persists issues' do

View File

@ -6,11 +6,14 @@ RSpec.describe LearnGitlab::Onboarding do
describe '#completed_percentage' do
let(:completed_actions) { {} }
let(:onboarding_progress) { build(:onboarding_progress, namespace: namespace, **completed_actions) }
let(:namespace) { build(:namespace) }
let(:namespace) { create(:namespace) }
let_it_be(:tracked_action_columns) do
tracked_actions = described_class::ACTION_ISSUE_IDS.keys + described_class::ACTION_PATHS
tracked_actions.map { |key| OnboardingProgress.column_name(key) }
[
*described_class::ACTION_ISSUE_IDS.keys,
*described_class::ACTION_PATHS,
:security_scan_enabled
].map { |key| OnboardingProgress.column_name(key) }
end
before do
@ -29,12 +32,6 @@ RSpec.describe LearnGitlab::Onboarding do
it { is_expected.to eq(0) }
end
context 'when one action has been completed' do
let(:completed_actions) { Hash[tracked_action_columns.first, Time.current] }
it { is_expected.to eq(11) }
end
context 'when all tracked actions have been completed' do
let(:completed_actions) do
tracked_action_columns.to_h { |action| [action, Time.current] }
@ -42,5 +39,25 @@ RSpec.describe LearnGitlab::Onboarding do
it { is_expected.to eq(100) }
end
describe 'security_actions_continuous_onboarding experiment' do
let(:completed_actions) { Hash[tracked_action_columns.first, Time.current] }
context 'when control' do
before do
stub_experiments(security_actions_continuous_onboarding: :control)
end
it { is_expected.to eq(11) }
end
context 'when candidate' do
before do
stub_experiments(security_actions_continuous_onboarding: :candidate)
end
it { is_expected.to eq(9) }
end
end
end
end

View File

@ -799,7 +799,7 @@ RSpec.describe Integration do
shared_examples '#api_field_names' do
it 'filters out secret fields' do
safe_fields = %w[some_safe_field safe_field url trojan_gift]
safe_fields = %w[some_safe_field safe_field url trojan_gift api_only_field]
expect(fake_integration.new).to have_attributes(
api_field_names: match_array(safe_fields)
@ -807,6 +807,12 @@ RSpec.describe Integration do
end
end
shared_examples '#form_fields' do
it 'filters out API only fields' do
expect(fake_integration.new.form_fields.pluck(:name)).not_to include('api_only_field')
end
end
context 'when the class overrides #fields' do
let(:fake_integration) do
Class.new(Integration) do
@ -824,7 +830,8 @@ RSpec.describe Integration do
{ name: 'safe_field' },
{ name: 'url' },
{ name: 'trojan_horse', type: 'password' },
{ name: 'trojan_gift', type: 'text' }
{ name: 'trojan_gift', type: 'text' },
{ name: 'api_only_field', api_only: true }
].shuffle
end
end
@ -832,6 +839,7 @@ RSpec.describe Integration do
it_behaves_like '#fields'
it_behaves_like '#api_field_names'
it_behaves_like '#form_fields'
end
context 'when the class uses the field DSL' do
@ -850,11 +858,13 @@ RSpec.describe Integration do
field :url
field :trojan_horse, type: 'password'
field :trojan_gift, type: 'text'
field :api_only_field, api_only: true
end
end
it_behaves_like '#fields'
it_behaves_like '#api_field_names'
it_behaves_like '#form_fields'
end
end

View File

@ -164,7 +164,7 @@ RSpec.describe Integrations::Jira do
subject(:fields) { integration.fields }
it 'returns custom fields' do
expect(fields.pluck(:name)).to eq(%w[url api_url username password])
expect(fields.pluck(:name)).to eq(%w[url api_url username password jira_issue_transition_id])
end
end

View File

@ -7,22 +7,40 @@ RSpec.describe OauthAccessToken do
let(:app_one) { create(:oauth_application) }
let(:app_two) { create(:oauth_application) }
let(:app_three) { create(:oauth_application) }
let(:tokens) { described_class.all }
let(:token) { create(:oauth_access_token, application_id: app_one.id) }
before do
create(:oauth_access_token, application_id: app_one.id)
create_list(:oauth_access_token, 2, resource_owner: user, application_id: app_two.id)
end
describe 'scopes' do
describe '.distinct_resource_owner_counts' do
let(:tokens) { described_class.all }
it 'returns unique owners' do
expect(tokens.count).to eq(3)
expect(tokens.distinct_resource_owner_counts([app_one])).to eq({ app_one.id => 1 })
expect(tokens.distinct_resource_owner_counts([app_two])).to eq({ app_two.id => 1 })
expect(tokens.distinct_resource_owner_counts([app_three])).to eq({})
expect(tokens.distinct_resource_owner_counts([app_one, app_two]))
.to eq({
app_one.id => 1,
app_two.id => 1
})
before do
token
create_list(:oauth_access_token, 2, resource_owner: user, application_id: app_two.id)
end
it 'returns unique owners' do
expect(tokens.count).to eq(3)
expect(tokens.distinct_resource_owner_counts([app_one])).to eq({ app_one.id => 1 })
expect(tokens.distinct_resource_owner_counts([app_two])).to eq({ app_two.id => 1 })
expect(tokens.distinct_resource_owner_counts([app_three])).to eq({})
expect(tokens.distinct_resource_owner_counts([app_one, app_two]))
.to eq({
app_one.id => 1,
app_two.id => 1
})
end
end
describe '.latest_per_application' do
let!(:app_two_token1) { create(:oauth_access_token, application: app_two) }
let!(:app_two_token2) { create(:oauth_access_token, application: app_two) }
let!(:app_three_token1) { create(:oauth_access_token, application: app_three) }
let!(:app_three_token2) { create(:oauth_access_token, application: app_three) }
it 'returns only the latest token for each application' do
expect(described_class.latest_per_application.map(&:id))
.to match_array([app_two_token2.id, app_three_token2.id])
end
end
end
end

View File

@ -363,6 +363,31 @@ RSpec.describe API::Integrations do
end
end
describe 'Jira integration' do
let(:integration_name) { 'jira' }
let(:params) do
{ url: 'https://jira.example.com', username: 'username', password: 'password' }
end
before do
project.create_jira_integration(active: true, properties: params)
end
it 'returns the jira_issue_transition_id for get request' do
get api("/projects/#{project.id}/#{endpoint}/#{integration_name}", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['properties']).to include('jira_issue_transition_id' => nil)
end
it 'returns the jira_issue_transition_id for put request' do
put api("/projects/#{project.id}/#{endpoint}/#{integration_name}", user), params: params.merge(jira_issue_transition_id: '1')
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['properties']['jira_issue_transition_id']).to eq('1')
end
end
describe 'Pipelines Email Integration' do
let(:integration_name) { 'pipelines-email' }

View File

@ -114,6 +114,6 @@ RSpec.describe Integrations::FieldEntity do
end
def integration_field(name)
integration.global_fields.find { |f| f[:name] == name }
integration.form_fields.find { |f| f[:name] == name }
end
end

View File

@ -20,6 +20,11 @@ RSpec.shared_examples 'integration settings form' do
"#{integration.title} field #{field_name} not present"
end
api_only_fields = integration.fields.select { _1[:api_only] }
api_only_fields.each do |field|
expect(page).not_to have_field("service[#{field.name}]", wait: 0)
end
sections = integration.sections
events = parse_json(trigger_events_for_integration(integration))

View File

@ -11,7 +11,7 @@ require (
github.com/disintegration/imaging v1.6.2
github.com/getsentry/raven-go v0.2.0
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f
github.com/golang/protobuf v1.5.2
github.com/gomodule/redigo v2.0.0+incompatible
github.com/gorilla/websocket v1.4.1
@ -33,7 +33,7 @@ require (
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
golang.org/x/net v0.0.0-20220531201128-c960675eff93
golang.org/x/tools v0.1.5
golang.org/x/tools v0.1.11
google.golang.org/grpc v1.45.0
google.golang.org/protobuf v1.28.0
honnef.co/go/tools v0.1.3
@ -102,7 +102,7 @@ require (
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/mod v0.5.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect

View File

@ -1,5 +1,6 @@
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg=
cloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@ -261,6 +262,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -368,9 +370,11 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/raven-go v0.1.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/getsentry/raven-go v0.1.2/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
@ -429,6 +433,7 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
@ -457,8 +462,8 @@ github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721 h1:KRMr9A3qfbVM7iV/WcLY/rL5LICqwMHLhwRXKu99fXw=
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg=
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -466,6 +471,7 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@ -495,6 +501,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
@ -502,6 +509,7 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -564,6 +572,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@ -581,6 +591,7 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.3-0.20210213123510-be4c235f9d1c/go.mod h1:RXwzibsL7UhPcEmGyGvXKJ8kyJsOCOEaLgGce4igMFs=
@ -611,6 +622,7 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
@ -627,6 +639,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
@ -747,6 +760,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -780,8 +794,10 @@ github.com/lightstep/lightstep-tracer-go v0.24.0/go.mod h1:RnONwHKg89zYPmF+Uig5P
github.com/lightstep/lightstep-tracer-go v0.25.0 h1:sGVnz8h3jTQuHKMbUe2949nXm3Sg09N1UcR3VoQNN5E=
github.com/lightstep/lightstep-tracer-go v0.25.0/go.mod h1:G1ZAEaqTHFPWpWunnbUn1ADEY/Jvzz7jIOaXwAfD6A8=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@ -791,6 +807,7 @@ github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/
github.com/mattn/go-ieproxy v0.0.3/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
github.com/mattn/go-ieproxy v0.0.6 h1:tVDlituRyeHMMkHpGpUu8CJG+hxPMwbYCkIUK2PUCbo=
github.com/mattn/go-ieproxy v0.0.6/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@ -824,6 +841,7 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@ -890,6 +908,7 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
@ -998,15 +1017,20 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9VrZuz3wSlI+OEI=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@ -1071,6 +1095,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
gitlab.com/gitlab-org/gitaly v1.68.0 h1:VlcJs1+PrhW7lqJUU7Fh1q8FMJujmbbivdfde/cwB98=
@ -1206,8 +1231,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1266,6 +1292,7 @@ golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -1275,6 +1302,7 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1298,6 +1326,7 @@ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1402,6 +1431,7 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1430,6 +1460,7 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1513,8 +1544,9 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1527,6 +1559,7 @@ gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
google.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@ -1585,6 +1618,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -1678,6 +1712,7 @@ google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de h1:9Ti5SG2U4cAcluryUo/sFay3TQKoxiFMfaT0pbizU7k=
google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=