From f73f8e8af99a9e76e8d78805a9c91213643b672f Mon Sep 17 00:00:00 2001 From: Michal Bugno Date: Wed, 24 Nov 2010 15:04:10 +0100 Subject: [PATCH] Basic functionality --- .gitignore | 1 + Gemfile | 13 +- Gemfile.lock | 129 ++++++++++++++++++ app/controllers/projects_controller.rb | 22 +++ app/helpers/projects_helper.rb | 2 + app/models/build.rb | 35 +++++ app/models/project.rb | 13 ++ app/views/layouts/application.html.erb | 14 -- app/views/layouts/application.html.haml | 14 ++ app/views/projects/_form.html.haml | 11 ++ app/views/projects/index.html.haml | 4 + app/views/projects/new.html.haml | 2 + app/views/projects/show.html.haml | 3 + builds/.gitkeep | 0 config/database.yml.sample | 26 ++++ config/initializers/delayed_job_config.rb | 1 + config/routes.rb | 58 +------- db/migrate/20101124105347_create_projects.rb | 14 ++ .../20101124114908_create_delayed_jobs.rb | 21 +++ db/migrate/20101124114955_create_builds.rb | 15 ++ db/schema.rb | 47 +++++++ public/stylesheets/master.css | 0 script/delayed_job | 5 + test/unit/build_test.rb | 8 ++ test/unit/project_test.rb | 8 ++ 25 files changed, 395 insertions(+), 71 deletions(-) create mode 100644 Gemfile.lock create mode 100644 app/controllers/projects_controller.rb create mode 100644 app/helpers/projects_helper.rb create mode 100644 app/models/build.rb create mode 100644 app/models/project.rb delete mode 100644 app/views/layouts/application.html.erb create mode 100644 app/views/layouts/application.html.haml create mode 100644 app/views/projects/_form.html.haml create mode 100644 app/views/projects/index.html.haml create mode 100644 app/views/projects/new.html.haml create mode 100644 app/views/projects/show.html.haml create mode 100644 builds/.gitkeep create mode 100644 config/database.yml.sample create mode 100644 config/initializers/delayed_job_config.rb create mode 100644 db/migrate/20101124105347_create_projects.rb create mode 100644 db/migrate/20101124114908_create_delayed_jobs.rb create mode 100644 db/migrate/20101124114955_create_builds.rb create mode 100644 db/schema.rb create mode 100644 public/stylesheets/master.css create mode 100755 script/delayed_job create mode 100644 test/unit/build_test.rb create mode 100644 test/unit/project_test.rb diff --git a/.gitignore b/.gitignore index 027bc0b..545d120 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ test/performance capybara*.html config/*.yml +builds diff --git a/Gemfile b/Gemfile index 12575d5..e1ee8d9 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,17 @@ source 'http://rubygems.org' -gem 'rails', '3.0.3' +gem "rails", "3.0.3" +gem "pg" +gem "haml" +gem "delayed_job" group :development, :test do + gem "capybara" + gem "launchy" + gem "faker" + gem "ruby-debug" + gem "machinist" + gem "nokogiri" + gem "mocha" + gem "database_cleaner" end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..b964fd5 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,129 @@ +GEM + remote: http://rubygems.org/ + specs: + abstract (1.0.0) + actionmailer (3.0.3) + actionpack (= 3.0.3) + mail (~> 2.2.9) + actionpack (3.0.3) + activemodel (= 3.0.3) + activesupport (= 3.0.3) + builder (~> 2.1.2) + erubis (~> 2.6.6) + i18n (~> 0.4) + rack (~> 1.2.1) + rack-mount (~> 0.6.13) + rack-test (~> 0.5.6) + tzinfo (~> 0.3.23) + activemodel (3.0.3) + activesupport (= 3.0.3) + builder (~> 2.1.2) + i18n (~> 0.4) + activerecord (3.0.3) + activemodel (= 3.0.3) + activesupport (= 3.0.3) + arel (~> 2.0.2) + tzinfo (~> 0.3.23) + activeresource (3.0.3) + activemodel (= 3.0.3) + activesupport (= 3.0.3) + activesupport (3.0.3) + arel (2.0.4) + builder (2.1.2) + capybara (0.4.0) + celerity (>= 0.7.9) + culerity (>= 0.2.4) + mime-types (>= 1.16) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + selenium-webdriver (>= 0.0.27) + xpath (~> 0.1.2) + celerity (0.8.4) + childprocess (0.1.4) + ffi (~> 0.6.3) + columnize (0.3.2) + configuration (1.2.0) + culerity (0.2.12) + daemons (1.1.0) + database_cleaner (0.6.0) + delayed_job (2.1.1) + activesupport (~> 3.0) + daemons + erubis (2.6.6) + abstract (>= 1.0.0) + faker (0.3.1) + ffi (0.6.3) + rake (>= 0.8.7) + haml (3.0.24) + i18n (0.4.2) + json_pure (1.4.6) + launchy (0.3.7) + configuration (>= 0.0.5) + rake (>= 0.8.1) + linecache (0.43) + machinist (1.0.6) + mail (2.2.10) + activesupport (>= 2.3.6) + i18n (~> 0.4.1) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.16) + mocha (0.9.9) + rake + nokogiri (1.4.4) + pg (0.9.0) + polyglot (0.3.1) + rack (1.2.1) + rack-mount (0.6.13) + rack (>= 1.0.0) + rack-test (0.5.6) + rack (>= 1.0) + rails (3.0.3) + actionmailer (= 3.0.3) + actionpack (= 3.0.3) + activerecord (= 3.0.3) + activeresource (= 3.0.3) + activesupport (= 3.0.3) + bundler (~> 1.0) + railties (= 3.0.3) + railties (3.0.3) + actionpack (= 3.0.3) + activesupport (= 3.0.3) + rake (>= 0.8.7) + thor (~> 0.14.4) + rake (0.8.7) + ruby-debug (0.10.4) + columnize (>= 0.1) + ruby-debug-base (~> 0.10.4.0) + ruby-debug-base (0.10.4) + linecache (>= 0.3) + rubyzip (0.9.4) + selenium-webdriver (0.1.0) + childprocess (= 0.1.4) + ffi (~> 0.6.3) + json_pure + rubyzip + thor (0.14.6) + treetop (1.4.9) + polyglot (>= 0.3.1) + tzinfo (0.3.23) + xpath (0.1.2) + nokogiri (~> 1.3) + +PLATFORMS + ruby + +DEPENDENCIES + capybara + database_cleaner + delayed_job + faker + haml + launchy + machinist + mocha + nokogiri + pg + rails (= 3.0.3) + ruby-debug diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb new file mode 100644 index 0000000..344fcfa --- /dev/null +++ b/app/controllers/projects_controller.rb @@ -0,0 +1,22 @@ +class ProjectsController < ApplicationController + def index + @projects = Project.order("created_at DESC") + end + + def show + @project = Project.find(params[:id]) + end + + def new + @project = Project.new + end + + def create + @project = Project.new(params[:project]) + if @project.save + redirect_to project_path(@project) + else + render :new + end + end +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb new file mode 100644 index 0000000..db5c5ce --- /dev/null +++ b/app/helpers/projects_helper.rb @@ -0,0 +1,2 @@ +module ProjectsHelper +end diff --git a/app/models/build.rb b/app/models/build.rb new file mode 100644 index 0000000..a5013d9 --- /dev/null +++ b/app/models/build.rb @@ -0,0 +1,35 @@ +class Build < ActiveRecord::Base + belongs_to :project + + # Delayed::Job interface + def perform + # FileUtils.mkdir_p(File.join("builds", project_dir)) + project_dir = project.build_dir + # FileUtils.mkdir_p(File.join("builds", project_dir)) + build_dir = File.join(project_dir, Time.now.strftime("%Y%m%d%H%M") + "_" + commit) + command = "git clone #{project.vcs_source} \"#{build_dir}\"" + `#{command}` + self.stdout = `cd #{build_dir} && rake 2>&1 | tee rake.log` + Rails.logger.debug("*" * 5000) + Rails.logger.debug(self.stdout.inspect) + Rails.logger.debug(self.save!) + Rails.logger.debug("*" * 5000) + return false + end + + def after(job) + Rails.logger.debug("Job after hook") + Rails.logger.debug(job.inspect) + end + + def success(job) + Rails.logger.debug("Job success hook") + Rails.logger.debug(job.inspect) + end + + def error(job, exception) + Rails.logger.debug("Job error hook") + Rails.logger.debug(job.inspect) + Rails.logger.debug(exception.inspect) + end +end diff --git a/app/models/project.rb b/app/models/project.rb new file mode 100644 index 0000000..8cac106 --- /dev/null +++ b/app/models/project.rb @@ -0,0 +1,13 @@ +class Project < ActiveRecord::Base + has_many :builds + + def build! + commit = `git log --format=oneline --max-count=1`.split(" ")[0] + build = self.builds.create!(:commit => commit) + Delayed::Job.enqueue(build) + end + + def build_dir + File.join("builds", name.downcase.gsub(/[^A-Za-z0-9]/, "_")) + end +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb deleted file mode 100644 index 26d5d5f..0000000 --- a/app/views/layouts/application.html.erb +++ /dev/null @@ -1,14 +0,0 @@ - - - - BigTuna - <%= stylesheet_link_tag :all %> - <%= javascript_include_tag :defaults %> - <%= csrf_meta_tag %> - - - -<%= yield %> - - - diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml new file mode 100644 index 0000000..e61e2e2 --- /dev/null +++ b/app/views/layouts/application.html.haml @@ -0,0 +1,14 @@ +!!! +%html + %head + %title BigTuna Continuous Integration + = stylesheet_link_tag "master.css" + = csrf_meta_tag + %meta{:"http-equiv" => "Content-Type", :content => "text/html;charset=UTF-8"} + %meta{:name => "keywords", :content => "keywords"} + %meta{:name => "description", :content => "description"} + %body + %header + %h1 BigTuna + #content + = yield diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml new file mode 100644 index 0000000..7bf1352 --- /dev/null +++ b/app/views/projects/_form.html.haml @@ -0,0 +1,11 @@ +%div + = f.label(:name) + = f.text_field(:name) +%div + = f.label(:vcs_type) + = f.text_field(:vcs_type) +%div + = f.label(:vcs_source) + = f.text_field(:vcs_source) +%div + = f.submit(f.object.new_record? ? "Create" : "Update") diff --git a/app/views/projects/index.html.haml b/app/views/projects/index.html.haml new file mode 100644 index 0000000..c51f7e3 --- /dev/null +++ b/app/views/projects/index.html.haml @@ -0,0 +1,4 @@ += link_to("Add project", new_project_path) +%ol + - @projects.each do |project| + %li= link_to(project.name, project_path(project)) diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml new file mode 100644 index 0000000..c67f70d --- /dev/null +++ b/app/views/projects/new.html.haml @@ -0,0 +1,2 @@ += form_for(@project, :url => projects_path) do |f| + = render :partial => "form", :locals => {:f => f} diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml new file mode 100644 index 0000000..b4c347b --- /dev/null +++ b/app/views/projects/show.html.haml @@ -0,0 +1,3 @@ +%h2= @project.name +%span= @project.vcs_type +%span= @project.vcs_source diff --git a/builds/.gitkeep b/builds/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/database.yml.sample b/config/database.yml.sample new file mode 100644 index 0000000..66e73b6 --- /dev/null +++ b/config/database.yml.sample @@ -0,0 +1,26 @@ +development: + adapter: postgresql + encoding: utf8 + database: big_tuna_development + pool: 5 + username: msq + password: + template: template0 + +test: + adapter: postgresql + encoding: utf8 + database: big_tuna_test + pool: 5 + username: msq + password: + template: template0 + +production: + adapter: postgresql + encoding: utf8 + database: big_tuna_production + pool: 5 + username: msq + password: + template: template0 diff --git a/config/initializers/delayed_job_config.rb b/config/initializers/delayed_job_config.rb new file mode 100644 index 0000000..b25778b --- /dev/null +++ b/config/initializers/delayed_job_config.rb @@ -0,0 +1 @@ +Delayed::Worker.max_attempts = 1 diff --git a/config/routes.rb b/config/routes.rb index e3a9e43..cddf8d0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,58 +1,4 @@ BigTuna::Application.routes.draw do - # The priority is based upon order of creation: - # first created -> highest priority. - - # Sample of regular route: - # match 'products/:id' => 'catalog#view' - # Keep in mind you can assign values other than :controller and :action - - # Sample of named route: - # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase - # This route can be invoked with purchase_url(:id => product.id) - - # Sample resource route (maps HTTP verbs to controller actions automatically): - # resources :products - - # Sample resource route with options: - # resources :products do - # member do - # get 'short' - # post 'toggle' - # end - # - # collection do - # get 'sold' - # end - # end - - # Sample resource route with sub-resources: - # resources :products do - # resources :comments, :sales - # resource :seller - # end - - # Sample resource route with more complex sub-resources - # resources :products do - # resources :comments - # resources :sales do - # get 'recent', :on => :collection - # end - # end - - # Sample resource route within a namespace: - # namespace :admin do - # # Directs /admin/products/* to Admin::ProductsController - # # (app/controllers/admin/products_controller.rb) - # resources :products - # end - - # You can have the root of your site routed with "root" - # just remember to delete public/index.html. - # root :to => "welcome#index" - - # See how all your routes lay out with "rake routes" - - # This is a legacy wild controller route that's not recommended for RESTful applications. - # Note: This route will make all actions in every controller accessible via GET requests. - # match ':controller(/:action(/:id(.:format)))' + resources :projects + root :to => "projects#index" end diff --git a/db/migrate/20101124105347_create_projects.rb b/db/migrate/20101124105347_create_projects.rb new file mode 100644 index 0000000..21b550e --- /dev/null +++ b/db/migrate/20101124105347_create_projects.rb @@ -0,0 +1,14 @@ +class CreateProjects < ActiveRecord::Migration + def self.up + create_table :projects do |t| + t.string :name, :null => false + t.string :vcs_type, :null => false + t.string :vcs_source, :null => false + t.timestamps + end + end + + def self.down + drop_table :projects + end +end diff --git a/db/migrate/20101124114908_create_delayed_jobs.rb b/db/migrate/20101124114908_create_delayed_jobs.rb new file mode 100644 index 0000000..ac579df --- /dev/null +++ b/db/migrate/20101124114908_create_delayed_jobs.rb @@ -0,0 +1,21 @@ +class CreateDelayedJobs < ActiveRecord::Migration + def self.up + create_table :delayed_jobs, :force => true do |table| + table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue + table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually. + table.text :handler # YAML-encoded string of the object that will do work + table.text :last_error # reason for last failure (See Note below) + table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future. + table.datetime :locked_at # Set when a client is working on this object + table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead) + table.string :locked_by # Who is working on this object (if locked) + table.timestamps + end + + add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority' + end + + def self.down + drop_table :delayed_jobs + end +end \ No newline at end of file diff --git a/db/migrate/20101124114955_create_builds.rb b/db/migrate/20101124114955_create_builds.rb new file mode 100644 index 0000000..9427174 --- /dev/null +++ b/db/migrate/20101124114955_create_builds.rb @@ -0,0 +1,15 @@ +class CreateBuilds < ActiveRecord::Migration + def self.up + create_table :builds do |t| + t.references :project + t.string :commit + t.string :status + t.text :stdout + t.timestamps + end + end + + def self.down + drop_table :builds + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..90a8f88 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,47 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20101124114955) do + + create_table "builds", :force => true do |t| + t.integer "project_id" + t.string "commit" + t.string "status" + t.text "stdout" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "delayed_jobs", :force => true do |t| + t.integer "priority", :default => 0 + t.integer "attempts", :default => 0 + t.text "handler" + t.text "last_error" + t.datetime "run_at" + t.datetime "locked_at" + t.datetime "failed_at" + t.string "locked_by" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" + + create_table "projects", :force => true do |t| + t.string "name", :null => false + t.string "vcs_type", :null => false + t.string "vcs_source", :null => false + t.datetime "created_at" + t.datetime "updated_at" + end + +end diff --git a/public/stylesheets/master.css b/public/stylesheets/master.css new file mode 100644 index 0000000..e69de29 diff --git a/script/delayed_job b/script/delayed_job new file mode 100755 index 0000000..edf1959 --- /dev/null +++ b/script/delayed_job @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) +require 'delayed/command' +Delayed::Command.new(ARGV).daemonize diff --git a/test/unit/build_test.rb b/test/unit/build_test.rb new file mode 100644 index 0000000..c79f4a8 --- /dev/null +++ b/test/unit/build_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class BuildTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb new file mode 100644 index 0000000..bc23a8a --- /dev/null +++ b/test/unit/project_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class ProjectTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end