debian-mirror-gitlab/lib/tasks/gitlab/update_templates.rake

165 lines
5.5 KiB
Ruby
Raw Normal View History

2021-03-11 19:13:27 +05:30
# frozen_string_literal: true
2016-06-22 15:30:34 +05:30
namespace :gitlab do
desc "GitLab | Update templates"
task :update_templates do
TEMPLATE_DATA.each { |template| update(template) }
end
2017-09-10 17:25:29 +05:30
desc "GitLab | Update project templates"
2019-10-12 21:52:04 +05:30
task :update_project_templates, [] => :environment do |_task, args|
# we need an instance method from Gitlab::ImportExport::CommandLineUtil and don't
# want to include it in the task, as this would affect subsequent tasks as well
downloader = Class.new do
extend Gitlab::ImportExport::CommandLineUtil
def self.call(uploader, upload_path)
download_or_copy_upload(uploader, upload_path)
end
end
template_names = args.extras.to_set
2018-11-20 20:47:30 +05:30
2017-09-10 17:25:29 +05:30
if Rails.env.production?
2019-10-12 21:52:04 +05:30
raise "This rake task is not meant for production instances"
2017-09-10 17:25:29 +05:30
end
2018-03-17 18:26:18 +05:30
2017-09-10 17:25:29 +05:30
admin = User.find_by(admin: true)
unless admin
2019-10-12 21:52:04 +05:30
raise "No admin user could be found"
2017-09-10 17:25:29 +05:30
end
2019-10-12 21:52:04 +05:30
tmp_namespace_path = "tmp-project-import-#{Time.now.to_i}"
puts "Creating temporary namespace #{tmp_namespace_path}"
2022-01-26 12:08:38 +05:30
tmp_namespace = Namespace.create!(owner: admin, name: tmp_namespace_path, path: tmp_namespace_path, type: Namespaces::UserNamespace.sti_name)
2019-10-12 21:52:04 +05:30
templates = if template_names.empty?
Gitlab::ProjectTemplate.all
else
Gitlab::ProjectTemplate.all.select { |template| template_names.include?(template.name) }
end
templates.each do |template|
2017-09-10 17:25:29 +05:30
params = {
2019-10-12 21:52:04 +05:30
namespace_id: tmp_namespace.id,
2017-09-10 17:25:29 +05:30
path: template.name,
skip_wiki: true
}
puts "Creating project for #{template.title}"
project = Projects::CreateService.new(admin, params).execute
unless project.persisted?
2019-10-12 21:52:04 +05:30
raise "Failed to create project: #{project.errors.messages}"
2017-09-10 17:25:29 +05:30
end
2019-10-12 21:52:04 +05:30
uri_encoded_project_path = template.uri_encoded_project_path
2017-09-10 17:25:29 +05:30
2019-10-12 21:52:04 +05:30
# extract a concrete commit for signing off what we actually downloaded
# this way we do the right thing even if the repository gets updated in the meantime
get_commits_response = Gitlab::HTTP.get("https://gitlab.com/api/v4/projects/#{uri_encoded_project_path}/repository/commits",
query: { page: 1, per_page: 1 }
)
raise "Failed to retrieve latest commit for template '#{template.name}'" unless get_commits_response.success?
commit_sha = get_commits_response.parsed_response.dig(0, 'id')
project_archive_uri = "https://gitlab.com/api/v4/projects/#{uri_encoded_project_path}/repository/archive.tar.gz?sha=#{commit_sha}"
commit_message = <<~MSG
Initialized from '#{template.title}' project template
2017-09-10 17:25:29 +05:30
2019-10-12 21:52:04 +05:30
Template repository: #{template.preview}
Commit SHA: #{commit_sha}
MSG
2017-09-10 17:25:29 +05:30
2019-10-12 21:52:04 +05:30
Dir.mktmpdir do |tmpdir|
Dir.chdir(tmpdir) do
Gitlab::TaskHelpers.run_command!(['wget', project_archive_uri, '-O', 'archive.tar.gz'])
Gitlab::TaskHelpers.run_command!(['tar', 'xf', 'archive.tar.gz'])
extracted_project_basename = Dir['*/'].first
Dir.chdir(extracted_project_basename) do
Gitlab::TaskHelpers.run_command!(%w(git init))
Gitlab::TaskHelpers.run_command!(%w(git add .))
Gitlab::TaskHelpers.run_command!(['git', 'commit', '--author', 'GitLab <root@localhost>', '--message', commit_message])
# Hacky workaround to push to the project in a way that works with both GDK and the test environment
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab::TaskHelpers.run_command!(['git', 'remote', 'add', 'origin', "file://#{project.repository.raw.path}"])
end
Gitlab::TaskHelpers.run_command!(['git', 'push', '-u', 'origin', 'master'])
end
end
2017-09-10 17:25:29 +05:30
end
2019-10-12 21:52:04 +05:30
project.reset
2017-09-10 17:25:29 +05:30
Projects::ImportExport::ExportService.new(project, admin).execute
2019-10-12 21:52:04 +05:30
downloader.call(project.export_file, template.archive_path)
unless Projects::DestroyService.new(project, admin).execute
puts "Failed to destroy project #{template.name} (but namespace will be cleaned up later)"
end
2017-09-10 17:25:29 +05:30
puts "Exported #{template.name}".green
end
2019-10-12 21:52:04 +05:30
success = true
ensure
if tmp_namespace
puts "Destroying temporary namespace #{tmp_namespace_path}"
tmp_namespace.destroy
end
puts "Done".green if success
2017-09-10 17:25:29 +05:30
end
2016-06-22 15:30:34 +05:30
def update(template)
2017-08-17 22:00:37 +05:30
sub_dir = template.repo_url.match(/([A-Za-z-]+)\.git\z/)[1]
2016-06-22 15:30:34 +05:30
dir = File.join(vendor_directory, sub_dir)
unless clone_repository(template.repo_url, dir)
puts "Cloning the #{sub_dir} templates failed".red
return
end
remove_unneeded_files(dir, template.cleanup_regex)
puts "Done".green
end
def clone_repository(url, directory)
FileUtils.rm_rf(directory) if Dir.exist?(directory)
system("git clone #{url} --depth=1 --branch=master #{directory}")
end
# Retain only certain files:
# - The LICENSE, because we have to
# - The sub dirs so we can organise the file by category
# - The templates themself
# - Dir.entries returns also the entries '.' and '..'
def remove_unneeded_files(directory, regex)
Dir.foreach(directory) do |file|
FileUtils.rm_rf(File.join(directory, file)) unless file =~ regex
end
end
private
Template = Struct.new(:repo_url, :cleanup_regex)
TEMPLATE_DATA = [
Template.new(
"https://github.com/github/gitignore.git",
/(\.{1,2}|LICENSE|Global|\.gitignore)\z/
),
2017-08-17 22:00:37 +05:30
Template.new(
"https://gitlab.com/gitlab-org/Dockerfile.git",
/(\.{1,2}|LICENSE|CONTRIBUTING.md|\.Dockerfile)\z/
2017-09-10 17:25:29 +05:30
)
2017-08-17 22:00:37 +05:30
].freeze
2016-06-22 15:30:34 +05:30
def vendor_directory
Rails.root.join('vendor')
end
end