igor-starostenko/report_factory

View on GitHub
app/controllers/project_rspec_reports_controller.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

# Provides logic and interface for Project Rspec Reports API
class ProjectRspecReportsController < BaseProjectsController
  before_action :set_project
  before_action :search_tags, only: %i[index]

  REPORT_ATTRIBUTES = { tags: [] }.freeze
  RSPEC_REPORT_ATTRIBUTES = %i[version summary_line].freeze
  SUMMARY_ATTRIBUTES = {
    summary: %i[duration example_count failure_count
                errors_outside_of_examples_count
                pending_count]
  }.freeze
  EXAMPLE_ATTRIBUTES = {
    examples: [:id, :description, :full_description, :status, :file_path,
               :line_number, :run_time, :pending_message,
               { exception: [:class, :message, { backtrace: [] }] }]
  }.freeze

  def index
    render jsonapi: ensure_in_bounds(@rspec_reports), status: :ok
  end

  def show
    @rspec_report = RspecReport.includes(:report, :project)
                               .find(params.fetch(:id))
    render jsonapi: @rspec_report, status: :ok
  end

  def create
    return render_bad_report unless valid_report?

    if new_rspec_report.save
      new_report.save && new_user_report.save
      render jsonapi: @rspec_report, status: :created
    else
      render jsonapi_errors: @rspec_report.errors, status: :bad_request
    end
  end

  private

  def search_tags
    reports = tags ? reports_by_tags(tags) : all_reports
    reports_desc = reports.order('rspec_reports.id desc')
    @rspec_reports = paginate(reports_desc, per_page: per_page)
  end

  def reports_by_tags(tags)
    RspecReport.all_details.tags_by_project(@project.project_name, tags)
  end

  def all_reports
    RspecReport.all_details.by_project(@project.project_name).includes(:report)
  end

  def valid_report?
    examples = attributes(:example, :examples)
    attributes(:summary, :summary) &&
      examples && examples.size.positive?
  end

  def new_rspec_report
    @rspec_report = RspecReport.new(attributes(:rspec_report)
      .merge(summary_attributes: attributes(:summary, :summary),
             examples_attributes: rspec_examples_attributes))
  end

  def new_report
    @report = Report.new(project_id: @project.id,
                         reportable_type: RspecReport,
                         status: @rspec_report.status,
                         tags: attributes(:report).fetch(:tags, []),
                         reportable_id: @rspec_report.id)
  end

  def new_user_report
    @user_report = UserReport.new(user_id: @auth_user.id,
                                  report_id: @report.id)
  end

  def rspec_examples_attributes
    attributes(:example, :examples).map do |example_args|
      exception_attributes =
        rspec_exception_attributes(example_args[:exception])
      args = { spec_id: example_args[:id],
               exception_attributes: exception_attributes }
      args.merge(example_args).except('id', 'exception')
    end
  end

  def rspec_exception_attributes(exception_args)
    return {} unless exception_args

    { 'classname' => exception_args[:class] }
      .merge(exception_args).except('class')
  end

  def render_bad_report
    render json: { error: 'Bad report' }, status: :bad_request
  end

  def per_page
    @per_page ||= params.fetch(:per_page, 30)
  end

  def tags
    @tags ||= params[:tags]&.map(&:downcase)
  end
end