foca-integrity 0.1.8 → 0.1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +7 -0
- data/Rakefile +89 -81
- data/config/config.sample.ru +11 -21
- data/config/config.sample.yml +15 -12
- data/lib/integrity.rb +21 -23
- data/lib/integrity/app.rb +138 -0
- data/lib/integrity/author.rb +39 -0
- data/lib/integrity/build.rb +54 -31
- data/lib/integrity/commit.rb +71 -0
- data/lib/integrity/helpers.rb +3 -3
- data/lib/integrity/helpers/authorization.rb +2 -2
- data/lib/integrity/helpers/forms.rb +3 -3
- data/lib/integrity/helpers/pretty_output.rb +1 -1
- data/lib/integrity/helpers/rendering.rb +6 -1
- data/lib/integrity/helpers/resources.rb +9 -3
- data/lib/integrity/helpers/urls.rb +15 -13
- data/lib/integrity/installer.rb +43 -60
- data/lib/integrity/migrations.rb +31 -48
- data/lib/integrity/notifier.rb +14 -16
- data/lib/integrity/notifier/base.rb +29 -19
- data/lib/integrity/notifier/test_helpers.rb +100 -0
- data/lib/integrity/project.rb +69 -33
- data/lib/integrity/project_builder.rb +23 -14
- data/lib/integrity/scm/git.rb +15 -14
- data/lib/integrity/scm/git/uri.rb +9 -9
- data/test/acceptance/api_test.rb +97 -0
- data/test/acceptance/browse_project_builds_test.rb +65 -0
- data/test/acceptance/browse_project_test.rb +95 -0
- data/test/acceptance/build_notifications_test.rb +42 -0
- data/test/acceptance/create_project_test.rb +97 -0
- data/test/acceptance/delete_project_test.rb +53 -0
- data/test/acceptance/edit_project_test.rb +117 -0
- data/test/acceptance/error_page_test.rb +18 -0
- data/test/acceptance/helpers.rb +2 -0
- data/test/acceptance/installer_test.rb +62 -0
- data/test/acceptance/manual_build_project_test.rb +82 -0
- data/test/acceptance/notifier_test.rb +109 -0
- data/test/acceptance/project_syndication_test.rb +30 -0
- data/test/acceptance/stylesheet_test.rb +18 -0
- data/test/helpers.rb +59 -27
- data/test/helpers/acceptance.rb +19 -64
- data/test/helpers/acceptance/email_notifier.rb +55 -0
- data/test/helpers/acceptance/git_helper.rb +15 -15
- data/test/helpers/acceptance/textfile_notifier.rb +3 -3
- data/test/helpers/expectations.rb +0 -1
- data/test/helpers/expectations/be_a.rb +4 -4
- data/test/helpers/expectations/change.rb +5 -5
- data/test/helpers/expectations/have.rb +4 -4
- data/test/helpers/expectations/predicates.rb +4 -4
- data/test/helpers/fixtures.rb +44 -18
- data/test/helpers/initial_migration_fixture.sql +44 -0
- data/test/unit/build_test.rb +51 -0
- data/test/unit/commit_test.rb +83 -0
- data/test/unit/helpers_test.rb +56 -0
- data/test/unit/integrity_test.rb +18 -0
- data/test/unit/migrations_test.rb +56 -0
- data/test/unit/notifier_test.rb +123 -0
- data/test/unit/project_builder_test.rb +108 -0
- data/test/unit/project_test.rb +282 -0
- data/test/unit/scm_test.rb +54 -0
- data/views/_commit_info.haml +24 -0
- data/views/build.haml +2 -2
- data/views/error.haml +4 -3
- data/views/home.haml +3 -5
- data/views/integrity.sass +19 -6
- data/views/new.haml +6 -6
- data/views/project.builder +9 -9
- data/views/project.haml +14 -12
- metadata +98 -116
- data/VERSION.yml +0 -4
- data/app.rb +0 -137
- data/integrity.gemspec +0 -76
- data/lib/integrity/core_ext/string.rb +0 -5
- data/test/helpers/expectations/have_tag.rb +0 -128
- data/views/_build_info.haml +0 -18
@@ -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
|
data/lib/integrity/build.rb
CHANGED
@@ -2,60 +2,83 @@ module Integrity
|
|
2
2
|
class Build
|
3
3
|
include DataMapper::Resource
|
4
4
|
|
5
|
-
property :id,
|
6
|
-
property :output,
|
7
|
-
property :successful,
|
8
|
-
property :
|
9
|
-
property :
|
10
|
-
property :
|
11
|
-
property :
|
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
|
12
13
|
|
13
|
-
belongs_to :
|
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
|
14
23
|
|
15
24
|
def failed?
|
16
25
|
!successful?
|
17
26
|
end
|
18
27
|
|
19
28
|
def status
|
20
|
-
|
29
|
+
case
|
30
|
+
when pending? then :pending
|
31
|
+
when successful? then :success
|
32
|
+
when failed? then :failed
|
33
|
+
end
|
21
34
|
end
|
22
35
|
|
23
|
-
def
|
24
|
-
|
36
|
+
def start!(time=Time.now)
|
37
|
+
self.started_at = time
|
25
38
|
end
|
26
39
|
|
40
|
+
def complete!(time=Time.now)
|
41
|
+
self.completed_at = time
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Deprecated methods
|
46
|
+
#
|
27
47
|
def short_commit_identifier
|
28
|
-
|
48
|
+
warn "Build#short_commit_identifier is deprecated, use Commit#short_identifier"
|
49
|
+
commit.short_identifier
|
29
50
|
end
|
30
|
-
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
else data
|
35
|
-
end
|
51
|
+
|
52
|
+
def commit_identifier
|
53
|
+
warn "Build#commit_identifier is deprecated, use Commit#identifier"
|
54
|
+
commit.identifier
|
36
55
|
end
|
37
56
|
|
38
57
|
def commit_author
|
39
|
-
|
40
|
-
|
41
|
-
OpenStruct.new(:name => $1.strip, :email => $2.strip, :full => commit_metadata[:author])
|
42
|
-
end
|
58
|
+
warn "Build#commit_author is deprecated, use Commit#author"
|
59
|
+
commit.author
|
43
60
|
end
|
44
61
|
|
45
62
|
def commit_message
|
46
|
-
|
63
|
+
warn "Build#commit_message is deprecated, use Commit#message"
|
64
|
+
commit.message
|
47
65
|
end
|
48
66
|
|
49
67
|
def commited_at
|
50
|
-
|
51
|
-
|
52
|
-
else commit_metadata[:date]
|
53
|
-
end
|
68
|
+
warn "Build#commited_at is deprecated, use Commit#committed_at"
|
69
|
+
commit.committed_at
|
54
70
|
end
|
55
71
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
60
83
|
end
|
61
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
|
data/lib/integrity/helpers.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Dir["#{File.dirname(__FILE__)}/helpers/*.rb"].each &method(:require)
|
2
2
|
|
3
3
|
module Integrity
|
4
|
-
module Helpers
|
4
|
+
module Helpers
|
5
5
|
include Authorization
|
6
6
|
include Breadcrumbs
|
7
7
|
include Forms
|
@@ -9,8 +9,8 @@ module Integrity
|
|
9
9
|
include Rendering
|
10
10
|
include Resources
|
11
11
|
include Urls
|
12
|
-
|
12
|
+
|
13
13
|
include Rack::Utils
|
14
14
|
alias :h :escape_html
|
15
15
|
end
|
16
|
-
end
|
16
|
+
end
|
@@ -12,8 +12,8 @@ module Integrity
|
|
12
12
|
|
13
13
|
def checkbox(name, condition, extras={})
|
14
14
|
attrs = { :name => name, :type => "checkbox", :value => "1" }
|
15
|
-
attrs
|
16
|
-
attrs.
|
15
|
+
attrs[:checked] = !!condition
|
16
|
+
attrs.update(extras)
|
17
17
|
end
|
18
18
|
|
19
19
|
def notifier_form(notifier)
|
@@ -25,4 +25,4 @@ module Integrity
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
-
end
|
28
|
+
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module Integrity
|
2
2
|
module Helpers
|
3
3
|
module Rendering
|
4
|
+
def stylesheet_hash
|
5
|
+
@_hash ||= Digest::MD5.file(
|
6
|
+
options.views + "/integrity.sass").tap { |file| file.hexdigest }
|
7
|
+
end
|
8
|
+
|
4
9
|
def show(view, options={})
|
5
10
|
@title = breadcrumbs(*options[:title])
|
6
11
|
haml view
|
@@ -11,4 +16,4 @@ module Integrity
|
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
14
|
-
end
|
19
|
+
end
|
@@ -5,9 +5,15 @@ module Integrity
|
|
5
5
|
@project ||= Project.first(:permalink => params[:project]) or raise Sinatra::NotFound
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
@
|
8
|
+
def current_commit
|
9
|
+
@commit ||= current_project.commits.first(:identifier => params[:commit]) or raise Sinatra::NotFound
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_notifiers_of(project)
|
13
|
+
if params["notifiers"]
|
14
|
+
project.enable_notifiers(params["notifiers"].keys, params["notifiers"])
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
13
|
-
end
|
19
|
+
end
|
@@ -2,15 +2,7 @@ module Integrity
|
|
2
2
|
module Helpers
|
3
3
|
module Urls
|
4
4
|
def url(path)
|
5
|
-
|
6
|
-
|
7
|
-
if request.scheme == "https" && request.port != 443 ||
|
8
|
-
request.scheme == "http" && request.port != 80
|
9
|
-
url << ":#{request.port}"
|
10
|
-
end
|
11
|
-
|
12
|
-
url << "/" unless path.index("/").zero?
|
13
|
-
url << path
|
5
|
+
Addressable::URI.parse(request.url).join(path).to_s
|
14
6
|
end
|
15
7
|
|
16
8
|
def root_url
|
@@ -35,13 +27,23 @@ module Integrity
|
|
35
27
|
end.to_s
|
36
28
|
end
|
37
29
|
|
38
|
-
def
|
39
|
-
|
30
|
+
def commit_path(commit, *path)
|
31
|
+
project_path(commit.project, "commits", commit.identifier, *path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_path(build, *path)
|
35
|
+
warn "#build_path is deprecated, use #commit_path instead"
|
36
|
+
commit_path build.commit, *path
|
37
|
+
end
|
38
|
+
|
39
|
+
def commit_url(commit)
|
40
|
+
url commit_path(commit)
|
40
41
|
end
|
41
42
|
|
42
43
|
def build_url(build)
|
43
|
-
|
44
|
+
warn "#build_url is deprecated, use #commit_url instead"
|
45
|
+
commit_url build.commit
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
47
|
-
end
|
49
|
+
end
|
data/lib/integrity/installer.rb
CHANGED
@@ -6,63 +6,73 @@ module Integrity
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
desc "install [PATH]",
|
9
|
-
"Copy template files to PATH
|
9
|
+
"Copy template files to PATH for desired deployement strategy
|
10
|
+
(either Thin or Passenger). Next, go there and edit them."
|
11
|
+
method_options :passenger => false, :thin => false
|
10
12
|
def install(path)
|
11
|
-
@root =
|
13
|
+
@root = Pathname(path).expand_path
|
12
14
|
|
13
15
|
create_dir_structure
|
14
16
|
copy_template_files
|
15
17
|
edit_template_files
|
16
|
-
|
18
|
+
migrate_db(root.join("config.yml"))
|
17
19
|
after_setup_message
|
18
20
|
end
|
19
21
|
|
20
|
-
desc "
|
21
|
-
"Checks the `database_uri` in CONFIG and
|
22
|
-
|
22
|
+
desc "migrate_db [CONFIG]",
|
23
|
+
"Checks the `database_uri` in CONFIG and migrates the
|
24
|
+
database up to the lastest version."
|
25
|
+
def migrate_db(config)
|
23
26
|
Integrity.new(config)
|
24
|
-
migrate_db(direction, 1)
|
25
|
-
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
def version
|
30
|
-
puts Integrity.version
|
28
|
+
require "integrity/migrations"
|
29
|
+
Integrity.migrate_db
|
31
30
|
end
|
32
31
|
|
33
|
-
|
34
|
-
|
32
|
+
desc "launch [CONFIG]",
|
33
|
+
"Launch Integrity real quick."
|
34
|
+
method_options :config => :optional, :port => 4567
|
35
|
+
def launch
|
36
|
+
require "thin"
|
37
|
+
require "do_sqlite3"
|
38
|
+
|
39
|
+
if File.file?(options[:config].to_s)
|
40
|
+
Integrity.new(options[:config])
|
41
|
+
else
|
42
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
43
|
+
end
|
35
44
|
|
36
|
-
|
37
|
-
require 'migrations'
|
45
|
+
DataMapper.auto_migrate!
|
38
46
|
|
39
|
-
|
40
|
-
|
47
|
+
Thin::Server.start("0.0.0.0", options[:port], Integrity::App)
|
48
|
+
rescue LoadError => boom
|
49
|
+
missing_dependency = boom.message.split("--").last.lstrip
|
50
|
+
puts "Please install #{missing_dependency} to launch Integrity"
|
51
|
+
end
|
41
52
|
|
42
|
-
|
43
|
-
|
44
|
-
when "down" then Integrity::Migrations.migrate_down!(level)
|
45
|
-
else raise ArgumentError, "DIRECTION must be either up or down"
|
46
|
-
end
|
47
|
-
end
|
53
|
+
private
|
54
|
+
attr_reader :root
|
48
55
|
|
49
56
|
def create_dir_structure
|
50
57
|
mkdir_p root
|
51
58
|
mkdir_p root / "builds"
|
52
59
|
mkdir_p root / "log"
|
53
|
-
|
54
|
-
|
60
|
+
|
61
|
+
if options[:passenger]
|
62
|
+
mkdir_p root / "public"
|
63
|
+
mkdir_p root / "tmp"
|
64
|
+
end
|
55
65
|
end
|
56
66
|
|
57
67
|
def copy_template_files
|
58
|
-
|
59
|
-
|
60
|
-
|
68
|
+
copy "config/config.sample.ru"
|
69
|
+
copy "config/config.sample.yml"
|
70
|
+
copy "config/thin.sample.yml" if options[:thin]
|
61
71
|
end
|
62
72
|
|
63
73
|
def edit_template_files
|
64
74
|
edit_integrity_configuration
|
65
|
-
edit_thin_configuration
|
75
|
+
edit_thin_configuration if options[:thin]
|
66
76
|
end
|
67
77
|
|
68
78
|
def edit_integrity_configuration
|
@@ -97,36 +107,9 @@ module Integrity
|
|
97
107
|
puts %Q(Don't forget to tweak #{root / "config.yml"} to your needs.)
|
98
108
|
end
|
99
109
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
def add_initial_migration
|
105
|
-
database_adapter.execute %q(INSERT INTO "migration_info" ("migration_name") VALUES ("initial"))
|
106
|
-
end
|
107
|
-
|
108
|
-
def tables_from_before_migrations_exist?
|
109
|
-
table_exists?("integrity_projects") &&
|
110
|
-
table_exists?("integrity_builds") &&
|
111
|
-
table_exists?("integrity_notifiers")
|
112
|
-
end
|
113
|
-
|
114
|
-
def migrations_already_set_up?
|
115
|
-
table_exists?("migration_info")
|
116
|
-
end
|
117
|
-
|
118
|
-
def without_pluralizing_table_names
|
119
|
-
database_adapter.resource_naming_convention = DataMapper::NamingConventions::Resource::Underscored
|
120
|
-
yield
|
121
|
-
database_adapter.resource_naming_convention = DataMapper::NamingConventions::Resource::UnderscoredAndPluralized
|
122
|
-
end
|
123
|
-
|
124
|
-
def table_exists?(table_name)
|
125
|
-
database_adapter.storage_exists?(table_name)
|
126
|
-
end
|
127
|
-
|
128
|
-
def database_adapter
|
129
|
-
DataMapper.repository(:default).adapter
|
110
|
+
def copy(path)
|
111
|
+
cp(File.dirname(__FILE__) + "/../../#{path}",
|
112
|
+
root.join(File.basename(path).gsub(/\.sample/, "")))
|
130
113
|
end
|
131
114
|
end
|
132
115
|
end
|