100 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
module Gitlab
 | 
						|
  module Chat
 | 
						|
    # Class for gathering and formatting the output of a `Ci::Build`.
 | 
						|
    class Output
 | 
						|
      attr_reader :build
 | 
						|
 | 
						|
      MissingBuildSectionError = Class.new(StandardError)
 | 
						|
 | 
						|
      # The primary trace section to look for.
 | 
						|
      PRIMARY_SECTION = 'chat_reply'
 | 
						|
 | 
						|
      # The backup trace section in case the primary one could not be found.
 | 
						|
      FALLBACK_SECTION = 'step_script'
 | 
						|
 | 
						|
      # `step_script` used to be `build_script` before runner 13.1
 | 
						|
      LEGACY_SECTION = 'build_script'
 | 
						|
 | 
						|
      # build - The `Ci::Build` to obtain the output from.
 | 
						|
      def initialize(build)
 | 
						|
        @build = build
 | 
						|
      end
 | 
						|
 | 
						|
      # Returns a `String` containing the output of the build.
 | 
						|
      #
 | 
						|
      # The output _does not_ include the command that was executed.
 | 
						|
      def to_s
 | 
						|
        offset, length = read_offset_and_length
 | 
						|
 | 
						|
        trace.read do |stream|
 | 
						|
          stream.seek(offset)
 | 
						|
 | 
						|
          output = stream
 | 
						|
            .stream
 | 
						|
            .read(length)
 | 
						|
            .force_encoding(Encoding.default_external)
 | 
						|
 | 
						|
          without_executed_command_line(output)
 | 
						|
        end
 | 
						|
      end
 | 
						|
 | 
						|
      # Removes the line containing the executed command from the build output.
 | 
						|
      #
 | 
						|
      # output - A `String` containing the output of a trace section.
 | 
						|
      def without_executed_command_line(output)
 | 
						|
        # If `output.split("\n")` produces an empty Array then the slicing that
 | 
						|
        # follows it will produce a nil. For example:
 | 
						|
        #
 | 
						|
        #     "\n".split("\n")        # => []
 | 
						|
        #     "\n".split("\n")[1..] # => nil
 | 
						|
        #
 | 
						|
        # To work around this we only "join" if we're given an Array.
 | 
						|
        if (converted = output.split("\n")[1..])
 | 
						|
          converted.join("\n")
 | 
						|
        else
 | 
						|
          ''
 | 
						|
        end
 | 
						|
      end
 | 
						|
 | 
						|
      # Returns the trace section for the given name, or `nil` if the section
 | 
						|
      # could not be found.
 | 
						|
      #
 | 
						|
      # name - The name of the trace section to find.
 | 
						|
      def find_build_trace_section(name)
 | 
						|
        trace_sections.find { |s| s[:name] == name }
 | 
						|
      end
 | 
						|
 | 
						|
      def trace_sections
 | 
						|
        @trace_sections ||= trace.extract_sections
 | 
						|
      end
 | 
						|
 | 
						|
      def trace
 | 
						|
        @trace ||= build.trace
 | 
						|
      end
 | 
						|
 | 
						|
      private
 | 
						|
 | 
						|
      # Returns the offset to seek to and the number of bytes to read relative
 | 
						|
      # to the offset.
 | 
						|
      def read_offset_and_length
 | 
						|
        section = find_build_trace_section(PRIMARY_SECTION) ||
 | 
						|
          find_build_trace_section(FALLBACK_SECTION) ||
 | 
						|
          find_build_trace_section(LEGACY_SECTION)
 | 
						|
 | 
						|
        unless section
 | 
						|
          raise(
 | 
						|
            MissingBuildSectionError,
 | 
						|
            "The build_script trace section could not be found for build #{build.id}"
 | 
						|
          )
 | 
						|
        end
 | 
						|
 | 
						|
        length = section[:byte_end] - section[:byte_start]
 | 
						|
 | 
						|
        [section[:byte_start], length]
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |