secpick 3.21 KB
Newer Older
1
#!/usr/bin/env ruby
James Lopez's avatar
James Lopez committed
2 3 4
# frozen_string_literal: false

require 'active_support/core_ext/object/to_query'
5 6 7 8 9 10
require 'optparse'
require 'open3'
require 'rainbow/refinement'
using Rainbow

BRANCH_PREFIX = 'security'.freeze
11
DEFAULT_REMOTE = 'dev'.freeze
James Lopez's avatar
James Lopez committed
12
NEW_MR_URL = 'https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/new'.freeze
13 14 15 16 17 18 19 20 21

options = { version: nil, branch: nil, sha: nil }

parser = OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options]"
  opts.on('-v', '--version 10.0', 'Version') do |version|
    options[:version] = version&.tr('.', '-')
  end

22
  opts.on('-b', '--branch security-fix-branch', 'Original branch name (optional, defaults to current)') do |branch|
23 24 25 26 27 28 29
    options[:branch] = branch
  end

  opts.on('-s', '--sha abcd', 'SHA to cherry pick') do |sha|
    options[:sha] = sha
  end

30
  opts.on('-r', '--remote abcd', 'Git remote name of dev.gitlab.org (optional, defaults to `dev`)') do |remote|
31 32 33
    options[:remote] = remote
  end

34
  opts.on('-d', '--dry-run', 'Only show Git commands, without calling them') do |remote|
35 36 37
    options[:try] = true
  end

38 39 40 41 42 43 44 45 46
  opts.on('-h', '--help', 'Displays Help') do
    puts opts

    exit
  end
end

parser.parse!

47
options[:branch] ||= `git rev-parse --abbrev-ref HEAD`
48
options[:remote] ||= DEFAULT_REMOTE
49

50 51 52
abort("Missing options. Use #{$0} --help to see the list of options available".red) if options.values.include?(nil)
abort("Wrong version format #{options[:version].bold}".red) unless options[:version] =~ /\A\d*\-\d*\Z/

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
class SecurityFix
  def initialize(options)
    @options = options
  end

  def ee?
    File.exist?('./CHANGELOG-EE.md')
  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 = branch.freeze
  end

  def security_branch
    "#{BRANCH_PREFIX}-#{@options[:version]}".tap do |name|
      name << "-ee" if ee?
    end.freeze
  end

  def git_commands
    ["git fetch #{@options[:remote]} #{security_branch}",
     "git checkout #{security_branch}",
     "git pull #{@options[:remote]} #{security_branch}",
     "git checkout -B #{source_branch}",
     "git cherry-pick #{@options[:sha]}",
     "git push #{@options[:remote]} #{source_branch}",
     "git checkout #{original_branch}"]
  end

  def gitlab_params
    {
      merge_request: {
        source_branch: source_branch,
        target_branch: security_branch,
        title: "WIP: [#{@options[:version].tr('-', '.')}] ",
        description: '/label ~security'
      }
James Lopez's avatar
James Lopez committed
100
    }
101
  end
James Lopez's avatar
James Lopez committed
102

103 104 105 106 107 108 109 110
  def new_mr_url
    if ee?
      NEW_MR_URL.sub('gitlabhq', 'gitlab-ee')
    else
      NEW_MR_URL
    end
  end

111 112 113 114 115 116 117 118 119 120 121 122 123
  def create!
    if dry_run?
      puts git_commands.join("\n").green
      puts "\nMerge request params: ".blue
      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?
124
        puts "#{new_mr_url}?#{gitlab_params.to_query}".blue
125 126 127 128 129 130 131
      end

      stdin.close
      stdout.close
      stderr.close
    end
  end
James Lopez's avatar
James Lopez committed
132 133
end

134
SecurityFix.new(options).create!