<commit_before>#
# Author: <NAME> <<EMAIL>>
# Date: Sat, 10 Jan 2009 16:12:47 +0200
#

require 'fileutils'

class CiaRails::Builder
  class BuildError < StandardError;end

  attr_reader :project
  attr_accessor :work_dir, :state_file, :state_dir

  def initialize(prj)
    @project = prj
    reset_buffer
    @operation = "Build"
  end

  def reset_buffer
    @output = ""
  end

  def add_line(line)
    @output << line << "\n"
  end

  # Used to deploy to stage server
  def deploy
    @operation = "Deploy"

    prepare_local_dir do
      run_cmd "cap -q deploy"
      run_cmd "cap -q deploy:migrate"
      run_cmd "cap -q deploy:cleanup"
    end
  end

  # Verify tests
  def build
    prepare_local_dir do
      add_scm_log
      # TODO install new gems
      # TODO install new Debian packages
      ignore_logs { prepare_env }
      run_build
    end
  end

  def run_build
    unless rails?
      run_cmd(project[:build_cmd])
    else
      run_tests
    end
  end

  def prepare_env
    unless rails?
      # TODO
    else
      prepare_db
    end
  end

  def rails?
    ! (project[:type] && project[:type] != "rails")
  end

  def prepare_local_dir # yields
    self.state_dir = File.join(work_dir, project[:name])
    self.state_file = File.join(state_dir, "state.yml")

    load_state if test ?f, state_file
    state = :ok

    begin
      # TODO if project dir does not exist, checkout project and create a default database.yml
      unless test ?d, project[:home_dir]
        g = CiaRails::Git.new(self)
        g.checkout(project[:scm_url], project[:home_dir])
      end

      Dir.chdir(project[:home_dir])
      ignore_logs { update_sources }

      if @vcs.changed?
        yield
      end
    rescue BuildError
      state = :failed
    ensure
      if @vcs && @vcs.changed?
        save_state(state)
        send_notifications(state)
      end
    end
  end

  def ignore_logs(&block)
    buf = @output.clone
    yield
    # if no exceptions
    @output = buf
  end

  def add_scm_log
    @vcs.logs
  end

  def load_state
    @config = YAML::load_file(state_file)
    @old_state = config[:state]
  end

  def config
    @config || {}
  end

  def save_state(state)
    FileUtils::mkdir_p(state_dir)
    number = Time.now.to_i

    @config ||= {}
    @config[:last_revision] = @vcs.revision
    @config[:state] = state
    @config[:number] = number

    if state == :ok
      config[:failed_rev] = nil
    elsif state == :failed && @config[:failed_rev].nil?
      # Save last rev when build failed
      @config[:failed_rev] = @config[:last_revision]
    end

    File.open(state_file, "w") do |f|
      f.write YAML.dump(@config)
    end

    @output_file = File.join(state_dir, "output_#{number}.txt")

    File.open(@output_file, "w") do |f|
      f.write @output
    end
  end

  def prepare_db
    dev = rails_config['development']

    run_cmd("mysqladmin drop -f \"#{dev['database']}\"", true)
    run_cmd("mysqladmin create \"#{dev['database']}\"")
    run_cmd("mysqladmin create \"#{rails_config['test']['database']}\"", true)
    run_cmd("rake db:migrate --trace")
  end

  def run_tests
    run_cmd("rake")
  end

  def send_notifications(event)
    subject = nil

    if event == @old_state
      # Do not send notifications if build state was not changed
      return
    end

    if event == :ok
      if @old_state == :failed
        subject = "#{@operation} is fixed"
      end
    elsif event == :failed
      subject = "#{@operation} failed"
    else
      raise "bad event"
    end

    if subject
      if @vcs.emails.include?(project[:qa_email])<commit_msg>drop test db too on rails prepare_db<commit_after>#
# Author: <NAME> <<EMAIL>>
# Date: Sat, 10 Jan 2009 16:12:47 +0200
#

require 'fileutils'

class CiaRails::Builder
  class BuildError < StandardError;end

  attr_reader :project
  attr_accessor :work_dir, :state_file, :state_dir

  def initialize(prj)
    @project = prj
    reset_buffer
    @operation = "Build"
  end

  def reset_buffer
    @output = ""
  end

  def add_line(line)
    @output << line << "\n"
  end

  # Used to deploy to stage server
  def deploy
    @operation = "Deploy"

    prepare_local_dir do
      run_cmd "cap -q deploy"
      run_cmd "cap -q deploy:migrate"
      run_cmd "cap -q deploy:cleanup"
    end
  end

  # Verify tests
  def build
    prepare_local_dir do
      add_scm_log
      # TODO install new gems
      # TODO install new Debian packages
      ignore_logs { prepare_env }
      run_build
    end
  end

  def run_build
    unless rails?
      run_cmd(project[:build_cmd])
    else
      run_tests
    end
  end

  def prepare_env
    unless rails?
      # TODO
    else
      prepare_db
    end
  end

  def rails?
    ! (project[:type] && project[:type] != "rails")
  end

  def prepare_local_dir # yields
    self.state_dir = File.join(work_dir, project[:name])
    self.state_file = File.join(state_dir, "state.yml")

    load_state if test ?f, state_file
    state = :ok

    begin
      # TODO if project dir does not exist, checkout project and create a default database.yml
      unless test ?d, project[:home_dir]
        g = CiaRails::Git.new(self)
        g.checkout(project[:scm_url], project[:home_dir])
      end

      Dir.chdir(project[:home_dir])
      ignore_logs { update_sources }

      if @vcs.changed?
        yield
      end
    rescue BuildError
      state = :failed
    ensure
      if @vcs && @vcs.changed?
        save_state(state)
        send_notifications(state)
      end
    end
  end

  def ignore_logs(&block)
    buf = @output.clone
    yield
    # if no exceptions
    @output = buf
  end

  def add_scm_log
    @vcs.logs
  end

  def load_state
    @config = YAML::load_file(state_file)
    @old_state = config[:state]
  end

  def config
    @config || {}
  end

  def save_state(state)
    FileUtils::mkdir_p(state_dir)
    number = Time.now.to_i

    @config ||= {}
    @config[:last_revision] = @vcs.revision
    @config[:state] = state
    @config[:number] = number

    if state == :ok
      config[:failed_rev] = nil
    elsif state == :failed && @config[:failed_rev].nil?
      # Save last rev when build failed
      @config[:failed_rev] = @config[:last_revision]
    end

    File.open(state_file, "w") do |f|
      f.write YAML.dump(@config)
    end

    @output_file = File.join(state_dir, "output_#{number}.txt")

    File.open(@output_file, "w") do |f|
      f.write @output
    end
  end

  def prepare_db
    dev = rails_config['development']

    run_cmd("mysqladmin drop -f \"#{dev['database']}\"", true)
    run_cmd("mysqladmin create \"#{dev['database']}\"")

    run_cmd("mysqladmin drop \"#{rails_config['test']['database']}\"", true)
    run_cmd("mysqladmin create \"#{rails_config['test']['database']}\"")

    run_cmd("rake db:migrate --trace")
  end

  def run_tests
    run_cmd("rake")
  end

  def send_notifications(event)
    subject = nil

    if event == @old_state
      # Do not send notifications if build state was not changed
      return
    end

    if event == :ok
      if @old_state == :failed
        subject = "#{@operation} is fixed"
      end
    elsif event == :failed
      subject = "#{@operation} failed"
    else
      raise "bad event"
    end

    if subject
      if @vcs.emails.include?(project[:qa_email])
{'fraction_non_alphanumeric': 0.11252741228070176, 'fraction_numerical': 0.0043859649122807015, 'mean_word_length': 2.545675413022352, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7186917', 'n_tokens_mistral': 2541, 'n_tokens_neox': 2431, 'n_words': 640}