This instance will be upgraded to Heptapod 0.27.1 on 2021-12-02 at 15:00 UTC+1 (a few minutes of down time)

Commit 26af2cfd authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 1513fb5d6e2e
<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"
......
......@@ -9,7 +9,8 @@ def initialize(project, current_user = nil)
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
......
......@@ -603,6 +603,8 @@ def project_permissions_panel_data(project)
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?,
......
......@@ -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
......
......@@ -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 }
......
......@@ -288,8 +288,7 @@ def url_to_repo
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
......
......@@ -77,6 +77,7 @@ def persist_artifact(job, artifact, artifact_metadata)
track_exception(error, job, params)
error(error.message, :service_unavailable)
rescue => error
track_exception(error, job, params)
error(error.message, :bad_request)
end
......
---
title: Filter out Releases with missing tags
merge_request: 27716
author:
type: fixed
---
title: Add missing track_exception() call to Ci::CreateJobArtifactsService
merge_request: 27954
author:
type: other
---
title: Ensure freshness of settings with snippet creation
merge_request: 27897
author:
type: changed
---
title: Show object access warning when disabling repo LFS
merge_request: 26696
author:
type: other
---
title: Add namespace_storage_size_limit to application settings
merge_request: 27786
author:
type: added
# 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
# 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
......@@ -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');
......@@ -314,6 +314,19 @@ It is important to note that selective synchronization:
</