Commit 7b25add3 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'group-similar' into 'master'

Group similar builds

We group builds by removing from the builds name two numbers which are delimited by whitespace or colon:
* `name 0 1` => `name`
* `name 0:1` => `name`
* `name 0/1` => `name`
* `name 0:1 ruby` => `name ruby`
* `name 0/1 ruby` => `name ruby`
* `0 1 name ruby` => `name ruby`
* `0:1 name ruby` => `name ruby`
* `0/1 name ruby` => `name ruby`

See merge request !6242
parents 247ae131 2f3dc314
...@@ -318,9 +318,17 @@ ...@@ -318,9 +318,17 @@
.build-content { .build-content {
width: 130px; width: 130px;
.ci-status-text {
width: 110px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
vertical-align: middle;
display: inline-block;
position: relative;
top: -1px;
}
a { a {
color: $layout-link-gray; color: $layout-link-gray;
...@@ -331,13 +339,74 @@ ...@@ -331,13 +339,74 @@
text-decoration: underline; text-decoration: underline;
} }
} }
}
.dropdown-menu-toggle {
border: none;
width: auto;
padding: 0;
color: $layout-link-gray;
.ci-status-text {
width: 80px;
}
}
.grouped-pipeline-dropdown {
padding: 8px 0;
width: 200px;
left: auto;
right: -214px;
top: -9px;
a:hover {
.ci-status-text {
text-decoration: none;
}
}
.ci-status-text {
width: 145px;
}
.arrow {
&:before,
&:after {
content: '';
display: inline-block;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 18px;
}
&:before {
left: -5px;
margin-top: -6px;
border-width: 7px 5px 7px 0;
border-right-color: $border-color;
}
&:after {
left: -4px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
border-right-color: $white-light;
}
}
}
.badge {
background-color: $gray-dark;
color: $layout-link-gray;
font-weight: normal;
} }
} }
svg { svg {
position: relative; vertical-align: middle;
top: 2px;
margin-right: 5px; margin-right: 5px;
} }
...@@ -442,7 +511,7 @@ ...@@ -442,7 +511,7 @@
width: 21px; width: 21px;
height: 25px; height: 25px;
position: absolute; position: absolute;
top: -28.5px; top: -29px;
border-top: 2px solid $border-color; border-top: 2px solid $border-color;
} }
......
...@@ -93,6 +93,10 @@ class CommitStatus < ActiveRecord::Base ...@@ -93,6 +93,10 @@ class CommitStatus < ActiveRecord::Base
pipeline.before_sha || Gitlab::Git::BLANK_SHA pipeline.before_sha || Gitlab::Git::BLANK_SHA
end end
def group_name
name.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip
end
def self.stages def self.stages
# We group by stage name, but order stages by theirs' index # We group by stage name, but order stages by theirs' index
unscoped.from(all, :sg).group('stage').order('max(stage_idx)', 'stage').pluck('sg.stage') unscoped.from(all, :sg).group('stage').order('max(stage_idx)', 'stage').pluck('sg.stage')
...@@ -111,6 +115,10 @@ class CommitStatus < ActiveRecord::Base ...@@ -111,6 +115,10 @@ class CommitStatus < ActiveRecord::Base
allow_failure? && (failed? || canceled?) allow_failure? && (failed? || canceled?)
end end
def playable?
false
end
def duration def duration
calculate_duration calculate_duration
end end
......
- is_playable = subject.playable? && can?(current_user, :update_build, @project) - is_playable = subject.playable? && can?(current_user, :update_build, @project)
%li.build{class: ("playable" if is_playable)} - if is_playable
.curve
.build-content
- if is_playable
= link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do
= render_status_with_link('build', 'play') = render_status_with_link('build', 'play')
%span.ci-status-text= subject.name .ci-status-text= subject.name
- elsif can?(current_user, :read_build, @project) - elsif can?(current_user, :read_build, @project)
= link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do
= render_status_with_link('build', subject.status) = render_status_with_link('build', subject.status)
%span.ci-status-text= subject.name .ci-status-text= subject.name
- else - else
= render_status_with_link('build', subject.status) = render_status_with_link('build', subject.status)
= ci_icon_for_status(subject.status) = ci_icon_for_status(subject.status)
...@@ -39,8 +39,7 @@ ...@@ -39,8 +39,7 @@
= stage.titleize = stage.titleize
.builds-container .builds-container
%ul %ul
- statuses.each do |status| = render "projects/commit/pipeline_stage", statuses: statuses
= render "projects/#{status.to_partial_path}_pipeline", subject: status
- if pipeline.yaml_errors.present? - if pipeline.yaml_errors.present?
......
- status_groups = statuses.group_by(&:group_name)
- status_groups.each do |group_name, grouped_statuses|
- if grouped_statuses.one?
- status = grouped_statuses.first
- is_playable = status.playable? && can?(current_user, :update_build, @project)
%li.build{ class: ("playable" if is_playable) }
.curve
.build-content
= render "projects/#{status.to_partial_path}_pipeline", subject: status
- else
%li.build
.curve
.build-content
= render "projects/commit/pipeline_status_group", name: group_name, subject: grouped_statuses
- group_status = CommitStatus.where(id: subject).status
= render_status_with_link('build', group_status)
.dropdown.inline
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } }
%span.ci-status-text
= name
%span.badge= subject.size
%ul.dropdown-menu.grouped-pipeline-dropdown
.arrow
- subject.each do |status|
= render "projects/#{status.to_partial_path}_pipeline", subject: status
%li.build - if subject.target_url
.curve = link_to subject.target_url do
.build-content
- if subject.target_url
- link_to subject.target_url do
= render_status_with_link('commit status', subject.status) = render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name %span.ci-status-text= subject.name
- else - else
= render_status_with_link('commit status', subject.status) = render_status_with_link('commit status', subject.status)
%span.ci-status-text= subject.name %span.ci-status-text= subject.name
...@@ -3,9 +3,13 @@ class Gitlab::Seeder::Pipelines ...@@ -3,9 +3,13 @@ class Gitlab::Seeder::Pipelines
BUILDS = [ BUILDS = [
{ name: 'build:linux', stage: 'build', status: :success }, { name: 'build:linux', stage: 'build', status: :success },
{ name: 'build:osx', stage: 'build', status: :success }, { name: 'build:osx', stage: 'build', status: :success },
{ name: 'rspec:linux', stage: 'test', status: :success }, { name: 'rspec:linux 0 3', stage: 'test', status: :success },
{ name: 'rspec:windows', stage: 'test', status: :success }, { name: 'rspec:linux 1 3', stage: 'test', status: :success },
{ name: 'rspec:windows', stage: 'test', status: :success }, { name: 'rspec:linux 2 3', stage: 'test', status: :success },
{ name: 'rspec:windows 0 3', stage: 'test', status: :success },
{ name: 'rspec:windows 1 3', stage: 'test', status: :success },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success },
{ name: 'rspec:osx', stage: 'test', status_event: :success }, { name: 'rspec:osx', stage: 'test', status_event: :success },
{ name: 'spinach:linux', stage: 'test', status: :success }, { name: 'spinach:linux', stage: 'test', status: :success },
{ name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true}, { name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true},
......
...@@ -223,4 +223,33 @@ describe CommitStatus, models: true do ...@@ -223,4 +223,33 @@ describe CommitStatus, models: true do
expect(commit_status.commit).to eq project.commit expect(commit_status.commit).to eq project.commit
end end
end end
describe '#group_name' do
subject { commit_status.group_name }
tests = {
'rspec:windows' => 'rspec:windows',
'rspec:windows 0' => 'rspec:windows 0',
'rspec:windows 0 test' => 'rspec:windows 0 test',
'rspec:windows 0 1' => 'rspec:windows',
'rspec:windows 0 1 name' => 'rspec:windows name',
'rspec:windows 0/1' => 'rspec:windows',
'rspec:windows 0/1 name' => 'rspec:windows name',
'rspec:windows 0:1' => 'rspec:windows',
'rspec:windows 0:1 name' => 'rspec:windows name',
'rspec:windows 10000 20000' => 'rspec:windows',
'rspec:windows 0 : / 1' => 'rspec:windows',
'rspec:windows 0 : / 1 name' => 'rspec:windows name',
'0 1 name ruby' => 'name ruby',
'0 :/ 1 name ruby' => 'name ruby'
}
tests.each do |name, group_name|
it "'#{name}' puts in '#{group_name}'" do
commit_status.name = name
is_expected.to eq(group_name)
end
end
end
end end
require 'spec_helper'
describe 'projects/pipelines/show' do
include Devise::TestHelpers
let(:project) { create(:project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id) }
before do
controller.prepend_view_path('app/views/projects')
create_build('build', 0, 'build')
create_build('test', 1, 'rspec 0:2')
create_build('test', 1, 'rspec 1:2')
create_build('test', 1, 'audit')
create_build('deploy', 2, 'production')
create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3)
assign(:project, project)
assign(:pipeline, pipeline)
allow(view).to receive(:can?).and_return(true)
end
it 'shows a graph with grouped stages' do
render
expect(rendered).to have_css('.pipeline-graph')
expect(rendered).to have_css('.grouped-pipeline-dropdown')
# stages
expect(rendered).to have_text('Build')
expect(rendered).to have_text('Test')
expect(rendered).to have_text('Deploy')
expect(rendered).to have_text('External')
# builds
expect(rendered).to have_text('rspec')
expect(rendered).to have_text('rspec 0:2')
expect(rendered).to have_text('production')
expect(rendered).to have_text('jenkins')
end
private
def create_build(stage, stage_idx, name)
create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment