sr-integrity 0.1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +73 -0
- data/Rakefile +91 -0
- data/VERSION.yml +4 -0
- data/bin/integrity +4 -0
- data/config/config.sample.ru +21 -0
- data/config/config.sample.yml +41 -0
- data/config/thin.sample.yml +13 -0
- data/integrity.gemspec +55 -0
- data/lib/integrity/app.rb +137 -0
- data/lib/integrity/author.rb +39 -0
- data/lib/integrity/build.rb +84 -0
- data/lib/integrity/commit.rb +71 -0
- data/lib/integrity/core_ext/object.rb +6 -0
- data/lib/integrity/helpers/authorization.rb +33 -0
- data/lib/integrity/helpers/breadcrumbs.rb +20 -0
- data/lib/integrity/helpers/forms.rb +28 -0
- data/lib/integrity/helpers/pretty_output.rb +45 -0
- data/lib/integrity/helpers/rendering.rb +14 -0
- data/lib/integrity/helpers/resources.rb +13 -0
- data/lib/integrity/helpers/urls.rb +49 -0
- data/lib/integrity/helpers.rb +16 -0
- data/lib/integrity/installer.rb +121 -0
- data/lib/integrity/migrations.rb +140 -0
- data/lib/integrity/notifier/base.rb +65 -0
- data/lib/integrity/notifier.rb +50 -0
- data/lib/integrity/project.rb +142 -0
- data/lib/integrity/project_builder.rb +56 -0
- data/lib/integrity/scm/git/uri.rb +57 -0
- data/lib/integrity/scm/git.rb +84 -0
- data/lib/integrity/scm.rb +19 -0
- data/lib/integrity.rb +80 -0
- data/public/buttons.css +82 -0
- data/public/reset.css +7 -0
- data/public/spinner.gif +0 -0
- data/test/helpers/acceptance/git_helper.rb +99 -0
- data/test/helpers/acceptance/textfile_notifier.rb +26 -0
- data/test/helpers/acceptance.rb +80 -0
- data/test/helpers/expectations/be_a.rb +23 -0
- data/test/helpers/expectations/change.rb +90 -0
- data/test/helpers/expectations/have.rb +105 -0
- data/test/helpers/expectations/have_tag.rb +128 -0
- data/test/helpers/expectations/predicates.rb +37 -0
- data/test/helpers/expectations.rb +5 -0
- data/test/helpers/fixtures.rb +107 -0
- data/test/helpers/initial_migration_fixture.sql +44 -0
- data/test/helpers.rb +70 -0
- data/views/_commit_info.haml +24 -0
- data/views/build.haml +2 -0
- data/views/error.haml +37 -0
- data/views/home.haml +21 -0
- data/views/integrity.sass +400 -0
- data/views/layout.haml +28 -0
- data/views/new.haml +51 -0
- data/views/not_found.haml +31 -0
- data/views/notifier.haml +7 -0
- data/views/project.builder +21 -0
- data/views/project.haml +30 -0
- data/views/unauthorized.haml +38 -0
- metadata +190 -0
data/README.markdown
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Integrity
|
2
|
+
=========
|
3
|
+
|
4
|
+
[Integrity][website] is your friendly automated Continuous Integration server.
|
5
|
+
|
6
|
+
* See our [website][] for documentation and a [live demo][demo]
|
7
|
+
* Report bugs and submit features request on our [Lighthouse account][lighthouse]
|
8
|
+
* Join us on [#integrity][irc-channel] for ideas, help, patches or something
|
9
|
+
* Get the code on [GitHub][repo]
|
10
|
+
|
11
|
+
Try it!
|
12
|
+
-------
|
13
|
+
|
14
|
+
$ git clone git://github.com/foca/integrity.git
|
15
|
+
$ rake launch
|
16
|
+
# Navigate to <http://0.0.0.0:4567>
|
17
|
+
|
18
|
+
Thanks
|
19
|
+
------
|
20
|
+
|
21
|
+
Thanks to the fellowing people for their feedbacks, ideas and patches :
|
22
|
+
|
23
|
+
* [James Adam][james]
|
24
|
+
* [Elliott Cable][ec]
|
25
|
+
* [Corey Donohoe][atmos]
|
26
|
+
* [Kyle Hargraves][kyle]
|
27
|
+
* [Pier-Hugues Pellerin][ph]
|
28
|
+
* [Simon Rozet][sr]
|
29
|
+
* [Scott Taylor][scott]
|
30
|
+
|
31
|
+
License
|
32
|
+
-------
|
33
|
+
|
34
|
+
(The MIT License)
|
35
|
+
|
36
|
+
Copyright (c) 2008 [Nicolás Sanguinetti][foca], [entp][]
|
37
|
+
|
38
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
39
|
+
a copy of this software and associated documentation files (the
|
40
|
+
'Software'), to deal in the Software without restriction, including
|
41
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
42
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
43
|
+
permit persons to whom the Software is furnished to do so, subject to
|
44
|
+
the following conditions:
|
45
|
+
|
46
|
+
The above copyright notice and this permission notice shall be
|
47
|
+
included in all copies or substantial portions of the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
52
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
53
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
54
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
55
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
56
|
+
|
57
|
+
[website]: http://integrityapp.com
|
58
|
+
[demo]: http://builder.integrityapp.com
|
59
|
+
[repo]: http://github.com/foca/integrity
|
60
|
+
[lighthouse]: http://integrity.lighthouseapp.com/projects/14308-integrity
|
61
|
+
[irc-channel]: irc://irc.freenode.net/integrity
|
62
|
+
|
63
|
+
[foca]: http://nicolassanguinetti.info/
|
64
|
+
[entp]: http://entp.com
|
65
|
+
|
66
|
+
[james]: http://github.com/lazyatom
|
67
|
+
[ec]: http://github.com/elliotcabble
|
68
|
+
[atmos]: http://github.com/atmos
|
69
|
+
[kyle]: http://github.com/pd
|
70
|
+
[ph]: http://github.com/ph
|
71
|
+
[sr]: http://purl.org/net/sr/
|
72
|
+
[scott]: http://github.com/smtlaissezfaire
|
73
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/lib/integrity"
|
2
|
+
require "rake/testtask"
|
3
|
+
require "rcov/rcovtask"
|
4
|
+
|
5
|
+
desc "Run all tests and check test coverage"
|
6
|
+
task :default => "test:coverage:verify"
|
7
|
+
|
8
|
+
desc "Run tests"
|
9
|
+
task :test => %w(test:units test:acceptance)
|
10
|
+
|
11
|
+
namespace :test do
|
12
|
+
Rake::TestTask.new(:units) do |t|
|
13
|
+
t.test_files = FileList["test/unit/*_test.rb"]
|
14
|
+
end
|
15
|
+
|
16
|
+
Rake::TestTask.new(:acceptance) do |t|
|
17
|
+
t.test_files = FileList["test/acceptance/*_test.rb"]
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Measure test coverage"
|
21
|
+
task :coverage => %w(test:coverage:units test:coverage:acceptance)
|
22
|
+
|
23
|
+
namespace :coverage do
|
24
|
+
desc "Measure test coverage of unit tests"
|
25
|
+
Rcov::RcovTask.new(:units) do |rcov|
|
26
|
+
rcov.pattern = "test/unit/*_test.rb"
|
27
|
+
rcov.rcov_opts = %w(--html --aggregate .aggregated_coverage_report)
|
28
|
+
rcov.rcov_opts << ENV["RCOV_OPTS"] if ENV["RCOV_OPTS"]
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Measure test coverage of acceptance tests"
|
32
|
+
Rcov::RcovTask.new(:acceptance) do |rcov|
|
33
|
+
rcov.pattern = "test/acceptance/*_test.rb"
|
34
|
+
rcov.rcov_opts = %w(--html --aggregate .aggregated_coverage_report)
|
35
|
+
rcov.rcov_opts << ENV["RCOV_OPTS"] if ENV["RCOV_OPTS"]
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Verify test coverage"
|
39
|
+
task :verify => "test:coverage" do
|
40
|
+
File.read("coverage/index.html") =~ /<tt class='coverage_total'>\s*(\d+\.\d+)%\s*<\/tt>/
|
41
|
+
coverage = $1.to_f
|
42
|
+
|
43
|
+
puts
|
44
|
+
if coverage == 100
|
45
|
+
puts "\e[32m100% coverage! Awesome!\e[0m"
|
46
|
+
else
|
47
|
+
puts "\e[31mOnly #{coverage}% code coverage. You can do better ;)\e[0m"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Install all gems on which the tests depend on"
|
53
|
+
task :install_dependencies do
|
54
|
+
system 'gem install redgreen rr mocha ruby-debug dm-sweatshop webrat ZenTest'
|
55
|
+
system 'gem install -s http://gems.github.com jeremymcanally-context jeremymcanally-matchy jeremymcanally-pending foca-storyteller'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "Launch Integrity real quick"
|
60
|
+
task :launch do
|
61
|
+
ruby "bin/integrity launch"
|
62
|
+
end
|
63
|
+
|
64
|
+
begin
|
65
|
+
require "jeweler"
|
66
|
+
|
67
|
+
Jeweler::Tasks.new do |s|
|
68
|
+
files = `git ls-files`.split("\n").reject {|f| f =~ %r(^test/acceptance) || f =~ %r(^test/unit) || f =~ /^\.git/ }
|
69
|
+
|
70
|
+
s.name = 'integrity'
|
71
|
+
s.summary = 'The easy and fun Continuous Integration server'
|
72
|
+
s.description = 'Your Friendly Continuous Integration server. Easy, fun and painless!'
|
73
|
+
s.homepage = 'http://integrityapp.com'
|
74
|
+
s.rubyforge_project = 'integrity'
|
75
|
+
s.email = 'contacto@nicolassanguinetti.info'
|
76
|
+
s.authors = ['Nicolás Sanguinetti', 'Simon Rozet']
|
77
|
+
s.files = files
|
78
|
+
s.executables = ['integrity']
|
79
|
+
s.post_install_message = 'Run `integrity help` for information on how to setup Integrity.'
|
80
|
+
|
81
|
+
s.add_dependency 'sinatra', ['~> 0.9.0.4']
|
82
|
+
s.add_dependency 'haml', ['~> 2.0.0']
|
83
|
+
s.add_dependency 'data_mapper', ['~> 0.9.10']
|
84
|
+
s.add_dependency 'uuidtools' # required by dm-types
|
85
|
+
s.add_dependency 'bcrypt-ruby' # required by dm-types
|
86
|
+
s.add_dependency 'json'
|
87
|
+
s.add_dependency 'sinatra-ditties', ['~> 0.0.2']
|
88
|
+
s.add_dependency 'thor'
|
89
|
+
end
|
90
|
+
rescue LoadError
|
91
|
+
end
|
data/VERSION.yml
ADDED
data/bin/integrity
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "rubygems"
|
3
|
+
require "integrity"
|
4
|
+
|
5
|
+
# If you want to add any notifiers, install the gems and then require them here
|
6
|
+
# For example, to enable the Email notifier: install the gem (from github:
|
7
|
+
#
|
8
|
+
# sudo gem install -s http://gems.github.com foca-integrity-email
|
9
|
+
#
|
10
|
+
# And then uncomment the following line:
|
11
|
+
#
|
12
|
+
# require "notifier/email"
|
13
|
+
|
14
|
+
# Load configuration and initialize Integrity
|
15
|
+
Integrity.new(File.dirname(__FILE__) + "/config.yml")
|
16
|
+
|
17
|
+
# You probably don't want to edit anything below
|
18
|
+
Integrity::App.set :environment, ENV["RACK_ENV"] || :production
|
19
|
+
Integrity::App.set :port, 8910
|
20
|
+
|
21
|
+
run Integrity::App
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Domain where integrity will be running from. This is used to have
|
2
|
+
# nice URLs in your notifications.
|
3
|
+
# For example:
|
4
|
+
# http://builder.integrityapp.com
|
5
|
+
:base_uri: http://integrity.domain.tld
|
6
|
+
|
7
|
+
# This should be a complete connection string to your database.
|
8
|
+
#
|
9
|
+
# Examples:
|
10
|
+
# * `mysql://user:password@localhost/integrity`
|
11
|
+
# * `postgres://user:password@localhost/integrity`
|
12
|
+
# * `sqlite3:///home/integrity/db/integrity.sqlite`
|
13
|
+
#
|
14
|
+
# Note:
|
15
|
+
# * The appropriate data_objects adapter must be installed (`do_mysql`, etc)
|
16
|
+
# * You must create the `integrity` database on localhost, of course.
|
17
|
+
:database_uri: sqlite3:///var/integrity.db
|
18
|
+
|
19
|
+
# This is where your project's code will be checked out to. Make sure it's
|
20
|
+
# writable by the user that runs Integrity.
|
21
|
+
:export_directory: /path/to/scm/exports
|
22
|
+
|
23
|
+
# Path to the integrity log file
|
24
|
+
:log: /var/log/integrity.log
|
25
|
+
|
26
|
+
# Enable or disable HTTP authentication for the app. BE AWARE that if you
|
27
|
+
# disable this anyone can delete and alter projects, so do it only if your
|
28
|
+
# app is running in a controlled environment (ie, behind your company's
|
29
|
+
# firewall.)
|
30
|
+
:use_basic_auth: false
|
31
|
+
|
32
|
+
# When `use_basic_auth` is true, the admin's username for HTTP authentication.
|
33
|
+
:admin_username: username
|
34
|
+
|
35
|
+
# When `use_basic_auth` is true, the admin's password. Usually saved as a
|
36
|
+
# SHA1 hash. See the next option.
|
37
|
+
:admin_password: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
|
38
|
+
|
39
|
+
# If this is true, then whenever we authenticate the admin user, will hash
|
40
|
+
# it using SHA1. If not, we'll assume the provided password is in plain text.
|
41
|
+
:hash_admin_password: true
|
@@ -0,0 +1,13 @@
|
|
1
|
+
---
|
2
|
+
environment: production
|
3
|
+
chdir: /apps/integrity
|
4
|
+
address: 127.0.0.1
|
5
|
+
port: 8910
|
6
|
+
pid: /apps/integrity/thin.pid
|
7
|
+
rackup: /apps/integrity/config.ru
|
8
|
+
log: /apps/integrity/log/thin.log
|
9
|
+
max_conns: 1024
|
10
|
+
timeout: 30
|
11
|
+
max_persistent_conns: 512
|
12
|
+
daemonize: true
|
13
|
+
servers: 2
|
data/integrity.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{integrity}
|
5
|
+
s.version = "0.1.8.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Nicol\303\241s Sanguinetti", "Simon Rozet"]
|
9
|
+
s.date = %q{2009-02-23}
|
10
|
+
s.default_executable = %q{integrity}
|
11
|
+
s.description = %q{Your Friendly Continuous Integration server. Easy, fun and painless!}
|
12
|
+
s.email = %q{contacto@nicolassanguinetti.info}
|
13
|
+
s.executables = ["integrity"]
|
14
|
+
s.files = ["README.markdown", "Rakefile", "VERSION.yml", "bin/integrity", "config/config.sample.ru", "config/config.sample.yml", "config/thin.sample.yml", "integrity.gemspec", "lib/integrity.rb", "lib/integrity/app.rb", "lib/integrity/author.rb", "lib/integrity/build.rb", "lib/integrity/commit.rb", "lib/integrity/core_ext/object.rb", "lib/integrity/helpers.rb", "lib/integrity/helpers/authorization.rb", "lib/integrity/helpers/breadcrumbs.rb", "lib/integrity/helpers/forms.rb", "lib/integrity/helpers/pretty_output.rb", "lib/integrity/helpers/rendering.rb", "lib/integrity/helpers/resources.rb", "lib/integrity/helpers/urls.rb", "lib/integrity/installer.rb", "lib/integrity/migrations.rb", "lib/integrity/notifier.rb", "lib/integrity/notifier/base.rb", "lib/integrity/project.rb", "lib/integrity/project_builder.rb", "lib/integrity/scm.rb", "lib/integrity/scm/git.rb", "lib/integrity/scm/git/uri.rb", "public/buttons.css", "public/reset.css", "public/spinner.gif", "test/helpers.rb", "test/helpers/acceptance.rb", "test/helpers/acceptance/git_helper.rb", "test/helpers/acceptance/textfile_notifier.rb", "test/helpers/expectations.rb", "test/helpers/expectations/be_a.rb", "test/helpers/expectations/change.rb", "test/helpers/expectations/have.rb", "test/helpers/expectations/have_tag.rb", "test/helpers/expectations/predicates.rb", "test/helpers/fixtures.rb", "test/helpers/initial_migration_fixture.sql", "views/_commit_info.haml", "views/build.haml", "views/error.haml", "views/home.haml", "views/integrity.sass", "views/layout.haml", "views/new.haml", "views/not_found.haml", "views/notifier.haml", "views/project.builder", "views/project.haml", "views/unauthorized.haml"]
|
15
|
+
s.homepage = %q{http://integrityapp.com}
|
16
|
+
s.post_install_message = %q{Run `integrity help` for information on how to setup Integrity.}
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{integrity}
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{The easy and fun Continuous Integration server}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<sinatra>, ["~> 0.9.0.4"])
|
28
|
+
s.add_runtime_dependency(%q<haml>, ["~> 2.0.0"])
|
29
|
+
s.add_runtime_dependency(%q<data_mapper>, ["~> 0.9.10"])
|
30
|
+
s.add_runtime_dependency(%q<uuidtools>, [">= 0"])
|
31
|
+
s.add_runtime_dependency(%q<bcrypt-ruby>, [">= 0"])
|
32
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
33
|
+
s.add_runtime_dependency(%q<sinatra-ditties>, ["~> 0.0.2"])
|
34
|
+
s.add_runtime_dependency(%q<thor>, [">= 0"])
|
35
|
+
else
|
36
|
+
s.add_dependency(%q<sinatra>, ["~> 0.9.0.4"])
|
37
|
+
s.add_dependency(%q<haml>, ["~> 2.0.0"])
|
38
|
+
s.add_dependency(%q<data_mapper>, ["~> 0.9.10"])
|
39
|
+
s.add_dependency(%q<uuidtools>, [">= 0"])
|
40
|
+
s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
|
41
|
+
s.add_dependency(%q<json>, [">= 0"])
|
42
|
+
s.add_dependency(%q<sinatra-ditties>, ["~> 0.0.2"])
|
43
|
+
s.add_dependency(%q<thor>, [">= 0"])
|
44
|
+
end
|
45
|
+
else
|
46
|
+
s.add_dependency(%q<sinatra>, ["~> 0.9.0.4"])
|
47
|
+
s.add_dependency(%q<haml>, ["~> 2.0.0"])
|
48
|
+
s.add_dependency(%q<data_mapper>, ["~> 0.9.10"])
|
49
|
+
s.add_dependency(%q<uuidtools>, [">= 0"])
|
50
|
+
s.add_dependency(%q<bcrypt-ruby>, [">= 0"])
|
51
|
+
s.add_dependency(%q<json>, [">= 0"])
|
52
|
+
s.add_dependency(%q<sinatra-ditties>, ["~> 0.0.2"])
|
53
|
+
s.add_dependency(%q<thor>, [">= 0"])
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Integrity
|
2
|
+
class App < Sinatra::Default
|
3
|
+
set :root, File.dirname(__FILE__) + "/../.."
|
4
|
+
set :app_file, __FILE__
|
5
|
+
enable :sessions
|
6
|
+
|
7
|
+
include Integrity
|
8
|
+
include Integrity::Helpers
|
9
|
+
|
10
|
+
not_found do
|
11
|
+
status 404
|
12
|
+
show :not_found, :title => "lost, are we?"
|
13
|
+
end
|
14
|
+
|
15
|
+
error do
|
16
|
+
@error = request.env['sinatra.error']
|
17
|
+
status 500
|
18
|
+
show :error, :title => "something has gone terribly wrong"
|
19
|
+
end
|
20
|
+
|
21
|
+
before do
|
22
|
+
# The browser only sends http auth data for requests that are explicitly
|
23
|
+
# required to do so. This way we get the real values of +#logged_in?+ and
|
24
|
+
# +#current_user+
|
25
|
+
login_required if session[:user]
|
26
|
+
end
|
27
|
+
|
28
|
+
get "/" do
|
29
|
+
@projects = Project.only_public_unless(authorized?)
|
30
|
+
show :home, :title => "projects"
|
31
|
+
end
|
32
|
+
|
33
|
+
get "/login" do
|
34
|
+
login_required
|
35
|
+
|
36
|
+
session[:user] = current_user
|
37
|
+
redirect root_url
|
38
|
+
end
|
39
|
+
|
40
|
+
get "/new" do
|
41
|
+
login_required
|
42
|
+
|
43
|
+
@project = Project.new
|
44
|
+
show :new, :title => ["projects", "new project"]
|
45
|
+
end
|
46
|
+
|
47
|
+
post "/" do
|
48
|
+
login_required
|
49
|
+
|
50
|
+
@project = Project.new(params[:project_data])
|
51
|
+
|
52
|
+
if @project.save
|
53
|
+
@project.enable_notifiers(params["enabled_notifiers[]"], params["notifiers"])
|
54
|
+
redirect project_url(@project)
|
55
|
+
else
|
56
|
+
show :new, :title => ["projects", "new project"]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
get "/:project" do
|
61
|
+
login_required unless current_project.public?
|
62
|
+
show :project, :title => ["projects", current_project.name]
|
63
|
+
end
|
64
|
+
|
65
|
+
get "/:project.atom" do
|
66
|
+
login_required unless current_project.public?
|
67
|
+
response["Content-Type"] = "application/rss+xml; charset=utf-8"
|
68
|
+
builder :project
|
69
|
+
end
|
70
|
+
|
71
|
+
put "/:project" do
|
72
|
+
login_required
|
73
|
+
|
74
|
+
if current_project.update_attributes(params[:project_data])
|
75
|
+
current_project.enable_notifiers(params["enabled_notifiers"], params["notifiers"])
|
76
|
+
redirect project_url(current_project)
|
77
|
+
else
|
78
|
+
show :new, :title => ["projects", current_project.permalink, "edit"]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
delete "/:project" do
|
83
|
+
login_required
|
84
|
+
|
85
|
+
current_project.destroy
|
86
|
+
redirect root_url
|
87
|
+
end
|
88
|
+
|
89
|
+
get "/:project/edit" do
|
90
|
+
login_required
|
91
|
+
|
92
|
+
show :new, :title => ["projects", current_project.permalink, "edit"]
|
93
|
+
end
|
94
|
+
|
95
|
+
post "/:project/push" do
|
96
|
+
login_required
|
97
|
+
|
98
|
+
content_type "text/plain"
|
99
|
+
|
100
|
+
begin
|
101
|
+
current_project.push(params[:payload])
|
102
|
+
"Thanks, build started."
|
103
|
+
rescue JSON::ParserError => exception
|
104
|
+
throw :halt, [422, exception.to_s]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
post "/:project/builds" do
|
109
|
+
login_required
|
110
|
+
|
111
|
+
current_project.build
|
112
|
+
redirect project_url(current_project)
|
113
|
+
end
|
114
|
+
|
115
|
+
get "/:project/commits/:commit" do
|
116
|
+
login_required unless current_project.public?
|
117
|
+
|
118
|
+
show :build, :title => ["projects", current_project.permalink, current_commit.short_commit_identifier]
|
119
|
+
end
|
120
|
+
|
121
|
+
get "/:project/builds/:commit" do
|
122
|
+
redirect "/#{params[:project]}/commits/#{params[:commit]}", 301
|
123
|
+
end
|
124
|
+
|
125
|
+
post "/:project/commits/:commit/builds" do
|
126
|
+
login_required
|
127
|
+
|
128
|
+
current_project.build(params[:commit])
|
129
|
+
redirect commit_url(current_commit)
|
130
|
+
end
|
131
|
+
|
132
|
+
get "/integrity.css" do
|
133
|
+
response["Content-Type"] = "text/css; charset=utf-8"
|
134
|
+
sass :integrity
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Integrity
|
2
|
+
class Author < DataMapper::Type
|
3
|
+
primitive String
|
4
|
+
size 65535
|
5
|
+
lazy true
|
6
|
+
|
7
|
+
class AuthorStruct < Struct.new(:name, :email)
|
8
|
+
def self.parse(string)
|
9
|
+
raise ArgumentError.new("invalid author string") unless string =~ /^(.*) <(.*)>$/
|
10
|
+
|
11
|
+
new($1.strip, $2.strip)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@full ||= "#{name} <#{email}>"
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :full, :to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.load(value, property)
|
22
|
+
AuthorStruct.parse(value) unless value.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.dump(value, property)
|
26
|
+
return nil if value.nil?
|
27
|
+
|
28
|
+
value.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.typecast(value, property)
|
32
|
+
case value
|
33
|
+
when AuthorStruct then value
|
34
|
+
when NilClass then load(nil, property)
|
35
|
+
else load(value.to_s, property)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Integrity
|
2
|
+
class Build
|
3
|
+
include DataMapper::Resource
|
4
|
+
|
5
|
+
property :id, Integer, :serial => true
|
6
|
+
property :output, Text, :default => "", :lazy => false
|
7
|
+
property :successful, Boolean, :default => false
|
8
|
+
property :commit_id, Integer, :nullable => false
|
9
|
+
property :created_at, DateTime
|
10
|
+
property :updated_at, DateTime
|
11
|
+
property :started_at, DateTime
|
12
|
+
property :completed_at, DateTime
|
13
|
+
|
14
|
+
belongs_to :commit, :class_name => "Integrity::Commit"
|
15
|
+
|
16
|
+
def self.pending
|
17
|
+
all(:started_at => nil)
|
18
|
+
end
|
19
|
+
|
20
|
+
def pending?
|
21
|
+
started_at.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def failed?
|
25
|
+
!successful?
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
case
|
30
|
+
when pending? then :pending
|
31
|
+
when successful? then :success
|
32
|
+
when failed? then :failed
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def start!(time=Time.now)
|
37
|
+
self.started_at = time
|
38
|
+
end
|
39
|
+
|
40
|
+
def complete!(time=Time.now)
|
41
|
+
self.completed_at = time
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Deprecated methods
|
46
|
+
#
|
47
|
+
def short_commit_identifier
|
48
|
+
warn "Build#short_commit_identifier is deprecated, use Commit#short_identifier"
|
49
|
+
commit.short_identifier
|
50
|
+
end
|
51
|
+
|
52
|
+
def commit_identifier
|
53
|
+
warn "Build#commit_identifier is deprecated, use Commit#identifier"
|
54
|
+
commit.identifier
|
55
|
+
end
|
56
|
+
|
57
|
+
def commit_author
|
58
|
+
warn "Build#commit_author is deprecated, use Commit#author"
|
59
|
+
commit.author
|
60
|
+
end
|
61
|
+
|
62
|
+
def commit_message
|
63
|
+
warn "Build#commit_message is deprecated, use Commit#message"
|
64
|
+
commit.message
|
65
|
+
end
|
66
|
+
|
67
|
+
def commited_at
|
68
|
+
warn "Build#commited_at is deprecated, use Commit#committed_at"
|
69
|
+
commit.committed_at
|
70
|
+
end
|
71
|
+
|
72
|
+
def project_id
|
73
|
+
warn "Build#project_id is deprecated, use Commit#project_id"
|
74
|
+
commit.project_id
|
75
|
+
end
|
76
|
+
|
77
|
+
def commit_metadata
|
78
|
+
warn "Build#commit_metadata is deprecated, use the different methods in Commit instead"
|
79
|
+
{ :message => commit.message,
|
80
|
+
:author => commit.author,
|
81
|
+
:date => commit.committed_at }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Integrity
|
2
|
+
class Commit
|
3
|
+
include DataMapper::Resource
|
4
|
+
|
5
|
+
property :id, Integer, :serial => true
|
6
|
+
property :identifier, String, :nullable => false
|
7
|
+
property :message, String, :length => 255
|
8
|
+
property :author, Author, :length => 255
|
9
|
+
property :committed_at, DateTime
|
10
|
+
property :created_at, DateTime
|
11
|
+
property :updated_at, DateTime
|
12
|
+
|
13
|
+
has 1, :build, :class_name => "Integrity::Build", :order => [:created_at.desc]
|
14
|
+
belongs_to :project, :class_name => "Integrity::Project"
|
15
|
+
|
16
|
+
def message
|
17
|
+
attribute_get(:message) || "<Commit message not loaded>"
|
18
|
+
end
|
19
|
+
|
20
|
+
def author
|
21
|
+
attribute_get(:author) || Author.load('<Commit author not loaded> <<Commit author not loaded>>', :author)
|
22
|
+
end
|
23
|
+
|
24
|
+
def short_identifier
|
25
|
+
identifier.to_s[0..6]
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
build.nil? ? :pending : build.status
|
30
|
+
end
|
31
|
+
|
32
|
+
def successful?
|
33
|
+
status == :success
|
34
|
+
end
|
35
|
+
|
36
|
+
def failed?
|
37
|
+
status == :failed
|
38
|
+
end
|
39
|
+
|
40
|
+
def pending?
|
41
|
+
status == :pending
|
42
|
+
end
|
43
|
+
|
44
|
+
def human_readable_status
|
45
|
+
case status
|
46
|
+
when :success; "Built #{short_identifier} successfully"
|
47
|
+
when :failed; "Built #{short_identifier} and failed"
|
48
|
+
when :pending; "#{short_identifier} hasn't been built yet"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def output
|
53
|
+
build && build.output
|
54
|
+
end
|
55
|
+
|
56
|
+
def queue_build
|
57
|
+
self.build = Build.create(:commit_id => id)
|
58
|
+
self.save
|
59
|
+
|
60
|
+
# Build on foreground (this will move away, I promise)
|
61
|
+
ProjectBuilder.new(project).build(self)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Deprecation layer
|
65
|
+
alias :short_commit_identifier :short_identifier
|
66
|
+
alias :commit_identifier :identifier
|
67
|
+
alias :commit_author :author
|
68
|
+
alias :commit_message :message
|
69
|
+
alias :commited_at :committed_at
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "sinatra/ditties"
|
2
|
+
|
3
|
+
module Integrity
|
4
|
+
module Helpers
|
5
|
+
module Authorization
|
6
|
+
include Sinatra::Authorization
|
7
|
+
|
8
|
+
def authorization_realm
|
9
|
+
"Integrity"
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorized?
|
13
|
+
return true unless Integrity.config[:use_basic_auth]
|
14
|
+
!!request.env["REMOTE_USER"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def authorize(user, password)
|
18
|
+
if Integrity.config[:hash_admin_password]
|
19
|
+
password = Digest::SHA1.hexdigest(password)
|
20
|
+
end
|
21
|
+
|
22
|
+
!Integrity.config[:use_basic_auth] ||
|
23
|
+
(Integrity.config[:admin_username] == user &&
|
24
|
+
Integrity.config[:admin_password] == password)
|
25
|
+
end
|
26
|
+
|
27
|
+
def unauthorized!(realm=authorization_realm)
|
28
|
+
response["WWW-Authenticate"] = %(Basic realm="#{realm}")
|
29
|
+
throw :halt, [401, show(:unauthorized, :title => "incorrect credentials")]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|