Commit cae84aa2 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into category-search-dropdown

parents 57ec290f 53498e42
This diff is collapsed.
......@@ -2,10 +2,14 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.9.0 (unreleased)
- Bulk assign/unassign labels to issues.
- Ability to prioritize labels !4009 / !3205 (Thijs Wouters)
- Fix endless redirections when accessing user OAuth applications when they are disabled
- Allow enabling wiki page events from Webhook management UI
- Bump rouge to 1.11.0
- Make EmailsOnPushWorker use Sidekiq mailers queue
- Fix wiki page events' webhook to point to the wiki repository
- Fix issue todo not remove when leave project !4150 (Long Nguyen)
- Bump recaptcha gem to 3.0.0 to remove deprecated stoken support
- Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API
- Reduce number of fog gem dependencies
......@@ -14,7 +18,9 @@ v 8.9.0 (unreleased)
- Redesign navigation for project pages
- Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails
- Bump nokogiri to 1.6.8
- Use gitlab-shell v3.0.0
- Use Knapsack to evenly distribute tests across multiple nodes
- Add `sha` parameter to MR merge API, to ensure only reviewed changes are merged
- Don't allow MRs to be merged when commits were added since the last review / page load
- Add DB index on users.state
......@@ -33,7 +39,9 @@ v 8.9.0 (unreleased)
- Make authentication service for Container Registry to be compatible with < Docker 1.11
- Add Application Setting to configure Container Registry token expire delay (default 5min)
- Cache assigned issue and merge request counts in sidebar nav
- Use Knapsack only in CI environment
- Cache project build count in sidebar nav
- Fix markdown_spec to use before instead of before(:all) to properly cleanup database after testing
- Reduce number of queries needed to render issue labels in the sidebar
- Improve error handling importing projects
- Remove duplicated notification settings
......@@ -41,6 +49,7 @@ v 8.9.0 (unreleased)
- Replace Colorize with Rainbow for coloring console output in Rake tasks.
- An indicator is now displayed at the top of the comment field for confidential issues.
- Show categorised search queries in the search autocomplete
- RepositoryCheck::SingleRepositoryWorker public and private methods are now instrumented
v 8.8.4 (unreleased)
- Ensure branch cleanup regardless of whether the GitHub import process succeeds
......@@ -49,6 +58,10 @@ v 8.8.4 (unreleased)
- Reduce number of SQL queries when rendering user references
- Upgrade to jQuery 2
- Remove prev/next buttons on issues and merge requests
- Import GitHub repositories respecting the API rate limit
- Fix importer for GitHub comments on diff
- Disable Webhooks before proceeding with the GitHub import
- Added descriptions to notification settings dropdown
v 8.8.3
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312
......@@ -169,6 +182,7 @@ v 8.7.6
- Fix import from GitLab.com to a private instance failure. !4181
- Fix external imports not finding the import data. !4106
- Fix notification delay when changing status of an issue
- Bump Workhorse to 0.7.5 so it can serve raw diffs
v 8.7.5
- Fix relative links in wiki pages. !4050
......
......@@ -405,6 +405,7 @@ description area. Copy-paste it to retain the markdown format.
entire line to follow it. This prevents linting tools from generating warnings.
- Don't touch neighbouring lines. As an exception, automatic mass
refactoring modifications may leave style non-compliant.
1. If the merge request adds any new libraries (gems, JavaScript libraries, etc.), they should conform to our [Licensing guidelines][license-finder-doc]. See the instructions in that document for help if your MR fails the "license-finder" test with a "Dependencies that need approval" error.
## Changes for Stable Releases
......@@ -531,3 +532,4 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
[license-finder-doc]: doc/development/licensing.md
......@@ -38,7 +38,7 @@ gem 'rack-oauth2', '~> 1.2.1'
gem 'jwt'
# Spam and anti-bot protection
gem 'recaptcha', require: 'recaptcha/rails'
gem 'recaptcha', '~> 3.0', require: 'recaptcha/rails'
gem 'akismet', '~> 2.0'
# Two-factor authentication
......@@ -86,6 +86,7 @@ gem 'dropzonejs-rails', '~> 0.7.1'
# for backups
gem 'fog-aws', '~> 0.9'
gem 'fog-azure', '~> 0.0'
gem 'fog-core', '~> 1.40'
gem 'fog-local', '~> 0.3'
gem 'fog-google', '~> 0.3'
......@@ -111,7 +112,7 @@ gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.10.1'
gem 'rouge', '~> 1.11'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
......@@ -306,6 +307,9 @@ group :development, :test do
gem 'bundler-audit', require: false
gem 'benchmark-ips', require: false
gem "license_finder", require: false
gem 'knapsack'
end
group :test do
......
......@@ -70,6 +70,21 @@ GEM
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
azure (0.7.5)
addressable (~> 2.3)
azure-core (~> 0.1)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
json (~> 1.8)
mime-types (>= 1, < 3.0)
nokogiri (~> 1.6)
systemu (~> 2.6)
thor (~> 0.19)
uuid (~> 2.0)
azure-core (0.1.2)
faraday (~> 0.9)
faraday_middleware (~> 0.10)
nokogiri (~> 1.6)
babosa (1.0.2)
base32 (0.3.2)
bcrypt (3.1.11)
......@@ -213,6 +228,11 @@ GEM
fog-json (~> 1.0)
fog-xml (~> 0.1)
ipaddress (~> 0.8)
fog-azure (0.0.2)
azure (~> 0.6)
fog-core (~> 1.27)
fog-json (~> 1.0)
fog-xml (~> 0.1)
fog-core (1.40.0)
builder
excon (~> 0.49)
......@@ -358,6 +378,9 @@ GEM
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
kgio (2.10.0)
knapsack (1.11.0)
rake
timecop (>= 0.1.0)
launchy (2.4.3)
addressable (~> 2.3)
letter_opener (1.4.1)
......@@ -366,6 +389,12 @@ GEM
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
license_finder (2.1.0)
bundler
httparty
rubyzip
thor
xml-simple
licensee (8.0.0)
rugged (>= 0.24b)
listen (3.0.5)
......@@ -381,7 +410,7 @@ GEM
method_source (0.8.2)
mime-types (2.99.1)
mimemagic (0.3.0)
mini_portile2 (2.0.0)
mini_portile2 (2.1.0)
minitest (5.7.0)
mousetrap-rails (1.4.6)
multi_json (1.11.2)
......@@ -392,8 +421,9 @@ GEM
net-ldap (0.12.1)
net-ssh (3.0.1)
newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
nokogiri (1.6.8)
mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7)
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
......@@ -465,6 +495,7 @@ GEM
parser (2.3.1.0)
ast (~> 2.2)
pg (0.18.4)
pkg-config (1.1.7)
poltergeist (1.9.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
......@@ -540,7 +571,7 @@ GEM
debugger-ruby_core_source (~> 1.3)
rdoc (3.12.2)
json (~> 1.4)
recaptcha (1.0.2)
recaptcha (3.0.0)
json
redcarpet (3.3.3)
redis (3.3.0)
......@@ -569,7 +600,7 @@ GEM
railties (>= 4.2.0, < 5.1)
rinku (1.7.3)
rotp (2.1.2)
rouge (1.10.1)
rouge (1.11.0)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
......@@ -618,6 +649,7 @@ GEM
sexp_processor (~> 4.1)
rubyntlm (0.5.2)
rubypants (0.2.0)
rubyzip (1.2.0)
rufus-scheduler (3.1.10)
rugged (0.24.0)
safe_yaml (1.0.4)
......@@ -728,6 +760,7 @@ GEM
thor (0.19.1)
thread_safe (0.3.5)
tilt (2.0.2)
timecop (0.8.1)
timfel-krb5-auth (0.8.3)
tinder (1.10.1)
eventmachine (~> 1.0)
......@@ -789,6 +822,7 @@ GEM
builder
expression_parser
rinku
xml-simple (1.1.5)
xpath (2.0.0)
nokogiri (~> 1.3)
......@@ -842,6 +876,7 @@ DEPENDENCIES
flay
flog
fog-aws (~> 0.9)
fog-azure (~> 0.0)
fog-core (~> 1.40)
fog-google (~> 0.3)
fog-local (~> 0.3)
......@@ -874,7 +909,9 @@ DEPENDENCIES
jquery-ui-rails (~> 5.0.0)
jwt
kaminari (~> 0.17.0)
knapsack
letter_opener_web (~> 1.3.0)
license_finder
licensee (~> 8.0.0)
loofah (~> 2.0.3)
mail_room (~> 0.7)
......@@ -918,7 +955,7 @@ DEPENDENCIES
raphael-rails (~> 2.1.2)
rblineprof
rdoc (~> 3.6)
recaptcha
recaptcha (~> 3.0)
redcarpet (~> 3.3.3)
redis (~> 3.2)
redis-namespace
......@@ -926,7 +963,7 @@ DEPENDENCIES
request_store (~> 1.3.0)
rerun (~> 0.11.0)
responders (~> 2.0)
rouge (~> 1.10.1)
rouge (~> 1.11)
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.4.0)
rspec-retry
......
......@@ -8,3 +8,5 @@ relative_url_conf = File.expand_path('../config/initializers/relative_url', __FI
require relative_url_conf if File.exist?("#{relative_url_conf}.rb")
Gitlab::Application.load_tasks
Knapsack.load_tasks if defined?(Knapsack)
class @LabelManager
errorMessage: 'Unable to update label prioritization at this time'
constructor: (opts = {}) ->
# Defaults
{
@togglePriorityButton = $('.js-toggle-priority')
@prioritizedLabels = $('.js-prioritized-labels')
@otherLabels = $('.js-other-labels')
} = opts
@prioritizedLabels.sortable(
items: 'li'
placeholder: 'list-placeholder'
axis: 'y'
update: @onPrioritySortUpdate.bind(@)
)
@bindEvents()
bindEvents: ->
@togglePriorityButton.on 'click', @, @onTogglePriorityClick
onTogglePriorityClick: (e) ->
e.preventDefault()
_this = e.data
$btn = $(e.currentTarget)
$label = $("##{$btn.data('domId')}")
action = if $btn.parents('.js-prioritized-labels').length then 'remove' else 'add'
_this.toggleLabelPriority($label, action)
toggleLabelPriority: ($label, action, persistState = true) ->
_this = @
url = $label.find('.js-toggle-priority').data 'url'
$target = @prioritizedLabels
$from = @otherLabels
# Optimistic update
if action is 'remove'
$target = @otherLabels
$from = @prioritizedLabels
if $from.find('li').length is 1
$from.find('.empty-message').show()
if not $target.find('li').length
$target.find('.empty-message').hide()
$label.detach().appendTo($target)
# Return if we are not persisting state
return unless persistState
if action is 'remove'
xhr = $.ajax url: url, type: 'DELETE'
else
xhr = @savePrioritySort($label, action)
xhr.fail @rollbackLabelPosition.bind(@, $label, action)
onPrioritySortUpdate: ->
xhr = @savePrioritySort()
xhr.fail ->
new Flash(@errorMessage, 'alert')
savePrioritySort: () ->
$.post
url: @prioritizedLabels.data('url')
data:
label_ids: @getSortedLabelsIds()
rollbackLabelPosition: ($label, originalAction)->
action = if originalAction is 'remove' then 'add' else 'remove'
@toggleLabelPriority($label, action, false)
new Flash(@errorMessage, 'alert')
getSortedLabelsIds: ->
sortedIds = []
@prioritizedLabels.find('li').each ->
sortedIds.push $(@).data 'id'
sortedIds
......@@ -100,6 +100,8 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
when 'projects:labels:new', 'projects:labels:edit'
new Labels()
when 'projects:labels:index'
new LabelManager() if $('.prioritized-labels').length
when 'projects:network:show'
# Ensure we don't create a particular shortcut handler here. This is
# already created, where the network graph is created.
......
......@@ -211,6 +211,7 @@ class GitLabDropdown
@dropdown.on "shown.bs.dropdown", @opened
@dropdown.on "hidden.bs.dropdown", @hidden
$(@el).on "update.label", @updateLabel
@dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate
@dropdown.on 'keyup', (e) =>
if e.which is 27 # Escape key
......@@ -453,7 +454,7 @@ class GitLabDropdown
# Toggle the dropdown label
if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel
@updateLabel()
else
selectedObject
else if el.hasClass(INDETERMINATE_CLASS)
......@@ -480,7 +481,7 @@ class GitLabDropdown
# Toggle the dropdown label
if @options.toggleLabel
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject, el)
@updateLabel(selectedObject, el)
if value?
if !field.length and fieldName
@addInput(fieldName, value)
......@@ -579,6 +580,9 @@ class GitLabDropdown
# Scroll the dropdown content up
$dropdownContent.scrollTop(listItemTop - dropdownContentTop)
updateLabel: (selected = null, el = null) =>
$(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selected, el)
$.fn.glDropdown = (opts) ->
return @.each ->
if (!$.data @, 'glDropdown')
......
......@@ -6,12 +6,18 @@ issuable_created = false
Issuable.initTemplates()
Issuable.initSearch()
Issuable.initChecks()
Issuable.initLabelFilterRemove()
initTemplates: ->
Issuable.labelRow = _.template(
'<% _.each(labels, function(label){ %>
<span class="label-row">
<a href="#"><span class="label color-label has-tooltip" style="background-color: <%= label.color %>; color: <%= label.text_color %>" title="<%= _.escape(label.description) %>" data-container="body"><%= _.escape(label.title) %></span></a>
<span class="label-row btn-group" role="group" aria-label="<%= _.escape(label.title) %>" style="color: <%= label.text_color %>;">
<a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%= label.color %>;" title="<%= _.escape(label.description) %>" data-container="body">
<%= _.escape(label.title) %>
</a>
<button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%= label.color %>;" data-label="<%= _.escape(label.title) %>">
<i class="fa fa-times"></i>
</button>
</span>
<% }); %>'
)
......@@ -35,6 +41,21 @@ issuable_created = false
Issuable.filterResults $form
, 500)
initLabelFilterRemove: ->
$(document)
.off 'click', '.js-label-filter-remove'
.on 'click', '.js-label-filter-remove', (e) ->
$button = $(@)
# Remove the label input box
$('input[name="label_name[]"]')
.filter -> @value is $button.data('label')
.remove()
# Submit the form to get new data
Issuable.filterResults $('.filter-form')
$('.js-label-select').trigger('update.label')
toggleLabelFilters: ->
$filteredLabels = $('.filtered-labels')
if $filteredLabels.find('.label-row').length > 0
......
......@@ -61,6 +61,11 @@
margin-bottom: -$gl-padding;
}
&.content-component-block {
padding: 11px 0;
background-color: $white-light;
}
.title {
color: $gl-text-color;
}
......
......@@ -122,10 +122,8 @@
a {
display: block;
position: relative;
padding-left: 10px;
padding-right: 10px;
padding: 5px 10px;
color: $dropdown-link-color;
line-height: 34px;
text-overflow: ellipsis;
border-radius: 2px;
white-space: nowrap;
......@@ -162,6 +160,16 @@
}
}
.dropdown-menu-large {
width: 340px;
}
.dropdown-menu-no-wrap {
a {
white-space: normal;
}
}
.dropdown-menu-full-width {
width: 100%;
}
......@@ -236,8 +244,7 @@
&::before {
position: absolute;
left: 5px;
top: 50%;
margin-top: -7px;
top: 8px;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
......@@ -532,3 +539,14 @@
background-color: $calendar-unselectable-bg;
}
}
.dropdown-menu-inner-title {
display: block;
color: $gl-title-color;
font-weight: 600;
}
.dropdown-menu-inner-content {
display: block;
color: $gl-placeholder-color;
}
......@@ -89,8 +89,11 @@
}
}
$theme-blue: #2980b9;
$theme-charcoal: #3d454d;
$theme-charcoal-dark: #383f45;
$theme-charcoal-text: #b9bbbe;
$theme-blue: #2980b9;
$theme-graphite: #666;
$theme-gray: #373737;
$theme-green: #019875;
......@@ -102,7 +105,7 @@ body {
}
&.ui_charcoal {
@include gitlab-theme(#d6d7d9, #485157, $theme-charcoal, #353b41);
@include gitlab-theme($theme-charcoal-text, #485157, $theme-charcoal, $theme-charcoal-dark);
}
&.ui_graphite {
......
......@@ -79,6 +79,10 @@ header {
&.header-collapsed {
padding: 0 16px;
.side-nav-toggle {
display: block;
}
}
.side-nav-toggle {
......@@ -86,6 +90,7 @@ header {
position: absolute;
left: -10px;
margin: 6px 0;
font-size: 18px;
padding: 6px 10px;
border: none;
background-color: $background-color;
......@@ -97,10 +102,6 @@ header {
&:focus {
outline: none;
}
@media (max-width: $screen-xs-min) {
display: block;
}
}
}
......@@ -171,31 +172,21 @@ header {
}
}
@mixin collapsed-header {
margin-left: $sidebar_collapsed_width;
}
.header-collapsed {
margin-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) {
@include collapsed-header;
}
margin-left: 0;
@media (max-width: $screen-xs-min) {
margin-left: 0;
.header-content {
padding-left: 30px;
transition-duration: .3s;
}
}
.header-expanded {
margin-left: $sidebar_collapsed_width;
margin-left: 0;
@media (min-width: $screen-md-min) {
margin-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) {
margin-left: 0;
.header-content {
padding-left: $sidebar_width;
transition-duration: .3s;
}
}
......
......@@ -141,6 +141,18 @@ ul.content-list {
padding: 10px 14px;
}
}
// When dragging a list item
&.ui-sortable-helper {
border-bottom: none;
}
&.list-placeholder {
background-color: $gray-light;
border: dotted 1px $gray-dark;
margin: 1px 0;
min-height: 30px;
}
}
}
......
......@@ -41,8 +41,7 @@
a {
display: inline-block;
padding: 14px;
padding-top: $gl-padding;
padding: $gl-btn-padding;
padding-bottom: 11px;
margin-bottom: -1px;
font-size: 15px;
......@@ -67,6 +66,27 @@
color: #78a;
}
}
&.sub-nav {
background-color: $background-color;
.container-fluid {
background-color: $background-color;
}
li {
a {
margin: 0;
padding: 11px 10px 9px;
}
&.active a {
border-bottom: none;
color: $link-underline-blue;
}
}
}
}
.top-area {
......@@ -81,6 +101,10 @@
width: 50%;
line-height: 28px;
&.wiki-page {
padding: 16px 10px 11px;
}
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-min) {
width: 100%;
......@@ -104,6 +128,10 @@
margin-bottom: 0;
border-bottom: none;
li a {
padding: 16px 10px 11px;
}
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-sm-max) {
width: 100%;
......@@ -309,8 +337,8 @@
}
.nav-control {
.fade-right {
.fade-right {
@media (min-width: $screen-xs-max) {
right: 67px;
}
......@@ -321,6 +349,24 @@
}
}
.scrolling-tabs-container {
position: relative;
.nav-links {
@include scrolling-links();
.fade-right {
@include fade(left, rgba(255, 255, 255, 0.4), $background-color);
right: 0;
}
.fade-left {
@include fade(right, rgba(255, 255, 255, 0.4), $background-color);
left: 0;
}
}
}
.nav-block {
position: relative;
......
#logo {
z-index: 2;
position: absolute;
width: 58px;
cursor: pointer;
margin-top: 8px;
}
.page-with-sidebar {
padding-top: $header-height;
transition-duration: .3s;
......@@ -20,12 +12,6 @@
height: 100%;
transition-duration: .3s;
}
.gitlab-text-container-link {
z-index: 1;
position: absolute;
left: 0;
}
}
.sidebar-wrapper {
......@@ -50,47 +36,8 @@
.sidebar-wrapper {
.header-logo {
border-bottom: 1px solid transparent;
float: left;
height: $header-height;
width: $sidebar_width;
position: fixed;
z-index: 999;
overflow: hidden;
transition-duration: .3s;
a {
float: left;
height: $header-height;
width: 100%;
padding-left: 22px;
overflow: hidden;
outline: none;
transition-duration: .3s;
img {
width: 36px;
height: 36px;
}
#tanuki-logo, img {
float: left;
}
.gitlab-text-container {
width: 230px;
h3 {
width: 158px;
float: left;
margin: 0;
margin-left: 50px;
font-size: 19px;
line-height: 50px;
font-weight: normal;
}
}
}
padding: 8px 26px;
&:hover {
background-color: #eee;
......@@ -98,7 +45,7 @@
}
.sidebar-user {
padding: 7px 22px;
padding: 15px 22px;
position: fixed;
bottom: 40px;
width: $sidebar_width;
......@@ -126,8 +73,7 @@
.nav-sidebar {
margin-top: 14 + $header-height;
margin-bottom: 100px;
margin: 22px 0;
transition-duration: .3s;
list-style: none;
overflow: hidden;
......@@ -145,13 +91,12 @@
}
a {
padding: 7px 15px;
text-align: center;
padding: 8px;
font-size: $gl-font-size;
line-height: 24px;
color: $gray;
display: block;
text-decoration: none;
padding-left: 23px;
font-weight: normal;
outline: none;
......@@ -166,14 +111,12 @@
i {
width: 16px;
color: $gray-light;
margin-right: 13px;
}
.count {
float: right;
background: #eee;
padding: 0 8px;
@include border-radius(6px);
.nav-link-text {
margin-top: 3px;
font-size: 13px;
line-height: 18px;
}
&.back-link i {
......@@ -217,25 +160,13 @@
}
.page-sidebar-collapsed {
padding-left: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-left: 0;
}
padding-left: 0;
.sidebar-wrapper {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
width: 0;
.header-logo {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
width: 0;
a {
padding-left: ($sidebar_collapsed_width - 36) / 2;
......@@ -246,6 +177,10 @@
}
}
#logo {
display: none;
}
.nav-sidebar {
width: $sidebar_collapsed_width;
......@@ -261,44 +196,23 @@
}
.collapse-nav a {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
width: 0;
}
.sidebar-user {
padding-left: ($sidebar_collapsed_width - 36) / 2;
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
padding-left: 0;
padding-right: 0;
}
width: 0;
padding-left: 0;
padding-right: 0;
.username {
display: none;
}
}
}
.layout-nav {
padding-right: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-right: 0;;
}
}
}
.page-sidebar-expanded {
padding-left: $sidebar_collapsed_width;
@media (min-width: $screen-md-min) {
padding-left: $sidebar_width;
}
padding-left: $sidebar_width;
@media (max-width: $screen-xs-min) {
padding-left: 0;
......@@ -328,7 +242,7 @@
}
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
padding-right: 62px;
padding-right: 90px;
}
@media (min-width: $screen-md-min) {
......
......@@ -2,7 +2,7 @@
* Layout
*/
$sidebar_collapsed_width: 62px;
$sidebar_width: 220px;
$sidebar_width: 90px;
$gutter_collapsed_width: 62px;
$gutter_width: 290px;
$gutter_inner_width: 258px;
......
@import "framework/variables";
// This file is largely copied from `highlight/white.scss`, but modified to
// avoid all descendant selectors (`table td`). This is because the CSS inlining
// we use performs dramatically worse on descendant selectors than the
// alternatives.
// <https://gitlab.com/gitlab-org/gitlab-ee/issues/490#note_12283632>
//
// DO NOT ADD ANY DESCENDANT SELECTORS TO THIS FILE. Instead, use (in order of
// preference): plain class selectors, type (element name) selectors, or
// explicit child selectors.
table.code {
width: 100%;
font-family: monospace;
......@@ -11,33 +21,162 @@ table.code {
-premailer-cellspacing: 0;
-premailer-width: 100%;
td {
> tr > td {
line-height: $code_line_height;
font-family: monospace;
font-size: $code_font_size;
&.diff-line-num {
margin: 0;
padding: 0;
border: none;
padding: 0 5px;
border-right: 1px solid;
text-align: right;
min-width: 35px;
max-width: 50px;
width: 35px;
}
&.line_content {
display: block;
margin: 0;
padding: 0 0.5em;
border: none;
white-space: pre;
}
}
}
.line-numbers, .diff-line-num {
background-color: $background-color;
}
.diff-line-num, .diff-line-num a {
color: $black-transparent;
}
td.diff-line-num {
margin: 0;
padding: 0;
border: none;
background: $background-color;
color: rgba(0, 0, 0, 0.3);
padding: 0 5px;
border-right: 1px solid $border-color;
text-align: right;
min-width: 35px;
max-width: 50px;
width: 35px;
pre.code, .diff-line-num {
border-color: $table-border-gray;
}
.code.white, pre.code, .line_content {
background-color: #fff;
color: #333;
}
.diff-line-num {
&.old {
background-color: $line-number-old;
border-color: $line-removed-dark;
}
td.line_content {
display: block;
margin: 0;
padding: 0 0.5em;
border: none;
white-space: pre;
&.new {
background-color: $line-number-new;
border-color: $line-added-dark;
}
&.hll:not(.empty-cell) {
background-color: $line-number-select;
border-color: $line-select-yellow-dark;
}
}
.line_content {
&.old {
background-color: $line-removed;
> .line > span.idiff, > .line > span > span.idiff {
background-color: $line-removed-dark;
}
}
&.new {
background-color: $line-added;
> .line > span.idiff, > .line > span > span.idiff {
background-color: $line-added-dark;
}
}
&.match {
color: $black-transparent;
background-color: $match-line;
}
&.hll:not(.empty-cell) {
background-color: $line-select-yellow;
}
}
pre > .hll {
background-color: #f8eec7 !important;
}
span.highlight_word {
background-color: #fafe3d !important;
}
@import "highlight/white";
.hll { background-color: #f8f8f8 }
.c { color: #998; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
.k { font-weight: bold; }
.o { font-weight: bold; }
.cm { color: #998; font-style: italic; }
.cp { color: #999; font-weight: bold; }
.c1 { color: #998; font-style: italic; }
.cs { color: #999; font-weight: bold; font-style: italic; }
.gd { color: #000; background-color: #fdd; }
.gd .x { color: #000; background-color: #faa; }
.ge { font-style: italic; }
.gr { color: #a00; }
.gh { color: #999; }
.gi { color: #000; background-color: #dfd; }
.gi .x { color: #000; background-color: #afa; }
.go { color: #888; }
.gp { color: #555; }
.gs { font-weight: bold; }
.gu { color: #800080; font-weight: bold; }
.gt { color: #a00; }
.kc { font-weight: bold; }
.kd { font-weight: bold; }
.kn { font-weight: bold; }
.kp { font-weight: bold; }
.kr { font-weight: bold; }
.kt { color: #458; font-weight: bold; }
.m { color: #099; }
.s { color: #d14; }
.n { color: #333; }
.na { color: teal; }
.nb { color: #0086b3; }
.nc { color: #458; font-weight: bold; }
.no { color: teal; }
.ni { color: purple; }
.ne { color: #900; font-weight: bold; }
.nf { color: #900; font-weight: bold; }
.nn { color: #555; }
.nt { color: navy; }
.nv { color: teal; }
.ow { font-weight: bold; }
.w { color: #bbb; }
.mf { color: #099; }
.mh { color: #099; }
.mi { color: #099; }
.mo { color: #099; }
.sb { color: #d14; }
.sc { color: #d14; }
.sd { color: #d14; }
.s2 { color: #d14; }
.se { color: #d14; }
.sh { color: #d14; }
.si { color: #d14; }
.sx { color: #d14; }
.sr { color: #009926; }
.s1 { color: #d14; }
.ss { color: #990073; }
.bp { color: #999; }
.vc { color: teal; }
.vg { color: teal; }
.vi { color: teal; }
.il { color: #099; }
.gc { color: #999; background-color: #eaf2f5; }
......@@ -6,19 +6,19 @@ p.details {
font-style: italic;
color: #777
}
.footer p {
.footer > p {
font-size: small;
color: #777
}
pre.commit-message {
white-space: pre-wrap;
}
.file-stats a {
.file-stats > a {
text-decoration: none;
}
.file-stats .new-file {
color: #090;
}
.file-stats .deleted-file {
color: #b00;
> .new-file {
color: #090;
}
> .deleted-file {
color: #b00;
}
}
......@@ -51,7 +51,7 @@
.label-row {
.label-name {
display: inline-block;
width: 200px;
width: 170px;
@media (max-width: $screen-xs-min) {
display: block;
......@@ -138,3 +138,51 @@
}
}
}
.prioritized-labels {
margin-bottom: 30px;
.add-priority {
display: none;
color: $gray-light;
}
}
.other-labels {
.remove-priority {
display: none;
}
}
.toggle-priority {
display: inline-block;
vertical-align: middle;
button {
border-color: transparent;
padding: 5px 8px;
vertical-align: top;
font-size: 14px;
&:hover {
border-color: transparent;
}
}
}
.filtered-labels {
.label-row {
&:not(:last-child) {
margin-right: 5px;
}
}
.label-remove {
border-left: 1px solid rgba(0, 0, 0, .1);
z-index: 3;
}
.btn {
color: inherit;
}
}
......@@ -79,11 +79,14 @@
}
&.ci-failed,
&.ci-canceled,
&.ci-error {
color: $gl-danger;
}
&.ci-canceled {
color: $gl-gray;
}
a.monospace {
color: inherit;
}
......
......@@ -32,6 +32,15 @@
.container-fluid {
position: relative;
@media (min-width: $screen-md-max) {
.row {
display: flex;
-ms-flex-align: center;
-webkit-align-items: center;
-webkit-box-align: center;
}
}
}
.cover-controls {
......@@ -57,7 +66,6 @@
max-width: 86px;
min-width: 86px;
padding-right: 0;
margin: 11px 0;
@media (max-width: $screen-md-max) {
padding-left: 0;
......@@ -489,9 +497,11 @@ pre.light-well {
margin: 0;
}
.project-show-activity {
.activity-filter-block {
margin-top: -1px;
.activity-filter-block {
.controls {
padding-bottom: 10px;
border-bottom: 1px solid $border-color;
}
}
......
......@@ -42,46 +42,8 @@ class JwtController < ApplicationController
end
def authenticate_user(login, password)
# TODO: this is a copy and paste from grack_auth,
# it should be refactored in the future
user = Gitlab::Auth.new.find(login, password)
# If the user authenticated successfully, we reset the auth failure count
# from Rack::Attack for that IP. A client may attempt to authenticate
# with a username and blank password first, and only after it receives
# a 401 error does it present a password. Resetting the count prevents
# false positives from occurring.
#
# Otherwise, we let Rack::Attack know there was a failed authentication
# attempt from this IP. This information is stored in the Rails cache
# (Redis) and will be used by the Rack::Attack middleware to decide
# whether to block requests from this IP.
config = Gitlab.config.rack_attack.git_basic_auth
if config.enabled
if user
# A successful login will reset the auth failure count from this IP
Rack::Attack::Allow2Ban.reset(request.ip, config)
else
banned = Rack::Attack::Allow2Ban.filter(request.ip, config) do
# Unless the IP is whitelisted, return true so that Allow2Ban
# increments the counter (stored in Rails.cache) for the IP
if config.ip_whitelist.include?(request.ip)
false
else
true
end
end
if banned
Rails.logger.info "IP #{request.ip} failed to login " \
"as #{login} but has been temporarily banned from Git auth"
return
end
end
end
user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password)
Gitlab::Auth.rate_limit!(request.ip, success: user.present?, login: login)
user
end
end
......@@ -32,7 +32,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
def verify_user_oauth_applications_enabled
return if current_application_settings.user_oauth_applications?
redirect_to applications_profile_url
redirect_to profile_path
end
def set_index_vars
......
......@@ -26,9 +26,9 @@ class Projects::BuildsController < Projects::ApplicationController
end
def show
@builds = @project.ci_commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @project.pipelines.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit
@pipeline = @build.pipeline
respond_to do |format|
format.html
......
......@@ -99,12 +99,12 @@ class Projects::CommitController < Projects::ApplicationController
@commit ||= @project.commit(params[:id])
end
def ci_commits
@ci_commits ||= project.ci_commits.where(sha: commit.sha)
def pipelines
@pipelines ||= project.pipelines.where(sha: commit.sha)
end
def ci_builds
@ci_builds ||= Ci::Build.where(commit: ci_commits)
@ci_builds ||= Ci::Build.where(pipeline: pipelines)
end
def define_show_vars
......@@ -117,8 +117,8 @@ class Projects::CommitController < Projects::ApplicationController
@diff_refs = [commit.parent || commit, commit]
@notes_count = commit.notes.count
@statuses = CommitStatus.where(commit: ci_commits)
@builds = Ci::Build.where(commit: ci_commits)
@statuses = CommitStatus.where(pipeline: pipelines)
@builds = Ci::Build.where(pipeline: pipelines)
end
def assign_change_commit_vars(mr_source_branch)
......
class Projects::GitHttpController < Projects::ApplicationController
attr_reader :user
skip_before_action :repository
before_action :authenticate_user
before_action :ensure_project_found!
# GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
def info_refs
if upload_pack? && upload_pack_allowed?
render_ok
elsif receive_pack? && receive_pack_allowed?
render_ok
else
render_not_found
end
end
# POST /foo/bar.git/git-upload-pack (git pull)
def git_upload_pack
if upload_pack? && upload_pack_allowed?
render_ok
else
render_not_found
end
end
# POST /foo/bar.git/git-receive-pack" (git push)
def git_receive_pack
if receive_pack? && receive_pack_allowed?
render_ok
else
render_not_found
end
end
private
def authenticate_user
return if project && project.public? && upload_pack?
authenticate_or_request_with_http_basic do |login, password|
auth_result = Gitlab::Auth.find(login, password, project: project, ip: request.ip)
if auth_result.type == :ci && upload_pack?
@ci = true
elsif auth_result.type == :oauth && !upload_pack?
# Not allowed
else
@user = auth_result.user
end
ci? || user
end
end
def ensure_project_found!
render_not_found if project.blank?
end
def project
return @project if defined?(@project)
project_id, _ = project_id_with_suffix
if project_id.blank?
@project = nil
else
@project = Project.find_with_namespace("#{params[:namespace_id]}/#{project_id}")
end
end
# This method returns two values so that we can parse
# params[:project_id] (untrusted input!) in exactly one place.
def project_id_with_suffix
id = params[:project_id] || ''
%w[.wiki.git .git].each do |suffix|
if id.end_with?(suffix)
# Be careful to only remove the suffix from the end of 'id'.
# Accidentally removing it from the middle is how security
# vulnerabilities happen!
return [id.slice(0, id.length - suffix.length), suffix]
end
end
# Something is wrong with params[:project_id]; do not pass it on.
[nil, nil]
end
def upload_pack?
git_command == 'git-upload-pack'
end
def receive_pack?
git_command == 'git-receive-pack'
end
def git_command
if action_name == 'info_refs'
params[:service]
else
action_name.dasherize
end
end
def render_ok
render json: Gitlab::Workhorse.git_http_ok(repository, user)
end
def repository
_, suffix = project_id_with_suffix
if suffix == '.wiki.git'
project.wiki.repository
else
project.repository
end
end
def render_not_found
render text: 'Not Found', status: :not_found
end
def ci?
@ci.present?
end
def upload_pack_allowed?
return false unless Gitlab.config.gitlab_shell.upload_pack
if user
Gitlab::GitAccess.new(user, project).download_access_check.allowed?
else
ci? || project.public?
end
end
def receive_pack_allowed?
return false unless Gitlab.config.gitlab_shell.receive_pack
# Skip user authorization on upload request.
# It will be done by the pre-receive hook in the repository.
user.present?
end
end
......@@ -5,13 +5,14 @@ class Projects::LabelsController < Projects::ApplicationController
before_action :label, only: [:edit, :update, :destroy]
before_action :authorize_read_label!
before_action :authorize_admin_labels!, only: [
:new, :create, :edit, :update, :generate, :destroy
:new, :create, :edit, :update, :generate, :destroy, :remove_priority, :set_priorities
]
respond_to :js, :html
def index
@labels = @project.labels.page(params[:page])
@labels = @project.labels.unprioritized.page(params[:page])
@prioritized_labels = @project.labels.prioritized
respond_to do |format|
format.html
......@@ -71,6 +72,30 @@ class Projects::LabelsController < Projects::ApplicationController
end
end
def remove_priority
respond_to do |format|
if label.update_attribute(:priority, nil)
format.json { render json: label }
else
message = label.errors.full_messages.uniq.join('. ')
format.json { render json: { message: message }, status: :unprocessable_entity }
end
end
end
def set_priorities
Label.transaction do
params[:label_ids].each_with_index do |label_id, index|
label = @project.labels.find_by_id(label_id)
label.update_attribute(:priority, index) if label
end
end
respond_to do |format|
format.json { render json: { message: 'success' } }
end
end
protected
def module_enabled
......
......@@ -58,9 +58,16 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format|
format.html
format.json { render json: @merge_request }
format.diff { render text: @merge_request.to_diff }
format.patch { render text: @merge_request.to_patch }
format.json { render json: @merge_request }
format.patch { render text: @merge_request.to_patch }
format.diff do
headers.store(*Gitlab::Workhorse.send_git_diff(@project.repository,
@merge_request.diff_base_commit.id,
@merge_request.last_commit.id))
headers['Content-Disposition'] = 'inline'
head :ok
end
end
end
......@@ -120,8 +127,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare
@diff_notes_disabled = true
@ci_commit = @merge_request.ci_commit
@statuses = @ci_commit.statuses if @ci_commit
@pipeline = @merge_request.pipeline
@statuses = @pipeline.statuses if @pipeline
@note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
......@@ -200,7 +207,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.update(merge_error: nil)
if params[:merge_when_build_succeeds].present? && @merge_request.ci_commit && @merge_request.ci_commit.active?
if params[:merge_when_build_succeeds].present? && @merge_request.pipeline && @merge_request.pipeline.active?
MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
.execute(@merge_request)
@status = :merge_when_build_succeeds
......@@ -231,10 +238,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def ci_status
ci_commit = @merge_request.ci_commit
if ci_commit
status = ci_commit.status
coverage = ci_commit.try(:coverage)
pipeline = @merge_request.pipeline
if pipeline
status = pipeline.status
coverage = pipeline.try(:coverage)
status ||= "preparing"
else
......@@ -317,8 +324,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request_diff = @merge_request.merge_request_diff
@ci_commit = @merge_request.ci_commit
@statuses = @ci_commit.statuses if @ci_commit
@pipeline = @merge_request.pipeline
@statuses = @pipeline.statuses if @pipeline
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
......@@ -327,8 +334,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def define_widget_vars
@ci_commit = @merge_request.ci_commit
@ci_commits = [@ci_commit].compact
@pipeline = @merge_request.pipeline
@pipelines = [@pipeline].compact
closes_issues
end
......
......@@ -7,7 +7,7 @@ class Projects::PipelinesController < Projects::ApplicationController
def index
@scope = params[:scope]
all_pipelines = project.ci_commits
all_pipelines = project.pipelines
@pipelines_count = all_pipelines.count
@running_or_pending_count = all_pipelines.running_or_pending.count
@pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope)
......@@ -15,7 +15,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def new
@pipeline = project.ci_commits.new(ref: @project.default_branch)
@pipeline = project.pipelines.new(ref: @project.default_branch)
end
def create
......@@ -50,7 +50,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def pipeline
@pipeline ||= project.ci_commits.find_by!(id: params[:id])
@pipeline ||= project.pipelines.find_by!(id: params[:id])
end
def commit
......
......@@ -224,7 +224,7 @@ class IssuableFinder
def sort(items)
# Ensure we always have an explicit sort order (instead of inheriting
# multiple orders when combining ActiveRecord::Relation objects).
params[:sort] ? items.sort(params[:sort]) : items.reorder(id: :desc)
params[:sort] ? items.sort(params[:sort], excluded_labels: label_names) : items.reorder(id: :desc)
end
def by_assignee(items)
......@@ -318,7 +318,11 @@ class IssuableFinder
end
def label_names
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
if labels?
params[:label_name].is_a?(String) ? params[:label_name].split(',') : params[:label_name]
else
[]
end
end
def current_user_related?
......
module CiStatusHelper
def ci_status_path(ci_commit)
project = ci_commit.project
builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
def ci_status_path(pipeline)
project = pipeline.project
builds_namespace_project_commit_path(project.namespace, project, pipeline.sha)
end
def ci_status_with_icon(status, target = nil)
......
......@@ -31,6 +31,21 @@ module NotificationsHelper
end
end
def notification_description(level)
case level.to_sym
when :participating
'You will only receive notifications from related resources'
when :mention
'You will receive notifications only for comments in which you were @mentioned'
when :watch
'You will receive notifications for any activity'
when :disabled
'You will not get any notifications via email'
when :global
'Use your global notification setting'
end
end
def notification_list_item(level, setting)
title = notification_title(level)
......@@ -39,9 +54,10 @@ module NotificationsHelper
notification_title: title
}
content_tag(:li, class: ('active' if setting.level == level)) do
link_to '#', class: 'update-notification', data: data do
notification_icon(level, title)
content_tag(:li, role: "menuitem") do
link_to '#', class: "update-notification #{('is-active' if setting.level == level)}", data: data do
link_output = content_tag(:strong, title, class: 'dropdown-menu-inner-title')
link_output << content_tag(:span, notification_description(level), class: 'dropdown-menu-inner-content')
end
end
end
......
......@@ -14,7 +14,8 @@ module SortingHelper
sort_value_recently_signin => sort_title_recently_signin,
sort_value_oldest_signin => sort_title_oldest_signin,
sort_value_downvotes => sort_title_downvotes,
sort_value_upvotes => sort_title_upvotes
sort_value_upvotes => sort_title_upvotes,
sort_value_priority => sort_title_priority
}
end
......@@ -28,6 +29,10 @@ module SortingHelper
}
end
def sort_title_priority
'Priority'
end
def sort_title_oldest_updated
'Oldest updated'
end
......@@ -84,6 +89,10 @@ module SortingHelper
'Most popular'
end
def sort_value_priority
'priority'
end
def sort_value_oldest_updated
'updated_asc'
end
......
......@@ -45,8 +45,8 @@ module Ci
new_build.options = build.options
new_build.commands = build.commands
new_build.tag_list = build.tag_list
new_build.gl_project_id = build.gl_project_id
new_build.commit_id = build.commit_id
new_build.project = build.project
new_build.pipeline = build.pipeline
new_build.name = build.name
new_build.allow_failure = build.allow_failure
new_build.stage = build.stage
......@@ -66,7 +66,7 @@ module Ci
# We use around_transition to create builds for next stage as soon as possible, before the `after_*` is executed
around_transition any => [:success, :failed, :canceled] do |build, block|
block.call
build.commit.create_next_builds(build) if build.commit
build.pipeline.create_next_builds(build) if build.pipeline
end
after_transition any => [:success, :failed, :canceled] do |build|
......@@ -80,7 +80,7 @@ module Ci
end
def retried?
!self.commit.statuses.latest.include?(self)
!self.pipeline.statuses.latest.include?(self)
end
def retry
......@@ -89,7 +89,7 @@ module Ci
def depends_on_builds
# Get builds of the same type
latest_builds = self.commit.builds.latest
latest_builds = self.pipeline.builds.latest
# Return builds from previous stages
latest_builds.where('stage_idx < ?', stage_idx)
......@@ -114,16 +114,16 @@ module Ci
def merge_request
merge_requests = MergeRequest.includes(:merge_request_diff)
.where(source_branch: ref, source_project_id: commit.gl_project_id)
.where(source_branch: ref, source_project_id: pipeline.gl_project_id)
.reorder(iid: :asc)
merge_requests.find do |merge_request|
merge_request.commits.any? { |ci| ci.id == commit.sha }
merge_request.commits.any? { |ci| ci.id == pipeline.sha }
end
end
def project_id
commit.project.id
pipeline.project_id
end
def project_name
......@@ -360,8 +360,8 @@ module Ci
end
def global_yaml_variables
if commit.config_processor
commit.config_processor.global_variables.map do |key, value|
if pipeline.config_processor
pipeline.config_processor.global_variables.map do |key, value|
{ key: key, value: value, public: true }
end
else
......@@ -370,8 +370,8 @@ module Ci
end
def job_yaml_variables
if commit.config_processor
commit.config_processor.job_variables(name).map do |key, value|
if pipeline.config_processor
pipeline.config_processor.job_variables(name).map do |key, value|
{ key: key, value: value, public: true }
end
else
......
module Ci
class Commit < ActiveRecord::Base
class Pipeline < ActiveRecord::Base
extend Ci::Model
include Statuseable
self.table_name = 'ci_commits'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
has_many :statuses, class_name: 'CommitStatus'
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id
validates_presence_of :sha
validates_presence_of :status
......@@ -21,7 +23,7 @@ module Ci
def self.stages
# We use pluck here due to problems with MySQL which doesn't allow LIMIT/OFFSET in queries
CommitStatus.where(commit: pluck(:id)).stages
CommitStatus.where(pipeline: pluck(:id)).stages
end
def project_id
......@@ -47,7 +49,7 @@ module Ci
end
def short_sha
Ci::Commit.truncate_sha(sha)
Ci::Pipeline.truncate_sha(sha)
end
def commit_data
......
......@@ -3,7 +3,7 @@ module Ci
extend Ci::Model
belongs_to :trigger, class_name: 'Ci::Trigger'
belongs_to :commit, class_name: 'Ci::Commit'
belongs_to :commit, class_name: 'Ci::Pipeline', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build'
serialize :variables
......
......@@ -214,13 +214,13 @@ class Commit
@raw.short_id(7)
end
def ci_commits
@ci_commits ||= project.ci_commits.where(sha: sha)
def pipelines
@pipeline ||= project.pipelines.where(sha: sha)
end
def status
return @status if defined?(@status)
@status ||= ci_commits.status
@status ||= pipelines.status
end
def revert_branch_name
......
......@@ -4,10 +4,10 @@ class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
belongs_to :commit, class_name: 'Ci::Commit', touch: true
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id, touch: true
belongs_to :user
validates :commit, presence: true
validates :pipeline, presence: true
validates_presence_of :name
......@@ -44,18 +44,18 @@ class CommitStatus < ActiveRecord::Base
end
after_transition [:pending, :running] => :success do |commit_status|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.commit.project, nil).trigger(commit_status)
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status)
end
after_transition any => :failed do |commit_status|
MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.commit.project, nil).execute(commit_status)
MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.pipeline.project, nil).execute(commit_status)
end
end
delegate :sha, :short_sha, to: :commit
delegate :sha, :short_sha, to: :pipeline
def before_sha
commit.before_sha || Gitlab::Git::BLANK_SHA
pipeline.before_sha || Gitlab::Git::BLANK_SHA
end
def self.stages
......
......@@ -105,17 +105,24 @@ module Issuable
where(t[:title].matches(pattern).or(t[:description].matches(pattern)))
end
def sort(method)
def sort(method, excluded_labels: [])
case method.to_s
when 'milestone_due_asc' then order_milestone_due_asc
when 'milestone_due_desc' then order_milestone_due_desc
when 'downvotes_desc' then order_downvotes_desc
when 'upvotes_desc' then order_upvotes_desc
when 'priority' then order_labels_priority(excluded_labels: excluded_labels)
else
order_by(method)
end
end
def order_labels_priority(excluded_labels: [])
select("#{table_name}.*, (#{highest_label_priority(excluded_labels).to_sql}) AS highest_priority").
group(arel_table[:id]).
reorder(Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
end
def with_label(title, sort = nil)
if title.is_a?(Array) && title.size > 1
joins(:labels).where(labels: { title: title }).group(*grouping_columns(sort)).having("COUNT(DISTINCT labels.title) = #{title.size}")
......@@ -139,6 +146,20 @@ module Issuable
grouping_columns
end
private
def highest_label_priority(excluded_labels)
query = Label.select(Label.arel_table[:priority].minimum).
joins(:label_links).
where(label_links: { target_type: name }).
where("label_links.target_id = #{table_name}.id").
reorder(nil)
query.where.not(title: excluded_labels) if excluded_labels.present?
query
end
end
def today?
......
......@@ -75,10 +75,10 @@ class Issue < ActiveRecord::Base
@link_reference_pattern ||= super("issues", /(?<issue>\d+)/)
end
def self.sort(method)
def self.sort(method, excluded_labels: [])
case method.to_s
when 'due_date_asc' then order_due_date_asc
when 'due_date_desc' then order_due_date_desc
when 'due_date_desc' then order_due_date_desc
else
super
end
......
......@@ -26,10 +26,20 @@ class Label < ActiveRecord::Base
format: { with: /\A[^&\?,]+\z/ },
uniqueness: { scope: :project_id }
before_save :nullify_priority
default_scope { order(title: :asc) }
scope :templates, -> { where(template: true) }
def self.prioritized
where.not(priority: nil).reorder(:priority, :title)
end
def self.unprioritized
where(priority: nil)
end
alias_attribute :name, :title
def self.reference_prefix
......@@ -118,4 +128,8 @@ class Label < ActiveRecord::Base
id
end
end
def nullify_priority
self.priority = nil if priority.blank?
end
end
......@@ -313,13 +313,6 @@ class MergeRequest < ActiveRecord::Base
)
end
# Returns the raw diff for this merge request
#
# see "git diff"
def to_diff
target_project.repository.diff_text(diff_base_commit.sha, source_sha)
end
# Returns the commit as a series of email patches.
#
# see "git format-patch"
......@@ -579,8 +572,8 @@ class MergeRequest < ActiveRecord::Base
diverged_commits_count > 0
end
def ci_commit
@ci_commit ||= source_project.ci_commit(last_commit.id, source_branch) if last_commit && source_project
def pipeline
@pipeline ||= source_project.pipeline(last_commit.id, source_branch) if last_commit && source_project
end
def diff_refs
......
class NotificationSetting < ActiveRecord::Base
enum level: { disabled: 0, participating: 1, watch: 2, global: 3, mention: 4 }
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0 }
default_value_for :level, NotificationSetting.levels[:global]
......
......@@ -119,7 +119,7 @@ class Project < ActiveRecord::Base
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
has_many :commit_statuses, dependent: :destroy, class_name: 'CommitStatus', foreign_key: :gl_project_id
has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline', foreign_key: :gl_project_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id
has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
......@@ -930,12 +930,12 @@ class Project < ActiveRecord::Base
!namespace.share_with_group_lock
end
def ci_commit(sha, ref)
ci_commits.order(id: :desc).find_by(sha: sha, ref: ref)
def pipeline(sha, ref)
pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
end
def ensure_ci_commit(sha, ref)
ci_commit(sha, ref) || ci_commits.create(sha: sha, ref: ref)
def ensure_pipeline(sha, ref)
pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref)
end
def enable_ci
......
module Ci
class CreateBuildsService
def initialize(commit)
@commit = commit
def initialize(pipeline)
@pipeline = pipeline
end
def execute(stage, user, status, trigger_request = nil)
builds_attrs = config_processor.builds_for_stage_and_ref(stage, @commit.ref, @commit.tag, trigger_request)
builds_attrs = config_processor.builds_for_stage_and_ref(stage, @pipeline.ref, @pipeline.tag, trigger_request)
# check when to create next build
builds_attrs = builds_attrs.select do |build_attrs|
......@@ -21,8 +21,8 @@ module Ci
builds_attrs.map do |build_attrs|
# don't create the same build twice
unless @commit.builds.find_by(ref: @commit.ref, tag: @commit.tag,
trigger_request: trigger_request, name: build_attrs[:name])
unless @pipeline.builds.find_by(ref: @pipeline.ref, tag: @pipeline.tag,
trigger_request: trigger_request, name: build_attrs[:name])
build_attrs.slice!(:name,
:commands,
:tag_list,
......@@ -31,13 +31,13 @@ module Ci
:stage,
:stage_idx)
build_attrs.merge!(ref: @commit.ref,
tag: @commit.tag,
build_attrs.merge!(ref: @pipeline.ref,
tag: @pipeline.tag,
trigger_request: trigger_request,
user: user,
project: @commit.project)
project: @pipeline.project)
@commit.builds.create!(build_attrs)
@pipeline.builds.create!(build_attrs)
end
end
end
......@@ -45,7 +45,7 @@ module Ci
private
def config_processor
@config_processor ||= @commit.config_processor
@config_processor ||= @pipeline.config_processor
end
end
end
module Ci
class CreatePipelineService < BaseService
def execute
pipeline = project.ci_commits.new(params)
pipeline = project.pipelines.new(params)
unless ref_names.include?(params[:ref])
pipeline.errors.add(:base, 'Reference not found')
......@@ -19,7 +19,7 @@ module Ci
end
begin
Ci::Commit.transaction do
Ci::Pipeline.transaction do
pipeline.sha = commit.id
unless pipeline.config_processor
......
......@@ -7,14 +7,14 @@ module Ci
# check if ref is tag
tag = project.repository.find_tag(ref).present?
ci_commit = project.ci_commits.create(sha: commit.sha, ref: ref, tag: tag)
pipeline = project.pipelines.create(sha: commit.sha, ref: ref, tag: tag)
trigger_request = trigger.trigger_requests.create!(
variables: variables,
commit: ci_commit,
commit: pipeline,
)
if ci_commit.create_builds(nil, trigger_request)
if pipeline.create_builds(nil, trigger_request)
trigger_request
end
end
......
......@@ -3,9 +3,9 @@ module Ci
def execute(project, opts)
sha = opts[:sha] || ref_sha(project, opts[:ref])
ci_commits = project.ci_commits.where(sha: sha)
ci_commits = ci_commits.where(ref: opts[:ref]) if opts[:ref]
image_name = image_for_status(ci_commits.status)
pipelines = project.pipelines.where(sha: sha)
pipelines = pipelines.where(ref: opts[:ref]) if opts[:ref]
image_name = image_for_status(pipelines.status)
image_path = Rails.root.join('public/ci', image_name)
OpenStruct.new(path: image_path, name: image_name)
......
......@@ -18,23 +18,23 @@ class CreateCommitBuildsService
return false
end
commit = Ci::Commit.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag)
pipeline = Ci::Pipeline.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag)
# Skip creating ci_commit when no gitlab-ci.yml is found
unless commit.ci_yaml_file
# Skip creating pipeline when no gitlab-ci.yml is found
unless pipeline.ci_yaml_file
return false
end
# Create a new ci_commit
commit.save!
# Create a new pipeline
pipeline.save!
# Skip creating builds for commits that have [ci skip]
unless commit.skip_ci?
unless pipeline.skip_ci?
# Create builds for commit
commit.create_builds(user)
pipeline.create_builds(user)
end
commit.touch
commit
pipeline.touch
pipeline
end
end
......@@ -55,12 +55,12 @@ module MergeRequests
def each_merge_request(commit_status)
merge_request_from(commit_status).each do |merge_request|
ci_commit = merge_request.ci_commit
pipeline = merge_request.pipeline
next unless ci_commit
next unless ci_commit.sha == commit_status.sha
next unless pipeline
next unless pipeline.sha == commit_status.sha
yield merge_request, ci_commit
yield merge_request, pipeline
end
end
end
......
......@@ -20,10 +20,10 @@ module MergeRequests
# Triggers the automatic merge of merge_request once the build succeeds
def trigger(commit_status)
each_merge_request(commit_status) do |merge_request, ci_commit|
each_merge_request(commit_status) do |merge_request, pipeline|
next unless merge_request.merge_when_build_succeeds?
next unless merge_request.mergeable?
next unless ci_commit.success?
next unless pipeline.success?
MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params)
end
......
......@@ -99,8 +99,8 @@
%td.build-link
- if project
= link_to ci_status_path(build.commit) do
%strong #{build.commit.short_sha}
= link_to ci_status_path(build.pipeline) do
%strong #{build.pipeline.short_sha}
%td.timestamp
- if build.finished_at
......
......@@ -4,6 +4,10 @@
%i.fa.fa-github
Import projects from GitHub
%p
%i.fa.fa-warning
To import GitHub pull requests, any pull request source branches that had been deleted are temporarily restored on GitHub. To prevent any connected CI services from being overloaded with dozens of irrelevant branches being created and deleted again, GitHub webhooks are temporarily disabled during the import process.
%p.light
Select projects you want to import.
%hr
......
.page-with-sidebar{ class: "#{page_sidebar_class} #{page_gutter_class}" }
.sidebar-wrapper.nicescroll{ class: nav_sidebar_class }
.header-logo
%a#logo
= brand_header_logo
= link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do
.gitlab-text-container
%h3 GitLab
= link_to root_path, class: 'gitlab-text-container-link', title: 'Dashboard', id: 'js-shortcuts-home' do
.header-logo
#logo
= brand_header_logo
- if defined?(sidebar) && sidebar
= render "layouts/nav/#{sidebar}"
......@@ -17,10 +15,8 @@
.collapse-nav
= render partial: 'layouts/collapse_button'
- if current_user
= link_to current_user, class: 'sidebar-user', title: "Profile" do
= image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36'
.username
= current_user.username
= link_to current_user, class: 'sidebar-user', title: "Profile", data: {user: current_user.username} do
= image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s46'
- if defined?(nav) && nav
.layout-nav
.container-fluid
......
......@@ -2,54 +2,50 @@
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
= icon('bookmark fw')
%span
.nav-link-text
Projects
= nav_link(controller: :todos) do
= link_to dashboard_todos_path, title: 'Todos' do
= icon('bell fw')
%span
.nav-link-text
Todos
%span.count.todos-pending-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
= icon('dashboard fw')
%span
.nav-link-text
Activity
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to dashboard_groups_path, title: 'Groups' do
= icon('group fw')
%span
.nav-link-text
Groups
= nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, title: 'Milestones' do
= icon('clock-o fw')
%span
.nav-link-text
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
= icon('exclamation-circle fw')
%span
.nav-link-text
Issues
%span.count= number_with_delimiter(current_user.assigned_open_issues_count)
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw')
%span
.nav-link-text
Merge Requests
%span.count= number_with_delimiter(current_user.assigned_open_merge_request_count)
= nav_link(controller: :snippets) do
= link_to dashboard_snippets_path, title: 'Snippets' do
= icon('clipboard fw')
%span
.nav-link-text
Snippets
= nav_link(controller: :help) do
= link_to help_path, title: 'Help' do
= icon('question-circle fw')
%span
.nav-link-text
Help
= nav_link(html_options: {class: profile_tab_class}) do
= link_to profile_path, title: 'Profile Settings', data: {placement: 'bottom'} do
= icon('user fw')
%span
.nav-link-text
Profile Settings
......@@ -10,11 +10,12 @@
= icon('gear fw')
%span
Account
= nav_link(controller: 'oauth/applications') do
= link_to applications_profile_path, title: 'Applications' do
= icon('cloud fw')
%span
Applications
- if current_application_settings.user_oauth_applications?
= nav_link(controller: 'oauth/applications') do
= link_to applications_profile_path, title: 'Applications' do
= icon('cloud fw')
%span
Applications
= nav_link(controller: :emails) do
= link_to profile_emails_path, title: 'Emails' do
= icon('envelope-o fw')
......
......@@ -10,7 +10,7 @@
%p
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p
Author: #{@build.commit.git_author_name}
Author: #{@build.pipeline.git_author_name}
%p
Branch: #{@build.ref}
%p
......@@ -18,7 +18,7 @@
%p
Job: #{@build.name}
%p
Message: #{@build.commit.git_commit_message}
Message: #{@build.pipeline.git_commit_message}
%p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Build failed for <%= @project.name %>
Status: <%= @build.status %>
Commit: <%= @build.commit.short_sha %>
Author: <%= @build.commit.git_author_name %>
Commit: <%= @build.pipeline.short_sha %>
Author: <%= @build.pipeline.git_author_name %>
Branch: <%= @build.ref %>
Stage: <%= @build.stage %>
Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %>
Message: <%= @build.pipeline.git_commit_message %>
Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
......@@ -10,7 +10,7 @@
%p
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p
Author: #{@build.commit.git_author_name}
Author: #{@build.pipeline.git_author_name}
%p
Branch: #{@build.ref}
%p
......@@ -18,7 +18,7 @@
%p
Job: #{@build.name}
%p
Message: #{@build.commit.git_commit_message}
Message: #{@build.pipeline.git_commit_message}
%p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Build successful for <%= @project.name %>
Status: <%= @build.status %>
Commit: <%= @build.commit.short_sha %>
Author: <%= @build.commit.git_author_name %>
Commit: <%= @build.pipeline.short_sha %>
Author: <%= @build.pipeline.git_author_name %>
Branch: <%= @build.ref %>
Stage: <%= @build.stage %>
Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %>
Message: <%= @build.pipeline.git_commit_message %>
Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
......@@ -29,10 +29,10 @@
.project-clone-holder
= render "shared/clone_panel"
.project-repo-buttons.btn-group.project-right-buttons
= render "projects/buttons/download"
= render 'projects/buttons/dropdown'
= render 'projects/buttons/notifications'
.project-repo-buttons.btn-group.project-right-buttons
= render "projects/buttons/download"
= render 'projects/buttons/dropdown'
= render 'projects/buttons/notifications'
:javascript
new Star();
- @no_container = true
- page_title "Branches"
= render "projects/commits/head"
.row-content-block
.pull-right
- if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
= icon('plus')
New branch
&nbsp;
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light
- if @sort.present?
= @sort.humanize
- else
Name
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to namespace_project_branches_path(sort: nil) do
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
.pull-right
- if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
= icon('plus')
New branch
&nbsp;
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light
- if @sort.present?
= @sort.humanize
- else
Name
= link_to namespace_project_branches_path(sort: 'recently_updated') do
= sort_title_recently_updated
= link_to namespace_project_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
.oneline
Protected branches can be managed in project settings
- unless @branches.empty?
%ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab'
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to namespace_project_branches_path(sort: nil) do
Name
= link_to namespace_project_branches_path(sort: 'recently_updated') do
= sort_title_recently_updated
= link_to namespace_project_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
.oneline
Protected branches can be managed in project settings
- unless @branches.empty?
%ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab'
- @no_container = true
- page_title "Builds"
= render "projects/pipelines/head"
.top-area
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
= link_to project_builds_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
%span.badge.js-running-count
= number_with_delimiter(@all_builds.running_or_pending.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to project_builds_path(@project, scope: :finished) do
Finished
%span.badge.js-running-count
= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls
- if can?(current_user, :update_build, @project)
- if @all_builds.running_or_pending.any?
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
= icon('wrench')
%span CI Lint
%ul.content-list
- if @builds.blank?
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Build ID
%th Commit
%th Ref
%th Stage
%th Name
%th Tags
%th Duration
%th Finished at
- if @project.build_coverage_enabled?
%th Coverage
%th
= render @builds, commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
= paginate @builds, theme: 'gitlab'
%div{ class: (container_class) }
.top-area
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
= link_to project_builds_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
%span.badge.js-running-count
= number_with_delimiter(@all_builds.running_or_pending.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to project_builds_path(@project, scope: :finished) do
Finished
%span.badge.js-running-count
= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls
- if can?(current_user, :update_build, @project)
- if @all_builds.running_or_pending.any?
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
= icon('wrench')
%span CI Lint
%ul.content-list
- if @builds.blank?
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Build ID
%th Commit
%th Ref
%th Stage
%th Name
%th Tags
%th Duration
%th Finished at
- if @project.build_coverage_enabled?
%th Coverage
%th
= render @builds, commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
= paginate @builds, theme: 'gitlab'
......@@ -4,7 +4,7 @@
.build-page
.row-content-block.top-block
Build ##{@build.id} for commit
%strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit)
%strong.monospace= link_to @build.pipeline.short_sha, ci_status_path(@build.pipeline)
from
= link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
- merge_request = @build.merge_request
......@@ -13,7 +13,7 @@
= link_to "merge request #{merge_request.to_reference}", merge_request_path(merge_request)
#up-build-trace
- builds = @build.commit.builds.latest.to_a
- builds = @build.pipeline.builds.latest.to_a
- if builds.size > 1
%ul.nav-links.no-top.no-bottom
- builds.each do |build|
......@@ -178,16 +178,16 @@
Commit
.pull-right
%small
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace"
= link_to @build.pipeline.short_sha, ci_status_path(@build.pipeline), class: "monospace"
%p
%span.attr-name Branch:
= link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
%p
%span.attr-name Author:
#{@build.commit.git_author_name}
#{@build.pipeline.git_author_name}
%p
%span.attr-name Message:
#{@build.commit.git_commit_message}
#{@build.pipeline.git_commit_message}
- if @build.tags.any?
.build-widget
......@@ -201,7 +201,7 @@
.build-widget
%h4.title #{pluralize(@builds.count(:id), "other build")} for
= succeed ":" do
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace"
= link_to @build.pipeline.short_sha, ci_status_path(@build.pipeline), class: "monospace"
%table.table.builds
- @builds.each_with_index do |build, i|
%tr.build
......
......@@ -2,10 +2,10 @@
= form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f|
= f.hidden_field :level
.dropdown
%a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
%button.btn.btn-default.notifications-btn#notifications-button{ data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } }
= icon('bell')
= notification_title(@notification_setting.level)
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
%ul.dropdown-menu.dropdown-menu-no-wrap.dropdown-menu-align-right.dropdown-menu-selectable.dropdown-menu-large{ role: "menu" }
- NotificationSetting.levels.each do |level|
= notification_list_item(level.first, @notification_setting)
- status = commit.status
- status = pipeline.status
%tr.commit
%td.commit-link
= link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: "ci-status ci-#{status}" do
= link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: "ci-status ci-#{status}" do
= ci_icon_for_status(status)
%strong ##{commit.id}
%strong ##{pipeline.id}
%td
%div.branch-commit
- if commit.ref
= link_to commit.ref, namespace_project_commits_path(@project.namespace, @project, commit.ref), class: "monospace"
- if pipeline.ref
= link_to pipeline.ref, namespace_project_commits_path(@project.namespace, @project, pipeline.ref), class: "monospace"
&middot;
= link_to commit.short_sha, namespace_project_commit_path(@project.namespace, @project, commit.sha), class: "commit-id monospace"
= link_to pipeline.short_sha, namespace_project_commit_path(@project.namespace, @project, pipeline.sha), class: "commit-id monospace"
&nbsp;
- if commit.tag?
- if pipeline.tag?
%span.label.label-primary tag
- elsif commit.latest?
- elsif pipeline.latest?
%span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest
- if commit.triggered?
- if pipeline.triggered?
%span.label.label-primary triggered
- if commit.yaml_errors.present?
%span.label.label-danger.has-tooltip{ title: "#{commit.yaml_errors}" } yaml invalid
- if commit.builds.any?(&:stuck?)
- if pipeline.yaml_errors.present?
%span.label.label-danger.has-tooltip{ title: "#{pipeline.yaml_errors}" } yaml invalid
- if pipeline.builds.any?(&:stuck?)
%span.label.label-warning stuck
%p.commit-title
- if commit_data = commit.commit_data
- if commit_data = pipeline.commit_data
= link_to_gfm truncate(commit_data.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
- else
Cant find HEAD commit for this branch
- stages_status = commit.statuses.stages_status
- stages_status = pipeline.statuses.stages_status
- stages.each do |stage|
%td
- status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status || 'not found'}"
- if status
= link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
= link_to namespace_project_pipeline_path(@project.namespace, @project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
= ci_icon_for_status(status)
- else
.light.has-tooltip{ title: tooltip }
\-
%td
- if commit.started_at && commit.finished_at
- if pipeline.started_at && pipeline.finished_at
%p.duration
#{duration_in_words(commit.finished_at, commit.started_at)}
#{duration_in_words(pipeline.finished_at, pipeline.started_at)}
%td
.controls.hidden-xs.pull-right
- artifacts = commit.builds.latest.select { |b| b.artifacts? }
- artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
- if artifacts.present?
.dropdown.inline.build-artifacts
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
......@@ -63,9 +63,9 @@
%span #{build.name}
- if can?(current_user, :update_pipeline, @project)
- if commit.retryable?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do
- if pipeline.retryable?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat")
- if commit.cancelable?
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
- if pipeline.cancelable?
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
= icon("remove")
- @ci_commits.each do |ci_commit|
= render "ci_commit", ci_commit: ci_commit, pipeline_details: true
- @pipelines.each do |pipeline|
= render "pipeline", pipeline: pipeline, pipeline_details: true
......@@ -53,13 +53,13 @@
- if @commit.status
.commit-info-row
Builds for
= pluralize(@commit.ci_commits.count, 'pipeline')
= pluralize(@commit.pipelines.count, 'pipeline')
= link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status-link ci-status-icon-#{@commit.status}" do
= ci_icon_for_status(@commit.status)
= ci_label_for_status(@commit.status)
- if @commit.ci_commits.duration
- if @commit.pipelines.duration
in
= time_interval_in_words @commit.ci_commits.duration
= time_interval_in_words @commit.pipelines.duration
.commit-box.content-block
%h3.commit-title
......
.row-content-block.build-content.middle-block
.pull-right
- if can?(current_user, :update_pipeline, ci_commit.project)
- if ci_commit.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), class: 'btn btn-grouped btn-primary', method: :post
- if can?(current_user, :update_pipeline, pipeline.project)
- if pipeline.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-grouped btn-primary', method: :post
- if ci_commit.builds.running_or_pending.any?
= link_to "Cancel running", cancel_namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
- if pipeline.builds.running_or_pending.any?
= link_to "Cancel running", cancel_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
.oneline.clearfix
- if defined?(pipeline_details) && pipeline_details
Pipeline
= link_to "##{ci_commit.id}", namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), class: "monospace"
= link_to "##{pipeline.id}", namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "monospace"
with
= pluralize ci_commit.statuses.count(:id), "build"
- if ci_commit.ref
= pluralize pipeline.statuses.count(:id), "build"
- if pipeline.ref
for
= link_to ci_commit.ref, namespace_project_commits_path(ci_commit.project.namespace, ci_commit.project, ci_commit.ref), class: "monospace"
= link_to pipeline.ref, namespace_project_commits_path(pipeline.project.namespace, pipeline.project, pipeline.ref), class: "monospace"
- if defined?(link_to_commit) && link_to_commit
for commit
= link_to ci_commit.short_sha, namespace_project_commit_path(ci_commit.project.namespace, ci_commit.project, ci_commit.sha), class: "monospace"
- if ci_commit.duration
= link_to pipeline.short_sha, namespace_project_commit_path(pipeline.project.namespace, pipeline.project, pipeline.sha), class: "monospace"
- if pipeline.duration
in
= time_interval_in_words ci_commit.duration
= time_interval_in_words pipeline.duration
- if ci_commit.yaml_errors.present?
- if pipeline.yaml_errors.present?
.bs-callout.bs-callout-danger
%h4 Found errors in your .gitlab-ci.yml:
%ul
- ci_commit.yaml_errors.split(",").each do |error|
- pipeline.yaml_errors.split(",").each do |error|
%li= error
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
- if ci_commit.project.builds_enabled? && !ci_commit.ci_yaml_file
- if pipeline.project.builds_enabled? && !pipeline.ci_yaml_file
.bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit
......@@ -45,8 +45,8 @@
%th Tags
%th Duration
%th Finished at
- if ci_commit.project.build_coverage_enabled?
- if pipeline.project.build_coverage_enabled?
%th Coverage
%th
- ci_commit.statuses.stages.each do |stage|
= render 'projects/commit/ci_stage', stage: stage, statuses: ci_commit.statuses.where(stage: stage)
- pipeline.statuses.stages.each do |stage|
= render 'projects/commit/ci_stage', stage: stage, statuses: pipeline.statuses.where(stage: stage)
%ul.nav-links
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project) do
Files
.scrolling-tabs-container
%ul.nav-links.sub-nav.scrolling-tabs
%div{ class: (container_class) }
.fade-left
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project) do
Files
= nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
Commits
= nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
Commits
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
Network
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
Network
= nav_link(controller: :compare) do
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: current_ref) do
Compare
= nav_link(controller: :compare) do
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: current_ref) do
Compare
= nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do
Branches
= nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do
Branches
= nav_link(controller: [:tags, :releases]) do
= link_to namespace_project_tags_path(@project.namespace, @project) do
Tags
= nav_link(controller: [:tags, :releases]) do
= link_to namespace_project_tags_path(@project.namespace, @project) do
Tags
.fade-right
- @no_container = true
- page_title "Commits", @ref
= content_for :meta_tags do
- if current_user
......@@ -5,37 +7,38 @@
= render "head"
.row-content-block.second-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits'
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits'
.block-controls.hidden-xs.hidden-sm
- if @merge_request.present?
.control
= link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
- elsif create_mr_button?(@repository.root_ref, @ref)
.control
= link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
= icon('plus')
Create Merge Request
.block-controls.hidden-xs.hidden-sm
- if @merge_request.present?
.control
= link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
- elsif create_mr_button?(@repository.root_ref, @ref)
.control
= link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
= icon('plus')
Create Merge Request
= form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'pull-left commits-search-form') do
= search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false }
.control
= form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'pull-left commits-search-form') do
= search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false }
- if current_user && current_user.private_token
.control
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'btn' do
= icon("rss")
- if current_user && current_user.private_token
.control
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'btn' do
= icon("rss")
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
%div{id: dom_id(@project)}
#commits-list.content_list= render "commits", project: @project
.clear
= spinner
%div{id: dom_id(@project)}
#commits-list.content_list= render "commits", project: @project
.clear
= spinner
:javascript
CommitsList.init(#{@limit});
- @no_container = true
- page_title "Compare"
= render "projects/commits/head"
.row-content-block
Compare branches, tags or commit ranges.
%br
Fill input field with commit id like
%code.label-branch 4eedf23
or branch/tag name like
%code.label-branch master
and press compare button for the commits list and a code diff.
%br
Changes are shown <b>from</b> the version in the first field <b>to</b> the version in the second field.
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
Compare branches, tags or commit ranges.
%br
Fill input field with commit id like
%code.label-branch 4eedf23
or branch/tag name like
%code.label-branch master
and press compare button for the commits list and a code diff.
%br
Changes are shown <b>from</b> the version in the first field <b>to</b> the version in the second field.
.prepend-top-20
= render "form"
.prepend-top-20
= render "form"
......@@ -16,4 +16,4 @@
%li
Commits covered:
%strong
= @project.ci_commits.count(:all)
= @project.pipelines.count(:all)
- page_title "Webhooks"
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0
= page_title
%p
#{link_to "Webhooks", help_page_path("web_hooks", "web_hooks")} can be
used for binding events when something is happening within the project.
.col-lg-9.append-bottom-default
%h5.prepend-top-0
Add new webhook
= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project) do |f|
= form_errors(@hook)
.form-group
= f.label :url, "URL", class: "label-light"
= f.text_field :url, class: "form-control", placeholder: "http://example.com/trigger-ci.json"
.form-group
= f.label :token, "Secret Token", class: 'label-light'
= f.text_field :token, class: "form-control", placeholder: ''
%p.help-block
Use this token to validate received payloads
.form-group
= f.label :url, "Trigger", class: "label-light"
%div
= f.check_box :push_events, class: "pull-left"
.prepend-left-20
= f.label :push_events, class: "label-light append-bottom-0" do
Push events
%p.light
This url will be triggered by a push to the repository
%div
= f.check_box :tag_push_events, class: "pull-left"
.prepend-left-20
= f.label :tag_push_events, class: "label-light append-bottom-0" do
Tag push events
%p.light
This url will be triggered when a new tag is pushed to the repository
%div
= f.check_box :note_events, class: "pull-left"
.prepend-left-20
= f.label :note_events, class: "label-light append-bottom-0" do
Comments
%p.light
This url will be triggered when someone adds a comment
%div
= f.check_box :issues_events, class: "pull-left"
.prepend-left-20
= f.label :issues_events, class: "label-light append-bottom-0" do
Issues events
%p.light
This url will be triggered when an issue is created/updated/merged
%div
= f.check_box :merge_requests_events, class: "pull-left"
.prepend-left-20
= f.label :merge_requests_events, class: "label-light append-bottom-0" do
Merge Request events
%p.light
This url will be triggered when a merge request is created/updated/merged
%div
= f.check_box :build_events, class: "pull-left"
.prepend-left-20
= f.label :build_events, class: "label-light append-bottom-0" do
Build events
%p.light
This url will be triggered when the build status changes
%div
= f.check_box :wiki_page_events, class: 'pull-left'
.prepend-left-20
= f.label :wiki_page_events, class: 'label-light append-bottom-0' do
Wiki Page events
%p.light
This url will be triggered when a wiki page is created/updated
.form-group
= f.label :enable_ssl_verification, "SSL verification", class: "label-light"
%div
= f.check_box :enable_ssl_verification, class: "pull-left"
.prepend-left-20
= f.label :enable_ssl_verification, class: "label-light append-bottom-0" do
Enable SSL verification
= f.submit "Add Webhook", class: "btn btn-create"
%hr
%h5.prepend-top-default
Webhooks (#{@hooks.count})
- if @hooks.any?
%ul.well-list
- @hooks.each do |hook|
= render "project_hook", hook: hook
- else
%p.settings-message.text-center.append-bottom-0
No webhooks found, add one in the form above.
= render 'shared/web_hooks/form', hook: @hook, hooks: @hooks, url_components: [@project.namespace.becomes(Namespace), @project]
......@@ -2,12 +2,12 @@
%h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request')
%ul.unstyled-list
- has_any_ci = @merge_requests.any?(&:ci_commit)
- has_any_ci = @merge_requests.any?(&:pipeline)
- @merge_requests.each do |merge_request|
%li
%span.merge-request-ci-status
- if merge_request.ci_commit
= render_pipeline_status(merge_request.ci_commit)
- if merge_request.pipeline
= render_pipeline_status(merge_request.pipeline)
- elsif has_any_ci
= icon('blank fw')
%span.merge-request-id
......
......@@ -5,10 +5,10 @@
- @related_branches.each do |branch|
%li
- sha = @project.repository.find_branch(branch).target
- ci_commit = @project.ci_commit(sha, branch) if sha
- if ci_commit
- pipeline = @project.pipeline(sha, branch) if sha
- if ci_copipelinemmit
%span.related-branch-ci-status
= render_pipeline_status(ci_commit)
= render_pipeline_status(pipeline)
%span.related-branch-info
%strong
= link_to namespace_project_compare_path(@project.namespace, @project, from: @project.default_branch, to: branch), class: "label-branch" do
......
%li{ id: dom_id(label), data: { id: label.id } }
- label_css_id = dom_id(label)
%li{id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label
.pull-info-right
%span.append-right-20
......@@ -10,18 +11,18 @@
= pluralize label.open_issues_count(current_user), 'open issue'
- if current_user
.label-subscription{data: {url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label)}}
.subscription-status{data: {status: label_subscription_status(label)}}
.label-subscription{ data: { url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label) } }
.subscription-status{ data: { status: label_subscription_status(label) } }
%button.js-subscribe-button.label-subscribe-button.btn.action-buttons{ type: "button", data: { toggle: "tooltip" } }
%span= label_subscription_toggle_button_text(label)
- if can? current_user, :admin_label, @project
= link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn action-buttons', data: {toggle: "tooltip"} do
- if can?(current_user, :admin_label, @project)
= link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn action-buttons', data: { toggle: 'tooltip' } do
%i.fa.fa-pencil-square-o
= link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn action-buttons remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?", toggle: "tooltip"} do
= link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn action-buttons remove-row', method: :delete, remote: true, data: { confirm: 'Remove this label? Are you sure?', toggle: 'tooltip' } do
%i.fa.fa-trash-o
- if current_user
:javascript
new Subscription('##{dom_id(label)} .label-subscription');
new Subscription('##{label_css_id} .label-subscription');
- page_title "Labels"
- hide_class = ''
.top-area
.nav-text
Labels can be applied to issues and merge requests.
.nav-controls
- if can? current_user, :admin_label, @project
- if can?(current_user, :admin_label, @project)
= link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do
= icon('plus')
New label
.labels
- if @labels.present?
%ul.content-list.manage-labels-list
= render @labels
= paginate @labels, theme: 'gitlab'
- else
.nothing-here-block
- if can? current_user, :admin_label, @project
Create a label or #{link_to 'generate a default set of labels', generate_namespace_project_labels_path(@project.namespace, @project), method: :post}.
- else
No labels created
- if can?(current_user, :admin_label, @project)
-# Only show it in the first page
- hide = @project.labels.empty? || (params[:page].present? && params[:page] != '1')
.prioritized-labels{ class: ('hide' if hide) }
%h5 Prioritized Labels
%ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_namespace_project_labels_path(@project.namespace, @project) }
- if @prioritized_labels.present?
= render @prioritized_labels
- else
%p.empty-message No prioritized labels yet
.other-labels
- if can?(current_user, :admin_label, @project)
%h5{ class: ('hide' if hide) } Other Labels
- if @labels.present?
%ul.content-list.manage-labels-list.js-other-labels
= render @labels
= paginate @labels, theme: 'gitlab'
- else
.nothing-here-block
- if can?(current_user, :admin_label, @project)
Create a label or #{link_to 'generate a default set of labels', generate_namespace_project_labels_path(@project.namespace, @project), method: :post}.
- else
No labels created
......@@ -11,9 +11,9 @@
= icon('ban')
CLOSED
- if merge_request.ci_commit
- if merge_request.pipeline
%li
= render_pipeline_status(merge_request.ci_commit)
= render_pipeline_status(merge_request.pipeline)
- if merge_request.open? && merge_request.broken?
%li
......
......@@ -23,7 +23,7 @@
= link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
Commits
%span.badge= @commits.size
- if @ci_commit
- if @pipeline
%li.builds-tab.active
= link_to url_for(params), data: {target: 'div#builds', action: 'builds', toggle: 'tab'} do
Builds
......@@ -43,7 +43,7 @@
%p To preserve performance the line changes are not shown.
- else
= render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs, show_whitespace_toggle: false
- if @ci_commit
- if @pipeline
#builds.builds.tab-pane
= render "projects/merge_requests/show/builds"
......
......@@ -54,7 +54,7 @@
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
Commits
%span.badge= @commits.size
- if @ci_commit
- if @pipeline
%li.builds-tab
= link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
Builds
......
= render "projects/commit/ci_commit", ci_commit: @ci_commit, link_to_commit: true
= render "projects/commit/pipeline", pipeline: @pipeline, link_to_commit: true
- if @ci_commit
- if @pipeline
.mr-widget-heading
- %w[success skipped canceled failed running pending].each do |status|
.ci_widget{ class: "ci-#{status}", style: ("display:none" unless @ci_commit.status == status) }
.ci_widget{ class: "ci-#{status}", style: ("display:none" unless @pipeline.status == status) }
= ci_icon_for_status(status)
%span
CI build
......@@ -9,7 +9,7 @@
for
- commit = @merge_request.last_commit
= succeed "." do
= link_to @ci_commit.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @ci_commit.sha), class: "monospace"
= link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace"
%span.ci-coverage
= link_to "View details", builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "js-show-tab", data: {action: 'builds'}
......
......@@ -13,7 +13,7 @@
check_enable: #{@merge_request.unchecked? ? "true" : "false"},
ci_status_url: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
gitlab_icon: "#{asset_path 'gitlab_logo.png'}",
ci_status: "#{@merge_request.ci_commit ? @merge_request.ci_commit.status : ''}",
ci_status: "#{@merge_request.pipeline ? @merge_request.pipeline.status : ''}",
ci_message: {
normal: "Build {{status}} for \"{{title}}\"",
preparing: "{{status}} build for \"{{title}}\""
......
- status_class = @ci_commit ? " ci-#{@ci_commit.status}" : nil
- status_class = @pipeline ? " ci-#{@pipeline.status}" : nil
= form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-quick-submit js-requires-input' } do |f|
= hidden_field_tag :authenticity_token, form_authenticity_token
......@@ -6,7 +6,7 @@
.accept-merge-holder.clearfix.js-toggle-container
.clearfix
.accept-action
- if @ci_commit && @ci_commit.active?
- if @pipeline && @pipeline.active?
%span.btn-group
= button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do
Merge When Build Succeeds
......
.row-content-block.append-bottom-default
.tree-ref-holder
= render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
- @no_container = true
.oneline
You can move around the graph by using the arrow keys.
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
.tree-ref-holder
= render partial: 'shared/ref_switcher', locals: {destination: 'graph'}
.oneline
You can move around the graph by using the arrow keys.
- page_title "Network", @ref
= render "projects/commits/head"
= render "head"
.project-network
.controls
= form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha'
= button_tag class: 'btn btn-success' do
= icon('search')
.inline.prepend-left-20
.checkbox.light
= label_tag :filter_ref do
= check_box_tag :filter_ref, 1, @options[:filter_ref]
%span Begin with the selected commit
%div{ class: (container_class) }
.project-network
.controls
= form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha'
= button_tag class: 'btn btn-success' do
= icon('search')
.inline.prepend-left-20
.checkbox.light
= label_tag :filter_ref do
= check_box_tag :filter_ref, 1, @options[:filter_ref]
%span Begin with the selected commit
.network-graph
= spinner nil, true
.network-graph
= spinner nil, true
:javascript
network_graph = new Network({
......
%ul.nav-links
- if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span
Pipelines
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
%ul.nav-links.sub-nav
%div{ class: (container_class) }
- if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span
Pipelines
%span.badge.count.ci_counter= number_with_delimiter(@project.pipelines.running_or_pending.count)
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
%span
Builds
%span.badge.count.builds_counter= number_with_delimiter(@project.running_or_pending_build_count)
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
%span
Builds
%span.badge.count.builds_counter= number_with_delimiter(@project.running_or_pending_build_count)
- @no_container = true
- page_title "Pipelines"
= render "projects/pipelines/head"
.top-area
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
= link_to project_pipelines_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@pipelines_count)
%li{class: ('active' if @scope == 'running')}
= link_to project_pipelines_path(@project, scope: :running) do
Running
%span.badge.js-running-count
= number_with_delimiter(@running_or_pending_count)
%li{class: ('active' if @scope == 'branches')}
= link_to project_pipelines_path(@project, scope: :branches) do
Branches
%li{class: ('active' if @scope == 'tags')}
= link_to project_pipelines_path(@project, scope: :tags) do
Tags
.nav-controls
- if can? current_user, :create_pipeline, @project
= link_to new_namespace_project_pipeline_path(@project.namespace, @project), class: 'btn btn-create' do
= icon('plus')
New pipeline
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
= icon('wrench')
%span CI Lint
%ul.content-list.pipelines
- stages = @pipelines.stages
- if @pipelines.blank?
%li
.nothing-here-block No pipelines to show
- else
.table-holder
%table.table.builds
%tbody
%th ID
%th Commit
- stages.each do |stage|
%th.stage
%span.has-tooltip{ title: "#{stage.titleize}" }
= stage.titleize.pluralize
%th Duration
%th
= render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
= paginate @pipelines, theme: 'gitlab'
%div{ class: (container_class) }
.top-area
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
= link_to project_pipelines_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@pipelines_count)
%li{class: ('active' if @scope == 'running')}
= link_to project_pipelines_path(@project, scope: :running) do
Running
%span.badge.js-running-count
= number_with_delimiter(@running_or_pending_count)
%li{class: ('active' if @scope == 'branches')}
= link_to project_pipelines_path(@project, scope: :branches) do
Branches
%li{class: ('active' if @scope == 'tags')}
= link_to project_pipelines_path(@project, scope: :tags) do
Tags
.nav-controls
- if can? current_user, :create_pipeline, @project
= link_to new_namespace_project_pipeline_path(@project.namespace, @project), class: 'btn btn-create' do
= icon('plus')
New pipeline
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
= icon('wrench')
%span CI Lint
%ul.content-list.pipelines
- stages = @pipelines.stages
- if @pipelines.blank?
%li
.nothing-here-block No pipelines to show
- else
.table-holder
%table.table.builds
%tbody
%th ID
%th Commit
- stages.each do |stage|
%th.stage
%span.has-tooltip{ title: "#{stage.titleize}" }
= stage.titleize.pluralize
%th Duration
%th
= render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
= paginate @pipelines, theme: 'gitlab'
......@@ -5,4 +5,4 @@
= render "projects/pipelines/info"
%div.block-connector
= render "projects/commit/ci_commit", ci_commit: @pipeline
= render "projects/commit/pipeline", pipeline: @pipeline
- @no_container = true
- page_title "Tags"
= render "projects/commits/head"
.row-content-block
- if can? current_user, :push_code, @project
.pull-right
= link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
= icon('plus')
New tag
.oneline
Tags give the ability to mark specific points in history as being important
%div{ class: (container_class) }
.row-content-block.second-block.content-component-block
- if can? current_user, :push_code, @project
.pull-right
= link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
= icon('plus')
New tag
.oneline
Tags give the ability to mark specific points in history as being important
.tags
- unless @tags.empty?
%ul.content-list
- @tags.each do |tag|
= render 'tag', tag: @repository.find_tag(tag)
.tags
- unless @tags.empty?
%ul.content-list
- @tags.each do |tag|
= render 'tag', tag: @repository.find_tag(tag)
= paginate @tags, theme: 'gitlab'
= paginate @tags, theme: 'gitlab'
- else
.nothing-here-block
Repository has no tags yet.
%br
%small
Use git tag command to add a new one:
- else
.nothing-here-block
Repository has no tags yet.
%br
%span.monospace git tag -a v1.4 -m 'version 1.4'
%small
Use git tag command to add a new one:
%br
%span.monospace git tag -a v1.4 -m 'version 1.4'
- @no_container = true
- page_title @path.presence || "Files", @ref
= content_for :meta_tags do
- if current_user
......@@ -5,13 +7,14 @@
= render 'projects/last_push'
= render "projects/commits/head"
.tree-controls
= render 'projects/find_file_link'
- if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true
%div{ class: (container_class) }
.tree-controls
= render 'projects/find_file_link'
- if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true
#tree-holder.tree-holder.clearfix
.nav-block
= render 'projects/tree/tree_header', tree: @tree
#tree-holder.tree-holder.clearfix
.nav-block
= render 'projects/tree/tree_header', tree: @tree
= render 'projects/tree/tree_content', tree: @tree
= render 'projects/tree/tree_content', tree: @tree
......@@ -2,7 +2,7 @@
= render 'nav'
.top-area
.nav-text
.nav-text.wiki-page
%strong
- if @page.persisted?
= link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
......
- if @issues.any?
- if @issues.reorder(nil).any?
- @issues.group_by(&:project).each do |group|
.panel.panel-default.panel-small
- project = group[0]
......
%span.label-row
- if can?(current_user, :admin_label, @project)
.js-toggle-priority.toggle-priority{ data: { url: remove_priority_namespace_project_label_path(@project.namespace, @project, label),
dom_id: dom_id(label) } }
%button.add-priority.btn.has-tooltip{ title: 'Prioritize', :'data-placement' => 'top' }
= icon('star-o')
%button.remove-priority.btn.has-tooltip{ title: 'Remove priority', :'data-placement' => 'top' }
= icon('star')
%span.label-name
= link_to_label(label, tooltip: false)
%span.prepend-left-10
= markdown(label.description, pipeline: :single_line)
\ No newline at end of file
= markdown(label.description, pipeline: :single_line)
- labels.each do |label|
%span.label-row
= link_to_label(label, tooltip: false)
%span.label-row.btn-group{ role: "group", aria: { label: escape_once(label.name) }, style: "color: #{text_color_for_bg(label.color)}" }
= link_to namespace_project_label_path(@project.namespace, @project, label),
class: "btn btn-transparent has-tooltip",
style: "background-color: #{label.color};",
title: escape_once(label.description),
data: { container: "body" } do
= escape_once label.name
%button.btn.btn-transparent.label-remove.js-label-filter-remove{ type: "button", style: "background-color: #{label.color};", data: { label: label.title } }
= icon("times")
......@@ -8,6 +8,8 @@
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort
%li
= link_to page_filter_path(sort: sort_value_priority) do
= sort_title_priority
= link_to page_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to page_filter_path(sort: sort_value_oldest_created) do
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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