upgrader.rb 3.04 KB
Newer Older
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
1
require_relative "popen"
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
2 3 4 5 6
require_relative "version_info"

module Gitlab
  class Upgrader
    def execute
7
      puts "GitLab #{current_version.major} upgrade tool"
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
8 9 10 11
      puts "Your version is #{current_version}"
      puts "Latest available version for GitLab #{current_version.major} is #{latest_version}"

      if latest_version?
12
        puts "You are using the latest GitLab version"
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
13 14
      else
        puts "Newer GitLab version is available"
15
        answer = if ARGV.first == "-y"
16 17
                   "yes"
                 else
18
                   prompt("Do you want to upgrade (yes/no)? ", %w{yes no})
19
                 end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

        if answer == "yes"
          upgrade
        else
          exit 0
        end
      end
    end

    def latest_version?
      current_version >= latest_version
    end

    def current_version
      @current_version ||= Gitlab::VersionInfo.parse(current_version_raw)
    end

    def latest_version
      @latest_version ||= Gitlab::VersionInfo.parse(latest_version_raw)
    end

    def current_version_raw
      File.read(File.join(gitlab_path, "VERSION")).strip
    end

    def latest_version_raw
Martins Polakovs's avatar
Martins Polakovs committed
46 47 48 49 50 51 52
      git_tags = fetch_git_tags
      git_tags = git_tags.select { |version| version =~ /v\d+\.\d+\.\d+\Z/ }
      git_versions = git_tags.map { |tag| Gitlab::VersionInfo.parse(tag.match(/v\d+\.\d+\.\d+/).to_s) }
      "v#{git_versions.sort.last.to_s}"
    end

    def fetch_git_tags
53
      remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
Martins Polakovs's avatar
Martins Polakovs committed
54
      remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
55 56 57 58
    end

    def update_commands
      {
59 60 61
        "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash),
        "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch),
        "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}),
62 63
        "Install gems" => %W(bundle),
        "Migrate DB" => %W(bundle exec rake db:migrate),
64
        "Recompile assets" => %W(bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile),
65
        "Clear cache" => %W(bundle exec rake cache:clear)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
66 67 68
      }
    end

69
    def env
70
      { 'RAILS_ENV' => 'production' }
71 72
    end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
73 74
    def upgrade
      update_commands.each do |title, cmd|
75
        puts title
76 77
        puts " -> #{cmd.join(' ')}"
        if system(env, *cmd)
78
          puts " -> OK"
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
79
        else
80
          puts " -> FAILED"
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
          puts "Failed to upgrade. Try to repeat task or proceed with upgrade manually "
          exit 1
        end
      end

      puts "Done"
    end

    def gitlab_path
      File.expand_path(File.join(File.dirname(__FILE__), '../..'))
    end

    # Prompt the user to input something
    #
    # message - the message to display before input
    # choices - array of strings of acceptable answers or nil for any answer
    #
    # Returns the user's answer
    def prompt(message, choices = nil)
      begin
        print(message)
        answer = STDIN.gets.chomp
      end while !choices.include?(answer)
      answer
    end
  end
end