summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG9
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/dropzone_input.js.coffee14
-rw-r--r--app/assets/stylesheets/pages/events.scss1
-rw-r--r--app/assets/stylesheets/pages/issuable.scss10
-rw-r--r--app/assets/stylesheets/pages/projects.scss1
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/issues_helper.rb2
-rw-r--r--app/helpers/sorting_helper.rb4
-rw-r--r--app/models/global_milestone.rb4
-rw-r--r--app/models/hooks/web_hook.rb2
-rw-r--r--app/models/milestone.rb4
-rw-r--r--app/models/project_services/builds_email_service.rb6
-rw-r--r--app/models/project_services/jira_service.rb7
-rw-r--r--app/services/projects/download_service.rb8
-rw-r--r--app/services/projects/upload_service.rb8
-rw-r--r--app/uploaders/file_uploader.rb15
-rw-r--r--app/validators/namespace_validator.rb1
-rw-r--r--app/views/admin/abuse_reports/_abuse_report.html.haml5
-rw-r--r--app/views/admin/groups/show.html.haml2
-rw-r--r--app/views/admin/projects/show.html.haml2
-rw-r--r--app/views/admin/users/_profile.html.haml2
-rw-r--r--app/views/admin/users/show.html.haml8
-rw-r--r--app/views/dashboard/issues.atom.builder2
-rw-r--r--app/views/dashboard/projects/index.atom.builder2
-rw-r--r--app/views/groups/issues.atom.builder2
-rw-r--r--app/views/groups/show.atom.builder2
-rw-r--r--app/views/notify/repository_push_email.html.haml2
-rw-r--r--app/views/notify/repository_push_email.text.haml2
-rw-r--r--app/views/profiles/keys/_key_details.html.haml2
-rw-r--r--app/views/projects/commits/_commits.html.haml2
-rw-r--r--app/views/projects/commits/show.atom.builder4
-rw-r--r--app/views/projects/issues/index.atom.builder2
-rw-r--r--app/views/projects/show.atom.builder2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml19
-rw-r--r--app/views/users/show.atom.builder2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--config/initializers/date_time_formats.rb9
-rw-r--r--config/routes.rb6
-rw-r--r--doc/api/projects.md28
-rw-r--r--doc/api/tags.md20
-rw-r--r--doc/integration/README.md29
-rw-r--r--doc/integration/external-issue-tracker.md48
-rw-r--r--doc/integration/img/jira_issue_reference.png (renamed from doc/integration/jira_issue_reference.png)bin39942 -> 39942 bytes
-rw-r--r--doc/integration/img/jira_merge_request_close.pngbin0 -> 111150 bytes
-rw-r--r--doc/integration/img/jira_project_name.png (renamed from doc/integration/jira_project_name.png)bin60598 -> 60598 bytes
-rw-r--r--doc/integration/img/jira_service.png (renamed from doc/integration/jira_service.png)bin59082 -> 59082 bytes
-rw-r--r--doc/integration/img/jira_service_close_issue.png (renamed from doc/integration/jira_service_close_issue.png)bin88433 -> 88433 bytes
-rw-r--r--doc/integration/img/jira_service_page.pngbin0 -> 35496 bytes
-rw-r--r--doc/integration/img/jira_workflow_screenshot.png (renamed from doc/integration/jira_workflow_screenshot.png)bin121534 -> 121534 bytes
-rw-r--r--doc/integration/jira.md138
-rw-r--r--doc/integration/jira_service_page.pngbin162449 -> 0 bytes
-rw-r--r--doc/integration/redmine_configuration.pngbin118752 -> 0 bytes
-rw-r--r--doc/integration/redmine_service_template.pngbin198077 -> 0 bytes
-rw-r--r--doc/project_services/img/redmine_configuration.pngbin0 -> 21061 bytes
-rw-r--r--doc/project_services/img/services_templates_redmine_example.pngbin0 -> 17351 bytes
-rw-r--r--doc/project_services/project_services.md49
-rw-r--r--doc/project_services/redmine.md21
-rw-r--r--doc/project_services/services_templates.md25
-rw-r--r--doc/workflow/add-user/add-user.md90
-rw-r--r--doc/workflow/add-user/images/add-members.pngbin2361 -> 0 bytes
-rw-r--r--doc/workflow/add-user/images/new-member.pngbin12038 -> 0 bytes
-rw-r--r--doc/workflow/add-user/images/select-project.pngbin4042 -> 0 bytes
-rw-r--r--doc/workflow/add-user/img/add_new_user_to_project_settings.pngbin0 -> 22822 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_email_accept.pngbin0 -> 10833 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_email_ready.pngbin0 -> 16177 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_email_search.pngbin0 -> 15889 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_give_permissions.pngbin0 -> 22089 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_import_members_from_another_project.pngbin0 -> 18897 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_imported_members.pngbin0 -> 23897 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_list_members.pngbin0 -> 15732 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_members_menu.png (renamed from doc/workflow/add-user/images/members.png)bin8295 -> 8295 bytes
-rw-r--r--doc/workflow/add-user/img/add_user_search_people.pngbin0 -> 13518 bytes
-rw-r--r--features/steps/group/milestones.rb2
-rw-r--r--lib/api/projects.rb12
-rw-r--r--lib/api/tags.rb21
-rw-r--r--lib/gitlab/build_data_builder.rb1
-rw-r--r--lib/gitlab/current_settings.rb3
-rw-r--r--lib/gitlab/email/receiver.rb7
-rw-r--r--lib/gitlab/fogbugz_import/importer.rb4
-rw-r--r--spec/helpers/application_helper_spec.rb8
-rw-r--r--spec/lib/banzai/filter/task_list_filter_spec.rb6
-rw-r--r--spec/lib/gitlab/build_data_builder_spec.rb1
-rw-r--r--spec/lib/gitlab/email/receiver_spec.rb11
-rw-r--r--spec/models/hooks/web_hook_spec.rb12
-rw-r--r--spec/models/project_services/builds_email_service_spec.rb23
-rw-r--r--spec/requests/api/projects_spec.rb14
-rw-r--r--spec/requests/api/tags_spec.rb21
-rw-r--r--spec/routing/project_routing_spec.rb1
-rw-r--r--spec/services/projects/download_service_spec.rb24
91 files changed, 571 insertions, 233 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 2d760c2f53b..f7c278823ee 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,8 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.4.0 (unreleased)
+ - The default GitLab logo now acts as a loading indicator
+ - Accept 2xx status codes for successful Web hook triggers (Stan Hu)
- Fix missing date of month in network graph when commits span a month (Stan Hu)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
@@ -14,24 +16,29 @@ v 8.4.0 (unreleased)
- Add "Frequently used" category to emoji picker
- Add CAS support (tduehr)
- Add link to merge request on build detail page
+ - Fix: Problem with projects ending with .keys (Jose Corcuera)
- Revert back upvote and downvote button to the issue and MR pages
- Swap position of Assignee and Author selector on Issuables (Zeger-Jan van de Weg)
- Add system hook messages for project rename and transfer (Steve Norman)
- Fix version check image in Safari
- Show 'All' tab by default in the builds page
+ - Add Open Graph and Twitter Card data to all pages
- Fix API project lookups when querying with a namespace with dots (Stan Hu)
- Update version check images to use SVG
- Validate README format before displaying
- Enable Microsoft Azure OAuth2 support (Janis Meybohm)
- Properly set task-list class on single item task lists
- - Add file finder feature in tree view (koreamic)
+ - Add file finder feature in tree view (Kyungchul Shin)
- Ajax filter by message for commits page
+ - API: Add support for deleting a tag via the API (Robert Schilling)
v 8.3.3 (unreleased)
- Preserve CE behavior with JIRA integration by only calling API if URL is set
- Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running
+ - Suppress e-mails on failed builds if allow_failure is set (Stan Hu)
- Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu)
- Enable "Add key" button when user fills in a proper key (Stan Hu)
+ - Fix error in processing reply-by-email messages (Jason Lee)
v 8.3.2
- Change single user API endpoint to return more detailed data (Michael Potthoff)
diff --git a/Gemfile b/Gemfile
index 6b0bc241494..aa912867dda 100644
--- a/Gemfile
+++ b/Gemfile
@@ -67,10 +67,6 @@ gem 'grape', '~> 0.13.0'
gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
-# Format dates and times
-# based on human-friendly examples
-gem "stamp", '~> 0.6.0'
-
# Pagination
gem "kaminari", "~> 0.16.3"
diff --git a/Gemfile.lock b/Gemfile.lock
index f5391ef9e48..96bf2bd1a2e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -734,7 +734,6 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
- stamp (0.6.0)
state_machines (0.4.0)
state_machines-activemodel (0.3.0)
activemodel (~> 4.1)
@@ -978,7 +977,6 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3)
- stamp (~> 0.6.0)
state_machines-activerecord (~> 0.3.0)
task_list (~> 1.0.2)
teaspoon (~> 1.0.0)
diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee
index 30a35a04339..c714c0fa939 100644
--- a/app/assets/javascripts/dropzone_input.js.coffee
+++ b/app/assets/javascripts/dropzone_input.js.coffee
@@ -66,7 +66,7 @@ class @DropzoneInput
success: (header, response) ->
child = $(dropzone[0]).children("textarea")
- $(child).val $(child).val() + formatLink(response.link) + "\n"
+ $(child).val $(child).val() + response.link.markdown + "\n"
return
error: (temp, errorMessage) ->
@@ -99,11 +99,6 @@ class @DropzoneInput
child = $(dropzone[0]).children("textarea")
- formatLink = (link) ->
- text = "[#{link.alt}](#{link.url})"
- text = "!#{text}" if link.is_image
- text
-
handlePaste = (event) ->
pasteEvent = event.originalEvent
if pasteEvent.clipboardData and pasteEvent.clipboardData.items
@@ -162,7 +157,7 @@ class @DropzoneInput
closeAlertMessage()
success: (e, textStatus, response) ->
- insertToTextArea(filename, formatLink(response.responseJSON.link))
+ insertToTextArea(filename, response.responseJSON.link.markdown)
error: (response) ->
showError(response.responseJSON.message)
@@ -202,8 +197,3 @@ class @DropzoneInput
e.preventDefault()
$(@).closest('.gfm-form').find('.div-dropzone').click()
return
-
- formatLink: (link) ->
- text = "[#{link.alt}](#{link.url})"
- text = "!#{text}" if link.is_image
- text
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 282aaf2219b..984b4b91216 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -138,6 +138,7 @@
*/
.event-last-push {
overflow: auto;
+ width: 100%;
.event-last-push-text {
@include str-truncated(100%);
padding: 5px 0;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 9da273a0b6b..d4b44004f4f 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -94,8 +94,16 @@
}
.cross-project-reference {
- font-weight: bold;
color: $gl-link-color;
+
+ span {
+ white-space: nowrap;
+ width: 85%;
+ overflow: hidden;
+ position: relative;
+ display: inline-block;
+ text-overflow: ellipsis;
+ }
button {
float: right;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index be6ef43e49c..0133a0d6822 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -415,6 +415,7 @@ ul.nav.nav-projects-tabs {
border-bottom: 1px solid #EEE;
margin: 0 -16px;
padding: 0 $gl-padding;
+ height: 57px;
ul.left-top-menu {
display: inline-block;
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index f7f7a1a02d3..2b9bad9c9ea 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -206,7 +206,7 @@ module ApplicationHelper
element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago js-timeago-pending",
datetime: time.getutc.iso8601,
- title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
+ title: time.in_time_zone.to_s(:medium),
data: { toggle: 'tooltip', placement: placement, container: 'body' }
unless skip_js
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index c12456a187f..a7080ddfefb 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -80,7 +80,7 @@ module IssuesHelper
xml.link href: namespace_project_issue_url(issue.project.namespace,
issue.project, issue)
xml.title truncate(issue.title, length: 80)
- xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
+ xml.updated issue.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
xml.author do |author|
xml.name issue.author_name
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index bb12d43f397..99d7df64a83 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -19,7 +19,7 @@ module SortingHelper
end
def sort_title_recently_updated
- 'Recently updated'
+ 'Last updated'
end
def sort_title_oldest_created
@@ -27,7 +27,7 @@ module SortingHelper
end
def sort_title_recently_created
- 'Recently created'
+ 'Last created'
end
def sort_title_milestone_soon
diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb
index af1d7562ebe..7ee276255a0 100644
--- a/app/models/global_milestone.rb
+++ b/app/models/global_milestone.rb
@@ -121,9 +121,9 @@ class GlobalMilestone
def expires_at
if due_date
if due_date.past?
- "expired at #{due_date.stamp("Aug 21, 2011")}"
+ "expired on #{due_date.to_s(:medium)}"
else
- "expires at #{due_date.stamp("Aug 21, 2011")}"
+ "expires on #{due_date.to_s(:medium)}"
end
end
end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 7164c0e1e90..d0aadfc330a 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -61,7 +61,7 @@ class WebHook < ActiveRecord::Base
basic_auth: auth)
end
- [response.code == 200, ActionView::Base.full_sanitizer.sanitize(response.to_s)]
+ [(response.code >= 200 && response.code < 300), ActionView::Base.full_sanitizer.sanitize(response.to_s)]
rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
logger.error("WebHook Error => #{e}")
[false, e.to_s]
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 550d14d4c39..c9a0ad8b9b6 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -112,9 +112,9 @@ class Milestone < ActiveRecord::Base
def expires_at
if due_date
if due_date.past?
- "expired at #{due_date.stamp("Aug 21, 2011")}"
+ "expired on #{due_date.to_s(:medium)}"
else
- "expires at #{due_date.stamp("Aug 21, 2011")}"
+ "expires on #{due_date.to_s(:medium)}"
end
end
end
diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb
index 92c9b13c9b9..f6313255cbb 100644
--- a/app/models/project_services/builds_email_service.rb
+++ b/app/models/project_services/builds_email_service.rb
@@ -73,12 +73,16 @@ class BuildsEmailService < Service
when 'success'
!notify_only_broken_builds?
when 'failed'
- true
+ !allow_failure?(data)
else
false
end
end
+ def allow_failure?(data)
+ data[:build_allow_failure] == true
+ end
+
def all_recipients(data)
all_recipients = recipients.split(',')
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index b6c01c32d9a..f6571fc063e 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -40,15 +40,10 @@ class JiraService < IssueTrackerService
end
def help
- line1 = 'Setting `project_url`, `issues_url` and `new_issue_url` will '\
+ 'Setting `project_url`, `issues_url` and `new_issue_url` will '\
'allow a user to easily navigate to the Jira issue tracker. See the '\
'[integration doc](http://doc.gitlab.com/ce/integration/external-issue-tracker.html) '\
'for details.'
-
- line2 = 'Support for referencing commits and automatic closing of Jira issues directly '\
- 'from GitLab is [available in GitLab EE.](http://doc.gitlab.com/ee/integration/jira.html)'
-
- [line1, line2].join("\n\n")
end
def title
diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb
index 99f22293d0d..6386f57fb0d 100644
--- a/app/services/projects/download_service.rb
+++ b/app/services/projects/download_service.rb
@@ -16,13 +16,7 @@ module Projects
uploader.download!(@url)
uploader.store!
- filename = uploader.image? ? uploader.file.basename : uploader.file.filename
-
- {
- 'alt' => filename,
- 'url' => uploader.secure_url,
- 'is_image' => uploader.image?
- }
+ uploader.to_h
end
private
diff --git a/app/services/projects/upload_service.rb b/app/services/projects/upload_service.rb
index 279550d6f4a..012e82a7704 100644
--- a/app/services/projects/upload_service.rb
+++ b/app/services/projects/upload_service.rb
@@ -10,13 +10,7 @@ module Projects
uploader = FileUploader.new(@project)
uploader.store!(@file)
- filename = uploader.image? ? uploader.file.basename : uploader.file.filename
-
- {
- alt: filename,
- url: uploader.secure_url,
- is_image: uploader.image?
- }
+ uploader.to_h
end
private
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index ac920119a85..86d24469e05 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -30,4 +30,19 @@ class FileUploader < CarrierWave::Uploader::Base
def secure_url
File.join("/uploads", @secret, file.filename)
end
+
+ def to_h
+ filename = image? ? self.file.basename : self.file.filename
+ escaped_filename = filename.gsub("]", "\\]")
+
+ markdown = "[#{escaped_filename}](#{self.secure_url})"
+ markdown.prepend("!") if image?
+
+ {
+ alt: filename,
+ url: self.secure_url,
+ is_image: image?,
+ markdown: markdown
+ }
+ end
end
diff --git a/app/validators/namespace_validator.rb b/app/validators/namespace_validator.rb
index 10e35ce665a..7a35958cc5f 100644
--- a/app/validators/namespace_validator.rb
+++ b/app/validators/namespace_validator.rb
@@ -17,6 +17,7 @@ class NamespaceValidator < ActiveModel::EachValidator
hooks
issues
merge_requests
+ new
notes
profile
projects
diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml
index cf50a376e11..2ab01704b77 100644
--- a/app/views/admin/abuse_reports/_abuse_report.html.haml
+++ b/app/views/admin/abuse_reports/_abuse_report.html.haml
@@ -23,6 +23,9 @@
data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, remote: true, method: :delete, class: "btn btn-xs btn-remove js-remove-tr"
%td
- - if user
+ - if user && !user.blocked?
= link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs"
+ - else
+ .btn.btn-xs.disabled
+ Already Blocked
= link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr"
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 296497a4cd4..f7fd156b84a 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -30,7 +30,7 @@
%li
%span.light Created on:
%strong
- = @group.created_at.stamp("March 1, 1999")
+ = @group.created_at.to_s(:medium)
.panel.panel-default
.panel-heading
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 5260eadf95b..0c986af4a95 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -38,7 +38,7 @@
%li
%span.light Created on:
%strong
- = @project.created_at.stamp("March 1, 1999")
+ = @project.created_at.to_s(:medium)
%li
%span.light http:
diff --git a/app/views/admin/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml
index 7d11edc79e2..6bc217f84cc 100644
--- a/app/views/admin/users/_profile.html.haml
+++ b/app/views/admin/users/_profile.html.haml
@@ -4,7 +4,7 @@
%ul.well-list
%li
%span.light Member since
- %strong= user.created_at.stamp("Aug 21, 2011")
+ %strong= user.created_at.to_s(:medium)
- unless user.public_email.blank?
%li
%span.light E-mail:
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 0848504b7a6..2c2450d4117 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -58,12 +58,12 @@
%li
%span.light Member since:
%strong
- = @user.created_at.stamp("Nov 12, 2031")
+ = @user.created_at.to_s(:medium)
- if @user.confirmed_at
%li
%span.light Confirmed at:
%strong
- = @user.confirmed_at.stamp("Nov 12, 2031")
+ = @user.confirmed_at.to_s(:medium)
- else
%li
%span.light Confirmed:
@@ -74,7 +74,7 @@
%span.light Current sign-in at:
%strong
- if @user.current_sign_in_at
- = @user.current_sign_in_at.stamp("Nov 12, 2031")
+ = @user.current_sign_in_at.to_s(:medium)
- else
never
@@ -82,7 +82,7 @@
%span.light Last sign-in at:
%strong
- if @user.last_sign_in_at
- = @user.last_sign_in_at.stamp("Nov 12, 2031")
+ = @user.last_sign_in_at.to_s(:medium)
- else
never
diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder
index 07bda1c77f8..0d7b1b30dc3 100644
--- a/app/views/dashboard/issues.atom.builder
+++ b/app/views/dashboard/issues.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url
- xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
+ xml.updated @issues.first.created_at.xmlschema if @issues.any?
@issues.each do |issue|
issue_to_atom(xml, issue)
diff --git a/app/views/dashboard/projects/index.atom.builder b/app/views/dashboard/projects/index.atom.builder
index c8c219f4cca..2e2712c5146 100644
--- a/app/views/dashboard/projects/index.atom.builder
+++ b/app/views/dashboard/projects/index.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: dashboard_projects_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: dashboard_projects_url, rel: "alternate", type: "text/html"
xml.id dashboard_projects_url
- xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
+ xml.updated @events.latest_update_time.xmlschema if @events.any?
@events.each do |event|
event_to_atom(xml, event)
diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder
index 66fe7e25871..486d1d8587a 100644
--- a/app/views/groups/issues.atom.builder
+++ b/app/views/groups/issues.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: issues_dashboard_url(format: :atom, private_token: @user.private_token), rel: "self", type: "application/atom+xml"
xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url
- xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
+ xml.updated @issues.first.created_at.xmlschema if @issues.any?
@issues.each do |issue|
issue_to_atom(xml, issue)
diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder
index 7ea574434c3..5cc0f5e1d2e 100644
--- a/app/views/groups/show.atom.builder
+++ b/app/views/groups/show.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: group_url(@group, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: group_url(@group), rel: "alternate", type: "text/html"
xml.id group_url(@group)
- xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
+ xml.updated @events.latest_update_time.xmlschema if @events.any?
@events.each do |event|
event_to_atom(xml, event)
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index 4361f67a74d..3dd2595f1ad 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -17,7 +17,7 @@
%strong #{link_to(commit.short_id, namespace_project_commit_url(@message.project_namespace, @message.project, commit))}
%div
%span by #{commit.author_name}
- %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
+ %i at #{commit.committed_date.to_s(:iso8601)}
%pre.commit-message
= commit.safe_message
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index aa0e263b6df..53869e36b28 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -8,7 +8,7 @@
\
= @message.reverse_compare? ? "Deleted commits:" : "Commits:"
- @message.commits.each do |commit|
- #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
+ #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.to_s(:iso8601)}
#{commit.safe_message}
\- - - - -
\
diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml
index 0ca8bd95157..3bd1f1af162 100644
--- a/app/views/profiles/keys/_key_details.html.haml
+++ b/app/views/profiles/keys/_key_details.html.haml
@@ -10,7 +10,7 @@
%strong= @key.title
%li
%span.light Created on:
- %strong= @key.created_at.stamp("Aug 21, 2011")
+ %strong= @key.created_at.to_s(:medium)
.col-md-8
%p
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index 0cd9ce1f371..6c631228002 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -6,7 +6,7 @@
.col-md-2.hidden-xs.hidden-sm
%h5.commits-row-date
%i.fa.fa-calendar
- %span= day.stamp("28 Aug, 2010")
+ %span= day.strftime('%d %b, %Y')
.light
= pluralize(commits.count, 'commit')
.col-md-10.col-sm-12
diff --git a/app/views/projects/commits/show.atom.builder b/app/views/projects/commits/show.atom.builder
index 7ffa7317196..e310fafd82c 100644
--- a/app/views/projects/commits/show.atom.builder
+++ b/app/views/projects/commits/show.atom.builder
@@ -4,14 +4,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref), rel: "alternate", type: "text/html"
xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
- xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any?
+ xml.updated @commits.first.committed_date.xmlschema if @commits.any?
@commits.each do |commit|
xml.entry do
xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.title truncate(commit.title, length: 80)
- xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")
+ xml.updated commit.committed_date.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
xml.author do |author|
xml.name commit.author_name
diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder
index dc8e477185b..ee8a9414657 100644
--- a/app/views/projects/issues/index.atom.builder
+++ b/app/views/projects/issues/index.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_issues_url(@project.namespace, @project)
- xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
+ xml.updated @issues.first.created_at.xmlschema if @issues.any?
@issues.each do |issue|
issue_to_atom(xml, issue)
diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder
index 15c49767556..d6762219108 100644
--- a/app/views/projects/show.atom.builder
+++ b/app/views/projects/show.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_url(@project.namespace, @project)
- xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
+ xml.updated @events.latest_update_time.xmlschema if @events.any?
@events.each do |event|
event_to_atom(xml, event)
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 79c5cc7f40a..2299112bec7 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -54,14 +54,6 @@
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
{ selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" }
- .block
- .title
- Cross-project reference
- .cross-project-reference
- %span#cross-project-reference
- = cross_project_reference(@project, issuable)
- = clipboard_button(clipboard_target: 'span#cross-project-reference')
-
= render "shared/issuable/participants", participants: issuable.participants(current_user)
- if current_user
@@ -77,7 +69,16 @@
You're not receiving notifications from this thread.
.subscribed{class: ( 'hidden' unless subscribed )}
You're receiving notifications because you're subscribed to this thread.
+ - project_ref = cross_project_reference(@project, issuable)
+ .block
+ .title
+ .cross-project-reference
+ %span#cross-project-reference
+ Reference:
+ %a{href: '#', title:project_ref}
+ = project_ref
+ = clipboard_button(clipboard_target: 'span#cross-project-reference')
:javascript
new Subscription("#{toggle_subscription_path(issuable)}");
- new IssuableContext();
+ new IssuableContext(); \ No newline at end of file
diff --git a/app/views/users/show.atom.builder b/app/views/users/show.atom.builder
index 2fe5b7fac83..114d1e7a379 100644
--- a/app/views/users/show.atom.builder
+++ b/app/views/users/show.atom.builder
@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link href: user_url(@user, :atom), rel: "self", type: "application/atom+xml"
xml.link href: user_url(@user), rel: "alternate", type: "text/html"
xml.id user_url(@user)
- xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
+ xml.updated @events.latest_update_time.xmlschema if @events.any?
@events.each do |event|
event_to_atom(xml, event)
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 0bca8177e14..ce17fc7bca1 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -21,7 +21,7 @@
%span
#{@user.bio}.
%span
- Member since #{@user.created_at.stamp("Aug 21, 2011")}
+ Member since #{@user.created_at.to_s(:medium)}
.cover-desc
- unless @user.public_email.blank?
diff --git a/config/initializers/date_time_formats.rb b/config/initializers/date_time_formats.rb
new file mode 100644
index 00000000000..57568203cab
--- /dev/null
+++ b/config/initializers/date_time_formats.rb
@@ -0,0 +1,9 @@
+# :short - 10 Nov
+# :medium - Nov 10, 2007
+# :long - November 10, 2007
+Date::DATE_FORMATS[:medium] = '%b %-d, %Y'
+
+# :short - 18 Jan 06:10
+# :medium - Jan 18, 2007 6:10am
+# :long - January 18, 2007 06:10
+Time::DATE_FORMATS[:medium] = '%b %-d, %Y %-I:%M%P'
diff --git a/config/routes.rb b/config/routes.rb
index 5b69d06eb76..4fcea1185c0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -52,9 +52,6 @@ Rails.application.routes.draw do
API::API.logger Rails.logger
mount API::API => '/api'
- # Get all keys of user
- get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ }
-
constraint = lambda { |request| request.env['warden'].authenticate? and request.env['warden'].user.admin? }
constraints constraint do
mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq
@@ -686,5 +683,8 @@ Rails.application.routes.draw do
end
end
+ # Get all keys of user
+ get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ }
+
get ':id' => 'namespaces#show', constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
end
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 0ca81ffd49e..37d74216c1b 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -482,6 +482,34 @@ Parameters:
- `id` (required) - The ID of a project
+## Uploads
+
+### Upload a file
+
+Uploads a file to the specified project to be used in an issue or merge request description, or a comment.
+
+```
+POST /projects/:id/uploads
+```
+
+Parameters:
+
+- `id` (required) - The ID of the project
+- `file` (required) - The file to be uploaded
+
+```json
+{
+ "alt": "dk",
+ "url": "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png",
+ "is_image": true,
+ "markdown": "![dk](/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png)"
+}
+```
+
+**Note**: The returned `url` is relative to the project path.
+In Markdown contexts, the link is automatically expanded when the format in `markdown` is used.
+
+
## Team members
### List project team members
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 085d387e824..17d12e9cc62 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -83,6 +83,26 @@ it will contain the annotation.
It returns 200 if the operation succeed. In case of an error,
405 with an explaining error message is returned.
+## Delete a tag
+
+Deletes a tag of a repository with given name. On success, this API method
+returns 200 with the name of the deleted tag. If the tag does not exist, the
+API returns 404.
+
+```
+DELETE /projects/:id/repository/tags/:tag_name
+```
+
+Parameters:
+
+- `id` (required) - The ID of a project
+- `tag_name` (required) - The name of a tag
+
+```json
+{
+ "tag_name": "v4.3.0"
+}
+```
## Create a new release
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 2a9f76533b7..5edac746c7b 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -1,6 +1,7 @@
# GitLab Integration
-GitLab integrates with multiple third-party services to allow external issue trackers and external authentication.
+GitLab integrates with multiple third-party services to allow external issue
+trackers and external authentication.
See the documentation below for details on how to configure these services.
@@ -15,13 +16,25 @@ See the documentation below for details on how to configure these services.
- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
- [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users
-GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html).
+GitLab Enterprise Edition contains [advanced Jenkins support][jenkins].
## Project services
-Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a Project Service.
-You can find these within GitLab in the Services page under Project Settings if you are at least a master on the project.
-Project Services are a bit like plugins in that they allow a lot of freedom in adding functionality to GitLab, for example there is also a service that can send an email every time someone pushes new commits.
-Because GitLab is open source we can ship with the code and tests for all plugins.
-This allows the community to keep the plugins up to date so that they always work in newer GitLab versions.
-For an overview of what projects services are available without logging in please see the [project_services directory](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/models/project_services).
+Integration with services such as Campfire, Flowdock, Gemnasium, HipChat,
+Pivotal Tracker, and Slack are available in the form of a [Project Service][].
+You can find these within GitLab in the Services page under Project Settings if
+you are at least a master on the project.
+Project Services are a bit like plugins in that they allow a lot of freedom in
+adding functionality to GitLab. For example there is also a service that can
+send an email every time someone pushes new commits.
+
+Because GitLab is open source we can ship with the code and tests for all
+plugins. This allows the community to keep the plugins up to date so that they
+always work in newer GitLab versions.
+
+For an overview of what projects services are available without logging in,
+please see the [project_services directory][projects-code].
+
+[jenkins]: http://doc.gitlab.com/ee/integration/jenkins.html
+[Project Service]: ../project_services/project_services.md
+[projects-code]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/models/project_services
diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md
index 3e660cfba1e..3543a67dd49 100644
--- a/doc/integration/external-issue-tracker.md
+++ b/doc/integration/external-issue-tracker.md
@@ -1,44 +1,30 @@
# External issue tracker
-GitLab has a great issue tracker but you can also use an external issue tracker such as Jira, Bugzilla or Redmine. You can configure issue trackers per GitLab project. For instance, if you configure Jira it allows you to do the following:
+GitLab has a great issue tracker but you can also use an external one such as
+Jira or Redmine. Issue trackers are configurable per GitLab project and allow
+you to do the following:
-- the 'Issues' link on the GitLab project pages takes you to the appropriate Jira issue index;
-- clicking 'New issue' on the project dashboard creates a new Jira issue;
-- To reference Jira issue PROJECT-1234 in comments, use syntax PROJECT-1234. Commit messages get turned into HTML links to the corresponding Jira issue.
-
-![Jira screenshot](jira-integration-points.png)
-
-GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html).
+- the **Issues** link on the GitLab project pages takes you to the appropriate
+ issue index of the external tracker
+- clicking **New issue** on the project dashboard creates a new issue on the
+ external tracker
## Configuration
-### Project Service
+The configuration is done via a project's **Services**.
-You can enable an external issue tracker per project. As an example, we will configure `Redmine` for project named gitlab-ci.
-
-Fill in the required details on the page:
+### Project Service
-![redmine configuration](redmine_configuration.png)
+To enable an external issue tracker you must configure the appropriate **Service**.
+Visit the links below for details:
-* `description` A name for the issue tracker (to differentiate between instances, for example).
-* `project_url` The URL to the project in Redmine which is being linked to this GitLab project.
-* `issues_url` The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the url. This id is used by GitLab as a placeholder to replace the issue number.
-* `new_issue_url` This is the URL to create a new issue in Redmine for the project linked to this GitLab project.
+- [Redmine](../project_services/redmine.md)
+- [Jira](jira.md)
### Service Template
-It is necessary to configure the external issue tracker per project, because project specific details are needed for the integration with GitLab.
-The admin can add a service template that sets a default for each project. This makes it much easier to configure individual projects.
-
-In GitLab Admin section, navigate to `Service Templates` and choose the service template you want to create:
-
-![redmine service template](redmine_service_template.png)
-
-After the template is created, the template details will be pre-filled on the project service page.
-
-NOTE: For each project, you will still need to configure the issue tracking URLs by replacing `:issues_tracker_id` in the above screenshot
-with the ID used by your external issue tracker. Prior to GitLab v7.8, this ID was configured in the project settings, and GitLab would automatically
-update the URL configured in `gitlab.yml`. This behavior is now depecated, and all issue tracker URLs must be configured directly
-within the project's Services settings.
+To save you the hassle from configuring each project's service individually,
+GitLab provides the ability to set Service Templates which can then be
+overridden in each project's settings.
-Support to add your commits to the Jira ticket automatically is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jira.html).
+Read more on [Services Templates](../project_services/services_templates.md).
diff --git a/doc/integration/jira_issue_reference.png b/doc/integration/img/jira_issue_reference.png
index 15739a22dc7..15739a22dc7 100644
--- a/doc/integration/jira_issue_reference.png
+++ b/doc/integration/img/jira_issue_reference.png
Binary files differ
diff --git a/doc/integration/img/jira_merge_request_close.png b/doc/integration/img/jira_merge_request_close.png
new file mode 100644
index 00000000000..1e78daf105f
--- /dev/null
+++ b/doc/integration/img/jira_merge_request_close.png
Binary files differ
diff --git a/doc/integration/jira_project_name.png b/doc/integration/img/jira_project_name.png
index 5986fdb63fb..5986fdb63fb 100644
--- a/doc/integration/jira_project_name.png
+++ b/doc/integration/img/jira_project_name.png
Binary files differ
diff --git a/doc/integration/jira_service.png b/doc/integration/img/jira_service.png
index 1f6628c4371..1f6628c4371 100644
--- a/doc/integration/jira_service.png
+++ b/doc/integration/img/jira_service.png
Binary files differ
diff --git a/doc/integration/jira_service_close_issue.png b/doc/integration/img/jira_service_close_issue.png
index 67dfc6144c4..67dfc6144c4 100644
--- a/doc/integration/jira_service_close_issue.png
+++ b/doc/integration/img/jira_service_close_issue.png
Binary files differ
diff --git a/doc/integration/img/jira_service_page.png b/doc/integration/img/jira_service_page.png
new file mode 100644
index 00000000000..2b37eda3520
--- /dev/null
+++ b/doc/integration/img/jira_service_page.png
Binary files differ
diff --git a/doc/integration/jira_workflow_screenshot.png b/doc/integration/img/jira_workflow_screenshot.png
index 8635a32eb68..8635a32eb68 100644
--- a/doc/integration/jira_workflow_screenshot.png
+++ b/doc/integration/img/jira_workflow_screenshot.png
Binary files differ
diff --git a/doc/integration/jira.md b/doc/integration/jira.md
index 624601d0fac..de574d53410 100644
--- a/doc/integration/jira.md
+++ b/doc/integration/jira.md
@@ -1,14 +1,15 @@
# GitLab Jira integration
-GitLab can be configured to interact with Jira.
-Configuration happens via username and password.
-Connecting to a Jira server via CAS is not possible.
+GitLab can be configured to interact with Jira. Configuration happens via
+username and password. Connecting to a Jira server via CAS is not possible.
-Each project can be configured to connect to a different Jira instance, configuration is explained [here](#configuration).
-If you have one Jira instance you can pre-fill the settings page with a default template. To configure the template [see external issue tracker document](external-issue-tracker.md#service-template)).
-
-Once the project is connected to Jira, you can reference and close the issues in Jira directly from GitLab.
+Each project can be configured to connect to a different Jira instance, see the
+[configuration](#configuration) section. If you have one Jira instance you can
+pre-fill the settings page with a default template. To configure the template
+see the [Services Templates][services-templates] document.
+Once the project is connected to Jira, you can reference and close the issues
+in Jira directly from GitLab.
## Table of Contents
@@ -18,8 +19,11 @@ Once the project is connected to Jira, you can reference and close the issues in
### Referencing Jira Issues
-When GitLab project has Jira issue tracker configured and enabled, mentioning Jira issue in GitLab will automatically add a comment in Jira issue with the link back to GitLab. This means that in comments in merge requests and commits referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the format:
-
+When GitLab project has Jira issue tracker configured and enabled, mentioning
+Jira issue in GitLab will automatically add a comment in Jira issue with the
+link back to GitLab. This means that in comments in merge requests and commits
+referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the
+format:
```
USER mentioned this issue in LINK_TO_THE_MENTION
@@ -29,85 +33,117 @@ When GitLab project has Jira issue tracker configured and enabled, mentioning Ji
* `LINK_TO_THE_MENTION` Link to the origin of mention with a name of the entity where Jira issue was mentioned.
Can be commit or merge request.
+![example of mentioning or closing the Jira issue](img/jira_issue_reference.png)
-![example of mentioning or closing the Jira issue](jira_issue_reference.png)
-
+---
### Closing Jira Issues
-Jira issues can be closed directly from GitLab by using trigger words, eg. `Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and merge requests.
-When a commit which contains the trigger word in the commit message is pushed, GitLab will add a comment in the mentioned Jira issue.
+Jira issues can be closed directly from GitLab by using trigger words, eg.
+`Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and
+merge requests. When a commit which contains the trigger word in the commit
+message is pushed, GitLab will add a comment in the mentioned Jira issue.
-For example, for project named PROJECT in Jira, we implemented a new feature and created a merge request in GitLab.
+For example, for project named `PROJECT` in Jira, we implemented a new feature
+and created a merge request in GitLab.
-This feature was requested in Jira issue PROJECT-7. Merge request in GitLab contains the improvement and in merge request description we say that this merge request `Closes PROJECT-7` issue.
+This feature was requested in Jira issue `PROJECT-7`. Merge request in GitLab
+contains the improvement and in merge request description we say that this
+merge request `Closes PROJECT-7` issue.
-Once this merge request is merged, Jira issue will be automatically closed with a link to the commit that resolved the issue.
+Once this merge request is merged, the Jira issue will be automatically closed
+with a link to the commit that resolved the issue.
-![A Git commit that causes the Jira issue to be closed](merge_request_close_jira.png)
+![A Git commit that causes the Jira issue to be closed](img/jira_merge_request_close.png)
+---
-![The GitLab integration user leaves a comment on Jira](jira_service_close_issue.png)
+![The GitLab integration user leaves a comment on Jira](img/jira_service_close_issue.png)
+---
## Configuration
### Configuring JIRA
-We need to create a user in JIRA which will have access to all projects that need to integrate with GitLab.
-Login to your JIRA instance as admin and under Administration go to User Management and create a new user.
-As an example, we'll create a user named `gitlab` and add it to `jira-developers` group.
+We need to create a user in JIRA which will have access to all projects that
+need to integrate with GitLab. Login to your JIRA instance as admin and under
+Administration go to User Management and create a new user.
+
+As an example, we'll create a user named `gitlab` and add it to `jira-developers`
+group.
**It is important that the user `gitlab` has write-access to projects in JIRA**
### Configuring GitLab
-### GitLab 7.8 EE and up with JIRA v6.x
+JIRA configuration in GitLab is done via a project's **Services**.
-To enable JIRA integration in a project, navigate to the project Settings page and go to Services. Here you will find JIRA.
+#### GitLab 7.8 and up with JIRA v6.x
-Fill in the required details on the page:
+See next section.
-![Jira service page](jira_service_page.png)
+#### GitLab 7.8 and up
-* `description` A name for the issue tracker (to differentiate between instances, for instance).
-* `project url` The URL to the JIRA project which is being linked to this GitLab project.
-* `issues url` The URL to the JIRA project issues overview for the project that is linked to this GitLab project.
-* `new issue url` This is the URL to create a new issue in JIRA for the project linked to this GitLab project.
-* `api url` The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`.
-* `username` The username of the user created in [configuring JIRA step](#configuring-jira).
-* `password` The password of the user created in [configuring JIRA step](#configuring-jira).
-* `Jira issue transition` This is the id of a transition that moves issues to a closed state. You can find this number under [JIRA workflow administration, see screenshot](jira_workflow_screenshot.png). By default, this id is `2`. (In the example image, this is `2` as well)
+_The currently supported JIRA versions are v6.x and v7.x._
-After saving the configuration, your GitLab project will be able to interact with the linked JIRA project.
+To enable JIRA integration in a project, navigate to the project's
+**Settings > Services > JIRA**.
+Fill in the required details on the page as described in the table below.
-### GitLab 6.x-7.7 with JIRA v6.x
+| Field | Description |
+| ----- | ----------- |
+| `description` | A name for the issue tracker (to differentiate between instances, for instance). |
+| `project url` | The URL to the JIRA project which is being linked to this GitLab project. |
+| `issues url` | The URL to the JIRA project issues overview for the project that is linked to this GitLab project. |
+| `new issue url` | This is the URL to create a new issue in JIRA for the project linked to this GitLab project. |
+| `api url` | The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`. |
+| `username` | The username of the user created in [configuring JIRA step](#configuring-jira). |
+| `password` |The password of the user created in [configuring JIRA step](#configuring-jira). |
+| `Jira issue transition` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). By default, this ID is `2` (in the example image, this is `2` as well) |
-**Note: GitLab 7.8 and up contain various integration improvements. We strongly recommend upgrading.**
+After saving the configuration, your GitLab project will be able to interact
+with the linked JIRA project.
+![Jira service page](img/jira_service_page.png)
-In `gitlab.yml` enable [JIRA issue tracker section by uncommenting the lines](https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115).
-This will make sure that all issues within GitLab are pointing to the JIRA issue tracker.
+---
-We can also enable JIRA service that will allow us to interact with JIRA issues.
+#### GitLab 6.x-7.7 with JIRA v6.x
-For example, we can close issues in JIRA by a commit in GitLab.
+_**Note:** GitLab versions 7.8 and up contain various integration improvements.
+We strongly recommend upgrading._
-Go to project settings page and fill in the project name for the JIRA project:
+In `gitlab.yml` enable the JIRA issue tracker section by
+[uncommenting these lines][jira-gitlab-yml]. This will make sure that all
+issues within GitLab are pointing to the JIRA issue tracker.
-![Set the JIRA project name in GitLab to 'NEW'](jira_project_name.png)
+After you set this, you will be able to close issues in JIRA by a commit in
+GitLab.
-Next, go to the services page and find JIRA.
+Go to your project's **Settings** page and fill in the project name for the
+JIRA project:
-![Jira services page](jira_service.png)
+![Set the JIRA project name in GitLab to 'NEW'](img/jira_project_name.png)
-1. Tick the active check box to enable the service.
-1. Supply the url to JIRA server, for example http://jira.sample
-1. Supply the username of a user we created under `Configuring JIRA` section, for example `gitlab`
+---
+
+You can also enable the JIRA service that will allow you to interact with JIRA
+issues. Go to the **Settings > Services > JIRA** and:
+
+1. Tick the active check box to enable the service
+1. Supply the URL to JIRA server, for example http://jira.example.com
+1. Supply the username of a user we created under `Configuring JIRA` section,
+ for example `gitlab`
1. Supply the password of the user
-1. Optional: supply the JIRA api version, default is version
-1. Optional: supply the JIRA issue transition ID (issue transition to closed). This is dependant on JIRA settings, default is 2
-1. Save
+1. Optional: supply the JIRA API version, default is version `2`
+1. Optional: supply the JIRA issue transition ID (issue transition to closed).
+ This is dependent on JIRA settings, default is `2`
+1. Hit save
+
+
+![Jira services page](img/jira_service.png)
-Now we should be able to interact with JIRA issues.
+[services-templates]: ../project_services/services_templates.md
+[jira-gitlab-yml]: https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115
diff --git a/doc/integration/jira_service_page.png b/doc/integration/jira_service_page.png
deleted file mode 100644
index 69ec44e826f..00000000000
--- a/doc/integration/jira_service_page.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/redmine_configuration.png b/doc/integration/redmine_configuration.png
deleted file mode 100644
index 6b145363229..00000000000
--- a/doc/integration/redmine_configuration.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/redmine_service_template.png b/doc/integration/redmine_service_template.png
deleted file mode 100644
index 1159eb5b964..00000000000
--- a/doc/integration/redmine_service_template.png
+++ /dev/null
Binary files differ
diff --git a/doc/project_services/img/redmine_configuration.png b/doc/project_services/img/redmine_configuration.png
new file mode 100644
index 00000000000..d14e526ad33
--- /dev/null
+++ b/doc/project_services/img/redmine_configuration.png
Binary files differ
diff --git a/doc/project_services/img/services_templates_redmine_example.png b/doc/project_services/img/services_templates_redmine_example.png
new file mode 100644
index 00000000000..384d057fc8e
--- /dev/null
+++ b/doc/project_services/img/services_templates_redmine_example.png
Binary files differ
diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md
index 03937d20728..e3403127723 100644
--- a/doc/project_services/project_services.md
+++ b/doc/project_services/project_services.md
@@ -1,20 +1,37 @@
# Project Services
-
-__Project integrations with external services for continuous integration and more.__
+
+Project services allow you to integrate GitLab with other applications. Below
+is list of the currently supported ones. Click on the service links to see
+further configuration instructions and details. Contributions are welcome.
## Services
-- Assembla
-- [Atlassian Bamboo CI](bamboo.md) An Atlassian product for continuous integration.
-- Build box
-- Campfire
-- Emails on push
-- Flowdock
-- Gemnasium
-- GitLab CI
-- [HipChat](hipchat.md) An Atlassian product for private group chat and instant messaging.
-- [Irker](irker.md) An IRC gateway to receive messages on repository updates.
-- Pivotal Tracker
-- Pushover
-- Slack
-- TeamCity
+| Service | Description |
+| ------- | ----------- |
+| Asana | Asana - Teamwork without email |
+| Assembla | Project Management Software (Source Commits Endpoint) |
+| [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server |
+| Buildkite | Continuous integration and deployments |
+| Builds emails | Email the builds status to a list of recipients |
+| Campfire | Simple web-based real-time group chat |
+| Custom Issue Tracker | Custom issue tracker |
+| Drone CI | Continuous Integration platform built on Docker, written in Go |
+| Emails on push | Email the commits and diff of each push to a list of recipients |
+| External Wiki | Replaces the link to the internal wiki with a link to an external wiki |
+| Flowdock | Flowdock is a collaboration web app for technical teams |
+| Gemnasium | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities |
+| [HipChat](hipchat.md) | Private group chat and IM |
+| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway |
+| JIRA | Jira issue tracker |
+| JetBrains TeamCity CI | A continuous integration and build server |
+| PivotalTracker | Project Management Software (Source Commits Endpoint) |
+| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop |
+| [Redmine](redmine.md) | Redmine issue tracker |
+| Slack | A team communication tool for the 21st century |
+
+## Services Templates
+
+Services templates is a way to set some predefined values in the Service of
+your liking which will then be pre-filled on each project's Service.
+
+Read more about [Services Templates in this document](services_templates.md).
diff --git a/doc/project_services/redmine.md b/doc/project_services/redmine.md
new file mode 100644
index 00000000000..b9830ea7c38
--- /dev/null
+++ b/doc/project_services/redmine.md
@@ -0,0 +1,21 @@
+# Redmine Service
+
+Go to your project's **Settings > Services > Redmine** and fill in the required
+details as described in the table below.
+
+| Field | Description |
+| ----- | ----------- |
+| `description` | A name for the issue tracker (to differentiate between instances, for example) |
+| `project_url` | The URL to the project in Redmine which is being linked to this GitLab project |
+| `issues_url` | The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. |
+| `new_issue_url` | This is the URL to create a new issue in Redmine for the project linked to this GitLab project |
+
+Once you have configured and enabled Redmine:
+
+- the **Issues** link on the GitLab project pages takes you to the appropriate
+ Redmine issue index
+- clicking **New issue** on the project dashboard creates a new Redmine issue
+
+As an example, below is a configuration for a project named gitlab-ci.
+
+![Redmine configuration](img/redmine_configuration.png)
diff --git a/doc/project_services/services_templates.md b/doc/project_services/services_templates.md
new file mode 100644
index 00000000000..be6d13b6d2b
--- /dev/null
+++ b/doc/project_services/services_templates.md
@@ -0,0 +1,25 @@
+# Services Templates
+
+A GitLab administrator can add a service template that sets a default for each
+project. This makes it much easier to configure individual projects.
+
+After the template is created, the template details will be pre-filled on a
+project's Service page.
+
+## Enable a Service template
+
+In GitLab's Admin area, navigate to **Service Templates** and choose the
+service template you wish to create.
+
+For example, in the image below you can see Redmine.
+
+![Redmine service template](img/services_templates_redmine_example.png)
+
+---
+
+**NOTE:** For each project, you will still need to configure the issue tracking
+URLs by replacing `:issues_tracker_id` in the above screenshot with the ID used
+by your external issue tracker. Prior to GitLab v7.8, this ID was configured in
+the project settings, and GitLab would automatically update the URL configured
+in `gitlab.yml`. This behavior is now deprecated and all issue tracker URLs
+must be configured directly within the project's **Services** settings.
diff --git a/doc/workflow/add-user/add-user.md b/doc/workflow/add-user/add-user.md
index 8c9b4f72631..fffa0aba57f 100644
--- a/doc/workflow/add-user/add-user.md
+++ b/doc/workflow/add-user/add-user.md
@@ -1,25 +1,89 @@
# Project users
-You can manage the groups and users and their access levels in all of your projects. You can also personalize the access level you give each user, per project.
+You can manage the groups and users and their access levels in all of your
+projects. You can also personalize the access level you give each user,
+per-project.
-Here's how to add or import users to your projects.
-
-You should have 'master' or 'owner' permissions to add or import a new user
+You should have `master` or `owner` permissions to add or import a new user
to your project.
-To add or import a user, go to your project and click on "Members" on the left side of your screen:
+The first step to add or import a user, go to your project and click on
+**Members** on the left side of your screen.
+
+![Members](img/add_user_members_menu.png)
+
+---
+
+## Add a user
+
+Right next to **People**, start typing the name or username of the user you
+want to add.
+
+![Search for people](img/add_user_search_people.png)
+
+---
+
+Select the user and the [permission level](../../permissions/permissions.md)
+that you'd like to give the user. Note that you can select more than one user.
+
+![Give user permissions](img/add_user_give_permissions.png)
+
+---
+
+Once done, hit **Add users to project** and they will be immediately added to
+your project with the permissions you gave them above.
+
+![List members](img/add_user_list_members.png)
+
+---
+
+From there on, you can either remove an existing user or change their access
+level to the project.
+
+## Import users from another project
+
+You can import another project's users in your own project by hitting the
+**Import members** button on the upper right corner of the **Members** menu.
+
+In the dropdown menu, you can see only the projects you are Master on.
+
+![Import members from another project](img/add_user_import_members_from_another_project.png)
+
+---
+
+Select the one you want and hit **Import project members**. A flash message
+notifying you that the import was successful will appear, and the new members
+are now in the project's members list. Notice that the permissions that they
+had on the project you imported from are retained.
+
+![Members list of new members](img/add_user_imported_members.png)
+
+---
+
+## Invite people using their e-mail address
+
+If a user you want to give access to doesn't have an account on your GitLab
+instance, you can invite them just by typing their e-mail address in the
+user search field.
+
+![Invite user by mail](img/add_user_email_search.png)
+
+---
-![Members](images/members.png)
+As you can imagine, you can mix inviting multiple people and adding existing
+GitLab users to the project.
-Select "Add members" or "Import members" on the right side of your screen:
+![Invite user by mail ready to submit](img/add_user_email_ready.png)
-![Add or Import](images/add-members.png)
+---
-If you are adding a user, select the user and the [permission level](doc/permissions/permissions.md) that you'd like to
-give the user:
+Once done, hit **Add users to project** and watch that there is a new member
+with the e-mail address we used above. From there on, you can resend the
+invitation, change their access level or even delete them.
-![Add or Import](images/new-member.png)
+![Invite user members list](img/add_user_email_accept.png)
-If you are importing a user, follow the steps to select the project where you'd like to import the user from:
+---
-![Add or Import](images/select-project.png)
+Once the user accepts the invitation, they will be prompted to create a new
+GitLab account using the same e-mail address the invitation was sent to.
diff --git a/doc/workflow/add-user/images/add-members.png b/doc/workflow/add-user/images/add-members.png
deleted file mode 100644
index 2805c5764a5..00000000000
--- a/doc/workflow/add-user/images/add-members.png
+++ /dev/null
Binary files differ
diff --git a/doc/workflow/add-user/images/new-member.png b/doc/workflow/add-user/images/new-member.png
deleted file mode 100644
index d500daea56e..00000000000
--- a/doc/workflow/add-user/images/new-member.png
+++ /dev/null
Binary files differ
diff --git a/doc/workflow/add-user/images/select-project.png b/doc/workflow/add-user/images/select-project.png
deleted file mode 100644
index dd3844edff8..00000000000
--- a/doc/workflow/add-user/images/select-project.png
+++ /dev/null
Binary files differ
diff --git a/doc/workflow/add-user/img/add_new_user_to_project_settings.png b/doc/workflow/add-user/img/add_new_user_to_project_settings.png
new file mode 100644
index 00000000000..3da18cdae53
--- /dev/null
+++ b/doc/workflow/add-user/img/add_new_user_to_project_settings.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_email_accept.png b/doc/workflow/add-user/img/add_user_email_accept.png
new file mode 100644
index 00000000000..910affc9659
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_email_accept.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_email_ready.png b/doc/workflow/add-user/img/add_user_email_ready.png
new file mode 100644
index 00000000000..5f02ce89b3e
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_email_ready.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_email_search.png b/doc/workflow/add-user/img/add_user_email_search.png
new file mode 100644
index 00000000000..140979fbe13
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_email_search.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_give_permissions.png b/doc/workflow/add-user/img/add_user_give_permissions.png
new file mode 100644
index 00000000000..8ef9156c8d5
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_give_permissions.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_import_members_from_another_project.png b/doc/workflow/add-user/img/add_user_import_members_from_another_project.png
new file mode 100644
index 00000000000..5770d5cf0c4
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_import_members_from_another_project.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_imported_members.png b/doc/workflow/add-user/img/add_user_imported_members.png
new file mode 100644
index 00000000000..dea4b3f40ad
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_imported_members.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_list_members.png b/doc/workflow/add-user/img/add_user_list_members.png
new file mode 100644
index 00000000000..7daa6ca7d9e
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_list_members.png
Binary files differ
diff --git a/doc/workflow/add-user/images/members.png b/doc/workflow/add-user/img/add_user_members_menu.png
index f1797b95f67..f1797b95f67 100644
--- a/doc/workflow/add-user/images/members.png
+++ b/doc/workflow/add-user/img/add_user_members_menu.png
Binary files differ
diff --git a/doc/workflow/add-user/img/add_user_search_people.png b/doc/workflow/add-user/img/add_user_search_people.png
new file mode 100644
index 00000000000..5ac10ce80d4
--- /dev/null
+++ b/doc/workflow/add-user/img/add_user_search_people.png
Binary files differ
diff --git a/features/steps/group/milestones.rb b/features/steps/group/milestones.rb
index 6e57b16ccb6..2363ad797fa 100644
--- a/features/steps/group/milestones.rb
+++ b/features/steps/group/milestones.rb
@@ -28,7 +28,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps
end
step 'I should see group milestone with descriptions and expiry date' do
- expect(page).to have_content('expires at Aug 20, 2114')
+ expect(page).to have_content('expires on Aug 20, 2114')
end
step 'I should see group milestone with all issues and MRs assigned to that milestone' do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 0781236cf6d..8b1390e3289 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -269,7 +269,7 @@ module API
# Remove a forked_from relationship
#
# Parameters:
- # id: (required) - The ID of the project being marked as a fork
+ # id: (required) - The ID of the project being marked as a fork
# Example Request:
# DELETE /projects/:id/fork
delete ":id/fork" do
@@ -278,6 +278,16 @@ module API
user_project.forked_project_link.destroy
end
end
+
+ # Upload a file
+ #
+ # Parameters:
+ # id: (required) - The ID of the project
+ # file: (required) - The file to be uploaded
+ post ":id/uploads" do
+ ::Projects::UploadService.new(user_project, params[:file]).execute
+ end
+
# search for projects current_user has access to
#
# Parameters:
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 47621f443e6..2d8a9e51bb9 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -40,6 +40,27 @@ module API
end
end
+ # Delete tag
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # tag_name (required) - The name of the tag
+ # Example Request:
+ # DELETE /projects/:id/repository/tags/:tag
+ delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.*/ } do
+ authorize_push_project
+ result = DeleteTagService.new(user_project, current_user).
+ execute(params[:tag_name])
+
+ if result[:status] == :success
+ {
+ tag_name: params[:tag_name]
+ }
+ else
+ render_api_error!(result[:message], result[:return_code])
+ end
+ end
+
# Add release notes to tag
#
# Parameters:
diff --git a/lib/gitlab/build_data_builder.rb b/lib/gitlab/build_data_builder.rb
index 86bfa0a4378..34e949130da 100644
--- a/lib/gitlab/build_data_builder.rb
+++ b/lib/gitlab/build_data_builder.rb
@@ -23,6 +23,7 @@ module Gitlab
build_started_at: build.started_at,
build_finished_at: build.finished_at,
build_duration: build.duration,
+ build_allow_failure: build.allow_failure,
# TODO: do we still need it?
project_id: project.id,
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 7a86c09158e..7f938780ab1 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -41,6 +41,9 @@ module Gitlab
use_db && ActiveRecord::Base.connection.active? &&
!ActiveRecord::Migrator.needs_migration? &&
ActiveRecord::Base.connection.table_exists?('application_settings')
+
+ rescue ActiveRecord::NoDatabaseError
+ false
end
end
end
diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb
index 2b252b32887..2ca21af5bc8 100644
--- a/lib/gitlab/email/receiver.rb
+++ b/lib/gitlab/email/receiver.rb
@@ -74,7 +74,7 @@ module Gitlab
def sent_notification
return nil unless reply_key
-
+
SentNotification.for(reply_key)
end
@@ -82,10 +82,7 @@ module Gitlab
attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project)
attachments.each do |link|
- text = "[#{link[:alt]}](#{link[:url]})"
- text.prepend("!") if link[:is_image]
-
- reply << "\n\n#{text}"
+ reply << "\n\n#{link[:markdown]}"
end
reply
diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb
index 403ebeec474..db580b5e578 100644
--- a/lib/gitlab/fogbugz_import/importer.rb
+++ b/lib/gitlab/fogbugz_import/importer.rb
@@ -232,9 +232,7 @@ module Gitlab
return nil if res.nil?
- text = "[#{res['alt']}](#{res['url']})"
- text = "!#{text}" if res['is_image']
- text
+ res[:markdown]
end
def build_attachment_url(rel_url)
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 68527c3a4f8..efc850eb705 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -240,7 +240,7 @@ describe ApplicationHelper do
describe 'time_ago_with_tooltip' do
def element(*arguments)
Time.zone = 'UTC'
- time = Time.zone.parse('2015-07-02 08:00')
+ time = Time.zone.parse('2015-07-02 08:23')
element = helper.time_ago_with_tooltip(time, *arguments)
Nokogiri::HTML::DocumentFragment.parse(element).first_element_child
@@ -251,15 +251,15 @@ describe ApplicationHelper do
end
it 'includes the date string' do
- expect(element.text).to eq '2015-07-02 08:00:00 UTC'
+ expect(element.text).to eq '2015-07-02 08:23:00 UTC'
end
it 'has a datetime attribute' do
- expect(element.attr('datetime')).to eq '2015-07-02T08:00:00Z'
+ expect(element.attr('datetime')).to eq '2015-07-02T08:23:00Z'
end
it 'has a formatted title attribute' do
- expect(element.attr('title')).to eq 'Jul 02, 2015 8:00am'
+ expect(element.attr('title')).to eq 'Jul 2, 2015 8:23am'
end
it 'includes a default js-timeago class' do
diff --git a/spec/lib/banzai/filter/task_list_filter_spec.rb b/spec/lib/banzai/filter/task_list_filter_spec.rb
index f2e3a44478d..569cbc885c7 100644
--- a/spec/lib/banzai/filter/task_list_filter_spec.rb
+++ b/spec/lib/banzai/filter/task_list_filter_spec.rb
@@ -7,4 +7,10 @@ describe Banzai::Filter::TaskListFilter, lib: true do
exp = act = %(<ul><li>Item</li></ul>)
expect(filter(act).to_html).to eq exp
end
+
+ it 'applies `task-list` to single-item task lists' do
+ act = filter('<ul><li>[ ] Task 1</li></ul>')
+
+ expect(act.to_html).to start_with '<ul class="task-list">'
+ end
end
diff --git a/spec/lib/gitlab/build_data_builder_spec.rb b/spec/lib/gitlab/build_data_builder_spec.rb
index 839b30f1ff4..38be9448794 100644
--- a/spec/lib/gitlab/build_data_builder_spec.rb
+++ b/spec/lib/gitlab/build_data_builder_spec.rb
@@ -14,6 +14,7 @@ describe 'Gitlab::BuildDataBuilder' do
it { expect(data[:tag]).to eq(build.tag) }
it { expect(data[:build_id]).to eq(build.id) }
it { expect(data[:build_status]).to eq(build.status) }
+ it { expect(data[:build_allow_failure]).to eq(false) }
it { expect(data[:project_id]).to eq(build.project.id) }
it { expect(data[:project_name]).to eq(build.project.name_with_namespace) }
end
diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb
index b535413bbd4..abe179cd4af 100644
--- a/spec/lib/gitlab/email/receiver_spec.rb
+++ b/spec/lib/gitlab/email/receiver_spec.rb
@@ -42,7 +42,7 @@ describe Gitlab::Email::Receiver, lib: true do
context "when the email was auto generated" do
let!(:reply_key) { '636ca428858779856c226bb145ef4fad' }
let!(:email_raw) { fixture_file("emails/auto_reply.eml") }
-
+
it "raises an AutoGeneratedEmailError" do
expect { receiver.execute }.to raise_error(Gitlab::Email::Receiver::AutoGeneratedEmailError)
end
@@ -90,7 +90,7 @@ describe Gitlab::Email::Receiver, lib: true do
context "when the reply is blank" do
let!(:email_raw) { fixture_file("emails/no_content_reply.eml") }
-
+
it "raises an EmptyEmailError" do
expect { receiver.execute }.to raise_error(Gitlab::Email::Receiver::EmptyEmailError)
end
@@ -107,13 +107,16 @@ describe Gitlab::Email::Receiver, lib: true do
end
context "when everything is fine" do
+ let(:markdown) { "![image](uploads/image.png)" }
+
before do
allow_any_instance_of(Gitlab::Email::AttachmentUploader).to receive(:execute).and_return(
[
{
url: "uploads/image.png",
is_image: true,
- alt: "image"
+ alt: "image",
+ markdown: markdown
}
]
)
@@ -132,7 +135,7 @@ describe Gitlab::Email::Receiver, lib: true do
note = noteable.notes.last
- expect(note.note).to include("![image](uploads/image.png)")
+ expect(note.note).to include(markdown)
end
end
end
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 2d90b0793cc..7070aa4ac62 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -77,5 +77,17 @@ describe ProjectHook, models: true do
expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error'])
end
+
+ it "handles 200 status code" do
+ WebMock.stub_request(:post, @project_hook.url).to_return(status: 200, body: "Success")
+
+ expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success'])
+ end
+
+ it "handles 2xx status codes" do
+ WebMock.stub_request(:post, @project_hook.url).to_return(status: 201, body: "Success")
+
+ expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success'])
+ end
end
end
diff --git a/spec/models/project_services/builds_email_service_spec.rb b/spec/models/project_services/builds_email_service_spec.rb
new file mode 100644
index 00000000000..905379a64e3
--- /dev/null
+++ b/spec/models/project_services/builds_email_service_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe BuildsEmailService do
+ let(:build) { create(:ci_build) }
+ let(:data) { Gitlab::BuildDataBuilder.build(build) }
+ let(:service) { BuildsEmailService.new }
+
+ describe :execute do
+ it "sends email" do
+ service.recipients = 'test@gitlab.com'
+ data[:build_status] = 'failed'
+ expect(BuildEmailWorker).to receive(:perform_async)
+ service.execute(data)
+ end
+
+ it "does not sends email with failed build and allowed_failure on" do
+ data[:build_status] = 'failed'
+ data[:build_allow_failure] = true
+ expect(BuildEmailWorker).not_to receive(:perform_async)
+ service.execute(data)
+ end
+ end
+end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index ab2530859ea..6f4c336b66c 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -353,6 +353,20 @@ describe API::API, api: true do
end
end
+ describe "POST /projects/:id/uploads" do
+ before { project }
+
+ it "uploads the file and returns its info" do
+ post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")
+
+ expect(response.status).to be(201)
+ expect(json_response['alt']).to eq("dk")
+ expect(json_response['url']).to start_with("/uploads/")
+ expect(json_response['url']).to end_with("/dk.png")
+ expect(json_response['is_image']).to eq(true)
+ end
+ end
+
describe 'GET /projects/:id' do
before { project }
before { project_member }
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index 17f2643fd45..f966e38cd3e 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -65,6 +65,27 @@ describe API::API, api: true do
end
end
+ describe 'DELETE /projects/:id/repository/tags/:tag_name' do
+ let(:tag_name) { project.repository.tag_names.sort.reverse.first }
+
+ before do
+ allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true)
+ end
+
+ context 'delete tag' do
+ it 'should delete an existing tag' do
+ delete api("/projects/#{project.id}/repository/tags/#{tag_name}", user)
+ expect(response.status).to eq(200)
+ expect(json_response['tag_name']).to eq(tag_name)
+ end
+
+ it 'should raise 404 if the tag does not exist' do
+ delete api("/projects/#{project.id}/repository/tags/foobar", user)
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
context 'annotated tag' do
it 'should create a new annotated tag' do
# Identity must be set in .gitconfig to create annotated tag.
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 2a70c190337..22ba25217f0 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -80,6 +80,7 @@ describe ProjectsController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq')
+ expect(get('/gitlab/gitlabhq.keys')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq.keys')
end
it 'to #update' do
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index 5ceed5af9a5..f252e2c5902 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -33,12 +33,12 @@ describe Projects::DownloadService, services: true do
@link_to_file = download_file(@project, url)
end
- it { expect(@link_to_file).to have_key('alt') }
- it { expect(@link_to_file).to have_key('url') }
- it { expect(@link_to_file).to have_key('is_image') }
- it { expect(@link_to_file['is_image']).to be true }
- it { expect(@link_to_file['url']).to match('rails_sample.jpg') }
- it { expect(@link_to_file['alt']).to eq('rails_sample') }
+ it { expect(@link_to_file).to have_key(:alt) }
+ it { expect(@link_to_file).to have_key(:url) }
+ it { expect(@link_to_file).to have_key(:is_image) }
+ it { expect(@link_to_file[:is_image]).to be true }
+ it { expect(@link_to_file[:url]).to match('rails_sample.jpg') }
+ it { expect(@link_to_file[:alt]).to eq('rails_sample') }
end
context 'a txt file' do
@@ -47,12 +47,12 @@ describe Projects::DownloadService, services: true do
@link_to_file = download_file(@project, url)
end
- it { expect(@link_to_file).to have_key('alt') }
- it { expect(@link_to_file).to have_key('url') }
- it { expect(@link_to_file).to have_key('is_image') }
- it { expect(@link_to_file['is_image']).to be false }
- it { expect(@link_to_file['url']).to match('doc_sample.txt') }
- it { expect(@link_to_file['alt']).to eq('doc_sample.txt') }
+ it { expect(@link_to_file).to have_key(:alt) }
+ it { expect(@link_to_file).to have_key(:url) }
+ it { expect(@link_to_file).to have_key(:is_image) }
+ it { expect(@link_to_file[:is_image]).to be false }
+ it { expect(@link_to_file[:url]).to match('doc_sample.txt') }
+ it { expect(@link_to_file[:alt]).to eq('doc_sample.txt') }
end
end
end