Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/workhorse.gitlab-ci.yml4
-rw-r--r--CHANGELOG.md4
-rw-r--r--app/assets/javascripts/blob/notebook/index.js3
-rw-r--r--app/assets/javascripts/blob/notebook/notebook_viewer.vue6
-rw-r--r--app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql10
-rw-r--r--app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql10
-rw-r--r--app/assets/javascripts/boards/stores/actions.js48
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js4
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js14
-rw-r--r--app/assets/javascripts/boards/stores/state.js2
-rw-r--r--app/assets/javascripts/deprecated_notes.js4
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue13
-rw-r--r--app/assets/javascripts/repository/components/table/index.vue4
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue4
-rw-r--r--app/assets/javascripts/repository/components/tree_content.vue21
-rw-r--r--app/assets/javascripts/repository/mixins/preload.js3
-rw-r--r--app/controllers/projects/tree_controller.rb4
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/graphql/queries/repository/paginated_tree.query.graphql54
-rw-r--r--app/helpers/blob_helper.rb4
-rw-r--r--app/models/ci/job_artifact.rb3
-rw-r--r--app/presenters/snippet_blob_presenter.rb6
-rw-r--r--app/views/projects/blob/viewers/_notebook.html.haml2
-rw-r--r--config/metrics/counts_all/20210216183023_wiki_pages_view.yml18
-rw-r--r--db/post_migrate/20210823142036_drop_temporary_trigger_for_ci_job_artifacts.rb30
-rw-r--r--db/schema_migrations/202108231420361
-rw-r--r--db/structure.sql12
-rw-r--r--doc/development/contributing/design.md14
-rw-r--r--doc/user/packages/conan_repository/index.md3
-rw-r--r--lib/gitlab/contributions_calendar.rb1
-rw-r--r--locale/gitlab.pot2
-rw-r--r--spec/frontend/blob/notebook/notebook_viever_spec.js3
-rw-r--r--spec/frontend/notebook/cells/markdown_spec.js140
-rw-r--r--spec/frontend/notebook/index_spec.js31
-rw-r--r--spec/frontend/repository/components/tree_content_spec.js7
-rw-r--r--spec/helpers/blob_helper_spec.rb24
-rw-r--r--spec/presenters/snippet_blob_presenter_spec.rb3
-rw-r--r--workhorse/go.mod3
-rw-r--r--workhorse/go.sum8
39 files changed, 368 insertions, 160 deletions
diff --git a/.gitlab/ci/workhorse.gitlab-ci.yml b/.gitlab/ci/workhorse.gitlab-ci.yml
index 92b537f3f7d..0da0a334699 100644
--- a/.gitlab/ci/workhorse.gitlab-ci.yml
+++ b/.gitlab/ci/workhorse.gitlab-ci.yml
@@ -23,10 +23,6 @@ workhorse:verify:
- apt-get update && apt-get -y install libimage-exiftool-perl
- make -C workhorse test
-workhorse:test using go 1.15:
- extends: .workhorse:test
- image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15
-
workhorse:test using go 1.16:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.16
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8bcc5e10951..0acdd73aad6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1217,6 +1217,10 @@ entry.
- [Remove diffs gradual load feature flag](gitlab-org/gitlab@027d7c4327b5b6205a84281239027273517bf81b) ([merge request](gitlab-org/gitlab!55478))
- [Remove partial index for Hashed Storage migration](gitlab-org/gitlab@3ed017a1023d7b0941a7606b69e6caee8d22f15c) ([merge request](gitlab-org/gitlab!62920))
+## 14.0.10 (2021-09-02)
+
+No changes.
+
## 14.0.9 (2021-08-31)
### Security (9 changes)
diff --git a/app/assets/javascripts/blob/notebook/index.js b/app/assets/javascripts/blob/notebook/index.js
index a8c94b6263e..25fe29c4fbe 100644
--- a/app/assets/javascripts/blob/notebook/index.js
+++ b/app/assets/javascripts/blob/notebook/index.js
@@ -6,6 +6,9 @@ export default () => {
return new Vue({
el,
+ provide: {
+ relativeRawPath: el.dataset.relativeRawPath,
+ },
render(createElement) {
return createElement(NotebookViewer, {
props: {
diff --git a/app/assets/javascripts/blob/notebook/notebook_viewer.vue b/app/assets/javascripts/blob/notebook/notebook_viewer.vue
index 02f93e14219..d2a841c88f1 100644
--- a/app/assets/javascripts/blob/notebook/notebook_viewer.vue
+++ b/app/assets/javascripts/blob/notebook/notebook_viewer.vue
@@ -77,3 +77,9 @@ export default {
</p>
</div>
</template>
+
+<style>
+.output img {
+ min-width: 0; /* https://www.w3.org/TR/css-flexbox-1/#min-size-auto */
+}
+</style>
diff --git a/app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql b/app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql
new file mode 100644
index 00000000000..1c382c4747b
--- /dev/null
+++ b/app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql
@@ -0,0 +1,10 @@
+query GroupBoardIterations($fullPath: ID!, $title: String) {
+ group(fullPath: $fullPath) {
+ iterations(includeAncestors: true, title: $title) {
+ nodes {
+ id
+ title
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql b/app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql
new file mode 100644
index 00000000000..078151a275a
--- /dev/null
+++ b/app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql
@@ -0,0 +1,10 @@
+query ProjectBoardIterations($fullPath: ID!, $title: String) {
+ project(fullPath: $fullPath) {
+ iterations(includeAncestors: true, title: $title) {
+ nodes {
+ id
+ title
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index e67b8b6235b..402205334c8 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -36,11 +36,13 @@ import {
filterVariables,
} from '../boards_util';
import boardLabelsQuery from '../graphql/board_labels.query.graphql';
+import groupBoardIterationsQuery from '../graphql/group_board_iterations.query.graphql';
import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql';
import groupProjectsQuery from '../graphql/group_projects.query.graphql';
import issueCreateMutation from '../graphql/issue_create.mutation.graphql';
import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql';
import listsIssuesQuery from '../graphql/lists_issues.query.graphql';
+import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql';
import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql';
import * as types from './mutation_types';
@@ -208,6 +210,52 @@ export default {
});
},
+ fetchIterations({ state, commit }, title) {
+ commit(types.RECEIVE_ITERATIONS_REQUEST);
+
+ const { fullPath, boardType } = state;
+
+ const variables = {
+ fullPath,
+ title,
+ };
+
+ let query;
+ if (boardType === BoardType.project) {
+ query = projectBoardIterationsQuery;
+ }
+ if (boardType === BoardType.group) {
+ query = groupBoardIterationsQuery;
+ }
+
+ if (!query) {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ throw new Error('Unknown board type');
+ }
+
+ return gqlClient
+ .query({
+ query,
+ variables,
+ })
+ .then(({ data }) => {
+ const errors = data[boardType]?.errors;
+ const iterations = data[boardType]?.iterations.nodes;
+
+ if (errors?.[0]) {
+ throw new Error(errors[0]);
+ }
+
+ commit(types.RECEIVE_ITERATIONS_SUCCESS, iterations);
+
+ return iterations;
+ })
+ .catch((e) => {
+ commit(types.RECEIVE_ITERATIONS_FAILURE);
+ throw e;
+ });
+ },
+
fetchMilestones({ state, commit }, searchTerm) {
commit(types.RECEIVE_MILESTONES_REQUEST);
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
index 31b78014525..928cece19f7 100644
--- a/app/assets/javascripts/boards/stores/mutation_types.js
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -41,3 +41,7 @@ export const ADD_LIST_TO_HIGHLIGHTED_LISTS = 'ADD_LIST_TO_HIGHLIGHTED_LISTS';
export const REMOVE_LIST_FROM_HIGHLIGHTED_LISTS = 'REMOVE_LIST_FROM_HIGHLIGHTED_LISTS';
export const RESET_BOARD_ITEM_SELECTION = 'RESET_BOARD_ITEM_SELECTION';
export const SET_ERROR = 'SET_ERROR';
+
+export const RECEIVE_ITERATIONS_REQUEST = 'RECEIVE_ITERATIONS_REQUEST';
+export const RECEIVE_ITERATIONS_SUCCESS = 'RECEIVE_ITERATIONS_SUCCESS';
+export const RECEIVE_ITERATIONS_FAILURE = 'RECEIVE_ITERATIONS_FAILURE';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index 668a3dbaa7e..86df3139e0a 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -65,6 +65,20 @@ export default {
);
},
+ [mutationTypes.RECEIVE_ITERATIONS_REQUEST](state) {
+ state.iterationsLoading = true;
+ },
+
+ [mutationTypes.RECEIVE_ITERATIONS_SUCCESS](state, iterations) {
+ state.iterations = iterations;
+ state.iterationsLoading = false;
+ },
+
+ [mutationTypes.RECEIVE_ITERATIONS_FAILURE](state) {
+ state.iterationsLoading = false;
+ state.error = __('Failed to load iterations.');
+ },
+
[mutationTypes.SET_ACTIVE_ID](state, { id, sidebarType }) {
state.activeId = id;
state.sidebarType = sidebarType;
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
index 264a03ff39d..80c51c966d2 100644
--- a/app/assets/javascripts/boards/stores/state.js
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -31,6 +31,8 @@ export default () => ({
},
selectedProject: {},
error: undefined,
+ iterations: [],
+ iterationsLoading: false,
addColumnForm: {
visible: false,
columnType: ListType.label,
diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js
index 0f3dd6eb328..a42b50edb8a 100644
--- a/app/assets/javascripts/deprecated_notes.js
+++ b/app/assets/javascripts/deprecated_notes.js
@@ -670,6 +670,10 @@ export default class Notes {
updateNote(noteEntity, $targetNote) {
// Convert returned HTML to a jQuery object so we can modify it further
const $noteEntityEl = $(noteEntity.html);
+ const $noteAvatar = $noteEntityEl.find('.image-diff-avatar-link');
+ const $targetNoteBadge = $targetNote.find('.badge');
+
+ $noteAvatar.append($targetNoteBadge);
this.revertNoteEditForm($targetNote);
$noteEntityEl.renderGFM();
// Find the note's `li` element by ID and replace it with the updated HTML
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
index 4bb35c919ed..1384c9c40b3 100644
--- a/app/assets/javascripts/notebook/cells/markdown.vue
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -94,7 +94,16 @@ renderer.image = function image(href, title, text) {
const attachmentHeader = `attachment:`; // eslint-disable-line @gitlab/require-i18n-strings
if (!this.attachments || !href.startsWith(attachmentHeader)) {
- return this.originalImage(href, title, text);
+ let relativeHref = href;
+
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ if (!(href.startsWith('http') || href.startsWith('data:'))) {
+ // These are images within the repo. This will only work if the image
+ // is relative to the path where the file is located
+ relativeHref = this.relativeRawPath + href;
+ }
+
+ return this.originalImage(relativeHref, title, text);
}
let img = ``;
@@ -129,6 +138,7 @@ export default {
components: {
prompt: Prompt,
},
+ inject: ['relativeRawPath'],
props: {
cell: {
type: Object,
@@ -138,6 +148,7 @@ export default {
computed: {
markdown() {
renderer.attachments = this.cell.attachments;
+ renderer.relativeRawPath = this.relativeRawPath;
return sanitize(marked(this.cell.source.join('').replace(/\\/g, '\\\\')), markdownConfig);
},
diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue
index 69eefc807d7..10a30bd44b1 100644
--- a/app/assets/javascripts/repository/components/table/index.vue
+++ b/app/assets/javascripts/repository/components/table/index.vue
@@ -100,9 +100,9 @@ export default {
/>
<template v-for="val in entries">
<table-row
- v-for="entry in val"
+ v-for="(entry, index) in val"
:id="entry.id"
- :key="`${entry.flatPath}-${entry.id}`"
+ :key="`${entry.flatPath}-${entry.id}-${index}`"
:sha="entry.sha"
:project-path="projectPath"
:current-path="path"
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index 528b1096f40..009dd19b4a5 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -10,6 +10,7 @@ import {
} from '@gitlab/ui';
import { escapeRegExp } from 'lodash';
import filesQuery from 'shared_queries/repository/files.query.graphql';
+import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
import { escapeFileUrl } from '~/lib/utils/url_utility';
import { TREE_PAGE_SIZE } from '~/repository/constants';
import FileIcon from '~/vue_shared/components/file_icon.vue';
@@ -153,7 +154,8 @@ export default {
return this.isFolder ? this.loadFolder() : this.loadBlob();
},
loadFolder() {
- this.apolloQuery(filesQuery, {
+ const query = this.glFeatures.paginatedTreeGraphqlQuery ? paginatedTreeQuery : filesQuery;
+ this.apolloQuery(query, {
projectPath: this.projectPath,
ref: this.ref,
path: this.path,
diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue
index c861fb8dd06..5a8ead9ae8f 100644
--- a/app/assets/javascripts/repository/components/tree_content.vue
+++ b/app/assets/javascripts/repository/components/tree_content.vue
@@ -1,5 +1,6 @@
<script>
import filesQuery from 'shared_queries/repository/files.query.graphql';
+import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
import createFlash from '~/flash';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __ } from '../../locale';
@@ -69,6 +70,9 @@ export default {
hasShowMore() {
return !this.clickedShowMore && this.pageLimitReached;
},
+ paginatedTreeEnabled() {
+ return this.glFeatures.paginatedTreeGraphqlQuery;
+ },
},
watch: {
@@ -91,7 +95,7 @@ export default {
return this.$apollo
.query({
- query: filesQuery,
+ query: this.paginatedTreeEnabled ? paginatedTreeQuery : filesQuery,
variables: {
projectPath: this.projectPath,
ref: this.ref,
@@ -104,13 +108,20 @@ export default {
if (data.errors) throw data.errors;
if (!data?.project?.repository || originalPath !== (this.path || '/')) return;
- const pageInfo = this.hasNextPage(data.project.repository.tree);
+ const pageInfo = this.paginatedTreeEnabled
+ ? data.project.repository.paginatedTree.pageInfo
+ : this.hasNextPage(data.project.repository.tree);
this.isLoadingFiles = false;
this.entries = Object.keys(this.entries).reduce(
(acc, key) => ({
...acc,
- [key]: this.normalizeData(key, data.project.repository.tree[key].edges),
+ [key]: this.normalizeData(
+ key,
+ this.paginatedTreeEnabled
+ ? data.project.repository.paginatedTree.nodes[0][key]
+ : data.project.repository.tree[key].edges,
+ ),
}),
{},
);
@@ -132,7 +143,9 @@ export default {
});
},
normalizeData(key, data) {
- return this.entries[key].concat(data.map(({ node }) => node));
+ return this.entries[key].concat(
+ this.paginatedTreeEnabled ? data.nodes : data.map(({ node }) => node),
+ );
},
hasNextPage(data) {
return []
diff --git a/app/assets/javascripts/repository/mixins/preload.js b/app/assets/javascripts/repository/mixins/preload.js
index ffc260ec84f..a2ddcbf0e4c 100644
--- a/app/assets/javascripts/repository/mixins/preload.js
+++ b/app/assets/javascripts/repository/mixins/preload.js
@@ -1,4 +1,5 @@
import filesQuery from 'shared_queries/repository/files.query.graphql';
+import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
import projectPathQuery from '../queries/project_path.query.graphql';
import getRefMixin from './get_ref';
@@ -21,7 +22,7 @@ export default {
return this.$apollo
.query({
- query: filesQuery,
+ query: gon.features.paginatedTreeGraphqlQuery ? paginatedTreeQuery : filesQuery,
variables: {
projectPath: this.projectPath,
ref: this.ref,
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 475c9de2503..6fd4c632dd3 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -15,6 +15,10 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_download_code!
before_action :authorize_edit_tree!, only: [:create_dir]
+ before_action do
+ push_frontend_feature_flag(:paginated_tree_graphql_query, @project, default_enabled: :yaml)
+ end
+
feature_category :source_code_management
def show
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index bdb645e1934..d7c1d87ae4b 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -34,6 +34,7 @@ class ProjectsController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml)
+ push_frontend_feature_flag(:paginated_tree_graphql_query, @project, default_enabled: :yaml)
end
layout :determine_layout
diff --git a/app/graphql/queries/repository/paginated_tree.query.graphql b/app/graphql/queries/repository/paginated_tree.query.graphql
new file mode 100644
index 00000000000..e82bc6d0734
--- /dev/null
+++ b/app/graphql/queries/repository/paginated_tree.query.graphql
@@ -0,0 +1,54 @@
+fragment TreeEntry on Entry {
+ __typename
+ id
+ sha
+ name
+ flatPath
+ type
+}
+
+query getPaginatedTree($projectPath: ID!, $path: String, $ref: String!, $nextPageCursor: String) {
+ project(fullPath: $projectPath) {
+ id
+ __typename
+ repository {
+ __typename
+ paginatedTree(path: $path, ref: $ref, after: $nextPageCursor) {
+ __typename
+ pageInfo {
+ __typename
+ endCursor
+ startCursor
+ hasNextPage
+ }
+ nodes {
+ __typename
+ trees {
+ __typename
+ nodes {
+ ...TreeEntry
+ webPath
+ }
+ }
+ submodules {
+ __typename
+ nodes {
+ ...TreeEntry
+ webUrl
+ treeUrl
+ }
+ }
+ blobs {
+ __typename
+ nodes {
+ ...TreeEntry
+ mode
+ webPath
+ lfsOid
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index c1a33794b50..f0e8ff7778e 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -183,6 +183,10 @@ module BlobHelper
blob_raw_url(**kwargs, only_path: true)
end
+ def parent_dir_raw_path
+ blob_raw_path.rpartition("/").first + "/"
+ end
+
# SVGs can contain malicious JavaScript; only include whitelisted
# elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements.
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 1f0da4345f2..b22b2d3e264 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -10,6 +10,9 @@ module Ci
include Artifactable
include FileStoreMounter
include EachBatch
+ include IgnorableColumns
+
+ ignore_columns %i[id_convert_to_bigint job_id_convert_to_bigint], remove_with: '14.5', remove_after: '2021-11-22'
TEST_REPORT_FILE_TYPES = %w[junit].freeze
COVERAGE_REPORT_FILE_TYPES = %w[cobertura].freeze
diff --git a/app/presenters/snippet_blob_presenter.rb b/app/presenters/snippet_blob_presenter.rb
index 0003a13a7bc..ab8fc0f905b 100644
--- a/app/presenters/snippet_blob_presenter.rb
+++ b/app/presenters/snippet_blob_presenter.rb
@@ -17,6 +17,10 @@ class SnippetBlobPresenter < BlobPresenter
snippet_blob_raw_route
end
+ def raw_directory
+ raw_path.rpartition("/").first + "/"
+ end
+
def raw_plain_data
blob.data unless blob.binary?
end
@@ -33,7 +37,7 @@ class SnippetBlobPresenter < BlobPresenter
def render_rich_partial
renderer.render("projects/blob/viewers/_#{blob.rich_viewer.partial_name}",
- locals: { viewer: blob.rich_viewer, blob: blob, blob_raw_path: raw_path, blob_raw_url: raw_url },
+ locals: { viewer: blob.rich_viewer, blob: blob, blob_raw_path: raw_path, blob_raw_url: raw_url, parent_dir_raw_path: raw_directory },
layout: false)
end
diff --git a/app/views/projects/blob/viewers/_notebook.html.haml b/app/views/projects/blob/viewers/_notebook.html.haml
index eb4ca1b9816..b537a48e087 100644
--- a/app/views/projects/blob/viewers/_notebook.html.haml
+++ b/app/views/projects/blob/viewers/_notebook.html.haml
@@ -1 +1 @@
-.file-content#js-notebook-viewer{ data: { endpoint: blob_raw_path } }
+.file-content#js-notebook-viewer{ data: { endpoint: blob_raw_path, relative_raw_path: parent_dir_raw_path } }
diff --git a/config/metrics/counts_all/20210216183023_wiki_pages_view.yml b/config/metrics/counts_all/20210216183023_wiki_pages_view.yml
index 75403722e5c..d7694fd36a1 100644
--- a/config/metrics/counts_all/20210216183023_wiki_pages_view.yml
+++ b/config/metrics/counts_all/20210216183023_wiki_pages_view.yml
@@ -1,18 +1,22 @@
---
data_category: optional
key_path: counts.wiki_pages_view
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Total number of wiki page views
+product_section: dev
+product_stage: create
+product_group: group::editor
+product_category: wiki
value_type: number
status: data_available
+milestone: "13.3"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38784"
time_frame: all
-data_source: database
+data_source: redis
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
performance_indicator_type: []
diff --git a/db/post_migrate/20210823142036_drop_temporary_trigger_for_ci_job_artifacts.rb b/db/post_migrate/20210823142036_drop_temporary_trigger_for_ci_job_artifacts.rb
new file mode 100644
index 00000000000..42b25a192d5
--- /dev/null
+++ b/db/post_migrate/20210823142036_drop_temporary_trigger_for_ci_job_artifacts.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class DropTemporaryTriggerForCiJobArtifacts < ActiveRecord::Migration[6.1]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ TABLE = 'ci_job_artifacts'
+ TEMPORARY_COLUMNS = %w(id_convert_to_bigint job_id_convert_to_bigint)
+ MAIN_COLUMNS = %w(id job_id)
+ TRIGGER = 'trigger_be1804f21693'
+
+ # rubocop:disable Migration/WithLockRetriesDisallowedMethod
+ def up
+ check_trigger_permissions!(TABLE)
+
+ with_lock_retries do
+ remove_rename_triggers(TABLE, TRIGGER)
+ end
+ end
+
+ def down
+ check_trigger_permissions!(TABLE)
+
+ with_lock_retries do
+ install_rename_triggers(TABLE, MAIN_COLUMNS, TEMPORARY_COLUMNS, trigger_name: TRIGGER)
+ end
+ end
+ # rubocop:enable Migration/WithLockRetriesDisallowedMethod
+end
diff --git a/db/schema_migrations/20210823142036 b/db/schema_migrations/20210823142036
new file mode 100644
index 00000000000..ec24927dfcf
--- /dev/null
+++ b/db/schema_migrations/20210823142036
@@ -0,0 +1 @@
+874ed71410406d10ade9c834d1374b039effd9e88514d327d04275e11e837ffb \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index ca27bf2e816..db686151cfa 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -153,16 +153,6 @@ BEGIN
END;
$$;
-CREATE FUNCTION trigger_be1804f21693() RETURNS trigger
- LANGUAGE plpgsql
- AS $$
-BEGIN
- NEW."id_convert_to_bigint" := NEW."id";
- NEW."job_id_convert_to_bigint" := NEW."job_id";
- RETURN NEW;
-END;
-$$;
-
CREATE FUNCTION trigger_cf2f9e35f002() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -27351,8 +27341,6 @@ CREATE TRIGGER trigger_91dc388a5fe6 BEFORE INSERT OR UPDATE ON dep_ci_build_trac
CREATE TRIGGER trigger_aebe8b822ad3 BEFORE INSERT OR UPDATE ON taggings FOR EACH ROW EXECUTE FUNCTION trigger_aebe8b822ad3();
-CREATE TRIGGER trigger_be1804f21693 BEFORE INSERT OR UPDATE ON ci_job_artifacts FOR EACH ROW EXECUTE FUNCTION trigger_be1804f21693();
-
CREATE TRIGGER trigger_cf2f9e35f002 BEFORE INSERT OR UPDATE ON ci_build_trace_chunks FOR EACH ROW EXECUTE FUNCTION trigger_cf2f9e35f002();
CREATE TRIGGER trigger_f1ca8ec18d78 BEFORE INSERT OR UPDATE ON geo_job_artifact_deleted_events FOR EACH ROW EXECUTE FUNCTION trigger_f1ca8ec18d78();
diff --git a/doc/development/contributing/design.md b/doc/development/contributing/design.md
index 446e7227413..9e8375fcbdd 100644
--- a/doc/development/contributing/design.md
+++ b/doc/development/contributing/design.md
@@ -11,28 +11,28 @@ For guidance on UX implementation at GitLab, please refer to our [Design System]
The UX team uses labels to manage their workflow.
-The ~"UX" label on an issue is a signal to the UX team that it will need UX attention.
+The `~UX` label on an issue is a signal to the UX team that it will need UX attention.
To better understand the priority by which UX tackles issues, see the [UX section](https://about.gitlab.com/handbook/engineering/ux/) of the handbook.
-Once an issue has been worked on and is ready for development, a UXer removes the ~"UX" label and applies the ~"UX ready" label to that issue.
+Once an issue has been worked on and is ready for development, a UXer removes the `~UX` label and applies the `~"UX ready"` label to that issue.
-There is a special type label called ~"product discovery" intended for UX,
-PM, FE, and BE. It represents a discovery issue to discuss the problem and
+There is a special type label called `~"product discovery"` intended for UX (user experience),
+PM (product manager), FE (frontend), and BE (backend). It represents a discovery issue to discuss the problem and
potential solutions. The final output for this issue could be a doc of
requirements, a design artifact, or even a prototype. The solution will be
developed in a subsequent milestone.
-~"product discovery" issues are like any other issue and should contain a milestone label, ~"Deliverable" or ~"Stretch", when scheduled in the current milestone.
+`~"product discovery"` issues are like any other issue and should contain a milestone label, `~Deliverable` or `~Stretch`, when scheduled in the current milestone.
The initial issue should be about the problem we are solving. If a separate [product discovery issue](https://about.gitlab.com/handbook/engineering/ux/ux-department-workflow/#how-we-use-labels)
is needed for additional research and design work, it will be created by a PM or UX person.
-Assign the ~UX, ~"product discovery" and ~"Deliverable" labels, add a milestone and
+Assign the `~UX`, `~"product discovery"` and `~Deliverable` labels, add a milestone and
use a title that makes it clear that the scheduled issue is product discovery
(for example, `Product discovery for XYZ`).
In order to complete a product discovery issue in a release, you must complete the following:
-1. UXer removes the ~UX label, adds the ~"UX ready" label.
+1. UXer removes the `~UX` label, adds the `~"UX ready"` label.
1. Modify the issue description in the product discovery issue to contain the final design. If it makes sense, the original information indicating the need for the design can be moved to a lower "Original Information" section.
1. Copy the design to the description of the delivery issue for which the product discovery issue was created. Do not simply refer to the product discovery issue as a separate source of truth.
1. In some cases, a product discovery issue also identifies future enhancements that will not go into the issue that originated the product discovery issue. For these items, create new issues containing the designs to ensure they are not lost. Put the issues in the backlog if they are agreed upon as good ideas. Otherwise leave them for triage.
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index d3e913edfda..dc08baaf731 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -297,9 +297,6 @@ dependency. You can install a package from the scope of your instance or your pr
If multiple packages have the same recipe, when you install
a package, the most recently-published package is retrieved.
-WARNING:
-Project-level packages [cannot be downloaded currently](https://gitlab.com/gitlab-org/gitlab/-/issues/270129).
-
Conan packages are often installed as dependencies by using the `conanfile.txt`
file.
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 4e430d8937d..7d7c604d86a 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -33,6 +33,7 @@ module Gitlab
.having(action: :commented)
events = Event
+ .select(:project_id, :target_type, :action, :date, :total_amount)
.from_union([repo_events, issue_events, mr_events, note_events])
.map(&:attributes)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 462b0d7dcb7..a50f3fda7d3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -29128,7 +29128,7 @@ msgstr ""
msgid "SastEntryPoints|How do I set up SAST?"
msgstr ""
-msgid "SastEntryPoints|Learn more."
+msgid "SastEntryPoints|Learn more"
msgstr ""
msgid "Satisfied"
diff --git a/spec/frontend/blob/notebook/notebook_viever_spec.js b/spec/frontend/blob/notebook/notebook_viever_spec.js
index 604104bb31f..93406db2675 100644
--- a/spec/frontend/blob/notebook/notebook_viever_spec.js
+++ b/spec/frontend/blob/notebook/notebook_viever_spec.js
@@ -11,6 +11,7 @@ describe('iPython notebook renderer', () => {
let mock;
const endpoint = 'test';
+ const relativeRawPath = '';
const mockNotebook = {
cells: [
{
@@ -27,7 +28,7 @@ describe('iPython notebook renderer', () => {
};
const mountComponent = () => {
- wrapper = shallowMount(component, { propsData: { endpoint } });
+ wrapper = shallowMount(component, { propsData: { endpoint, relativeRawPath } });
};
const findLoading = () => wrapper.find(GlLoadingIcon);
diff --git a/spec/frontend/notebook/cells/markdown_spec.js b/spec/frontend/notebook/cells/markdown_spec.js
index deeee5d6589..707efa21528 100644
--- a/spec/frontend/notebook/cells/markdown_spec.js
+++ b/spec/frontend/notebook/cells/markdown_spec.js
@@ -1,3 +1,4 @@
+import { mount } from '@vue/test-utils';
import katex from 'katex';
import Vue from 'vue';
import MarkdownComponent from '~/notebook/cells/markdown.vue';
@@ -6,6 +7,28 @@ const Component = Vue.extend(MarkdownComponent);
window.katex = katex;
+function buildCellComponent(cell, relativePath = '') {
+ return mount(Component, {
+ propsData: {
+ cell,
+ },
+ provide: {
+ relativeRawPath: relativePath,
+ },
+ }).vm;
+}
+
+function buildMarkdownComponent(markdownContent, relativePath = '') {
+ return buildCellComponent(
+ {
+ cell_type: 'markdown',
+ metadata: {},
+ source: markdownContent,
+ },
+ relativePath,
+ );
+}
+
describe('Markdown component', () => {
let vm;
let cell;
@@ -17,12 +40,7 @@ describe('Markdown component', () => {
// eslint-disable-next-line prefer-destructuring
cell = json.cells[1];
- vm = new Component({
- propsData: {
- cell,
- },
- });
- vm.$mount();
+ vm = buildCellComponent(cell);
return vm.$nextTick();
});
@@ -61,17 +79,36 @@ describe('Markdown component', () => {
expect(findLink().getAttribute('data-type')).toBe(null);
});
+ describe('When parsing images', () => {
+ it.each([
+ [
+ 'for relative images in root folder, it does',
+ '![](local_image.png)\n',
+ 'src="/raw/local_image',
+ ],
+ [
+ 'for relative images in child folders, it does',
+ '![](data/local_image.png)\n',
+ 'src="/raw/data',
+ ],
+ ["for embedded images, it doesn't", '![](data:image/jpeg;base64)\n', 'src="data:'],
+ ["for images urls, it doesn't", '![](http://image.png)\n', 'src="http:'],
+ ])('%s', async ([testMd, mustContain]) => {
+ vm = buildMarkdownComponent([testMd], '/raw/');
+
+ await vm.$nextTick();
+
+ expect(vm.$el.innerHTML).toContain(mustContain);
+ });
+ });
+
describe('tables', () => {
beforeEach(() => {
json = getJSONFixture('blob/notebook/markdown-table.json');
});
it('renders images and text', () => {
- vm = new Component({
- propsData: {
- cell: json.cells[0],
- },
- }).$mount();
+ vm = buildCellComponent(json.cells[0]);
return vm.$nextTick().then(() => {
const images = vm.$el.querySelectorAll('img');
@@ -102,48 +139,28 @@ describe('Markdown component', () => {
});
it('renders multi-line katex', async () => {
- vm = new Component({
- propsData: {
- cell: json.cells[0],
- },
- }).$mount();
+ vm = buildCellComponent(json.cells[0]);
await vm.$nextTick();
expect(vm.$el.querySelector('.katex')).not.toBeNull();
});
it('renders inline katex', async () => {
- vm = new Component({
- propsData: {
- cell: json.cells[1],
- },
- }).$mount();
+ vm = buildCellComponent(json.cells[1]);
await vm.$nextTick();
expect(vm.$el.querySelector('p:first-child .katex')).not.toBeNull();
});
it('renders multiple inline katex', async () => {
- vm = new Component({
- propsData: {
- cell: json.cells[1],
- },
- }).$mount();
+ vm = buildCellComponent(json.cells[1]);
await vm.$nextTick();
expect(vm.$el.querySelectorAll('p:nth-child(2) .katex')).toHaveLength(4);
});
it('output cell in case of katex error', async () => {
- vm = new Component({
- propsData: {
- cell: {
- cell_type: 'markdown',
- metadata: {},
- source: ['Some invalid $a & b$ inline formula $b & c$\n', '\n'],
- },
- },
- }).$mount();
+ vm = buildMarkdownComponent(['Some invalid $a & b$ inline formula $b & c$\n', '\n']);
await vm.$nextTick();
// expect one paragraph with no katex formula in it
@@ -152,15 +169,10 @@ describe('Markdown component', () => {
});
it('output cell and render remaining formula in case of katex error', async () => {
- vm = new Component({
- propsData: {
- cell: {
- cell_type: 'markdown',
- metadata: {},
- source: ['An invalid $a & b$ inline formula and a vaild one $b = c$\n', '\n'],
- },
- },
- }).$mount();
+ vm = buildMarkdownComponent([
+ 'An invalid $a & b$ inline formula and a vaild one $b = c$\n',
+ '\n',
+ ]);
await vm.$nextTick();
// expect one paragraph with no katex formula in it
@@ -169,15 +181,7 @@ describe('Markdown component', () => {
});
it('renders math formula in list object', async () => {
- vm = new Component({
- propsData: {
- cell: {
- cell_type: 'markdown',
- metadata: {},
- source: ["- list with inline $a=2$ inline formula $a' + b = c$\n", '\n'],
- },
- },
- }).$mount();
+ vm = buildMarkdownComponent(["- list with inline $a=2$ inline formula $a' + b = c$\n", '\n']);
await vm.$nextTick();
// expect one list with a katex formula in it
@@ -186,15 +190,7 @@ describe('Markdown component', () => {
});
it("renders math formula with tick ' in it", async () => {
- vm = new Component({
- propsData: {
- cell: {
- cell_type: 'markdown',
- metadata: {},
- source: ["- list with inline $a=2$ inline formula $a' + b = c$\n", '\n'],
- },
- },
- }).$mount();
+ vm = buildMarkdownComponent(["- list with inline $a=2$ inline formula $a' + b = c$\n", '\n']);
await vm.$nextTick();
// expect one list with a katex formula in it
@@ -203,15 +199,7 @@ describe('Markdown component', () => {
});
it('renders math formula with less-than-operator < in it', async () => {
- vm = new Component({
- propsData: {
- cell: {
- cell_type: 'markdown',
- metadata: {},
- source: ['- list with inline $a=2$ inline formula $a + b < c$\n', '\n'],
- },
- },
- }).$mount();
+ vm = buildMarkdownComponent(['- list with inline $a=2$ inline formula $a + b < c$\n', '\n']);
await vm.$nextTick();
// expect one list with a katex formula in it
@@ -220,15 +208,7 @@ describe('Markdown component', () => {
});
it('renders math formula with greater-than-operator > in it', async () => {
- vm = new Component({
- propsData: {
- cell: {
- cell_type: 'markdown',
- metadata: {},
- source: ['- list with inline $a=2$ inline formula $a + b > c$\n', '\n'],
- },
- },
- }).$mount();
+ vm = buildMarkdownComponent(['- list with inline $a=2$ inline formula $a + b > c$\n', '\n']);
await vm.$nextTick();
// expect one list with a katex formula in it
diff --git a/spec/frontend/notebook/index_spec.js b/spec/frontend/notebook/index_spec.js
index 945af08e4d5..4d0dacaf37e 100644
--- a/spec/frontend/notebook/index_spec.js
+++ b/spec/frontend/notebook/index_spec.js
@@ -1,3 +1,4 @@
+import { mount } from '@vue/test-utils';
import Vue from 'vue';
import Notebook from '~/notebook/index.vue';
@@ -13,14 +14,16 @@ describe('Notebook component', () => {
jsonWithWorksheet = getJSONFixture('blob/notebook/worksheets.json');
});
+ function buildComponent(notebook) {
+ return mount(Component, {
+ propsData: { notebook, codeCssClass: 'js-code-class' },
+ provide: { relativeRawPath: '' },
+ }).vm;
+ }
+
describe('without JSON', () => {
beforeEach((done) => {
- vm = new Component({
- propsData: {
- notebook: {},
- },
- });
- vm.$mount();
+ vm = buildComponent({});
setImmediate(() => {
done();
@@ -34,13 +37,7 @@ describe('Notebook component', () => {
describe('with JSON', () => {
beforeEach((done) => {
- vm = new Component({
- propsData: {
- notebook: json,
- codeCssClass: 'js-code-class',
- },
- });
- vm.$mount();
+ vm = buildComponent(json);
setImmediate(() => {
done();
@@ -66,13 +63,7 @@ describe('Notebook component', () => {
describe('with worksheets', () => {
beforeEach((done) => {
- vm = new Component({
- propsData: {
- notebook: jsonWithWorksheet,
- codeCssClass: 'js-code-class',
- },
- });
- vm.$mount();
+ vm = buildComponent(jsonWithWorksheet);
setImmediate(() => {
done();
diff --git a/spec/frontend/repository/components/tree_content_spec.js b/spec/frontend/repository/components/tree_content_spec.js
index 1d1ec58100f..e36287eff29 100644
--- a/spec/frontend/repository/components/tree_content_spec.js
+++ b/spec/frontend/repository/components/tree_content_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import filesQuery from 'shared_queries/repository/files.query.graphql';
+import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
import FilePreview from '~/repository/components/preview/index.vue';
import FileTable from '~/repository/components/table/index.vue';
import TreeContent from '~/repository/components/tree_content.vue';
@@ -22,6 +22,7 @@ function factory(path, data = () => ({})) {
provide: {
glFeatures: {
increasePageSizeExponentially: true,
+ paginatedTreeGraphqlQuery: true,
},
},
});
@@ -58,7 +59,7 @@ describe('Repository table component', () => {
it('normalizes edge nodes', () => {
factory('/');
- const output = vm.vm.normalizeData('blobs', [{ node: '1' }, { node: '2' }]);
+ const output = vm.vm.normalizeData('blobs', { nodes: ['1', '2'] });
expect(output).toEqual(['1', '2']);
});
@@ -168,7 +169,7 @@ describe('Repository table component', () => {
vm.vm.fetchFiles();
expect($apollo.query).toHaveBeenCalledWith({
- query: filesQuery,
+ query: paginatedTreeQuery,
variables: {
pageSize,
nextPageCursor: '',
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index c48d609836d..efcb8125f68 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -92,6 +92,30 @@ RSpec.describe BlobHelper do
end
end
+ describe "#relative_raw_path" do
+ include FakeBlobHelpers
+
+ let_it_be(:project) { create(:project) }
+
+ before do
+ assign(:project, project)
+ end
+
+ [
+ %w[/file.md /-/raw/main/],
+ %w[/test/file.md /-/raw/main/test/],
+ %w[/another/test/file.md /-/raw/main/another/test/]
+ ].each do |file_path, expected_path|
+ it "pointing from '#{file_path}' to '#{expected_path}'" do
+ blob = fake_blob(path: file_path)
+ assign(:blob, blob)
+ assign(:id, "main#{blob.path}")
+ assign(:path, blob.path)
+
+ expect(helper.parent_dir_raw_path).to eq "/#{project.full_path}#{expected_path}"
+ end
+ end
+ end
context 'viewer related' do
include FakeBlobHelpers
diff --git a/spec/presenters/snippet_blob_presenter_spec.rb b/spec/presenters/snippet_blob_presenter_spec.rb
index 1a5130dcdf6..d7f56c30b5e 100644
--- a/spec/presenters/snippet_blob_presenter_spec.rb
+++ b/spec/presenters/snippet_blob_presenter_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe SnippetBlobPresenter do
describe '#rich_data' do
let(:data_endpoint_url) { "/-/snippets/#{snippet.id}/raw/#{branch}/#{file}" }
+ let(:data_raw_dir) { "/-/snippets/#{snippet.id}/raw/#{branch}/" }
before do
allow_next_instance_of(described_class) do |instance|
@@ -45,7 +46,7 @@ RSpec.describe SnippetBlobPresenter do
let(:file) { 'test.ipynb' }
it 'returns rich notebook content' do
- expect(subject.strip).to eq %Q(<div class="file-content" data-endpoint="#{data_endpoint_url}" id="js-notebook-viewer"></div>)
+ expect(subject.strip).to eq %Q(<div class="file-content" data-endpoint="#{data_endpoint_url}" data-relative-raw-path="#{data_raw_dir}" id="js-notebook-viewer"></div>)
end
end
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 3ce279f2ccc..4c272310232 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -1,6 +1,6 @@
module gitlab.com/gitlab-org/gitlab/workhorse
-go 1.15
+go 1.16
require (
github.com/Azure/azure-storage-blob-go v0.11.1-0.20201209121048-6df5d9af221d
@@ -31,7 +31,6 @@ require (
gitlab.com/gitlab-org/gitaly/v14 v14.0.0-rc1
gitlab.com/gitlab-org/labkit v1.6.0
gocloud.dev v0.21.1-0.20201223184910-5094f54ed8bb
- golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4
diff --git a/workhorse/go.sum b/workhorse/go.sum
index bb7f4f70fc4..d30ea93e18e 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -246,7 +246,6 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu
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/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=
@@ -267,7 +266,6 @@ github.com/git-lfs/gitobj/v2 v2.0.1/go.mod h1:q6aqxl6Uu3gWsip5GEKpw+7459F97er8CO
github.com/git-lfs/go-netrc v0.0.0-20180525200031-e0e9ca483a18/go.mod h1:70O4NAtvWn1jW8V8V+OKrJJYcxDLTmIozfi2fmSz5SI=
github.com/git-lfs/wildmatch v1.0.4/go.mod h1:SdHAGnApDpnFYQ0vAxbniWR0sn7yLJ3QXo9RRfhn2ew=
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=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -373,7 +371,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
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=
@@ -638,7 +635,6 @@ github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.0.0-20170505043639-c605e284fe17/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -850,8 +846,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
-golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1123,9 +1117,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
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=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
-gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
-gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=