Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f2ebc27236
commit
ef8c47e97e
|
@ -51,7 +51,6 @@ rules:
|
|||
# new ones, to ease migration to v7, so violations of each can be fixed
|
||||
# separately.
|
||||
vue/no-mutating-props: off
|
||||
vue/one-component-per-file: off
|
||||
vue/no-lone-template: off
|
||||
# END eslint-plugin-vue@7 overrides
|
||||
overrides:
|
||||
|
|
|
@ -1 +1 @@
|
|||
8.59.0
|
||||
8.60.0
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -462,7 +462,7 @@ group :ed25519 do
|
|||
end
|
||||
|
||||
# Gitaly GRPC protocol definitions
|
||||
gem 'gitaly', '~> 13.8.0.pre.rc2'
|
||||
gem 'gitaly', '~> 13.8.0.pre.rc3'
|
||||
|
||||
gem 'grpc', '~> 1.30.2'
|
||||
|
||||
|
|
|
@ -417,7 +417,7 @@ GEM
|
|||
rails (>= 3.2.0)
|
||||
git (1.7.0)
|
||||
rchardet (~> 1.8)
|
||||
gitaly (13.8.0.pre.rc2)
|
||||
gitaly (13.8.0.pre.rc3)
|
||||
grpc (~> 1.0)
|
||||
github-markup (1.7.0)
|
||||
gitlab-chronic (0.10.5)
|
||||
|
@ -1357,7 +1357,7 @@ DEPENDENCIES
|
|||
gettext (~> 3.3)
|
||||
gettext_i18n_rails (~> 1.8.0)
|
||||
gettext_i18n_rails_js (~> 1.3)
|
||||
gitaly (~> 13.8.0.pre.rc2)
|
||||
gitaly (~> 13.8.0.pre.rc3)
|
||||
github-markup (~> 1.7.0)
|
||||
gitlab-chronic (~> 0.10.5)
|
||||
gitlab-experiment (~> 0.4.5)
|
||||
|
|
|
@ -2,60 +2,42 @@
|
|||
import { GlAlert } from '@gitlab/ui';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import ServiceDeskSetting from './service_desk_setting.vue';
|
||||
import ServiceDeskService from '../services/service_desk_service';
|
||||
import eventHub from '../event_hub';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
export default {
|
||||
name: 'ServiceDeskRoot',
|
||||
components: {
|
||||
GlAlert,
|
||||
ServiceDeskSetting,
|
||||
},
|
||||
props: {
|
||||
inject: {
|
||||
initialIsEnabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
incomingEmail: {
|
||||
type: String,
|
||||
required: false,
|
||||
initialIncomingEmail: {
|
||||
default: '',
|
||||
},
|
||||
customEmail: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
customEmailEnabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
selectedTemplate: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
outgoingName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
projectKey: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
templates: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isEnabled: this.initialIsEnabled,
|
||||
|
@ -63,28 +45,21 @@ export default {
|
|||
isAlertShowing: false,
|
||||
alertVariant: 'danger',
|
||||
alertMessage: '',
|
||||
incomingEmail: this.initialIncomingEmail,
|
||||
updatedCustomEmail: this.customEmail,
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
eventHub.$on('serviceDeskEnabledCheckboxToggled', this.onEnableToggled);
|
||||
eventHub.$on('serviceDeskTemplateSave', this.onSaveTemplate);
|
||||
this.service = new ServiceDeskService(this.endpoint);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
eventHub.$off('serviceDeskEnabledCheckboxToggled', this.onEnableToggled);
|
||||
eventHub.$off('serviceDeskTemplateSave', this.onSaveTemplate);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onEnableToggled(isChecked) {
|
||||
this.isEnabled = isChecked;
|
||||
this.incomingEmail = '';
|
||||
|
||||
this.service
|
||||
.toggleServiceDesk(isChecked)
|
||||
const body = {
|
||||
service_desk_enabled: isChecked,
|
||||
};
|
||||
|
||||
return axios
|
||||
.put(this.endpoint, body)
|
||||
.then(({ data }) => {
|
||||
const email = data.service_desk_address;
|
||||
if (isChecked && !email) {
|
||||
|
@ -104,8 +79,16 @@ export default {
|
|||
|
||||
onSaveTemplate({ selectedTemplate, outgoingName, projectKey }) {
|
||||
this.isTemplateSaving = true;
|
||||
this.service
|
||||
.updateTemplate({ selectedTemplate, outgoingName, projectKey }, this.isEnabled)
|
||||
|
||||
const body = {
|
||||
issue_template_key: selectedTemplate,
|
||||
outgoing_name: outgoingName,
|
||||
project_key: projectKey,
|
||||
service_desk_enabled: this.isEnabled,
|
||||
};
|
||||
|
||||
return axios
|
||||
.put(this.endpoint, body)
|
||||
.then(({ data }) => {
|
||||
this.updatedCustomEmail = data?.service_desk_address;
|
||||
this.showAlert(__('Changes saved.'), 'success');
|
||||
|
@ -150,6 +133,8 @@ export default {
|
|||
:initial-project-key="projectKey"
|
||||
:templates="templates"
|
||||
:is-template-saving="isTemplateSaving"
|
||||
@save="onSaveTemplate"
|
||||
@toggle="onEnableToggled"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
<script>
|
||||
import { GlButton, GlFormSelect, GlToggle, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import eventHub from '../event_hub';
|
||||
|
||||
export default {
|
||||
name: 'ServiceDeskSetting',
|
||||
components: {
|
||||
ClipboardButton,
|
||||
GlButton,
|
||||
|
@ -15,7 +12,6 @@ export default {
|
|||
GlLoadingIcon,
|
||||
GlSprintf,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
isEnabled: {
|
||||
type: Boolean,
|
||||
|
@ -84,10 +80,10 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
onCheckboxToggle(isChecked) {
|
||||
eventHub.$emit('serviceDeskEnabledCheckboxToggled', isChecked);
|
||||
this.$emit('toggle', isChecked);
|
||||
},
|
||||
onSaveTemplate() {
|
||||
eventHub.$emit('serviceDeskTemplateSave', {
|
||||
this.$emit('save', {
|
||||
selectedTemplate: this.selectedTemplate,
|
||||
outgoingName: this.outgoingName,
|
||||
projectKey: this.projectKey,
|
||||
|
@ -111,7 +107,11 @@ export default {
|
|||
</label>
|
||||
<div v-if="isEnabled" class="row mt-3">
|
||||
<div class="col-md-9 mb-0">
|
||||
<strong id="incoming-email-describer" class="d-block mb-1">
|
||||
<strong
|
||||
id="incoming-email-describer"
|
||||
class="gl-display-block gl-mb-1"
|
||||
data-testid="incoming-email-describer"
|
||||
>
|
||||
{{ __('Email address to use for Support Desk') }}
|
||||
</strong>
|
||||
<template v-if="email">
|
||||
|
@ -128,11 +128,7 @@ export default {
|
|||
disabled="true"
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<clipboard-button
|
||||
:title="__('Copy')"
|
||||
:text="email"
|
||||
css-class="input-group-text qa-clipboard-button"
|
||||
/>
|
||||
<clipboard-button :title="__('Copy')" :text="email" css-class="input-group-text" />
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="hasCustomEmail" class="form-text text-muted">
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import createEventHub from '~/helpers/event_hub_factory';
|
||||
|
||||
export default createEventHub();
|
|
@ -3,43 +3,37 @@ import { parseBoolean } from '~/lib/utils/common_utils';
|
|||
import ServiceDeskRoot from './components/service_desk_root.vue';
|
||||
|
||||
export default () => {
|
||||
const serviceDeskRootElement = document.querySelector('.js-service-desk-setting-root');
|
||||
if (serviceDeskRootElement) {
|
||||
// eslint-disable-next-line no-new
|
||||
new Vue({
|
||||
el: serviceDeskRootElement,
|
||||
components: {
|
||||
ServiceDeskRoot,
|
||||
},
|
||||
data() {
|
||||
const { dataset } = serviceDeskRootElement;
|
||||
return {
|
||||
initialIsEnabled: parseBoolean(dataset.enabled),
|
||||
endpoint: dataset.endpoint,
|
||||
incomingEmail: dataset.incomingEmail,
|
||||
customEmail: dataset.customEmail,
|
||||
customEmailEnabled: parseBoolean(dataset.customEmailEnabled),
|
||||
selectedTemplate: dataset.selectedTemplate,
|
||||
outgoingName: dataset.outgoingName,
|
||||
projectKey: dataset.projectKey,
|
||||
templates: JSON.parse(dataset.templates),
|
||||
};
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('service-desk-root', {
|
||||
props: {
|
||||
initialIsEnabled: this.initialIsEnabled,
|
||||
endpoint: this.endpoint,
|
||||
incomingEmail: this.incomingEmail,
|
||||
customEmail: this.customEmail,
|
||||
customEmailEnabled: this.customEmailEnabled,
|
||||
selectedTemplate: this.selectedTemplate,
|
||||
outgoingName: this.outgoingName,
|
||||
projectKey: this.projectKey,
|
||||
templates: this.templates,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
const el = document.querySelector('.js-service-desk-setting-root');
|
||||
|
||||
if (!el) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
customEmail,
|
||||
customEmailEnabled,
|
||||
enabled,
|
||||
endpoint,
|
||||
incomingEmail,
|
||||
outgoingName,
|
||||
projectKey,
|
||||
selectedTemplate,
|
||||
templates,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
provide: {
|
||||
customEmail,
|
||||
customEmailEnabled: parseBoolean(customEmailEnabled),
|
||||
endpoint,
|
||||
initialIncomingEmail: incomingEmail,
|
||||
initialIsEnabled: parseBoolean(enabled),
|
||||
outgoingName,
|
||||
projectKey,
|
||||
selectedTemplate,
|
||||
templates: JSON.parse(templates),
|
||||
},
|
||||
render: (createElement) => createElement(ServiceDeskRoot),
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
class ServiceDeskService {
|
||||
constructor(endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
toggleServiceDesk(enable) {
|
||||
return axios.put(this.endpoint, { service_desk_enabled: enable });
|
||||
}
|
||||
|
||||
updateTemplate({ selectedTemplate, outgoingName, projectKey = '' }, isEnabled) {
|
||||
const body = {
|
||||
issue_template_key: selectedTemplate,
|
||||
outgoing_name: outgoingName,
|
||||
project_key: projectKey,
|
||||
service_desk_enabled: isEnabled,
|
||||
};
|
||||
return axios.put(this.endpoint, body);
|
||||
}
|
||||
}
|
||||
|
||||
export default ServiceDeskService;
|
|
@ -1,4 +1,6 @@
|
|||
<script>
|
||||
// Work around for https://github.com/vuejs/eslint-plugin-vue/issues/1411
|
||||
/* eslint-disable vue/one-component-per-file */
|
||||
import { GlDropdown } from '@gitlab/ui';
|
||||
import Tracking from '~/tracking';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<script>
|
||||
// Work around for https://github.com/vuejs/eslint-plugin-vue/issues/1411
|
||||
/* eslint-disable vue/one-component-per-file */
|
||||
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
|
|
|
@ -54,7 +54,7 @@ export default {
|
|||
class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1"
|
||||
:class="optionalClasses"
|
||||
>
|
||||
<div class="gl-display-flex gl-align-items-center gl-py-5">
|
||||
<div class="gl-display-flex gl-align-items-center gl-py-3">
|
||||
<div
|
||||
v-if="$slots['left-action']"
|
||||
class="gl-w-7 gl-display-none gl-display-sm-flex gl-justify-content-start gl-pl-2"
|
||||
|
@ -64,9 +64,7 @@ export default {
|
|||
<div
|
||||
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-fill-1"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column gl-justify-content-space-between gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
|
||||
>
|
||||
<div class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1">
|
||||
<div
|
||||
v-if="$slots['left-primary']"
|
||||
class="gl-display-flex gl-align-items-center gl-text-body gl-font-weight-bold gl-min-h-6 gl-min-w-0"
|
||||
|
@ -83,7 +81,7 @@ export default {
|
|||
</div>
|
||||
<div
|
||||
v-if="$slots['left-secondary']"
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1 gl-min-h-6 gl-min-w-0 gl-flex-fill-1"
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-fill-1"
|
||||
>
|
||||
<slot name="left-secondary"></slot>
|
||||
</div>
|
||||
|
@ -99,7 +97,7 @@ export default {
|
|||
</div>
|
||||
<div
|
||||
v-if="$slots['right-secondary']"
|
||||
class="gl-display-flex gl-align-items-center gl-mt-1 gl-min-h-6"
|
||||
class="gl-display-flex gl-align-items-center gl-min-h-6"
|
||||
>
|
||||
<slot name="right-secondary"></slot>
|
||||
</div>
|
||||
|
|
|
@ -42,8 +42,7 @@
|
|||
.login-box,
|
||||
.omniauth-container {
|
||||
box-shadow: 0 0 0 1px $border-color;
|
||||
border-bottom-right-radius: $border-radius;
|
||||
border-bottom-left-radius: $border-radius;
|
||||
border-radius: $border-radius;
|
||||
padding: 15px;
|
||||
|
||||
.login-heading h3 {
|
||||
|
|
|
@ -2093,8 +2093,7 @@ table.code {
|
|||
.login-page .login-box,
|
||||
.login-page .omniauth-container {
|
||||
box-shadow: 0 0 0 1px #dbdbdb;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
padding: 15px;
|
||||
}
|
||||
.login-page .login-box .nav .active a,
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Repositories
|
||||
# Finder for obtaining commits between two refs, with a Git trailer set.
|
||||
class CommitsWithTrailerFinder
|
||||
# The maximum number of commits to retrieve per page.
|
||||
#
|
||||
# This value is arbitrarily chosen. Lowering it means more Gitaly calls, but
|
||||
# less data being loaded into memory at once. Increasing it has the opposite
|
||||
# effect.
|
||||
#
|
||||
# This amount is based around the number of commits that usually go in a
|
||||
# GitLab release. Some examples for GitLab's own releases:
|
||||
#
|
||||
# * 13.6.0: 4636 commits
|
||||
# * 13.5.0: 5912 commits
|
||||
# * 13.4.0: 5541 commits
|
||||
#
|
||||
# Using this limit should result in most (very large) projects only needing
|
||||
# 5-10 Gitaly calls, while keeping memory usage at a reasonable amount.
|
||||
COMMITS_PER_PAGE = 1024
|
||||
|
||||
# The `project` argument specifies the project for which to obtain the
|
||||
# commits.
|
||||
#
|
||||
# The `from` and `to` arguments specify the range of commits to include. The
|
||||
# commit specified in `from` won't be included itself. The commit specified
|
||||
# in `to` _is_ included.
|
||||
#
|
||||
# The `per_page` argument specifies how many commits are retrieved in a single
|
||||
# Gitaly API call.
|
||||
def initialize(project:, from:, to:, per_page: COMMITS_PER_PAGE)
|
||||
@project = project
|
||||
@from = from
|
||||
@to = to
|
||||
@per_page = per_page
|
||||
end
|
||||
|
||||
# Fetches all commits that have the given trailer set.
|
||||
#
|
||||
# The commits are yielded to the supplied block in batches. This allows
|
||||
# other code to process these commits in batches too, instead of first
|
||||
# having to load all commits into memory.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# CommitsWithTrailerFinder.new(...).each_page('Signed-off-by') do |commits|
|
||||
# commits.each do |commit|
|
||||
# ...
|
||||
# end
|
||||
# end
|
||||
def each_page(trailer)
|
||||
return to_enum(__method__, trailer) unless block_given?
|
||||
|
||||
offset = 0
|
||||
response = fetch_commits
|
||||
|
||||
while response.any?
|
||||
commits = []
|
||||
|
||||
response.each do |commit|
|
||||
commits.push(commit) if commit.trailers.key?(trailer)
|
||||
end
|
||||
|
||||
yield commits
|
||||
|
||||
offset += response.length
|
||||
response = fetch_commits(offset)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_commits(offset = 0)
|
||||
range = "#{@from}..#{@to}"
|
||||
|
||||
@project
|
||||
.repository
|
||||
.commits(range, limit: @per_page, offset: offset, trailers: true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,24 +3,26 @@
|
|||
module Types
|
||||
module Notes
|
||||
class DiscussionType < BaseObject
|
||||
DiscussionID = ::Types::GlobalIDType[::Discussion]
|
||||
|
||||
graphql_name 'Discussion'
|
||||
|
||||
authorize :read_note
|
||||
|
||||
implements(Types::ResolvableInterface)
|
||||
|
||||
field :id, GraphQL::ID_TYPE, null: false,
|
||||
field :id, DiscussionID, null: false,
|
||||
description: "ID of this discussion"
|
||||
field :reply_id, GraphQL::ID_TYPE, null: false,
|
||||
field :reply_id, DiscussionID, null: false,
|
||||
description: 'ID used to reply to this discussion'
|
||||
field :created_at, Types::TimeType, null: false,
|
||||
description: "Timestamp of the discussion's creation"
|
||||
field :notes, Types::Notes::NoteType.connection_type, null: false,
|
||||
description: 'All notes in the discussion'
|
||||
|
||||
# The gem we use to generate Global IDs is hard-coded to work with
|
||||
# `id` properties. To generate a GID for the `reply_id` property,
|
||||
# we must use the ::Gitlab::GlobalId module.
|
||||
# DiscussionID.coerce_result is suitable here, but will always mark this
|
||||
# as being a 'Discussion'. Using `GlobalId.build` guarantees that we get
|
||||
# the correct class, and that it matches `id`.
|
||||
def reply_id
|
||||
::Gitlab::GlobalId.build(object, id: object.reply_id)
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ module Types
|
|||
|
||||
implements(Types::ResolvableInterface)
|
||||
|
||||
field :id, GraphQL::ID_TYPE, null: false,
|
||||
field :id, ::Types::GlobalIDType[::Note], null: false,
|
||||
description: 'ID of the note'
|
||||
|
||||
field :project, Types::ProjectType,
|
||||
|
|
|
@ -12,6 +12,9 @@ class MergeRequestContextCommit < ApplicationRecord
|
|||
validates :sha, presence: true
|
||||
validates :sha, uniqueness: { message: 'has already been added' }
|
||||
|
||||
serialize :trailers, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
validates :trailers, json_schema: { filename: 'git_trailers' }
|
||||
|
||||
# Sort by committed date in descending order to ensure latest commits comes on the top
|
||||
scope :order_by_committed_date_desc, -> { order('committed_date DESC') }
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
sha_attribute :sha
|
||||
alias_attribute :id, :sha
|
||||
|
||||
serialize :trailers, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
|
||||
validates :trailers, json_schema: { filename: 'git_trailers' }
|
||||
|
||||
# Deprecated; use `bulk_insert!` from `BulkInsertSafe` mixin instead.
|
||||
# cf. https://gitlab.com/gitlab-org/gitlab/issues/207989 for progress
|
||||
def self.create_bulk(merge_request_diff_id, commits)
|
||||
|
@ -23,7 +26,8 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
relative_order: index,
|
||||
sha: Gitlab::Database::ShaAttribute.serialize(sha), # rubocop:disable Cop/ActiveRecordSerialize
|
||||
authored_date: Gitlab::Database.sanitize_timestamp(commit_hash[:authored_date]),
|
||||
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date])
|
||||
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date]),
|
||||
trailers: commit_hash.fetch(:trailers, {}).to_json
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -1314,21 +1314,11 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def external_issue_tracker
|
||||
if has_external_issue_tracker.nil?
|
||||
cache_has_external_issue_tracker
|
||||
end
|
||||
cache_has_external_issue_tracker if has_external_issue_tracker.nil?
|
||||
|
||||
if has_external_issue_tracker?
|
||||
strong_memoize(:external_issue_tracker) do
|
||||
services.external_issue_trackers.first
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
return unless has_external_issue_tracker?
|
||||
|
||||
def cache_has_external_issue_tracker
|
||||
update_column(:has_external_issue_tracker, services.external_issue_trackers.any?) if Gitlab::Database.read_write?
|
||||
@external_issue_tracker ||= services.external_issue_trackers.first
|
||||
end
|
||||
|
||||
def external_references_supported?
|
||||
|
@ -2690,6 +2680,10 @@ class Project < ApplicationRecord
|
|||
def cache_has_external_wiki
|
||||
update_column(:has_external_wiki, services.external_wikis.any?) if Gitlab::Database.read_write?
|
||||
end
|
||||
|
||||
def cache_has_external_issue_tracker
|
||||
update_column(:has_external_issue_tracker, services.external_issue_trackers.any?) if Gitlab::Database.read_write?
|
||||
end
|
||||
end
|
||||
|
||||
Project.prepend_if_ee('EE::Project')
|
||||
|
|
|
@ -151,7 +151,8 @@ class Repository
|
|||
all: !!opts[:all],
|
||||
first_parent: !!opts[:first_parent],
|
||||
order: opts[:order],
|
||||
literal_pathspec: opts.fetch(:literal_pathspec, true)
|
||||
literal_pathspec: opts.fetch(:literal_pathspec, true),
|
||||
trailers: opts[:trailers]
|
||||
}
|
||||
|
||||
commits = Gitlab::Git::Commit.where(options)
|
||||
|
|
|
@ -46,7 +46,6 @@ class Service < ApplicationRecord
|
|||
after_initialize :initialize_properties
|
||||
|
||||
after_commit :reset_updated_properties
|
||||
after_commit :cache_project_has_external_issue_tracker
|
||||
|
||||
belongs_to :project, inverse_of: :services
|
||||
belongs_to :group, inverse_of: :services
|
||||
|
@ -438,10 +437,6 @@ class Service < ApplicationRecord
|
|||
ProjectServiceWorker.perform_async(id, data)
|
||||
end
|
||||
|
||||
def external_issue_tracker?
|
||||
category == :issue_tracker && active?
|
||||
end
|
||||
|
||||
def external_wiki?
|
||||
type == 'ExternalWikiService' && active?
|
||||
end
|
||||
|
@ -461,12 +456,6 @@ class Service < ApplicationRecord
|
|||
errors.add(:project_id, 'The service cannot belong to both a project and a group') if project_id && group_id
|
||||
end
|
||||
|
||||
def cache_project_has_external_issue_tracker
|
||||
if project && !project.destroyed?
|
||||
project.cache_has_external_issue_tracker
|
||||
end
|
||||
end
|
||||
|
||||
def valid_recipients?
|
||||
activated? && !importing?
|
||||
end
|
||||
|
|
|
@ -11,8 +11,6 @@ class BulkCreateIntegrationService
|
|||
service_list = ServiceList.new(batch, service_hash, association).to_array
|
||||
|
||||
Service.transaction do
|
||||
run_callbacks(batch) if association == 'project'
|
||||
|
||||
results = bulk_insert(*service_list)
|
||||
|
||||
if integration.data_fields_present?
|
||||
|
@ -33,14 +31,6 @@ class BulkCreateIntegrationService
|
|||
klass.insert_all(items_to_insert, returning: [:id])
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def run_callbacks(batch)
|
||||
if integration.external_issue_tracker?
|
||||
Project.where(id: batch.select(:id)).update_all(has_external_issue_tracker: true)
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def service_hash
|
||||
if integration.template?
|
||||
integration.to_service_hash
|
||||
|
|
|
@ -41,7 +41,6 @@ module FeatureFlags
|
|||
|
||||
def sync_to_jira(feature_flag)
|
||||
return unless feature_flag.present?
|
||||
return unless Feature.enabled?(:jira_sync_feature_flags, feature_flag.project)
|
||||
|
||||
seq_id = ::Atlassian::JiraConnect::Client.generate_update_sequence_id
|
||||
feature_flag.run_after_commit do
|
||||
|
|
|
@ -66,7 +66,8 @@ module MergeRequests
|
|||
relative_order: index,
|
||||
sha: sha,
|
||||
authored_date: Gitlab::Database.sanitize_timestamp(commit_hash[:authored_date]),
|
||||
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date])
|
||||
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date]),
|
||||
trailers: commit_hash.fetch(:trailers, {}).to_json
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"description": "Git trailer key/value pairs",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,8 @@
|
|||
%td.text-content
|
||||
%p
|
||||
= _('By authenticating with an account tied to an Enterprise e-mail address, it is understood that this account is an Enterprise User. ')
|
||||
= _('To ensure no loss of personal content, an Individual User should create a separate account under their own personal email address, not tied to the Enterprise email domain or name-space.')
|
||||
= _('To ensure no loss of personal content, this account should only be used for matters related to %{group_name}.') % { group_name: member_source.human_name }
|
||||
= _('For individual use, create a separate account under your personal email address, not tied to the Enterprise email domain or group.')
|
||||
- unless @user.confirmed?
|
||||
%p
|
||||
= _('To get started, click the link below to confirm your account.')
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
|
||||
<%= _('By authenticating with an account tied to an Enterprise e-mail address, it is understood that this account is an Enterprise User. ') %>
|
||||
<%= _('To ensure no loss of personal content, an Individual User should create a separate account under their own personal email address, not tied to the Enterprise email domain or name-space.') %>
|
||||
<%= _('To ensure no loss of personal content, this account should only be used for matters related to %{group_name}.') % { group_name: member_source.human_name } %>
|
||||
<%= _('For individual use, create a separate account under your personal email address, not tied to the Enterprise email domain or group.') %>
|
||||
<%- unless @user.confirmed? %>
|
||||
<%= _('To get started, click the link below to confirm your account.') %>
|
||||
<%= confirmation_url(@user, confirmation_token: @user.confirmation_token) %>
|
|
@ -14,7 +14,6 @@ module JiraConnect
|
|||
feature_flag = ::Operations::FeatureFlag.find_by_id(feature_flag_id)
|
||||
|
||||
return unless feature_flag
|
||||
return unless Feature.enabled?(:jira_sync_feature_flags, feature_flag.project)
|
||||
|
||||
::JiraConnect::SyncService
|
||||
.new(feature_flag.project)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add PostgreSQL trigger to maintain projects.has_external_issue_tracker
|
||||
merge_request: 51852
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update Workhorse to v8.60.0
|
||||
merge_request: 51965
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Reduce vertical padding of registry list item
|
||||
merge_request: 51961
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable synchronization of feature flags to Jira
|
||||
merge_request: 51796
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add finder for getting commits with a trailer set
|
||||
merge_request: 49243
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix top border-radius of the login box
|
||||
merge_request: 51950
|
||||
author: Yogi (@yo)
|
||||
type: fixed
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: jira_sync_feature_flags
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50390
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/296990
|
||||
milestone: '13.8'
|
||||
type: development
|
||||
group: group::ecosystem
|
||||
default_enabled: false
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddMergeRequestDiffCommitTrailers < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column :merge_request_diff_commits, :trailers, :jsonb, default: {}, null: false
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_column :merge_request_diff_commits, :trailers
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddMergeRequestContextCommitTrailers < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
add_column :merge_request_context_commits, :trailers, :jsonb, default: {}, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddHasExternalIssueTrackerTrigger < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::SchemaHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
FUNCTION_NAME = 'set_has_external_issue_tracker'
|
||||
TRIGGER_ON_INSERT_NAME = 'trigger_has_external_issue_tracker_on_insert'
|
||||
TRIGGER_ON_UPDATE_NAME = 'trigger_has_external_issue_tracker_on_update'
|
||||
TRIGGER_ON_DELETE_NAME = 'trigger_has_external_issue_tracker_on_delete'
|
||||
|
||||
def up
|
||||
create_trigger_function(FUNCTION_NAME, replace: true) do
|
||||
<<~SQL
|
||||
UPDATE projects SET has_external_issue_tracker = (
|
||||
EXISTS
|
||||
(
|
||||
SELECT 1
|
||||
FROM services
|
||||
WHERE project_id = COALESCE(NEW.project_id, OLD.project_id)
|
||||
AND active = TRUE
|
||||
AND category = 'issue_tracker'
|
||||
)
|
||||
)
|
||||
WHERE projects.id = COALESCE(NEW.project_id, OLD.project_id);
|
||||
RETURN NULL;
|
||||
SQL
|
||||
end
|
||||
|
||||
execute(<<~SQL)
|
||||
CREATE TRIGGER #{TRIGGER_ON_INSERT_NAME}
|
||||
AFTER INSERT ON services
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.category = 'issue_tracker' AND NEW.active = TRUE AND NEW.project_id IS NOT NULL)
|
||||
EXECUTE FUNCTION #{FUNCTION_NAME}();
|
||||
SQL
|
||||
|
||||
execute(<<~SQL)
|
||||
CREATE TRIGGER #{TRIGGER_ON_UPDATE_NAME}
|
||||
AFTER UPDATE ON services
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.category = 'issue_tracker' AND OLD.active != NEW.active AND NEW.project_id IS NOT NULL)
|
||||
EXECUTE FUNCTION #{FUNCTION_NAME}();
|
||||
SQL
|
||||
|
||||
execute(<<~SQL)
|
||||
CREATE TRIGGER #{TRIGGER_ON_DELETE_NAME}
|
||||
AFTER DELETE ON services
|
||||
FOR EACH ROW
|
||||
WHEN (OLD.category = 'issue_tracker' AND OLD.active = TRUE AND OLD.project_id IS NOT NULL)
|
||||
EXECUTE FUNCTION #{FUNCTION_NAME}();
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
drop_trigger(:services, TRIGGER_ON_INSERT_NAME)
|
||||
drop_trigger(:services, TRIGGER_ON_UPDATE_NAME)
|
||||
drop_trigger(:services, TRIGGER_ON_DELETE_NAME)
|
||||
drop_function(FUNCTION_NAME)
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
4aeff45663a9f5a41a8dd92298afb4b0b57aa6f190f4648455df2fa1e39e174f
|
|
@ -0,0 +1 @@
|
|||
3e867ceefcab4f043b89d3c04e6e0a1182423039e1a9245e611128efe77c0e88
|
|
@ -0,0 +1 @@
|
|||
c0d22d00d52a516347930e1a36f350113c0949214925176f08ceed81999746bd
|
|
@ -10,6 +10,26 @@ CREATE EXTENSION IF NOT EXISTS btree_gist;
|
|||
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
CREATE FUNCTION set_has_external_issue_tracker() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
UPDATE projects SET has_external_issue_tracker = (
|
||||
EXISTS
|
||||
(
|
||||
SELECT 1
|
||||
FROM services
|
||||
WHERE project_id = COALESCE(NEW.project_id, OLD.project_id)
|
||||
AND active = TRUE
|
||||
AND category = 'issue_tracker'
|
||||
)
|
||||
)
|
||||
WHERE projects.id = COALESCE(NEW.project_id, OLD.project_id);
|
||||
RETURN NULL;
|
||||
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION set_has_external_wiki() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
|
@ -13863,7 +13883,8 @@ CREATE TABLE merge_request_context_commits (
|
|||
committer_name text,
|
||||
committer_email text,
|
||||
message text,
|
||||
merge_request_id bigint
|
||||
merge_request_id bigint,
|
||||
trailers jsonb DEFAULT '{}'::jsonb NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE merge_request_context_commits_id_seq
|
||||
|
@ -13885,7 +13906,8 @@ CREATE TABLE merge_request_diff_commits (
|
|||
author_email text,
|
||||
committer_name text,
|
||||
committer_email text,
|
||||
message text
|
||||
message text,
|
||||
trailers jsonb DEFAULT '{}'::jsonb NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE merge_request_diff_details (
|
||||
|
@ -23637,6 +23659,12 @@ ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_p
|
|||
|
||||
CREATE TRIGGER table_sync_trigger_ee39a25f9d AFTER INSERT OR DELETE OR UPDATE ON audit_events FOR EACH ROW EXECUTE PROCEDURE table_sync_function_2be879775d();
|
||||
|
||||
CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON services FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE PROCEDURE set_has_external_issue_tracker();
|
||||
|
||||
CREATE TRIGGER trigger_has_external_issue_tracker_on_insert AFTER INSERT ON services FOR EACH ROW WHEN ((((new.category)::text = 'issue_tracker'::text) AND (new.active = true) AND (new.project_id IS NOT NULL))) EXECUTE PROCEDURE set_has_external_issue_tracker();
|
||||
|
||||
CREATE TRIGGER trigger_has_external_issue_tracker_on_update AFTER UPDATE ON services FOR EACH ROW WHEN ((((new.category)::text = 'issue_tracker'::text) AND (old.active <> new.active) AND (new.project_id IS NOT NULL))) EXECUTE PROCEDURE set_has_external_issue_tracker();
|
||||
|
||||
CREATE TRIGGER trigger_has_external_wiki_on_delete AFTER DELETE ON services FOR EACH ROW WHEN ((((old.type)::text = 'ExternalWikiService'::text) AND (old.project_id IS NOT NULL))) EXECUTE PROCEDURE set_has_external_wiki();
|
||||
|
||||
CREATE TRIGGER trigger_has_external_wiki_on_insert AFTER INSERT ON services FOR EACH ROW WHEN (((new.active = true) AND ((new.type)::text = 'ExternalWikiService'::text) AND (new.project_id IS NOT NULL))) EXECUTE PROCEDURE set_has_external_wiki();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
extends: substitution
|
||||
message: 'Use "administration", "administrator", "administer", or "Admin Area" instead of "admin" or "admin area".'
|
||||
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html
|
||||
# Do not set `level: error`, as our docs refer to other docs which use "admin" and "Admin"
|
||||
level: warning
|
||||
ignorecase: true
|
||||
swap:
|
||||
|
|
|
@ -7878,7 +7878,7 @@ type Discussion implements ResolvableInterface {
|
|||
"""
|
||||
ID of this discussion
|
||||
"""
|
||||
id: ID!
|
||||
id: DiscussionID!
|
||||
|
||||
"""
|
||||
All notes in the discussion
|
||||
|
@ -7908,7 +7908,7 @@ type Discussion implements ResolvableInterface {
|
|||
"""
|
||||
ID used to reply to this discussion
|
||||
"""
|
||||
replyId: ID!
|
||||
replyId: DiscussionID!
|
||||
|
||||
"""
|
||||
Indicates if the object can be resolved
|
||||
|
@ -16154,7 +16154,7 @@ type Note implements ResolvableInterface {
|
|||
"""
|
||||
ID of the note
|
||||
"""
|
||||
id: ID!
|
||||
id: NoteID!
|
||||
|
||||
"""
|
||||
The position of this note on a diff
|
||||
|
|
|
@ -21766,7 +21766,7 @@
|
|||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"name": "DiscussionID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
|
@ -21841,7 +21841,7 @@
|
|||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"name": "DiscussionID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
|
@ -47730,7 +47730,7 @@
|
|||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"name": "NoteID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1301,9 +1301,9 @@ Aggregated summary of changes.
|
|||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `createdAt` | Time! | Timestamp of the discussion's creation |
|
||||
| `id` | ID! | ID of this discussion |
|
||||
| `id` | DiscussionID! | ID of this discussion |
|
||||
| `notes` | NoteConnection! | All notes in the discussion |
|
||||
| `replyId` | ID! | ID used to reply to this discussion |
|
||||
| `replyId` | DiscussionID! | ID used to reply to this discussion |
|
||||
| `resolvable` | Boolean! | Indicates if the object can be resolved |
|
||||
| `resolved` | Boolean! | Indicates if the object is resolved |
|
||||
| `resolvedAt` | Time | Timestamp of when the object was resolved |
|
||||
|
@ -2429,7 +2429,7 @@ Autogenerated return type of NamespaceIncreaseStorageTemporarily.
|
|||
| `confidential` | Boolean | Indicates if this note is confidential |
|
||||
| `createdAt` | Time! | Timestamp of the note creation |
|
||||
| `discussion` | Discussion | The discussion this note is a part of |
|
||||
| `id` | ID! | ID of the note |
|
||||
| `id` | NoteID! | ID of the note |
|
||||
| `position` | DiffPosition | The position of this note on a diff |
|
||||
| `project` | Project | Project associated with the note |
|
||||
| `resolvable` | Boolean! | Indicates if the object can be resolved |
|
||||
|
|
|
@ -20,7 +20,13 @@ Features include:
|
|||
- **Mention that a commit or MR resolves or closes a specific Jira issue** and when it's merged to the default branch:
|
||||
- The GitLab MR displays a note that it closed the Jira issue. Prior to the merge, MRs indicate which issue they close.
|
||||
- The Jira issue shows the activity and is closed or otherwise transitioned as specified in your GitLab settings.
|
||||
- **View a list of Jira issues directly in GitLab** **(PREMIUM)**
|
||||
- **Run a pipeline** on an MR linked to a Jira issue:
|
||||
- The Jira issue shows the current pipeline status (in the sidebar as "builds").
|
||||
- **Deploy to an environment** from an MR linked to a Jira issue:
|
||||
- The Jira issue shows the status of the deployment (in the sidebar as "deployments").
|
||||
- **Create or modify a feature flag** that mentions a Jira issue in its description:
|
||||
- The Jira issue shows the details of the feature-flag (in the sidebar as "feature flags").
|
||||
- **View a list of Jira issues** directly in GitLab **(PREMIUM)**
|
||||
|
||||
For additional features, you can install the
|
||||
[Jira Development Panel integration](../../../integration/jira_development_panel.md).
|
||||
|
@ -29,6 +35,9 @@ This enables you to:
|
|||
- In a Jira issue, display relevant GitLab information in the [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/), including related branches, commits, and merge requests.
|
||||
- Use Jira [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html) in GitLab to add Jira comments, log time spent on the issue, or apply any issue transition.
|
||||
|
||||
Some features (such as showing pipeline, deployment, and feature flags in Jira
|
||||
issues) are only available when using the [Jira Development Panel integration](../../../integration/jira_development_panel.md).
|
||||
|
||||
See the [feature comparison](jira_integrations.md#feature-comparison) for more details.
|
||||
|
||||
## Configuration
|
||||
|
|
|
@ -176,8 +176,7 @@ This feature might not be available to you. Check the **version history** note a
|
|||
|
||||
When editing the **Reviewers** field in a new or existing merge request, GitLab
|
||||
displays the name of the matching [approval rule](merge_request_approvals.md#approval-rules)
|
||||
below the name of each suggested reviewer. [Code Owners](../code_owners.md) are displayed as **Code Owner** without group detail.
|
||||
We intend to iterate on this feature in future releases.
|
||||
below the name of each suggested reviewer. [Code Owners](../code_owners.md) are displayed as `Codeowner` without group detail.
|
||||
|
||||
This example shows reviewers and approval rules when creating a new merge request:
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ module Atlassian
|
|||
private
|
||||
|
||||
def store_ff_info(project:, feature_flags:, **opts)
|
||||
return unless Feature.enabled?(:jira_sync_feature_flags, project)
|
||||
|
||||
items = feature_flags.map { |flag| ::Atlassian::JiraConnect::Serializers::FeatureFlagEntity.represent(flag, opts) }
|
||||
items.reject! { |item| item.issue_keys.empty? }
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ module Gitlab
|
|||
SERIALIZE_KEYS = [
|
||||
:id, :message, :parent_ids,
|
||||
:authored_date, :author_name, :author_email,
|
||||
:committed_date, :committer_name, :committer_email
|
||||
:committed_date, :committer_name, :committer_email, :trailers
|
||||
].freeze
|
||||
|
||||
attr_accessor(*SERIALIZE_KEYS)
|
||||
|
@ -389,6 +389,7 @@ module Gitlab
|
|||
@committer_name = commit.committer.name.dup
|
||||
@committer_email = commit.committer.email.dup
|
||||
@parent_ids = Array(commit.parent_ids)
|
||||
@trailers = Hash[commit.trailers.map { |t| [t.key, t.value] }]
|
||||
end
|
||||
|
||||
# Gitaly provides a UNIX timestamp in author.date.seconds, and a timezone
|
||||
|
|
|
@ -103,6 +103,7 @@ module Gitlab
|
|||
@committer_name = committer[:name]
|
||||
@committer_email = committer[:email]
|
||||
@parent_ids = commit.parents.map(&:oid)
|
||||
@trailers = Hash[commit.trailers]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -335,7 +335,8 @@ module Gitlab
|
|||
all: !!options[:all],
|
||||
first_parent: !!options[:first_parent],
|
||||
global_options: parse_global_options!(options),
|
||||
disable_walk: true # This option is deprecated. The 'walk' implementation is being removed.
|
||||
disable_walk: true, # This option is deprecated. The 'walk' implementation is being removed.
|
||||
trailers: options[:trailers]
|
||||
)
|
||||
request.after = GitalyClient.timestamp(options[:after]) if options[:after]
|
||||
request.before = GitalyClient.timestamp(options[:before]) if options[:before]
|
||||
|
|
|
@ -19,8 +19,8 @@ module Gitlab
|
|||
value
|
||||
when URI::GID
|
||||
GlobalID.new(value)
|
||||
when Integer
|
||||
raise CoerceError, 'Cannot coerce Integer' unless model_name.present?
|
||||
when Integer, String
|
||||
raise CoerceError, "Cannot coerce #{value.class}" unless model_name.present?
|
||||
|
||||
GlobalID.new(::Gitlab::GlobalId.build(model_name: model_name, id: value))
|
||||
else
|
||||
|
|
|
@ -12650,6 +12650,9 @@ msgstr ""
|
|||
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
|
||||
msgstr ""
|
||||
|
||||
msgid "For individual use, create a separate account under your personal email address, not tied to the Enterprise email domain or group."
|
||||
msgstr ""
|
||||
|
||||
msgid "For internal projects, any logged in user except external users can view pipelines and access job details (output logs and artifacts)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -29658,7 +29661,7 @@ msgstr ""
|
|||
msgid "To define internal users, first enable new users set to external"
|
||||
msgstr ""
|
||||
|
||||
msgid "To ensure no loss of personal content, an Individual User should create a separate account under their own personal email address, not tied to the Enterprise email domain or name-space."
|
||||
msgid "To ensure no loss of personal content, this account should only be used for matters related to %{group_name}."
|
||||
msgstr ""
|
||||
|
||||
msgid "To further protect your account, consider configuring a %{mfa_link_start}two-factor authentication%{mfa_link_end} method."
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Repositories::CommitsWithTrailerFinder do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
describe '#each_page' do
|
||||
it 'only yields commits with the given trailer' do
|
||||
finder = described_class.new(
|
||||
project: project,
|
||||
from: '570e7b2abdd848b95f2f578043fc23bd6f6fd24d',
|
||||
to: 'c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd'
|
||||
)
|
||||
|
||||
commits = finder.each_page('Signed-off-by').to_a.flatten
|
||||
|
||||
expect(commits.length).to eq(1)
|
||||
expect(commits.first.id).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
|
||||
expect(commits.first.trailers).to eq(
|
||||
'Signed-off-by' => 'Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>'
|
||||
)
|
||||
end
|
||||
|
||||
it 'supports paginating of commits' do
|
||||
finder = described_class.new(
|
||||
project: project,
|
||||
from: 'c1acaa58bbcbc3eafe538cb8274ba387047b69f8',
|
||||
to: '5937ac0a7beb003549fc5fd26fc247adbce4a52e',
|
||||
per_page: 1
|
||||
)
|
||||
|
||||
commits = finder.each_page('Signed-off-by')
|
||||
|
||||
expect(commits.count).to eq(4)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@ describe('Applications', () => {
|
|||
gon.features = gon.features || {};
|
||||
});
|
||||
|
||||
const createApp = ({ applications, type, propsData } = {}, isShallow) => {
|
||||
const createComponent = ({ applications, type, propsData } = {}, isShallow) => {
|
||||
const mountMethod = isShallow ? shallowMount : mount;
|
||||
|
||||
wrapper = mountMethod(Applications, {
|
||||
|
@ -29,7 +29,7 @@ describe('Applications', () => {
|
|||
});
|
||||
};
|
||||
|
||||
const createShallowApp = (options) => createApp(options, true);
|
||||
const createShallowComponent = (options) => createComponent(options, true);
|
||||
const findByTestId = (id) => wrapper.find(`[data-testid="${id}"]`);
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
|
@ -37,7 +37,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('Project cluster applications', () => {
|
||||
beforeEach(() => {
|
||||
createApp({ type: CLUSTER_TYPE.PROJECT });
|
||||
createComponent({ type: CLUSTER_TYPE.PROJECT });
|
||||
});
|
||||
|
||||
it('renders a row for Ingress', () => {
|
||||
|
@ -82,7 +82,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('Group cluster applications', () => {
|
||||
beforeEach(() => {
|
||||
createApp({ type: CLUSTER_TYPE.GROUP });
|
||||
createComponent({ type: CLUSTER_TYPE.GROUP });
|
||||
});
|
||||
|
||||
it('renders a row for Ingress', () => {
|
||||
|
@ -128,7 +128,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('Instance cluster applications', () => {
|
||||
beforeEach(() => {
|
||||
createApp({ type: CLUSTER_TYPE.INSTANCE });
|
||||
createComponent({ type: CLUSTER_TYPE.INSTANCE });
|
||||
});
|
||||
|
||||
it('renders a row for Ingress', () => {
|
||||
|
@ -174,14 +174,14 @@ describe('Applications', () => {
|
|||
|
||||
describe('Helm application', () => {
|
||||
it('does not render a row for Helm Tiller', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
expect(wrapper.find('.js-cluster-application-row-helm').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ingress application', () => {
|
||||
it('shows the correct warning message', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
expect(findByTestId('ingressCostWarning').element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -195,7 +195,7 @@ describe('Applications', () => {
|
|||
},
|
||||
};
|
||||
|
||||
beforeEach(() => createShallowApp(propsData));
|
||||
beforeEach(() => createShallowComponent(propsData));
|
||||
|
||||
it('renders IngressModsecuritySettings', () => {
|
||||
const modsecuritySettings = wrapper.find(IngressModsecuritySettings);
|
||||
|
@ -206,7 +206,7 @@ describe('Applications', () => {
|
|||
describe('when installed', () => {
|
||||
describe('with ip address', () => {
|
||||
it('renders ip address with a clipboard button', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
ingress: {
|
||||
title: 'Ingress',
|
||||
|
@ -225,7 +225,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('with hostname', () => {
|
||||
it('renders hostname with a clipboard button', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
ingress: {
|
||||
title: 'Ingress',
|
||||
|
@ -255,7 +255,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('without ip address', () => {
|
||||
it('renders an input text with a loading icon and an alert text', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
ingress: {
|
||||
title: 'Ingress',
|
||||
|
@ -272,7 +272,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('before installing', () => {
|
||||
it('does not render the IP address', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.text()).not.toContain('Ingress IP Address');
|
||||
expect(wrapper.find('.js-endpoint').exists()).toBe(false);
|
||||
|
@ -282,13 +282,13 @@ describe('Applications', () => {
|
|||
|
||||
describe('Cert-Manager application', () => {
|
||||
it('shows the correct description', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
expect(findByTestId('certManagerDescription').element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('when not installed', () => {
|
||||
it('renders email & allows editing', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
cert_manager: {
|
||||
title: 'Cert-Manager',
|
||||
|
@ -305,7 +305,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('when installed', () => {
|
||||
it('renders email in readonly', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
cert_manager: {
|
||||
title: 'Cert-Manager',
|
||||
|
@ -324,7 +324,7 @@ describe('Applications', () => {
|
|||
describe('Jupyter application', () => {
|
||||
describe('with ingress installed with ip & jupyter installable', () => {
|
||||
it('renders hostname active input', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
ingress: {
|
||||
title: 'Ingress',
|
||||
|
@ -342,7 +342,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('with ingress installed without external ip', () => {
|
||||
it('does not render hostname input', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
ingress: { title: 'Ingress', status: 'installed' },
|
||||
},
|
||||
|
@ -356,7 +356,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('with ingress & jupyter installed', () => {
|
||||
it('renders readonly input', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
ingress: {
|
||||
title: 'Ingress',
|
||||
|
@ -375,7 +375,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('without ingress installed', () => {
|
||||
beforeEach(() => {
|
||||
createApp();
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('does not render input', () => {
|
||||
|
@ -388,7 +388,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('Prometheus application', () => {
|
||||
it('shows the correct description', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
expect(findByTestId('prometheusDescription').element).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -414,14 +414,14 @@ describe('Applications', () => {
|
|||
let knativeDomainEditor;
|
||||
|
||||
beforeEach(() => {
|
||||
createShallowApp(propsData);
|
||||
createShallowComponent(propsData);
|
||||
jest.spyOn(eventHub, '$emit');
|
||||
|
||||
knativeDomainEditor = wrapper.find(KnativeDomainEditor);
|
||||
});
|
||||
|
||||
it('shows the correct description', async () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
wrapper.setProps({
|
||||
providerType: PROVIDER_TYPE.GCP,
|
||||
preInstalledKnative: true,
|
||||
|
@ -487,7 +487,7 @@ describe('Applications', () => {
|
|||
},
|
||||
};
|
||||
|
||||
beforeEach(() => createShallowApp(propsData));
|
||||
beforeEach(() => createShallowComponent(propsData));
|
||||
|
||||
it('renders the correct Component', () => {
|
||||
const crossplane = wrapper.find(CrossplaneProviderStack);
|
||||
|
@ -495,7 +495,7 @@ describe('Applications', () => {
|
|||
});
|
||||
|
||||
it('shows the correct description', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
expect(findByTestId('crossplaneDescription').element).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -503,7 +503,7 @@ describe('Applications', () => {
|
|||
describe('Elastic Stack application', () => {
|
||||
describe('with elastic stack installable', () => {
|
||||
it('renders the install button enabled', () => {
|
||||
createApp();
|
||||
createComponent();
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
|
@ -517,7 +517,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('elastic stack installed', () => {
|
||||
it('renders uninstall button', () => {
|
||||
createApp({
|
||||
createComponent({
|
||||
applications: {
|
||||
elastic_stack: { title: 'Elastic Stack', status: 'installed' },
|
||||
},
|
||||
|
@ -535,7 +535,7 @@ describe('Applications', () => {
|
|||
});
|
||||
|
||||
describe('Fluentd application', () => {
|
||||
beforeEach(() => createShallowApp());
|
||||
beforeEach(() => createShallowComponent());
|
||||
|
||||
it('renders the correct Component', () => {
|
||||
expect(wrapper.find(FluentdOutputSettings).exists()).toBe(true);
|
||||
|
@ -544,7 +544,7 @@ describe('Applications', () => {
|
|||
|
||||
describe('Cilium application', () => {
|
||||
it('shows the correct description', () => {
|
||||
createApp({ propsData: { ciliumHelpPath: 'cilium-help-path' } });
|
||||
createComponent({ propsData: { ciliumHelpPath: 'cilium-help-path' } });
|
||||
expect(findByTestId('ciliumDescription').element).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ exports[`packages_list_row renders 1`] = `
|
|||
data-qa-selector="package_row"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-py-5"
|
||||
class="gl-display-flex gl-align-items-center gl-py-3"
|
||||
>
|
||||
<!---->
|
||||
|
||||
|
@ -14,7 +14,7 @@ exports[`packages_list_row renders 1`] = `
|
|||
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-fill-1"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column gl-justify-content-space-between gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
|
||||
class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-text-body gl-font-weight-bold gl-min-h-6 gl-min-w-0"
|
||||
|
@ -40,7 +40,7 @@ exports[`packages_list_row renders 1`] = `
|
|||
</div>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1 gl-min-h-6 gl-min-w-0 gl-flex-fill-1"
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-fill-1"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex"
|
||||
|
@ -85,7 +85,7 @@ exports[`packages_list_row renders 1`] = `
|
|||
</div>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mt-1 gl-min-h-6"
|
||||
class="gl-display-flex gl-align-items-center gl-min-h-6"
|
||||
>
|
||||
<span>
|
||||
<gl-sprintf-stub
|
||||
|
|
|
@ -1,20 +1,36 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { GlAlert } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import ServiceDeskRoot from '~/projects/settings_service_desk/components/service_desk_root.vue';
|
||||
import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import ServiceDeskRoot from '~/projects/settings_service_desk/components/service_desk_root.vue';
|
||||
import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue';
|
||||
|
||||
describe('ServiceDeskRoot', () => {
|
||||
const endpoint = '/gitlab-org/gitlab-test/service_desk';
|
||||
const initialIncomingEmail = 'servicedeskaddress@example.com';
|
||||
let axiosMock;
|
||||
let wrapper;
|
||||
let spy;
|
||||
|
||||
const provideData = {
|
||||
customEmail: 'custom.email@example.com',
|
||||
customEmailEnabled: true,
|
||||
endpoint: '/gitlab-org/gitlab-test/service_desk',
|
||||
initialIncomingEmail: 'servicedeskaddress@example.com',
|
||||
initialIsEnabled: true,
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
projectKey: 'key',
|
||||
selectedTemplate: 'Bug',
|
||||
templates: ['Bug', 'Documentation'],
|
||||
};
|
||||
|
||||
const getAlertText = () => wrapper.find(GlAlert).text();
|
||||
|
||||
const createComponent = () => shallowMount(ServiceDeskRoot, { provide: provideData });
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock = new AxiosMockAdapter(axios);
|
||||
spy = jest.spyOn(axios, 'put');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -25,156 +41,122 @@ describe('ServiceDeskRoot', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('sends a request to toggle service desk off when the toggle is clicked from the on state', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK);
|
||||
describe('ServiceDeskSetting component', () => {
|
||||
it('is rendered', () => {
|
||||
wrapper = createComponent();
|
||||
|
||||
spy = jest.spyOn(axios, 'put');
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: true,
|
||||
initialIncomingEmail,
|
||||
endpoint,
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('button.gl-toggle').trigger('click');
|
||||
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(spy).toHaveBeenCalledWith(endpoint, { service_desk_enabled: false });
|
||||
});
|
||||
});
|
||||
|
||||
it('sends a request to toggle service desk on when the toggle is clicked from the off state', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK);
|
||||
|
||||
spy = jest.spyOn(axios, 'put');
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: false,
|
||||
initialIncomingEmail: '',
|
||||
endpoint,
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('button.gl-toggle').trigger('click');
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(spy).toHaveBeenCalledWith(endpoint, { service_desk_enabled: true });
|
||||
});
|
||||
});
|
||||
|
||||
it('shows an error message when there is an issue toggling service desk on', () => {
|
||||
axiosMock.onPut(endpoint).networkError();
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: false,
|
||||
initialIncomingEmail: '',
|
||||
endpoint,
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('button.gl-toggle').trigger('click');
|
||||
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(wrapper.html()).toContain('An error occurred while enabling Service Desk.');
|
||||
});
|
||||
});
|
||||
|
||||
it('sends a request to update template when the "Save template" button is clicked', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK);
|
||||
|
||||
spy = jest.spyOn(axios, 'put');
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: true,
|
||||
endpoint,
|
||||
initialIncomingEmail,
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
templates: ['Bug', 'Documentation'],
|
||||
projectKey: 'key',
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('button.btn-success').trigger('click');
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(spy).toHaveBeenCalledWith(endpoint, {
|
||||
issue_template_key: 'Bug',
|
||||
outgoing_name: 'GitLab Support Bot',
|
||||
project_key: 'key',
|
||||
service_desk_enabled: true,
|
||||
expect(wrapper.find(ServiceDeskSetting).props()).toEqual({
|
||||
customEmail: provideData.customEmail,
|
||||
customEmailEnabled: provideData.customEmailEnabled,
|
||||
incomingEmail: provideData.initialIncomingEmail,
|
||||
initialOutgoingName: provideData.outgoingName,
|
||||
initialProjectKey: provideData.projectKey,
|
||||
initialSelectedTemplate: provideData.selectedTemplate,
|
||||
isEnabled: provideData.initialIsEnabled,
|
||||
isTemplateSaving: false,
|
||||
templates: provideData.templates,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('saves the template when the "Save template" button is clicked', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK);
|
||||
describe('toggle event', () => {
|
||||
describe('when toggling service desk on', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper = createComponent();
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: true,
|
||||
endpoint,
|
||||
initialIncomingEmail,
|
||||
selectedTemplate: 'Bug',
|
||||
templates: ['Bug', 'Documentation'],
|
||||
},
|
||||
});
|
||||
wrapper.find(ServiceDeskSetting).vm.$emit('toggle', true);
|
||||
|
||||
wrapper.find('button.btn-success').trigger('click');
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(wrapper.html()).toContain('Changes saved.');
|
||||
it('sends a request to turn service desk on', () => {
|
||||
axiosMock.onPut(provideData.endpoint).replyOnce(httpStatusCodes.OK);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith(provideData.endpoint, { service_desk_enabled: true });
|
||||
});
|
||||
|
||||
it('shows a message when there is an error', () => {
|
||||
axiosMock.onPut(provideData.endpoint).networkError();
|
||||
|
||||
expect(getAlertText()).toContain('An error occurred while enabling Service Desk.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('shows an error message when there is an issue saving the template', () => {
|
||||
axiosMock.onPut(endpoint).networkError();
|
||||
describe('when toggling service desk off', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper = createComponent();
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: true,
|
||||
endpoint,
|
||||
initialIncomingEmail,
|
||||
selectedTemplate: 'Bug',
|
||||
templates: ['Bug', 'Documentation'],
|
||||
},
|
||||
});
|
||||
wrapper.find(ServiceDeskSetting).vm.$emit('toggle', false);
|
||||
|
||||
wrapper.find('button.btn-success').trigger('click');
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(wrapper.html()).toContain('An error occured while saving changes:');
|
||||
it('sends a request to turn service desk off', () => {
|
||||
axiosMock.onPut(provideData.endpoint).replyOnce(httpStatusCodes.OK);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith(provideData.endpoint, { service_desk_enabled: false });
|
||||
});
|
||||
|
||||
it('shows a message when there is an error', () => {
|
||||
axiosMock.onPut(provideData.endpoint).networkError();
|
||||
|
||||
expect(getAlertText()).toContain('An error occurred while disabling Service Desk.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('passes customEmail through updatedCustomEmail correctly', () => {
|
||||
const customEmail = 'foo';
|
||||
|
||||
wrapper = mount(ServiceDeskRoot, {
|
||||
propsData: {
|
||||
initialIsEnabled: true,
|
||||
endpoint,
|
||||
customEmail,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(ServiceDeskSetting).props('customEmail')).toEqual(customEmail);
|
||||
describe('save event', () => {
|
||||
describe('successful request', () => {
|
||||
beforeEach(async () => {
|
||||
axiosMock.onPut(provideData.endpoint).replyOnce(httpStatusCodes.OK);
|
||||
|
||||
wrapper = createComponent();
|
||||
|
||||
const payload = {
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
projectKey: 'key',
|
||||
};
|
||||
|
||||
wrapper.find(ServiceDeskSetting).vm.$emit('save', payload);
|
||||
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('sends a request to update template', async () => {
|
||||
expect(spy).toHaveBeenCalledWith(provideData.endpoint, {
|
||||
issue_template_key: 'Bug',
|
||||
outgoing_name: 'GitLab Support Bot',
|
||||
project_key: 'key',
|
||||
service_desk_enabled: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows success message', () => {
|
||||
expect(getAlertText()).toContain('Changes saved.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unsuccessful request', () => {
|
||||
beforeEach(async () => {
|
||||
axiosMock.onPut(provideData.endpoint).networkError();
|
||||
|
||||
wrapper = createComponent();
|
||||
|
||||
const payload = {
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
projectKey: 'key',
|
||||
};
|
||||
|
||||
wrapper.find(ServiceDeskSetting).vm.$emit('save', payload);
|
||||
|
||||
await waitForPromises();
|
||||
});
|
||||
|
||||
it('shows an error message', () => {
|
||||
expect(getAlertText()).toContain('An error occured while saving changes:');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,63 +1,68 @@
|
|||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import eventHub from '~/projects/settings_service_desk/event_hub';
|
||||
import { GlButton, GlFormSelect, GlLoadingIcon, GlToggle } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import ServiceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
|
||||
describe('ServiceDeskSetting', () => {
|
||||
let wrapper;
|
||||
|
||||
const findButton = () => wrapper.find(GlButton);
|
||||
const findClipboardButton = () => wrapper.find(ClipboardButton);
|
||||
const findIncomingEmail = () => wrapper.findByTestId('incoming-email');
|
||||
const findIncomingEmailLabel = () => wrapper.findByTestId('incoming-email-describer');
|
||||
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
||||
const findTemplateDropdown = () => wrapper.find(GlFormSelect);
|
||||
const findToggle = () => wrapper.find(GlToggle);
|
||||
|
||||
const createComponent = ({ props = {}, mountFunction = shallowMount } = {}) =>
|
||||
extendedWrapper(
|
||||
mountFunction(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
...props,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
const findTemplateDropdown = () => wrapper.find('#service-desk-template-select');
|
||||
const findIncomingEmail = () => wrapper.find('[data-testid="incoming-email"]');
|
||||
|
||||
describe('when isEnabled=true', () => {
|
||||
describe('only isEnabled', () => {
|
||||
describe('as project admin', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallowMount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
},
|
||||
});
|
||||
wrapper = createComponent();
|
||||
});
|
||||
|
||||
it('should see activation checkbox', () => {
|
||||
expect(wrapper.find('#service-desk-checkbox').exists()).toBe(true);
|
||||
expect(findToggle().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should see main panel with the email info', () => {
|
||||
expect(wrapper.find('#incoming-email-describer').exists()).toBe(true);
|
||||
expect(findIncomingEmailLabel().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should see loading spinner and not the incoming email', () => {
|
||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
|
||||
expect(findLoadingIcon().exists()).toBe(true);
|
||||
expect(findIncomingEmail().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('service desk toggle', () => {
|
||||
it('emits an event to turn on Service Desk when clicked', () => {
|
||||
const eventSpy = jest.fn();
|
||||
eventHub.$on('serviceDeskEnabledCheckboxToggled', eventSpy);
|
||||
it('emits an event to turn on Service Desk when clicked', async () => {
|
||||
wrapper = createComponent();
|
||||
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: false,
|
||||
},
|
||||
});
|
||||
findToggle().vm.$emit('change', true);
|
||||
|
||||
wrapper.find('#service-desk-checkbox').trigger('click');
|
||||
await nextTick();
|
||||
|
||||
expect(eventSpy).toHaveBeenCalledWith(true);
|
||||
|
||||
eventHub.$off('serviceDeskEnabledCheckboxToggled', eventSpy);
|
||||
eventSpy.mockRestore();
|
||||
expect(wrapper.emitted('toggle')[0]).toEqual([true]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -65,23 +70,23 @@ describe('ServiceDeskSetting', () => {
|
|||
const incomingEmail = 'foo@bar.com';
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
incomingEmail,
|
||||
},
|
||||
wrapper = createComponent({
|
||||
props: { incomingEmail },
|
||||
});
|
||||
});
|
||||
|
||||
it('should see email and not the loading spinner', () => {
|
||||
expect(findIncomingEmail().element.value).toEqual(incomingEmail);
|
||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders a copy to clipboard button', () => {
|
||||
expect(wrapper.find('.qa-clipboard-button').exists()).toBe(true);
|
||||
expect(wrapper.find('.qa-clipboard-button').element.dataset.clipboardText).toBe(
|
||||
incomingEmail,
|
||||
expect(findClipboardButton().exists()).toBe(true);
|
||||
expect(findClipboardButton().props()).toEqual(
|
||||
expect.objectContaining({
|
||||
title: 'Copy',
|
||||
text: incomingEmail,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -92,12 +97,8 @@ describe('ServiceDeskSetting', () => {
|
|||
const customEmail = 'custom@bar.com';
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
incomingEmail,
|
||||
customEmail,
|
||||
},
|
||||
wrapper = createComponent({
|
||||
props: { incomingEmail, customEmail },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -110,12 +111,8 @@ describe('ServiceDeskSetting', () => {
|
|||
const email = 'foo@bar.com';
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
incomingEmail: email,
|
||||
customEmail: email,
|
||||
},
|
||||
wrapper = createComponent({
|
||||
props: { incomingEmail: email, customEmail: email },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -127,21 +124,13 @@ describe('ServiceDeskSetting', () => {
|
|||
|
||||
describe('templates dropdown', () => {
|
||||
it('renders a dropdown to choose a template', () => {
|
||||
wrapper = shallowMount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
},
|
||||
});
|
||||
wrapper = createComponent();
|
||||
|
||||
expect(wrapper.find('#service-desk-template-select').exists()).toBe(true);
|
||||
expect(findTemplateDropdown().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders a dropdown with a default value of ""', () => {
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
},
|
||||
});
|
||||
wrapper = createComponent({ mountFunction: mount });
|
||||
|
||||
expect(findTemplateDropdown().element.value).toEqual('');
|
||||
});
|
||||
|
@ -149,23 +138,18 @@ describe('ServiceDeskSetting', () => {
|
|||
it('renders a dropdown with a value of "Bug" when it is the initial value', () => {
|
||||
const templates = ['Bug', 'Documentation', 'Security release'];
|
||||
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
initialSelectedTemplate: 'Bug',
|
||||
templates,
|
||||
},
|
||||
wrapper = createComponent({
|
||||
props: { initialSelectedTemplate: 'Bug', templates },
|
||||
mountFunction: mount,
|
||||
});
|
||||
|
||||
expect(findTemplateDropdown().element.value).toEqual('Bug');
|
||||
});
|
||||
|
||||
it('renders a dropdown with no options when the project has no templates', () => {
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
templates: [],
|
||||
},
|
||||
wrapper = createComponent({
|
||||
props: { templates: [] },
|
||||
mountFunction: mount,
|
||||
});
|
||||
|
||||
// The dropdown by default has one empty option
|
||||
|
@ -174,11 +158,10 @@ describe('ServiceDeskSetting', () => {
|
|||
|
||||
it('renders a dropdown with options when the project has templates', () => {
|
||||
const templates = ['Bug', 'Documentation', 'Security release'];
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
templates,
|
||||
},
|
||||
|
||||
wrapper = createComponent({
|
||||
props: { templates },
|
||||
mountFunction: mount,
|
||||
});
|
||||
|
||||
// An empty-named template is prepended so the user can select no template
|
||||
|
@ -199,78 +182,59 @@ describe('ServiceDeskSetting', () => {
|
|||
|
||||
describe('save button', () => {
|
||||
it('renders a save button to save a template', () => {
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
},
|
||||
});
|
||||
wrapper = createComponent();
|
||||
|
||||
expect(wrapper.find('button.btn-success').text()).toContain('Save changes');
|
||||
expect(findButton().text()).toContain('Save changes');
|
||||
});
|
||||
|
||||
it('emits a save event with the chosen template when the save button is clicked', () => {
|
||||
const eventSpy = jest.fn();
|
||||
eventHub.$on('serviceDeskTemplateSave', eventSpy);
|
||||
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
it('emits a save event with the chosen template when the save button is clicked', async () => {
|
||||
wrapper = createComponent({
|
||||
props: {
|
||||
initialSelectedTemplate: 'Bug',
|
||||
initialOutgoingName: 'GitLab Support Bot',
|
||||
initialProjectKey: 'key',
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('button.btn-success').trigger('click');
|
||||
findButton().vm.$emit('click');
|
||||
|
||||
expect(eventSpy).toHaveBeenCalledWith({
|
||||
await nextTick();
|
||||
|
||||
const payload = {
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
projectKey: 'key',
|
||||
});
|
||||
};
|
||||
|
||||
eventHub.$off('serviceDeskTemplateSave', eventSpy);
|
||||
eventSpy.mockRestore();
|
||||
expect(wrapper.emitted('save')[0]).toEqual([payload]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when isEnabled=false', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = shallowMount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: false,
|
||||
},
|
||||
wrapper = createComponent({
|
||||
props: { isEnabled: false },
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render email panel', () => {
|
||||
expect(wrapper.find('#incoming-email-describer').exists()).toBe(false);
|
||||
expect(findIncomingEmailLabel().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not render template dropdown', () => {
|
||||
expect(wrapper.find('#service-desk-template-select').exists()).toBe(false);
|
||||
expect(findTemplateDropdown().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not render template save button', () => {
|
||||
expect(wrapper.find('button.btn-success').exists()).toBe(false);
|
||||
expect(findButton().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('emits an event to turn on Service Desk when the toggle is clicked', () => {
|
||||
const eventSpy = jest.fn();
|
||||
eventHub.$on('serviceDeskEnabledCheckboxToggled', eventSpy);
|
||||
it('emits an event to turn on Service Desk when the toggle is clicked', async () => {
|
||||
findToggle().vm.$emit('change', false);
|
||||
|
||||
wrapper = mount(ServiceDeskSetting, {
|
||||
propsData: {
|
||||
isEnabled: true,
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
wrapper.find('#service-desk-checkbox').trigger('click');
|
||||
|
||||
expect(eventSpy).toHaveBeenCalledWith(false);
|
||||
|
||||
eventHub.$off('serviceDeskEnabledCheckboxToggled', eventSpy);
|
||||
eventSpy.mockRestore();
|
||||
expect(wrapper.emitted('toggle')[0]).toEqual([false]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import ServiceDeskService from '~/projects/settings_service_desk/services/service_desk_service';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
|
||||
describe('ServiceDeskService', () => {
|
||||
const endpoint = `/gitlab-org/gitlab-test/service_desk`;
|
||||
const dummyResponse = { message: 'Dummy response' };
|
||||
const errorMessage = 'Network Error';
|
||||
let axiosMock;
|
||||
let service;
|
||||
|
||||
beforeEach(() => {
|
||||
axiosMock = new AxiosMockAdapter(axios);
|
||||
service = new ServiceDeskService(endpoint);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
axiosMock.restore();
|
||||
});
|
||||
|
||||
describe('toggleServiceDesk', () => {
|
||||
it('makes a request to set service desk', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse);
|
||||
|
||||
return service.toggleServiceDesk(true).then((response) => {
|
||||
expect(response.data).toEqual(dummyResponse);
|
||||
});
|
||||
});
|
||||
|
||||
it('fails on error response', () => {
|
||||
axiosMock.onPut(endpoint).networkError();
|
||||
|
||||
return service.toggleServiceDesk(true).catch((error) => {
|
||||
expect(error.message).toBe(errorMessage);
|
||||
});
|
||||
});
|
||||
|
||||
it('makes a request with the expected body', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse);
|
||||
|
||||
const spy = jest.spyOn(axios, 'put');
|
||||
|
||||
service.toggleServiceDesk(true);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith(endpoint, {
|
||||
service_desk_enabled: true,
|
||||
});
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateTemplate', () => {
|
||||
it('makes a request to update template', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse);
|
||||
|
||||
return service
|
||||
.updateTemplate(
|
||||
{
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
},
|
||||
true,
|
||||
)
|
||||
.then((response) => {
|
||||
expect(response.data).toEqual(dummyResponse);
|
||||
});
|
||||
});
|
||||
|
||||
it('fails on error response', () => {
|
||||
axiosMock.onPut(endpoint).networkError();
|
||||
|
||||
return service
|
||||
.updateTemplate(
|
||||
{
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
},
|
||||
true,
|
||||
)
|
||||
.catch((error) => {
|
||||
expect(error.message).toBe(errorMessage);
|
||||
});
|
||||
});
|
||||
|
||||
it('makes a request with the expected body', () => {
|
||||
axiosMock.onPut(endpoint).replyOnce(httpStatusCodes.OK, dummyResponse);
|
||||
|
||||
const spy = jest.spyOn(axios, 'put');
|
||||
|
||||
service.updateTemplate(
|
||||
{
|
||||
selectedTemplate: 'Bug',
|
||||
outgoingName: 'GitLab Support Bot',
|
||||
projectKey: 'key',
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith(endpoint, {
|
||||
issue_template_key: 'Bug',
|
||||
outgoing_name: 'GitLab Support Bot',
|
||||
project_key: 'key',
|
||||
service_desk_enabled: true,
|
||||
});
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
// Work around for https://github.com/vuejs/eslint-plugin-vue/issues/1411
|
||||
/* eslint-disable vue/one-component-per-file */
|
||||
import { setHTMLFixture } from 'helpers/fixtures';
|
||||
import Tracking, { initUserTracking, initDefaultTrackers } from '~/tracking';
|
||||
|
||||
|
|
|
@ -303,24 +303,6 @@ RSpec.describe Atlassian::JiraConnect::Client do
|
|||
expect(response['errorMessages']).to eq(['a: X', 'a: Y', 'b: Z'])
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not call the API if the feature flag is not enabled' do
|
||||
stub_feature_flags(jira_sync_feature_flags: false)
|
||||
|
||||
expect(subject).not_to receive(:post)
|
||||
|
||||
subject.send(:store_ff_info, project: project, feature_flags: feature_flags)
|
||||
end
|
||||
|
||||
it 'does call the API if the feature flag enabled for the project' do
|
||||
stub_feature_flags(jira_sync_feature_flags: project)
|
||||
|
||||
expect(subject).to receive(:post).with('/rest/featureflags/0.1/bulk', {
|
||||
flags: Array, properties: Hash
|
||||
}).and_call_original
|
||||
|
||||
subject.send(:store_ff_info, project: project, feature_flags: feature_flags)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#store_build_info' do
|
||||
|
|
|
@ -720,7 +720,8 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
|
|||
committer_name: "Dmitriy Zaporozhets",
|
||||
id: SeedRepo::Commit::ID,
|
||||
message: "tree css fixes",
|
||||
parent_ids: ["874797c3a73b60d2187ed6e2fcabd289ff75171e"]
|
||||
parent_ids: ["874797c3a73b60d2187ed6e2fcabd289ff75171e"],
|
||||
trailers: {}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -231,6 +231,7 @@ MergeRequestDiffCommit:
|
|||
- committer_name
|
||||
- committer_email
|
||||
- message
|
||||
- trailers
|
||||
MergeRequestDiffFile:
|
||||
- merge_request_diff_id
|
||||
- relative_order
|
||||
|
@ -255,6 +256,7 @@ MergeRequestContextCommit:
|
|||
- committer_email
|
||||
- message
|
||||
- merge_request_id
|
||||
- trailers
|
||||
MergeRequestContextCommitDiffFile:
|
||||
- sha
|
||||
- relative_order
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
require_migration!
|
||||
|
||||
RSpec.describe AddHasExternalIssueTrackerTrigger do
|
||||
let(:migration) { described_class.new }
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
let(:projects) { table(:projects) }
|
||||
let(:services) { table(:services) }
|
||||
|
||||
before do
|
||||
@namespace = namespaces.create!(name: 'foo', path: 'foo')
|
||||
@project = projects.create!(namespace_id: @namespace.id)
|
||||
end
|
||||
|
||||
describe '#up' do
|
||||
before do
|
||||
migrate!
|
||||
end
|
||||
|
||||
describe 'INSERT trigger' do
|
||||
it 'sets `has_external_issue_tracker` to true when active `issue_tracker` is inserted' do
|
||||
expect do
|
||||
services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
end.to change { @project.reload.has_external_issue_tracker }.to(true)
|
||||
end
|
||||
|
||||
it 'does not set `has_external_issue_tracker` to true when service is for a different project' do
|
||||
different_project = projects.create!(namespace_id: @namespace.id)
|
||||
|
||||
expect do
|
||||
services.create!(category: 'issue_tracker', active: true, project_id: different_project.id)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
|
||||
it 'does not set `has_external_issue_tracker` to true when inactive `issue_tracker` is inserted' do
|
||||
expect do
|
||||
services.create!(category: 'issue_tracker', active: false, project_id: @project.id)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
|
||||
it 'does not set `has_external_issue_tracker` to true when a non-`issue tracker` active service is inserted' do
|
||||
expect do
|
||||
services.create!(category: 'my_type', active: true, project_id: @project.id)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'UPDATE trigger' do
|
||||
it 'sets `has_external_issue_tracker` to true when `issue_tracker` is made active' do
|
||||
service = services.create!(category: 'issue_tracker', active: false, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.update!(active: true)
|
||||
end.to change { @project.reload.has_external_issue_tracker }.to(true)
|
||||
end
|
||||
|
||||
it 'sets `has_external_issue_tracker` to false when `issue_tracker` is made inactive' do
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.update!(active: false)
|
||||
end.to change { @project.reload.has_external_issue_tracker }.to(false)
|
||||
end
|
||||
|
||||
it 'sets `has_external_issue_tracker` to false when `issue_tracker` is made inactive, and an inactive `issue_tracker` exists' do
|
||||
services.create!(category: 'issue_tracker', active: false, project_id: @project.id)
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.update!(active: false)
|
||||
end.to change { @project.reload.has_external_issue_tracker }.to(false)
|
||||
end
|
||||
|
||||
it 'does not change `has_external_issue_tracker` when `issue_tracker` is made inactive, if an active `issue_tracker` exists' do
|
||||
services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.update!(active: false)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
|
||||
it 'does not change `has_external_issue_tracker` when service is for a different project' do
|
||||
different_project = projects.create!(namespace_id: @namespace.id)
|
||||
service = services.create!(category: 'issue_tracker', active: false, project_id: different_project.id)
|
||||
|
||||
expect do
|
||||
service.update!(active: true)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE trigger' do
|
||||
it 'sets `has_external_issue_tracker` to false when `issue_tracker` is deleted' do
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.delete
|
||||
end.to change { @project.reload.has_external_issue_tracker }.to(false)
|
||||
end
|
||||
|
||||
it 'sets `has_external_issue_tracker` to false when `issue_tracker` is deleted, if an inactive `issue_tracker` still exists' do
|
||||
services.create!(category: 'issue_tracker', active: false, project_id: @project.id)
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.delete
|
||||
end.to change { @project.reload.has_external_issue_tracker }.to(false)
|
||||
end
|
||||
|
||||
it 'does not change `has_external_issue_tracker` when `issue_tracker` is deleted, if an active `issue_tracker` still exists' do
|
||||
services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
|
||||
expect do
|
||||
service.delete
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
|
||||
it 'does not change `has_external_issue_tracker` when service is for a different project' do
|
||||
different_project = projects.create!(namespace_id: @namespace.id)
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: different_project.id)
|
||||
|
||||
expect do
|
||||
service.delete
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#down' do
|
||||
before do
|
||||
migration.up
|
||||
migration.down
|
||||
end
|
||||
|
||||
it 'drops the INSERT trigger' do
|
||||
expect do
|
||||
services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
|
||||
it 'drops the UPDATE trigger' do
|
||||
service = services.create!(category: 'issue_tracker', active: false, project_id: @project.id)
|
||||
@project.update!(has_external_issue_tracker: false)
|
||||
|
||||
expect do
|
||||
service.update!(active: true)
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
|
||||
it 'drops the DELETE trigger' do
|
||||
service = services.create!(category: 'issue_tracker', active: true, project_id: @project.id)
|
||||
@project.update!(has_external_issue_tracker: true)
|
||||
|
||||
expect do
|
||||
service.delete
|
||||
end.not_to change { @project.reload.has_external_issue_tracker }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -48,7 +48,8 @@ RSpec.describe MergeRequestDiffCommit do
|
|||
"committer_email": "dmitriy.zaporozhets@gmail.com",
|
||||
"merge_request_diff_id": merge_request_diff_id,
|
||||
"relative_order": 0,
|
||||
"sha": Gitlab::Database::ShaAttribute.serialize("5937ac0a7beb003549fc5fd26fc247adbce4a52e")
|
||||
"sha": Gitlab::Database::ShaAttribute.serialize("5937ac0a7beb003549fc5fd26fc247adbce4a52e"),
|
||||
"trailers": {}.to_json
|
||||
},
|
||||
{
|
||||
"message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
|
||||
|
@ -60,7 +61,8 @@ RSpec.describe MergeRequestDiffCommit do
|
|||
"committer_email": "dmitriy.zaporozhets@gmail.com",
|
||||
"merge_request_diff_id": merge_request_diff_id,
|
||||
"relative_order": 1,
|
||||
"sha": Gitlab::Database::ShaAttribute.serialize("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
|
||||
"sha": Gitlab::Database::ShaAttribute.serialize("570e7b2abdd848b95f2f578043fc23bd6f6fd24d"),
|
||||
"trailers": {}.to_json
|
||||
}
|
||||
]
|
||||
end
|
||||
|
@ -92,7 +94,8 @@ RSpec.describe MergeRequestDiffCommit do
|
|||
"committer_email": "alejorro70@gmail.com",
|
||||
"merge_request_diff_id": merge_request_diff_id,
|
||||
"relative_order": 0,
|
||||
"sha": Gitlab::Database::ShaAttribute.serialize("ba3343bc4fa403a8dfbfcab7fc1a8c29ee34bd69")
|
||||
"sha": Gitlab::Database::ShaAttribute.serialize("ba3343bc4fa403a8dfbfcab7fc1a8c29ee34bd69"),
|
||||
"trailers": {}.to_json
|
||||
}]
|
||||
end
|
||||
|
||||
|
|
|
@ -754,9 +754,8 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
|
||||
context 'when both internal and external issue trackers are enabled' do
|
||||
before do
|
||||
subject.project.has_external_issue_tracker = true
|
||||
subject.project.save!
|
||||
create(:jira_service, project: subject.project)
|
||||
subject.project.reload
|
||||
end
|
||||
|
||||
it 'does not cache issues from external trackers' do
|
||||
|
@ -1263,9 +1262,10 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
describe '#issues_mentioned_but_not_closing' do
|
||||
let(:closing_issue) { create :issue, project: subject.project }
|
||||
let(:mentioned_issue) { create :issue, project: subject.project }
|
||||
|
||||
let(:commit) { double('commit', safe_message: "Fixes #{closing_issue.to_reference}") }
|
||||
|
||||
subject { create(:merge_request, source_project: create(:project)) }
|
||||
|
||||
it 'detects issues mentioned in description but not closed' do
|
||||
subject.project.add_developer(subject.author)
|
||||
subject.description = "Is related to #{mentioned_issue.to_reference} and #{closing_issue.to_reference}"
|
||||
|
@ -1279,13 +1279,12 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
context 'when the project has an external issue tracker' do
|
||||
subject { create(:merge_request, source_project: create(:project, :repository)) }
|
||||
|
||||
before do
|
||||
subject.project.add_developer(subject.author)
|
||||
commit = double(:commit, safe_message: 'Fixes TEST-3')
|
||||
|
||||
create(:jira_service, project: subject.project)
|
||||
subject.project.reload
|
||||
|
||||
allow(subject).to receive(:commits).and_return([commit])
|
||||
allow(subject).to receive(:description).and_return('Is related to TEST-2 and TEST-3')
|
||||
|
@ -1469,6 +1468,8 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
describe '#default_merge_commit_message' do
|
||||
subject { create(:merge_request, source_project: create(:project)) }
|
||||
|
||||
it 'includes merge information as the title' do
|
||||
request = build(:merge_request, source_branch: 'source', target_branch: 'target')
|
||||
|
||||
|
@ -1645,7 +1646,7 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
it_behaves_like 'an editable mentionable' do
|
||||
subject { create(:merge_request, :simple) }
|
||||
subject { create(:merge_request, :simple, source_project: create(:project, :repository)) }
|
||||
|
||||
let(:backref_text) { "merge request #{subject.to_reference}" }
|
||||
let(:set_mentionable_text) { ->(txt) { subject.description = txt } }
|
||||
|
|
|
@ -1002,71 +1002,6 @@ RSpec.describe Project, factory_default: :keep do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#external_issue_tracker' do
|
||||
let(:project) { create(:project) }
|
||||
let(:ext_project) { create(:redmine_project) }
|
||||
|
||||
context 'on existing projects with no value for has_external_issue_tracker' do
|
||||
before do
|
||||
project.update_column(:has_external_issue_tracker, nil)
|
||||
ext_project.update_column(:has_external_issue_tracker, nil)
|
||||
end
|
||||
|
||||
it 'updates the has_external_issue_tracker boolean' do
|
||||
expect do
|
||||
project.external_issue_tracker
|
||||
end.to change { project.reload.has_external_issue_tracker }.to(false)
|
||||
|
||||
expect do
|
||||
ext_project.external_issue_tracker
|
||||
end.to change { ext_project.reload.has_external_issue_tracker }.to(true)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns nil and does not query services when there is no external issue tracker' do
|
||||
expect(project).not_to receive(:services)
|
||||
|
||||
expect(project.external_issue_tracker).to eq(nil)
|
||||
end
|
||||
|
||||
it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
|
||||
ext_project.reload # Factory returns a project with changed attributes
|
||||
expect(ext_project).to receive(:services).once.and_call_original
|
||||
|
||||
2.times { expect(ext_project.external_issue_tracker).to be_a_kind_of(RedmineService) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cache_has_external_issue_tracker' do
|
||||
let_it_be(:project) { create(:project, has_external_issue_tracker: nil) }
|
||||
|
||||
it 'stores true if there is any external_issue_tracker' do
|
||||
services = double(:service, external_issue_trackers: [RedmineService.new])
|
||||
expect(project).to receive(:services).and_return(services)
|
||||
|
||||
expect do
|
||||
project.cache_has_external_issue_tracker
|
||||
end.to change { project.has_external_issue_tracker}.to(true)
|
||||
end
|
||||
|
||||
it 'stores false if there is no external_issue_tracker' do
|
||||
services = double(:service, external_issue_trackers: [])
|
||||
expect(project).to receive(:services).and_return(services)
|
||||
|
||||
expect do
|
||||
project.cache_has_external_issue_tracker
|
||||
end.to change { project.has_external_issue_tracker}.to(false)
|
||||
end
|
||||
|
||||
it 'does not cache data when in a read-only GitLab instance' do
|
||||
allow(Gitlab::Database).to receive(:read_only?) { true }
|
||||
|
||||
expect do
|
||||
project.cache_has_external_issue_tracker
|
||||
end.not_to change { project.has_external_issue_tracker }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_wiki?' do
|
||||
let(:no_wiki_project) { create(:project, :wiki_disabled, has_external_wiki: false) }
|
||||
let(:wiki_enabled_project) { create(:project) }
|
||||
|
@ -1103,6 +1038,93 @@ RSpec.describe Project, factory_default: :keep do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#external_issue_tracker' do
|
||||
it 'sets Project#has_external_issue_tracker when it is nil' do
|
||||
project_with_no_tracker = create(:project, has_external_issue_tracker: nil)
|
||||
project_with_tracker = create(:redmine_project, has_external_issue_tracker: nil)
|
||||
|
||||
expect do
|
||||
project_with_no_tracker.external_issue_tracker
|
||||
end.to change { project_with_no_tracker.reload.has_external_issue_tracker }.from(nil).to(false)
|
||||
|
||||
expect do
|
||||
project_with_tracker.external_issue_tracker
|
||||
end.to change { project_with_tracker.reload.has_external_issue_tracker }.from(nil).to(true)
|
||||
end
|
||||
|
||||
it 'returns nil and does not query services when there is no external issue tracker' do
|
||||
project = create(:project)
|
||||
|
||||
expect(project).not_to receive(:services)
|
||||
expect(project.external_issue_tracker).to eq(nil)
|
||||
end
|
||||
|
||||
it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
|
||||
project = create(:redmine_project)
|
||||
|
||||
expect(project).to receive(:services).once.and_call_original
|
||||
2.times { expect(project.external_issue_tracker).to be_a_kind_of(RedmineService) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_external_issue_tracker' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
def subject
|
||||
project.reload.has_external_issue_tracker
|
||||
end
|
||||
|
||||
it 'is false when external issue tracker service is not active' do
|
||||
create(:service, project: project, category: 'issue_tracker', active: false)
|
||||
|
||||
is_expected.to eq(false)
|
||||
end
|
||||
|
||||
it 'is false when other service is active' do
|
||||
create(:service, project: project, category: 'not_issue_tracker', active: true)
|
||||
|
||||
is_expected.to eq(false)
|
||||
end
|
||||
|
||||
context 'when there is an active external issue tracker service' do
|
||||
let!(:service) do
|
||||
create(:service, project: project, type: 'JiraService', category: 'issue_tracker', active: true)
|
||||
end
|
||||
|
||||
specify { is_expected.to eq(true) }
|
||||
|
||||
it 'becomes false when external issue tracker service is destroyed' do
|
||||
expect do
|
||||
Service.find(service.id).delete
|
||||
end.to change { subject }.to(false)
|
||||
end
|
||||
|
||||
it 'becomes false when external issue tracker service becomes inactive' do
|
||||
expect do
|
||||
service.update_column(:active, false)
|
||||
end.to change { subject }.to(false)
|
||||
end
|
||||
|
||||
context 'when there are two active external issue tracker services' do
|
||||
let_it_be(:second_service) do
|
||||
create(:service, project: project, type: 'CustomIssueTracker', category: 'issue_tracker', active: true)
|
||||
end
|
||||
|
||||
it 'does not become false when external issue tracker service is destroyed' do
|
||||
expect do
|
||||
Service.find(service.id).delete
|
||||
end.not_to change { subject }
|
||||
end
|
||||
|
||||
it 'does not become false when external issue tracker service becomes inactive' do
|
||||
expect do
|
||||
service.update_column(:active, false)
|
||||
end.not_to change { subject }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#external_wiki' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
|
|
|
@ -753,38 +753,6 @@ RSpec.describe Service do
|
|||
end
|
||||
end
|
||||
|
||||
describe "callbacks" do
|
||||
let!(:service) do
|
||||
RedmineService.new(
|
||||
project: project,
|
||||
active: true,
|
||||
properties: {
|
||||
project_url: 'http://redmine/projects/project_name_in_redmine',
|
||||
issues_url: "http://redmine/#{project.id}/project_name_in_redmine/:id",
|
||||
new_issue_url: 'http://redmine/projects/project_name_in_redmine/issues/new'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
describe "on create" do
|
||||
it "updates the has_external_issue_tracker boolean" do
|
||||
expect do
|
||||
service.save!
|
||||
end.to change { service.project.has_external_issue_tracker }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "on update" do
|
||||
it "updates the has_external_issue_tracker boolean" do
|
||||
service.save!
|
||||
|
||||
expect do
|
||||
service.update(active: false)
|
||||
end.to change { service.project.has_external_issue_tracker }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#api_field_names' do
|
||||
let(:fake_service) do
|
||||
Class.new(Service) do
|
||||
|
@ -864,20 +832,6 @@ RSpec.describe Service do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#external_issue_tracker?' do
|
||||
where(:category, :active, :result) do
|
||||
:issue_tracker | true | true
|
||||
:issue_tracker | false | false
|
||||
:common | true | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it 'returns the right result' do
|
||||
expect(build(:service, category: category, active: active).external_issue_tracker?).to eq(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#external_wiki?' do
|
||||
where(:type, :active, :result) do
|
||||
'ExternalWikiService' | true | true
|
||||
|
|
|
@ -24,6 +24,20 @@ RSpec.describe 'Query.issue(id)' do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'a noteable graphql type we can query' do
|
||||
let(:noteable) { issue }
|
||||
let(:project) { issue.project }
|
||||
let(:path_to_noteable) { [:issue] }
|
||||
|
||||
before do
|
||||
project.add_guest(current_user)
|
||||
end
|
||||
|
||||
def query(fields)
|
||||
graphql_query_for('issue', issue_params, fields)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user does not have access to the issue' do
|
||||
it 'returns nil' do
|
||||
project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
|
||||
|
|
|
@ -22,6 +22,23 @@ RSpec.describe 'Getting designs related to an issue' do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'a noteable graphql type we can query' do
|
||||
let(:noteable) { design }
|
||||
let(:note_factory) { :diff_note_on_design }
|
||||
let(:discussion_factory) { :diff_note_on_design }
|
||||
let(:path_to_noteable) { [:issue, :design_collection, :designs, :nodes, 0] }
|
||||
|
||||
before do
|
||||
project.add_developer(current_user)
|
||||
end
|
||||
|
||||
def query(fields)
|
||||
graphql_query_for(:issue, { id: global_id_of(issue) }, <<~FIELDS)
|
||||
designCollection { designs { nodes { #{fields} } } }
|
||||
FIELDS
|
||||
end
|
||||
end
|
||||
|
||||
it 'is not too deep for anonymous users' do
|
||||
note_fields = <<~FIELDS
|
||||
id
|
||||
|
@ -37,7 +54,7 @@ RSpec.describe 'Getting designs related to an issue' do
|
|||
expect(note_data['id']).to eq(note.to_global_id.to_s)
|
||||
end
|
||||
|
||||
def query(note_fields = all_graphql_fields_for(Note))
|
||||
def query(note_fields = all_graphql_fields_for(Note, max_depth: 1))
|
||||
design_node = <<~NODE
|
||||
designs {
|
||||
nodes {
|
||||
|
|
|
@ -43,46 +43,6 @@ RSpec.describe BulkCreateIntegrationService do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'updates project callbacks' do
|
||||
it 'updates projects#has_external_issue_tracker for issue tracker services' do
|
||||
described_class.new(integration, batch, association).execute
|
||||
|
||||
expect(project.reload.has_external_issue_tracker).to eq(true)
|
||||
expect(excluded_project.reload.has_external_issue_tracker).to eq(false)
|
||||
end
|
||||
|
||||
context 'with an external wiki integration' do
|
||||
before do
|
||||
integration.update!(category: 'common', type: 'ExternalWikiService')
|
||||
end
|
||||
|
||||
it 'updates projects#has_external_wiki for external wiki services' do
|
||||
described_class.new(integration, batch, association).execute
|
||||
|
||||
expect(project.reload.has_external_wiki).to eq(true)
|
||||
expect(excluded_project.reload.has_external_wiki).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'does not update project callbacks' do
|
||||
it 'does not update projects#has_external_issue_tracker for issue tracker services' do
|
||||
described_class.new(integration, batch, association).execute
|
||||
|
||||
expect(project.reload.has_external_issue_tracker).to eq(false)
|
||||
end
|
||||
|
||||
context 'with an inactive external wiki integration' do
|
||||
let(:integration) { create(:external_wiki_service, :instance, active: false) }
|
||||
|
||||
it 'does not update projects#has_external_wiki for external wiki services' do
|
||||
described_class.new(integration, batch, association).execute
|
||||
|
||||
expect(project.reload.has_external_wiki).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'passing an instance-level integration' do
|
||||
let(:integration) { instance_integration }
|
||||
let(:inherit_from_id) { integration.id }
|
||||
|
@ -95,15 +55,6 @@ RSpec.describe BulkCreateIntegrationService do
|
|||
|
||||
it_behaves_like 'creates integration from batch ids'
|
||||
it_behaves_like 'updates inherit_from_id'
|
||||
it_behaves_like 'updates project callbacks'
|
||||
|
||||
context 'when integration is not active' do
|
||||
before do
|
||||
integration.update!(active: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'does not update project callbacks'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a group association' do
|
||||
|
@ -130,7 +81,6 @@ RSpec.describe BulkCreateIntegrationService do
|
|||
|
||||
it_behaves_like 'creates integration from batch ids'
|
||||
it_behaves_like 'updates inherit_from_id'
|
||||
it_behaves_like 'updates project callbacks'
|
||||
end
|
||||
|
||||
context 'with a group association' do
|
||||
|
@ -157,7 +107,6 @@ RSpec.describe BulkCreateIntegrationService do
|
|||
let(:inherit_from_id) { integration.id }
|
||||
|
||||
it_behaves_like 'creates integration from batch ids'
|
||||
it_behaves_like 'updates project callbacks'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,18 +66,6 @@ RSpec.describe FeatureFlags::CreateService do
|
|||
subject
|
||||
end
|
||||
|
||||
context 'the feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(jira_sync_feature_flags: false)
|
||||
end
|
||||
|
||||
it 'does not sync the feature flag to Jira' do
|
||||
expect(::JiraConnect::SyncFeatureFlagsWorker).not_to receive(:perform_async)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates audit event' do
|
||||
expected_message = 'Created feature flag <strong>feature_flag</strong> '\
|
||||
'with description <strong>"description"</strong>. '\
|
||||
|
|
|
@ -26,18 +26,6 @@ RSpec.describe FeatureFlags::UpdateService do
|
|||
expect(subject[:status]).to eq(:success)
|
||||
end
|
||||
|
||||
context 'the feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(jira_sync_feature_flags: false)
|
||||
end
|
||||
|
||||
it 'does not sync the feature flag to Jira' do
|
||||
expect(::JiraConnect::SyncFeatureFlagsWorker).not_to receive(:perform_async)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
it 'syncs the feature flag to Jira' do
|
||||
expect(::JiraConnect::SyncFeatureFlagsWorker).to receive(:perform_async).with(Integer, Integer)
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ RSpec.describe Issues::CloseService do
|
|||
let!(:external_issue_tracker) { create(:jira_service, project: project) }
|
||||
|
||||
it 'closes the issue on the external issue tracker' do
|
||||
project.reload
|
||||
expect(project.external_issue_tracker).to receive(:close_issue)
|
||||
|
||||
described_class.new(project, user).close_issue(external_issue)
|
||||
|
@ -94,6 +95,7 @@ RSpec.describe Issues::CloseService do
|
|||
let!(:external_issue_tracker) { create(:jira_service, project: project, active: false) }
|
||||
|
||||
it 'does not close the issue on the external issue tracker' do
|
||||
project.reload
|
||||
expect(project.external_issue_tracker).not_to receive(:close_issue)
|
||||
|
||||
described_class.new(project, user).close_issue(external_issue)
|
||||
|
@ -104,6 +106,7 @@ RSpec.describe Issues::CloseService do
|
|||
let!(:external_issue_tracker) { create(:bugzilla_service, project: project) }
|
||||
|
||||
it 'does not close the issue on the external issue tracker' do
|
||||
project.reload
|
||||
expect(project.external_issue_tracker).not_to receive(:close_issue)
|
||||
|
||||
described_class.new(project, user).close_issue(external_issue)
|
||||
|
|
|
@ -252,6 +252,7 @@ RSpec.describe MergeRequests::BuildService do
|
|||
issue.update!(iid: 123)
|
||||
else
|
||||
create(:"#{issue_tracker}_service", project: project)
|
||||
project.reload
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -351,6 +352,7 @@ RSpec.describe MergeRequests::BuildService do
|
|||
issue.update!(iid: 123)
|
||||
else
|
||||
create(:"#{issue_tracker}_service", project: project)
|
||||
project.reload
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -729,12 +729,14 @@ RSpec.describe ::SystemNotes::IssuablesService do
|
|||
|
||||
it 'is false with issue tracker supporting referencing' do
|
||||
create(:jira_service, project: project)
|
||||
project.reload
|
||||
|
||||
expect(service.cross_reference_disallowed?(noteable)).to be_falsey
|
||||
end
|
||||
|
||||
it 'is true with issue tracker not supporting referencing' do
|
||||
create(:bugzilla_service, project: project)
|
||||
project.reload
|
||||
|
||||
expect(service.cross_reference_disallowed?(noteable)).to be_truthy
|
||||
end
|
||||
|
|
|
@ -510,8 +510,12 @@ module GraphqlHelpers
|
|||
end
|
||||
end
|
||||
|
||||
def global_id_of(model)
|
||||
model.to_global_id.to_s
|
||||
def global_id_of(model, id: nil, model_name: nil)
|
||||
if id || model_name
|
||||
::Gitlab::GlobalId.build(model, id: id, model_name: model_name).to_s
|
||||
else
|
||||
model.to_global_id.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def missing_required_argument(path, argument)
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'can housekeep repository' do
|
||||
context 'with a clean redis state', :clean_gitlab_redis_shared_state do
|
||||
describe '#pushes_since_gc' do
|
||||
context 'without any pushes' do
|
||||
it 'returns 0' do
|
||||
expect(resource.pushes_since_gc).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a number of pushes' do
|
||||
it 'returns the number of pushes' do
|
||||
3.times { resource.increment_pushes_since_gc }
|
||||
|
||||
expect(resource.pushes_since_gc).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#increment_pushes_since_gc' do
|
||||
it 'increments the number of pushes since the last GC' do
|
||||
3.times { resource.increment_pushes_since_gc }
|
||||
|
||||
expect(resource.pushes_since_gc).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reset_pushes_since_gc' do
|
||||
it 'resets the number of pushes since the last GC' do
|
||||
3.times { resource.increment_pushes_since_gc }
|
||||
|
||||
resource.reset_pushes_since_gc
|
||||
|
||||
expect(resource.pushes_since_gc).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pushes_since_gc_redis_shared_state_key' do
|
||||
it 'returns the proper redis key format' do
|
||||
expect(resource.send(:pushes_since_gc_redis_shared_state_key)).to eq("#{resource_key}/#{resource.id}/pushes_since_gc")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Requires `query(fields)`, `path_to_noteable`, `project`, and `noteable` bindings
|
||||
RSpec.shared_examples 'a noteable graphql type we can query' do
|
||||
let(:note_factory) { :note }
|
||||
let(:discussion_factory) { :discussion_note }
|
||||
|
||||
describe '.discussions' do
|
||||
let(:fields) do
|
||||
"discussions { nodes { #{all_graphql_fields_for('Discussion')} } }"
|
||||
end
|
||||
|
||||
def expected
|
||||
noteable.discussions.map do |discussion|
|
||||
include(
|
||||
'id' => global_id_of(discussion),
|
||||
'replyId' => global_id_of(discussion, id: discussion.reply_id),
|
||||
'createdAt' => discussion.created_at.iso8601,
|
||||
'notes' => include(
|
||||
'nodes' => have_attributes(size: discussion.notes.size)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'can fetch discussions' do
|
||||
create(discussion_factory, project: project, noteable: noteable)
|
||||
|
||||
post_graphql(query(fields), current_user: current_user)
|
||||
|
||||
expect(graphql_data_at(*path_to_noteable, :discussions, :nodes))
|
||||
.to match_array(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.notes' do
|
||||
let(:fields) do
|
||||
"notes { nodes { #{all_graphql_fields_for('Note', max_depth: 2)} } }"
|
||||
end
|
||||
|
||||
def expected
|
||||
noteable.notes.map do |note|
|
||||
include(
|
||||
'id' => global_id_of(note),
|
||||
'project' => include('id' => global_id_of(project)),
|
||||
'author' => include('id' => global_id_of(note.author)),
|
||||
'createdAt' => note.created_at.iso8601,
|
||||
'body' => eq(note.note)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'can fetch notes' do
|
||||
create(note_factory, project: project, noteable: noteable)
|
||||
|
||||
post_graphql(query(fields), current_user: current_user)
|
||||
|
||||
expect(graphql_data_at(*path_to_noteable, :notes, :nodes))
|
||||
.to match_array(expected)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -32,29 +32,5 @@ RSpec.describe ::JiraConnect::SyncFeatureFlagsWorker do
|
|||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(jira_sync_feature_flags: false)
|
||||
end
|
||||
|
||||
it 'does not call the sync service' do
|
||||
expect_next(::JiraConnect::SyncService).not_to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature flag is enabled for this project' do
|
||||
before do
|
||||
stub_feature_flags(jira_sync_feature_flags: feature_flag.project)
|
||||
end
|
||||
|
||||
it 'calls the sync service' do
|
||||
expect_next(::JiraConnect::SyncService).to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
# Changelog for gitlab-workhorse
|
||||
|
||||
## v8.60.0
|
||||
|
||||
### Added
|
||||
- Support Git HTTP on toplevel repositories
|
||||
https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/670
|
||||
- Update GoCloud to v0.21.1+
|
||||
https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/675
|
||||
|
||||
### Changed
|
||||
- Allow blank S3 regions to be used
|
||||
https://gitlab.com/gitlab-org/gitlab-workhorse/-/merge_requests/677
|
||||
|
||||
## v8.59.0
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -1 +1 @@
|
|||
8.59.0
|
||||
8.60.0
|
||||
|
|
|
@ -169,6 +169,57 @@ func TestGetInfoRefsProxiedToGitalyInterruptedStream(t *testing.T) {
|
|||
waitDone(t, done)
|
||||
}
|
||||
|
||||
func TestGetInfoRefsRouting(t *testing.T) {
|
||||
gitalyServer, socketPath := startGitalyServer(t, codes.OK)
|
||||
defer gitalyServer.GracefulStop()
|
||||
|
||||
apiResponse := gitOkBody(t)
|
||||
apiResponse.GitalyServer.Address = "unix:" + socketPath
|
||||
ts := testAuthServer(t, nil, nil, 200, apiResponse)
|
||||
defer ts.Close()
|
||||
|
||||
ws := startWorkhorseServer(ts.URL)
|
||||
defer ws.Close()
|
||||
|
||||
testCases := []struct {
|
||||
method string
|
||||
path string
|
||||
match bool
|
||||
}{
|
||||
{"GET", "/toplevel.git/info/refs?service=git-receive-pack", true},
|
||||
{"GET", "/toplevel.wiki.git/info/refs?service=git-upload-pack", true},
|
||||
{"GET", "/toplevel/child/project.git/info/refs?service=git-receive-pack", true},
|
||||
{"GET", "/toplevel/child/project.wiki.git/info/refs?service=git-upload-pack", true},
|
||||
{"GET", "/toplevel/child/project/snippets/123.git/info/refs?service=git-receive-pack", true},
|
||||
{"GET", "/snippets/123.git/info/refs?service=git-upload-pack", true},
|
||||
{"GET", "/foo/bar.git/info/refs", false},
|
||||
{"GET", "/foo/bar.git/info/refs?service=git-zzz-pack", false},
|
||||
{"GET", "/.git/info/refs?service=git-upload-pack", false},
|
||||
{"POST", "/toplevel.git/info/refs?service=git-receive-pack", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
req, err := http.NewRequest(tc.method, ws.URL+tc.path, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
body := string(testhelper.ReadAll(t, resp.Body))
|
||||
|
||||
if tc.match {
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
require.Contains(t, body, "\x00", "expect response generated by test gitaly server")
|
||||
} else {
|
||||
require.Equal(t, 204, resp.StatusCode)
|
||||
require.Empty(t, body, "normal request has empty response body")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func waitDone(t *testing.T, done chan struct{}) {
|
||||
t.Helper()
|
||||
select {
|
||||
|
@ -259,6 +310,65 @@ func TestPostReceivePackProxiedToGitalyInterrupted(t *testing.T) {
|
|||
waitDone(t, done)
|
||||
}
|
||||
|
||||
func TestPostReceivePackRouting(t *testing.T) {
|
||||
gitalyServer, socketPath := startGitalyServer(t, codes.OK)
|
||||
defer gitalyServer.GracefulStop()
|
||||
|
||||
apiResponse := gitOkBody(t)
|
||||
apiResponse.GitalyServer.Address = "unix:" + socketPath
|
||||
ts := testAuthServer(t, nil, nil, 200, apiResponse)
|
||||
defer ts.Close()
|
||||
|
||||
ws := startWorkhorseServer(ts.URL)
|
||||
defer ws.Close()
|
||||
|
||||
testCases := []struct {
|
||||
method string
|
||||
path string
|
||||
contentType string
|
||||
match bool
|
||||
}{
|
||||
{"POST", "/toplevel.git/git-receive-pack", "application/x-git-receive-pack-request", true},
|
||||
{"POST", "/toplevel.wiki.git/git-receive-pack", "application/x-git-receive-pack-request", true},
|
||||
{"POST", "/toplevel/child/project.git/git-receive-pack", "application/x-git-receive-pack-request", true},
|
||||
{"POST", "/toplevel/child/project.wiki.git/git-receive-pack", "application/x-git-receive-pack-request", true},
|
||||
{"POST", "/toplevel/child/project/snippets/123.git/git-receive-pack", "application/x-git-receive-pack-request", true},
|
||||
{"POST", "/snippets/123.git/git-receive-pack", "application/x-git-receive-pack-request", true},
|
||||
{"POST", "/foo/bar/git-receive-pack", "application/x-git-receive-pack-request", false},
|
||||
{"POST", "/foo/bar.git/git-zzz-pack", "application/x-git-receive-pack-request", false},
|
||||
{"POST", "/.git/git-receive-pack", "application/x-git-receive-pack-request", false},
|
||||
{"POST", "/toplevel.git/git-receive-pack", "application/x-git-upload-pack-request", false},
|
||||
{"GET", "/toplevel.git/git-receive-pack", "application/x-git-receive-pack-request", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
req, err := http.NewRequest(
|
||||
tc.method,
|
||||
ws.URL+tc.path,
|
||||
bytes.NewReader(testhelper.GitalyReceivePackResponseMock),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Content-Type", tc.contentType)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
body := string(testhelper.ReadAll(t, resp.Body))
|
||||
|
||||
if tc.match {
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
require.Contains(t, body, "\x00", "expect response generated by test gitaly server")
|
||||
} else {
|
||||
require.Equal(t, 204, resp.StatusCode)
|
||||
require.Empty(t, body, "normal request has empty response body")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ReaderFunc is an adapter to turn a conforming function into an io.Reader.
|
||||
type ReaderFunc func(b []byte) (int, error)
|
||||
|
||||
|
@ -376,6 +486,65 @@ func TestPostUploadPackProxiedToGitalyInterrupted(t *testing.T) {
|
|||
waitDone(t, done)
|
||||
}
|
||||
|
||||
func TestPostUploadPackRouting(t *testing.T) {
|
||||
gitalyServer, socketPath := startGitalyServer(t, codes.OK)
|
||||
defer gitalyServer.GracefulStop()
|
||||
|
||||
apiResponse := gitOkBody(t)
|
||||
apiResponse.GitalyServer.Address = "unix:" + socketPath
|
||||
ts := testAuthServer(t, nil, nil, 200, apiResponse)
|
||||
defer ts.Close()
|
||||
|
||||
ws := startWorkhorseServer(ts.URL)
|
||||
defer ws.Close()
|
||||
|
||||
testCases := []struct {
|
||||
method string
|
||||
path string
|
||||
contentType string
|
||||
match bool
|
||||
}{
|
||||
{"POST", "/toplevel.git/git-upload-pack", "application/x-git-upload-pack-request", true},
|
||||
{"POST", "/toplevel.wiki.git/git-upload-pack", "application/x-git-upload-pack-request", true},
|
||||
{"POST", "/toplevel/child/project.git/git-upload-pack", "application/x-git-upload-pack-request", true},
|
||||
{"POST", "/toplevel/child/project.wiki.git/git-upload-pack", "application/x-git-upload-pack-request", true},
|
||||
{"POST", "/toplevel/child/project/snippets/123.git/git-upload-pack", "application/x-git-upload-pack-request", true},
|
||||
{"POST", "/snippets/123.git/git-upload-pack", "application/x-git-upload-pack-request", true},
|
||||
{"POST", "/foo/bar/git-upload-pack", "application/x-git-upload-pack-request", false},
|
||||
{"POST", "/foo/bar.git/git-zzz-pack", "application/x-git-upload-pack-request", false},
|
||||
{"POST", "/.git/git-upload-pack", "application/x-git-upload-pack-request", false},
|
||||
{"POST", "/toplevel.git/git-upload-pack", "application/x-git-receive-pack-request", false},
|
||||
{"GET", "/toplevel.git/git-upload-pack", "application/x-git-upload-pack-request", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
req, err := http.NewRequest(
|
||||
tc.method,
|
||||
ws.URL+tc.path,
|
||||
bytes.NewReader(testhelper.GitalyReceivePackResponseMock),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Content-Type", tc.contentType)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
body := string(testhelper.ReadAll(t, resp.Body))
|
||||
|
||||
if tc.match {
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
require.Contains(t, body, "\x00", "expect response generated by test gitaly server")
|
||||
} else {
|
||||
require.Equal(t, 204, resp.StatusCode)
|
||||
require.Empty(t, body, "normal request has empty response body")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDiffProxiedToGitalySuccessfully(t *testing.T) {
|
||||
gitalyServer, socketPath := startGitalyServer(t, codes.OK)
|
||||
defer gitalyServer.GracefulStop()
|
||||
|
|
|
@ -3,11 +3,11 @@ module gitlab.com/gitlab-org/gitlab-workhorse
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-storage-blob-go v0.10.0
|
||||
github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/FZambia/sentinel v1.0.0
|
||||
github.com/alecthomas/chroma v0.7.3
|
||||
github.com/aws/aws-sdk-go v1.31.13
|
||||
github.com/aws/aws-sdk-go v1.36.1
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/johannesboyne/gofakes3 v0.0.0-20200510090907-02d71f533bec
|
||||
|
@ -30,11 +30,15 @@ require (
|
|||
github.com/stretchr/testify v1.6.1
|
||||
gitlab.com/gitlab-org/gitaly v1.74.0
|
||||
gitlab.com/gitlab-org/labkit v1.0.0
|
||||
gocloud.dev v0.20.0
|
||||
gocloud.dev v0.21.1-0.20201223184910-5094f54ed8bb
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344
|
||||
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509
|
||||
google.golang.org/grpc v1.29.1
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061 // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
golang.org/x/tools v0.0.0-20201203202102-a1a1cbeaa516
|
||||
google.golang.org/genproto v0.0.0-20210111234610-22ae2b108f89 // indirect
|
||||
google.golang.org/grpc v1.34.1
|
||||
google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4 // indirect
|
||||
honnef.co/go/tools v0.0.1-2020.1.5
|
||||
)
|
||||
|
||||
|
|
297
workhorse/go.sum
297
workhorse/go.sum
|
@ -6,18 +6,19 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
|
|||
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.58.0 h1:vtAfVc723K3xKq1BQydk/FyCldnaNFhGhpJxaJzgRMQ=
|
||||
cloud.google.com/go v0.58.0/go.mod h1:W+9FnSUw6nhVwXlFcp1eL+krq5+HQUJeUogSeJZZiWg=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0Ko=
|
||||
cloud.google.com/go v0.72.0 h1:eWRCuwubtDrCJG0oSUMgnsbD4CmPFQF2ei4OFbXvwww=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
@ -28,60 +29,64 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7
|
|||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.2.0/go.mod h1:iISCjWnTpnoJT1R287xRdjvQHJrxQOpeah4phb5D3h0=
|
||||
cloud.google.com/go/firestore v1.4.0/go.mod h1:NjjGEnxCS3CAKYp+vmALu20QzcqasGodQp48WxJGAYc=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/pubsub v1.9.0/go.mod h1:G3o6/kJvEMIEAN5urdkaP4be49WQsjNiykBIto9LFtY=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.9.0 h1:oXnZyBjHB6hC8TnSle0AWW6pGJ29EuSo5ww+SFmdNBg=
|
||||
cloud.google.com/go/storage v1.9.0/go.mod h1:m+/etGaqZbylxaNT876QGXqEHp4PR2Rq5GMqICWb9bU=
|
||||
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
|
||||
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
|
||||
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.12.0 h1:4y3gHptW1EHVtcPAVE0eBBlFuGqEejTTG3KdIE0lUX4=
|
||||
cloud.google.com/go/storage v1.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho=
|
||||
contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
|
||||
contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/Azure/azure-amqp-common-go/v3 v3.0.0/go.mod h1:SY08giD/XbhTz07tJdpw1SoxQXHPN30+DI3Z04SYqyg=
|
||||
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
|
||||
github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY=
|
||||
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
|
||||
github.com/Azure/azure-amqp-common-go/v3 v3.0.1/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0=
|
||||
github.com/Azure/azure-amqp-common-go/v3 v3.1.0/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0=
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
|
||||
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
|
||||
github.com/Azure/azure-sdk-for-go v37.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-service-bus-go v0.10.1/go.mod h1:E/FOceuKAFUfpbIJDKWz/May6guE+eGibfGT6q+n1to=
|
||||
github.com/Azure/azure-storage-blob-go v0.9.0/go.mod h1:8UBPbiOhrMQ4pLPi3gA1tXnpjrS76UYE/fo5A40vf4g=
|
||||
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
|
||||
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
|
||||
github.com/Azure/go-amqp v0.12.6/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo=
|
||||
github.com/Azure/go-amqp v0.12.7/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
|
||||
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.3 h1:O1AGG9Xig71FxdX9HO5pGNyZ7TbSyHaVg+5eJO/jSGw=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
|
||||
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
|
||||
github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
|
||||
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/Azure/azure-sdk-for-go v49.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-service-bus-go v0.10.7/go.mod h1:o5z/3lDG1iT/T/G7vgIwIqVDTx9Qa2wndf5OdzSzpF8=
|
||||
github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d h1:YEjZNZ0HS7ITX+BJ7wUXtTk6GXM3g8xftaqQ94XU/cs=
|
||||
github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d/go.mod h1:A0u4VjtpgZJ7Y7um/+ix2DHBuEKFC6sEIlj0xc13a4Q=
|
||||
github.com/Azure/go-amqp v0.13.0/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1xlxUTs=
|
||||
github.com/Azure/go-amqp v0.13.1/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1xlxUTs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
|
||||
github.com/Azure/go-autorest/autorest v0.11.7/go.mod h1:V6p3pKZx1KKkJubbxnDWrzNhEIfOy/pTGasLqzHIPHs=
|
||||
github.com/Azure/go-autorest/autorest v0.11.9/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
|
||||
github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE=
|
||||
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.4/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.6 h1:d3pSDwvBWBLqdA91u+keH1zs1cCEzrQdHKY6iqbQNkE=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.6/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.3 h1:lZifaPRAk1bqg5vGqreL6F8uLC5V0fDpY8nFvc3boFc=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.3/go.mod h1:4bJZhUhcq8LB20TruwHbAQsmUs2Xh+QR7utuJpLXX3A=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 h1:dMOmEJfkLKW/7JsokJqkyoYSgmR08hi9KrhjZb+JALY=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
|
||||
github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE=
|
||||
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
|
@ -89,7 +94,7 @@ github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EF
|
|||
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
||||
github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc=
|
||||
github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v1.19.1/go.mod h1:+yYmuKqcBVkgRePGpUhTA9OEg0XsnFE96eZ6nJ2yCQM=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
|
@ -123,10 +128,10 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l
|
|||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||
github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.31.13 h1:UeWMTRTL0XAKLR7vxDL4/u7KOtz/LtfJr+lXtxN4YEQ=
|
||||
github.com/aws/aws-sdk-go v1.31.13/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.36.1 h1:rDgSL20giXXu48Ycx6Qa4vWaNTVTltUl6vA73ObCSVk=
|
||||
github.com/aws/aws-sdk-go v1.36.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
@ -137,8 +142,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
|||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
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.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
|
@ -153,6 +158,7 @@ github.com/client9/reopen v1.0.0 h1:8tpLVR74DLpLObrn2KvsyxJY++2iORGR17WLUdSzUws=
|
|||
github.com/client9/reopen v1.0.0/go.mod h1:caXVCEr+lUtoN1FlsRiOWdfQtdRHIYfcb0ai8qKWtkQ=
|
||||
github.com/cloudflare/tableflip v1.2.1-0.20200514155827-4baec9811f2b/go.mod h1:vhhSlJqV8uUnxGkRSgyvGthfGlkAwJ4UuSV51fSrCQY=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
|
@ -171,6 +177,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
|
@ -178,6 +185,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
|
@ -193,17 +202,22 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
|
|||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
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.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
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.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
|
||||
|
@ -213,7 +227,9 @@ github.com/getsentry/sentry-go v0.7.0 h1:MR2yfR4vFfv/2+iBuSnkdQwVg7N9cJzihZ6KJu7
|
|||
github.com/getsentry/sentry-go v0.7.0/go.mod h1:pLFpD2Y5RHIKF9Bw3KH6/68DeN2K/XBJd8awjdPnUwg=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
|
@ -228,6 +244,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
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.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
|
@ -261,6 +281,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -288,28 +310,40 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-replayers/grpcreplay v0.1.0 h1:eNb1y9rZFmY4ax45uEEECSa8fsxGRU+8Bil52ASAwic=
|
||||
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
||||
github.com/google/go-replayers/httpreplay v0.1.0 h1:AX7FUb4BjrrzNvblr/OlgwrmFiep6soj5K2QSDW7BGk=
|
||||
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
||||
github.com/google/go-replayers/grpcreplay v1.0.0 h1:B5kVOzJ1hBgnevTgIWhSTatQ3608yu/2NnU0Ta1d0kY=
|
||||
github.com/google/go-replayers/grpcreplay v1.0.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
||||
github.com/google/go-replayers/httpreplay v0.1.2 h1:HCfx+dQzwN9XbGTHF8qJ+67WN8glL9FTWV5rraCJ/jU=
|
||||
github.com/google/go-replayers/httpreplay v0.1.2/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE=
|
||||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c h1:lIC98ZUNah83ky7d9EXktLFe4H7Nwus59dTOLXr8xAI=
|
||||
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c h1:Jx2lEv4nMccTJE+IIZOVIvk+DjNKlRsW0sm1uBr896U=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE=
|
||||
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
|
||||
|
@ -325,6 +359,8 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
|
|||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
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/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.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
|
||||
|
@ -357,6 +393,7 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||
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=
|
||||
|
@ -366,8 +403,10 @@ github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62
|
|||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/johannesboyne/gofakes3 v0.0.0-20200510090907-02d71f533bec h1:jEZFmuFe51KdrceqM4NL3dJiuog0zojzcN/VculG26o=
|
||||
github.com/johannesboyne/gofakes3 v0.0.0-20200510090907-02d71f533bec/go.mod h1:fNiSoOiEI5KlkWXn26OwKnNe58ilTIkpBlgOrt7Olu8=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
|
@ -377,6 +416,7 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
|
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
|
@ -399,6 +439,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -411,8 +453,9 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/libgit2/git2go/v30 v30.0.5/go.mod h1:YReiQ7xhMoyAL4ISYFLZt+OGqn6xtLqvTC1xJ9oAH7Y=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743 h1:143Bb8f8DuGWck/xpNUOckBVYfFbBTnLevfRZ1aVVqo=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
|
@ -424,8 +467,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
|
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
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=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
|
||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
|
@ -457,6 +498,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
|||
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 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.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -475,6 +518,8 @@ github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7
|
|||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=
|
||||
|
@ -642,6 +687,8 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf
|
|||
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
gitlab.com/gitlab-org/gitaly v1.87.1-0.20201001041716-3f5e218def93 h1:5qkRBchgs4IvlbRdJTMISuktLF1ZtLMowyhzQteEeKI=
|
||||
gitlab.com/gitlab-org/gitaly v1.87.1-0.20201001041716-3f5e218def93/go.mod h1:NEpGSBkjMt7yV5SB1MFySVQqTKFEUdfTDxS76Rt7GC8=
|
||||
|
@ -660,6 +707,9 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
|
@ -669,8 +719,8 @@ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+
|
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
gocloud.dev v0.20.0 h1:mbEKMfnyPV7W1Rj35R1xXfjszs9dXkwSOq2KoFr25g8=
|
||||
gocloud.dev v0.20.0/go.mod h1:+Y/RpSXrJthIOM8uFNzWp6MRu9pFPNFEEZrQMxpkfIc=
|
||||
gocloud.dev v0.21.1-0.20201223184910-5094f54ed8bb h1:3EJw/ZRo3jKHY2WP8HiAxCpGlfsrKpaIeCl6VfMprKw=
|
||||
gocloud.dev v0.21.1-0.20201223184910-5094f54ed8bb/go.mod h1:iI47kpBb27cms1+KJCbcO2NbZBOg4V6SJWFeO/Kpp1c=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -681,9 +731,12 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -719,6 +772,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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=
|
||||
|
@ -737,11 +792,12 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -755,16 +811,28 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19 h1:ZD+2Sd/BnevwJp8PSli8WgGAGzb9IZtxBsv1iZMYeEA=
|
||||
golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
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=
|
||||
|
@ -773,6 +841,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -798,6 +868,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -811,7 +882,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -820,21 +890,37 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435 h1:25AvDqqB9PrNqj1FLf2/70I4W0L19qqoaFq3gjNwbKk=
|
||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061 h1:DQmQoKxQWtyybCtX/3dIuDBcAhFszqq8YiNeS6sNu1c=
|
||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
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=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -858,6 +944,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -879,26 +966,36 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
|
|||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509 h1:MI14dOfl3OG6Zd32w3ugsrvcUO810fDZdWakTq39dH4=
|
||||
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201202200335-bef1c476418a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201203202102-a1a1cbeaa516 h1:E8xavSjXY8LFvcMSu/8Fjztt+SerwKnuAUOdS+aCXUM=
|
||||
golang.org/x/tools v0.0.0-20201203202102-a1a1cbeaa516/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
|
@ -908,16 +1005,25 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
|||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.26.0 h1:VJZ8h6E8ip82FRpQl848c5vAadxlTXrUh8RzQzSRm08=
|
||||
google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.31.0/go.mod h1:CL+9IBCa2WWU6gRuBWaKqGWLFFwbEUXkfeMkHLQWYWo=
|
||||
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0 h1:l2Nfbl2GPXdWorv+dT2XfinX2jOOw4zv1VhLstx+6rE=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
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-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -940,17 +1046,27 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
|
|||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200325114520-5b2d0af7952b/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8=
|
||||
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200831141814-d751682dd103/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200921151605-7abf4a1a14d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201203001206-6486ece9c497 h1:jDYzwXmX9tLnuG4sL85HPmE1ruErXOopALp2i/0AHnI=
|
||||
google.golang.org/genproto v0.0.0-20201203001206-6486ece9c497/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210111234610-22ae2b108f89 h1:R2owLnwrU3BdTJ5R9cnHDNsnEmBQ7n5lZjKShnbISe4=
|
||||
google.golang.org/genproto v0.0.0-20210111234610-22ae2b108f89/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
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=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
|
@ -968,6 +1084,16 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.34.1 h1:ugq+9++ZQPFzM2pKUMCIK8gj9M0pFyuUWO9Q8kwEDQw=
|
||||
google.golang.org/grpc v1.34.1/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4 h1:tfxAh8kBsG9GdCdaDiSCA1qqpd8lMOqgEebUyqTtnH8=
|
||||
google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -978,6 +1104,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.7.0 h1:7wbMayb6JXcbAS95RN7MI42W3o1BCxCcdIzZfVWBAiE=
|
||||
gopkg.in/DataDog/dd-trace-go.v1 v1.7.0/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
|
@ -985,6 +1113,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
|
@ -1018,6 +1148,7 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
|||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -146,7 +146,7 @@ func (c *ObjectStorageConfig) IsGoCloud() bool {
|
|||
|
||||
func (c *ObjectStorageConfig) IsValid() bool {
|
||||
if c.IsAWS() {
|
||||
return c.S3Config.Bucket != "" && c.S3Config.Region != "" && c.s3CredentialsValid()
|
||||
return c.S3Config.Bucket != "" && c.s3CredentialsValid()
|
||||
} else if c.IsGoCloud() {
|
||||
// We could parse and validate the URL, but GoCloud providers
|
||||
// such as AzureRM don't have a fallback to normal HTTP, so we
|
||||
|
|
|
@ -187,6 +187,9 @@ func TestUseWorkhorseClientEnabled(t *testing.T) {
|
|||
iamConfig := missingCfg
|
||||
iamConfig.S3Config.UseIamProfile = true
|
||||
|
||||
missingRegion := cfg
|
||||
missingRegion.S3Config.Region = ""
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
UseWorkhorseClient bool
|
||||
|
@ -245,6 +248,13 @@ func TestUseWorkhorseClientEnabled(t *testing.T) {
|
|||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "missing S3 region",
|
||||
UseWorkhorseClient: true,
|
||||
remoteTempObjectID: "test-object",
|
||||
objectStorageConfig: missingRegion,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
@ -20,6 +20,11 @@ func GetInfoRefsHandler(a *api.API) http.Handler {
|
|||
return repoPreAuthorizeHandler(a, handleGetInfoRefs)
|
||||
}
|
||||
|
||||
func IsSmartInfoRefs(r *http.Request) bool {
|
||||
service := r.URL.Query().Get("service")
|
||||
return r.Method == "GET" && (service == "git-upload-pack" || service == "git-receive-pack")
|
||||
}
|
||||
|
||||
func handleGetInfoRefs(rw http.ResponseWriter, r *http.Request, a *api.Response) {
|
||||
responseWriter := NewHttpResponseWriter(rw)
|
||||
// Log 0 bytes in because we ignore the request body (and there usually is none anyway).
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIsSmartInfoRefs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
method string
|
||||
url string
|
||||
match bool
|
||||
}{
|
||||
{"GET", "?service=git-upload-pack", true},
|
||||
{"GET", "?service=git-receive-pack", true},
|
||||
{"GET", "", false},
|
||||
{"GET", "?service=", false},
|
||||
{"GET", "?service=foo", false},
|
||||
{"POST", "?service=git-upload-pack", false},
|
||||
{"POST", "?service=git-receive-pack", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
url, err := url.Parse(tc.url)
|
||||
require.NoError(t, err)
|
||||
|
||||
r := http.Request{Method: tc.method, URL: url}
|
||||
require.Equal(t, tc.match, IsSmartInfoRefs(&r))
|
||||
}
|
||||
}
|
|
@ -53,13 +53,13 @@ type uploadPreparers struct {
|
|||
}
|
||||
|
||||
const (
|
||||
apiPattern = `^/api/`
|
||||
ciAPIPattern = `^/ci/api/`
|
||||
gitProjectPattern = `^/([^/]+/){1,}[^/]+\.git/`
|
||||
projectPattern = `^/([^/]+/){1,}[^/]+/`
|
||||
snippetUploadPattern = `^/uploads/personal_snippet`
|
||||
userUploadPattern = `^/uploads/user`
|
||||
importPattern = `^/import/`
|
||||
apiPattern = `\A/api/`
|
||||
ciAPIPattern = `\A/ci/api/`
|
||||
gitRepositoryPattern = `\A/.+\.git/`
|
||||
projectPattern = `\A/([^/]+/){1,}[^/]+/`
|
||||
snippetUploadPattern = `\A/uploads/personal_snippet`
|
||||
userUploadPattern = `\A/uploads/user`
|
||||
importPattern = `\A/import/`
|
||||
)
|
||||
|
||||
func compileRegexp(regexpStr string) *regexp.Regexp {
|
||||
|
@ -222,10 +222,10 @@ func (u *upstream) configureRoutes() {
|
|||
|
||||
u.Routes = []routeEntry{
|
||||
// Git Clone
|
||||
u.route("GET", gitProjectPattern+`info/refs\z`, git.GetInfoRefsHandler(api)),
|
||||
u.route("POST", gitProjectPattern+`git-upload-pack\z`, contentEncodingHandler(git.UploadPack(api)), withMatcher(isContentType("application/x-git-upload-pack-request"))),
|
||||
u.route("POST", gitProjectPattern+`git-receive-pack\z`, contentEncodingHandler(git.ReceivePack(api)), withMatcher(isContentType("application/x-git-receive-pack-request"))),
|
||||
u.route("PUT", gitProjectPattern+`gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`, lfs.PutStore(api, signingProxy, preparers.lfs), withMatcher(isContentType("application/octet-stream"))),
|
||||
u.route("GET", gitRepositoryPattern+`info/refs\z`, git.GetInfoRefsHandler(api), withMatcher(git.IsSmartInfoRefs)),
|
||||
u.route("POST", gitRepositoryPattern+`git-upload-pack\z`, contentEncodingHandler(git.UploadPack(api)), withMatcher(isContentType("application/x-git-upload-pack-request"))),
|
||||
u.route("POST", gitRepositoryPattern+`git-receive-pack\z`, contentEncodingHandler(git.ReceivePack(api)), withMatcher(isContentType("application/x-git-receive-pack-request"))),
|
||||
u.route("PUT", gitRepositoryPattern+`gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`, lfs.PutStore(api, signingProxy, preparers.lfs), withMatcher(isContentType("application/octet-stream"))),
|
||||
|
||||
// CI Artifacts
|
||||
u.route("POST", apiPattern+`v4/jobs/[0-9]+/artifacts\z`, contentEncodingHandler(artifacts.UploadArtifacts(api, signingProxy, preparers.artifacts))),
|
||||
|
|
|
@ -694,6 +694,12 @@ func testAuthServer(t *testing.T, url *regexp.Regexp, params url.Values, code in
|
|||
return testhelper.TestServerWithHandler(url, func(w http.ResponseWriter, r *http.Request) {
|
||||
require.NotEmpty(t, r.Header.Get("X-Request-Id"))
|
||||
|
||||
// return a 204 No Content response if we don't receive the JWT header
|
||||
if r.Header.Get(secret.RequestHeader) == "" {
|
||||
w.WriteHeader(204)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", api.ResponseContentType)
|
||||
|
||||
logEntry := log.WithFields(log.Fields{
|
||||
|
|
|
@ -234,7 +234,7 @@ func TestLfsUpload(t *testing.T) {
|
|||
reqBody := "test data"
|
||||
rspBody := "test success"
|
||||
oid := "916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9"
|
||||
resource := fmt.Sprintf("/%s/gitlab-lfs/objects/%s/%d", testRepo, oid, len(reqBody))
|
||||
resource := fmt.Sprintf("/gitlab-org/gitlab-test.git/gitlab-lfs/objects/%s/%d", oid, len(reqBody))
|
||||
|
||||
lfsApiResponse := fmt.Sprintf(
|
||||
`{"TempPath":%q, "LfsOid":%q, "LfsSize": %d}`,
|
||||
|
@ -292,6 +292,74 @@ func TestLfsUpload(t *testing.T) {
|
|||
require.Equal(t, rspBody, string(rspData))
|
||||
}
|
||||
|
||||
func TestLfsUploadRouting(t *testing.T) {
|
||||
reqBody := "test data"
|
||||
rspBody := "test success"
|
||||
oid := "916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9"
|
||||
|
||||
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`.`), func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get(secret.RequestHeader) == "" {
|
||||
w.WriteHeader(204)
|
||||
} else {
|
||||
fmt.Fprint(w, rspBody)
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
ws := startWorkhorseServer(ts.URL)
|
||||
defer ws.Close()
|
||||
|
||||
testCases := []struct {
|
||||
method string
|
||||
path string
|
||||
contentType string
|
||||
match bool
|
||||
}{
|
||||
{"PUT", "/toplevel.git/gitlab-lfs/objects", "application/octet-stream", true},
|
||||
{"PUT", "/toplevel.wiki.git/gitlab-lfs/objects", "application/octet-stream", true},
|
||||
{"PUT", "/toplevel/child/project.git/gitlab-lfs/objects", "application/octet-stream", true},
|
||||
{"PUT", "/toplevel/child/project.wiki.git/gitlab-lfs/objects", "application/octet-stream", true},
|
||||
{"PUT", "/toplevel/child/project/snippets/123.git/gitlab-lfs/objects", "application/octet-stream", true},
|
||||
{"PUT", "/snippets/123.git/gitlab-lfs/objects", "application/octet-stream", true},
|
||||
{"PUT", "/foo/bar/gitlab-lfs/objects", "application/octet-stream", false},
|
||||
{"PUT", "/foo/bar.git/gitlab-lfs/objects/zzz", "application/octet-stream", false},
|
||||
{"PUT", "/.git/gitlab-lfs/objects", "application/octet-stream", false},
|
||||
{"PUT", "/toplevel.git/gitlab-lfs/objects", "application/zzz", false},
|
||||
{"POST", "/toplevel.git/gitlab-lfs/objects", "application/octet-stream", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
resource := fmt.Sprintf(tc.path+"/%s/%d", oid, len(reqBody))
|
||||
|
||||
req, err := http.NewRequest(
|
||||
tc.method,
|
||||
ws.URL+resource,
|
||||
strings.NewReader(reqBody),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Content-Type", tc.contentType)
|
||||
req.ContentLength = int64(len(reqBody))
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
rspData, err := ioutil.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.match {
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
require.Equal(t, rspBody, string(rspData), "expect response generated by test upstream server")
|
||||
} else {
|
||||
require.Equal(t, 204, resp.StatusCode)
|
||||
require.Empty(t, rspData, "normal request has empty response body")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func packageUploadTestServer(t *testing.T, resource string, reqBody string, rspBody string) *httptest.Server {
|
||||
return testhelper.TestServerWithHandler(regexp.MustCompile(`.`), func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, r.Method, "PUT")
|
||||
|
|
Loading…
Reference in New Issue