Skip to content
Snippets Groups Projects
Commit 06722589 authored by Kamil Trzcińśki's avatar Kamil Trzcińśki
Browse files

Cleanup CiCommit and CiBuild

- Remove all view related methods from Ci::Build and CommitStatus
- Remove unused Ci::Commit and Ci::Build methods
- Use polymorphism to render different types of CommitStatus
parent 37ba5a12
No related branches found
No related tags found
No related merge requests found
Showing
with 174 additions and 304 deletions
Loading
Loading
@@ -128,7 +128,7 @@ module Ci
end
 
def retried?
!self.commit.latest_builds_for_ref(self.ref).include?(self)
!self.commit.latest_statuses_for_ref(self.ref).include?(self)
end
 
def depends_on_builds
Loading
Loading
@@ -309,22 +309,6 @@ module Ci
project.valid_runners_token? token
end
 
def target_url
namespace_project_build_url(project.namespace, project, self)
end
def cancel_url
if active?
cancel_namespace_project_build_path(project.namespace, project, self)
end
end
def retry_url
if retryable?
retry_namespace_project_build_path(project.namespace, project, self)
end
end
def can_be_served?(runner)
(tag_list - runner.tag_list).empty?
end
Loading
Loading
@@ -333,7 +317,7 @@ module Ci
project.any_runners? { |runner| runner.active? && runner.online? && can_be_served?(runner) }
end
 
def show_warning?
def stuck?
pending? && !any_runners_online?
end
 
Loading
Loading
@@ -348,18 +332,6 @@ module Ci
artifacts_file.exists?
end
 
def artifacts_download_url
if artifacts?
download_namespace_project_build_artifacts_path(project.namespace, project, self)
end
end
def artifacts_browse_url
if artifacts_metadata?
browse_namespace_project_build_artifacts_path(project.namespace, project, self)
end
end
def artifacts_metadata?
artifacts? && artifacts_metadata.exists?
end
Loading
Loading
Loading
Loading
@@ -25,8 +25,6 @@ module Ci
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
 
scope :ordered, -> { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }
validates_presence_of :sha
validate :valid_commit_sha
 
Loading
Loading
@@ -42,16 +40,6 @@ module Ci
project.id
end
 
def last_build
builds.order(:id).last
end
def retry
latest_builds.each do |build|
Ci::Build.retry(build)
end
end
def valid_commit_sha
if self.sha == Gitlab::Git::BLANK_SHA
self.errors.add(:sha, " cant be 00000000 (branch removal)")
Loading
Loading
@@ -121,12 +109,8 @@ module Ci
@latest_statuses ||= statuses.latest.to_a
end
 
def latest_builds
@latest_builds ||= builds.latest.to_a
end
def latest_builds_for_ref(ref)
latest_builds.select { |build| build.ref == ref }
def latest_statuses_for_ref(ref)
latest_statuses.select { |status| status.ref == ref }
end
 
def retried
Loading
Loading
@@ -170,7 +154,7 @@ module Ci
end
 
def duration
duration_array = latest_statuses.map(&:duration).compact
duration_array = statuses.map(&:duration).compact
duration_array.reduce(:+).to_i
end
 
Loading
Loading
@@ -183,16 +167,12 @@ module Ci
end
 
def coverage
coverage_array = latest_builds.map(&:coverage).compact
coverage_array = latest_statuses.map(&:coverage).compact
if coverage_array.size >= 1
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
end
end
 
def matrix_for_ref?(ref)
latest_builds_for_ref(ref).size > 1
end
def config_processor
return nil unless ci_yaml_file
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
Loading
Loading
@@ -218,10 +198,6 @@ module Ci
git_commit_message =~ /(\[ci skip\])/ if git_commit_message
end
 
def update_committed!
update!(committed_at: DateTime.now)
end
private
 
def save_yaml_error(error)
Loading
Loading
Loading
Loading
@@ -125,23 +125,7 @@ class CommitStatus < ActiveRecord::Base
end
end
 
def cancel_url
nil
end
def retry_url
nil
end
def show_warning?
def stuck?
false
end
def artifacts_download_url
nil
end
def artifacts_browse_url
nil
end
end
Loading
Loading
@@ -3,7 +3,7 @@ module Ci
def execute(project, opts)
sha = opts[:sha] || ref_sha(project, opts[:ref])
 
commit = project.ci_commits.ordered.find_by(sha: sha)
commit = project.ci_commits.find_by(sha: sha)
image_name = image_for_commit(commit)
 
image_path = Rails.root.join('public/ci', image_name)
Loading
Loading
Loading
Loading
@@ -33,7 +33,6 @@ class CreateCommitBuildsService
unless commit.skip_ci?
# Create builds for commit
tag = Gitlab::Git.tag_ref?(origin_ref)
commit.update_committed!
commit.create_builds(ref, tag, user)
end
 
Loading
Loading
Loading
Loading
@@ -4,13 +4,13 @@
= ci_status_with_icon(build.status)
 
%td.build-link
- if can?(current_user, :read_build, project) && build.target_url
= link_to build.target_url do
- if can?(current_user, :read_build, build.project)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do
%strong Build ##{build.id}
- else
%strong Build ##{build.id}
 
- if build.show_warning?
- if build.stuck?
%i.fa.fa-warning.text-warning
 
%td
Loading
Loading
@@ -18,11 +18,11 @@
= link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project), class: "monospace"
 
%td
= link_to build.short_sha, namespace_project_commit_path(project.namespace, project, build.sha), class: "monospace"
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace"
 
%td
- if build.ref
= link_to build.ref, namespace_project_commits_path(project.namespace, project, build.ref)
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref)
- else
.light none
 
Loading
Loading
@@ -61,13 +61,12 @@
%td
.pull-right
- if can?(current_user, :read_build, project) && build.artifacts?
= link_to build.artifacts_download_url, title: 'Download artifacts' do
= link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts' do
%i.fa.fa-download
- if can?(current_user, :update_build, build.project)
- if build.active?
- if build.cancel_url
= link_to build.cancel_url, method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retry_url
= link_to build.retry_url, method: :post, title: 'Retry' do
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry' do
%i.fa.fa-repeat
%tr.build
%td.status
= ci_status_with_icon(commit.status)
- if commit.running?
&middot;
= commit.stage
%td.build-link
= link_to ci_status_path(commit) do
%strong #{commit.short_sha}
%td.build-message
%span= truncate_first_line(commit.git_commit_message)
%td.build-branch
- unless @ref
%span
- commit.refs.each do |ref|
= link_to truncate(ref, length: 25), ci_project_path(@project, ref: ref)
%td.duration
- if commit.duration > 0
#{time_interval_in_words commit.duration}
%td.timestamp
- if commit.finished_at
%span #{time_ago_in_words commit.finished_at} ago
- if commit.coverage
%td.coverage
#{commit.coverage}%
Loading
Loading
@@ -55,7 +55,6 @@
%th Coverage
%th
 
- @builds.each do |build|
= render 'projects/commit_statuses/commit_status', commit_status: build, commit_sha: true, stage: true, coverage: @project.build_coverage_enabled?, allow_retry: true
= render @builds, commit_sha: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
 
= paginate @builds, theme: 'gitlab'
Loading
Loading
@@ -13,9 +13,10 @@
= link_to "merge request ##{merge_request.iid}", merge_request_path(merge_request)
 
#up-build-trace
- if @commit.matrix_for_ref?(@build.ref)
- builds = @build.commit.builds.similar(@build).latest.ordered.to_a
- if builds.size > 1
%ul.nav-links.no-top.no-bottom
- @commit.latest_builds_for_ref(@build.ref).each do |build|
- builds.each do |build|
%li{class: ('active' if build == @build) }
= link_to namespace_project_build_path(@project.namespace, @project, build) do
= ci_icon_for_status(build.status)
Loading
Loading
@@ -44,7 +45,7 @@
.pull-right
#{time_ago_with_tooltip(@build.finished_at) if @build.finished_at}
 
- if @build.show_warning?
- if @build.stuck?
- unless @build.any_runners_online?
.bs-callout.bs-callout-warning
%p
Loading
Loading
@@ -100,12 +101,12 @@
%h4.title Build artifacts
.center
.btn-group{ role: :group }
= link_to @build.artifacts_download_url, class: 'btn btn-sm btn-primary' do
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary' do
= icon('download')
Download
 
- if @build.artifacts_metadata?
= link_to @build.artifacts_browse_url, class: 'btn btn-sm btn-primary' do
= link_to browse_namespace_project_build_artifacts_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary' do
= icon('folder-open')
Browse
 
Loading
Loading
@@ -115,10 +116,10 @@
- if can?(current_user, :update_build, @project)
.center
.btn-group{ role: :group }
- if @build.cancel_url
= link_to "Cancel", @build.cancel_url, class: 'btn btn-sm btn-danger', method: :post
- elsif @build.retry_url
= link_to "Retry", @build.retry_url, class: 'btn btn-sm btn-primary', method: :post
- if @build.active?
= link_to "Cancel", cancel_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-danger', method: :post
- elsif @build.retryable?
= link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary', method: :post
 
- if @build.erasable?
= link_to erase_namespace_project_build_path(@project.namespace, @project, @build),
Loading
Loading
%tr.build
%td.status
- if can?(current_user, :read_build, build)
= link_to namespace_project_build_url(build.project.namespace, build.project, build), class: "ci-status ci-#{build.status}" do
= ci_icon_for_status(build.status)
= build.status
- else
= ci_status_with_icon(build.status)
%td.build-link
- if can?(current_user, :read_build, build)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do
%strong ##{build.id}
- else
%strong ##{build.id}
- if build.stuck?
%i.fa.fa-warning.text-warning
- if defined?(commit_sha) && commit_sha
%td
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace"
%td
- if build.ref
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref)
- else
.light none
- if defined?(runner) && runner
%td
- if build.try(:runner)
= runner_link(build.runner)
- else
.light none
- if defined?(stage) && stage
%td
= build.stage
%td
= build.name
.pull-right
- if build.tags.any?
- build.tags.each do |tag|
%span.label.label-primary
= tag
- if build.try(:trigger_request)
%span.label.label-info triggered
- if build.try(:allow_failure)
%span.label.label-danger allowed to fail
%td.duration
- if build.duration
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
%td.coverage
- if build.try(:coverage)
#{build.coverage}%
%td
.pull-right
- if can?(current_user, :read_build, build) && build.artifacts?
= link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts' do
%i.fa.fa-download
- if can?(current_user, :update_build, build)
- if build.active?
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry' do
%i.fa.fa-repeat
Loading
Loading
@@ -43,8 +43,8 @@
%th Coverage
%th
- @ci_commit.refs.each do |ref|
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
locals: { coverage: @ci_commit.project.build_coverage_enabled?, stage: true, allow_retry: true }
- builds = @ci_commit.statuses.for_ref(ref).latest.ordered
= render builds, coverage: @ci_commit.project.build_coverage_enabled?, stage: true, allow_retry: true
 
- if @ci_commit.retried.any?
.gray-content-block.second-block
Loading
Loading
@@ -64,5 +64,4 @@
- if @ci_commit.project.build_coverage_enabled?
%th Coverage
%th
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
locals: { coverage: @ci_commit.project.build_coverage_enabled?, stage: true }
= render @ci_commit.retried, coverage: @ci_commit.project.build_coverage_enabled?, stage: true
%tr.commit_status
%td.status
- if can?(current_user, :read_commit_status, commit_status) && commit_status.target_url
= link_to commit_status.target_url, class: "ci-status ci-#{commit_status.status}" do
= ci_icon_for_status(commit_status.status)
= commit_status.status
- else
= ci_status_with_icon(commit_status.status)
%td.commit_status-link
- if can?(current_user, :read_commit_status, commit_status) && commit_status.target_url
= link_to commit_status.target_url do
%strong ##{commit_status.id}
- else
%strong ##{commit_status.id}
- if commit_status.show_warning?
%i.fa.fa-warning.text-warning{data: { toggle: "tooltip" }, title: "This build is stuck, open it to know more"}
- if defined?(commit_sha) && commit_sha
%td
= link_to commit_status.short_sha, namespace_project_commit_path(commit_status.project.namespace, commit_status.project, commit_status.sha), class: "monospace"
%td
- if commit_status.ref
= link_to commit_status.ref, namespace_project_commits_path(commit_status.project.namespace, commit_status.project, commit_status.ref)
- else
.light none
- if defined?(runner) && runner
%td
- if commit_status.try(:runner)
= runner_link(commit_status.runner)
- else
.light none
- if defined?(stage) && stage
%td
= commit_status.stage
%td
= commit_status.name
.pull-right
- if commit_status.tags.any?
- commit_status.tags.each do |tag|
%span.label.label-primary
= tag
- if commit_status.try(:trigger_request)
%span.label.label-info triggered
- if commit_status.try(:allow_failure)
%span.label.label-danger allowed to fail
%td.duration
- if commit_status.duration
#{duration_in_words(commit_status.finished_at, commit_status.started_at)}
%td.timestamp
- if commit_status.finished_at
%span #{time_ago_with_tooltip(commit_status.finished_at)}
- if defined?(coverage) && coverage
%td.coverage
- if commit_status.try(:coverage)
#{commit_status.coverage}%
%td
.pull-right
- if can?(current_user, :read_commit_status, commit_status) && commit_status.artifacts_download_url
= link_to commit_status.artifacts_download_url, title: 'Download artifacts' do
%i.fa.fa-download
- if can?(current_user, :update_commit_status, commit_status)
- if commit_status.active?
- if commit_status.cancel_url
= link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && commit_status.retry_url
= link_to commit_status.retry_url, method: :post, title: 'Retry' do
%i.fa.fa-repeat
%tr.generic_commit_status
%td.status
- if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url
= link_to generic_commit_status.target_url, class: "ci-status ci-#{generic_commit_status.status}" do
= ci_icon_for_status(generic_commit_status.status)
= generic_commit_status.status
- else
= ci_status_with_icon(generic_commit_status.status)
%td.generic_commit_status-link
- if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url
= link_to generic_commit_status.target_url do
%strong ##{generic_commit_status.id}
- else
%strong ##{generic_commit_status.id}
- if defined?(commit_sha) && commit_sha
%td
= link_to generic_commit_status.short_sha, namespace_project_commit_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.sha), class: "monospace"
%td
- if generic_commit_status.ref
= link_to generic_commit_status.ref, namespace_project_commits_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.ref)
- else
.light none
- if defined?(runner) && runner
%td
- if generic_commit_status.try(:runner)
= runner_link(generic_commit_status.runner)
- else
.light none
- if defined?(stage) && stage
%td
= generic_commit_status.stage
%td
= generic_commit_status.name
.pull-right
- if generic_commit_status.tags.any?
- generic_commit_status.tags.each do |tag|
%span.label.label-primary
= tag
%td.duration
- if generic_commit_status.duration
#{duration_in_words(generic_commit_status.finished_at, generic_commit_status.started_at)}
%td.timestamp
- if generic_commit_status.finished_at
%span #{time_ago_with_tooltip(generic_commit_status.finished_at)}
- if defined?(coverage) && coverage
%td.coverage
- if generic_commit_status.try(:coverage)
#{generic_commit_status.coverage}%
%td
Loading
Loading
@@ -33,7 +33,6 @@ Example of response
},
"coverage": null,
"created_at": "2015-12-24T15:51:21.802Z",
"download_url": null,
"artifacts_file": {
"filename": "artifacts.zip",
"size": 1000
Loading
Loading
@@ -75,7 +74,6 @@ Example of response
},
"coverage": null,
"created_at": "2015-12-24T15:51:21.727Z",
"download_url": null,
"artifacts_file": null,
"finished_at": "2015-12-24T17:54:24.921Z",
"id": 6,
Loading
Loading
@@ -139,7 +137,6 @@ Example of response
},
"coverage": null,
"created_at": "2016-01-11T10:13:33.506Z",
"download_url": null,
"artifacts_file": null,
"finished_at": "2016-01-11T10:14:09.526Z",
"id": 69,
Loading
Loading
@@ -164,7 +161,6 @@ Example of response
},
"coverage": null,
"created_at": "2015-12-24T15:51:21.957Z",
"download_url": null,
"artifacts_file": null,
"finished_at": "2015-12-24T17:54:33.913Z",
"id": 9,
Loading
Loading
@@ -226,7 +222,6 @@ Example of response
},
"coverage": null,
"created_at": "2015-12-24T15:51:21.880Z",
"download_url": null,
"artifacts_file": null,
"finished_at": "2015-12-24T17:54:31.198Z",
"id": 8,
Loading
Loading
@@ -315,7 +310,6 @@ Example of response
},
"coverage": null,
"created_at": "2016-01-11T10:13:33.506Z",
"download_url": null,
"artifacts_file": null,
"finished_at": "2016-01-11T10:14:09.526Z",
"id": 69,
Loading
Loading
@@ -362,7 +356,6 @@ Example of response
},
"coverage": null,
"created_at": "2016-01-11T10:13:33.506Z",
"download_url": null,
"artifacts_file": null,
"finished_at": null,
"id": 69,
Loading
Loading
Loading
Loading
@@ -68,7 +68,7 @@ module SharedBuilds
end
 
step 'I see the build' do
page.within('.commit_status') do
page.within('.build') do
expect(page).to have_content "##{@build.id}"
expect(page).to have_content @build.sha[0..7]
expect(page).to have_content @build.ref
Loading
Loading
Loading
Loading
@@ -401,13 +401,6 @@ module API
expose :id, :status, :stage, :name, :ref, :tag, :coverage
expose :created_at, :started_at, :finished_at
expose :user, with: User
# TODO: download_url in Ci:Build model is an GitLab Web Interface URL, not API URL. We should think on some API
# for downloading of artifacts (see: https://gitlab.com/gitlab-org/gitlab-ce/issues/4255)
expose :download_url do |repo_obj, options|
if options[:user_can_download_artifacts]
repo_obj.artifacts_download_url
end
end
expose :artifacts_file, using: BuildArtifactFile, if: -> (build, opts) { build.artifacts? }
expose :commit, with: RepoCommit do |repo_obj, _options|
if repo_obj.respond_to?(:commit)
Loading
Loading
Loading
Loading
@@ -312,8 +312,8 @@ describe Ci::Build, models: true do
end
end
 
describe :show_warning? do
subject { build.show_warning? }
describe :stuck? do
subject { build.stuck? }
 
%w(pending).each do |state|
context "if commit_status.status is #{state}" do
Loading
Loading
@@ -343,34 +343,6 @@ describe Ci::Build, models: true do
end
end
 
describe :artifacts_download_url do
subject { build.artifacts_download_url }
context 'artifacts file does not exist' do
before { build.update_attributes(artifacts_file: nil) }
it { is_expected.to be_nil }
end
context 'artifacts file exists' do
let(:build) { create(:ci_build, :artifacts) }
it { is_expected.to_not be_nil }
end
end
describe :artifacts_browse_url do
subject { build.artifacts_browse_url }
it "should be nil if artifacts browser is unsupported" do
allow(build).to receive(:artifacts_metadata?).and_return(false)
is_expected.to be_nil
end
it 'should not be nil if artifacts browser is supported' do
allow(build).to receive(:artifacts_metadata?).and_return(true)
is_expected.to_not be_nil
end
end
describe :artifacts? do
subject { build.artifacts? }
 
Loading
Loading
Loading
Loading
@@ -23,7 +23,7 @@ describe Ci::Commit, models: true do
let(:commit) { FactoryGirl.create :ci_commit, project: project }
 
it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:statuses) }
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:builds) }
it { is_expected.to validate_presence_of :sha }
Loading
Loading
@@ -32,50 +32,6 @@ describe Ci::Commit, models: true do
it { is_expected.to respond_to :git_author_email }
it { is_expected.to respond_to :short_sha }
 
describe :ordered do
let(:project) { FactoryGirl.create :empty_project }
it 'returns ordered list of commits' do
commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit1])
end
it 'returns commits ordered by committed_at and id, with nulls last' do
commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
end
end
describe :last_build do
subject { commit.last_build }
before do
@first = FactoryGirl.create :ci_build, commit: commit, created_at: Date.yesterday
@second = FactoryGirl.create :ci_build, commit: commit
end
it { is_expected.to be_a(Ci::Build) }
it('returns with the most recently created build') { is_expected.to eq(@second) }
end
describe :retry do
before do
@first = FactoryGirl.create :ci_build, commit: commit, created_at: Date.yesterday
@second = FactoryGirl.create :ci_build, commit: commit
end
it "creates only a new build" do
expect(commit.builds.count(:all)).to eq 2
expect(commit.statuses.count(:all)).to eq 2
commit.retry
expect(commit.builds.count(:all)).to eq 3
expect(commit.statuses.count(:all)).to eq 3
end
end
describe :valid_commit_sha do
context 'commit.sha can not start with 00000000' do
before do
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment