Welcome to mirror list, hosted at ThFree Co, Russian Federation.

runner_upgrade_check.rb « ci « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0808290fe5b937a751d90b4ea6896193438c3582 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
46
47
48
49
50
51
52
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
# frozen_string_literal: true

module Gitlab
  module Ci
    class RunnerUpgradeCheck
      include Singleton

      STATUSES = {
        invalid: 'Runner version is not valid.',
        not_available: 'Upgrade is not available for the runner.',
        available: 'Upgrade is available for the runner.',
        recommended: 'Upgrade is available and recommended for the runner.'
      }.freeze

      def initialize
        reset!
      end

      def check_runner_upgrade_status(runner_version)
        return :invalid unless runner_version

        releases = RunnerReleases.instance.releases
        orig_runner_version = runner_version
        runner_version = ::Gitlab::VersionInfo.parse(runner_version) unless runner_version.is_a?(::Gitlab::VersionInfo)

        raise ArgumentError, "'#{orig_runner_version}' is not a valid version" unless runner_version.valid?

        gitlab_minor_version = version_without_patch(@gitlab_version)

        available_releases = releases
            .reject { |release| release.major > @gitlab_version.major }
            .reject do |release|
              release_minor_version = version_without_patch(release)

              # Do not reject a patch update, even if the runner is ahead of the instance version
              next false if version_without_patch(runner_version) == release_minor_version

              release_minor_version > gitlab_minor_version
            end

        return :recommended if available_releases.any? { |available_rel| patch_update?(available_rel, runner_version) }
        return :recommended if outside_backport_window?(runner_version, releases)
        return :available if available_releases.any? { |available_rel| available_rel > runner_version }

        :not_available
      end

      def reset!
        @gitlab_version = ::Gitlab::VersionInfo.parse(::Gitlab::VERSION)
      end

      public_class_method :instance

      private

      def patch_update?(available_release, runner_version)
        # https://docs.gitlab.com/ee/policy/maintenance.html#patch-releases
        available_release.major == runner_version.major &&
          available_release.minor == runner_version.minor &&
          available_release.patch > runner_version.patch
      end

      def outside_backport_window?(runner_version, releases)
        return false if runner_version >= releases.last # return early if runner version is too new

        latest_minor_releases = releases.map { |r| version_without_patch(r) }.uniq { |v| v.to_s }
        latest_version_position = latest_minor_releases.count - 1
        runner_version_position = latest_minor_releases.index(version_without_patch(runner_version))

        return true if runner_version_position.nil? # consider outside if version is too old

        # https://docs.gitlab.com/ee/policy/maintenance.html#backporting-to-older-releases
        latest_version_position - runner_version_position > 2
      end

      def version_without_patch(version)
        ::Gitlab::VersionInfo.new(version.major, version.minor, 0)
      end
    end
  end
end