diff --git a/CHANGELOG b/CHANGELOG
index ca0b96b840223..52ee3cc5d605f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,13 @@ v 7.0.0
- The CPU no longer overheats when you hold down the spacebar
- Improve edit file UI
- Add ability to upload group avatar when create
+ - Protected branch cannot be removed
+ - Developers can remove normal branches with UI
+ - Remove branch via API (sponsored by O'Reilly Media)
+ - Move protected branches page to Project settings area
+ - Redirect to Files view when create new branch via UI
+ - Drag and drop upload of image in every markdown-area (Earle Randolph Bunao and Neil Francis Calabroso)
+ - Refactor the markdown relative links processing
v 6.9.0
- Store Rails cache data in the Redis `cache:gitlab` namespace
@@ -24,6 +31,7 @@ v 6.9.0
- Add more access checks during API calls
- Block SSH access for 'disabled' Active Directory users
- Labels for merge requests (Drew Blessing)
+ - Threaded emails by setting a Message-ID (Philip Blatter)
v 6.8.0
- Ability to at mention users that are participating in issue and merge req. discussion
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 780db547f829d..85f751919e9e2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -78,7 +78,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
-The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab.com team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
+The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? The smaller a MR is the more likely it is it will be merged, after that you can send more MR's to enhance it.
diff --git a/Gemfile b/Gemfile
index f7e3fe7b6dd14..9775334a7c1ea 100644
--- a/Gemfile
+++ b/Gemfile
@@ -69,6 +69,9 @@ gem "haml-rails"
# Files attachments
gem "carrierwave"
+# Drag and Drop UI
+gem 'dropzonejs-rails'
+
# for aws storage
gem "fog", "~> 1.14", group: :aws
gem "unf", group: :aws
diff --git a/Gemfile.lock b/Gemfile.lock
index 86c752505bdb6..3d4a673af1ca5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -103,6 +103,8 @@ GEM
diffy (3.0.3)
docile (1.1.1)
dotenv (0.9.0)
+ dropzonejs-rails (0.4.14)
+ rails (> 3.1)
email_spec (1.5.0)
launchy (~> 2.1)
mail (~> 2.2)
@@ -579,6 +581,7 @@ DEPENDENCIES
devise (= 3.0.4)
devise-async (= 0.8.0)
diffy (~> 3.0.3)
+ dropzonejs-rails
email_spec
email_validator (~> 1.4.0)
enumerize
diff --git a/LICENSE b/LICENSE
index 8ebd322ffc892..d11b8730bf124 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2011-2014 Dmitriy Zaporozhets
+Copyright (c) 2011-2014 GitLab B.V.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/PROCESS.md b/PROCESS.md
index 23dbfd0c699b6..89ad12ecd5a59 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -13,7 +13,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
- Monitors all issues for feedback (but especially ones commented on since automatically watching them)
- Closes issues with no feedback from the reporter for two weeks
-### Merge request officers
+### Merge marshal
- Responds to merge requests the issue team mentions them in and monitors for new merge requests
- Provides feedback to the merge request submitter to improve the merge request (style, tests, etc.)
diff --git a/README.md b/README.md
index cbbfebc81efb6..256f640454edf 100644
--- a/README.md
+++ b/README.md
@@ -65,6 +65,8 @@
* [Cloud 66 deployment and management](http://blog.cloud66.com/installing-gitlab-ubuntu/) Use Cloud 66 to deploy GitLab to your own server or any cloud (eg. DigitalOcean, AWS, Rackspace, GCE) and then manage it with database backups, scaling and more.
+* [Pkgr.io one-click installer](https://pkgr.io/apps/gitlabhq/gitlabhq) Currently supporting Ubuntu 14.04, Ubuntu 12.04 and Debian 7.4. For more information check the [README](https://gitlab.com/gitlab-org/gitlab-recipes/blob/master/install/pkgr/README.md) at gitlab-recipes repo.
+
#### Unofficial installation methods
* [GitLab recipes](https://gitlab.com/gitlab-org/gitlab-recipes/) repository with unofficial guides for using GitLab with different software (operating systems, webservers, etc.) than the official version.
@@ -106,7 +108,7 @@ Start it with [Foreman](https://github.com/ddollar/foreman)
or start each component separately
bundle exec rails s
- script/background_jobs start
+ bin/background_jobs start
And surf to [localhost:3000](http://localhost:3000/) and login with root / 5iveL!fe
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 587e51a7a8388..35e435546611b 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -29,6 +29,7 @@
#= require underscore
#= require nprogress
#= require nprogress-turbolinks
+#= require dropzone
#= require_tree .
window.slugify = (text) ->
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.coffee b/app/assets/javascripts/behaviors/toggler_behavior.coffee
index d06cb116dfed8..1b2ed9efc253b 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.coffee
+++ b/app/assets/javascripts/behaviors/toggler_behavior.coffee
@@ -1,8 +1,4 @@
$ ->
- $("body").on "click", ".js-toggler-target", ->
- container = $(@).closest(".js-toggler-container")
- container.toggleClass("on")
-
# Toggle button. Show/hide content inside parent container.
# Button does not change visibility. If button has icon - it changes chevron style.
#
diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee
index 9c004c997edf6..784d7d20bb13d 100644
--- a/app/assets/javascripts/commits.js.coffee
+++ b/app/assets/javascripts/commits.js.coffee
@@ -12,7 +12,7 @@ class CommitsList
$('.loading').hide()
@init: (ref, limit) ->
- $(".day-commits-table li.commit").live 'click', (event) ->
+ $("body").on "click", ".day-commits-table li.commit", (event) ->
if event.target.nodeName != "A"
location.href = $(this).attr("url")
e.stopPropagation()
diff --git a/app/assets/javascripts/markdown_area.js.coffee b/app/assets/javascripts/markdown_area.js.coffee
new file mode 100644
index 0000000000000..63561dc4b2087
--- /dev/null
+++ b/app/assets/javascripts/markdown_area.js.coffee
@@ -0,0 +1,178 @@
+$(document).ready ->
+ alertClass = "alert alert-danger alert-dismissable div-dropzone-alert"
+ alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\""
+ divHover = "
"
+ divSpinner = "
"
+ divAlert = "
"
+ iconPicture = " "
+ iconSpinner = " "
+ btnAlert = "× "
+ project_image_path_upload = window.project_image_path_upload or null
+
+ $("textarea.markdown-area").wrap "
"
+ $(".div-dropzone").parent().addClass "div-dropzone-wrapper"
+ $(".div-dropzone").append divHover
+ $(".div-dropzone-hover").append iconPicture
+ $(".div-dropzone").append divSpinner
+ $(".div-dropzone-spinner").append iconSpinner
+
+ dropzone = $(".div-dropzone").dropzone(
+ url: project_image_path_upload
+ dictDefaultMessage: ""
+ clickable: true
+ paramName: "markdown_img"
+ maxFilesize: 10
+ uploadMultiple: false
+ acceptedFiles: "image/jpg,image/jpeg,image/gif,image/png"
+ headers:
+ "X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
+
+ previewContainer: false
+
+ processing: ->
+ closeAlertMessage()
+
+ dragover: ->
+ $(".div-dropzone > textarea").addClass "div-dropzone-focus"
+ $(".div-dropzone-hover").css "opacity", 0.7
+ return
+
+ dragleave: ->
+ $(".div-dropzone > textarea").removeClass "div-dropzone-focus"
+ $(".div-dropzone-hover").css "opacity", 0
+ return
+
+ drop: ->
+ $(".div-dropzone > textarea").removeClass "div-dropzone-focus"
+ $(".div-dropzone-hover").css "opacity", 0
+ $(".div-dropzone > textarea").focus()
+ return
+
+ success: (header, response) ->
+ appendToTextArea(formatLink(response.link))
+ return
+
+ error: (temp, errorMessage) ->
+ showError(errorMessage)
+ return
+
+ sending: ->
+ showSpinner()
+ return
+
+ complete: ->
+ $(".dz-preview").remove()
+ $(".markdown-area").trigger "input"
+ closeSpinner()
+ return
+ )
+
+ child = $(dropzone[0]).children("textarea")
+
+ formatLink = (str) ->
+ ""
+
+ handlePaste = (e) ->
+ e.preventDefault()
+ my_event = e.originalEvent
+
+ if my_event.clipboardData and my_event.clipboardData.items
+ i = 0
+ console.log my_event.clipboardData.items[0]
+ while i < my_event.clipboardData.items.length
+ item = my_event.clipboardData.items[i]
+ processItem(my_event, item)
+ i++
+
+ processItem = (e, item) ->
+ console.log e.clipboardData.items.length
+ console.log isImage(item)
+ if isImage(item)
+ filename = getFilename(e) or "image.png"
+ text = "{{" + filename + "}}"
+ pasteText(text)
+ uploadFile item.getAsFile(), filename
+ else if e.clipboardData.items.length == 1
+ text = e.clipboardData.getData("text/plain")
+ pasteText(text)
+
+ isImage = (item) ->
+ if item
+ item.type.indexOf("image") isnt -1
+
+ pasteText = (text) ->
+ caretStart = $(child)[0].selectionStart
+ caretEnd = $(child)[0].selectionEnd
+ textEnd = $(child).val().length
+
+ beforeSelection = $(child).val().substring 0, caretStart
+ afterSelection = $(child).val().substring caretEnd, textEnd
+ $(child).val beforeSelection + text + afterSelection
+ $(".markdown-area").trigger "input"
+
+ getFilename = (e) ->
+ if window.clipboardData and window.clipboardData.getData
+ value = window.clipboardData.getData("Text")
+ else if e.clipboardData and e.clipboardData.getData
+ value = e.clipboardData.getData("text/plain")
+
+ value = value.split("\r")
+ value.first()
+
+ uploadFile = (item, filename) ->
+ formData = new FormData()
+ formData.append "markdown_img", item, filename
+ $.ajax
+ url: project_image_path_upload
+ type: "POST"
+ data: formData
+ dataType: "json"
+ processData: false
+ contentType: false
+ headers:
+ "X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
+
+ beforeSend: ->
+ showSpinner()
+ closeAlertMessage()
+
+ success: (e, textStatus, response) ->
+ insertToTextArea(filename, formatLink(response.responseJSON.link))
+
+ error: (response) ->
+ showError(response.responseJSON.message)
+
+ complete: ->
+ closeSpinner()
+
+ insertToTextArea = (filename, url) ->
+ $(child).val (index, val) ->
+ val.replace("{{" + filename + "}}", url + "\n")
+
+ appendToTextArea = (url) ->
+ $(child).val (index, val) ->
+ val + url + "\n"
+
+ showSpinner = (e) ->
+ $(".div-dropzone-spinner").css "opacity", 0.7
+
+ closeSpinner = ->
+ $(".div-dropzone-spinner").css "opacity", 0
+
+ showError = (message) ->
+ checkIfMsgExists = $(".error-alert").children().length
+ if checkIfMsgExists is 0
+ $(".error-alert").append divAlert
+ $(".div-dropzone-alert").append btnAlert + message
+
+ closeAlertMessage = ->
+ $(".div-dropzone-alert").alert "close"
+
+ $(".markdown-selector").click (e) ->
+ e.preventDefault()
+ $(".div-dropzone").click()
+ return
+
+ $(".div-dropzone").on "paste", handlePaste
+
+ return
\ No newline at end of file
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 7589fc70cd833..b04a81c85eb5a 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -43,7 +43,7 @@ class MergeRequest
, 'json'
bindEvents: ->
- this.$('.nav-tabs').on 'click', 'a', (event) =>
+ this.$('.merge-request-tabs').on 'click', 'a', (event) =>
a = $(event.currentTarget)
href = a.attr('href')
@@ -51,7 +51,7 @@ class MergeRequest
event.preventDefault()
- this.$('.nav-tabs').on 'click', 'li', (event) =>
+ this.$('.merge-request-tabs').on 'click', 'li', (event) =>
this.activateTab($(event.currentTarget).data('action'))
this.$('.accept_merge_request').on 'click', ->
@@ -71,15 +71,15 @@ class MergeRequest
this.$('.remove_source_branch_widget.failed').show()
activateTab: (action) ->
- this.$('.nav-tabs li').removeClass 'active'
+ this.$('.merge-request-tabs li').removeClass 'active'
this.$('.tab-content').hide()
switch action
when 'diffs'
- this.$('.nav-tabs .diffs-tab').addClass 'active'
+ this.$('.merge-request-tabs .diffs-tab').addClass 'active'
this.loadDiff() unless @diffs_loaded
this.$('.diffs').show()
else
- this.$('.nav-tabs .notes-tab').addClass 'active'
+ this.$('.merge-request-tabs .notes-tab').addClass 'active'
this.$('.notes').show()
showState: (state) ->
@@ -107,7 +107,7 @@ class MergeRequest
loadDiff: (event) ->
$.ajax
type: 'GET'
- url: this.$('.nav-tabs .diffs-tab a').attr('href')
+ url: this.$('.merge-request-tabs .diffs-tab a').attr('href')
beforeSend: =>
this.$('.status').addClass 'loading'
complete: =>
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 4510718c2fd17..a41ee67a8412b 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -32,6 +32,9 @@ class Notes
# Preview button
$(document).on "click", ".js-note-preview-button", @previewNote
+ # Preview button
+ $(document).on "click", ".js-note-write-button", @writeNote
+
# reset main target form after submit
$(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
@@ -68,6 +71,7 @@ class Notes
$(document).off "click", ".js-note-delete"
$(document).off "click", ".js-note-attachment-delete"
$(document).off "click", ".js-note-preview-button"
+ $(document).off "click", ".js-note-write-button"
$(document).off "ajax:complete", ".js-main-target-form"
$(document).off "click", ".js-choose-note-attachment-button"
$(document).off "click", ".js-discussion-reply-button"
@@ -144,16 +148,36 @@ class Notes
# cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm(form)
+ ###
+ Shows write note textarea.
+ ###
+ writeNote: (e) ->
+ e.preventDefault()
+ form = $(this).closest("form")
+ # toggle tabs
+ form.find(".js-note-write-button").parent().addClass "active"
+ form.find(".js-note-preview-button").parent().removeClass "active"
+
+ # toggle content
+ form.find(".note-write-holder").show()
+ form.find(".note-preview-holder").hide()
+
###
Shows the note preview.
Lets the server render GFM into Html and displays it.
-
- Note: uses the Toggler behavior to toggle preview/edit views/buttons
###
previewNote: (e) ->
e.preventDefault()
form = $(this).closest("form")
+ # toggle tabs
+ form.find(".js-note-write-button").parent().removeClass "active"
+ form.find(".js-note-preview-button").parent().addClass "active"
+
+ # toggle content
+ form.find(".note-write-holder").hide()
+ form.find(".note-preview-holder").show()
+
preview = form.find(".js-note-preview")
noteText = form.find(".js-note-text").val()
if noteText.trim().length is 0
@@ -179,8 +203,7 @@ class Notes
form.find(".js-errors").remove()
# reset text and preview
- previewContainer = form.find(".js-toggler-container.note_text_and_preview")
- previewContainer.removeClass "on" if previewContainer.is(".on")
+ form.find(".js-note-write-button").click()
form.find(".js-note-text").val("").trigger "input"
###
@@ -230,7 +253,7 @@ class Notes
form.removeClass "js-new-note-form"
# setup preview buttons
- form.find(".js-note-edit-button, .js-note-preview-button").tooltip placement: "left"
+ form.find(".js-note-write-button, .js-note-preview-button").tooltip placement: "left"
previewButton = form.find(".js-note-preview-button")
form.find(".js-note-text").on "input", ->
if $(this).val().trim() isnt ""
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index c53873f95a2af..0b372a87a111c 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -10,6 +10,7 @@
*= require_self
*= require nprogress
*= require nprogress-bootstrap
+ *= require dropzone/basic
*/
@import "main/*";
diff --git a/app/assets/stylesheets/behaviors.scss b/app/assets/stylesheets/behaviors.scss
index 3fdc20485f278..23f206ce3dc6c 100644
--- a/app/assets/stylesheets/behaviors.scss
+++ b/app/assets/stylesheets/behaviors.scss
@@ -4,11 +4,3 @@
.js-details-container .content.hide { display: block; }
.js-details-container.open .content { display: block; }
.js-details-container.open .content.hide { display: none; }
-
-
-// Toggler
-//--------
-.js-toggler-container .turn-on { display: inherit; }
-.js-toggler-container .turn-off { display: none; }
-.js-toggler-container.on .turn-on { display: none; }
-.js-toggler-container.on .turn-off { display: inherit; }
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 4e660d0b1e072..6ab6458ea0dc8 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -71,12 +71,7 @@ pre {
}
.str-truncated {
- display: inline-block;
- overflow: hidden;
- text-overflow: ellipsis;
- vertical-align: top;
- white-space: nowrap;
- max-width: 82%;
+ @include str-truncated;
}
/** FLASH message **/
diff --git a/app/assets/stylesheets/generic/markdown_area.scss b/app/assets/stylesheets/generic/markdown_area.scss
new file mode 100644
index 0000000000000..ae7ace61d49c4
--- /dev/null
+++ b/app/assets/stylesheets/generic/markdown_area.scss
@@ -0,0 +1,57 @@
+.div-dropzone-wrapper {
+ .div-dropzone {
+ position: relative;
+ padding: 0;
+ border: 0;
+ margin-bottom: 5px;
+
+ .div-dropzone-focus {
+ border-color: #66afe9 !important;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6) !important;
+ outline: 0 !important;
+ }
+
+ .div-dropzone-hover {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-top: -0.5em;
+ margin-left: -0.6em;
+ opacity: 0;
+ font-size: 50px;
+ transition: opacity 200ms ease-in-out;
+ }
+
+ .div-dropzone-spinner {
+ position: absolute;
+ top: 100%;
+ left: 100%;
+ margin-top: -1.1em;
+ margin-left: -1.1em;
+ opacity: 0;
+ font-size: 30px;
+ transition: opacity 200ms ease-in-out;
+ }
+
+ .div-dropzone-icon {
+ display: block;
+ text-align: center;
+ font-size: inherit;
+ }
+
+ .dz-preview {
+ display: none;
+ }
+ }
+
+ .hint {
+ padding: 0;
+ margin: 0;
+ }
+}
+
+.div-dropzone-alert {
+ margin-top: 5px;
+ margin-bottom: 0;
+ transition: opacity 200ms ease-in-out;
+}
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index 8143cfa2c8107..747676620b319 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -123,3 +123,12 @@
margin-top: 0px;
margin-bottom: 15px;
}
+
+@mixin str-truncated($max_width: "82%") {
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: top;
+ white-space: nowrap;
+ max-width: $max_width;
+}
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index b68f882220ec5..05361976efc63 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -45,6 +45,7 @@
padding: 12px 0px;
border-bottom: 1px solid #eee;
.event-title {
+ @include str-truncated(72%);
color: #333;
font-weight: normal;
font-size: 14px;
@@ -135,6 +136,12 @@
}
}
}
+
+ .event-item-timestamp {
+ float: right;
+ color: #999;
+ line-height: 22px;
+ }
}
/**
@@ -166,3 +173,13 @@
}
}
}
+
+/*
+ * Last push widget
+ */
+.event-last-push {
+ .event-last-push-text {
+ @include str-truncated(75%);
+ line-height: 24px;
+ }
+}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 2d9a5e4bbe6b0..cac4cb66aa415 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -19,12 +19,19 @@
}
}
-.merge-request .nav-tabs{
+.merge-request .merge-request-tabs{
+ border-color: #AAA;
li {
a {
- font-weight: bold;
- padding: 8px 20px;
- text-align: center;
+ border-color: #AAA;
+ padding: 14px 40px;
+ font-size: 14px;
+ background-color: #F9F9F9;
+ }
+ &.active a {
+ border-color: #AAA;
+ border-bottom-color: #FFF;
+ background-color: #FFF;
}
}
}
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 7e56781f56a87..2758f57bd544b 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -83,6 +83,7 @@ ul.notes {
overflow: hidden;
display: block;
position:relative;
+ border-bottom: 1px solid #eee;
p { color: $style_color; }
.avatar {
@@ -98,22 +99,16 @@ ul.notes {
.note-header {
padding-bottom: 3px;
}
+
+ &:last-child {
+ border-bottom: none;
+ }
}
.note:target {
-webkit-animation:target-note 2s linear;
background: #fffff0;
}
-
- // paint top or bottom borders depending on notes direction
- &:not(.reversed) .note,
- &:not(.reversed) .discussion {
- border-bottom: 1px solid #eee;
- }
- &.reversed .note,
- &.reversed .discussion {
- border-top: 1px solid #eee;
- }
}
.diff-file .notes_holder {
@@ -140,10 +135,6 @@ ul.notes {
border-width: 1px 0;
padding-top: 0;
vertical-align: top;
-
- li {
- padding: 5px;
- }
}
}
@@ -271,29 +262,33 @@ ul.notes {
.clearfix {
margin-bottom: 0;
}
- .note_text_and_preview {
- // makes the "absolute" position for links relative to this
- position: relative;
- // preview/edit buttons
- > a {
- position: absolute;
- right: 5px;
- bottom: -60px;
- }
- .note_preview {
- background: #f5f5f5;
- border: 1px solid #ddd;
- @include border-radius(4px);
- min-height: 80px;
- padding: 4px 6px;
+ .note-preview-holder,
+ .note_text {
+ background: #FFF;
+ border: 1px solid #ddd;
+ min-height: 100px;
+ padding: 5px;
+ font-size: 14px;
+ box-shadow: none;
+ }
+
+ .note-preview-holder {
+ > p {
+ overflow-x: auto;
}
- .note_text {
+ }
+
+ .note_text {
+ width: 100%;
+ }
+ .nav-tabs {
+ margin-bottom: 0;
+ border: none;
+
+ li a,
+ li.active a {
border: 1px solid #DDD;
- box-shadow: none;
- font-size: 14px;
- height: 80px;
- width: 100%;
}
}
}
@@ -310,19 +305,16 @@ ul.notes {
float: none;
}
-
.common-note-form {
margin: 0;
background: #F9F9F9;
- padding: 3px;
+ padding: 5px;
border: 1px solid #DDD;
}
-
.note-form-actions {
background: #F9F9F9;
height: 45px;
- padding: 0 5px;
.note-form-option {
margin-top: 8px;
@@ -333,6 +325,18 @@ ul.notes {
.js-notify-commit-author {
float: left;
}
+
+ .write-preview-btn {
+ // makes the "absolute" position for links relative to this
+ position: relative;
+
+ // preview/edit buttons
+ > a {
+ position: absolute;
+ right: 5px;
+ top: 8px;
+ }
+ }
}
.note-edit-form {
@@ -367,3 +371,8 @@ ul.notes {
.parallel-comment {
padding: 6px;
}
+
+.error-alert > .alert {
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
index bf30de565ed09..7937454810d99 100644
--- a/app/controllers/files_controller.rb
+++ b/app/controllers/files_controller.rb
@@ -14,4 +14,3 @@ def download
end
end
end
-
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 00811f17adb17..ab8892bbf0bee 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -7,7 +7,9 @@ class Projects::BranchesController < Projects::ApplicationController
before_filter :authorize_push!, only: [:create, :destroy]
def index
- @branches = Kaminari.paginate_array(@repository.branches).page(params[:page]).per(30)
+ @sort = params[:sort] || 'name'
+ @branches = @repository.branches_sorted_by(@sort)
+ @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(30)
end
def recent
@@ -15,9 +17,9 @@ def recent
end
def create
- CreateBranchService.new.execute(project, params[:branch_name], params[:ref], current_user)
+ @branch = CreateBranchService.new.execute(project, params[:branch_name], params[:ref], current_user)
- redirect_to project_branches_path(@project)
+ redirect_to project_tree_path(@project, @branch.name)
end
def destroy
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 4e7a716bfe411..6eec2094f86bb 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -69,7 +69,9 @@ def create
render :new
end
end
- format.js
+ format.js do |format|
+ @link = @issue.attachment.url.to_js
+ end
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index d8551db7b012c..a0a8aa059ec2f 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -225,7 +225,6 @@ def define_show_vars
@merge_request_diff = @merge_request.merge_request_diff
@allowed_to_merge = allowed_to_merge?
@show_merge_controls = @merge_request.open? && @commits.any? && @allowed_to_merge
- @allowed_to_remove_source_branch = allowed_to_remove_source_branch?
@source_branch = @merge_request.source_project.repository.find_branch(@merge_request.source_branch).try(:name)
end
@@ -238,11 +237,6 @@ def invalid_mr
render 'invalid'
end
- def allowed_to_remove_source_branch?
- allowed_to_push_code?(@merge_request.source_project, @merge_request.source_branch) &&
- !@merge_request.disallow_source_branch_removal?
- end
-
def allowed_to_push_code?(project, branch)
action = if project.protected_branch?(branch)
:push_code_to_protected_branches
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb
index cfc1bd99a2040..e39e97af8dd1c 100644
--- a/app/controllers/projects/protected_branches_controller.rb
+++ b/app/controllers/projects/protected_branches_controller.rb
@@ -1,9 +1,9 @@
class Projects::ProtectedBranchesController < Projects::ApplicationController
# Authorize
- before_filter :authorize_read_project!
before_filter :require_non_empty_project
+ before_filter :authorize_admin_project!
- before_filter :authorize_admin_project!, only: [:destroy, :create]
+ layout "project_settings"
def index
@branches = @project.protected_branches.to_a
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index e356d09a270e6..54c7c6bc52eeb 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -11,6 +11,8 @@ class ProjectsController < ApplicationController
layout 'navless', only: [:new, :create, :fork]
before_filter :set_title, only: [:new, :create]
+ rescue_from CarrierWave::IntegrityError, :with => :invalid_file
+
def new
@project = Project.new
end
@@ -162,8 +164,33 @@ def unarchive
end
end
+ def upload_image
+ link_to_image = ::Projects::ImageService.new(repository, params, root_url).execute
+
+ respond_to do |format|
+ if link_to_image
+ format.json { render json: { link: link_to_image } }
+ else
+ format.json { render json: "Invalid file.", status: :unprocessable_entity }
+ end
+ end
+ end
+
private
+ def upload_path
+ base_dir = FileUploader.generate_dir
+ File.join(repository.path_with_namespace, base_dir)
+ end
+
+ def accepted_images
+ %w(png jpg jpeg gif)
+ end
+
+ def invalid_file(error)
+ render json: { message: error.message }, status: :internal_server_error
+ end
+
def set_title
@title = 'New Project'
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 69425bc171d81..b8891d801aaed 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -59,90 +59,67 @@ def render_wiki_content(wiki_page)
end
end
- # text - whole text from a markdown file
- # project_path_with_namespace - namespace/projectname, eg. gitlabhq/gitlabhq
- # ref - name of the branch or reference, eg. stable
- # requested_path - path of request, eg. doc/api/README.md, used in special case when path is pointing to the .md file were the original request is coming from
- def create_relative_links(text, project, ref, requested_path)
- @path_to_satellite = project.satellite.path
- project_path_with_namespace = project.path_with_namespace
+ def create_relative_links(text)
paths = extract_paths(text)
- paths.each do |file_path|
- original_file_path = extract(file_path)
- new_path = rebuild_path(project_path_with_namespace, original_file_path, requested_path, ref)
- if reference_path?(file_path)
- # Replacing old string with a new one that contains updated path
- # eg. [some document]: document.md will be replaced with [some document] /namespace/project/master/blob/document.md
- text.gsub!(file_path, file_path.gsub(original_file_path, "/#{new_path}"))
- else
- # Replacing old string with a new one with brackets ]() to prevent replacing occurence of a word
- # e.g. If we have a markdown like [test](test) this will replace ](test) and not the word test
- text.gsub!("](#{file_path})", "](/#{new_path})")
- end
- end
- text
- end
- def extract_paths(markdown_text)
- all_markdown_paths = pick_out_paths(markdown_text)
- paths = remove_empty(all_markdown_paths)
- select_relative(paths)
- end
+ paths.uniq.each do |file_path|
+ new_path = rebuild_path(file_path)
+ # Finds quoted path so we don't replace other mentions of the string
+ # eg. "doc/api" will be replaced and "/home/doc/api/text" won't
+ text.gsub!("\"#{file_path}\"", "\"/#{new_path}\"")
+ end
- # Split the markdown text to each line and find all paths, this will match anything with - ]("some_text") and [some text]: file.md
- def pick_out_paths(markdown_text)
- inline_paths = markdown_text.split("\n").map { |text| text.scan(/\]\(([^(]+)\)/) }
- reference_paths = markdown_text.split("\n").map { |text| text.scan(/\[.*\]:.*/) }
- inline_paths + reference_paths
+ text
end
- # Removes any empty result produced by not matching the regexp
- def remove_empty(paths)
- paths.reject{|l| l.empty? }.flatten
+ def extract_paths(text)
+ links = substitute_links(text)
+ image_links = substitute_image_links(text)
+ links + image_links
end
- # If a path is a reference style link we need to omit ]:
- def extract(path)
- path.split("]: ").last
+ def substitute_links(text)
+ links = text.scan(//)
+ relative_links = links.flatten.reject{ |link| link_to_ignore? link }
+ relative_links
end
- # Reject any path that contains ignored protocol
- # eg. reject "https://gitlab.org} but accept "doc/api/README.md"
- def select_relative(paths)
- paths.reject{|path| ignored_protocols.map{|protocol| path.include?(protocol)}.any?}
+ def substitute_image_links(text)
+ links = text.scan(/ commit(a.target).committed_date
- end[0..limit]
- end
-
def add_branch(branch_name, ref)
Rails.cache.delete(cache_key(:branch_names))
@@ -220,4 +214,19 @@ def last_commit_for_path(sha, path)
def clean_old_archives
Gitlab::Popen.popen(%W(find #{Gitlab.config.gitlab.repository_downloads_path} -mmin +120 -delete))
end
+
+ def branches_sorted_by(value)
+ case value
+ when 'recently_updated'
+ branches.sort do |a, b|
+ commit(b.target).committed_date <=> commit(a.target).committed_date
+ end
+ when 'last_updated'
+ branches.sort do |a, b|
+ commit(a.target).committed_date <=> commit(b.target).committed_date
+ end
+ else
+ branches
+ end
+ end
end
diff --git a/app/services/projects/image_service.rb b/app/services/projects/image_service.rb
new file mode 100644
index 0000000000000..c79ddddd97200
--- /dev/null
+++ b/app/services/projects/image_service.rb
@@ -0,0 +1,39 @@
+module Projects
+ class ImageService < BaseService
+ include Rails.application.routes.url_helpers
+ def initialize(repository, params, root_url)
+ @repository, @params, @root_url = repository, params.dup, root_url
+ end
+
+ def execute
+ uploader = FileUploader.new('uploads', upload_path, accepted_images)
+ image = @params['markdown_img']
+
+ if image && correct_mime_type?(image)
+ alt = image.original_filename
+ uploader.store!(image)
+ link = {
+ 'alt' => File.basename(alt, '.*'),
+ 'url' => File.join(@root_url, uploader.url)
+ }
+ else
+ link = nil
+ end
+ end
+
+ protected
+
+ def upload_path
+ base_dir = FileUploader.generate_dir
+ File.join(@repository.path_with_namespace, base_dir)
+ end
+
+ def accepted_images
+ %w(png jpg jpeg gif)
+ end
+
+ def correct_mime_type?(image)
+ accepted_images.map{ |format| image.content_type.include? format }.any?
+ end
+ end
+end
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
new file mode 100644
index 0000000000000..0fa987c93f641
--- /dev/null
+++ b/app/uploaders/file_uploader.rb
@@ -0,0 +1,41 @@
+# encoding: utf-8
+class FileUploader < CarrierWave::Uploader::Base
+ storage :file
+
+ def initialize(base_dir, path = '', allowed_extensions = nil)
+ @base_dir = base_dir
+ @path = path
+ @allowed_extensions = allowed_extensions
+ end
+
+ def base_dir
+ @base_dir
+ end
+
+ def store_dir
+ File.join(@base_dir, @path)
+ end
+
+ def cache_dir
+ File.join(@base_dir, 'tmp', @path)
+ end
+
+ def extension_white_list
+ @allowed_extensions
+ end
+
+ def store!(file)
+ @filename = self.class.generate_filename(file)
+ super
+ end
+
+ def self.generate_filename(file)
+ original_filename = File.basename(file.original_filename, '.*')
+ extension = File.extname(file.original_filename)
+ new_filename = Digest::MD5.hexdigest(original_filename) + extension
+ end
+
+ def self.generate_dir
+ SecureRandom.hex(5)
+ end
+end
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 8cf26671e3bf9..613833153739e 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -1,6 +1,6 @@
- if event.proper?
.event-item{class: "#{event.body? ? "event-block" : "event-inline" }"}
- %span.cgray.pull-right
+ .event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
= cache event do
diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml
index 6db05a1a5a6ef..4c9a39bcc272b 100644
--- a/app/views/events/_event_last_push.html.haml
+++ b/app/views/events/_event_last_push.html.haml
@@ -1,11 +1,12 @@
- if show_last_push_widget?(event)
.event-last-push
- %span You pushed to
- = link_to project_commits_path(event.project, event.ref_name) do
- %strong= truncate(event.ref_name, length: 28)
- at
- %strong= link_to_project event.project
- #{time_ago_with_tooltip(event.created_at)}
+ .event-last-push-text
+ %span You pushed to
+ = link_to project_commits_path(event.project, event.ref_name) do
+ %strong= event.ref_name
+ at
+ %strong= link_to_project event.project
+ #{time_ago_with_tooltip(event.created_at)}
.pull-right
= link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-small" do
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index f181df23eb4c6..1bca64c7d508c 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -5,7 +5,7 @@
%strong= event.ref_name
- else
= link_to project_commits_path(event.project, event.ref_name) do
- %strong= truncate(event.ref_name, length: 30)
+ %strong= event.ref_name
at
= link_to_project event.project
diff --git a/app/views/help/raketasks.html.haml b/app/views/help/raketasks.html.haml
index 17a02e913eec7..61a3774a1322e 100644
--- a/app/views/help/raketasks.html.haml
+++ b/app/views/help/raketasks.html.haml
@@ -6,8 +6,6 @@
%ul.nav.nav-tabs.log-tabs
%li.active
- = link_to "Features", "#features", 'data-toggle' => 'tab'
- %li
= link_to "Maintenance", "#maintenance", 'data-toggle' => 'tab'
%li
= link_to "User Management", "#user_management", 'data-toggle' => 'tab'
@@ -17,16 +15,7 @@
= link_to "Cleanup", "#cleanup", 'data-toggle' => 'tab'
.tab-content
- .tab-pane.active#features
- .file-holder
- .file-title
- %i.icon-file
- Features
- .file-content.wiki
- = preserve do
- = markdown File.read(Rails.root.join("doc", "raketasks", "features.md"))
-
- .tab-pane#maintenance
+ .tab-pane.active#maintenance
.file-holder
.file-title
%i.icon-file
@@ -57,7 +46,7 @@
.file-holder
.file-title
%i.icon-file
- Backup & Restore
+ Backup & Restore
.file-content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "raketasks", "backup_restore.md"))
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index 53e0dbaef9ba4..c7a827555a7a4 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -10,3 +10,4 @@
.container
.content= yield
+ = yield :embedded_scripts
\ No newline at end of file
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 1f70cf1798721..d7d330e2a616e 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -8,7 +8,7 @@
= link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref)
- if project_nav_tab? :commits
- = nav_link(controller: %w(commit commits compare repositories protected_branches tags branches)) do
+ = nav_link(controller: %w(commit commits compare repositories tags branches)) do
= link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref)
- if project_nav_tab? :network
diff --git a/app/views/layouts/projects.html.haml b/app/views/layouts/projects.html.haml
index 3ae4961b13752..11c815c52a764 100644
--- a/app/views/layouts/projects.html.haml
+++ b/app/views/layouts/projects.html.haml
@@ -14,3 +14,4 @@
.container
.content= yield
+ = yield :embedded_scripts
\ No newline at end of file
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index 4c7b088ae9a54..9b73f06a5be55 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -19,3 +19,7 @@
= link_to project_services_path(@project) do
%i.icon-cogs
Services
+ = nav_link(controller: :protected_branches) do
+ = link_to project_protected_branches_path(@project) do
+ %i.icon-lock
+ Protected branches
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 87f4dd88c27e0..2abcd00ee8126 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,13 +1,14 @@
- commit = @repository.commit(branch.target)
%li
%h4
- = link_to project_commits_path(@project, branch.name) do
+ = link_to project_tree_path(@project, branch.name) do
%strong= truncate(branch.name, length: 60)
- if branch.name == @repository.root_ref
%span.label.label-info default
- if @project.protected_branch? branch.name
%span.label.label-success
%i.icon-lock
+ protected
.pull-right
- if can?(current_user, :download_code, @project)
= render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'btn-grouped btn-group-small'
@@ -21,13 +22,8 @@
%i.icon-trash
- if commit
- %p
- = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- = image_tag avatar_icon(commit.author_email), class: "avatar s16", alt: ''
- %span.light
- = gfm escape_once(truncate(commit.title, length: 40))
- #{time_ago_with_tooltip(commit.committed_date)}
+ %ul.list-unstyled
+ = render 'projects/commits/inline_commit', commit: commit, project: @project
- else
%p
Cant find HEAD commit for this branch
diff --git a/app/views/projects/branches/_filter.html.haml b/app/views/projects/branches/_filter.html.haml
deleted file mode 100644
index 7e1478292e01b..0000000000000
--- a/app/views/projects/branches/_filter.html.haml
+++ /dev/null
@@ -1,27 +0,0 @@
-%ul.nav.nav-pills.nav-stacked
- = nav_link(path: 'branches#recent') do
- = link_to recent_project_branches_path(@project) do
- Recent
- .pull-right
- = @repository.recent_branches.count
-
- = nav_link(path: 'protected_branches#index') do
- = link_to project_protected_branches_path(@project) do
- Protected
- %i.icon-lock
- .pull-right
- = @project.protected_branches.count
-
- = nav_link(path: 'branches#index') do
- = link_to project_branches_path(@project) do
- All branches
- .pull-right
- = @repository.branch_names.count
-
-
-%hr
-- if can? current_user, :push_code, @project
- = link_to new_project_branch_path(@project), class: 'btn btn-create' do
- %i.icon-add-sign
- New branch
-
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index bee04eb013ebb..8bc4a8f7e989c 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,10 +1,31 @@
= render "projects/commits/head"
-.row
- .col-md-3
- = render "filter"
- .col-md-9
- - unless @branches.empty?
- %ul.bordered-list.top-list.all-branches
- - @branches.each do |branch|
- = render "projects/branches/branch", branch: branch
- = paginate @branches, theme: 'gitlab'
+%h3.page-title
+ Branches
+ .pull-right
+ - if can? current_user, :push_code, @project
+ = link_to new_project_branch_path(@project), class: 'btn btn-create' do
+ %i.icon-add-sign
+ New branch
+
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %span.light sort:
+ - if @sort.present?
+ = @sort.humanize
+ - else
+ Name
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_branches_path(sort: nil) do
+ Name
+ = link_to project_branches_path(sort: 'recently_updated') do
+ Recently updated
+ = link_to project_branches_path(sort: 'last_updated') do
+ Last updated
+%hr
+- unless @branches.empty?
+ %ul.bordered-list.top-list.all-branches
+ - @branches.each do |branch|
+ = render "projects/branches/branch", branch: branch
+ = paginate @branches, theme: 'gitlab'
diff --git a/app/views/projects/branches/recent.html.haml b/app/views/projects/branches/recent.html.haml
deleted file mode 100644
index 37d7919121e7d..0000000000000
--- a/app/views/projects/branches/recent.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-= render "projects/commits/head"
-.row
- .col-md-3
- = render "filter"
- .col-md-9
- %ul.bordered-list.top-list
- - @branches.each do |branch|
- = render "projects/branches/branch", branch: branch
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index 81e3374391150..0facfc4b5f1d5 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -7,9 +7,9 @@
= link_to 'Compare', project_compare_index_path(@project, from: @repository.root_ref, to: @ref || @repository.root_ref)
= nav_link(html_options: {class: branches_tab_class}) do
- = link_to recent_project_branches_path(@project) do
+ = link_to project_branches_path(@project) do
Branches
- %span.badge= @repository.branches.length
+ %span.badge= @repository.branches.size
= nav_link(controller: :tags) do
= link_to project_tags_path(@project) do
diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml
index 84703229fe6be..6e61fc8524f22 100644
--- a/app/views/projects/issues/_form.html.haml
+++ b/app/views/projects/issues/_form.html.haml
@@ -5,6 +5,7 @@
- contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
.alert.alert-info.col-sm-10.col-sm-offset-2
="Please review the #{link_to "guidelines for contribution", contribution_guide_url} to this repository.".html_safe
+
= form_for [@project, @issue], html: { class: 'form-horizontal issue-form' } do |f|
-if @issue.errors.any?
.alert.alert-danger
@@ -19,8 +20,12 @@
.form-group
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
- = f.text_area :description, class: "form-control js-gfm-input", rows: 14
- %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ = f.text_area :description, class: 'form-control js-gfm-input markdown-area', rows: 14
+ .col-sm-12.hint
+ .pull-left Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping, #{link_to "selecting them", '#', class: 'markdown-selector' } or pasting from the clipboard.
+ .clearfix
+ .error-alert
%hr
.form-group
.issue-assignee
@@ -57,9 +62,6 @@
- cancel_path = @issue.new_record? ? project_issues_path(@project) : project_issue_path(@project, @issue)
= link_to "Cancel", cancel_path, class: 'btn btn-cancel'
-
-
-
:javascript
$("#issue_label_list")
.bind( "keydown", function( event ) {
@@ -94,3 +96,5 @@
$('#issue_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault();
});
+
+ window.project_image_path_upload = "#{upload_image_project_path @project}";
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index b6d3a8edf4da9..2c816e788decc 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -73,4 +73,4 @@
= label.name
-.voting_notes#notes= render "projects/notes/notes_with_form"
+.voting_notes#notes= render "projects/notes/notes_with_form"
\ No newline at end of file
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index 290a15e2664d5..facc6a63f3b05 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -22,8 +22,13 @@
.form-group
= f.label :description, "Description", class: 'control-label'
.col-sm-10
- = f.text_area :description, class: "form-control js-gfm-input", rows: 14
- %p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ = f.text_area :description, class: "form-control js-gfm-input markdown-area", rows: 14
+ .col-sm-12.hint
+ .pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping, #{link_to "selecting them", '#', class: 'markdown-selector' } or pasting from the clipboard.
+
+ .clearfix
+ .error-alert
%hr
.form-group
.issue-assignee
@@ -98,3 +103,5 @@
return false;
}
});
+
+ window.project_image_path_upload = "#{upload_image_project_path @project}";
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index b5479be708b4d..bf0e40f9a1fbb 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -23,8 +23,13 @@
.form-group
.light
= f.label :description, "Description"
- = f.text_area :description, class: "form-control js-gfm-input", rows: 10
- %p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ = f.text_area :description, class: "form-control js-gfm-input markdown-area", rows: 10
+ .col-sm-12.hint
+ .pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping, #{link_to "selecting them", '#', class: 'markdown-selector' } or pasting from the clipboard.
+
+ .clearfix
+ .error-alert
.form-group
.issue-assignee
= f.label :assignee_id do
@@ -80,3 +85,5 @@
$('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault();
});
+
+ window.project_image_path_upload = "#{upload_image_project_path @project}";
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 193c600f7745e..cbb8c83e4d056 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -7,15 +7,17 @@
= render "projects/merge_requests/show/participants"
- if @commits.present?
- %ul.nav.nav-tabs
+ %ul.nav.nav-tabs.merge-request-tabs
%li.notes-tab{data: {action: 'notes'}}
= link_to project_merge_request_path(@project, @merge_request) do
%i.icon-comment
Discussion
+ %span.badge= @merge_request.mr_and_commit_notes.count
%li.diffs-tab{data: {action: 'diffs'}}
= link_to diffs_project_merge_request_path(@project, @merge_request) do
%i.icon-list-alt
Changes
+ %span.badge= @merge_request.diffs.size
- content_for :note_actions do
- if can?(current_user, :modify_merge_request, @merge_request)
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index 1276489c2d9e8..07e05f5501254 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -38,7 +38,7 @@
.accept-group
.pull-left
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
- - unless @merge_request.disallow_source_branch_removal?
+ - if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch)
.remove_branch_holder.pull-left
= label_tag :should_remove_source_branch, class: "checkbox" do
= check_box_tag :should_remove_source_branch
diff --git a/app/views/projects/merge_requests/show/_remove_source_branch.html.haml b/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
index f8f8b71f21d41..491360af1bbff 100644
--- a/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
+++ b/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
@@ -1,7 +1,7 @@
- if @source_branch.blank?
Source branch has been removed
-- elsif @allowed_to_remove_source_branch && @merge_request.merged?
+- elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && @merge_request.merged?
.remove_source_branch_widget
%p Changes merged into #{@merge_request.target_branch}. You can remove source branch now
= link_to project_branch_path(@merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-small remove_source_branch" do
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index d770bb5b3710b..2233a8838c32e 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -21,8 +21,12 @@
.form-group
= f.label :description, "Description", class: "control-label"
.col-sm-10
- = f.text_area :description, maxlength: 2000, class: "form-control", rows: 10
- %p.hint Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ = f.text_area :description, maxlength: 2000, class: "form-control markdown-area", rows: 10
+ .hint
+ .pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .pull-left Attach images (JPG, PNG, GIF) by dragging & dropping, #{link_to "selecting them", '#', class: 'markdown-selector' } or pasting from the clipboard.
+ .clearfix
+ .error-alert
.col-md-6
.form-group
= f.label :due_date, "Due Date", class: "control-label"
@@ -45,3 +49,5 @@
dateFormat: "yy-mm-dd",
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
}).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#milestone_due_date').val()));
+
+ window.project_image_path_upload = "#{upload_image_project_path @project}";
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 3db551e993b07..25ebaca930524 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -5,26 +5,28 @@
= f.hidden_field :noteable_id
= f.hidden_field :noteable_type
- .note_text_and_preview.js-toggler-container
- %a.btn.js-note-preview-button.js-toggler-target.turn-off{ href: "javascript:;", data: {url: preview_project_notes_path(@project)} }
- %i.icon-eye-open
- Preview
- %a.btn.btn-primary.js-note-edit-button.js-toggler-target.turn-off{ href: "javascript:;" }
- %i.icon-edit
- Write
+ %ul.nav.nav-tabs
+ %li.active
+ = link_to '#note-write-holder', class: 'js-note-write-button' do
+ Write
+ %li
+ = link_to '#note-preview-holder', class: 'js-note-preview-button', data: { url: preview_project_notes_path(@project) } do
+ Preview
+ %div
+ .note-write-holder
+ = f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input markdown-area'
- = f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input turn-on'
- .note_preview.js-note-preview.turn-off
-
- .hint
- .pull-right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
- .clearfix
+ .light.clearfix.hint
+ .pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping, #{link_to "selecting them", '#', class: 'markdown-selector' } or pasting from the clipboard.
+ .error-alert
+ .note-preview-holder.hide
+ .js-note-preview
.note-form-actions
.buttons
= f.submit 'Add Comment', class: "btn comment-btn btn-grouped js-comment-button"
= yield(:note_actions)
-
%a.btn.grouped.js-close-discussion-note-form Cancel
.note-form-option
@@ -35,4 +37,5 @@
%span.file_name.js-attachment-filename File name...
= f.file_field :attachment, class: "js-note-attachment-input hidden"
- .clearfix
+:javascript
+ window.project_image_path_upload = "#{upload_image_project_path @project}";
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index e9f67b671bf10..e51bf1d3a8cdc 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -1,52 +1,50 @@
-= render "projects/commits/head"
-.row
- .col-md-3
- = render "projects/branches/filter"
- .col-md-9
- .bs-callout.bs-callout-info
- %p Protected branches designed to
- %ul
- %li prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}.
- %li prevent branch from force push
- %li prevent branch from removal
- %p This ability allows to keep stable branches secured and force code review before merge to protected branches
- %p Read more about project permissions #{link_to "here", help_permissions_path, class: "underlined-link"}
+%h3.page-title Protected branches
+%p.light This ability allows to keep stable branches secured and force code review before merge to protected branches
+%hr
- - if can? current_user, :admin_project, @project
- = form_for [@project, @protected_branch], html: { class: 'form-horizontal' } do |f|
- -if @protected_branch.errors.any?
- .alert.alert-danger
- %ul
- - @protected_branch.errors.full_messages.each do |msg|
- %li= msg
+.bs-callout.bs-callout-info
+ %p Protected branches designed to
+ %ul
+ %li prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}.
+ %li prevent branch from force push
+ %li prevent branch from removal
+ %p Read more about project permissions #{link_to "here", help_permissions_path, class: "underlined-link"}
- .form-group
- = f.label :name, "Branch", class: 'control-label'
- .col-sm-10
- = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "select2"})
- .form-actions
- = f.submit 'Protect', class: "btn-create btn"
- - unless @branches.empty?
- %h5 Already Protected:
- %ul.bordered-list.protected-branches-list
- - @branches.each do |branch|
- %li
- %h4
- = link_to project_commits_path(@project, branch.name) do
- %strong= branch.name
- - if @project.root_ref?(branch.name)
- %span.label.label-info default
- %span.label.label-success
- %i.icon-lock
- .pull-right
- - if can? current_user, :admin_project, @project
- = link_to 'Unprotect', [@project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
+- if can? current_user, :admin_project, @project
+ = form_for [@project, @protected_branch], html: { class: 'form-horizontal' } do |f|
+ -if @protected_branch.errors.any?
+ .alert.alert-danger
+ %ul
+ - @protected_branch.errors.full_messages.each do |msg|
+ %li= msg
- - if commit = branch.commit
- = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- %span.light
- = gfm escape_once(truncate(commit.title, length: 40))
- #{time_ago_with_tooltip(commit.committed_date)}
- - else
- (branch was removed from repository)
+ .form-group
+ = f.label :name, "Branch", class: 'control-label'
+ .col-sm-10
+ = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "select2"})
+ .form-actions
+ = f.submit 'Protect', class: "btn-create btn"
+- unless @branches.empty?
+ %h5 Already Protected:
+ %ul.bordered-list.protected-branches-list
+ - @branches.each do |branch|
+ %li
+ %h4
+ = link_to project_commits_path(@project, branch.name) do
+ %strong= branch.name
+ - if @project.root_ref?(branch.name)
+ %span.label.label-info default
+ %span.label.label-success
+ %i.icon-lock
+ .pull-right
+ - if can? current_user, :admin_project, @project
+ = link_to 'Unprotect', [@project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
+
+ - if commit = branch.commit
+ = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
+ = commit.short_id
+ %span.light
+ = gfm escape_once(truncate(commit.title, length: 40))
+ #{time_ago_with_tooltip(commit.committed_date)}
+ - else
+ (branch was removed from repository)
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index 6b33493b7d299..735ffae9e2cf2 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -1,6 +1,6 @@
%div.tree-ref-holder
= render 'shared/ref_switcher', destination: 'tree', path: @path
- if can? current_user, :download_code, @project
- = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group-small tree-ref-holder pull-right', split_button: true
+ = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group-small pull-right', split_button: true
%div#tree-holder.tree-holder
= render "tree", tree: @tree
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 0c2e33f22820c..303cec8e98209 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -15,7 +15,6 @@
.col-sm-2
.col-sm-10
%p.cgray
- Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
To link to a (new) page you can just type
%code [Link Title](page-slug)
\.
@@ -23,8 +22,13 @@
.form-group
= f.label :content, class: 'control-label'
.col-sm-10
- = f.text_area :content, class: 'form-control js-gfm-input', rows: 18
+ = f.text_area :content, class: 'form-control js-gfm-input markdown-area', rows: 18
+ .col-sm-12.hint
+ .pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping, #{link_to "selecting them", '#', class: 'markdown-selector' } or pasting from the clipboard.
+ .clearfix
+ .error-alert
.form-group
= f.label :commit_message, class: 'control-label'
.col-sm-10= f.text_field :message, class: 'form-control', rows: 18
@@ -36,3 +40,7 @@
- else
= f.submit 'Create page', class: "btn-create btn"
= link_to "Cancel", project_wiki_path(@project, :home), class: "btn btn-cancel"
+
+:javascript
+ window.project_image_path_upload = "#{upload_image_project_path @project}";
+
diff --git a/script/background_jobs b/bin/background_jobs
similarity index 100%
rename from script/background_jobs
rename to bin/background_jobs
diff --git a/script/check b/bin/check
similarity index 100%
rename from script/check
rename to bin/check
diff --git a/script/upgrade.rb b/bin/upgrade.rb
similarity index 100%
rename from script/upgrade.rb
rename to bin/upgrade.rb
diff --git a/script/web b/bin/web
similarity index 100%
rename from script/web
rename to bin/web
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 7b53a0655336e..04e85ed9a9de2 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -38,6 +38,8 @@ production: &base
# Email address of your support contact (default: same as email_from)
support_email: support@example.com
+ # Email server smtp settings are in [a separate file](initializers/smtp_settings.rb.sample).
+
## User settings
default_projects_limit: 10
# default_can_create_group: false # default: true
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index d5cb110e8814f..50669ece7a81a 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -223,7 +223,6 @@
method: Gitlab.config.ldap['method'],
bind_dn: Gitlab.config.ldap['bind_dn'],
password: Gitlab.config.ldap['password'],
- filter: Gitlab.config.ldap['user_filter'],
name_proc: email_stripping_proc
end
@@ -245,4 +244,4 @@
config.omniauth provider['name'].to_sym, *provider_arguments
end
-end
\ No newline at end of file
+end
diff --git a/config/routes.rb b/config/routes.rb
index 7641fe430889b..ada9bb1d77a99 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -136,8 +136,6 @@
match "/u/:username" => "users#show", as: :user, constraints: { username: /.*/ }, via: :get
-
-
#
# Dashboard Area
#
@@ -178,6 +176,7 @@
post :fork
post :archive
post :unarchive
+ post :upload_image
get :autocomplete_sources
get :import
put :retry_import
@@ -244,12 +243,7 @@
end
end
- resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } do
- collection do
- get :recent, constraints: { id: Gitlab::Regex.git_reference_regex }
- end
- end
-
+ resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
resources :protected_branches, only: [:index, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
diff --git a/doc/api/branches.md b/doc/api/branches.md
index da9d4193f204e..bb2d3fec09d92 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -199,3 +199,17 @@ Parameters:
"protected": false
}
```
+
+## Delete repository branch
+
+
+```
+DELETE /projects/:id/repository/branches/:branch
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `branch` (required) - The name of the branch
+
+It return 200 if succeed or 405 if failed with error message explaining reason.
diff --git a/doc/api/deploy_keys.md b/doc/api/deploy_keys.md
index d6c0e624dfb00..6aa7be93c01d6 100644
--- a/doc/api/deploy_keys.md
+++ b/doc/api/deploy_keys.md
@@ -1,4 +1,4 @@
-## Deploy Keys
+# Deploy Keys
### List deploy keys
diff --git a/doc/api/groups.md b/doc/api/groups.md
index f5f5d7690509c..1dbb93f9082d3 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -1,3 +1,5 @@
+# Groups
+
## List project groups
Get a list of groups. (As user: my groups, as admin: all groups)
diff --git a/doc/api/issues.md b/doc/api/issues.md
index d18506f9ce6a6..c769d7bb69abd 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -1,3 +1,5 @@
+# Issues
+
## List issues
Get all issues created by authenticated user. This function takes pagination parameters
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index d68f34971f1be..284c2befe6fff 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -1,3 +1,5 @@
+# Merge requests
+
## List merge requests
Get all merge requests for this project.
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index 2a2ef4b79b1d2..b0f355b9a0c88 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -1,3 +1,5 @@
+# Milestones
+
## List project milestones
Returns a list of project milestones.
diff --git a/doc/api/notes.md b/doc/api/notes.md
index e9ad6e00c7316..6d140643fcbc6 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -1,3 +1,5 @@
+# Notes
+
Notes can be wall notes or comments on snippets, issues or merge requests.
## Wall
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index e16e1e845963e..7a49827233422 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -1,3 +1,5 @@
+# Project snippets
+
## List snippets
Get a list of project snippets.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index ffaba0af7fe40..ae2b8365e80fc 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,4 +1,4 @@
-## Projects
+# Projects
### List projects
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 858fad0a0b508..ecb0fa3f6a0d1 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -1,3 +1,5 @@
+# Repositories
+
## List project repository tags
Get a list of repository tags from a project, sorted by name in reverse alphabetical order.
@@ -131,3 +133,56 @@ GET /projects/:id/repository/archive
Parameters:
+ `id` (required) - The ID of a project
+ `sha` (optional) - The commit sha to download defaults to the tip of the default branch
+
+
+## Compare branches, tags or commits
+
+```
+GET /projects/:id/repository/compare
+```
+
+Parameters:
++ `id` (required) - The ID of a project
++ `from` (required) - the commit sha or branch name
++ `to` (required) - the commit sha or branch name
+
+
+```
+GET /projects/:id/repository/compare?from=master&to=feature
+```
+
+Response:
+
+```json
+
+{
+ "commit": {
+ "id": "12d65c8dd2b2676fa3ac47d955accc085a37a9c1",
+ "short_id": "12d65c8dd2b",
+ "title": "JS fix",
+ "author_name": "Dmitriy Zaporozhets",
+ "author_email": "dmitriy.zaporozhets@gmail.com",
+ "created_at": "2014-02-27T10:27:00+02:00"
+ },
+ "commits": [{
+ "id": "12d65c8dd2b2676fa3ac47d955accc085a37a9c1",
+ "short_id": "12d65c8dd2b",
+ "title": "JS fix",
+ "author_name": "Dmitriy Zaporozhets",
+ "author_email": "dmitriy.zaporozhets@gmail.com",
+ "created_at": "2014-02-27T10:27:00+02:00"
+ }],
+ "diffs": [{
+ "old_path": "files/js/application.js",
+ "new_path": "files/js/application.js",
+ "a_mode": null,
+ "b_mode": "100644",
+ "diff": "--- a/files/js/application.js\n+++ b/files/js/application.js\n@@ -24,8 +24,10 @@\n //= require g.raphael-min\n //= require g.bar-min\n //= require branch-graph\n-//= require highlightjs.min\n-//= require ace/ace\n //= require_tree .\n //= require d3\n //= require underscore\n+\n+function fix() { \n+ alert(\"Fixed\")\n+}",
+ "new_file": false,
+ "renamed_file": false,
+ "deleted_file": false
+ }],
+ "compare_timeout": false,
+ "compare_same_ref": false
+}
+```
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index b215cc2500197..820ae71361dfa 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -1,4 +1,6 @@
-# CRUD for repository files
+# Repository files
+
+## CRUD for repository files
## Create, read, update and delete repository files using this API
diff --git a/doc/api/session.md b/doc/api/session.md
index 0be5af79dad92..2e717a2ea7799 100644
--- a/doc/api/session.md
+++ b/doc/api/session.md
@@ -1,3 +1,5 @@
+# Session
+
Login to get private token
```
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index d4c45ea9bbd9f..0d33aee21339f 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -1,3 +1,5 @@
+# System hooks
+
All methods require admin authorization.
The url endpoint of the system hooks can be configured in [the admin area under hooks](/admin/hooks).
diff --git a/doc/api/users.md b/doc/api/users.md
index 2b927c3077734..c185cf6478a3e 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1,3 +1,5 @@
+# Users
+
## List users
Get a list of users.
diff --git a/doc/install/database_mysql.md b/doc/install/database_mysql.md
index bf8183729e7fb..270ad3b0b86b2 100644
--- a/doc/install/database_mysql.md
+++ b/doc/install/database_mysql.md
@@ -1,3 +1,5 @@
+# Database Mysql
+
## Note
We do not recommend using MySQL due to various issues. For example, case [(in)sensitivity](https://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html) and [problems](http://bugs.mysql.com/bug.php?id=65830) that [suggested](http://bugs.mysql.com/bug.php?id=50909) [fixes](http://bugs.mysql.com/bug.php?id=65830) [have](http://bugs.mysql.com/bug.php?id=63164).
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 44f5a28fde5e1..73fef0dadfeba 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,3 +1,5 @@
+# Installation
+
# Select Version to Install
Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md) from the branch (version) of GitLab you would like to install. In most cases
this should be the highest numbered stable branch (example shown below).
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index fd2dd16cd8eb4..2830a75df52bb 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -1,4 +1,6 @@
-# Operating Systems
+# Requirements
+
+## Operating Systems
GitLab is developed for the Linux operating system. For the installations options and instructions please see [the installation section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#installation).
diff --git a/doc/legal/corporate_contributor_license_agreement.md b/doc/legal/corporate_contributor_license_agreement.md
index bbc274f3b0cc7..eb808d8a761fd 100644
--- a/doc/legal/corporate_contributor_license_agreement.md
+++ b/doc/legal/corporate_contributor_license_agreement.md
@@ -1,14 +1,16 @@
-You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab.com. Except for the license granted herein to GitLab.com and recipients of software distributed by GitLab.com, You reserve all right, title, and interest in and to Your Contributions.
+# Corporate contributor license agreement
+
+You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
1. Definitions.
- "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab.com. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+ "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
- "Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab.com for inclusion in, or documentation of, any of the products owned or managed by GitLab.com (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab.com or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab.com for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
+ "Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
+2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
+3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated on Schedule A below (or in a subsequent written modification to that Schedule) is authorized to submit Contributions on behalf of the Corporation.
@@ -16,9 +18,9 @@ You accept and agree to the following terms and conditions for Your present and
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
-7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab.com separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
+7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
-8. It is your responsibility to notify GitLab.com when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab.com.
+8. It is your responsibility to notify GitLab B.V. when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab B.V..
---------------------------------------
diff --git a/doc/legal/individual_contributor_license_agreement.md b/doc/legal/individual_contributor_license_agreement.md
index eaf5812ca4c5a..95cbed7e75bb7 100644
--- a/doc/legal/individual_contributor_license_agreement.md
+++ b/doc/legal/individual_contributor_license_agreement.md
@@ -1,24 +1,26 @@
-You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab.com. Except for the license granted herein to GitLab.com and recipients of software distributed by GitLab.com, You reserve all right, title, and interest in and to Your Contributions.
+# Individual contributor license agreement
+
+You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
1. Definitions.
- "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab.com. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+ "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
- "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab.com for inclusion in, or documentation of, any of the products owned or managed by GitLab.com (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab.com or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab.com for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
+ "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
+2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
+3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
-4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab.com, or that your employer has executed a separate Corporate CLA with GitLab.com.
+4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab B.V., or that your employer has executed a separate Corporate CLA with GitLab B.V..
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
-7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab.com separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [[]named here]".
+7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [[]named here]".
-8. You agree to notify GitLab.com of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
+8. You agree to notify GitLab B.V. of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
---------------------------------------
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index e7ebc613431c6..47cb04cdb0484 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -1,3 +1,5 @@
+# Markdown
+
----------------------------------------------
Table of Contents
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index 9be6423f66761..840bb90163b1e 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -1,3 +1,5 @@
+# Permissions
+
Users have different abilities depending on the access level they have in a particular group or project.
If a user is both in a project group and in the project itself, the highest permission level is used.
If a user is a GitLab administrator they receive all permissions.
@@ -24,7 +26,7 @@ If a user is a GitLab administrator they receive all permissions.
|Manage issue tracker| ||✓|✓|✓|
|Add new team members| |||✓|✓|
|Push to protected branches| |||✓|✓|
-|Remove protected branches| |||✓|✓|
+|Enable/Disable branch protection| |||✓|✓|
|Edit project| |||✓|✓|
|Add Deploy Keys to project| |||✓|✓|
|Configure Project Hooks| |||✓|✓|
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index 76d83e6f3b69f..1714a7eeae48b 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -1,3 +1,5 @@
+# Public access
+
Gitlab allows you to open selected projects to be accessed **publicly** or **internally**.
Projects with either of these visibility levels will be listen in the [public access directory](/public).
Internal projects will only be available to authenticated users.
@@ -26,3 +28,7 @@ The public page of users, located at `/u/username` is visible if either:
Otherwise, you will be redirected to the sign in page.
When visiting the public page of an user, you will only see listed projects which you can view yourself.
+
+#### Restricting the use of public or internal projects
+In [gitlab.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/dbd88d453b8e6c78a423fa7e692004b1db6ea069/config/gitlab.yml.example#L64) you can disable public projects or public and internal projects for the entire GitLab installation to prevent people making code public by accident.
+
diff --git a/doc/raketasks/README.md b/doc/raketasks/README.md
index 6be24f0102aeb..b1c97c8223703 100644
--- a/doc/raketasks/README.md
+++ b/doc/raketasks/README.md
@@ -1,6 +1,5 @@
+ [Backup restore](backup_restore.md)
+ [Cleanup](cleanup.md)
-+ [Features](features.md)
+ [Maintenance](maintenance.md) and self-checks
+ [User management](user_management.md)
+ [Web hooks](web_hooks.md)
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index bdff6ad5da8f0..f0be2b6a44187 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -1,3 +1,5 @@
+# Backup restore
+
### Create a backup of the GitLab system
Creates a backup archive of the database and all repositories. This archive will be saved in backup_path (see `config/gitlab.yml`).
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 99809ef434df7..b0b82754da688 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -1,3 +1,5 @@
+# Cleanup
+
### Remove garbage from filesystem. Important! Data loss!
Remove namespaces(dirs) from `/home/git/repositories` if they don't exist in GitLab database.
diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md
deleted file mode 100644
index 018817d219ba7..0000000000000
--- a/doc/raketasks/features.md
+++ /dev/null
@@ -1,36 +0,0 @@
-### Enable usernames and namespaces for user projects
-
-This command will enable the namespaces feature introduced in v4.0. It will move every project in its namespace folder.
-
-Note:
-
-* Because the **repository location will change**, you will need to **update all your git url's** to point to the new location.
-* Username can be changed at [Profile / Account](/profile/account)
-
-**Example:**
-
-Old path: `git@example.org:myrepo.git`
-New path: `git@example.org:username/myrepo.git` or `git@example.org:groupname/myrepo.git`
-
-```
-bundle exec rake gitlab:enable_namespaces RAILS_ENV=production
-```
-
-
-### Rebuild project satellites
-
-This command will build missing satellites for projects. After this you will be able to **merge a merge request** via GitLab and use the **online editor**.
-
-```
-bundle exec rake gitlab:satellites:create RAILS_ENV=production
-```
-
-Example output:
-
-```
-Creating satellite for abcd.git
-[git clone output]
-Creating satellite for abcd2.git
-[git clone output]
-done
-```
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index e11328dc5ce7d..628bd373b8d7c 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -1,3 +1,5 @@
+# Import
+
### Import bare repositories into GitLab project instance
Notes:
diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md
index 907c9352c5976..da58962499b71 100644
--- a/doc/raketasks/maintenance.md
+++ b/doc/raketasks/maintenance.md
@@ -1,3 +1,5 @@
+# Maintenance
+
### Gather information about GitLab and the system it runs on
This command gathers information about your GitLab installation and the System
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
index e82320829166a..d5b173fde65b1 100644
--- a/doc/raketasks/user_management.md
+++ b/doc/raketasks/user_management.md
@@ -1,3 +1,5 @@
+# User management
+
### Add user as a developer to all projects
```bash
diff --git a/doc/raketasks/web_hooks.md b/doc/raketasks/web_hooks.md
index 1ca5bacb9d104..4ffbf5f8698a6 100644
--- a/doc/raketasks/web_hooks.md
+++ b/doc/raketasks/web_hooks.md
@@ -1,3 +1,5 @@
+# Web hooks
+
### Add a web hook for **ALL** projects:
RAILS_ENV=production bundle exec rake gitlab:web_hook:add URL="http://example.com/hook"
diff --git a/doc/release/README.md b/doc/release/README.md
index 22510be3f1802..d53720acbd427 100644
--- a/doc/release/README.md
+++ b/doc/release/README.md
@@ -1,2 +1,6 @@
-+ [Monthly](monthly.md)
-+ [Security](security.md)
+GitLab has the following updates:
+
++ [Monthly release](monthly.md), every month on the 22nd.
++ [Patch release](patch.md), if there are serious regressions.
++ [Security](security.md), for security problems.
++ [Master](master.md), update process for the master branch.
diff --git a/doc/release/master.md b/doc/release/master.md
new file mode 100644
index 0000000000000..bed5692d0a2c0
--- /dev/null
+++ b/doc/release/master.md
@@ -0,0 +1,31 @@
+# How to push GitLab CE master branch to all remotes.
+
+Distribution to other repo's is done by the lead developer if there is no rush.
+This happens a few times per workday on average.
+If a GitLab B.V. person wants to do it here are the instructions.
+
+## Add this to `.bashrc` or [your dotfiles](https://github.com/dosire/dotfiles/commit/52803ce3ac60d57632164b7713ff0041e86fa26c)
+
+```bash
+gpa ()
+{
+ git push origin ${1:-master} && git push gh ${1:-master} && git push gl ${1:-master}
+}
+```
+
+## Then add remotes to your local repo
+
+```bash
+cd my-gitlab-ce-repo
+
+git remote add origin git@dev.gitlab.org:gitlab/gitlabhq.git
+git remote add gh git@github.com:gitlabhq/gitlabhq.git
+git remote add gl git@gitlab.com:gitlab-org/gitlab-ce.git
+```
+
+## Push to all remotes
+
+```bash
+gpa
+```
+
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 514d73517b2ad..71cd56a099983 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -1,4 +1,5 @@
# Monthly Release
+
NOTE: This is a guide for GitLab developers.
# **15th - Code Freeze & Release Manager**
@@ -9,12 +10,18 @@ NOTE: This is a guide for GitLab developers.
A release manager is selected that coordinates the entire release of this version. The release manager has to make sure all the steps below are done and delegated where necessary. This person should also make sure this document is kept up to date and issues are created and updated.
+### **3. Update Changelog**
+
+Any changes not yet added to the changelog are added by lead developer and in that merge request the complete team is asked if there is anything missing.
+
# **18th - Releasing RC1**
The RC1 release comes with the task to update the installation and upgrade docs. Be mindful that there might already be merge requests for this on GitLab or GitHub.
### **1. Create an issue for RC1 release**
+Consider naming the issue "Release x.x.x.rc1" to make it easier for later searches.
+
### **2. Update the installation guide**
1. Check if it references the correct branch `x-x-stable` (doesn't exist yet, but that is okay)
@@ -82,7 +89,7 @@ Make sure the code quality indicators are green / good.
### **5. Set VERSION**
-Set VERSION tot x.x.0.rc1
+Change version in VERSION to x.x.0.rc1
### **6. Tag**
@@ -98,12 +105,34 @@ Tweet about the RC release:
> GitLab x.x.x.rc1 is out. This is a release candidate intended for testing only. Please let us know if you find regressions.
-### **8. Update Cloud**
+### **8. Update GitLab.com**
-Merge the RC1 code into Cloud. Once the build is green, deploy in the morning.
+Merge the RC1 code into GitLab.com. Once the build is green, deploy in the morning.
It is important to do this as soon as possible, so we can catch any errors before we release the full version.
+# **21st - Preparation **
+
+### **1. Prepare the blog post**
+
+* Check the changelog of CE and EE for important changes. Based on [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md) fill in the important information.
+* Create a WIP MR for the blog post and cc the team so everyone can give feedback.
+* Ask Dmitriy to add screenshots to the WIP MR.
+* Decide with team who will be the MVP user.
+* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
+
+### **2. Q&A**
+
+Create issue on dev.gitlab.org gitlab repository, named "GitLab X.X release" in order to keep track of the progress.
+
+Use the omnibus packages of Enterprise Edition using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md).
+
+**NOTE** Upgrader can only be tested when tags are pushed to all repositories. Do not forget to confirm it is working before releasing. Note that in the issue.
+
+
+### **3. Fix anything coming out of the QA**
+
+Create an issue with description of a problem, if it is quick fix fix yourself otherwise contact the team for advice.
# **22nd - Release CE and EE**
@@ -125,27 +154,31 @@ git push x-x-stable
### **2. Build the Omnibus packages**
[Follow this guide](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md)
-### **3. QA**
-Use the omnibus packages to test using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md)
+### **3. Set VERSION to x.x.x and push**
+Change the VERSION file in `master` branch of the CE repository and commit.
+Cherry-pick into the `x-x-stable` branch of CE.
-### **4. Fix anything coming out of the QA**
+Change the VERSION file in `master branch of the EE repository and commit.
+Cherry-pick into the `x-x-stable-ee` branch of EE.
-### **5. Set VERSION to x.x.0**
+### **4. Create annotated tag vx.x.x**
+
+In `x-x-stable` branch check for the sha1 of the commit with VERSION file changed. Tag that commit,
-### **6. Create annotated tag vx.x.0**
```
-git tag -a vx.x.0 -m 'Version x.x.0'
+git tag -a vx.x.0 -m 'Version x.x.0' xxxxx
```
-### **7. Push VERSION + Tag to master, merge into x-x-stable**
+where `xxxxx` is sha1.
+
+### **5. Push the tag**
+
```
-git push origin master
+git push origin vx.x.0
```
-Next, merge the VERSION into the x-x-stable branch.
-
-### **8. Push to remotes**
+### **6. Push to remotes**
For GitLab CE, push to dev, GitLab.com and GitHub.
@@ -153,15 +186,41 @@ For GitLab EE, push to the subscribers repo.
NOTE: You might not have the rights to push to master on dev. Ask Dmitriy.
-### **9. Publish blog for new release**
-* Mention what GitLab is on the second line: GitLab is open source software to collaborate on code.
-* Select and thank the the Most Valuable Person (MVP) of this release.
-* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
+### **7. Publish blog for new release**
+
+Merge the [blog merge request](#1-prepare-the-blog-post) in `www-gitlab-com` repository.
-### **10. Tweet to blog**
+### **8. Tweet to blog**
Send out a tweet to share the good news with the world. List the features in short and link to the blog post.
+Proposed tweet for CE "GitLab X.X.X CE is released! It brings *** "
+
+Proposed tweet for EE "GitLab X.X.X EE is released! It brings *** "
+
+### **9. Send out newsletter**
+
+In mailchimp replicate the former release newsletters to customers / newsletter subscribers (these are two separate things) and modify them accordingly.
+
+Include a link to the blog post and keep it short.
+
+Proposed email for CE: "We have released a new version of GitLab Community Edition and its packages. See our blog post( ) for more information."
+
+### **10. Create a regressions issue**
+
+On [the GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues/) create an issue titled "GitLab X.X regressions" add the following text:
+
+This is a meta issue to discuss possible regressions in this monthly release and any patch versions.
+Please do not raise issues directly in this issue but link to issues that might warrant a patch release.
+The decision to create a patch release or not is with the release manager who is assigned to this issue.
+The release manager will comment here about the plans for patch releases.
+
+Assign the issue to the release manager and /cc all the core-team members active on the issue tracker. If there are any known bugs in the release add them immediately.
+
# **23rd - Optional Patch Release**
+# **24th - Update GitLab.com**
+
+Merge the stable release into GitLab.com. Once the build is green deploy the next morning.
+
# **25th - Release GitLab CI**
diff --git a/doc/release/patch.md b/doc/release/patch.md
index 30bb39b4e49d6..b6f904b140543 100644
--- a/doc/release/patch.md
+++ b/doc/release/patch.md
@@ -1,4 +1,5 @@
# Things to do when doing a patch release
+
NOTE: This is a guide for GitLab developers. If you are trying to install GitLab see the latest stable [installation guide](install/installation.md) and if you are trying to upgrade, see the [upgrade guides](update).
## When to do a patch release
@@ -9,17 +10,20 @@ Otherwise include it in the monthly release and note there was a regression fix
## Release Procedure
1. Verify that the issue can be repoduced
+1. Note in the 'GitLab X.X regressions' that you will create a patch
1. Create an issue on private GitLab development server
1. Name the issue "Release X.X.X CE and X.X.X EE", this will make searching easier
1. Fix the issue on a feature branch, do this on the private GitLab development server
1. Consider creating and testing workarounds
1. After the branch is merged into master, cherry pick the commit(s) into the current stable branch
-1. In a separate commit in the stable branch, update the VERSION and CHANGELOG
+1. In a separate commit in the stable branch update the VERSION
+1. In a separate commit in the stable branch update the CHANGELOG
1. For EE, update the CHANGELOG-EE if it is EE specific fix. Otherwise, merge the stable CE branch and add to CHANGELOG-EE "Merge community edition changes for version X.X.X"
1. Create an annotated tag vX.X.X for CE and another patch release for EE
-1. Make sure that the build has passed and no tests are failing
+1. Make sure that the build has passed and all tests are passing
1. Push the code and the tags to all the CE and EE repositories
1. Apply the patch to GitLab Cloud and the private GitLab development server
-1. Send tweets about the release from @gitlabhq, tweet should include the most important feature that the release is addressing as well as the link to the changelog
1. Build new packages with the latest version
-
+1. Cherry-pick the changelog update back into master
+1. Send tweets about the release from @gitlabhq, tweet should include the most important feature that the release is addressing as well as the link to the changelog
+1. Note in the 'GitLab X.X regressions' issue that the patch was published
diff --git a/doc/release/security.md b/doc/release/security.md
index 2fe0a948ad2fe..ac2f79dfb9284 100644
--- a/doc/release/security.md
+++ b/doc/release/security.md
@@ -1,4 +1,5 @@
# Things to do when doing an out-of-bound security release
+
NOTE: This is a guide for GitLab developers. If you are trying to install GitLab see the latest stable [installation guide](install/installation.md) and if you are trying to upgrade, see the [upgrade guides](update).
## When to do a security release
diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md
index a0d02b1650f3e..9e863bbd19018 100644
--- a/doc/security/rack_attack.md
+++ b/doc/security/rack_attack.md
@@ -1,3 +1,5 @@
+# Rack attack
+
To prevent abusive clients doing damage GitLab uses rack-attack gem.
If you installed or upgraded GitLab by following the official guides this should be enabled by default.
If you are missing `config/initializers/rack_attack.rb` the following steps need to be taken in order to enable protection for your GitLab instance:
@@ -16,4 +18,4 @@ If you want more restrictive/relaxed throttle rule change the `limit` or `period
In case you find throttling is not enough to protect you against abusive clients, rack-attack gem offers IP whitelisting, blacklisting, Fail2ban style filter and tracking.
-For more information on how to use these options check out [rack-attack README](https://github.com/kickstarter/rack-attack/blob/master/README.md).
\ No newline at end of file
+For more information on how to use these options check out [rack-attack README](https://github.com/kickstarter/rack-attack/blob/master/README.md).
diff --git a/doc/ssh/deploy_keys.md b/doc/ssh/deploy_keys.md
index c7125b7949e7b..e113160c9bc1e 100644
--- a/doc/ssh/deploy_keys.md
+++ b/doc/ssh/deploy_keys.md
@@ -1,3 +1,5 @@
+# Deploy keys
+
Deploy keys allow read-only access one or multiple projects with a single SSH key.
This is really useful for cloning repositories to your Continuous Integration (CI) server.
diff --git a/doc/ssh/ssh.md b/doc/ssh/ssh.md
index 0a38bc16b49ce..f89b6a14ce1c4 100644
--- a/doc/ssh/ssh.md
+++ b/doc/ssh/ssh.md
@@ -1,3 +1,5 @@
+# SSH keys
+
SSH key allows you to establish a secure connection between your computer and GitLab
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index 5c8daf466ab43..5a1a32c1edbd0 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -1,3 +1,5 @@
+# System hooks
+
Your GitLab instance can perform HTTP POST requests on the following events: `create_project`, `delete_project`, `create_user`, `delete_user` and `change_team_member`.
System hooks can be used, e.g. for logging or changing information in a LDAP server.
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index 72a94f67b3c5b..2875b1a8236be 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -19,10 +19,10 @@ __GitLab Upgrader is available only for GitLab version 6.4.2 or higher__
### 2. Run gitlab upgrade tool
cd /home/git/gitlab
- sudo -u git -H ruby script/upgrade.rb
+ sudo -u git -H ruby bin/upgrade.rb
# to perform a non-interactive install (no user input required) you can add -y
- # sudo -u git -H ruby script/upgrade.rb -y
+ # sudo -u git -H ruby bin/upgrade.rb -y
### 3. Start application
@@ -34,13 +34,22 @@ __GitLab Upgrader is available only for GitLab version 6.4.2 or higher__
Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
-
+
To make sure you didn't miss anything run a more thorough check with:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
-
+
If all items are green, then congratulations upgrade is complete!
+### (optional) 5. Application status check fails
+
+If the `gitlab:check` task reports an old version of gitlab-shell and recommends upgrading, upgrade gitlab-shell by running:
+
+```
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v1.9.4
+```
### One line upgrade command
@@ -48,6 +57,6 @@ You've read through the entire guide, and probably did all the steps manually. H
```bash
cd /home/git/gitlab; sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \
- sudo service gitlab stop; sudo -u git -H ruby script/upgrade.rb -y; sudo service gitlab start; \
+ sudo service gitlab stop; sudo -u git -H ruby bin/upgrade.rb -y; sudo service gitlab start; \
sudo service nginx restart; sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
```
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index 4c06bc4d44401..19a60db00ad34 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -1,3 +1,5 @@
+# Web hooks
+
Project web hooks allow you to trigger an URL if new code is pushed or a new issue is created.
---
diff --git a/doc/workflow/authorization_for_merge_requests.md b/doc/workflow/authorization_for_merge_requests.md
index 4e07d7c04c5dc..cc7031b11e143 100644
--- a/doc/workflow/authorization_for_merge_requests.md
+++ b/doc/workflow/authorization_for_merge_requests.md
@@ -1,3 +1,5 @@
+# Authorization for Merge requests
+
There are two main ways to have a merge request flow with GitLab: working with protected branches in a single repository, or working with forks of an authoritative project.
## Protected branch flow
diff --git a/doc/workflow/project_features.md b/doc/workflow/project_features.md
index 25fe403257083..ec2c273db01ee 100644
--- a/doc/workflow/project_features.md
+++ b/doc/workflow/project_features.md
@@ -1,3 +1,5 @@
+# Project features
+
When in a Project -> Settings, you will find Features on the bottom of the page that you can toggle.
Below you will find a more elaborate explanation of each of these.
@@ -7,7 +9,7 @@ Below you will find a more elaborate explanation of each of these.
Issues is a really powerful, but lightweight issue tracking system.
You can make tickets, assign them to people, file them under milestones, order them with labels and have discussion in them.
They integrate deeply into GitLab and are easily referenced from anywhere by using # and the issuenumber.
-At GitLab.com, we use this for all our project management needs.
+
## Merge Requests
diff --git a/doc/workflow/workflow.md b/doc/workflow/workflow.md
index bb232e9d5c57d..8186cd53b200f 100644
--- a/doc/workflow/workflow.md
+++ b/doc/workflow/workflow.md
@@ -1,3 +1,5 @@
+# Workflow
+
1. Clone project
```bash
diff --git a/features/project/commits/branches.feature b/features/project/commits/branches.feature
index fcf8b7694f453..abebef04fcd97 100644
--- a/features/project/commits/branches.feature
+++ b/features/project/commits/branches.feature
@@ -3,20 +3,17 @@ Feature: Project Browse branches
Given I sign in as a user
And I own project "Shop"
And project "Shop" has protected branches
- Given I visit project branches page
-
- Scenario: I can see project recent git branches
- Then I should see "Shop" recent branches list
Scenario: I can see project all git branches
- Given I click link "All"
+ Given I visit project branches page
Then I should see "Shop" all branches list
Scenario: I can see project protected git branches
- Given I click link "Protected"
+ Given I visit project protected branches page
Then I should see "Shop" protected branches list
Scenario: I create a branch
- Given I click new branch link
+ Given I visit project branches page
+ And I click new branch link
When I submit new branch form
Then I should see new branch created
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index c5311544efa5a..191e8dcbe7fd7 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -68,6 +68,12 @@ Feature: Project Issues
And I leave a comment with a header containing "Comment with a header"
Then The comment with the header should not have an ID
+ @javascript
+ Scenario: Blocks inside comments should not build relative links
+ Given I visit issue page "Release 0.4"
+ And I leave a comment with code block
+ Then The code block should be unchanged
+
Scenario: Issues on empty project
Given empty project "Empty Project"
When I visit empty project page
diff --git a/features/steps/help.rb b/features/steps/help.rb
index aa147fd65cef2..5ea2c5daeebb7 100644
--- a/features/steps/help.rb
+++ b/features/steps/help.rb
@@ -16,6 +16,6 @@ class Spinach::Features::Help < Spinach::FeatureSteps
end
step 'Header "Rebuild project satellites" should have correct ids and links' do
- header_should_have_correct_id_and_link(3, 'Rebuild project satellites', 'rebuild-project-satellites')
+ header_should_have_correct_id_and_link(3, '(Re-)Create satellite repos', 're-create-satellite-repos')
end
end
diff --git a/features/steps/project/browse_branches.rb b/features/steps/project/browse_branches.rb
index 30c8cef80c836..7a0625952de78 100644
--- a/features/steps/project/browse_branches.rb
+++ b/features/steps/project/browse_branches.rb
@@ -3,11 +3,6 @@ class ProjectBrowseBranches < Spinach::FeatureSteps
include SharedProject
include SharedPaths
- step 'I should see "Shop" recent branches list' do
- page.should have_content "Branches"
- page.should have_content "master"
- end
-
step 'I click link "All"' do
click_link "All"
end
@@ -44,7 +39,7 @@ class ProjectBrowseBranches < Spinach::FeatureSteps
end
step 'I should see new branch created' do
- within '.all-branches' do
+ within '.tree-ref-holder' do
page.should have_content 'deploy_keys'
end
end
diff --git a/features/steps/project/issues.rb b/features/steps/project/issues.rb
index d1f3ba25a21b8..d0b4aa6e08009 100644
--- a/features/steps/project/issues.rb
+++ b/features/steps/project/issues.rb
@@ -163,4 +163,16 @@ class ProjectIssues < Spinach::FeatureSteps
project = Project.find_by(name: 'Empty Project')
visit project_issues_path(project)
end
+
+ step 'I leave a comment with code block' do
+ within(".js-main-target-form") do
+ fill_in "note[note]", with: "```\nCommand [1]: /usr/local/bin/git , see [text](doc/text)\n```"
+ click_button "Add Comment"
+ sleep 0.05
+ end
+ end
+
+ step 'The code block should be unchanged' do
+ page.should have_content("```\nCommand [1]: /usr/local/bin/git , see [text](doc/text)\n```")
+ end
end
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index f80d8d064755d..f917d7bde08c1 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -138,7 +138,7 @@ module SharedDiffNote
Then 'I should see the diff comment edit button' do
within(".diff-file") do
- page.should have_css(".js-note-edit-button", visible: true)
+ page.should have_css(".js-note-write-button", visible: true)
end
end
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index 36b81b74186dc..1c52d4c72d89a 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -81,7 +81,7 @@ module SharedNote
Then 'I should see the comment edit button' do
within(".js-main-target-form") do
- page.should have_css(".js-note-edit-button", visible: true)
+ page.should have_css(".js-note-write-button", visible: true)
end
end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index a0213815a781c..d36ff7e3884d3 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -240,6 +240,10 @@ module SharedPaths
visit project_branches_path(@project)
end
+ step 'I visit project protected branches page' do
+ visit project_protected_branches_path(@project)
+ end
+
step 'I visit compare refs page' do
visit project_compare_index_path(@project)
end
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 32597eb94c478..b32a4aa7bc286 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -94,7 +94,13 @@ class Branches < Grape::API
# DELETE /projects/:id/repository/branches/:branch
delete ":id/repository/branches/:branch" do
authorize_push_project
- DeleteBranchService.new.execute(user_project, params[:branch], current_user)
+ result = DeleteBranchService.new.execute(user_project, params[:branch], current_user)
+
+ if result[:state] == :success
+ true
+ else
+ render_api_error!(result[:message], 405)
+ end
end
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 457af52fe9dad..6bad6c74bca4c 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -194,5 +194,30 @@ class ProjectWithAccess < Project
class Label < Grape::Entity
expose :name
end
+
+ class RepoDiff < Grape::Entity
+ expose :old_path, :new_path, :a_mode, :b_mode, :diff
+ expose :new_file, :renamed_file, :deleted_file
+ end
+
+ class Compare < Grape::Entity
+ expose :commit, using: Entities::RepoCommit do |compare, options|
+ if compare.commit
+ Commit.new compare.commit
+ end
+ end
+ expose :commits, using: Entities::RepoCommit do |compare, options|
+ Commit.decorate compare.commits
+ end
+ expose :diffs, using: Entities::RepoDiff do |compare, options|
+ compare.diffs
+ end
+
+ expose :compare_timeout do |compare, options|
+ compare.timeout
+ end
+
+ expose :same, as: :compare_same_ref
+ end
end
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 076a9ceeb744e..a587d4a7bdffa 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -15,6 +15,7 @@ def handle_project_member_errors(errors)
not_found!
end
end
+
# Get a project repository tags
#
# Parameters:
@@ -118,6 +119,21 @@ def handle_project_member_errors(errors)
not_found!
end
end
+
+ # Compare two branches, tags or commits
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # from (required) - the commit sha or branch name
+ # to (required) - the commit sha or branch name
+ # Example Request:
+ # GET /projects/:id/repository/compare?from=master&to=feature
+ get ':id/repository/compare' do
+ authorize! :download_code, user_project
+ required_attributes! [:from, :to]
+ compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE)
+ present compare, with: Entities::Compare
+ end
end
end
end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 7d9428ff27d4a..bb225f1acd8a2 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -6,8 +6,6 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
def initialize(template, options = {})
@template = template
@project = @template.instance_variable_get("@project")
- @ref = @template.instance_variable_get("@ref")
- @request_path = @template.instance_variable_get("@path")
@options = options.dup
super options
end
@@ -45,23 +43,10 @@ def header(text, level)
end
end
- def preprocess(full_document)
- if is_wiki?
- full_document
- elsif @project
- h.create_relative_links(full_document, @project, @ref, @request_path)
- else
- full_document
- end
- end
-
def postprocess(full_document)
- h.gfm(full_document)
- end
-
- def is_wiki?
- if @template.instance_variable_get("@project_wiki")
- @template.instance_variable_get("@page")
+ unless @template.instance_variable_get("@project_wiki") || @project.nil?
+ full_document = h.create_relative_links(full_document)
end
+ h.gfm(full_document)
end
end
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index 3dd4465a6d8a0..5c1ce2dadab86 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -167,14 +167,14 @@ start_gitlab() {
# Remove old socket if it exists
rm -f "$socket_path"/gitlab.socket 2>/dev/null
# Start the web server
- RAILS_ENV=$RAILS_ENV script/web start
+ RAILS_ENV=$RAILS_ENV bin/web start
fi
# If sidekiq is already running, don't start it again.
if [ "$sidekiq_status" = "0" ]; then
echo "The Sidekiq job dispatcher is already running with pid $spid, not restarting"
else
- RAILS_ENV=$RAILS_ENV script/background_jobs start &
+ RAILS_ENV=$RAILS_ENV bin/background_jobs start &
fi
# Wait for the pids to be planted
@@ -197,11 +197,11 @@ stop_gitlab() {
# If the Unicorn web server is running, tell it to stop;
if [ "$web_status" = "0" ]; then
- RAILS_ENV=$RAILS_ENV script/web stop
+ RAILS_ENV=$RAILS_ENV bin/web stop
fi
# And do the same thing for the Sidekiq.
if [ "$sidekiq_status" = "0" ]; then
- RAILS_ENV=$RAILS_ENV script/background_jobs stop
+ RAILS_ENV=$RAILS_ENV bin/background_jobs stop
fi
# If something needs to be stopped, lets wait for it to stop. Never use SIGKILL in a script.
@@ -253,10 +253,10 @@ reload_gitlab(){
exit 1
fi
printf "Reloading GitLab Unicorn configuration... "
- RAILS_ENV=$RAILS_ENV script/web reload
+ RAILS_ENV=$RAILS_ENV bin/web reload
echo "Done."
echo "Restarting GitLab Sidekiq since it isn't capable of reloading its config..."
- RAILS_ENV=$RAILS_ENV script/background_jobs restart
+ RAILS_ENV=$RAILS_ENV bin/background_jobs restart
wait_for_pids
print_status
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 0387795fa4846..ad5e04ecab944 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -637,7 +637,7 @@ namespace :gitlab do
else
puts "no".red
try_fixing_it(
- sudo_gitlab("RAILS_ENV=production script/background_jobs start")
+ sudo_gitlab("RAILS_ENV=production bin/background_jobs start")
)
for_more_information(
see_installation_guide_section("Install Init Script"),
diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake
index 9516210e205ff..5b937ce0a2895 100644
--- a/lib/tasks/gitlab/test.rake
+++ b/lib/tasks/gitlab/test.rake
@@ -8,9 +8,7 @@ namespace :gitlab do
]
cmds.each do |cmd|
- result = system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd)
-
- raise "#{cmd} failed!" unless result
+ system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!")
end
end
-end
+end
\ No newline at end of file
diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake
index ba806e53ccf12..e4bd6545755f2 100644
--- a/lib/tasks/sidekiq.rake
+++ b/lib/tasks/sidekiq.rake
@@ -1,21 +1,21 @@
namespace :sidekiq do
desc "GITLAB | Stop sidekiq"
task :stop do
- system *%W(script/background_jobs stop)
+ system *%W(bin/background_jobs stop)
end
desc "GITLAB | Start sidekiq"
task :start do
- system *%W(script/background_jobs start)
+ system *%W(bin/background_jobs start)
end
desc 'GitLab | Restart sidekiq'
task :restart do
- system *%W(script/background_jobs restart)
+ system *%W(bin/background_jobs restart)
end
desc "GITLAB | Start sidekiq with launchd on Mac OS X"
task :launchd do
- system *%W(script/background_jobs start_no_deamonize)
+ system *%W(bin/background_jobs start_no_deamonize)
end
end
diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake
index 49fbe1bd47ae7..bee2230029815 100644
--- a/lib/tasks/spec.rake
+++ b/lib/tasks/spec.rake
@@ -40,7 +40,6 @@ end
def run_commands(cmds)
cmds.each do |cmd|
- system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd)
- raise "#{cmd} failed!" unless $?.exitstatus.zero?
+ system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!")
end
end
diff --git a/lib/tasks/spinach.rake b/lib/tasks/spinach.rake
index c23d0e0e188fa..dcc7d0fe01c24 100644
--- a/lib/tasks/spinach.rake
+++ b/lib/tasks/spinach.rake
@@ -8,7 +8,6 @@ task :spinach do
]
cmds.each do |cmd|
- system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd)
- raise "#{cmd} failed!" unless $?.exitstatus.zero?
+ system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!")
end
end
diff --git a/script/rails b/script/rails
deleted file mode 100755
index f8da2cffd4de0..0000000000000
--- a/script/rails
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env ruby
-# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
-
-APP_PATH = File.expand_path('../../config/application', __FILE__)
-require File.expand_path('../../config/boot', __FILE__)
-require 'rails/commands'
diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb
index fbf4f29acfd69..0c19d755eb188 100644
--- a/spec/controllers/commits_controller_spec.rb
+++ b/spec/controllers/commits_controller_spec.rb
@@ -6,7 +6,6 @@
before do
sign_in(user)
-
project.team << [user, :master]
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
new file mode 100644
index 0000000000000..944df5314bd04
--- /dev/null
+++ b/spec/controllers/projects_controller_spec.rb
@@ -0,0 +1,43 @@
+require('spec_helper')
+
+describe ProjectsController do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
+ let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
+
+ describe "POST #upload_image" do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
+ context "without params['markdown_img']" do
+ it "returns an error" do
+ post :upload_image, id: project.to_param, format: :json
+ expect(response.status).to eq(422)
+ end
+ end
+
+ context "with invalid file" do
+ before do
+ post :upload_image, id: project.to_param, markdown_img: txt, format: :json
+ end
+
+ it "returns an error" do
+ expect(response.status).to eq(422)
+ end
+ end
+
+ context "with valid file" do
+ before do
+ post :upload_image, id: project.to_param, markdown_img: jpg, format: :json
+ end
+
+ it "returns a content with original filename and new link." do
+ expect(response.body).to match "\"alt\":\"rails_sample\""
+ expect(response.body).to match "\"url\":\"http://test.host/uploads/#{project.path_with_namespace}"
+ end
+ end
+ end
+end
diff --git a/spec/factories.rb b/spec/factories.rb
index 148477d638901..41cc99cbcb91e 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -201,7 +201,7 @@
end
trait :with_attachment do
- attachment { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") }
+ attachment { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "`/png") }
end
end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 45aebf128c299..7f1da3cffdf79 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -44,7 +44,7 @@
it 'should have text and visible edit button' do
within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) }
within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) }
- within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) }
+ within(".js-main-target-form") { should have_css(".js-note-write-button", visible: true) }
end
end
end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index f6ab47ed91ba9..eb8422df599d3 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -190,17 +190,6 @@
it { should be_denied_for :visitor }
end
- describe "GET /:project_path/branches/recent" do
- subject { recent_project_branches_path(project) }
-
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
-
describe "GET /:project_path/branches" do
subject { project_branches_path(project) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 8a0fcb8e9fffa..186ad35046976 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -168,17 +168,6 @@
it { should be_denied_for :visitor }
end
- describe "GET /:project_path/branches/recent" do
- subject { recent_project_branches_path(project) }
-
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
- end
-
describe "GET /:project_path/branches" do
subject { project_branches_path(project) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index eb511bfefe02b..f5d1cf7b971cf 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -195,17 +195,6 @@
it { should be_denied_for :visitor }
end
- describe "GET /:project_path/branches/recent" do
- subject { recent_project_branches_path(project) }
-
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
- end
-
describe "GET /:project_path/branches" do
subject { project_branches_path(project) }
diff --git a/spec/fixtures/banana_sample.gif b/spec/fixtures/banana_sample.gif
new file mode 100644
index 0000000000000..1322ac92d141f
Binary files /dev/null and b/spec/fixtures/banana_sample.gif differ
diff --git a/spec/fixtures/doc_sample.txt b/spec/fixtures/doc_sample.txt
new file mode 100644
index 0000000000000..45dbc1aadde03
--- /dev/null
+++ b/spec/fixtures/doc_sample.txt
@@ -0,0 +1,3 @@
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
\ No newline at end of file
diff --git a/spec/fixtures/rails_sample.jpg b/spec/fixtures/rails_sample.jpg
new file mode 100644
index 0000000000000..a847b19332535
Binary files /dev/null and b/spec/fixtures/rails_sample.jpg differ
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index abf6a8646ecbb..72589da5d4034 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -91,7 +91,6 @@
end
end
-
describe "POST /projects/:id/repository/branches" do
it "should create a new branch" do
post api("/projects/#{project.id}/repository/branches", user),
@@ -112,4 +111,26 @@
response.status.should == 403
end
end
+
+ describe "DELETE /projects/:id/repository/branches/:branch" do
+ before { Repository.any_instance.stub(rm_branch: true) }
+
+ it "should remove branch" do
+ delete api("/projects/#{project.id}/repository/branches/new_design", user)
+ response.status.should == 200
+ end
+
+ it "should remove protected branch" do
+ project.protected_branches.create(name: 'new_design')
+ delete api("/projects/#{project.id}/repository/branches/new_design", user)
+ response.status.should == 405
+ json_response['message'].should == 'Protected branch cant be removed'
+ end
+
+ it "should not remove HEAD branch" do
+ delete api("/projects/#{project.id}/repository/branches/master", user)
+ response.status.should == 405
+ json_response['message'].should == 'Cannot remove HEAD branch'
+ end
+ end
end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 5a5222ed3c52b..a902a1542ccf2 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -112,4 +112,43 @@
response.status.should == 404
end
end
+
+ describe 'GET /GET /projects/:id/repository/compare' do
+ it "should compare branches" do
+ get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'simple_merge_request'
+ response.status.should == 200
+ json_response['commits'].should be_present
+ json_response['diffs'].should be_present
+ end
+
+ it "should compare tags" do
+ get api("/projects/#{project.id}/repository/compare", user), from: 'v1.0.1', to: 'v1.0.2'
+ response.status.should == 200
+ json_response['commits'].should be_present
+ json_response['diffs'].should be_present
+ end
+
+ it "should compare commits" do
+ get api("/projects/#{project.id}/repository/compare", user), from: 'b1e6a9dbf1c85', to: '1e689bfba395'
+ response.status.should == 200
+ json_response['commits'].should be_empty
+ json_response['diffs'].should be_empty
+ json_response['compare_same_ref'].should be_false
+ end
+
+ it "should compare commits in reverse order" do
+ get api("/projects/#{project.id}/repository/compare", user), from: '1e689bfba395', to: 'b1e6a9dbf1c85'
+ response.status.should == 200
+ json_response['commits'].should be_present
+ json_response['diffs'].should be_present
+ end
+
+ it "should compare same refs" do
+ get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'master'
+ response.status.should == 200
+ json_response['commits'].should be_empty
+ json_response['diffs'].should be_empty
+ json_response['compare_same_ref'].should be_true
+ end
+ end
end
diff --git a/spec/services/projects/image_service_spec.rb b/spec/services/projects/image_service_spec.rb
new file mode 100644
index 0000000000000..070c21698cf5f
--- /dev/null
+++ b/spec/services/projects/image_service_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe Projects::ImageService do
+ before(:each) { enable_observers }
+ after(:each) { disable_observers }
+
+ describe 'Image service' do
+ before do
+ @user = create :user
+ @project = create :project, creator_id: @user.id, namespace: @user.namespace
+ end
+
+ context 'for valid gif file' do
+ before do
+ gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')
+ @link_to_image = upload_image(@project.repository, { 'markdown_img' => gif }, "http://test.example/")
+ end
+
+ it { expect(@link_to_image).to have_key("alt") }
+ it { expect(@link_to_image).to have_key("url") }
+ it { expect(@link_to_image).to have_value("banana_sample") }
+ it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") }
+ it { expect(@link_to_image["url"]).to match("banana_sample.gif") }
+ end
+
+ context 'for valid png file' do
+ before do
+ png = fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/png')
+ @link_to_image = upload_image(@project.repository, { 'markdown_img' => png }, "http://test.example/")
+ end
+
+ it { expect(@link_to_image).to have_key("alt") }
+ it { expect(@link_to_image).to have_key("url") }
+ it { expect(@link_to_image).to have_value("dk") }
+ it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") }
+ it { expect(@link_to_image["url"]).to match("dk.png") }
+ end
+
+ context 'for valid jpg file' do
+ before do
+ jpg = fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg')
+ @link_to_image = upload_image(@project.repository, { 'markdown_img' => jpg }, "http://test.example/")
+ end
+
+ it { expect(@link_to_image).to have_key("alt") }
+ it { expect(@link_to_image).to have_key("url") }
+ it { expect(@link_to_image).to have_value("rails_sample") }
+ it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") }
+ it { expect(@link_to_image["url"]).to match("rails_sample.jpg") }
+ end
+
+ context 'for txt file' do
+ before do
+ txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain')
+ @link_to_image = upload_image(@project.repository, { 'markdown_img' => txt }, "http://test.example/")
+ end
+
+ it { expect(@link_to_image).to be_nil }
+ end
+ end
+
+ def upload_image(repository, params, root_url)
+ Projects::ImageService.new(repository, params, root_url).execute
+ end
+end