diff options
author | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2012-11-01 11:33:02 +0200 |
---|---|---|
committer | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2012-11-01 11:33:02 +0200 |
commit | c473b30398191c5715b98e4bf51cf40e9b1587cf (patch) | |
tree | ecb9aaeccacd67a1ae5a656381ae1edc916eac16 | |
parent | 0773854f387f6d85f3ae382d228ee51c4df5e566 (diff) | |
download | gitlab-ci-c473b30398191c5715b98e4bf51cf40e9b1587cf.tar.gz |
Routes, bootstrap, builds
-rw-r--r-- | app/assets/javascripts/application.js | 8 | ||||
-rw-r--r-- | app/assets/stylesheets/main.scss | 56 | ||||
-rw-r--r-- | app/controllers/builds_controller.rb | 57 | ||||
-rw-r--r-- | app/helpers/builds_helper.rb | 2 | ||||
-rw-r--r-- | app/models/project.rb | 4 | ||||
-rw-r--r-- | app/views/builds/_form.html.haml | 16 | ||||
-rw-r--r-- | app/views/builds/edit.html.haml | 7 | ||||
-rw-r--r-- | app/views/builds/index.html.haml | 21 | ||||
-rw-r--r-- | app/views/builds/new.html.haml | 5 | ||||
-rw-r--r-- | app/views/builds/show.html.haml | 12 | ||||
-rw-r--r-- | app/views/layouts/application.html.haml | 32 | ||||
-rw-r--r-- | config/routes.rb | 62 | ||||
-rw-r--r-- | lib/runner.rb | 86 | ||||
-rw-r--r-- | spec/controllers/builds_controller_spec.rb | 164 | ||||
-rw-r--r-- | spec/helpers/builds_helper_spec.rb | 15 | ||||
-rw-r--r-- | spec/requests/builds_spec.rb | 11 | ||||
-rw-r--r-- | spec/routing/builds_routing_spec.rb | 35 | ||||
-rw-r--r-- | spec/views/builds/edit.html.haml_spec.rb | 20 | ||||
-rw-r--r-- | spec/views/builds/index.html.haml_spec.rb | 23 | ||||
-rw-r--r-- | spec/views/builds/new.html.haml_spec.rb | 20 | ||||
-rw-r--r-- | spec/views/builds/show.html.haml_spec.rb | 17 |
21 files changed, 613 insertions, 60 deletions
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 9097d83..f251ec0 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -13,3 +13,11 @@ //= require jquery //= require jquery_ujs //= require_tree . +// +function getBuild(buildPath) { + console.log('run'); + setTimeout(function() { + $.get(buildPath + ".js"); + }, 1500); +} + diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss new file mode 100644 index 0000000..1b51de9 --- /dev/null +++ b/app/assets/stylesheets/main.scss @@ -0,0 +1,56 @@ +@import "bootstrap"; + +body { + color:#666; + margin-bottom:10px; +} + +.right { + float:right; +} + +.project_box { + color:#777; + border: 1px solid #ddd; + margin-right:20px; + margin-bottom:20px; + float:left; + width:270px; +} + +.project_box .alert { + border-radius: 0; +} + +.project_box .title { + font-size:14px; + line-height:28px; + padding: 10px; +} + +.project_box .body { + padding:10px; +} + +pre.trace { + background: #000; + color:#fff; +} +.navbar .navbar-inner { border-radius: 0; } + +.builds .build.alert{ + margin-bottom: 6px; +} + +.color31 { + color: red !important; +} + +.color32 { + color: green !important; +} + +.color33 { + color: yellow !important; +} + diff --git a/app/controllers/builds_controller.rb b/app/controllers/builds_controller.rb new file mode 100644 index 0000000..94de014 --- /dev/null +++ b/app/controllers/builds_controller.rb @@ -0,0 +1,57 @@ +class BuildsController < ApplicationController + before_filter :authenticate_user!, except :index, :show + + def index + @builds = Build.all + end + + def show + @build = Build.find(params[:id]) + end + + def new + @build = Build.new + end + + def edit + @build = Build.find(params[:id]) + end + + def create + @build = Build.new(params[:build]) + + respond_to do |format| + if @build.save + format.html { redirect_to @build, notice: 'Build was successfully created.' } + format.json { render json: @build, status: :created, location: @build } + else + format.html { render action: "new" } + format.json { render json: @build.errors, status: :unprocessable_entity } + end + end + end + + def update + @build = Build.find(params[:id]) + + respond_to do |format| + if @build.update_attributes(params[:build]) + format.html { redirect_to @build, notice: 'Build was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @build.errors, status: :unprocessable_entity } + end + end + end + + def destroy + @build = Build.find(params[:id]) + @build.destroy + + respond_to do |format| + format.html { redirect_to builds_url } + format.json { head :no_content } + end + end +end diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb new file mode 100644 index 0000000..d621e99 --- /dev/null +++ b/app/helpers/builds_helper.rb @@ -0,0 +1,2 @@ +module BuildsHelper +end diff --git a/app/models/project.rb b/app/models/project.rb index 727246e..2f266f8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,11 +1,9 @@ -require_relative 'build' - class Project < ActiveRecord::Base attr_accessible :name, :path, :scripts validates_presence_of :name, :path, :scripts - has_many :builds + has_many :builds, dependent: :destroy def register_build opts={} default_opts = { diff --git a/app/views/builds/_form.html.haml b/app/views/builds/_form.html.haml new file mode 100644 index 0000000..b8a305e --- /dev/null +++ b/app/views/builds/_form.html.haml @@ -0,0 +1,16 @@ += form_for @build do |f| + - if @build.errors.any? + #error_explanation + %h2= "#{pluralize(@build.errors.count, "error")} prohibited this build from being saved:" + %ul + - @build.errors.full_messages.each do |msg| + %li= msg + + .field + = f.label :trace + = f.text_area :trace + .field + = f.label :status + = f.text_field :status + .actions + = f.submit 'Save' diff --git a/app/views/builds/edit.html.haml b/app/views/builds/edit.html.haml new file mode 100644 index 0000000..5342315 --- /dev/null +++ b/app/views/builds/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing build + += render 'form' + += link_to 'Show', @build +\| += link_to 'Back', builds_path diff --git a/app/views/builds/index.html.haml b/app/views/builds/index.html.haml new file mode 100644 index 0000000..aced983 --- /dev/null +++ b/app/views/builds/index.html.haml @@ -0,0 +1,21 @@ +%h1 Listing builds + +%table + %tr + %th Trace + %th Status + %th + %th + %th + + - @builds.each do |build| + %tr + %td= build.trace + %td= build.status + %td= link_to 'Show', build + %td= link_to 'Edit', edit_build_path(build) + %td= link_to 'Destroy', build, method: :delete, data: { confirm: 'Are you sure?' } + +%br + += link_to 'New Build', new_build_path diff --git a/app/views/builds/new.html.haml b/app/views/builds/new.html.haml new file mode 100644 index 0000000..5053f95 --- /dev/null +++ b/app/views/builds/new.html.haml @@ -0,0 +1,5 @@ +%h1 New build + += render 'form' + += link_to 'Back', builds_path diff --git a/app/views/builds/show.html.haml b/app/views/builds/show.html.haml new file mode 100644 index 0000000..8c23694 --- /dev/null +++ b/app/views/builds/show.html.haml @@ -0,0 +1,12 @@ +%p#notice= notice + +%p + %b Trace: + = @build.trace +%p + %b Status: + = @build.status + += link_to 'Edit', edit_build_path(@build) +\| += link_to 'Back', builds_path diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml new file mode 100644 index 0000000..b6d3817 --- /dev/null +++ b/app/views/layouts/application.html.haml @@ -0,0 +1,32 @@ +!!! 5 +%html{ lang: "en"} + %head + %meta{charset: "utf-8"} + %title GitLab CI + %link{:href => "/bootstrap/css/bootstrap.min.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/ + %link{:href => "/custom.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/ + %script{:src => "/jquery-1.8.2.min.js", :type => "text/javascript"} + %script{:src => "/application.js", :type => "text/javascript"} + %script{:src => "/bootstrap/js/bootstrap.min.js", :type => "text/javascript"} + = stylesheet_link_tag "application", :media => "all" + = javascript_include_tag "application" + = csrf_meta_tags + %body + .navbar + .navbar-inner + %a.brand{:href => "/"} GitLab CI + %ul.nav + %li + %a{:href => "/"} Home + - if is_user? + %li + %span.btn.disabled= @user.email + %li + %a{:href => "/projects/new"} Add Project + %li + %a{:href => "/logout"} Logout + - else + %li + %a{:href => "/login"} Login + .container + = yield diff --git a/config/routes.rb b/config/routes.rb index 4bbe5c8..422be5a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,60 +1,8 @@ GitlabCi::Application.routes.draw do - devise_for :users - - # 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 + resources :projects do + resources :builds + 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)' + devise_for :users + root :to => 'projects#index' end diff --git a/lib/runner.rb b/lib/runner.rb new file mode 100644 index 0000000..13a2631 --- /dev/null +++ b/lib/runner.rb @@ -0,0 +1,86 @@ +require 'open3' +require 'timeout' + +class Runner + TIMEOUT = 1800 + attr_accessor :project, :build, :output + + @queue = :runner + + def self.perform(build_id) + new(Build.find(build_id)).run + end + + def initialize(build) + @logger = Logger.new(STDOUT) + @logger.level = Logger::INFO + + @build = build + @project = build.project + @output = '' + end + + def run + path = project.path + commands = project.scripts + + + + Dir.chdir(path) do + commands.each_line do |line| + status = command(line, path) + build.write_trace(@output) + + unless status + build.fail! + return + end + end + end + + build.success! + rescue Errno::ENOENT + @output << "INVALID PROJECT PATH" + build.fail! + rescue Timeout::Error + @output << "TIMEOUT" + build.fail! + ensure + build.write_trace(@output) + end + + def command(cmd, path) + cmd = cmd.strip + status = 0 + + @output ||= "" + @output << "\n" + @output << cmd + @output << "\n" + + vars = { + "BUNDLE_GEMFILE" => nil, + "BUNDLE_BIN_PATH" => nil, + "RUBYOPT" => nil, + "rvm_" => nil, + "RACK_ENV" => nil, + "RAILS_ENV" => nil, + "PWD" => path + } + + options = { + :chdir => path + } + + Timeout.timeout(TIMEOUT) do + Open3.popen3(vars, cmd, options) do |stdin, stdout, stderr, wait_thr| + status = wait_thr.value.exitstatus + @pid = wait_thr.pid + @output << stdout.read + @output << stderr.read + end + end + + status == 0 + end +end diff --git a/spec/controllers/builds_controller_spec.rb b/spec/controllers/builds_controller_spec.rb new file mode 100644 index 0000000..ef885fc --- /dev/null +++ b/spec/controllers/builds_controller_spec.rb @@ -0,0 +1,164 @@ +require 'spec_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to specify the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. +# +# Compared to earlier versions of this generator, there is very limited use of +# stubs and message expectations in this spec. Stubs are only used when there +# is no simpler way to get a handle on the object needed for the example. +# Message expectations are only used when there is no simpler way to specify +# that an instance is receiving a specific message. + +describe BuildsController do + + # This should return the minimal set of attributes required to create a valid + # Build. As you add validations to Build, be sure to + # update the return value of this method accordingly. + def valid_attributes + {} + end + + # This should return the minimal set of values that should be in the session + # in order to pass any filters (e.g. authentication) defined in + # BuildsController. Be sure to keep this updated too. + def valid_session + {} + end + + describe "GET index" do + it "assigns all builds as @builds" do + build = Build.create! valid_attributes + get :index, {}, valid_session + assigns(:builds).should eq([build]) + end + end + + describe "GET show" do + it "assigns the requested build as @build" do + build = Build.create! valid_attributes + get :show, {:id => build.to_param}, valid_session + assigns(:build).should eq(build) + end + end + + describe "GET new" do + it "assigns a new build as @build" do + get :new, {}, valid_session + assigns(:build).should be_a_new(Build) + end + end + + describe "GET edit" do + it "assigns the requested build as @build" do + build = Build.create! valid_attributes + get :edit, {:id => build.to_param}, valid_session + assigns(:build).should eq(build) + end + end + + describe "POST create" do + describe "with valid params" do + it "creates a new Build" do + expect { + post :create, {:build => valid_attributes}, valid_session + }.to change(Build, :count).by(1) + end + + it "assigns a newly created build as @build" do + post :create, {:build => valid_attributes}, valid_session + assigns(:build).should be_a(Build) + assigns(:build).should be_persisted + end + + it "redirects to the created build" do + post :create, {:build => valid_attributes}, valid_session + response.should redirect_to(Build.last) + end + end + + describe "with invalid params" do + it "assigns a newly created but unsaved build as @build" do + # Trigger the behavior that occurs when invalid params are submitted + Build.any_instance.stub(:save).and_return(false) + post :create, {:build => {}}, valid_session + assigns(:build).should be_a_new(Build) + end + + it "re-renders the 'new' template" do + # Trigger the behavior that occurs when invalid params are submitted + Build.any_instance.stub(:save).and_return(false) + post :create, {:build => {}}, valid_session + response.should render_template("new") + end + end + end + + describe "PUT update" do + describe "with valid params" do + it "updates the requested build" do + build = Build.create! valid_attributes + # Assuming there are no other builds in the database, this + # specifies that the Build created on the previous line + # receives the :update_attributes message with whatever params are + # submitted in the request. + Build.any_instance.should_receive(:update_attributes).with({'these' => 'params'}) + put :update, {:id => build.to_param, :build => {'these' => 'params'}}, valid_session + end + + it "assigns the requested build as @build" do + build = Build.create! valid_attributes + put :update, {:id => build.to_param, :build => valid_attributes}, valid_session + assigns(:build).should eq(build) + end + + it "redirects to the build" do + build = Build.create! valid_attributes + put :update, {:id => build.to_param, :build => valid_attributes}, valid_session + response.should redirect_to(build) + end + end + + describe "with invalid params" do + it "assigns the build as @build" do + build = Build.create! valid_attributes + # Trigger the behavior that occurs when invalid params are submitted + Build.any_instance.stub(:save).and_return(false) + put :update, {:id => build.to_param, :build => {}}, valid_session + assigns(:build).should eq(build) + end + + it "re-renders the 'edit' template" do + build = Build.create! valid_attributes + # Trigger the behavior that occurs when invalid params are submitted + Build.any_instance.stub(:save).and_return(false) + put :update, {:id => build.to_param, :build => {}}, valid_session + response.should render_template("edit") + end + end + end + + describe "DELETE destroy" do + it "destroys the requested build" do + build = Build.create! valid_attributes + expect { + delete :destroy, {:id => build.to_param}, valid_session + }.to change(Build, :count).by(-1) + end + + it "redirects to the builds list" do + build = Build.create! valid_attributes + delete :destroy, {:id => build.to_param}, valid_session + response.should redirect_to(builds_url) + end + end + +end diff --git a/spec/helpers/builds_helper_spec.rb b/spec/helpers/builds_helper_spec.rb new file mode 100644 index 0000000..cc13b20 --- /dev/null +++ b/spec/helpers/builds_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the BuildsHelper. For example: +# +# describe BuildsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe BuildsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/builds_spec.rb b/spec/requests/builds_spec.rb new file mode 100644 index 0000000..98b2113 --- /dev/null +++ b/spec/requests/builds_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe "Builds" do + describe "GET /builds" do + it "works! (now write some real specs)" do + # Run the generator again with the --webrat flag if you want to use webrat methods/matchers + get builds_path + response.status.should be(200) + end + end +end diff --git a/spec/routing/builds_routing_spec.rb b/spec/routing/builds_routing_spec.rb new file mode 100644 index 0000000..38b5b17 --- /dev/null +++ b/spec/routing/builds_routing_spec.rb @@ -0,0 +1,35 @@ +require "spec_helper" + +describe BuildsController do + describe "routing" do + + it "routes to #index" do + get("/builds").should route_to("builds#index") + end + + it "routes to #new" do + get("/builds/new").should route_to("builds#new") + end + + it "routes to #show" do + get("/builds/1").should route_to("builds#show", :id => "1") + end + + it "routes to #edit" do + get("/builds/1/edit").should route_to("builds#edit", :id => "1") + end + + it "routes to #create" do + post("/builds").should route_to("builds#create") + end + + it "routes to #update" do + put("/builds/1").should route_to("builds#update", :id => "1") + end + + it "routes to #destroy" do + delete("/builds/1").should route_to("builds#destroy", :id => "1") + end + + end +end diff --git a/spec/views/builds/edit.html.haml_spec.rb b/spec/views/builds/edit.html.haml_spec.rb new file mode 100644 index 0000000..9be0eb5 --- /dev/null +++ b/spec/views/builds/edit.html.haml_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe "builds/edit" do + before(:each) do + @build = assign(:build, stub_model(Build, + :trace => "MyText", + :status => "MyString" + )) + end + + it "renders the edit build form" do + render + + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "form", :action => builds_path(@build), :method => "post" do + assert_select "textarea#build_trace", :name => "build[trace]" + assert_select "input#build_status", :name => "build[status]" + end + end +end diff --git a/spec/views/builds/index.html.haml_spec.rb b/spec/views/builds/index.html.haml_spec.rb new file mode 100644 index 0000000..0ade772 --- /dev/null +++ b/spec/views/builds/index.html.haml_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe "builds/index" do + before(:each) do + assign(:builds, [ + stub_model(Build, + :trace => "MyText", + :status => "Status" + ), + stub_model(Build, + :trace => "MyText", + :status => "Status" + ) + ]) + end + + it "renders a list of builds" do + render + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "tr>td", :text => "MyText".to_s, :count => 2 + assert_select "tr>td", :text => "Status".to_s, :count => 2 + end +end diff --git a/spec/views/builds/new.html.haml_spec.rb b/spec/views/builds/new.html.haml_spec.rb new file mode 100644 index 0000000..e54b4df --- /dev/null +++ b/spec/views/builds/new.html.haml_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe "builds/new" do + before(:each) do + assign(:build, stub_model(Build, + :trace => "MyText", + :status => "MyString" + ).as_new_record) + end + + it "renders new build form" do + render + + # Run the generator again with the --webrat flag if you want to use webrat matchers + assert_select "form", :action => builds_path, :method => "post" do + assert_select "textarea#build_trace", :name => "build[trace]" + assert_select "input#build_status", :name => "build[status]" + end + end +end diff --git a/spec/views/builds/show.html.haml_spec.rb b/spec/views/builds/show.html.haml_spec.rb new file mode 100644 index 0000000..560d282 --- /dev/null +++ b/spec/views/builds/show.html.haml_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe "builds/show" do + before(:each) do + @build = assign(:build, stub_model(Build, + :trace => "MyText", + :status => "Status" + )) + end + + it "renders attributes in <p>" do + render + # Run the generator again with the --webrat flag if you want to use webrat matchers + rendered.should match(/MyText/) + rendered.should match(/Status/) + end +end |