3scale/porta

View on GitHub
app/lib/system/deploy.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module System
  module Deploy
    mattr_accessor :info

    DEFAULT_DEPLOY_INFO_PATH = '.deploy_info'
    private_constant :DEFAULT_DEPLOY_INFO_PATH

    # Provides information about the version of the code:
    #   - revision: low-level version, that is used by BugSnag as app version
    #   - release: customer-facing version, that is visible in the admin portal footer
    #   - deployed_at: timestamp of the deployment
    #   - docs_version: product name and the version that are used as prefix for product documentation path in the
    #                   Red Hat Customer Portal
    # The data is taken from the `.deploy_info` file in the root directory, but for SaaS the release
    # is overridden with DEFAULT_VERSION.
    # `.deploy_info` file is injected to the container during container build process in CPaaS (the content is set in Dockerfile)
    # The information is exposed via {MASTER_PORTAL}/deploy endpoint for logged-in users.
    class Info
      DEFAULT_VERSION = '2.x'

      private_constant :DEFAULT_VERSION

      attr_reader :revision, :deployed_at, :release

      delegate :minor_version, :major_version, to: :version

      def initialize(info)
        @revision = info.fetch('revision') { `git rev-parse HEAD 2> /dev/null`.strip }
        @release = ThreeScale.saas? ? DEFAULT_VERSION : info.fetch('release', DEFAULT_VERSION)
        @deployed_at = info.fetch('deployed_at') { Time.now.utc }
        @error = info.fetch(:error) if info.key?(:error)
      end

      def docs_version
        @docs_version ||= ThreeScale.saas? || rhoam? ? 'red_hat_3scale/2-saas' : "red_hat_3scale_api_management/#{major_version}.#{minor_version}"
      end

      # RHOAM version has only one segment (release = 'RHOAM')
      def rhoam?
        version.segments.count < 2
      end

      private

      class VersionParser
        attr_reader :segments

        def initialize(release)
          @segments = release.to_s.split('.')
        end

        def minor_version
          segments[1]
        end

        def major_version
          segments[0]
        end
      end

      def version
        @version ||= VersionParser.new(release)
      end
    end

    class InvalidInfo
      attr_reader :release

      def initialize(error)
        @error = error.message
        @backtrace = error.backtrace
        @release = ENV['AMP_RELEASE'].presence
      end
    end

    def self.parse_deploy_info(deploy_info_path = DEFAULT_DEPLOY_INFO_PATH)
      path = Rails.root.join(deploy_info_path).expand_path
      return { error: { path: path.to_s, message: 'not found' } } unless path.exist?

      ActiveSupport::JSON.decode(path.read)
    end

    def self.call(_)
      [200, {'Content-Type' => 'application/json'}, [info.to_json]]
    end

    def self.load_info!(deploy_info = parse_deploy_info)
      self.info = Info.new(deploy_info)
    rescue StandardError => exception
      self.info = InvalidInfo.new(exception)
    end
  end
end

System::Deploy.load_info!