require 'fileutils' require 'cucumber/rake/task' module Henry class Task # The Henry Task implementation for Cucumber class CucumberTask < RakeTask attr_accessor :generated_reports, :report_recipients # The temporary output file path for the RspecTask execution. OUT_PATH = 'cucumber.out' # Default base output directory DEFAULT_OUTPUT_BASE_DIR = '.output' # The reports path template. REPORTS_DIR = 'reports/${FORMAT}' # Default time format to be used in the reports filepath. TIME_FORMAT = '%Y-%m-%dT%H%M%S' # The Cucumber Rake Application name. # # @return [String] the rake application name. APPLICATION_NAME = 'cucumber' def application_name APPLICATION_NAME end def out_path OUT_PATH end def execute super if self.execution.code == 'OK' self.execution.code = 'ERROR' if self.execution.output =~ /\d+ scenarios? \([^\(]*\d+ failed[^\(]*\)/ end end def after_execute if self.execution.code != 'OK' && !(self.generated_reports || []).empty? && !(self.report_recipients || []).empty? tgz_path = "#{self.base_output_path}/#{DateTime.now.strftime(TIME_FORMAT)}_#{self.name}.tgz" `tar czf "#{tgz_path}" "#{self.generated_reports.join('" "')}"` Henry::EmailClient.send_file(tgz_path, self.report_recipients.uniq, "[Henry Reports] #{self.name}") `rm "#{tgz_path}"` end super end # Returns output base path # # @return [String] the base output path. def base_output_path @base_output_path ||= (self.data.system[:output_directory] ? "#{self.data.system[:output_directory]}/output" : DEFAULT_OUTPUT_BASE_PATH) end # Configures the Task. # # @param [Hash] params the task params. # @param [Hash] extended_context task extended context. def configure(params, extended_context={}) File.open(OUT_PATH, 'w') { |f| } # Makes available the cucumber rake task. Rake.application.clear Cucumber::Rake::Task.new do |t| if self.data.options t.cucumber_opts = self.custom_options(extended_context['options']||{}) else t.cucumber_opts = self.default_options() end end super end # Returns the custom cucumber_opts that user may have passed. # # @param [Hash] extended_options set of extended options. # @return [String] def custom_options(extended_options={}) "#{self.format_options} #{self.tags_options(extended_options)} #{self.report_options} #{self.rerun_options} #{self.misc_options}" end # Returns the miscellaneous cucumber_opts. # # @return [String] def misc_options options = [] options << '--expand' if self.data.options['expand'] == 'true' options << "--require features #{self.data.options['pattern']}" if self.data.options['pattern'] options << '--no-source' if self.data.options['no-source'] == 'true' return options.join(' ') end # Returns the default cucumber_opts. # # @return [String] def default_options "--format pretty --format pretty --out #{OUT_PATH}" end # Returns the cucumber_opts related with formatting. # # @return [String] def format_options "--format #{self.data.options['format'] || 'pretty'} --format #{self.data.options['format'] || 'pretty'} --out #{OUT_PATH}" end # Returns the cucumber_opts related with tags to be run. # # # @return [String] def tags_options(extended_options={}) return '' if self.data.options['tags'].nil? && extended_options['tags'].nil? ((self.data.options['tags']||[])+(extended_options['tags']||[])).collect do |tag| "--tags #{tag.gsub(/(,?~?)(\w+)/, '\1@\2')}" end.join(' ') end # Returns the cucumber_opts related with report paaths and formats. # # @return [String] def report_options self.generated_reports = [] self.report_recipients = [] return '' if self.data.reports.nil? self.data.reports.collect do |report_options| report_options['name'] ||= "${DATE}_${TASK_NAME}.#{report_options['format']}" self.generated_reports << self.report_file_path(report_options['format'], report_options['name']) self.report_recipients += (report_options['recipients'] || []) FileUtils.mkdir_p(self.reports_dir(report_options['format'])) "--format #{report_options['format']} --out #{self.report_file_path(report_options['format'], report_options['name'])}" end.join(' ') end # Returns the cucumber_opts related with the rerun usage. # # @return [String] def rerun_options return '' return '' if self.data.options['rerun'].nil? self.data.options['rerun'] -= 1 "---format rerun --out tmp/rerun" end # Returns true whenever rerun is set and the reties counter is still positive. # # @return [True,False] def rerun? self.data.options['rerun'] && self.data.options['rerun'] >= 0 end # Returns the report file path for the given format and file name. # # @param [String] format the rspec formatter name. # @param [String] file_name the report file name template. # @return [String] the report file path. def report_file_path(format, file_name) "#{self.reports_dir(format)}/#{self.report_file_name(file_name)}" end # Interpolates and returns the report file name. # # @param [String] file_name the report file name. # @returns [String] the report file name. def report_file_name(file_name) file_name.gsub(/\${[A-Z_]+}/, '${TASK_NAME}' => self.name, '${DATE}' => DateTime.now.strftime(TIME_FORMAT)).gsub(' ', '_') end # Interpolates and returns the reports directory for the given format. # # @param [String] format the formatter name. # @return [Stiring] the reports directory. def reports_dir(format) "#{self.base_output_path}/#{REPORTS_DIR}".gsub(/\${[A-Z_]+}/, '${FORMAT}' => format).gsub(' ', '_') end end end end