summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKestred <kestred@riotcave.com>2014-08-23 22:27:52 -0700
committerKestred <kestred@riotcave.com>2014-08-23 22:27:52 -0700
commit18f954b31c242822b6c7430a50ca99a93adc6ea6 (patch)
treeb7ee4acac738d5b64b6fcfaf909756f784dd2d61
parent2eb3d91e1a6e51d3ca0be2fe0a5df750708b366d (diff)
downloadgitlab-ci-18f954b31c242822b6c7430a50ca99a93adc6ea6.tar.gz
Separate Commit model and logic from Build model|etc...
This is an entirely non-user facing change which prepares GitLab CI for future support of Parallel Builds. See https://about.gitlab.com/2013/12/19/gitlab-ci-with-parallel-builds-and-deployments/. These changes specifically avoid changing the supported API or changing any of the website views. Changes to the website views will come in tandem with future features like "Multiple build scripts". The supported API won't change as part of any future changes on this vein, to maintain support for the unofficial GitLab CI runners. This closes the following implementation step: 1. A commit has many builds Signed-off-by: Kestred <kestred@riotcave.com>
-rw-r--r--CHANGELOG3
-rw-r--r--app/controllers/builds_controller.rb6
-rw-r--r--app/helpers/builds_helper.rb8
-rw-r--r--app/models/build.rb119
-rw-r--r--app/models/commit.rb97
-rw-r--r--app/models/project.rb20
-rw-r--r--app/services/create_build_service.rb28
-rw-r--r--app/services/create_commit_service.rb28
-rw-r--r--app/services/image_for_build_service.rb2
-rw-r--r--app/services/notification_service.rb2
-rw-r--r--app/services/web_hook_service.rb2
-rw-r--r--app/views/builds/_build.html.haml2
-rw-r--r--app/views/builds/show.html.haml6
-rw-r--r--app/views/charts/_overall.haml2
-rw-r--r--db/migrate/20140823225019_create_commits_from_builds.rb80
-rw-r--r--db/schema.rb19
-rw-r--r--lib/api/builds.rb9
-rw-r--r--spec/factories/builds.rb9
-rw-r--r--spec/factories/commits.rb31
-rw-r--r--spec/features/builds_spec.rb9
-rw-r--r--spec/lib/charts_spec.rb3
-rw-r--r--spec/models/build_spec.rb220
-rw-r--r--spec/models/commit_spec.rb172
-rw-r--r--spec/models/project_spec.rb9
-rw-r--r--spec/requests/builds_spec.rb6
-rw-r--r--spec/services/create_commit_service_spec.rb25
-rw-r--r--spec/services/image_for_build_service_spec.rb3
-rw-r--r--spec/services/notification_service_spec.rb21
-rw-r--r--spec/services/web_hook_service_spec.rb3
29 files changed, 626 insertions, 318 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 541ea8b..1b2f6ac 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@ v5.1
- Registration token and runner token are named differently
- Redirect to previous page after sign-in
- Dont show archived projects
+ - Separate Commit logic from Build logic in prep for Parallel Builds
v5.0.1
- Update rails to 4.0.5
@@ -78,7 +79,7 @@ v2.2.0
- rescue build timeout correctly
- badge helper with markdown & html
- increased test coverage to 85%
-
+
v2.1.0
- Removed horizontal scroll for build trace
- new status badges
diff --git a/app/controllers/builds_controller.rb b/app/controllers/builds_controller.rb
index 79054a2..25b921e 100644
--- a/app/controllers/builds_controller.rb
+++ b/app/controllers/builds_controller.rb
@@ -20,7 +20,7 @@ class BuildsController < ApplicationController
raise ActiveRecord::RecordNotFound unless @build
- @builds = project.builds.where(sha: @build.sha).order('id DESC')
+ @builds = @project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20)
respond_to do |format|
@@ -35,7 +35,7 @@ class BuildsController < ApplicationController
build = project.builds.create(
sha: @build.sha,
before_sha: @build.before_sha,
- push_data: @build.push_data,
+ push_data: @build.commit.push_data,
ref: @build.ref
)
@@ -65,6 +65,6 @@ class BuildsController < ApplicationController
end
def build_by_sha
- project.builds.where(sha: params[:id]).last
+ @project.commits.find_by_sha(sha: params[:id]).try(:last_build)
end
end
diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb
index 9980e75..0c1e264 100644
--- a/app/helpers/builds_helper.rb
+++ b/app/helpers/builds_helper.rb
@@ -1,6 +1,6 @@
module BuildsHelper
def build_ref_link build
- if build.gitlab?
+ if build.commit.gitlab?
gitlab_ref_link build.project, build.ref
else
build.ref
@@ -8,13 +8,13 @@ module BuildsHelper
end
def build_compare_link build
- if build.gitlab?
- gitlab_compare_link build.project, build.short_before_sha, build.short_sha
+ if build.commit.gitlab?
+ gitlab_compare_link build.project, build.commit.short_before_sha, build.short_sha
end
end
def build_commit_link build
- if build.gitlab?
+ if build.commit.gitlab?
gitlab_commit_link build.project, build.short_sha
else
build.short_sha
diff --git a/app/models/build.rb b/app/models/build.rb
index 47ca196..2377d50 100644
--- a/app/models/build.rb
+++ b/app/models/build.rb
@@ -3,41 +3,30 @@
# Table name: builds
#
# id :integer not null, primary key
-# project_id :integer
-# ref :string(255)
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
-# sha :string(255)
# started_at :datetime
# tmp_file :string(255)
-# before_sha :string(255)
-# push_data :text
# runner_id :integer
+# commit_id :integer
#
class Build < ActiveRecord::Base
- belongs_to :project
+ belongs_to :commit
belongs_to :runner
- serialize :push_data
+ attr_accessible :status, :finished_at, :trace, :started_at, :runner_id, :commit_id
- attr_accessible :project_id, :ref, :sha, :before_sha,
- :status, :finished_at, :trace, :started_at, :push_data, :runner_id, :project_name
-
- validates :before_sha, presence: true
- validates :sha, presence: true
- validates :ref, presence: true
+ validates :commit, presence: true
validates :status, presence: true
- validate :valid_commit_sha
scope :running, ->() { where(status: "running") }
scope :pending, ->() { where(status: "pending") }
scope :success, ->() { where(status: "success") }
scope :failed, ->() { where(status: "failed") }
- scope :uniq_sha, ->() { select('DISTINCT(sha)') }
def self.last_month
where('created_at > ?', Date.today - 1.month)
@@ -97,44 +86,6 @@ class Build < ActiveRecord::Base
state :canceled, value: 'canceled'
end
- def valid_commit_sha
- if self.sha =~ /\A00000000/
- self.errors.add(:sha, " cant be 00000000 (branch removal)")
- end
- end
-
- def compare?
- gitlab? && before_sha
- end
-
- def gitlab?
- project.gitlab?
- end
-
- def ci_skip?
- !!(git_commit_message =~ /(\[ci skip\])/)
- end
-
- def git_author_name
- commit_data[:author][:name] if commit_data && commit_data[:author]
- end
-
- def git_author_email
- commit_data[:author][:email] if commit_data && commit_data[:author]
- end
-
- def git_commit_message
- commit_data[:message] if commit_data
- end
-
- def short_before_sha
- before_sha[0..8]
- end
-
- def short_sha
- sha[0..8]
- end
-
def trace_html
html = Ansi2html::convert(trace) if trace.present?
html ||= ''
@@ -156,47 +107,53 @@ class Build < ActiveRecord::Base
project.scripts
end
- def commit_data
- push_data[:commits].each do |commit|
- return commit if commit[:id] == sha
- end
- rescue
- nil
+ def timeout
+ project.timeout
end
- # Build a clone-able repo url
- # using http and basic auth
- def repo_url
- auth = "gitlab-ci-token:#{project.token}@"
- url = project.gitlab_url + ".git"
- url.sub(/^https?:\/\//) do |prefix|
- prefix + auth
+ def duration
+ if started_at && finished_at
+ finished_at - started_at
+ elsif started_at
+ Time.now - started_at
end
end
- def timeout
- project.timeout
+
+ # The following methods are provided for Grape::Entity and end up being
+ # useful everywhere else to reduce the changes needed for parallel builds.
+ def ref
+ commit.ref
+ end
+
+ def sha
+ commit.sha
+ end
+
+ def short_sha
+ commit.short_sha
end
+ def before_sha
+ commit.before_sha end
+
def allow_git_fetch
- project.allow_git_fetch
+ commit.allow_git_fetch
end
- def project_name
- project.name
+ def project
+ commit.project
end
- def project_recipients
- recipients = project.email_recipients.split(' ')
- recipients << git_author_email if project.email_add_committer?
- recipients.uniq
+ def project_id
+ commit.project_id
end
- def duration
- if started_at && finished_at
- finished_at - started_at
- elsif started_at
- Time.now - started_at
- end
+ def project_name
+ commit.project_name
+ end
+
+ def repo_url
+ commit.repo_url
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
new file mode 100644
index 0000000..665f136
--- /dev/null
+++ b/app/models/commit.rb
@@ -0,0 +1,97 @@
+# == Schema Information
+#
+# Table name: commits
+#
+# id :integer not null, primary key
+# project_id :integer
+# ref :string(255)
+# sha :string(255)
+# before_sha :string(255)
+# push_data :text
+# created_at :datetime
+# updated_at :datetime
+#
+
+class Commit < ActiveRecord::Base
+ belongs_to :project
+ has_many :builds
+
+ serialize :push_data
+
+ validates_presence_of :ref, :sha, :before_sha, :push_data
+ validate :valid_commit_sha
+
+ def last_build
+ builds.last
+ end
+
+ def valid_commit_sha
+ if self.sha =~ /\A00000000/
+ self.errors.add(:sha, " cant be 00000000 (branch removal)")
+ end
+ end
+
+ def compare?
+ gitlab? && before_sha
+ end
+
+ def gitlab?
+ project.gitlab?
+ end
+
+ def ci_skip?
+ !!(git_commit_message =~ /(\[ci skip\])/)
+ end
+
+ def git_author_name
+ commit_data[:author][:name] if commit_data && commit_data[:author]
+ end
+
+ def git_author_email
+ commit_data[:author][:email] if commit_data && commit_data[:author]
+ end
+
+ def git_commit_message
+ commit_data[:message] if commit_data
+ end
+
+ def short_before_sha
+ before_sha[0..8]
+ end
+
+ def short_sha
+ sha[0..8]
+ end
+
+ def commit_data
+ push_data[:commits].each do |commit|
+ return commit if commit[:id] == sha
+ end
+ rescue
+ nil
+ end
+
+ # Build a clone-able repo url
+ # using http and basic auth
+ def repo_url
+ auth = "gitlab-ci-token:#{project.token}@"
+ url = project.gitlab_url + ".git"
+ url.sub(/^https?:\/\//) do |prefix|
+ prefix + auth
+ end
+ end
+
+ def allow_git_fetch
+ project.allow_git_fetch
+ end
+
+ def project_name
+ project.name
+ end
+
+ def project_recipients
+ recipients = project.email_recipients.split(' ')
+ recipients << git_author_email if project.email_add_committer?
+ recipients.uniq
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 5a8f052..ec25158 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -28,7 +28,7 @@ class Project < ActiveRecord::Base
:public, :ssh_url_to_repo, :gitlab_id, :allow_git_fetch,
:email_recipients, :email_add_committer, :email_only_broken_builds
- has_many :builds, dependent: :destroy
+ has_many :commits, dependent: :destroy
has_many :runner_projects, dependent: :destroy
has_many :runners, through: :runner_projects
has_many :web_hooks, dependent: :destroy
@@ -123,6 +123,10 @@ ls -la
broken? || success?
end
+ def builds
+ Build.where(commit_id: commits).references(:commits)
+ end
+
def last_build
builds.last
end
@@ -135,8 +139,14 @@ ls -la
status
end
+ def last_build_for_ref(ref)
+ commits_for_ref = commits.where(ref: ref)
+ Build.where(commit_id: commits_for_ref).last
+ end
+
def last_build_for_sha(sha)
- builds.where(sha: sha).order('id DESC').limit(1).first
+ commit = commits.find_by_sha(sha)
+ commit.last_build unless commit.nil?
end
def tracked_refs
@@ -160,10 +170,10 @@ ls -la
web_hooks.any?
end
- # onlu check for toggling build status within same ref.
+ # only check for toggling build status within same ref.
def last_build_changed_status?
- ref = last_build.ref
- last_builds = builds.where(ref: ref).order('id DESC').limit(2)
+ commits_for_ref = commit.where(ref: last_build.ref)
+ last_builds = Build.where(commit_id: commits_for_ref).order('id DESC').limit(2)
return false if last_builds.size < 2
return last_builds[0].status != last_builds[1].status
end
diff --git a/app/services/create_build_service.rb b/app/services/create_build_service.rb
index a5b2484..b3a4edf 100644
--- a/app/services/create_build_service.rb
+++ b/app/services/create_build_service.rb
@@ -1,28 +1,12 @@
class CreateBuildService
def execute(project, params)
- before_sha = params[:before]
- sha = params[:after]
- ref = params[:ref]
+ commit = Commit.where(project: project).where(sha: params[:after]).first
+ commit ||= CreateCommitService.new.execute(project, params)
- if ref && ref.include?('refs/heads/')
- ref = ref.scan(/heads\/(.*)$/).flatten[0]
+ if commit.persisted?
+ commit.builds.create
+ else
+ commit.builds.new
end
-
- data = {
- ref: ref,
- sha: sha,
- before_sha: before_sha,
- push_data: {
- before: before_sha,
- after: sha,
- ref: ref,
- user_name: params[:user_name],
- repository: params[:repository],
- commits: params[:commits],
- total_commits_count: params[:total_commits_count]
- }
- }
-
- project.builds.create(data)
end
end
diff --git a/app/services/create_commit_service.rb b/app/services/create_commit_service.rb
new file mode 100644
index 0000000..5480802
--- /dev/null
+++ b/app/services/create_commit_service.rb
@@ -0,0 +1,28 @@
+class CreateCommitService
+ def execute(project, params)
+ before_sha = params[:before]
+ sha = params[:after]
+ ref = params[:ref]
+
+ if ref && ref.include?('refs/heads/')
+ ref = ref.scan(/heads\/(.*)$/).flatten[0]
+ end
+
+ data = {
+ ref: ref,
+ sha: sha,
+ before_sha: before_sha,
+ push_data: {
+ before: before_sha,
+ after: sha,
+ ref: ref,
+ user_name: params[:user_name],
+ repository: params[:repository],
+ commits: params[:commits],
+ total_commits_count: params[:total_commits_count]
+ }
+ }
+
+ project.commits.create(data)
+ end
+end
diff --git a/app/services/image_for_build_service.rb b/app/services/image_for_build_service.rb
index 425a020..79bf2ee 100644
--- a/app/services/image_for_build_service.rb
+++ b/app/services/image_for_build_service.rb
@@ -6,7 +6,7 @@ class ImageForBuildService
image_name = image_for_build(build)
elsif params[:ref]
# Look for last build per branch
- build = project.builds.where(ref: params[:ref]).last
+ build = project.last_build_for_ref(params[:ref])
image_name = image_for_build(build)
else
image_name = 'unknown.png'
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index acd2e54..db52c02 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -7,7 +7,7 @@
#
class NotificationService
def build_ended(build)
- build.project_recipients.each do |recipient|
+ build.commit.project_recipients.each do |recipient|
case build.status.to_sym
when :success
mailer.build_success_email(build.id, recipient)
diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb
index 3e61a99..94962a1 100644
--- a/app/services/web_hook_service.rb
+++ b/app/services/web_hook_service.rb
@@ -27,7 +27,7 @@ class WebHookService
ref: build.ref,
sha: build.sha,
before_sha: build.before_sha,
- push_data: build.push_data
+ push_data: build.commit.push_data
})
end
end
diff --git a/app/views/builds/_build.html.haml b/app/views/builds/_build.html.haml
index f97cd28..54f46df 100644
--- a/app/views/builds/_build.html.haml
+++ b/app/views/builds/_build.html.haml
@@ -7,7 +7,7 @@
%strong #{build.short_sha}
%td.build-message
- %span= truncate(build.git_commit_message, length: 50)
+ %span= truncate(build.commit.git_commit_message, length: 50)
%td.build-branch
- unless @ref
diff --git a/app/views/builds/show.html.haml b/app/views/builds/show.html.haml
index 85b37a0..f7e1182 100644
--- a/app/views/builds/show.html.haml
+++ b/app/views/builds/show.html.haml
@@ -76,7 +76,7 @@
.pull-right
%small #{build_commit_link @build}
- - if @build.compare?
+ - if @build.commit.compare?
%p
%span.attr-name Compare:
#{build_compare_link @build}
@@ -85,10 +85,10 @@
#{build_ref_link @build}
%p
%span.attr-name Author:
- #{@build.git_author_name}
+ #{@build.commit.git_author_name}
%p
%span.attr-name Message:
- #{@build.git_commit_message}
+ #{@build.commit.git_commit_message}
- if @builds.present?
.build-widget
diff --git a/app/views/charts/_overall.haml b/app/views/charts/_overall.haml
index 36e1616..34d83ab 100644
--- a/app/views/charts/_overall.haml
+++ b/app/views/charts/_overall.haml
@@ -18,4 +18,4 @@
%p
Commits covered:
%strong
- = @project.builds.uniq_sha.count \ No newline at end of file
+ = @project.commits.count
diff --git a/db/migrate/20140823225019_create_commits_from_builds.rb b/db/migrate/20140823225019_create_commits_from_builds.rb
new file mode 100644
index 0000000..97252a0
--- /dev/null
+++ b/db/migrate/20140823225019_create_commits_from_builds.rb
@@ -0,0 +1,80 @@
+class CreateCommitsFromBuilds < ActiveRecord::Migration
+ def change
+ create_table :commits do |t|
+ t.integer :project_id
+ t.string :ref, nil: false
+ t.string :sha, nil: false
+ t.string :before_sha, nil: false
+ t.text :push_data, nil: false
+
+ t.timestamps
+ end
+
+ reversible do |migration|
+ migration.up { init_commits }
+ migration.down {}
+ end
+
+ add_column :builds, :commit_id, :integer
+
+ reversible do |migration|
+ migration.up { associate_builds_with_commit }
+ migration.down { dissociate_builds_with_commit }
+ end
+
+ # Remove commit data from builds
+ # -- don't use change_table, its not very reversible
+ remove_column :builds, :project_id, :integer
+ remove_column :builds, :ref, :string
+ remove_column :builds, :sha, :string
+ remove_column :builds, :before_sha, :string
+ remove_column :builds, :push_data, :text
+ end
+
+ private
+
+ def init_commits
+ Commit.reset_column_information
+
+ # Create one Commit for each unique sha value
+ shas = Build.pluck(:sha).uniq
+ shas.each do |sha|
+ # Get latest build for a particular commit
+ build = Build.where(sha: sha).order('created_at desc').first
+ attributes = {
+ project_id: build.project_id,
+ ref: build.ref,
+ sha: build.sha,
+ before_sha: build.before_sha,
+ push_data: build.push_data,
+ # Original commit status matches the latest build status
+ status: build.status
+ }
+
+ Commit.create!(attributes)
+ end
+ end
+
+ def associate_builds_with_commit
+ Build.reset_column_information
+ Build.find_each do |build|
+ build.commit_id = Commit.find_by_sha(build.sha).id
+ build.save!
+ end
+ end
+
+ def dissociate_builds_with_commit
+ Build.reset_column_information
+ Build.find_each do |build|
+ # Don't assume an assocation exists
+ commit = Commit.find(build.commit_id)
+
+ build.project_id = commit.project_id
+ build.ref = commit.ref
+ build.sha = commit.sha
+ build.before_sha = commit.before_sha
+ build.push_data = commit.push_data
+ build.save!
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index dcb3569..a3edfda 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,30 +11,35 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140506091853) do
+ActiveRecord::Schema.define(version: 20140823225019) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "builds", force: true do |t|
- t.integer "project_id"
- t.string "ref"
t.string "status"
t.datetime "finished_at"
t.text "trace"
t.datetime "created_at"
t.datetime "updated_at"
- t.string "sha"
t.datetime "started_at"
t.string "tmp_file"
- t.string "before_sha"
- t.text "push_data"
t.integer "runner_id"
+ t.integer "commit_id"
end
- add_index "builds", ["project_id"], name: "index_builds_on_project_id", using: :btree
add_index "builds", ["runner_id"], name: "index_builds_on_runner_id", using: :btree
+ create_table "commits", force: true do |t|
+ t.integer "project_id"
+ t.string "ref"
+ t.string "sha"
+ t.string "before_sha"
+ t.text "push_data"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "projects", force: true do |t|
t.string "name", null: false
t.integer "timeout", default: 1800, null: false
diff --git a/lib/api/builds.rb b/lib/api/builds.rb
index 6ecc248..f96c1d4 100644
--- a/lib/api/builds.rb
+++ b/lib/api/builds.rb
@@ -14,9 +14,12 @@ module API
required_attributes! [:token]
ActiveRecord::Base.transaction do
- builds = Build.all
- builds = builds.where(project_id: current_runner.projects) unless current_runner.shared?
- build = builds.first_pending
+ build = if current_runner.shared?
+ Build.first_pending
+ else
+ commits = Commit.where(project_id: current_runner.projects)
+ Build.where(commit_id: commits).first_pending
+ end
not_found! and return unless build
diff --git a/spec/factories/builds.rb b/spec/factories/builds.rb
index d90d16d..7e222b2 100644
--- a/spec/factories/builds.rb
+++ b/spec/factories/builds.rb
@@ -3,28 +3,21 @@
# Table name: builds
#
# id :integer not null, primary key
-# project_id :integer
-# ref :string(255)
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
-# sha :string(255)
# started_at :datetime
# tmp_file :string(255)
-# before_sha :string(255)
-# push_data :text
# runner_id :integer
+# commit_id :integer
#
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :build do
- ref 'master'
- before_sha '76de212e80737a608d939f648d959671fb0a0142'
- sha '97de212e80737a608d939f648d959671fb0a0142'
started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013'
end
diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb
new file mode 100644
index 0000000..c05dad8
--- /dev/null
+++ b/spec/factories/commits.rb
@@ -0,0 +1,31 @@
+# == Schema Information
+#
+# Table name: commits
+#
+# id :integer not null, primary key
+# project_id :integer
+# ref :string(255)
+# sha :string(255)
+# before_sha :string(255)
+# status :string(255)
+# push_data :text
+# created_at :datetime
+# updated_at :datetime
+#
+
+# Read about factories at https://github.com/thoughtbot/factory_girl
+
+FactoryGirl.define do
+ factory :commit do
+ ref 'master'
+ before_sha '76de212e80737a608d939f648d959671fb0a0142'
+ sha '97de212e80737a608d939f648d959671fb0a0142'
+ push_data do
+ {
+ ref: 'refs/heads/master',
+ before_sha: '76de212e80737a608d939f648d959671fb0a0142',
+ after_sha: '97de212e80737a608d939f648d959671fb0a0142'
+ }
+ end
+ end
+end
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index 10cd6a1..2c59e14 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -4,7 +4,8 @@ describe "Builds" do
before do
login_as :user
@project = FactoryGirl.create :project
- @build = FactoryGirl.create :build, project: @project
+ @commit = FactoryGirl.create :commit, project: @project
+ @build = FactoryGirl.create :build, commit: @commit
end
describe "GET /:project/builds" do
@@ -12,8 +13,8 @@ describe "Builds" do
visit project_build_path(@project, @build)
end
- it { page.should have_content @build.sha[0..7] }
- it { page.should have_content @build.git_commit_message }
- it { page.should have_content @build.git_author_name }
+ it { page.should have_content @commit.sha[0..7] }
+ it { page.should have_content @commit.git_commit_message }
+ it { page.should have_content @commit.git_author_name }
end
end
diff --git a/spec/lib/charts_spec.rb b/spec/lib/charts_spec.rb
index f45a578..236cfc2 100644
--- a/spec/lib/charts_spec.rb
+++ b/spec/lib/charts_spec.rb
@@ -5,7 +5,8 @@ describe "Charts" do
context "build_times" do
before do
@project = FactoryGirl.create(:project)
- FactoryGirl.create(:build, :project_id => @project.id)
+ @commit = FactoryGirl.create(:commit, project: @project)
+ FactoryGirl.create(:build, commit: @commit)
end
it 'should return build times in minutes' do
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 9e932ab..ae67c33 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -3,58 +3,43 @@
# Table name: builds
#
# id :integer not null, primary key
-# project_id :integer
-# ref :string(255)
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
-# sha :string(255)
# started_at :datetime
# tmp_file :string(255)
-# before_sha :string(255)
-# push_data :text
# runner_id :integer
+# commit_id :integer
#
require 'spec_helper'
describe Build do
let(:project) { FactoryGirl.create :project }
- let(:build) { FactoryGirl.create :build }
- let(:build_with_project) { FactoryGirl.create :build, project: project }
+ let(:commit) { FactoryGirl.create :commit, project: project }
+ let(:build) { FactoryGirl.create :build, commit: commit }
- it { should belong_to(:project) }
- it { should validate_presence_of :before_sha }
- it { should validate_presence_of :sha }
- it { should validate_presence_of :ref }
+ it { should belong_to(:commit) }
it { should validate_presence_of :status }
it { should respond_to :success? }
it { should respond_to :failed? }
it { should respond_to :running? }
it { should respond_to :pending? }
- it { should respond_to :git_author_name }
- it { should respond_to :git_author_email }
- it { should respond_to :short_sha }
it { should respond_to :trace_html }
- it { should allow_mass_assignment_of(:project_id) }
- it { should allow_mass_assignment_of(:ref) }
- it { should allow_mass_assignment_of(:sha) }
- it { should allow_mass_assignment_of(:before_sha) }
+ it { should allow_mass_assignment_of(:commit_id) }
it { should allow_mass_assignment_of(:status) }
+ it { should allow_mass_assignment_of(:started_at) }
it { should allow_mass_assignment_of(:finished_at) }
it { should allow_mass_assignment_of(:trace) }
- it { should allow_mass_assignment_of(:started_at) }
- it { should allow_mass_assignment_of(:push_data) }
it { should allow_mass_assignment_of(:runner_id) }
- it { should allow_mass_assignment_of(:project_name) }
describe :first_pending do
- let(:first) { FactoryGirl.create :build, status: 'pending', created_at: Date.yesterday }
- let(:second) { FactoryGirl.create :build, status: 'pending' }
+ let(:first) { FactoryGirl.create :build, commit: commit, status: 'pending', created_at: Date.yesterday }
+ let(:second) { FactoryGirl.create :build, commit: commit, status: 'pending' }
before { first; second }
subject { Build.first_pending }
@@ -76,73 +61,6 @@ describe Build do
end
end
- describe :ci_skip? do
- let(:project) { FactoryGirl.create(:project) }
- let(:build) { FactoryGirl.create(:build, project: project) }
-
- it 'true if commit message contains [ci skip]' do
- build.stub(:git_commit_message) { 'Small typo [ci skip]' }
- build.ci_skip?.should == true
- end
-
- it 'false if commit message does not contain [ci skip]' do
- build.ci_skip?.should == false
- end
- end
-
- describe :project_recipients do
-
- context 'always sending notification' do
- it 'should return git_author_email as only recipient when no additional recipients are given' do
- project = FactoryGirl.create :project,
- email_add_committer: true,
- email_recipients: ''
- build = FactoryGirl.create :build,
- status: :success,
- project: project
- expected = 'git_author_email'
- build.stub(:git_author_email) { expected }
- build.project_recipients.should == [expected]
- end
-
- it 'should return git_author_email and additional recipients' do
- project = FactoryGirl.create :project,
- email_add_committer: true,
- email_recipients: 'rec1 rec2'
- build = FactoryGirl.create :build,
- status: :success,
- project: project
- expected = 'git_author_email'
- build.stub(:git_author_email) { expected }
- build.project_recipients.should == ['rec1', 'rec2', expected]
- end
-
- it 'should return recipients' do
- project = FactoryGirl.create :project,
- email_add_committer: false,
- email_recipients: 'rec1 rec2'
- build = FactoryGirl.create :build,
- status: :success,
- project: project
- expected = 'git_author_email'
- build.stub(:git_author_email) { expected }
- build.project_recipients.should == ['rec1', 'rec2']
- end
-
- it 'should return unique recipients only' do
- project = FactoryGirl.create :project,
- email_add_committer: true,
- email_recipients: 'rec1 rec1 rec2'
- build = FactoryGirl.create :build,
- status: :success,
- project: project
- expected = 'rec2'
- build.stub(:git_author_email) { expected }
- build.project_recipients.should == ['rec1', 'rec2']
- end
- end
- end
-
describe :started? do
subject { build.started? }
@@ -209,17 +127,6 @@ describe Build do
end
end
- describe :valid_commit_sha do
- context 'build.sha can not start with 00000000' do
- before do
- build.sha = '0' * 32
- build.valid_commit_sha
- end
-
- it('build errors should not be empty') { build.errors.should_not be_empty }
- end
- end
-
describe :trace do
subject { build.trace_html }
@@ -234,91 +141,94 @@ describe Build do
end
end
- describe :compare? do
- subject { build_with_project.compare? }
+ describe :commands do
+ subject { build.commands }
- context 'if project.gitlab_url and build.before_sha are not nil' do
- it { should be_true }
- end
+ it { should eq(commit.project.scripts) }
end
- describe :short_sha do
- subject { build.short_before_sha }
+ describe :timeout do
+ subject { build.timeout }
- it { should have(9).items }
- it { build.before_sha.should start_with(subject) }
+ it { should eq(commit.project.timeout) }
end
- describe :short_sha do
- subject { build.short_sha }
+ describe :duration do
+ subject { build.duration }
+
+ it { should eq(120.0) }
+
+ context 'if the building process has not started yet' do
+ before do
+ build.started_at = nil
+ build.finished_at = nil
+ end
- it { should have(9).items }
- it { build.sha.should start_with(subject) }
+ it { should be_nil }
+ end
+
+ context 'if the building process has started' do
+ before do
+ build.started_at = Time.now - 1.minute
+ build.finished_at = nil
+ end
+
+ it { should be_a(Float) }
+ it { should > 0.0 }
+ end
end
- describe :repo_url do
- subject { build_with_project.repo_url }
-
- it { should be_a(String) }
- it { should end_with(".git") }
- it { should start_with(project.gitlab_url[0..6]) }
- it { should include(project.token) }
- it { should include('gitlab-ci-token') }
- it { should include(project.gitlab_url[7..-1]) }
+ describe :ref do
+ subject { build.ref }
+
+ it { should eq(commit.ref) }
end
- describe :gitlab? do
- subject { build_with_project.gitlab? }
+ describe :sha do
+ subject { build.sha }
- it { should eq(project.gitlab?) }
+ it { should eq(commit.sha) }
end
- describe :commands do
- subject { build_with_project.commands }
+ describe :short_sha do
+ subject { build.short_sha }
- it { should eq(project.scripts) }
+ it { should eq(commit.short_sha) }
end
- describe :timeout do
- subject { build_with_project.timeout }
+ describe :before_sha do
+ subject { build.before_sha }
- it { should eq(project.timeout) }
+ it { should eq(commit.before_sha) }
end
describe :allow_git_fetch do
- subject { build_with_project.allow_git_fetch }
+ subject { build.allow_git_fetch }
- it { should eq(project.allow_git_fetch) }
+ it { should eq(commit.allow_git_fetch) }
end
- describe :name do
- subject { build_with_project.project_name }
+ describe :project do
+ subject { build.project }
- it { should eq(project.name) }
+ it { should eq(commit.project) }
end
- describe :duration do
- subject { build.duration }
+ describe :project_id do
+ subject { build.project_id }
- it { should eq(120.0) }
+ it { should eq(commit.project_id) }
+ end
- context 'if the building process has not started yet' do
- before do
- build.started_at = nil
- build.finished_at = nil
- end
+ describe :project_name do
+ subject { build.project_name }
- it { should be_nil }
- end
+ it { should eq(commit.project_name) }
+ end
- context 'if the building process has started' do
- before do
- build.started_at = Time.now - 1.minute
- build.finished_at = nil
- end
+ describe :repo_url do
+ subject { build.repo_url }
- it { should be_a(Float) }
- it { should > 0.0 }
- end
+ it { should eq(commit.repo_url) }
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
new file mode 100644
index 0000000..380a9b1
--- /dev/null
+++ b/spec/models/commit_spec.rb
@@ -0,0 +1,172 @@
+# == Schema Information
+#
+# Table name: commits
+#
+# id :integer not null, primary key
+# project_id :integer
+# ref :string(255)
+# sha :string(255)
+# before_sha :string(255)
+# push_data :text
+# created_at :datetime
+# updated_at :datetime
+#
+
+require 'spec_helper'
+
+describe Commit do
+ let(:project) { FactoryGirl.create :project }
+ let(:commit) { FactoryGirl.create :commit }
+ let(:commit_with_project) { FactoryGirl.create :commit, project: project }
+
+ it { should belong_to(:project) }
+ it { should have_many(:builds) }
+ it { should validate_presence_of :before_sha }
+ it { should validate_presence_of :sha }
+ it { should validate_presence_of :ref }
+ it { should validate_presence_of :push_data }
+
+ it { should respond_to :git_author_name }
+ it { should respond_to :git_author_email }
+ it { should respond_to :short_sha }
+
+ it { should allow_mass_assignment_of(:project_id) }
+ it { should allow_mass_assignment_of(:ref) }
+ it { should allow_mass_assignment_of(:sha) }
+ it { should allow_mass_assignment_of(:before_sha) }
+ it { should allow_mass_assignment_of(:push_data) }
+ it { should allow_mass_assignment_of(:status) }
+ it { should allow_mass_assignment_of(:project_name) }
+
+ describe :last_build do
+ subject { commit.last_build }
+ before do
+ @first = FactoryGirl.create :build, commit: commit, created_at: Date.yesterday
+ @second = FactoryGirl.create :build, commit: commit
+ end
+
+ it { should be_a(Build) }
+ it('returns with the most recently created build') { should eq(@second) }
+ end
+
+ describe :ci_skip? do
+ let(:project) { FactoryGirl.create(:project) }
+ let(:commit) { FactoryGirl.create(:commit, project: project) }
+
+ it 'true if commit message contains [ci skip]' do
+ commit.stub(:git_commit_message) { 'Small typo [ci skip]' }
+ commit.ci_skip?.should == true
+ end
+
+ it 'false if commit message does not contain [ci skip]' do
+ commit.ci_skip?.should == false
+ end
+ end
+
+ describe :project_recipients do
+
+ context 'always sending notification' do
+ it 'should return git_author_email as only recipient when no additional recipients are given' do
+ project = FactoryGirl.create :project,
+ email_add_committer: true,
+ email_recipients: ''
+ commit = FactoryGirl.create :commit, project: project
+ expected = 'git_author_email'
+ commit.stub(:git_author_email) { expected }
+ commit.project_recipients.should == [expected]
+ end
+
+ it 'should return git_author_email and additional recipients' do
+ project = FactoryGirl.create :project,
+ email_add_committer: true,
+ email_recipients: 'rec1 rec2'
+ commit = FactoryGirl.create :commit, project: project
+ expected = 'git_author_email'
+ commit.stub(:git_author_email) { expected }
+ commit.project_recipients.should == ['rec1', 'rec2', expected]
+ end
+
+ it 'should return recipients' do
+ project = FactoryGirl.create :project,
+ email_add_committer: false,
+ email_recipients: 'rec1 rec2'
+ commit = FactoryGirl.create :commit, project: project
+ expected = 'git_author_email'
+ commit.stub(:git_author_email) { expected }
+ commit.project_recipients.should == ['rec1', 'rec2']
+ end
+
+ it 'should return unique recipients only' do
+ project = FactoryGirl.create :project,
+ email_add_committer: true,
+ email_recipients: 'rec1 rec1 rec2'
+ commit = FactoryGirl.create :commit, project: project
+ expected = 'rec2'
+ commit.stub(:git_author_email) { expected }
+ commit.project_recipients.should == ['rec1', 'rec2']
+ end
+ end
+ end
+
+ describe :valid_commit_sha do
+ context 'commit.sha can not start with 00000000' do
+ before do
+ commit.sha = '0' * 32
+ commit.valid_commit_sha
+ end
+
+ it('commit errors should not be empty') { commit.errors.should_not be_empty }
+ end
+ end
+
+ describe :compare? do
+ subject { commit_with_project.compare? }
+
+ context 'if project.gitlab_url and commit.before_sha are not nil' do
+ it { should be_true }
+ end
+ end
+
+ describe :short_sha do
+ subject { commit.short_before_sha }
+
+ it { should have(9).items }
+ it { commit.before_sha.should start_with(subject) }
+ end
+
+ describe :short_sha do
+ subject { commit.short_sha }
+
+ it { should have(9).items }
+ it { commit.sha.should start_with(subject) }
+ end
+
+ describe :repo_url do
+ subject { commit_with_project.repo_url }
+
+ it { should be_a(String) }
+ it { should end_with(".git") }
+ it { should start_with(project.gitlab_url[0..6]) }
+ it { should include(project.token) }
+ it { should include('gitlab-ci-token') }
+ it { should include(project.gitlab_url[7..-1]) }
+ end
+
+ describe :gitlab? do
+ subject { commit_with_project.gitlab? }
+
+ it { should eq(project.gitlab?) }
+ end
+
+ describe :allow_git_fetch do
+ subject { commit_with_project.allow_git_fetch }
+
+ it { should eq(project.allow_git_fetch) }
+ end
+
+ describe :name do
+ subject { commit_with_project.project_name }
+
+ it { should eq(project.name) }
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index fc06414..0e29b5c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -27,7 +27,7 @@ require 'spec_helper'
describe Project do
subject { FactoryGirl.build :project }
- it { should have_many(:builds) }
+ it { should have_many(:commits) }
it { should validate_presence_of :name }
it { should validate_presence_of :scripts }
@@ -49,8 +49,11 @@ describe Project do
context :valid_project do
let(:project) { FactoryGirl.create :project }
- context :project_with_build do
- before { FactoryGirl.create(:build, project: project) }
+ context :project_with_commit_and_builds do
+ before do
+ commit = FactoryGirl.create(:commit, project: project)
+ FactoryGirl.create(:build, commit: commit)
+ end
it { project.status.should == 'pending' }
it { project.last_build.should be_kind_of(Build) }
diff --git a/spec/requests/builds_spec.rb b/spec/requests/builds_spec.rb
index 26b21b2..0fe2313 100644
--- a/spec/requests/builds_spec.rb
+++ b/spec/requests/builds_spec.rb
@@ -13,7 +13,8 @@ describe API::API do
describe "POST /builds/register" do
it "should start a build" do
- build = FactoryGirl.create(:build, project_id: project.id, status: 'pending' )
+ commit = FactoryGirl.create(:commit, project: project)
+ build = FactoryGirl.create(:build, commit: commit, status: 'pending' )
post api("/builds/register"), token: runner.token
@@ -29,7 +30,8 @@ describe API::API do
end
describe "PUT /builds/:id" do
- let(:build) { FactoryGirl.create(:build, project_id: project.id, runner_id: runner.id) }
+ let(:commit) { FactoryGirl.create(:commit, project: project)}
+ let(:build) { FactoryGirl.create(:build, commit: commit, runner_id: runner.id) }
it "should update a running build" do
build.run!
diff --git a/spec/services/create_commit_service_spec.rb b/spec/services/create_commit_service_spec.rb
new file mode 100644
index 0000000..bb2d2d9
--- /dev/null
+++ b/spec/services/create_commit_service_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe CreateCommitService do
+ let(:service) { CreateCommitService.new }
+ let(:project) { FactoryGirl.create(:project) }
+
+ describe :execute do
+ context 'valid params' do
+ let(:commit) { service.execute(project, ref: 'refs/heads/master', before: '00000000', after: '31das312') }
+
+ it { commit.should be_kind_of(Commit) }
+ it { commit.should be_valid }
+ it { commit.should be_persisted }
+ it { commit.should == project.commits.last }
+ end
+
+ context 'without params' do
+ let(:commit) { service.execute(project, {}) }
+
+ it { commit.should be_kind_of(Commit) }
+ it { commit.should_not be_valid }
+ it { commit.should_not be_persisted }
+ end
+ end
+end
diff --git a/spec/services/image_for_build_service_spec.rb b/spec/services/image_for_build_service_spec.rb
index 2a65c48..2c9da1f 100644
--- a/spec/services/image_for_build_service_spec.rb
+++ b/spec/services/image_for_build_service_spec.rb
@@ -3,7 +3,8 @@ require 'spec_helper'
describe ImageForBuildService do
let(:service) { ImageForBuildService.new }
let(:project) { FactoryGirl.create(:project) }
- let(:build) { FactoryGirl.create(:build, project: project, ref: 'master') }
+ let(:commit) { FactoryGirl.create(:commit, project: project, ref: 'master') }
+ let(:build) { FactoryGirl.create(:build, commit: commit) }
describe :execute do
before { build }
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index fff9c87..413523c 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -6,11 +6,12 @@ describe NotificationService do
describe 'Builds' do
describe 'failed build' do
- let(:project) { FactoryGirl.create(:project)}
- let(:build) { FactoryGirl.create(:build, :status => :failed, :project => project) }
+ let(:project) { FactoryGirl.create(:project) }
+ let(:commit) { FactoryGirl.create(:commit, project: project) }
+ let(:build) { FactoryGirl.create(:build, status: :failed, commit: commit) }
it do
- should_email(build.git_author_email)
+ should_email(commit.git_author_email)
notification.build_ended(build)
end
@@ -21,10 +22,11 @@ describe NotificationService do
end
describe 'successfull build' do
- let(:project) { FactoryGirl.create(:project)}
- let(:build) { FactoryGirl.create(:build, :status => :success, :project => project) }
+ let(:project) { FactoryGirl.create(:project) }
+ let(:commit) { FactoryGirl.create(:commit, project: project) }
+ let(:build) { FactoryGirl.create(:build, status: :success, commit: commit) }
it do
- should_email(build.git_author_email)
+ should_email(commit.git_author_email)
notification.build_ended(build)
end
@@ -35,11 +37,12 @@ describe NotificationService do
end
describe 'successfull build and project has email_recipients' do
- let(:project) { FactoryGirl.create(:project, :email_recipients => "jeroen@example.com")}
- let(:build) { FactoryGirl.create(:build, :status => :success, :project => project) }
+ let(:project) { FactoryGirl.create(:project, email_recipients: "jeroen@example.com") }
+ let(:commit) { FactoryGirl.create(:commit, project: project) }
+ let(:build) { FactoryGirl.create(:build, status: :success, commit: commit) }
it do
- should_email(build.git_author_email)
+ should_email(commit.git_author_email)
should_email("jeroen@example.com")
notification.build_ended(build)
end
diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb
index 699c126..bc63fd8 100644
--- a/spec/services/web_hook_service_spec.rb
+++ b/spec/services/web_hook_service_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
describe WebHookService do
let (:project) { FactoryGirl.create :project }
- let (:build) { FactoryGirl.create :build, project: project }
+ let (:commit) { FactoryGirl.create :commit, project: project }
+ let (:build) { FactoryGirl.create :build, commit: commit }
let (:hook) { FactoryGirl.create :web_hook, project: project }
describe :execute do