secpick 3.1 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 31 32 33 34 35 36 37
  opts.on('-r', '--remote abcd', 'Git remote name of dev.gitlab.org (optional, default to `dev`)') do |remote|
    options[:remote] = remote
  end

  opts.on('-d', '--dry-run', 'Show resulting Git commands without calling them') do |remote|
    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 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?
        puts "#{NEW_MR_URL}?#{gitlab_params.to_query}".blue
      end

      stdin.close
      stdout.close
      stderr.close
    end
  end
James Lopez's avatar
James Lopez committed
124 125
end

126
SecurityFix.new(options).create!