summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-25 00:08:11 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-25 00:08:11 +0000
commit23bc19cb73aad969c9636b8b935111645e809e54 (patch)
tree887c9e014f8345f577769db4f75315ca59853b98
parentc4db541c1b2c97ab1eda354ea3899489fe5c33e5 (diff)
downloadgitlab-ce-23bc19cb73aad969c9636b8b935111645e809e54.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue31
-rw-r--r--app/finders/releases_finder.rb3
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/models/concerns/has_repository.rb9
-rw-r--r--app/models/project.rb5
-rw-r--r--app/models/snippet.rb3
-rw-r--r--app/services/ci/create_job_artifacts_service.rb1
-rw-r--r--changelogs/unreleased/211394-releases-page-in-not-loading-on-pagination.yml5
-rw-r--r--changelogs/unreleased/add-missing-track-exception-call.yml5
-rw-r--r--changelogs/unreleased/fj-ensure-freshness-snippet-creation.yml5
-rw-r--r--changelogs/unreleased/improve-lfs-toggle-message.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-add-max-namepsace-storage-limit-column.yml5
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb342
-rw-r--r--db/migrate/20200324115359_add_namespace_storage_size_limit_to_application_settings.rb16
-rw-r--r--db/structure.sql6
-rw-r--r--doc/administration/geo/replication/configuration.md13
-rw-r--r--doc/administration/geo/replication/index.md1
-rw-r--r--doc/administration/lfs/manage_large_binaries_with_git_lfs.md7
-rw-r--r--doc/api/group_import_export.md2
-rw-r--r--doc/development/contributing/issue_workflow.md2
-rw-r--r--doc/development/database_review.md7
-rw-r--r--doc/development/documentation/styleguide.md15
-rw-r--r--doc/topics/git/index.md1
-rw-r--r--lib/gitlab/database/batch_count.rb6
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/finders/releases_finder_spec.rb12
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js62
-rw-r--r--spec/models/project_spec.rb29
-rw-r--r--spec/models/snippet_spec.rb18
-rw-r--r--spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb33
30 files changed, 397 insertions, 257 deletions
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index faaa65b1a16..a3743ded601 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -1,4 +1,6 @@
<script>
+import { GlSprintf, GlLink } from '@gitlab/ui';
+
import settingsMixin from 'ee_else_ce/pages/projects/shared/permissions/mixins/settings_pannel_mixin';
import { s__ } from '~/locale';
import projectFeatureSetting from './project_feature_setting.vue';
@@ -19,6 +21,8 @@ export default {
projectFeatureSetting,
projectFeatureToggle,
projectSettingRow,
+ GlSprintf,
+ GlLink,
},
mixins: [settingsMixin],
@@ -67,6 +71,16 @@ export default {
required: false,
default: '',
},
+ lfsObjectsExist: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ lfsObjectsRemovalHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
registryHelpPath: {
type: String,
required: false,
@@ -377,6 +391,23 @@ export default {
:disabled-input="!repositoryEnabled"
name="project[lfs_enabled]"
/>
+ <p v-if="!lfsEnabled && lfsObjectsExist">
+ <gl-sprintf
+ :message="
+ s__(
+ 'ProjectSettings|LFS objects from this repository are still available to forks. %{linkStart}How do I remove them?%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <span class="d-block">
+ <gl-link :href="lfsObjectsRemovalHelpPath" target="_blank">
+ {{ content }}
+ </gl-link>
+ </span>
+ </template>
+ </gl-sprintf>
+ </p>
</project-setting-row>
<project-setting-row
v-if="packagesAvailable"
diff --git a/app/finders/releases_finder.rb b/app/finders/releases_finder.rb
index 72bf968c8ec..e58a90922a5 100644
--- a/app/finders/releases_finder.rb
+++ b/app/finders/releases_finder.rb
@@ -9,7 +9,8 @@ class ReleasesFinder
def execute(preload: true)
return Release.none unless Ability.allowed?(@current_user, :read_release, @project)
- releases = @project.releases
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/211988
+ releases = @project.releases.where.not(tag: nil) # rubocop:disable CodeReuse/ActiveRecord
releases = releases.preloaded if preload
releases.sorted
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index cf9f3b9e924..015f8783db5 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -603,6 +603,8 @@ module ProjectsHelper
registryHelpPath: help_page_path('user/packages/container_registry/index'),
lfsAvailable: Gitlab.config.lfs.enabled,
lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs'),
+ lfsObjectsExist: project.lfs_objects.exists?,
+ lfsObjectsRemovalHelpPath: help_page_path('administration/lfs/manage_large_binaries_with_git_lfs', anchor: 'removing-objects-from-lfs'),
pagesAvailable: Gitlab.config.pages.enabled,
pagesAccessControlEnabled: Gitlab.config.pages.access_control,
pagesAccessControlForced: ::Gitlab::Pages.access_control_is_forced?,
diff --git a/app/models/concerns/has_repository.rb b/app/models/concerns/has_repository.rb
index cc792eab2e0..d50e088944e 100644
--- a/app/models/concerns/has_repository.rb
+++ b/app/models/concerns/has_repository.rb
@@ -15,6 +15,15 @@ module HasRepository
delegate :base_dir, :disk_path, to: :storage
+ class_methods do
+ def pick_repository_storage
+ # We need to ensure application settings are fresh when we pick
+ # a repository storage to use.
+ Gitlab::CurrentSettings.expire_current_application_settings
+ Gitlab::CurrentSettings.pick_repository_storage
+ end
+ end
+
def valid_repo?
repository.exists?
rescue
diff --git a/app/models/project.rb b/app/models/project.rb
index b9d8fd1e4d8..9d055cbd6c6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -67,10 +67,7 @@ class Project < ApplicationRecord
default_value_for :resolve_outdated_diff_discussions, false
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
default_value_for(:repository_storage) do
- # We need to ensure application settings are fresh when we pick
- # a repository storage to use.
- Gitlab::CurrentSettings.expire_current_application_settings
- Gitlab::CurrentSettings.pick_repository_storage
+ pick_repository_storage
end
default_value_for(:shared_runners_enabled) { Gitlab::CurrentSettings.shared_runners_enabled }
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 90221f4e463..b6127baca90 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -288,8 +288,7 @@ class Snippet < ApplicationRecord
end
def repository_storage
- snippet_repository&.shard_name ||
- Gitlab::CurrentSettings.pick_repository_storage
+ snippet_repository&.shard_name || self.class.pick_repository_storage
end
def create_repository
diff --git a/app/services/ci/create_job_artifacts_service.rb b/app/services/ci/create_job_artifacts_service.rb
index d207c215618..5d7d552dc5a 100644
--- a/app/services/ci/create_job_artifacts_service.rb
+++ b/app/services/ci/create_job_artifacts_service.rb
@@ -77,6 +77,7 @@ module Ci
track_exception(error, job, params)
error(error.message, :service_unavailable)
rescue => error
+ track_exception(error, job, params)
error(error.message, :bad_request)
end
diff --git a/changelogs/unreleased/211394-releases-page-in-not-loading-on-pagination.yml b/changelogs/unreleased/211394-releases-page-in-not-loading-on-pagination.yml
new file mode 100644
index 00000000000..f4455db8620
--- /dev/null
+++ b/changelogs/unreleased/211394-releases-page-in-not-loading-on-pagination.yml
@@ -0,0 +1,5 @@
+---
+title: Filter out Releases with missing tags
+merge_request: 27716
+author:
+type: fixed
diff --git a/changelogs/unreleased/add-missing-track-exception-call.yml b/changelogs/unreleased/add-missing-track-exception-call.yml
new file mode 100644
index 00000000000..ad08fbda765
--- /dev/null
+++ b/changelogs/unreleased/add-missing-track-exception-call.yml
@@ -0,0 +1,5 @@
+---
+title: Add missing track_exception() call to Ci::CreateJobArtifactsService
+merge_request: 27954
+author:
+type: other
diff --git a/changelogs/unreleased/fj-ensure-freshness-snippet-creation.yml b/changelogs/unreleased/fj-ensure-freshness-snippet-creation.yml
new file mode 100644
index 00000000000..9d6219cf177
--- /dev/null
+++ b/changelogs/unreleased/fj-ensure-freshness-snippet-creation.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure freshness of settings with snippet creation
+merge_request: 27897
+author:
+type: changed
diff --git a/changelogs/unreleased/improve-lfs-toggle-message.yml b/changelogs/unreleased/improve-lfs-toggle-message.yml
new file mode 100644
index 00000000000..2db2152c676
--- /dev/null
+++ b/changelogs/unreleased/improve-lfs-toggle-message.yml
@@ -0,0 +1,5 @@
+---
+title: Show object access warning when disabling repo LFS
+merge_request: 26696
+author:
+type: other
diff --git a/changelogs/unreleased/nicolasdular-add-max-namepsace-storage-limit-column.yml b/changelogs/unreleased/nicolasdular-add-max-namepsace-storage-limit-column.yml
new file mode 100644
index 00000000000..fe47473426e
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-add-max-namepsace-storage-limit-column.yml
@@ -0,0 +1,5 @@
+---
+title: Add namespace_storage_size_limit to application settings
+merge_request: 27786
+author:
+type: added
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 2bf3c918006..1bdaabad704 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -1,240 +1,204 @@
+# frozen_string_literal: true
+
require './spec/support/sidekiq_middleware'
require './spec/support/helpers/test_env'
+# Usage:
+#
+# Simple invocation always creates a new project:
+#
+# FILTER=cycle_analytics SEED_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu
+#
+# Create more issues/MRs:
+#
+# CYCLE_ANALYTICS_ISSUE_COUNT=100 FILTER=cycle_analytics SEED_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu
+#
+# Run for an existing project
+#
+# CYCLE_ANALYTICS_SEED_PROJECT_ID=10 FILTER=cycle_analytics SEED_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu
+
class Gitlab::Seeder::CycleAnalytics
- def initialize(project, perf: false)
- @project = project
- @user = User.admins.first
- @issue_count = perf ? 1000 : ENV.fetch('CYCLE_ANALYTICS_ISSUE_COUNT', 5).to_i
+ attr_reader :project, :issues, :merge_requests, :developers
+
+ FLAG = 'SEED_CYCLE_ANALYTICS'
+ PERF_TEST = 'CYCLE_ANALYTICS_PERF_TEST'
+
+ ISSUE_STAGE_MAX_DURATION_IN_HOURS = 72
+ PLAN_STAGE_MAX_DURATION_IN_HOURS = 48
+ CODE_STAGE_MAX_DURATION_IN_HOURS = 72
+ TEST_STAGE_MAX_DURATION_IN_HOURS = 5
+ REVIEW_STAGE_MAX_DURATION_IN_HOURS = 72
+ DEPLOYMENT_MAX_DURATION_IN_HOURS = 48
+
+ def self.seeder_base_on_env(project)
+ if ENV[FLAG]
+ self.new(project: project)
+ elsif ENV[PERF_TEST]
+ self.new(project: project, perf: true)
+ end
end
- def seed_metrics!
- @issue_count.times do |index|
- # Issue
- Timecop.travel 5.days.from_now
- title = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}"
- issue = Issue.create(project: @project, title: title, author: @user)
- issue_metrics = issue.metrics
-
- # Milestones / Labels
- Timecop.travel 5.days.from_now
-
- if index.even?
- issue_metrics.first_associated_with_milestone_at = rand(6..12).hours.from_now
- else
- issue_metrics.first_added_to_board_at = rand(6..12).hours.from_now
- end
-
- # Commit
- Timecop.travel 5.days.from_now
- issue_metrics.first_mentioned_in_commit_at = rand(6..12).hours.from_now
-
- # MR
- Timecop.travel 5.days.from_now
- branch_name = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}"
- @project.repository.add_branch(@user, branch_name, 'master')
- merge_request = MergeRequest.create(target_project: @project, source_project: @project, source_branch: branch_name, target_branch: 'master', title: branch_name, author: @user)
- merge_request_metrics = merge_request.metrics
-
- # MR closing issues
- Timecop.travel 5.days.from_now
- MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request)
-
- # Merge
- Timecop.travel 5.days.from_now
- merge_request_metrics.merged_at = rand(6..12).hours.from_now
-
- # Start build
- Timecop.travel 5.days.from_now
- merge_request_metrics.latest_build_started_at = rand(6..12).hours.from_now
-
- # Finish build
- Timecop.travel 5.days.from_now
- merge_request_metrics.latest_build_finished_at = rand(6..12).hours.from_now
-
- # Deploy to production
- Timecop.travel 5.days.from_now
- merge_request_metrics.first_deployed_to_production_at = rand(6..12).hours.from_now
-
- issue_metrics.save!
- merge_request_metrics.save!
-
- print '.'
- end
+ def initialize(project: nil, perf: false)
+ @project = project || create_new_vsm_project
+ @issue_count = perf ? 1000 : ENV.fetch('CYCLE_ANALYTICS_ISSUE_COUNT', 5).to_i
+ @issues = []
+ @merge_requests = []
+ @developers = []
end
def seed!
- Sidekiq::Worker.skipping_transaction_check do
- Sidekiq::Testing.inline! do
- issues = create_issues
- puts '.'
-
- # Stage 1
- Timecop.travel 5.days.from_now
- add_milestones_and_list_labels(issues)
- print '.'
-
- # Stage 2
- Timecop.travel 5.days.from_now
- branches = mention_in_commits(issues)
- print '.'
-
- # Stage 3
- Timecop.travel 5.days.from_now
- merge_requests = create_merge_requests_closing_issues(issues, branches)
- print '.'
-
- # Stage 4
- Timecop.travel 5.days.from_now
- run_builds(merge_requests)
- print '.'
-
- # Stage 5
- Timecop.travel 5.days.from_now
- merge_merge_requests(merge_requests)
- print '.'
-
- # Stage 6 / 7
- Timecop.travel 5.days.from_now
- deploy_to_production(merge_requests)
- print '.'
- end
- end
-
- print '.'
+ create_developers!
+ create_issues!
+
+ seed_issue_stage!
+ seed_plan_stage!
+ seed_code_stage!
+ seed_test_stage!
+ seed_review_stage!
+ seed_staging_stage!
+
+ puts "Successfully seeded '#{project.full_path}' for Value Stream Management!"
+ puts "URL: #{Rails.application.routes.url_helpers.project_url(project)}"
end
private
- def create_issues
- Array.new(@issue_count) do
- issue_params = {
- title: "Value Stream Analytics: #{FFaker::Lorem.sentence(6)}",
- description: FFaker::Lorem.sentence,
- state: 'opened',
- assignees: [@project.team.users.sample]
- }
-
- Issues::CreateService.new(@project, @project.team.users.sample, issue_params).execute
- end
- end
-
- def add_milestones_and_list_labels(issues)
- issues.shuffle.map.with_index do |issue, index|
- Timecop.travel 12.hours.from_now
+ def seed_issue_stage!
+ issues.each do |issue|
+ time = within_end_time(issue.created_at + rand(ISSUE_STAGE_MAX_DURATION_IN_HOURS).hours)
- if index.even?
- issue.update(milestone: @project.milestones.sample)
+ if issue.id.even?
+ issue.metrics.update!(first_associated_with_milestone_at: time)
else
- label_name = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}"
- list_label = FactoryBot.create(:label, title: label_name, project: issue.project)
- FactoryBot.create(:list, board: FactoryBot.create(:board, project: issue.project), label: list_label)
- issue.update(labels: [list_label])
+ issue.metrics.update!(first_added_to_board_at: time)
end
-
- issue
end
end
- def mention_in_commits(issues)
- issues.map do |issue|
- Timecop.travel 12.hours.from_now
+ def seed_plan_stage!
+ issues.each do |issue|
+ plan_stage_start = issue.metrics.first_associated_with_milestone_at || issue.metrics.first_added_to_board_at
- branch_name = filename = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}"
+ first_mentioned_in_commit_at = within_end_time(plan_stage_start + rand(PLAN_STAGE_MAX_DURATION_IN_HOURS).hours)
+ issue.metrics.update!(first_mentioned_in_commit_at: first_mentioned_in_commit_at)
+ end
+ end
- issue.project.repository.add_branch(@user, branch_name, 'master')
+ def seed_code_stage!
+ issues.each do |issue|
+ merge_request = FactoryBot.create(
+ :merge_request,
+ target_project: project,
+ source_project: project,
+ source_branch: "#{issue.iid}-feature-branch",
+ target_branch: 'master',
+ author: developers.sample,
+ created_at: within_end_time(issue.metrics.first_mentioned_in_commit_at + rand(CODE_STAGE_MAX_DURATION_IN_HOURS).hours)
+ )
- commit_sha = issue.project.repository.create_file(@user, filename, "content", message: "Commit for #{issue.to_reference}", branch_name: branch_name)
- issue.project.repository.commit(commit_sha)
+ @merge_requests << merge_request
- ::Git::BranchPushService.new(
- issue.project,
- @user,
- change: {
- oldrev: issue.project.repository.commit("master").sha,
- newrev: commit_sha,
- ref: 'refs/heads/master'
- }
- ).execute
+ MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request)
+ end
+ end
- branch_name
+ def seed_test_stage!
+ merge_requests.each do |merge_request|
+ pipeline = FactoryBot.create(:ci_pipeline, :success, project: project)
+ build = FactoryBot.create(:ci_build, pipeline: pipeline, project: project, user: developers.sample)
+
+ merge_request.metrics.update!(
+ latest_build_started_at: merge_request.created_at,
+ latest_build_finished_at: within_end_time(merge_request.created_at + TEST_STAGE_MAX_DURATION_IN_HOURS.hours),
+ pipeline_id: build.commit_id
+ )
end
end
- def create_merge_requests_closing_issues(issues, branches)
- issues.zip(branches).map do |issue, branch|
- Timecop.travel 12.hours.from_now
+ def seed_review_stage!
+ merge_requests.each do |merge_request|
+ merge_request.metrics.update!(merged_at: within_end_time(merge_request.created_at + REVIEW_STAGE_MAX_DURATION_IN_HOURS.hours))
+ end
+ end
- opts = {
- title: 'Value Stream Analytics merge_request',
- description: "Fixes #{issue.to_reference}",
- source_branch: branch,
- target_branch: 'master'
- }
+ def seed_staging_stage!
+ merge_requests.each do |merge_request|
+ merge_request.metrics.update!(first_deployed_to_production_at: within_end_time(merge_request.metrics.merged_at + DEPLOYMENT_MAX_DURATION_IN_HOURS.hours))
+ end
+ end
- MergeRequests::CreateService.new(issue.project, @user, opts).execute
+ def create_issues!
+ @issue_count.times do
+ Timecop.travel start_time + rand(5).days do
+ title = "#{FFaker::Product.brand}-#{suffix}"
+ @issues << Issue.create!(project: project, title: title, author: developers.sample)
+ end
end
end
- def run_builds(merge_requests)
- merge_requests.each do |merge_request|
- Timecop.travel 12.hours.from_now
+ def create_developers!
+ 5.times do |i|
+ user = FactoryBot.create(
+ :user,
+ name: "VSM User#{i}",
+ username: "vsm-user-#{i}-#{suffix}",
+ email: "vsm-user-#{i}@#{suffix}.com"
+ )
- service = Ci::CreatePipelineService.new(merge_request.project,
- @user,
- ref: "refs/heads/#{merge_request.source_branch}")
- pipeline = service.execute(:push, ignore_skip_ci: true, save_on_errors: false)
+ project.group.add_developer(user)
+ project.add_developer(user)
- pipeline.builds.each(&:enqueue) # make sure all pipelines in pending state
- pipeline.builds.each(&:run!)
- pipeline.update_legacy_status
+ @developers << user
end
end
- def merge_merge_requests(merge_requests)
- merge_requests.each do |merge_request|
- Timecop.travel 12.hours.from_now
+ def create_new_vsm_project
+ project = FactoryBot.create(
+ :project,
+ name: "Value Stream Management Project #{suffix}",
+ path: "vsmp-#{suffix}",
+ creator: admin,
+ namespace: FactoryBot.create(
+ :group,
+ name: "Value Stream Management Group (#{suffix})",
+ path: "vsmg-#{suffix}"
+ )
+ )
+
+ project.create_repository
+ project
+ end
- MergeRequests::MergeService.new(merge_request.project, @user).execute(merge_request)
- end
+ def admin
+ @admin ||= User.admins.first
end
- def deploy_to_production(merge_requests)
- merge_requests.each do |merge_request|
- next unless merge_request.head_pipeline
+ def suffix
+ @suffix ||= Time.now.to_i
+ end
- Timecop.travel 12.hours.from_now
+ def start_time
+ @start_time ||= 25.days.ago
+ end
- job = merge_request.head_pipeline.builds.where.not(environment: nil).last
+ def end_time
+ @end_time ||= Time.now
+ end
- job.success!
- job.pipeline.update_legacy_status
- end
+ def within_end_time(time)
+ [time, end_time].min
end
end
Gitlab::Seeder.quiet do
- flag = 'SEED_CYCLE_ANALYTICS'
-
- if ENV[flag]
- Project.not_mass_generated.find_each do |project|
- # This seed naively assumes that every project has a repository, and every
- # repository has a `master` branch, which may be the case for a pristine
- # GDK seed, but is almost never true for a GDK that's actually had
- # development performed on it.
- next unless project.repository_exists?
- next unless project.repository.commit('master')
-
- seeder = Gitlab::Seeder::CycleAnalytics.new(project)
- seeder.seed!
- end
- elsif ENV['CYCLE_ANALYTICS_PERF_TEST']
- seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true)
+ project_id = ENV['CYCLE_ANALYTICS_SEED_PROJECT_ID']
+ project = Project.find(project_id) if project_id
+
+ seeder = Gitlab::Seeder::CycleAnalytics.seeder_base_on_env(project)
+
+ if seeder
seeder.seed!
- elsif ENV['CYCLE_ANALYTICS_POPULATE_METRICS_DIRECTLY']
- seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true)
- seeder.seed_metrics!
else
- puts "Skipped. Use the `#{flag}` environment variable to enable."
+ puts "Skipped. Use the `#{Gitlab::Seeder::CycleAnalytics::FLAG}` environment variable to enable."
end
end
diff --git a/db/migrate/20200324115359_add_namespace_storage_size_limit_to_application_settings.rb b/db/migrate/20200324115359_add_namespace_storage_size_limit_to_application_settings.rb
new file mode 100644
index 00000000000..e5fe98a4d19
--- /dev/null
+++ b/db/migrate/20200324115359_add_namespace_storage_size_limit_to_application_settings.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddNamespaceStorageSizeLimitToApplicationSettings < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default :application_settings, :namespace_storage_size_limit, :bigint, default: 0
+ end
+
+ def down
+ remove_column :application_settings, :namespace_storage_size_limit
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index af6fa7555bb..9ad3711dd32 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -395,7 +395,8 @@ CREATE TABLE public.application_settings (
prevent_merge_requests_committers_approval boolean DEFAULT false NOT NULL,
email_restrictions_enabled boolean DEFAULT false NOT NULL,
email_restrictions text,
- npm_package_requests_forwarding boolean DEFAULT true NOT NULL
+ npm_package_requests_forwarding boolean DEFAULT true NOT NULL,
+ namespace_storage_size_limit bigint DEFAULT 0 NOT NULL
);
CREATE SEQUENCE public.application_settings_id_seq
@@ -12750,5 +12751,6 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200319123041'),
('20200319203901'),
('20200323075043'),
-('20200323122201');
+('20200323122201'),
+('20200324115359');
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index 1434eeb61af..ed3af59b7f0 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -314,6 +314,19 @@ It is important to note that selective synchronization:
Selective synchronization restrictions are implemented on the **secondary** nodes,
not the **primary** node.
+### Git operations on unreplicated respositories
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2562) in GitLab 12.10.
+
+Git clone, pull, and push operations over HTTP(S) are supported for repositories that
+exist on the **primary** node but not on **secondary** nodes. This situation can occur
+when:
+
+- Selective synchronization does not include the project attached to the repository.
+- The repository is actively being replicated but has not completed yet.
+
+SSH [support is planned](https://gitlab.com/groups/gitlab-org/-/epics/2562).
+
## Upgrading Geo
See the [updating the Geo nodes document](updating_the_geo_nodes.md).
diff --git a/doc/administration/geo/replication/index.md b/doc/administration/geo/replication/index.md
index 4f598162a63..74f9f8c05f4 100644
--- a/doc/administration/geo/replication/index.md
+++ b/doc/administration/geo/replication/index.md
@@ -244,6 +244,7 @@ CAUTION: **Caution:**
This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place.
- Pushing directly to a **secondary** node redirects (for HTTP) or proxies (for SSH) the request to the **primary** node instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/issues/1381), except when using Git over HTTP with credentials embedded within the URI. For example, `https://user:password@secondary.tld`.
+- Cloning, pulling, or pushing repositories that exist on the **primary** node but not on the **secondary** nodes where [selective synchronization](configuration.md#selective-synchronization) does not include the project is not supported over SSH [but support is planned](https://gitlab.com/groups/gitlab-org/-/epics/2562). HTTP(S) is supported.
- The **primary** node has to be online for OAuth login to happen. Existing sessions and Git are not affected.
- The installation takes multiple manual steps that together can take about an hour depending on circumstances. We are working on improving this experience. See [Omnibus GitLab issue #2978](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2978) for details.
- Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** node.
diff --git a/doc/administration/lfs/manage_large_binaries_with_git_lfs.md b/doc/administration/lfs/manage_large_binaries_with_git_lfs.md
index 61b8f28293f..27cf27fddc9 100644
--- a/doc/administration/lfs/manage_large_binaries_with_git_lfs.md
+++ b/doc/administration/lfs/manage_large_binaries_with_git_lfs.md
@@ -93,6 +93,13 @@ git lfs fetch origin master
Read the documentation on how to [migrate an existing Git repo with Git LFS](../../topics/git/migrate_to_git_lfs/index.md).
+### Removing objects from LFS
+
+To remove objects from LFS:
+
+1. Use [BFG-Cleaner](../../user/project/repository/reducing_the_repo_size_using_git.md#using-the-bfg-repo-cleaner) or [filter-branch](../../user/project/repository/reducing_the_repo_size_using_git.md#using-git-filter-branch) to remove the objects from the repository.
+1. Delete the relevant LFS lines for the objects you have removed from your `.gitattributes` file and commit those changes.
+
## File Locking
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/35856) in GitLab 10.5.
diff --git a/doc/api/group_import_export.md b/doc/api/group_import_export.md
index 039f81a18d0..50e8bd9dcf2 100644
--- a/doc/api/group_import_export.md
+++ b/doc/api/group_import_export.md
@@ -94,3 +94,5 @@ Note the following:
to allow project imports into the desired group structure.
- Imported groups are given a `private` visibility level, unless imported into a parent group.
- If imported into a parent group, subgroups will inherit a similar level of visibility, unless otherwise restricted.
+- To preserve the member list and their respective permissions on imported groups,
+ review the users in these groups. Make sure these users exist before importing the desired groups.
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 94cf1c223dd..31d99813061 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -14,7 +14,7 @@ see fit.
## Issue triaging
-Our issue triage policies are [described in our handbook](https://about.gitlab.com/handbook/engineering/issue-triage/).
+Our issue triage policies are [described in our handbook](https://about.gitlab.com/handbook/engineering/quality/issue-triage/).
You are very welcome to help the GitLab team triage issues.
We also organize [issue bash events](https://gitlab.com/gitlab-org/gitlab-foss/issues/17815)
once every quarter.
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 9c428c62434..0fdf255e266 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -45,13 +45,6 @@ A database **reviewer**'s role is to:
reassign MR to the database **maintainer** suggested by Reviewer
Roulette.
-#### When there are no database maintainers available
-
-Currently we have a [critical shortage of database maintainers](https://gitlab.com/gitlab-org/gitlab/issues/29717). Until we are able to increase the number of database maintainers to support the volume of reviews, we have implemented this temporary solution. If the database **reviewer** cannot find an available database **maintainer** then:
-
-1. Assign the MR for a second review by a **database trainee maintainer** for further review.
-1. Once satisfied with the review process and if the database **maintainer** is still not available, skip the database maintainer approval step and assign the merge request to a backend maintainer for final review and approval.
-
A database **maintainer**'s role is to:
- Perform the final database review on the MR.
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 88f8b9b57d2..16a175ec115 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -972,6 +972,7 @@ The following are examples of source Markdown for menu items with their publishe
1. Go to **{book}** **Wiki**
1. Go to **{snippet}** **Snippets**
1. Go to **{users}** **Members**
+1. Select the **More actions** **{ellipsis_v}** icon > **Hide stage**
```
1. Go to **{home}** **Project overview > Details**
@@ -986,6 +987,7 @@ The following are examples of source Markdown for menu items with their publishe
1. Go to **{book}** **Wiki**
1. Go to **{snippet}** **Snippets**
1. Go to **{users}** **Members**
+1. Select the **More actions** **{ellipsis_v}** icon > **Hide stage**
## Alert boxes
@@ -1364,17 +1366,18 @@ NOTE: **Note:**
The [Product Manager for the relevant group](https://about.gitlab.com/handbook/product/categories/#devops-stages)
must review and approve the addition or removal of any mentions of using feature flags before the doc change is merged.
-The following is sample text for adding feature flag documentation for a feature:
+The following is sample text for adding feature flag documentation for a feature that is
+off by default:
````md
-### Disabling the feature
+### Enabling the feature
-This feature comes with the `:feature_flag` feature flag enabled by default. However, in some cases
-this feature is incompatible with old configuration. To turn off the feature while configuration is
-migrated, ask a GitLab administrator with Rails console access to run the following command:
+This feature comes with the `:feature_flag` feature flag disabled by default. In some cases,
+this feature is incompatible with an old configuration. To turn on the feature,
+ask a GitLab administrator with Rails console access to run the following command:
```ruby
-Feature.disable(:feature_flag)
+Feature.enable(:feature_flag)
```
````
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index c7abfb1d974..4b76f5bdc58 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -85,6 +85,7 @@ The following relate to Git Large File Storage:
- [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
- [Migrate an existing Git repo with Git LFS](migrate_to_git_lfs/index.md)
+- [Removing objects from LFS](../../administration/lfs/manage_large_binaries_with_git_lfs.md#removing-objects-from-lfs)
- [GitLab Git LFS user documentation](../../administration/lfs/manage_large_binaries_with_git_lfs.md)
- [GitLab Git LFS admin documentation](../../administration/lfs/lfs_administration.md)
- [git-annex to Git-LFS migration guide](../../administration/lfs/migrate_from_git_annex_to_git_lfs.md)
diff --git a/lib/gitlab/database/batch_count.rb b/lib/gitlab/database/batch_count.rb
index 728e0d423af..8972b77abef 100644
--- a/lib/gitlab/database/batch_count.rb
+++ b/lib/gitlab/database/batch_count.rb
@@ -32,8 +32,8 @@ module Gitlab
MAX_ALLOWED_LOOPS = 10_000
SLEEP_TIME_IN_SECONDS = 0.01 # 10 msec sleep
# Each query should take <<500ms https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22705
- DEFAULT_DISTINCT_BATCH_SIZE = 100_000
- DEFAULT_BATCH_SIZE = 10_000
+ DEFAULT_DISTINCT_BATCH_SIZE = 10_000
+ DEFAULT_BATCH_SIZE = 100_000
def initialize(relation, column: nil)
@relation = relation
@@ -51,7 +51,7 @@ module Gitlab
raise "The mode #{mode.inspect} is not supported" unless [:itself, :distinct].include?(mode)
# non-distinct have better performance
- batch_size ||= mode == :distinct ? DEFAULT_BATCH_SIZE : DEFAULT_DISTINCT_BATCH_SIZE
+ batch_size ||= mode == :distinct ? DEFAULT_DISTINCT_BATCH_SIZE : DEFAULT_BATCH_SIZE
start = @relation.minimum(@column) || 0
finish = @relation.maximum(@column) || 0
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 48874a6c489..07aee723e82 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -15552,6 +15552,9 @@ msgstr ""
msgid "ProjectSettings|Issues"
msgstr ""
+msgid "ProjectSettings|LFS objects from this repository are still available to forks. %{linkStart}How do I remove them?%{linkEnd}"
+msgstr ""
+
msgid "ProjectSettings|Learn more about badges."
msgstr ""
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
index b9c67361f45..3da5ee47b6b 100644
--- a/spec/finders/releases_finder_spec.rb
+++ b/spec/finders/releases_finder_spec.rb
@@ -52,6 +52,18 @@ describe ReleasesFinder do
subject
end
end
+
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27716
+ context 'when tag is nil' do
+ before do
+ v1_0_0.update_column(:tag, nil)
+ end
+
+ it 'ignores rows with a nil tag' do
+ expect(subject.size).to eq(1)
+ expect(subject).to eq([v1_1_0])
+ end
+ end
end
end
end
diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
index c304dfd2048..76948f3ff4c 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js
@@ -1,4 +1,4 @@
-import { shallowMount } from '@vue/test-utils';
+import { shallowMount, mount } from '@vue/test-utils';
import settingsPanel from '~/pages/projects/shared/permissions/components/settings_panel.vue';
import {
@@ -32,6 +32,8 @@ const defaultProps = {
registryHelpPath: '/help/user/packages/container_registry/index',
lfsAvailable: true,
lfsHelpPath: '/help/workflow/lfs/manage_large_binaries_with_git_lfs',
+ lfsObjectsExist: false,
+ lfsObjectsRemovalHelpPath: `/help/administration/lfs/manage_large_binaries_with_git_lfs#removing-objects-from-lfs`,
pagesAvailable: true,
pagesAccessControlEnabled: false,
pagesAccessControlForced: false,
@@ -43,21 +45,25 @@ const defaultProps = {
describe('Settings Panel', () => {
let wrapper;
- const mountComponent = customProps => {
- const propsData = { ...defaultProps, ...customProps };
- return shallowMount(settingsPanel, { propsData });
+ const mountComponent = (
+ { currentSettings = {}, ...customProps } = {},
+ mountFn = shallowMount,
+ ) => {
+ const propsData = {
+ ...defaultProps,
+ ...customProps,
+ currentSettings: { ...defaultProps.currentSettings, ...currentSettings },
+ };
+
+ return mountFn(settingsPanel, { propsData });
};
const overrideCurrentSettings = (currentSettingsProps, extraProps = {}) => {
- return mountComponent({
- ...extraProps,
- currentSettings: {
- ...defaultProps.currentSettings,
- ...currentSettingsProps,
- },
- });
+ return mountComponent({ ...extraProps, currentSettings: currentSettingsProps });
};
+ const findLFSSettingsMessage = () => wrapper.find({ ref: 'git-lfs-settings' }).find('p');
+
beforeEach(() => {
wrapper = mountComponent();
});
@@ -333,6 +339,40 @@ describe('Settings Panel', () => {
expect(wrapper.find('[name="project[lfs_enabled]"]').props().disabledInput).toEqual(true);
});
+
+ describe.each`
+ lfsObjectsExist | lfsEnabled | isShown
+ ${true} | ${true} | ${false}
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${false}
+ ${false} | ${false} | ${false}
+ `(
+ 'with (lfsObjectsExist = $lfsObjectsExist, lfsEnabled = $lfsEnabled)',
+ ({ lfsObjectsExist, lfsEnabled, isShown }) => {
+ beforeEach(() => {
+ wrapper = mountComponent({ lfsObjectsExist, currentSettings: { lfsEnabled } }, mount);
+ });
+
+ if (isShown) {
+ it('shows warning message', () => {
+ const message = findLFSSettingsMessage();
+ const link = message.find('a');
+
+ expect(message.text()).toContain(
+ 'LFS objects from this repository are still available to forks',
+ );
+ expect(link.text()).toEqual('How do I remove them?');
+ expect(link.attributes('href')).toEqual(
+ '/help/administration/lfs/manage_large_binaries_with_git_lfs#removing-objects-from-lfs',
+ );
+ });
+ } else {
+ it('does not show warning message', () => {
+ expect(findLFSSettingsMessage().exists()).toEqual(false);
+ });
+ }
+ },
+ );
});
describe('Packages', () => {
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f0423937710..2586289a699 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1391,35 +1391,14 @@ describe Project do
context 'repository storage by default' do
let(:project) { build(:project) }
- before do
- storages = {
- 'default' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories'),
- 'picked' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories')
- }
- allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
- end
-
it 'picks storage from ApplicationSetting' do
- expect_any_instance_of(ApplicationSetting).to receive(:pick_repository_storage).and_return('picked')
+ expect_next_instance_of(ApplicationSetting) do |instance|
+ expect(instance).to receive(:pick_repository_storage).and_return('picked')
+ end
+ expect(described_class).to receive(:pick_repository_storage).and_call_original
expect(project.repository_storage).to eq('picked')
end
-
- it 'picks from the latest available storage', :request_store do
- stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- Gitlab::CurrentSettings.current_application_settings
-
- settings = ApplicationSetting.last
- settings.repository_storages = %w(picked)
- settings.save!
-
- expect(Gitlab::CurrentSettings.repository_storages).to eq(%w(default))
-
- project
-
- expect(project.repository.storage).to eq('picked')
- expect(Gitlab::CurrentSettings.repository_storages).to eq(%w(picked))
- end
end
context 'shared runners by default' do
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 533c10363ca..0e19dfc147b 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -655,10 +655,18 @@ describe Snippet do
describe '#repository_storage' do
let(:snippet) { create(:snippet) }
- it 'returns default repository storage' do
- expect(Gitlab::CurrentSettings).to receive(:pick_repository_storage)
+ subject { snippet.repository_storage }
- snippet.repository_storage
+ before do
+ expect_next_instance_of(ApplicationSetting) do |instance|
+ expect(instance).to receive(:pick_repository_storage).and_return('picked')
+ end
+ end
+
+ it 'returns repository storage from ApplicationSetting' do
+ expect(described_class).to receive(:pick_repository_storage).and_call_original
+
+ expect(subject).to eq 'picked'
end
context 'when snippet_project is already created' do
@@ -669,9 +677,7 @@ describe Snippet do
end
it 'returns repository_storage from snippet_project' do
- expect(Gitlab::CurrentSettings).not_to receive(:pick_repository_storage)
-
- expect(snippet.repository_storage).to eq 'foo'
+ expect(subject).to eq 'foo'
end
end
end
diff --git a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
index d5606e65981..5a5d7c8f038 100644
--- a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
@@ -168,4 +168,37 @@ RSpec.shared_examples 'model with repository' do
it { is_expected.to respond_to(:base_dir) }
it { is_expected.to respond_to(:disk_path) }
end
+
+ describe '.pick_repository_storage' do
+ subject { described_class.pick_repository_storage }
+
+ before do
+ storages = {
+ 'default' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories'),
+ 'picked' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories')
+ }
+ allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
+ end
+
+ it 'picks storage from ApplicationSetting' do
+ expect_next_instance_of(ApplicationSetting) do |instance|
+ expect(instance).to receive(:pick_repository_storage).and_return('picked')
+ end
+
+ expect(subject).to eq('picked')
+ end
+
+ it 'picks from the latest available storage', :request_store do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ Gitlab::CurrentSettings.current_application_settings
+
+ settings = ApplicationSetting.last
+ settings.repository_storages = %w(picked)
+ settings.save!
+
+ expect(Gitlab::CurrentSettings.repository_storages).to eq(%w(default))
+ expect(subject).to eq('picked')
+ expect(Gitlab::CurrentSettings.repository_storages).to eq(%w(picked))
+ end
+ end
end