2018-10-15 14:42:47 +05:30
|
|
|
#!/usr/bin/env ruby
|
2019-03-02 22:35:43 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
# frozen_string_literal: false
|
|
|
|
|
|
|
|
require 'active_support/core_ext/object/to_query'
|
2018-10-15 14:42:47 +05:30
|
|
|
require 'optparse'
|
|
|
|
require 'open3'
|
|
|
|
require 'rainbow/refinement'
|
|
|
|
using Rainbow
|
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
module Secpick
|
|
|
|
BRANCH_PREFIX = 'security'.freeze
|
|
|
|
STABLE_SUFFIX = 'stable'.freeze
|
2020-01-01 13:55:28 +05:30
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
DEFAULT_REMOTE = 'dev'.freeze
|
2020-01-01 13:55:28 +05:30
|
|
|
SECURITY_REMOTE = 'security'.freeze
|
|
|
|
|
2020-03-13 15:44:24 +05:30
|
|
|
NEW_MR_URL = 'https://dev.gitlab.org/gitlab/gitlabhq/-/merge_requests/new'.freeze
|
|
|
|
SECURITY_MR_URL = 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/new'.freeze
|
2019-03-02 22:35:43 +05:30
|
|
|
|
|
|
|
class SecurityFix
|
|
|
|
def initialize
|
|
|
|
@options = self.class.options
|
|
|
|
end
|
|
|
|
|
|
|
|
def ee?
|
2020-01-01 13:55:28 +05:30
|
|
|
File.exist?(File.expand_path('../ee/app/models/license.rb', __dir__))
|
2019-03-02 22:35:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def dry_run?
|
|
|
|
@options[:try] == true
|
|
|
|
end
|
|
|
|
|
|
|
|
def original_branch
|
|
|
|
@options[:branch].strip
|
|
|
|
end
|
|
|
|
|
|
|
|
def source_branch
|
|
|
|
branch = "#{original_branch}-#{@options[:version]}"
|
|
|
|
branch.prepend("#{BRANCH_PREFIX}-") unless branch.start_with?("#{BRANCH_PREFIX}-")
|
|
|
|
branch.freeze
|
|
|
|
end
|
|
|
|
|
|
|
|
def stable_branch
|
|
|
|
"#{@options[:version]}-#{STABLE_SUFFIX}".tap do |name|
|
|
|
|
name << "-ee" if ee?
|
|
|
|
end.freeze
|
|
|
|
end
|
|
|
|
|
|
|
|
def git_commands
|
|
|
|
["git fetch #{@options[:remote]} #{stable_branch}",
|
2019-10-12 21:52:04 +05:30
|
|
|
"git checkout -B #{source_branch} #{@options[:remote]}/#{stable_branch} --no-track",
|
2019-03-02 22:35:43 +05:30
|
|
|
"git cherry-pick #{@options[:sha]}",
|
|
|
|
"git push #{@options[:remote]} #{source_branch}",
|
|
|
|
"git checkout #{original_branch}"]
|
|
|
|
end
|
|
|
|
|
|
|
|
def gitlab_params
|
|
|
|
{
|
2019-07-07 11:18:12 +05:30
|
|
|
issuable_template: 'Security Release',
|
2019-03-02 22:35:43 +05:30
|
|
|
merge_request: {
|
|
|
|
source_branch: source_branch,
|
2019-07-07 11:18:12 +05:30
|
|
|
target_branch: stable_branch
|
2019-03-02 22:35:43 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def new_mr_url
|
2020-01-01 13:55:28 +05:30
|
|
|
if @options[:security_remote]
|
|
|
|
if ee?
|
|
|
|
SECURITY_MR_URL
|
|
|
|
else
|
|
|
|
SECURITY_MR_URL.sub('/gitlab/', '/gitlab-foss/')
|
|
|
|
end
|
2019-03-02 22:35:43 +05:30
|
|
|
else
|
2020-01-01 13:55:28 +05:30
|
|
|
if ee?
|
|
|
|
NEW_MR_URL.sub('gitlabhq', 'gitlab-ee')
|
|
|
|
else
|
|
|
|
NEW_MR_URL
|
|
|
|
end
|
2019-03-02 22:35:43 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def create!
|
|
|
|
if dry_run?
|
2020-01-01 13:55:28 +05:30
|
|
|
puts "\nGit commands:".blue
|
|
|
|
puts git_commands.join("\n")
|
|
|
|
|
|
|
|
puts "\nMerge request URL:".blue
|
|
|
|
puts new_mr_url
|
|
|
|
|
|
|
|
puts "\nMerge request params:".blue
|
2019-03-02 22:35:43 +05:30
|
|
|
pp gitlab_params
|
|
|
|
else
|
|
|
|
cmd = git_commands.join(' && ')
|
|
|
|
stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
|
|
|
|
|
|
|
|
puts stdout.read&.green
|
|
|
|
puts stderr.read&.red
|
|
|
|
|
|
|
|
if wait_thr.value.success?
|
|
|
|
puts "#{new_mr_url}?#{gitlab_params.to_query}".blue
|
|
|
|
end
|
|
|
|
|
|
|
|
stdin.close
|
|
|
|
stdout.close
|
|
|
|
stderr.close
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.options
|
|
|
|
{ version: nil, branch: nil, sha: nil }.tap do |options|
|
|
|
|
parser = OptionParser.new do |opts|
|
|
|
|
opts.banner = "Usage: #{$0} [options]"
|
|
|
|
opts.on('-v', '--version 10.0', 'Version') do |version|
|
|
|
|
options[:version] = version&.tr('.', '-')
|
|
|
|
end
|
|
|
|
|
|
|
|
opts.on('-b', '--branch security-fix-branch', 'Original branch name (optional, defaults to current)') do |branch|
|
|
|
|
options[:branch] = branch
|
|
|
|
end
|
|
|
|
|
2019-12-26 22:10:19 +05:30
|
|
|
opts.on('-s', '--sha abcd', 'SHA or SHA range to cherry pick') do |sha|
|
2019-03-02 22:35:43 +05:30
|
|
|
options[:sha] = sha
|
|
|
|
end
|
|
|
|
|
|
|
|
opts.on('-r', '--remote abcd', 'Git remote name of dev.gitlab.org (optional, defaults to `dev`)') do |remote|
|
|
|
|
options[:remote] = remote
|
|
|
|
end
|
|
|
|
|
2020-01-01 13:55:28 +05:30
|
|
|
opts.on('--security-remote', 'Use the new Security group-based workflow on gitlab.com (note: mutually exclusive to --remote)') do
|
|
|
|
unless options[:remote].nil?
|
|
|
|
abort('Cannot use --security-remote with --remote')
|
|
|
|
end
|
|
|
|
|
|
|
|
options[:security_remote] = true
|
|
|
|
options[:remote] = SECURITY_REMOTE
|
|
|
|
end
|
|
|
|
|
|
|
|
opts.on('-d', '--dry-run', 'Only show Git commands, without calling them') do
|
2019-03-02 22:35:43 +05:30
|
|
|
options[:try] = true
|
|
|
|
end
|
|
|
|
|
|
|
|
opts.on('-h', '--help', 'Displays Help') do
|
|
|
|
puts opts
|
|
|
|
|
2020-01-01 13:55:28 +05:30
|
|
|
puts
|
|
|
|
puts 'NOTE: If `--security-remote` is used, commands will default ' \
|
|
|
|
'to using a `security` remote, and merge requests will be created ' \
|
|
|
|
'on gitlab.com/gitlab-org/security/ rather than dev.gitlab.org.'
|
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
exit
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
parser.parse!
|
|
|
|
|
|
|
|
options[:branch] ||= `git rev-parse --abbrev-ref HEAD`
|
|
|
|
options[:remote] ||= DEFAULT_REMOTE
|
|
|
|
|
2020-01-01 13:55:28 +05:30
|
|
|
abort("Missing options. Use #{$0} --help to see the list of options available".red) if options.value?(nil)
|
2019-03-02 22:35:43 +05:30
|
|
|
abort("Wrong version format #{options[:version].bold}".red) unless options[:version] =~ /\A\d*\-\d*\Z/
|
|
|
|
end
|
|
|
|
end
|
2018-10-15 14:42:47 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
Secpick::SecurityFix.new.create!
|