diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 7c7053aa2388aa86bdb21e78ebbc049c21fed55d..32a6ce3c719b4aba1c8d630cd8d1f41b93317e18 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -1.75.0 +1.76.0 diff --git a/app/assets/javascripts/ide/lib/files.js b/app/assets/javascripts/ide/lib/files.js index e86dac2010466b96179bd804ab0c3074912c75c7..bee867fa47c1b00db37420c01504cb497817d795 100644 --- a/app/assets/javascripts/ide/lib/files.js +++ b/app/assets/javascripts/ide/lib/files.js @@ -1,5 +1,6 @@ import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils'; -import { decorateData, sortTree, escapeFileUrl } from '../stores/utils'; +import { escapeFileUrl } from '~/lib/utils/url_utility'; +import { decorateData, sortTree } from '../stores/utils'; export const splitParent = path => { const idx = path.lastIndexOf('/'); diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js index f6ad2f9c7d19787461a8cf6f6c705a1c92d8ba1e..b130e6e8b81b0537403cb4d6056f15869ca0e1d6 100644 --- a/app/assets/javascripts/ide/services/index.js +++ b/app/assets/javascripts/ide/services/index.js @@ -1,6 +1,5 @@ import axios from '~/lib/utils/axios_utils'; -import { joinPaths } from '~/lib/utils/url_utility'; -import { escapeFileUrl } from '../stores/utils'; +import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; import Api from '~/api'; export default { diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 9af0b50d1a564569f9ff772c1b46b7f87ebf1ff5..8864224c19e627b11b3cff42bdaeb23e0fb5ac70 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -1,10 +1,10 @@ -import { joinPaths } from '~/lib/utils/url_utility'; +import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import eventHub from '../../eventhub'; import service from '../../services'; import * as types from '../mutation_types'; import router from '../../ide_router'; -import { escapeFileUrl, addFinalNewlineIfNeeded, setPageTitleForFile } from '../utils'; +import { addFinalNewlineIfNeeded, setPageTitleForFile } from '../utils'; import { viewerTypes, stageKeys } from '../../constants'; export const closeFile = ({ commit, state, dispatch }, file) => { diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js index a29d9bf3b4097c70f16c97b20bb00b5482c8c49a..06e66da1069c5e6e7fa945710a6fa037c520c9ff 100644 --- a/app/assets/javascripts/ide/stores/utils.js +++ b/app/assets/javascripts/ide/stores/utils.js @@ -1,4 +1,5 @@ import { commitActionTypes, FILE_VIEW_MODE_EDITOR } from '../constants'; +import { escapeFileUrl } from '~/lib/utils/url_utility'; export const dataStructure = () => ({ id: '', @@ -217,8 +218,6 @@ export const mergeTrees = (fromTree, toTree) => { return toTree; }; -export const escapeFileUrl = fileUrl => encodeURIComponent(fileUrl).replace(/%2F/g, '/'); - export const replaceFileUrl = (url, oldPath, newPath) => { // Add `/-/` so that we don't accidentally replace project path const result = url.replace(`/-/${escapeFileUrl(oldPath)}`, `/-/${escapeFileUrl(newPath)}`); diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index cf1caed5cee3f036005f3164adecc815b73bef6e..d48678c21f61e96c3f0442e4e4f24e8b0fef0fb8 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -280,3 +280,5 @@ export const setUrlParams = (params, url = window.location.href, clearParams = f return urlObj.toString(); }; + +export const escapeFileUrl = fileUrl => encodeURIComponent(fileUrl).replace(/%2F/g, '/'); diff --git a/changelogs/unreleased/gitaly-version-v1.76.0.yml b/changelogs/unreleased/gitaly-version-v1.76.0.yml new file mode 100644 index 0000000000000000000000000000000000000000..9cf34e3a05f258946efe791168010850e6d91587 --- /dev/null +++ b/changelogs/unreleased/gitaly-version-v1.76.0.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade to Gitaly v1.76.0 +merge_request: 21857 +author: +type: changed diff --git a/db/post_migrate/20191030223057_backfill_version_author_and_created_at.rb b/db/post_migrate/20191030223057_backfill_version_author_and_created_at.rb new file mode 100644 index 0000000000000000000000000000000000000000..7a6d0b089a053edfd70a43aa854471dbd72dd3fd --- /dev/null +++ b/db/post_migrate/20191030223057_backfill_version_author_and_created_at.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +class BackfillVersionAuthorAndCreatedAt < ActiveRecord::Migration[5.2] + DOWNTIME = false + MIGRATION = 'BackfillVersionDataFromGitaly'.freeze + BATCH_SIZE = 500 + + disable_ddl_transaction! + + class Project < ActiveRecord::Base + self.table_name = 'projects' + self.inheritance_column = :_type_disabled + end + + class Issue < ActiveRecord::Base + self.table_name = 'issues' + self.inheritance_column = :_type_disabled + end + + class Version < ActiveRecord::Base + include EachBatch + self.table_name = 'design_management_versions' + self.inheritance_column = :_type_disabled + + # Returns unique issue ids of versions that are not in projects + # that are pending deletion. + scope :with_unique_issue_ids, -> do + versions = Version.arel_table + issues = Issue.arel_table + projects = Project.arel_table + + Version.select(versions[:issue_id]).where( + versions[:author_id].eq(nil).or( + versions[:created_at].eq(nil) + ).and( + issues[:project_id].not_in( + projects.project(projects[:id]).where(projects[:pending_delete].eq(true)) + ) + ) + ).joins( + versions.join(issues).on( + issues[:id].eq(versions[:issue_id]) + ).join_sources + ).distinct + end + end + + # This migration will make around ~1300 UPDATE queries on GitLab.com, + # one per design_management_versions record as the migration will update + # each record individually. + # + # It will make around 870 Gitaly `ListCommitsByOid` requests on GitLab.com. + # One for every unique issue with design_management_versions records. + def up + return unless Gitlab.ee? # no-op for CE + + Version.with_unique_issue_ids.each_batch(of: BATCH_SIZE) do |versions, index| + jobs = versions.map { |version| [MIGRATION, [version.issue_id]] } + + BackgroundMigrationWorker.bulk_perform_async(jobs) + end + end + + def down + # no-op + end +end diff --git a/doc/integration/github.md b/doc/integration/github.md index eaf81b8a1b727b7e44339914cfe00be3fdcf351c..f46038269c079afffe0e7ab20a00218b3255921a 100644 --- a/doc/integration/github.md +++ b/doc/integration/github.md @@ -175,7 +175,7 @@ Check the [`production.log`](../administration/logs.md#productionlog) on your GitLab server to obtain further details. If you are getting the error like `Faraday::ConnectionFailed (execution expired)` in the log, there may be a connectivity issue between your GitLab instance and GitHub Enterprise. To verify it, [start the rails console](https://docs.gitlab.com/omnibus/maintenance/#starting-a-rails-console-session) -and run the commands below replacing with the URL of your GitHub Enterprise instance: +and run the commands below replacing `` with the URL of your GitHub Enterprise instance: ```ruby uri = URI.parse("https://") # replace `GitHub-URL` with the real one here diff --git a/doc/user/instance_statistics/img/cohorts.png b/doc/user/instance_statistics/img/cohorts.png index 12e839e7cd2e9e1e379ab0ca42d2e6de74f94ef7..4d070fdb654b78bd660eb3a4fbd92cbbf0336ab0 100644 Binary files a/doc/user/instance_statistics/img/cohorts.png and b/doc/user/instance_statistics/img/cohorts.png differ diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 2fd4f18b7560fbe063b7d06b8142d11ae85900a4..bf92de73b4888a3e7375dbe1781485afd6166a4e 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -272,7 +272,7 @@ ee: - :push_event_payload - design_versions: - actions: - - :design # Duplicate export of issues.designs in order to link the record to both Issue and DesignVersion + - :design # Duplicate export of issues.designs in order to link the record to both Issue and Action - protected_branches: - :unprotect_access_levels - protected_environments: diff --git a/spec/frontend/ide/lib/files_spec.js b/spec/frontend/ide/lib/files_spec.js index 654dc6c13c8c9f3b5790afd9aca51742e2c6b67d..34eb57ae0d3f9f763b043ea42aba620da4bfac29 100644 --- a/spec/frontend/ide/lib/files_spec.js +++ b/spec/frontend/ide/lib/files_spec.js @@ -1,6 +1,7 @@ import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils'; import { decorateFiles, splitParent } from '~/ide/lib/files'; -import { decorateData, escapeFileUrl } from '~/ide/stores/utils'; +import { decorateData } from '~/ide/stores/utils'; +import { escapeFileUrl } from '~/lib/utils/url_utility'; const TEST_BRANCH_ID = 'lorem-ipsum'; const TEST_PROJECT_ID = 10; diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js index bb0d20bed911371d68294465a418d7ed04d69ad3..d676d7539b6d4d97cc4924b00febcaa99f550f3d 100644 --- a/spec/frontend/ide/services/index_spec.js +++ b/spec/frontend/ide/services/index_spec.js @@ -2,7 +2,7 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import services from '~/ide/services'; import Api from '~/api'; -import { escapeFileUrl } from '~/ide/stores/utils'; +import { escapeFileUrl } from '~/lib/utils/url_utility'; jest.mock('~/api'); diff --git a/spec/frontend/ide/stores/utils_spec.js b/spec/frontend/ide/stores/utils_spec.js index 1f54397db55e93ecc784661e4c45cc11d34245ac..90f2644de628789143753f30f556450c111180f2 100644 --- a/spec/frontend/ide/stores/utils_spec.js +++ b/spec/frontend/ide/stores/utils_spec.js @@ -395,14 +395,6 @@ describe('Multi-file store utils', () => { }); }); - describe('escapeFileUrl', () => { - it('encodes URL excluding the slashes', () => { - expect(utils.escapeFileUrl('/foo-bar/file.md')).toBe('/foo-bar/file.md'); - expect(utils.escapeFileUrl('foo bar/file.md')).toBe('foo%20bar/file.md'); - expect(utils.escapeFileUrl('foo/bar/file.md')).toBe('foo/bar/file.md'); - }); - }); - describe('swapInStateArray', () => { let localState; diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js index 0e818d6c402c65ac15f1e0d67d420c941f3de14e..a625c9cd274ae320f4fa01a2a6291c7e2273a06d 100644 --- a/spec/frontend/lib/utils/url_utility_spec.js +++ b/spec/frontend/lib/utils/url_utility_spec.js @@ -322,6 +322,14 @@ describe('URL utility', () => { expect(urlUtils.joinPaths(...paths)).toBe(expected); }); }); + + describe('escapeFileUrl', () => { + it('encodes URL excluding the slashes', () => { + expect(urlUtils.escapeFileUrl('/foo-bar/file.md')).toBe('/foo-bar/file.md'); + expect(urlUtils.escapeFileUrl('foo bar/file.md')).toBe('foo%20bar/file.md'); + expect(urlUtils.escapeFileUrl('foo/bar/file.md')).toBe('foo/bar/file.md'); + }); + }); }); describe('setUrlParams', () => { diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 8d436fb28e0ad690c4f46027ce1e58d27dae1e85..2ea563c50b68765334e9fd31971dddd38bb2f7d0 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -549,6 +549,7 @@ actions: - design - version versions: &version +- author - issue - designs - actions