Upstream version 8.4.0+dfsg~rc2

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJWnhL+AAoJEM4fnGdFEsIqmloP/0HpUbaj7HfM+R02jhLqK9fs
 lZ0vFBqfpLGM9rQRXqCmGFpYObsmiGZgoWmpIhDBoW/JljXH8pa4C/1En6qHMVC8
 l7d+5TqbKekwGaaqKVsP9/T/1lsgcf1vIcQZRa63VvIPYQ9bZKuzaMV8/h9YiIOo
 qlYfHWt122d6xRj3pQdpNrmEwtniBwiTQbwMm78RbS9kU/AeIlfBSaBuW64c9DHy
 C1K0L6naYu+4EFquwo9zdpWGF0P+DjfAK0TEOoJK6EBVrurnSbdSjPwTgJaFpXuy
 SdJc8G5EdOp8nMvPBjDGwfw5UOoPcENhb+Ru6X3Q/ltW8I4qr0OT0JsHPdwPE7db
 IIpZN/zrSVOEe9tom6QkEWcKvjh3iJA/bDAJT6uQdvV8y8ZwNRx21LEw1C3plAsO
 lvmH7Pvzel/LjHYPOJfEI+i0AbFTh5NlVj2v66VYsxOCB70M2wKIHX8RsvMtdEYA
 rt5PiTFABZKb3WjjE+Kvxeue/ETJgBUmOLr+7x4KXOMxdsWuXI3qYL07kmSYTjlG
 5kYSorGyQXnaZg27MqFiVplmIT4dXnDIJn7mMYPi79cmTMYMOdVtSkF7CZc03lax
 9KOsWNi7DtCuVK6cTuahnkaWAoOZeYu8kODE/FH60tuKSiQWOvijCquRdJ0bE0SV
 ypBN93pst422K3lb8L10
 =mu//
 -----END PGP SIGNATURE-----

Merge tag 'upstream/8.4.0+dfsg_rc2'

Upstream version 8.4.0+dfsg~rc2

# gpg: Signature made Tuesday 19 January 2016 04:12:06 PM IST using RSA key ID 4512C22A
# gpg: Good signature from "Praveen Arimbrathodiyil (piratepin) <praveen@debian.org>"
# gpg:                 aka "Pirate Praveen (pirates.org.in) <praveen@onenetbeyond.org>"
# gpg:                 aka "Pirate Praveen (piratesin) <me@j4v4m4n.in>"
# gpg:                 aka "Pirate Praveen (PP) <praveen@privacyrequired.com>"
# gpg:                 aka "Praveen Arimbrathodiyil (j4v4m4n) <pravi.a@gmail.com>"
This commit is contained in:
Praveen Arimbrathodiyil 2016-01-19 16:12:12 +05:30
commit 94edbca68b
341 changed files with 5861 additions and 1687 deletions

View file

@ -1,6 +1,9 @@
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.4.0 (unreleased) v 8.4.0 (unreleased)
- Add pagination headers to already paginated API resources
- Properly generate diff of orphan commits, like the first commit in a repository
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse) - Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
- Improved performance of finding issues for an entire group (Yorick Peterse) - Improved performance of finding issues for an entire group (Yorick Peterse)
- Added custom application performance measuring system powered by InfluxDB (Yorick Peterse) - Added custom application performance measuring system powered by InfluxDB (Yorick Peterse)
@ -13,8 +16,11 @@ v 8.4.0 (unreleased)
- Fix missing date of month in network graph when commits span a month (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
- Remove gray background from layout in UI
- Fix signup for OAuth providers that don't provide a name
- Implement new UI for group page - Implement new UI for group page
- Implement search inside emoji picker - Implement search inside emoji picker
- Let the CI runner know about builds that this build depends on
- Add API support for looking up a user by username (Stan Hu) - Add API support for looking up a user by username (Stan Hu)
- Add project permissions to all project API endpoints (Stan Hu) - Add project permissions to all project API endpoints (Stan Hu)
- Link to milestone in "Milestone changed" system note - Link to milestone in "Milestone changed" system note
@ -42,9 +48,20 @@ v 8.4.0 (unreleased)
- Ajax filter by message for commits page - Ajax filter by message for commits page
- API: Add support for deleting a tag via the API (Robert Schilling) - API: Add support for deleting a tag via the API (Robert Schilling)
- Allow subsequent validations in CI Linter - Allow subsequent validations in CI Linter
- Show referenced MRs & Issues only when the current viewer can access them
- Fix Encoding::CompatibilityError bug when markdown content has some complex URL (Jason Lee)
- Add API support for managing project's builds
- Add API support for managing project's build triggers
- Add API support for managing project's build variables
- Allow broadcast messages to be edited
- Autosize Markdown textareas
- Import GitHub wiki into GitLab
- Add reporters ability to download and browse build artifacts (Andrew Johnson)
- Autofill referring url in message box when reporting user abuse. (Josh Frye)
v 8.3.4 v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug) - Use gitlab-workhorse 0.5.4 (fixes API routing bug)
- Add build artifacts browser
v 8.3.3 v 8.3.3
- Preserve CE behavior with JIRA integration by only calling API if URL is set - Preserve CE behavior with JIRA integration by only calling API if URL is set
@ -59,6 +76,8 @@ v 8.3.3
- Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu)
- Use WOFF versions of SourceSansPro fonts - Use WOFF versions of SourceSansPro fonts
- Fix regression when builds were not generated for tags created through web/api interface - Fix regression when builds were not generated for tags created through web/api interface
- Fix: maintain milestone filter between Open and Closed tabs (Greg Smethells)
- Fix missing artifacts and build traces for build created before 8.3
v 8.3.2 v 8.3.2
- Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu) - Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu)
@ -76,6 +95,7 @@ v 8.3.0
- Add open_issues_count to project API (Stan Hu) - Add open_issues_count to project API (Stan Hu)
- Expand character set of usernames created by Omniauth (Corey Hinshaw) - Expand character set of usernames created by Omniauth (Corey Hinshaw)
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg) - Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
- Add unsubscribe link in the email footer (Zeger-Jan van de Weg)
- Provide better diagnostic message upon project creation errors (Stan Hu) - Provide better diagnostic message upon project creation errors (Stan Hu)
- Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu) - Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu)
- Remove api credentials from link to build_page - Remove api credentials from link to build_page

View file

@ -334,9 +334,9 @@ merge request:
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript) 1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript)
1. [Shell commands](doc/development/shell_commands.md) created by GitLab 1. [Shell commands](doc/development/shell_commands.md) created by GitLab
contributors to enhance security contributors to enhance security
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
1. [Database Migrations](doc/development/migration_style_guide.md) 1. [Database Migrations](doc/development/migration_style_guide.md)
1. [Documentation styleguide](doc_styleguide.md) 1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
1. [Documentation styleguide](doc/development/doc_styleguide.md)
1. Interface text should be written subjectively instead of objectively. It 1. Interface text should be written subjectively instead of objectively. It
should be the GitLab core team addressing a person. It should be written in should be the GitLab core team addressing a person. It should be written in
present time and never use past tense (has been/was). For example instead present time and never use past tense (has been/was). For example instead

View file

@ -2,6 +2,6 @@
# https://gitlab.com/gitlab-org/omnibus-gitlab or the init scripts in # https://gitlab.com/gitlab-org/omnibus-gitlab or the init scripts in
# lib/support/init.d, which call scripts in bin/ . # lib/support/init.d, which call scripts in bin/ .
# #
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"} web: RAILS_ENV=development bin/web start_foreground
worker: bundle exec sidekiq -q post_receive -q mailers -q archive_repo -q system_hook -q project_web_hook -q gitlab_shell -q incoming_email -q runner -q common -q default worker: RAILS_ENV=development bin/background_jobs start_foreground
# mail_room: bundle exec mail_room -q -c config/mail_room.yml # mail_room: bundle exec mail_room -q -c config/mail_room.yml

View file

@ -1 +1 @@
8.4.0.rc1 8.4.0-rc2

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,7 +1,7 @@
class @Activities class @Activities
constructor: -> constructor: ->
Pager.init 20, true Pager.init 20, true
$(".event-filter .btn").bind "click", (event) => $(".event-filter a").bind "click", (event) =>
event.preventDefault() event.preventDefault()
@toggleFilter($(event.currentTarget)) @toggleFilter($(event.currentTarget))
@reloadActivities() @reloadActivities()
@ -12,7 +12,7 @@ class @Activities
toggleFilter: (sender) -> toggleFilter: (sender) ->
sender.toggleClass "active" sender.closest('li').toggleClass "active"
event_filters = $.cookie("event_filter") event_filters = $.cookie("event_filter")
filter = sender.attr("id").split("_")[0] filter = sender.attr("id").split("_")[0]
if event_filters if event_filters

View file

@ -10,19 +10,19 @@ class @Admin
$('body').on 'click', '.js-toggle-colors-link', (e) -> $('body').on 'click', '.js-toggle-colors-link', (e) ->
e.preventDefault() e.preventDefault()
$('.js-toggle-colors-link').hide() $('.js-toggle-colors-container').toggle()
$('.js-toggle-colors-container').show()
$('input#broadcast_message_color').on 'input', -> $('input#broadcast_message_color').on 'input', ->
previewColor = $('input#broadcast_message_color').val() previewColor = $(@).val()
$('div.broadcast-message-preview').css('background-color', previewColor) $('div.broadcast-message-preview').css('background-color', previewColor)
$('input#broadcast_message_font').on 'input', -> $('input#broadcast_message_font').on 'input', ->
previewColor = $('input#broadcast_message_font').val() previewColor = $(@).val()
$('div.broadcast-message-preview').css('color', previewColor) $('div.broadcast-message-preview').css('color', previewColor)
$('textarea#broadcast_message_message').on 'input', -> $('textarea#broadcast_message_message').on 'input', ->
previewMessage = $('textarea#broadcast_message_message').val() previewMessage = $(@).val()
previewMessage = "Your message here" if previewMessage.trim() == ''
$('div.broadcast-message-preview span').text(previewMessage) $('div.broadcast-message-preview span').text(previewMessage)
$('.log-tabs a').click (e) -> $('.log-tabs a').click (e) ->

View file

@ -5,7 +5,7 @@ class @AwardsHandler
event.preventDefault() event.preventDefault()
$(".emoji-menu").show() $(".emoji-menu").show()
$("html").click -> $("html").on 'click', (event) ->
if !$(event.target).closest(".emoji-menu").length if !$(event.target).closest(".emoji-menu").length
if $(".emoji-menu").is(":visible") if $(".emoji-menu").is(":visible")
$(".emoji-menu").hide() $(".emoji-menu").hide()

View file

@ -0,0 +1,4 @@
#= require autosize
$ ->
autosize($('.js-autosize'))

View file

@ -6,11 +6,25 @@ class @Issue
constructor: -> constructor: ->
# Prevent duplicate event bindings # Prevent duplicate event bindings
@disableTaskList() @disableTaskList()
@fixAffixScroll()
if $('a.btn-close').length if $('a.btn-close').length
@initTaskList() @initTaskList()
@initIssueBtnEventListeners() @initIssueBtnEventListeners()
fixAffixScroll: ->
fixAffix = ->
$discussion = $('.issuable-discussion')
$sidebar = $('.issuable-sidebar')
if $sidebar.hasClass('no-affix')
$sidebar.removeClass(['affix-top','affix'])
discussionHeight = $discussion.height()
sidebarHeight = $sidebar.height()
if sidebarHeight > discussionHeight
$discussion.height(sidebarHeight + 50)
$sidebar.addClass('no-affix')
$(window).on('resize', fixAffix)
fixAffix()
initTaskList: -> initTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('enable') $('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList

View file

@ -15,6 +15,8 @@ class @MergeRequest
this.$('.show-all-commits').on 'click', => this.$('.show-all-commits').on 'click', =>
this.showAllCommits() this.showAllCommits()
@fixAffixScroll();
@initTabs() @initTabs()
# Prevent duplicate event bindings # Prevent duplicate event bindings
@ -28,6 +30,20 @@ class @MergeRequest
$: (selector) -> $: (selector) ->
this.$el.find(selector) this.$el.find(selector)
fixAffixScroll: ->
fixAffix = ->
$discussion = $('.issuable-discussion')
$sidebar = $('.issuable-sidebar')
if $sidebar.hasClass('no-affix')
$sidebar.removeClass(['affix-top','affix'])
discussionHeight = $discussion.height()
sidebarHeight = $sidebar.height()
if sidebarHeight > discussionHeight
$discussion.height(sidebarHeight + 50)
$sidebar.addClass('no-affix')
$(window).on('resize', fixAffix)
fixAffix()
initTabs: -> initTabs: ->
if @opts.action != 'new' if @opts.action != 'new'
# `MergeRequests#new` has no tab-persisting or lazy-loading behavior # `MergeRequests#new` has no tab-persisting or lazy-loading behavior
@ -48,14 +64,15 @@ class @MergeRequest
_this = @ _this = @
$('a.btn-close, a.btn-reopen').on 'click', (e) -> $('a.btn-close, a.btn-reopen').on 'click', (e) ->
$this = $(this) $this = $(this)
if $this.data('submitted')
return
e.preventDefault()
e.stopImmediatePropagation()
shouldSubmit = $this.hasClass('btn-comment') shouldSubmit = $this.hasClass('btn-comment')
console.log("shouldSubmit") if shouldSubmit && $this.data('submitted')
return
if shouldSubmit if shouldSubmit
_this.submitNoteForm($this.closest('form'),$this) if $this.hasClass('btn-comment-and-close') || $this.hasClass('btn-comment-and-reopen')
e.preventDefault()
e.stopImmediatePropagation()
_this.submitNoteForm($this.closest('form'),$this)
submitNoteForm: (form, $button) => submitNoteForm: (form, $button) =>
noteText = form.find("textarea.js-note-text").val() noteText = form.find("textarea.js-note-text").val()

View file

@ -5,7 +5,7 @@
# #
# ### Example Markup # ### Example Markup
# #
# <ul class="nav nav-tabs merge-request-tabs"> # <ul class="nav-links merge-request-tabs">
# <li class="notes-tab active"> # <li class="notes-tab active">
# <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1"> # <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1">
# Discussion # Discussion

View file

@ -1,4 +1,5 @@
#= require autosave #= require autosave
#= require autosize
#= require dropzone #= require dropzone
#= require dropzone_input #= require dropzone_input
#= require gfm_auto_complete #= require gfm_auto_complete
@ -246,6 +247,7 @@ class @Notes
else else
previewButton.removeClass("turn-on").addClass "turn-off" previewButton.removeClass("turn-on").addClass "turn-off"
autosize(textarea)
new Autosave textarea, [ new Autosave textarea, [
"Note" "Note"
form.find("#note_commit_id").val() form.find("#note_commit_id").val()
@ -353,7 +355,7 @@ class @Notes
$('.note[id="' + note_id + '"]').each -> $('.note[id="' + note_id + '"]').each ->
note = $(this) note = $(this)
notes = note.closest(".notes") notes = note.closest(".notes")
count = notes.closest(".notes_holder").find(".discussion-notes-count") count = notes.closest(".issuable-details").find(".notes-tab .badge")
# check if this is the last note for this line # check if this is the last note for this line
if notes.find(".note").length is 1 if notes.find(".note").length is 1
@ -363,9 +365,10 @@ class @Notes
# for diff lines # for diff lines
notes.closest("tr").remove() notes.closest("tr").remove()
else
# update notes count # update notes count
count.get(0).lastChild.nodeValue = " #{notes.children().length - 1}" oldNum = parseInt(count.text())
count.text(oldNum - 1)
note.remove() note.remove()
@ -521,9 +524,13 @@ class @Notes
if textarea.val().trim().length > 0 if textarea.val().trim().length > 0
form.find('.js-note-target-reopen').text('Comment & reopen') form.find('.js-note-target-reopen').text('Comment & reopen')
form.find('.js-note-target-close').text('Comment & close') form.find('.js-note-target-close').text('Comment & close')
form.find('.js-note-target-reopen').addClass('btn-comment-and-reopen')
form.find('.js-note-target-close').addClass('btn-comment-and-close')
else else
form.find('.js-note-target-reopen').text('Reopen') form.find('.js-note-target-reopen').text('Reopen')
form.find('.js-note-target-close').text('Close') form.find('.js-note-target-close').text('Close')
form.find('.js-note-target-reopen').removeClass('btn-comment-and-reopen')
form.find('.js-note-target-close').removeClass('btn-comment-and-close')
initTaskList: -> initTaskList: ->
@enableTaskList() @enableTaskList()

View file

@ -1,17 +1,18 @@
#= require latinise
class @Wikis class @Wikis
constructor: -> constructor: ->
$('.build-new-wiki').bind "click", (e) -> $('.build-new-wiki').bind 'click', (e) =>
$('[data-error~=slug]').addClass("hidden") $('[data-error~=slug]').addClass('hidden')
$('p.hint').show()
field = $('#new_wiki_path') field = $('#new_wiki_path')
valid_slug_pattern = /^[\w\/-]+$/ slug = @slugify(field.val())
slug = field.val() if (slug.length > 0)
if slug.match valid_slug_pattern
path = field.attr('data-wikis-path') path = field.attr('data-wikis-path')
if(slug.length > 0) location.href = path + '/' + slug
location.href = path + "/" + slug
else dasherize: (value) ->
e.preventDefault() value.replace(/[_\s]+/g, '-')
$('p.hint').hide()
$('[data-error~=slug]').removeClass("hidden") slugify: (value) =>
@dasherize(value.trim().toLowerCase().latinise())

View file

@ -24,6 +24,7 @@
@import "framework/lists.scss"; @import "framework/lists.scss";
@import "framework/markdown_area.scss"; @import "framework/markdown_area.scss";
@import "framework/mobile.scss"; @import "framework/mobile.scss";
@import "framework/nav.scss";
@import "framework/pagination.scss"; @import "framework/pagination.scss";
@import "framework/panels.scss"; @import "framework/panels.scss";
@import "framework/selects.scss"; @import "framework/selects.scss";

View file

@ -18,9 +18,9 @@
line-height: 36px; line-height: 36px;
} }
.content-block,
.gray-content-block { .gray-content-block {
margin: -$gl-padding; margin-top: 0;
margin-bottom: -$gl-padding;
background-color: $background-color; background-color: $background-color;
padding: $gl-padding; padding: $gl-padding;
margin-bottom: 0px; margin-bottom: 0px;
@ -86,10 +86,7 @@
.cover-block { .cover-block {
text-align: center; text-align: center;
background: $background-color; background: $background-color;
margin: -$gl-padding; padding-top: 44px;
margin-bottom: 0;
padding: 44px $gl-padding;
border-bottom: 1px solid $border-color;
position: relative; position: relative;
.avatar-holder { .avatar-holder {
@ -136,3 +133,19 @@
.block-connector { .block-connector {
margin-top: -1px; margin-top: -1px;
} }
.nav-block {
.controls {
float: right;
margin-top: 11px;
}
}
.content-block {
padding: $gl-padding 0;
border-bottom: 1px solid $border-color;
&.oneline-block {
line-height: 42px;
}
}

View file

@ -1,12 +1,8 @@
@mixin btn-default { @mixin btn-default {
@include border-radius(3px); @include border-radius(3px);
border-width: 1px; font-size: $gl-font-size;
border-style: solid;
font-size: 15px;
font-weight: 500; font-weight: 500;
line-height: 18px; padding: $gl-vert-padding $gl-padding;
padding: 11px $gl-padding;
letter-spacing: .4px;
&:focus, &:focus,
&:active { &:active {
@ -17,8 +13,6 @@
@mixin btn-middle { @mixin btn-middle {
@include btn-default; @include btn-default;
@include border-radius(3px);
padding: 11px 24px;
} }
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) { @mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
@ -74,16 +68,15 @@
@include btn-default; @include btn-default;
@include btn-white; @include btn-white;
&.btn-small,
&.btn-sm { &.btn-sm {
padding: 5px 10px; padding: 4px 10px;
} font-size: 13px;
line-height: 18px;
&.btn-nr {
padding: 7px 10px;
} }
&.btn-xs { &.btn-xs {
padding: 1px 5px; padding: 2px 5px;
} }
&.btn-success, &.btn-success,
@ -131,6 +124,12 @@
&:last-child { &:last-child {
margin-right: 0px; margin-right: 0px;
} }
&.btn-xs {
margin-right: 3px;
}
}
&.disabled {
pointer-events: auto !important;
} }
} }
@ -153,33 +152,42 @@
} }
} }
.btn-group-next {
.btn {
padding: 9px 0px;
font-size: 15px;
color: #7f8fa4;
border-color: #e7e9ed;
width: 140px;
.badge {
font-weight: normal;
background-color: #eee;
color: #78a;
}
&.active {
border-color: $gl-info;
background: $gl-info;
color: #fff;
.badge {
color: $gl-info;
background-color: white;
}
}
}
}
.btn-clipboard { .btn-clipboard {
border: none; border: none;
padding: 0 5px;
}
.input-group-btn {
.btn {
@include btn-gray;
@include btn-middle;
&:hover {
outline: none;
}
&:focus {
outline: none;
}
&:active {
outline: none;
}
&.btn-clipboard {
padding-left: 15px;
padding-right: 15px;
}
}
.active {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
border: 1px solid #c6cacf !important;
background-color: #e4e7ed !important;
}
.btn-green {
@include btn-green
}
} }

View file

@ -75,6 +75,8 @@ hr {
@include str-truncated; @include str-truncated;
} }
.item-title { font-weight: 600; }
/** FLASH message **/ /** FLASH message **/
.author_link { .author_link {
color: $gl-link-color; color: $gl-link-color;
@ -374,75 +376,6 @@ table {
} }
} }
.center-top-menu, .left-top-menu {
@include nav-menu;
text-align: center;
margin-top: 5px;
margin-bottom: $gl-padding;
height: auto;
margin-top: -$gl-padding;
&.no-bottom {
margin-bottom: 0;
}
&.no-top {
margin-top: 0;
}
li a {
display: inline-block;
padding-top: $gl-padding;
padding-bottom: 11px;
margin-bottom: -1px;
}
&.bottom-border {
border-bottom: 1px solid $border-color;
height: 57px;
}
&.wide {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
}
}
.left-top-menu {
text-align: left;
border-bottom: 1px solid #EEE;
}
.center-middle-menu {
@include nav-menu;
padding: 0;
text-align: center;
margin: -$gl-padding;
margin-top: 0;
margin-bottom: 0;
height: 58px;
border-bottom: 1px solid $border-color;
li {
&:after {
content: "|";
color: $border-gray-light;
}
&:last-child {
&:after {
content: none;
}
}
> a {
display: inline-block;
text-transform: uppercase;
font-size: 13px;
}
}
}
.dropzone .dz-preview .dz-progress { .dropzone .dz-preview .dz-progress {
border-color: $border-color !important; border-color: $border-color !important;
} }

View file

@ -3,11 +3,8 @@
* *
*/ */
.file-holder { .file-holder {
margin-left: -$gl-padding;
margin-right: -$gl-padding;
border: none; border: none;
border-top: 1px solid #E7E9EE; border: 1px solid $border-color;
border-bottom: 1px solid #E7E9EE;
&.readme-holder { &.readme-holder {
border-bottom: 0; border-bottom: 0;

View file

@ -8,10 +8,12 @@
.flash-notice { .flash-notice {
@extend .alert; @extend .alert;
@extend .alert-info; @extend .alert-info;
margin: 0;
} }
.flash-alert { .flash-alert {
@extend .alert; @extend .alert;
@extend .alert-danger; @extend .alert-danger;
margin: 0;
} }
} }

View file

@ -3,23 +3,39 @@
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf.woff'); src:
local('Source Sans Pro Light'),
local('SourceSansPro-Light'),
font-url('SourceSansPro-Light.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Light.ttf.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf.woff'); src:
local('Source Sans Pro'),
local('SourceSansPro-Regular'),
font-url('SourceSansPro-Regular.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Regular.ttf.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf.woff'); src:
local('Source Sans Pro Semibold'),
local('SourceSansPro-Semibold'),
font-url('SourceSansPro-Semibold.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Semibold.ttf.woff') format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf.woff'); src:
local('Source Sans Pro Bold'),
local('SourceSansPro-Bold'),
font-url('SourceSansPro-Bold.ttf.woff2') format('woff2'),
font-url('SourceSansPro-Bold.ttf.woff') format('woff');
} }

View file

@ -74,8 +74,10 @@ label {
.form-control { .form-control {
@include box-shadow(none); @include box-shadow(none);
height: 42px; }
padding: 8px $gl-padding;
.form-control-inline {
display: inline;
} }
.wiki-content { .wiki-content {

View file

@ -28,6 +28,7 @@ header {
min-height: $header-height; min-height: $header-height;
background-color: #fff; background-color: #fff;
border: none; border: none;
border-bottom: 1px solid #EEE;
.container-fluid { .container-fluid {
width: 100% !important; width: 100% !important;

View file

@ -5,8 +5,6 @@ html {
} }
body { body {
background-color: #F3F3F3 !important;
&.navless { &.navless {
background-color: white !important; background-color: white !important;
} }

View file

@ -109,10 +109,8 @@ ul.content-list {
padding: 0; padding: 0;
> li { > li {
padding: $gl-padding; padding: $gl-padding 0;
border-color: $table-border-color; border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray; color: $gl-gray;
.avatar { .avatar {
@ -133,6 +131,7 @@ ul.content-list {
.panel > .content-list { .panel > .content-list {
li { li {
margin: 0; margin: 0;
padding: $gl-padding;
} }
} }

View file

@ -65,13 +65,6 @@
position: relative; position: relative;
} }
.md-header {
ul {
float: left;
margin-bottom: 1px;
}
}
.referenced-users { .referenced-users {
color: #4c4e54; color: #4c4e54;
padding-top: 10px; padding-top: 10px;
@ -85,28 +78,12 @@
box-shadow: none; box-shadow: none;
} }
.new_note,
.edit_note,
.detail-page-description,
.milestone-description,
.wiki-content,
.merge-request-form {
.nav-tabs {
margin-bottom: 0;
border: none;
li a,
li.active a {
border: 1px solid #DDD;
}
}
}
.markdown-area { .markdown-area {
@include border-radius(0); @include border-radius(0);
background: #FFF; background: #FFF;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;
max-height: 430px;
padding: 5px; padding: 5px;
box-shadow: none; box-shadow: none;
width: 100%; width: 100%;

View file

@ -118,38 +118,3 @@
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
} }
@mixin nav-menu {
padding: 0;
margin: 0;
list-style: none;
height: 56px;
li {
display: inline-block;
a {
padding: 14px;
font-size: 15px;
line-height: 28px;
color: #959494;
border-bottom: 2px solid transparent;
&:hover, &:active, &:focus {
text-decoration: none;
outline: none;
}
}
&.active a {
color: #616060;
border-bottom: 2px solid #4688f1;
}
.badge {
font-weight: normal;
background-color: #eee;
color: #78a;
}
}
}

View file

@ -9,7 +9,7 @@
padding-right: 5px; padding-right: 5px;
} }
.nav.nav-tabs > li > a { .nav-links > li > a {
padding: 10px; padding: 10px;
font-size: 12px; font-size: 12px;
margin-right: 3px; margin-right: 3px;
@ -81,7 +81,7 @@
display: none; display: none;
} }
.center-top-menu, .left-top-menu { .nav-links, .nav-links {
li a { li a {
font-size: 14px; font-size: 14px;
padding: 19px 10px; padding: 19px 10px;
@ -100,11 +100,6 @@
} }
@media (max-width: $screen-sm-max) { @media (max-width: $screen-sm-max) {
.page-with-sidebar .content-wrapper {
padding: 0;
padding-top: 1px;
}
.issues-filters { .issues-filters {
.milestone-filter, .labels-filter { .milestone-filter, .labels-filter {
display: none; display: none;

View file

@ -0,0 +1,39 @@
.nav-links {
padding: 0;
margin: 0;
list-style: none;
height: auto;
border-bottom: 1px solid $border-color;
li {
display: inline-block;
a {
display: inline-block;
padding: 14px;
padding-top: $gl-padding;
padding-bottom: 11px;
margin-bottom: -1px;
font-size: 15px;
line-height: 28px;
color: #959494;
border-bottom: 2px solid transparent;
&:hover, &:active, &:focus {
text-decoration: none;
outline: none;
}
}
&.active a {
color: #000000;
border-bottom: 2px solid #4688f1;
}
.badge {
font-weight: normal;
background-color: #eee;
color: #78a;
}
}
}

View file

@ -3,8 +3,8 @@
.select2-choice { .select2-choice {
background: #FFF; background: #FFF;
border-color: #DDD; border-color: #DDD;
height: 42px; height: 36px;
padding: 8px $gl-padding; padding: 6px $gl-padding;
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 1.42857143; line-height: 1.42857143;

View file

@ -21,11 +21,10 @@
.content-wrapper { .content-wrapper {
width: 100%; width: 100%;
padding: 20px;
.container-fluid { .container-fluid {
background: #FFF; background: #FFF;
padding: $gl-padding; padding: 0 $gl-padding;
&.container-blank { &.container-blank {
background: none; background: none;

View file

@ -1,7 +1,5 @@
.table-holder { .table-holder {
margin: -$gl-padding; margin: 0;
margin-top: 0;
margin-bottom: 0;
} }
table { table {
@ -32,6 +30,7 @@ table {
} }
th { th {
background-color: $background-color;
font-weight: normal; font-weight: normal;
font-size: 15px; font-size: 15px;
border-bottom: 1px solid $border-color !important; border-bottom: 1px solid $border-color !important;

View file

@ -5,10 +5,8 @@
padding: 0; padding: 0;
.timeline-entry { .timeline-entry {
padding: $gl-padding; padding: $gl-padding 0;
border-color: $table-border-color; border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray; color: $gl-gray;
border-bottom: 1px solid $border-white-light; border-bottom: 1px solid $border-white-light;

View file

@ -99,47 +99,6 @@
} }
} }
// Nav tabs
.nav.nav-tabs {
margin-bottom: 15px;
li {
> a {
margin-right: 5px;
line-height: 20px;
border-color: #EEE;
color: #888;
border-bottom: 1px solid #ddd;
.badge {
background-color: #eee;
color: #888;
text-shadow: 0 1px 1px #fff;
}
i.fa {
line-height: 14px;
}
}
&.active {
> a {
border-color: #CCC;
border-bottom: 1px solid #fff;
color: #333;
font-weight: bold;
}
}
}
}
.nav-tabs > li > a,
.nav-pills > li > a {
color: #666;
}
.nav-pills > .active > a > span > .badge {
background-color: #fff;
color: $gl-primary;
}
/** /**
* fix to keep tooltips position in top navigation bar * fix to keep tooltips position in top navigation bar

View file

@ -46,7 +46,7 @@ $font-size-base: $gl-font-size;
// //
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start). //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
$padding-base-vertical: 9px; $padding-base-vertical: $gl-vert-padding;
$padding-base-horizontal: $gl-padding; $padding-base-horizontal: $gl-padding;
$component-active-color: #fff; $component-active-color: #fff;
$component-active-bg: $brand-info; $component-active-bg: $brand-info;

View file

@ -177,7 +177,7 @@ body {
} }
.page-title { .page-title {
margin-top: 0px; margin-top: $gl-padding;
line-height: 1.3; line-height: 1.3;
font-size: 1.25em; font-size: 1.25em;
font-weight: 600; font-weight: 600;

View file

@ -22,6 +22,7 @@ $header-height: 58px;
$fixed-layout-width: 1280px; $fixed-layout-width: 1280px;
$gl-gray: #5a5a5a; $gl-gray: #5a5a5a;
$gl-padding: 16px; $gl-padding: 16px;
$gl-vert-padding: 6px;
$gl-padding-top:10px; $gl-padding-top:10px;
$gl-avatar-size: 46px; $gl-avatar-size: 46px;
$secondary-text: #7f8fa4; $secondary-text: #7f8fa4;

View file

@ -4,7 +4,7 @@
position: absolute; position: absolute;
top: 0px; top: 0px;
right: 4px; right: 4px;
line-height: 40px; line-height: 56px;
} }
a.js-zen-leave { a.js-zen-leave {

View file

@ -35,6 +35,8 @@
} }
.commit-box { .commit-box {
border-top: 1px solid $border-color;
.commit-title { .commit-title {
margin: 0; margin: 0;
font-size: 23px; font-size: 23px;

View file

@ -1,7 +1,5 @@
.detail-page-header { .detail-page-header {
margin: -$gl-padding; padding: 11px 0;
padding: 7px $gl-padding;
margin-bottom: 0px;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
color: #5c5d5e; color: #5c5d5e;
font-size: 16px; font-size: 16px;

View file

@ -1,9 +1,7 @@
// Common // Common
.diff-file { .diff-file {
margin-left: -$gl-padding; border: 1px solid $border-color;
margin-right: -$gl-padding; border-top: none;
border: none;
border-bottom: 1px solid #E7E9EE;
.diff-header { .diff-header {
position: relative; position: relative;
@ -23,14 +21,6 @@
} }
} }
.diff-controls {
.btn {
padding: 0px 10px;
font-size: 13px;
line-height: 28px;
}
}
.commit-short-id { .commit-short-id {
font-family: $monospace_font; font-family: $monospace_font;
font-size: smaller; font-size: smaller;

View file

@ -4,9 +4,7 @@
*/ */
.event-item { .event-item {
font-size: $gl-font-size; font-size: $gl-font-size;
padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px); padding: $gl-padding 0 $gl-padding ($gl-avatar-size + 15px);
margin-left: -$gl-padding;
margin-right: -$gl-padding;
border-bottom: 1px solid $table-border-color; border-bottom: 1px solid $table-border-color;
color: #7f8fa4; color: #7f8fa4;

View file

@ -20,6 +20,11 @@
position: fixed; position: fixed;
top: 70px; top: 70px;
margin-right: 35px; margin-right: 35px;
&.no-affix {
position: relative;
top: 0;
}
} }
} }
} }
@ -27,10 +32,10 @@
.project-issuable-filter { .project-issuable-filter {
.controls { .controls {
float: right; float: right;
margin-top: 7px; margin-top: 11px;
} }
.center-top-menu { .nav-links {
text-align: left; text-align: left;
} }
} }
@ -105,8 +110,13 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
cite {
font-style: normal;
}
button { button {
float: right; float: right;
padding: 3px 5px;
} }
} }

View file

@ -6,7 +6,7 @@
.issue-title { .issue-title {
margin-bottom: 5px; margin-bottom: 5px;
font-size: $list-font-size; font-size: $list-font-size;
font-weight: bold; font-weight: 600;
} }
.issue-info { .issue-info {

View file

@ -3,9 +3,9 @@
* *
*/ */
.mr-state-widget { .mr-state-widget {
background: #F7F8FA; background: $background-color;
color: $gl-gray; color: $gl-gray;
border: 1px solid #dce0e6; border: 1px solid $border-color;
@include border-radius(2px); @include border-radius(2px);
form { form {
@ -150,7 +150,7 @@
.merge-request-title { .merge-request-title {
margin-bottom: 5px; margin-bottom: 5px;
font-size: $list-font-size; font-size: $list-font-size;
font-weight: bold; font-weight: 600;
} }
.merge-request-info { .merge-request-info {

View file

@ -159,6 +159,7 @@
.edit_note { .edit_note {
.markdown-area { .markdown-area {
min-height: 140px; min-height: 140px;
max-height: 430px;
} }
.note-form-actions { .note-form-actions {
background: transparent; background: transparent;

View file

@ -26,6 +26,8 @@
} }
.project-home-panel { .project-home-panel {
padding-bottom: 40px;
border-bottom: 1px solid $border-color;
.cover-controls { .cover-controls {
.project-settings-dropdown { .project-settings-dropdown {
@ -51,6 +53,8 @@
} }
.notifications-btn { .notifications-btn {
margin-top: -28px;
.fa-bell { .fa-bell {
margin-right: 6px; margin-right: 6px;
} }
@ -75,17 +79,6 @@
} }
} }
.git-clone-holder {
max-width: 498px;
.form-control {
background: #FFF;
font-size: 14px;
height: 42px;
margin-left: -1px;
}
}
.visibility-level-label { .visibility-level-label {
@extend .btn; @extend .btn;
@extend .btn-gray; @extend .btn-gray;
@ -98,11 +91,6 @@
} }
} }
.git-clone-holder {
display: inline-table;
position: relative;
}
.project-repo-buttons { .project-repo-buttons {
margin-top: 12px; margin-top: 12px;
margin-bottom: 0px; margin-bottom: 0px;
@ -112,10 +100,22 @@
margin-bottom: 12px; margin-bottom: 12px;
} }
.clone-row {
.split-repo-buttons,
.project-clone-holder {
display: inline-block;
}
.split-repo-buttons {
margin: 0 12px;
}
}
.btn { .btn {
@include btn-gray; @include btn-gray;
text-transform: none; text-transform: none;
} }
.count-with-arrow { .count-with-arrow {
display: inline-block; display: inline-block;
position: relative; position: relative;
@ -160,8 +160,8 @@
border-style: solid; border-style: solid;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
line-height: 20px; line-height: 13px;
padding: 11px 16px; padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px; letter-spacing: .4px;
padding: 10px; padding: 10px;
text-align: center; text-align: center;
@ -189,117 +189,6 @@
} }
} }
.git-clone-holder {
.project-home-dropdown + & {
margin-right: 45px;
}
.clone-options {
display: table-cell;
a.btn {
width: 100%;
}
}
.form-control {
cursor: auto;
@extend .monospace;
background: #FAFAFA;
width: 101%;
}
.input-group-addon {
background: #f7f8fa;
&.git-protocols {
padding: 0;
border: none;
.input-group-btn:last-child > .btn {
@include border-radius-right(0);
border-left: 1px solid #c6cacf;
margin-left: -2px !important;
}
}
}
}
.projects-search-form {
.input-group .form-control {
height: 42px;
}
}
.input-group-btn {
.btn {
@include btn-gray;
@include btn-middle;
&:hover {
outline: none;
}
&:focus {
outline: none;
}
&:active {
outline: none;
}
&.btn-clipboard {
padding-left: 15px;
padding-right: 15px;
}
}
.active {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
border: 1px solid #c6cacf !important;
background-color: #e4e7ed !important;
}
.btn-green {
@include btn-green
}
}
.split-repo-buttons {
display: inline-table;
margin: 0 12px 0 12px;
.btn{
@include btn-gray;
@include btn-default;
}
.dropdown-toggle {
margin: -5px;
}
}
#notification-form {
margin-left: 5px;
}
.dropdown-new {
margin-left: -5px;
}
.open > .dropdown-new.btn {
@include box-shadow(inset 0 0 4px rgba(0, 0, 0, 0.12));
border: 1px solid #c6cacf !important;
background-color: #e4e7ed !important;
text-transform: none;
color: #313236 !important;
font-size: 15px;
}
.dropdown-menu { .dropdown-menu {
@include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px); @include box-shadow(rgba(76, 86, 103, 0.247059) 0px 0px 1px 0px, rgba(31, 37, 50, 0.317647) 0px 2px 18px 0px);
@include border-radius (0px); @include border-radius (0px);
@ -351,28 +240,6 @@
color: #555; color: #555;
} }
ul.nav.nav-projects-tabs {
@extend .nav-tabs;
padding-left: 8px;
li {
a {
padding: 6px 25px;
margin-top: 2px;
border-color: #DDD;
background-color: #EEE;
text-shadow: 0 1px 1px white;
color: #555;
}
&.active {
a {
font-weight: bold;
}
}
}
}
.project_member_row form { .project_member_row form {
margin: 0px; margin: 0px;
} }
@ -399,9 +266,9 @@ ul.nav.nav-projects-tabs {
.breadcrumb.repo-breadcrumb { .breadcrumb.repo-breadcrumb {
padding: 0; padding: 0;
line-height: 42px;
background: transparent; background: transparent;
border: none; border: none;
line-height: 42px;
margin: 0; margin: 0;
> li + li:before { > li + li:before {
@ -416,11 +283,8 @@ ul.nav.nav-projects-tabs {
.top-area { .top-area {
border-bottom: 1px solid #EEE; border-bottom: 1px solid #EEE;
margin: 0 -16px;
padding: 0 $gl-padding;
height: 42px;
ul.left-top-menu { ul.nav-links {
display: inline-block; display: inline-block;
width: 50%; width: 50%;
margin-bottom: 0px; margin-bottom: 0px;
@ -431,12 +295,12 @@ ul.nav.nav-projects-tabs {
width: 50%; width: 50%;
display: inline-block; display: inline-block;
float: right; float: right;
padding-top: 7px; padding-top: 11px;
text-align: right; text-align: right;
.btn-green { .btn-green {
margin-top: -2px;
margin-left: 10px; margin-left: 10px;
float: right;
} }
} }
@ -482,11 +346,11 @@ table.table.protected-branches-list tr.no-border {
padding-top: 10px; padding-top: 10px;
padding-bottom: 4px; padding-bottom: 4px;
ul.nav-pills { ul.nav {
display:inline-block; display:inline-block;
} }
.nav-pills li { .nav li {
display:inline; display:inline;
} }
@ -523,8 +387,7 @@ pre.light-well {
} }
.projects-search-form { .projects-search-form {
margin: -$gl-padding; padding: $gl-padding 0;
padding: $gl-padding;
padding-bottom: 0; padding-bottom: 0;
margin-bottom: 0px; margin-bottom: 0px;
@ -574,10 +437,8 @@ pre.light-well {
@include basic-list; @include basic-list;
.project-row { .project-row {
padding: $gl-padding; padding: $gl-padding 0;
border-color: $table-border-color; border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
&.no-description { &.no-description {
.project { .project {
@ -631,8 +492,6 @@ pre.light-well {
} }
.project-last-commit { .project-last-commit {
margin: 0 7px;
.ci-status { .ci-status {
margin-right: 16px; margin-right: 16px;
} }
@ -662,9 +521,7 @@ pre.light-well {
} }
.project-show-readme .readme-holder { .project-show-readme .readme-holder {
margin-left: -$gl-padding; padding: $gl-padding 0;
margin-right: -$gl-padding;
padding: ($gl-padding + 7px);
border-top: 0; border-top: 0;
.edit-project-readme { .edit-project-readme {
@ -672,3 +529,32 @@ pre.light-well {
position: relative; position: relative;
} }
} }
.git-clone-holder {
width: 498px;
.btn-clipboard {
border: 1px solid $border-color;
padding: 6px $gl-padding;
}
.project-home-dropdown + & {
margin-right: 45px;
}
.clone-options {
display: table-cell;
a.btn {
width: 100%;
}
}
.form-control {
@extend .monospace;
background: #FFF;
font-size: 14px;
margin-left: -1px;
cursor: auto;
width: 101%;
}
}

View file

@ -1,4 +1,7 @@
.tree-holder { .tree-holder {
> .nav-block {
margin: 11px 0;
}
.file-finder { .file-finder {
width: 50%; width: 50%;
@ -13,7 +16,7 @@
tr { tr {
> td, > th { > td, > th {
line-height: 28px; line-height: 26px;
} }
&:hover { &:hover {
@ -86,12 +89,14 @@
.blob-commit-info { .blob-commit-info {
list-style: none; list-style: none;
padding: $gl-padding;
background: $background-color;
border: 1px solid $border-color;
border-bottom: none;
margin: 0; margin: 0;
padding: 0;
margin-bottom: 5px;
.commit { .commit {
padding: $gl-padding 0; padding: 0;
.commit-row-title { .commit-row-title {
.commit-row-message { .commit-row-message {
@ -115,3 +120,8 @@
font-weight: normal; font-weight: normal;
color: $md-link-color; color: $md-link-color;
} }
.tree-controls {
float: right;
margin-top: 11px;
}

View file

@ -2,6 +2,7 @@ class AbuseReportsController < ApplicationController
def new def new
@abuse_report = AbuseReport.new @abuse_report = AbuseReport.new
@abuse_report.user_id = params[:user_id] @abuse_report.user_id = params[:user_id]
@ref_url = params.fetch(:ref_url, '')
end end
def create def create

View file

@ -73,6 +73,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_pool_size, :metrics_pool_size,
:metrics_timeout, :metrics_timeout,
:metrics_method_call_threshold, :metrics_method_call_threshold,
:metrics_sample_interval,
:recaptcha_enabled, :recaptcha_enabled,
:recaptcha_site_key, :recaptcha_site_key,
:recaptcha_private_key, :recaptcha_private_key,

View file

@ -1,8 +1,12 @@
class Admin::BroadcastMessagesController < Admin::ApplicationController class Admin::BroadcastMessagesController < Admin::ApplicationController
before_action :broadcast_messages before_action :finder, only: [:edit, :update, :destroy]
def index def index
@broadcast_message = BroadcastMessage.new @broadcast_messages = BroadcastMessage.reorder("starts_at ASC").page(params[:page])
@broadcast_message = BroadcastMessage.new
end
def edit
end end
def create def create
@ -15,8 +19,16 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
end end
end end
def update
if @broadcast_message.update(broadcast_message_params)
redirect_to admin_broadcast_messages_path, notice: 'Broadcast Message was successfully updated.'
else
render :edit
end
end
def destroy def destroy
BroadcastMessage.find(params[:id]).destroy @broadcast_message.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_back_or_default(default: { action: 'index' }) } format.html { redirect_back_or_default(default: { action: 'index' }) }
@ -26,14 +38,17 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
protected protected
def broadcast_messages def finder
@broadcast_messages ||= BroadcastMessage.order("starts_at DESC").page(params[:page]) @broadcast_message = BroadcastMessage.find(params[:id])
end end
def broadcast_message_params def broadcast_message_params
params.require(:broadcast_message).permit( params.require(:broadcast_message).permit(%i(
:alert_type, :color, :ends_at, :font, color
:message, :starts_at ends_at
) font
message
starts_at
))
end end
end end

View file

@ -26,6 +26,7 @@ class Admin::IdentitiesController < Admin::ApplicationController
def update def update
if @identity.update_attributes(identity_params) if @identity.update_attributes(identity_params)
RepairLdapBlockedUserService.new(@user).execute
redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully updated.' redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully updated.'
else else
render :edit render :edit
@ -34,6 +35,7 @@ class Admin::IdentitiesController < Admin::ApplicationController
def destroy def destroy
if @identity.destroy if @identity.destroy
RepairLdapBlockedUserService.new(@user).execute
redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully removed.' redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully removed.'
else else
redirect_to admin_user_identities_path(@user), alert: 'Failed to remove user identity.' redirect_to admin_user_identities_path(@user), alert: 'Failed to remove user identity.'

View file

@ -40,7 +40,9 @@ class Admin::UsersController < Admin::ApplicationController
end end
def unblock def unblock
if user.activate if user.ldap_blocked?
redirect_back_or_admin_user(alert: "This user cannot be unlocked manually from GitLab")
elsif user.activate
redirect_back_or_admin_user(notice: "Successfully unblocked") redirect_back_or_admin_user(notice: "Successfully unblocked")
else else
redirect_back_or_admin_user(alert: "Error occurred. User was not unblocked") redirect_back_or_admin_user(alert: "Error occurred. User was not unblocked")

View file

@ -115,7 +115,7 @@ class ApplicationController < ActionController::Base
# localhost/group/project # localhost/group/project
# #
if id =~ /\.git\Z/ if id =~ /\.git\Z/
redirect_to request.original_url.gsub(/\.git\Z/, '') and return redirect_to request.original_url.gsub(/\.git\/?\Z/, '') and return
end end
project_path = "#{namespace}/#{id}" project_path = "#{namespace}/#{id}"

View file

@ -0,0 +1,56 @@
class Projects::ArtifactsController < Projects::ApplicationController
layout 'project'
before_action :authorize_read_build_artifacts!
def download
unless artifacts_file.file_storage?
return redirect_to artifacts_file.url
end
unless artifacts_file.exists?
return render_404
end
send_file artifacts_file.path, disposition: 'attachment'
end
def browse
return render_404 unless build.artifacts?
directory = params[:path] ? "#{params[:path]}/" : ''
@entry = build.artifacts_metadata_entry(directory)
return render_404 unless @entry.exists?
end
def file
entry = build.artifacts_metadata_entry(params[:path])
if entry.exists?
render json: { archive: build.artifacts_file.path,
entry: Base64.encode64(entry.path) }
else
render json: {}, status: 404
end
end
private
def build
@build ||= project.builds.unscoped.find_by!(id: params[:build_id])
end
def artifacts_file
@artifacts_file ||= build.artifacts_file
end
def authorize_read_build_artifacts!
unless can?(current_user, :read_build_artifacts, @project)
if current_user.nil?
return authenticate_user!
else
return render_404
end
end
end
end

View file

@ -2,7 +2,6 @@ class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all] before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status] before_action :authorize_manage_builds!, except: [:index, :show, :status]
before_action :authorize_download_build_artifacts!, only: [:download]
layout "project" layout "project"
@ -43,7 +42,7 @@ class Projects::BuildsController < Projects::ApplicationController
def retry def retry
unless @build.retryable? unless @build.retryable?
return page_404 return render_404
end end
build = Ci::Build.retry(@build) build = Ci::Build.retry(@build)
@ -51,18 +50,6 @@ class Projects::BuildsController < Projects::ApplicationController
redirect_to build_path(build) redirect_to build_path(build)
end end
def download
unless artifacts_file.file_storage?
return redirect_to artifacts_file.url
end
unless artifacts_file.exists?
return not_found!
end
send_file artifacts_file.path, disposition: 'attachment'
end
def status def status
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha) render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
end end
@ -79,27 +66,13 @@ class Projects::BuildsController < Projects::ApplicationController
@build ||= project.builds.unscoped.find_by!(id: params[:id]) @build ||= project.builds.unscoped.find_by!(id: params[:id])
end end
def artifacts_file
build.artifacts_file
end
def build_path(build) def build_path(build)
namespace_project_build_path(build.project.namespace, build.project, build) namespace_project_build_path(build.project.namespace, build.project, build)
end end
def authorize_manage_builds! def authorize_manage_builds!
unless can?(current_user, :manage_builds, project) unless can?(current_user, :manage_builds, project)
return page_404 return render_404
end
end
def authorize_download_build_artifacts!
unless can?(current_user, :download_build_artifacts, @project)
if current_user.nil?
return authenticate_user!
else
return render_404
end
end end
end end
end end

View file

@ -79,7 +79,7 @@ class Projects::CommitController < Projects::ApplicationController
def authorize_manage_builds! def authorize_manage_builds!
unless can?(current_user, :manage_builds, project) unless can?(current_user, :manage_builds, project)
return page_404 return render_404
end end
end end
end end

View file

@ -49,7 +49,7 @@ class Projects::IssuesController < Projects::ApplicationController
assignee_id: "" assignee_id: ""
) )
@issue = @project.issues.new(issue_params) @issue = @noteable = @project.issues.new(issue_params)
respond_with(@issue) respond_with(@issue)
end end
@ -61,7 +61,7 @@ class Projects::IssuesController < Projects::ApplicationController
@note = @project.notes.new(noteable: @issue) @note = @project.notes.new(noteable: @issue)
@notes = @issue.notes.nonawards.with_associations.fresh @notes = @issue.notes.nonawards.with_associations.fresh
@noteable = @issue @noteable = @issue
@merge_requests = @issue.referenced_merge_requests @merge_requests = @issue.referenced_merge_requests(current_user)
respond_with(@issue) respond_with(@issue)
end end

View file

@ -90,6 +90,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def new def new
params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) params[:merge_request] ||= ActionController::Parameters.new(source_project: @project)
@merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute @merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute
@noteable = @merge_request
@target_branches = if @merge_request.target_project @target_branches = if @merge_request.target_project
@merge_request.target_project.repository.branch_names @merge_request.target_project.repository.branch_names

View file

@ -25,7 +25,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end end
def new def new
@snippet = @project.snippets.build @snippet = @noteable = @project.snippets.build
end end
def create def create

View file

@ -0,0 +1,25 @@
class SentNotificationsController < ApplicationController
skip_before_action :authenticate_user!
def unsubscribe
@sent_notification = SentNotification.for(params[:id])
return render_404 unless @sent_notification && @sent_notification.unsubscribable?
noteable = @sent_notification.noteable
noteable.unsubscribe(@sent_notification.recipient)
flash[:notice] = "You have been unsubscribed from this thread."
if current_user
case noteable
when Issue
redirect_to issue_path(noteable)
when MergeRequest
redirect_to merge_request_path(noteable)
else
redirect_to root_path
end
else
redirect_to new_user_session_path
end
end
end

View file

@ -181,10 +181,6 @@ module ApplicationHelper
end end
end end
def broadcast_message
BroadcastMessage.current
end
# Render a `time` element with Javascript-based relative date and tooltip # Render a `time` element with Javascript-based relative date and tooltip
# #
# time - Time object # time - Time object
@ -266,7 +262,7 @@ module ApplicationHelper
state: params[:state], state: params[:state],
scope: params[:scope], scope: params[:scope],
label_name: params[:label_name], label_name: params[:label_name],
milestone_id: params[:milestone_id], milestone_title: params[:milestone_title],
assignee_id: params[:assignee_id], assignee_id: params[:assignee_id],
author_id: params[:author_id], author_id: params[:author_id],
sort: params[:sort], sort: params[:sort],

View file

@ -1,16 +1,34 @@
module BroadcastMessagesHelper module BroadcastMessagesHelper
def broadcast_styling(broadcast_message) def broadcast_message(message = BroadcastMessage.current)
styling = '' return unless message.present?
content_tag :div, class: 'broadcast-message', style: broadcast_message_style(message) do
icon('bullhorn') << ' ' << message.message
end
end
def broadcast_message_style(broadcast_message)
style = ''
if broadcast_message.color.present? if broadcast_message.color.present?
styling << "background-color: #{broadcast_message.color}" style << "background-color: #{broadcast_message.color}"
styling << '; ' if broadcast_message.font.present? style << '; ' if broadcast_message.font.present?
end end
if broadcast_message.font.present? if broadcast_message.font.present?
styling << "color: #{broadcast_message.font}" style << "color: #{broadcast_message.font}"
end end
styling style
end
def broadcast_message_status(broadcast_message)
if broadcast_message.active?
'Active'
elsif broadcast_message.ended?
'Expired'
else
'Pending'
end
end end
end end

View file

@ -17,7 +17,7 @@ module ButtonHelper
def clipboard_button(data = {}) def clipboard_button(data = {})
content_tag :button, content_tag :button,
icon('clipboard'), icon('clipboard'),
class: 'btn btn-xs btn-clipboard', class: 'btn btn-clipboard',
data: data, data: data,
type: :button type: :button
end end

View file

@ -27,13 +27,15 @@ module EventsHelper
key = key.to_s key = key.to_s
active = 'active' if @event_filter.active?(key) active = 'active' if @event_filter.active?(key)
link_opts = { link_opts = {
class: "event-filter-link btn btn-default #{active}", class: "event-filter-link",
id: "#{key}_event_filter", id: "#{key}_event_filter",
title: "Filter by #{tooltip.downcase}", title: "Filter by #{tooltip.downcase}",
} }
link_to request.path, link_opts do content_tag :li, class: active do
content_tag(:span, ' ' + tooltip) link_to request.path, link_opts do
content_tag(:span, ' ' + tooltip)
end
end end
end end

View file

@ -91,7 +91,7 @@ module GitlabMarkdownHelper
def render_wiki_content(wiki_page) def render_wiki_content(wiki_page)
case wiki_page.format case wiki_page.format
when :markdown when :markdown
markdown(wiki_page.content) markdown(wiki_page.content, pipeline: :wiki, project_wiki: @project_wiki)
when :asciidoc when :asciidoc
asciidoc(wiki_page.content) asciidoc(wiki_page.content)
else else

View file

@ -1,31 +1,31 @@
module Emails module Emails
module Issues module Issues
def new_issue_email(recipient_id, issue_id) def new_issue_email(recipient_id, issue_id)
issue_mail_with_notification(issue_id, recipient_id) do setup_issue_mail(issue_id, recipient_id)
mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id))
end mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id))
end end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id)
issue_mail_with_notification(issue_id, recipient_id) do setup_issue_mail(issue_id, recipient_id)
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
end mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
end end
def closed_issue_email(recipient_id, issue_id, updated_by_user_id) def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
issue_mail_with_notification(issue_id, recipient_id) do setup_issue_mail(issue_id, recipient_id)
@updated_by = User.find updated_by_user_id
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) @updated_by = User.find updated_by_user_id
end mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
end end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
issue_mail_with_notification(issue_id, recipient_id) do setup_issue_mail(issue_id, recipient_id)
@issue_status = status
@updated_by = User.find updated_by_user_id @issue_status = status
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) @updated_by = User.find updated_by_user_id
end mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
end end
private private
@ -38,14 +38,12 @@ module Emails
} }
end end
def issue_mail_with_notification(issue_id, recipient_id) def setup_issue_mail(issue_id, recipient_id)
@issue = Issue.find(issue_id) @issue = Issue.find(issue_id)
@project = @issue.project @project = @issue.project
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue) @target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
yield @sent_notification = SentNotification.record(@issue, recipient_id, reply_key)
SentNotification.record(@issue, recipient_id, reply_key)
end end
end end
end end

View file

@ -1,77 +1,64 @@
module Emails module Emails
module MergeRequests module MergeRequests
def new_merge_request_email(recipient_id, merge_request_id) def new_merge_request_email(recipient_id, merge_request_id)
@merge_request = MergeRequest.find(merge_request_id) setup_merge_request_mail(merge_request_id, recipient_id)
@project = @merge_request.project
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
mail_new_thread(@merge_request, mail_new_thread(@merge_request,
from: sender(@merge_request.author_id), from: sender(@merge_request.author_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id) def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id) setup_merge_request_mail(merge_request_id, recipient_id)
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
mail_answer_thread(@merge_request, mail_answer_thread(@merge_request,
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id) setup_merge_request_mail(merge_request_id, recipient_id)
@updated_by = User.find updated_by_user_id @updated_by = User.find updated_by_user_id
@project = @merge_request.project
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
mail_answer_thread(@merge_request, mail_answer_thread(@merge_request,
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id) setup_merge_request_mail(merge_request_id, recipient_id)
@project = @merge_request.project
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
mail_answer_thread(@merge_request, mail_answer_thread(@merge_request,
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
SentNotification.record(@merge_request, recipient_id, reply_key)
end end
def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id) def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id) setup_merge_request_mail(merge_request_id, recipient_id)
@mr_status = status @mr_status = status
@project = @merge_request.project
@updated_by = User.find updated_by_user_id @updated_by = User.find updated_by_user_id
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
mail_answer_thread(@merge_request, mail_answer_thread(@merge_request,
from: sender(updated_by_user_id), from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
SentNotification.record(@merge_request, recipient_id, reply_key) private
def setup_merge_request_mail(merge_request_id, recipient_id)
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
@target_url = namespace_project_merge_request_url(@project.namespace,
@project,
@merge_request)
@sent_notification = SentNotification.record(@merge_request, recipient_id, reply_key)
end end
end end
end end

View file

@ -1,31 +1,31 @@
module Emails module Emails
module Notes module Notes
def note_commit_email(recipient_id, note_id) def note_commit_email(recipient_id, note_id)
note_mail_with_notification(note_id, recipient_id) do setup_note_mail(note_id, recipient_id)
@commit = @note.noteable
@target_url = namespace_project_commit_url(*note_target_url_options)
mail_answer_thread(@commit, @commit = @note.noteable
from: sender(@note.author_id), @target_url = namespace_project_commit_url(*note_target_url_options)
to: recipient(recipient_id),
subject: subject("#{@commit.title} (#{@commit.short_id})")) mail_answer_thread(@commit,
end from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@commit.title} (#{@commit.short_id})"))
end end
def note_issue_email(recipient_id, note_id) def note_issue_email(recipient_id, note_id)
note_mail_with_notification(note_id, recipient_id) do setup_note_mail(note_id, recipient_id)
@issue = @note.noteable
@target_url = namespace_project_issue_url(*note_target_url_options) @issue = @note.noteable
mail_answer_thread(@issue, note_thread_options(recipient_id)) @target_url = namespace_project_issue_url(*note_target_url_options)
end mail_answer_thread(@issue, note_thread_options(recipient_id))
end end
def note_merge_request_email(recipient_id, note_id) def note_merge_request_email(recipient_id, note_id)
note_mail_with_notification(note_id, recipient_id) do setup_note_mail(note_id, recipient_id)
@merge_request = @note.noteable
@target_url = namespace_project_merge_request_url(*note_target_url_options) @merge_request = @note.noteable
mail_answer_thread(@merge_request, note_thread_options(recipient_id)) @target_url = namespace_project_merge_request_url(*note_target_url_options)
end mail_answer_thread(@merge_request, note_thread_options(recipient_id))
end end
private private
@ -42,13 +42,11 @@ module Emails
} }
end end
def note_mail_with_notification(note_id, recipient_id) def setup_note_mail(note_id, recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@project = @note.project @project = @note.project
yield @sent_notification = SentNotification.record_note(@note, recipient_id, reply_key)
SentNotification.record_note(@note, recipient_id, reply_key)
end end
end end
end end

View file

@ -107,10 +107,9 @@ class Notify < BaseMailer
end end
headers["X-GitLab-#{model.class.name}-ID"] = model.id headers["X-GitLab-#{model.class.name}-ID"] = model.id
headers['X-GitLab-Reply-Key'] = reply_key
if reply_key if Gitlab::IncomingEmail.enabled?
headers['X-GitLab-Reply-Key'] = reply_key
address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key)) address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key))
address.display_name = @project.name_with_namespace address.display_name = @project.name_with_namespace

View file

@ -160,6 +160,7 @@ class Ability
@project_report_rules ||= project_guest_rules + [ @project_report_rules ||= project_guest_rules + [
:create_commit_status, :create_commit_status,
:read_commit_statuses, :read_commit_statuses,
:read_build_artifacts,
:download_code, :download_code,
:fork_project, :fork_project,
:create_project_snippet, :create_project_snippet,
@ -175,7 +176,6 @@ class Ability
:create_merge_request, :create_merge_request,
:create_wiki, :create_wiki,
:manage_builds, :manage_builds,
:download_build_artifacts,
:push_code :push_code
] ]
end end

View file

@ -6,7 +6,6 @@
# message :text not null # message :text not null
# starts_at :datetime # starts_at :datetime
# ends_at :datetime # ends_at :datetime
# alert_type :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# color :string(255) # color :string(255)
@ -23,7 +22,22 @@ class BroadcastMessage < ActiveRecord::Base
validates :color, allow_blank: true, color: true validates :color, allow_blank: true, color: true
validates :font, allow_blank: true, color: true validates :font, allow_blank: true, color: true
default_value_for :color, '#E75E40'
default_value_for :font, '#FFFFFF'
def self.current def self.current
where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last where("ends_at > :now AND starts_at <= :now", now: Time.zone.now).last
end
def active?
started? && !ended?
end
def started?
Time.zone.now >= starts_at
end
def ended?
ends_at < Time.zone.now
end end
end end

View file

@ -30,10 +30,12 @@
# description :string(255) # description :string(255)
# artifacts_file :text # artifacts_file :text
# gl_project_id :integer # gl_project_id :integer
# artifacts_metadata :text
# #
module Ci module Ci
class Build < CommitStatus class Build < CommitStatus
include Gitlab::Application.routes.url_helpers
LAZY_ATTRIBUTES = ['trace'] LAZY_ATTRIBUTES = ['trace']
belongs_to :runner, class_name: 'Ci::Runner' belongs_to :runner, class_name: 'Ci::Runner'
@ -49,6 +51,7 @@ module Ci
scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) } scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) }
mount_uploader :artifacts_file, ArtifactUploader mount_uploader :artifacts_file, ArtifactUploader
mount_uploader :artifacts_metadata, ArtifactUploader
acts_as_taggable acts_as_taggable
@ -125,6 +128,14 @@ module Ci
!self.commit.latest_builds_for_ref(self.ref).include?(self) !self.commit.latest_builds_for_ref(self.ref).include?(self)
end end
def depends_on_builds
# Get builds of the same type
latest_builds = self.commit.builds.similar(self).latest
# Return builds from previous stages
latest_builds.where('stage_idx < ?', stage_idx)
end
def trace_html def trace_html
html = Ci::Ansi2html::convert(trace) if trace.present? html = Ci::Ansi2html::convert(trace) if trace.present?
html || '' html || ''
@ -291,21 +302,18 @@ module Ci
end end
def target_url def target_url
Gitlab::Application.routes.url_helpers. namespace_project_build_url(project.namespace, project, self)
namespace_project_build_url(project.namespace, project, self)
end end
def cancel_url def cancel_url
if active? if active?
Gitlab::Application.routes.url_helpers. cancel_namespace_project_build_path(project.namespace, project, self)
cancel_namespace_project_build_path(project.namespace, project, self)
end end
end end
def retry_url def retry_url
if retryable? if retryable?
Gitlab::Application.routes.url_helpers. retry_namespace_project_build_path(project.namespace, project, self)
retry_namespace_project_build_path(project.namespace, project, self)
end end
end end
@ -321,20 +329,35 @@ module Ci
pending? && !any_runners_online? pending? && !any_runners_online?
end end
def download_url
if artifacts_file.exists?
Gitlab::Application.routes.url_helpers.
download_namespace_project_build_path(project.namespace, project, self)
end
end
def execute_hooks def execute_hooks
build_data = Gitlab::BuildDataBuilder.build(self) build_data = Gitlab::BuildDataBuilder.build(self)
project.execute_hooks(build_data.dup, :build_hooks) project.execute_hooks(build_data.dup, :build_hooks)
project.execute_services(build_data.dup, :build_hooks) project.execute_services(build_data.dup, :build_hooks)
end end
def artifacts?
artifacts_file.exists?
end
def artifacts_download_url
if artifacts?
download_namespace_project_build_artifacts_path(project.namespace, project, self)
end
end
def artifacts_browse_url
if artifacts_browser_supported?
browse_namespace_project_build_artifacts_path(project.namespace, project, self)
end
end
def artifacts_browser_supported?
artifacts? && artifacts_metadata.exists?
end
def artifacts_metadata_entry(path)
Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path).to_entry
end
private private

View file

@ -33,6 +33,10 @@ module Ci
trigger_requests.last trigger_requests.last
end end
def last_used
last_trigger_request.try(:created_at)
end
def short_token def short_token
token[0...10] token[0...10]
end end

View file

@ -18,8 +18,12 @@ module Ci
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
validates_presence_of :key
validates_uniqueness_of :key, scope: :gl_project_id validates_uniqueness_of :key, scope: :gl_project_id
validates :key,
presence: true,
length: { within: 0..255 },
format: { with: /\A[a-zA-Z0-9_]+\z/,
message: "can contain only letters, digits and '_'." }
attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base
end end

View file

@ -56,6 +56,8 @@ class CommitStatus < ActiveRecord::Base
scope :ordered, -> { order(:ref, :stage_idx, :name) } scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) } scope :for_ref, ->(ref) { where(ref: ref) }
AVAILABLE_STATUSES = ['pending', 'running', 'success', 'failed', 'canceled']
state_machine :status, initial: :pending do state_machine :status, initial: :pending do
event :run do event :run do
transition pending: :running transition pending: :running
@ -131,7 +133,11 @@ class CommitStatus < ActiveRecord::Base
false false
end end
def download_url def artifacts_download_url
nil
end
def artifacts_browse_url
nil nil
end end
end end

View file

@ -119,6 +119,12 @@ module Issuable
update(subscribed: !subscribed?(user)) update(subscribed: !subscribed?(user))
end end
def unsubscribe(user)
subscriptions.
find_or_initialize_by(user_id: user.id).
update(subscribed: false)
end
def to_hook_data(user) def to_hook_data(user)
{ {
object_kind: self.class.name.underscore, object_kind: self.class.name.underscore,

View file

@ -48,8 +48,8 @@ class WebHook < ActiveRecord::Base
else else
post_url = url.gsub("#{parsed_url.userinfo}@", "") post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = { auth = {
username: URI.decode(parsed_url.user), username: CGI.unescape(parsed_url.user),
password: URI.decode(parsed_url.password), password: CGI.unescape(parsed_url.password),
} }
response = WebHook.post(post_url, response = WebHook.post(post_url,
body: data.to_json, body: data.to_json,

View file

@ -18,4 +18,8 @@ class Identity < ActiveRecord::Base
validates :provider, presence: true validates :provider, presence: true
validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider } validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider }
validates :user_id, uniqueness: { scope: :provider } validates :user_id, uniqueness: { scope: :provider }
def ldap?
provider.starts_with?('ldap')
end
end end

View file

@ -85,10 +85,10 @@ class Issue < ActiveRecord::Base
reference reference
end end
def referenced_merge_requests def referenced_merge_requests(current_user = nil)
Gitlab::ReferenceExtractor.lazily do Gitlab::ReferenceExtractor.lazily do
[self, *notes].flat_map do |note| [self, *notes].flat_map do |note|
note.all_references.merge_requests note.all_references(current_user).merge_requests
end end
end.sort_by(&:iid) end.sort_by(&:iid)
end end

View file

@ -358,6 +358,10 @@ class Note < ActiveRecord::Base
!system? && !is_award !system? && !is_award
end end
def cross_reference_not_visible_for?(user)
cross_reference? && referenced_mentionables(user).empty?
end
# Checks if note is an award added as a comment # Checks if note is an award added as a comment
# #
# If note is an award, this method sets is_award to true # If note is an award, this method sets is_award to true

View file

@ -397,7 +397,7 @@ class Project < ActiveRecord::Base
result.password = '*****' unless result.password.nil? result.password = '*****' unless result.password.nil?
result.to_s result.to_s
rescue rescue
original_url self.import_url
end end
def check_limit def check_limit

View file

@ -120,13 +120,13 @@ class HipchatService < Service
message << "#{push[:user_name]} " message << "#{push[:user_name]} "
if Gitlab::Git.blank_ref?(before) if Gitlab::Git.blank_ref?(before)
message << "pushed new #{ref_type} <a href=\""\ message << "pushed new #{ref_type} <a href=\""\
"#{project_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\ "#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"\
" to #{project_link}\n" " to #{project_link}\n"
elsif Gitlab::Git.blank_ref?(after) elsif Gitlab::Git.blank_ref?(after)
message << "removed #{ref_type} <b>#{ref}</b> from <a href=\"#{project.web_url}\">#{project_name}</a> \n" message << "removed #{ref_type} <b>#{ref}</b> from <a href=\"#{project.web_url}\">#{project_name}</a> \n"
else else
message << "pushed to #{ref_type} <a href=\""\ message << "pushed to #{ref_type} <a href=\""\
"#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a> " "#{project.web_url}/commits/#{CGI.escape(ref)}\">#{ref}</a> "
message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> " message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> "
message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)" message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
@ -255,8 +255,8 @@ class HipchatService < Service
status = data[:commit][:status] status = data[:commit][:status]
duration = data[:commit][:duration] duration = data[:commit][:duration]
branch_link = "<a href=\"#{project_url}/commits/#{URI.escape(ref)}\">#{ref}</a>" branch_link = "<a href=\"#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"
commit_link = "<a href=\"#{project_url}/commit/#{URI.escape(sha)}/builds\">#{Commit.truncate_sha(sha)}</a>" commit_link = "<a href=\"#{project_url}/commit/#{CGI.escape(sha)}/builds\">#{Commit.truncate_sha(sha)}</a>"
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)" "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
end end

View file

@ -38,6 +38,10 @@ class ProjectWiki
[Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
end end
def wiki_base_path
["/", @project.path_with_namespace, "/wikis"].join('')
end
# Returns the Gollum::Wiki object. # Returns the Gollum::Wiki object.
def wiki def wiki
@wiki ||= begin @wiki ||= begin

View file

@ -25,8 +25,6 @@ class SentNotification < ActiveRecord::Base
class << self class << self
def reply_key def reply_key
return nil unless Gitlab::IncomingEmail.enabled?
SecureRandom.hex(16) SecureRandom.hex(16)
end end
@ -64,6 +62,10 @@ class SentNotification < ActiveRecord::Base
end end
end end
def unsubscribable?
!for_commit?
end
def for_commit? def for_commit?
noteable_type == "Commit" noteable_type == "Commit"
end end
@ -75,4 +77,8 @@ class SentNotification < ActiveRecord::Base
super super
end end
end end
def to_param
self.reply_key
end
end end

View file

@ -196,10 +196,22 @@ class User < ActiveRecord::Base
state_machine :state, initial: :active do state_machine :state, initial: :active do
event :block do event :block do
transition active: :blocked transition active: :blocked
transition ldap_blocked: :blocked
end
event :ldap_block do
transition active: :ldap_blocked
end end
event :activate do event :activate do
transition blocked: :active transition blocked: :active
transition ldap_blocked: :active
end
state :blocked, :ldap_blocked do
def blocked?
true
end
end end
end end
@ -207,7 +219,7 @@ class User < ActiveRecord::Base
# Scopes # Scopes
scope :admins, -> { where(admin: true) } scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_state(:blocked) } scope :blocked, -> { with_states(:blocked, :ldap_blocked) }
scope :active, -> { with_state(:active) } scope :active, -> { with_state(:active) }
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all } scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') } scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }

View file

@ -169,7 +169,7 @@ class WikiPage
private private
def set_attributes def set_attributes
attributes[:slug] = @page.escaped_url_path attributes[:slug] = @page.url_path
attributes[:title] = @page.title attributes[:title] = @page.title
attributes[:format] = @page.format attributes[:format] = @page.format
end end

View file

@ -44,7 +44,7 @@ module MergeRequests
def after_merge def after_merge
MergeRequests::PostMergeService.new(project, current_user).execute(merge_request) MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
if params[:should_remove_source_branch] if params[:should_remove_source_branch].present?
DeleteBranchService.new(@merge_request.source_project, current_user). DeleteBranchService.new(@merge_request.source_project, current_user).
execute(merge_request.source_branch) execute(merge_request.source_branch)
end end

View file

@ -0,0 +1,17 @@
class RepairLdapBlockedUserService
attr_accessor :user
def initialize(user)
@user = user
end
def execute
user.block if ldap_hard_blocked?
end
private
def ldap_hard_blocked?
user.ldap_blocked? && !user.ldap_user?
end
end

Some files were not shown because too many files have changed in this diff Show more