Commit 2c37ae2f authored by Jeroen Nijhof's avatar Jeroen Nijhof

Merge gitlab.com:gitlab-org/gitlab-ce

parents 1695063d 08213ed4
...@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.4.0 (unreleased) v 8.4.0 (unreleased)
- Add housekeeping function to project settings page - Add housekeeping function to project settings page
- 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) - Fix missing date of month in network graph when commits span a month (Stan Hu)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
...@@ -9,6 +10,7 @@ v 8.4.0 (unreleased) ...@@ -9,6 +10,7 @@ v 8.4.0 (unreleased)
- Implement search inside emoji picker - Implement search inside emoji picker
- Add API support for looking up a user by username (Stan Hu) - Add API support for looking up a user by username (Stan Hu)
- Add project permissions to all project API endpoints (Stan Hu) - Add project permissions to all project API endpoints (Stan Hu)
- Link to milestone in "Milestone changed" system note
- Only allow group/project members to mention `@all` - Only allow group/project members to mention `@all`
- Expose Git's version in the admin area (Trey Davis) - Expose Git's version in the admin area (Trey Davis)
- Add "Frequently used" category to emoji picker - Add "Frequently used" category to emoji picker
...@@ -23,6 +25,9 @@ v 8.4.0 (unreleased) ...@@ -23,6 +25,9 @@ v 8.4.0 (unreleased)
- Update version check images to use SVG - Update version check images to use SVG
- Validate README format before displaying - Validate README format before displaying
- Enable Microsoft Azure OAuth2 support (Janis Meybohm) - Enable Microsoft Azure OAuth2 support (Janis Meybohm)
- Properly set task-list class on single item task lists
- Add file finder feature in tree view (Kyungchul Shin)
- Ajax filter by message for commits page
v 8.3.3 (unreleased) v 8.3.3 (unreleased)
- Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running
...@@ -108,7 +113,6 @@ v 8.3.0 ...@@ -108,7 +113,6 @@ v 8.3.0
- Fix online editor should not remove newlines at the end of the file - Fix online editor should not remove newlines at the end of the file
- Expose Git's version in the admin area - Expose Git's version in the admin area
- Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye)
- Add file finder feature in tree view
v 8.2.3 v 8.2.3
- Fix application settings cache not expiring after changes (Stan Hu) - Fix application settings cache not expiring after changes (Stan Hu)
......
...@@ -67,10 +67,6 @@ gem 'grape', '~> 0.13.0' ...@@ -67,10 +67,6 @@ gem 'grape', '~> 0.13.0'
gem 'grape-entity', '~> 0.4.2' gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times
# based on human-friendly examples
gem "stamp", '~> 0.6.0'
# Pagination # Pagination
gem "kaminari", "~> 0.16.3" gem "kaminari", "~> 0.16.3"
......
...@@ -443,6 +443,10 @@ GEM ...@@ -443,6 +443,10 @@ GEM
omniauth (1.2.2) omniauth (1.2.2)
hashie (>= 1.2, < 4) hashie (>= 1.2, < 4)
rack (~> 1.0) rack (~> 1.0)
omniauth-azure-oauth2 (0.0.6)
jwt (~> 1.0)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-bitbucket (0.0.2) omniauth-bitbucket (0.0.2)
multi_json (~> 1.7) multi_json (~> 1.7)
omniauth (~> 1.1) omniauth (~> 1.1)
...@@ -488,10 +492,6 @@ GEM ...@@ -488,10 +492,6 @@ GEM
activesupport activesupport
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-azure-oauth2 (0.0.6)
jwt (~> 1.0)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
opennebula (4.14.2) opennebula (4.14.2)
json json
nokogiri nokogiri
...@@ -734,7 +734,6 @@ GEM ...@@ -734,7 +734,6 @@ GEM
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
stamp (0.6.0)
state_machines (0.4.0) state_machines (0.4.0)
state_machines-activemodel (0.3.0) state_machines-activemodel (0.3.0)
activemodel (~> 4.1) activemodel (~> 4.1)
...@@ -920,6 +919,7 @@ DEPENDENCIES ...@@ -920,6 +919,7 @@ DEPENDENCIES
oauth2 (~> 1.0.0) oauth2 (~> 1.0.0)
octokit (~> 3.7.0) octokit (~> 3.7.0)
omniauth (~> 1.2.2) omniauth (~> 1.2.2)
omniauth-azure-oauth2
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2) omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0) omniauth-facebook (~> 3.0.0)
...@@ -931,7 +931,6 @@ DEPENDENCIES ...@@ -931,7 +931,6 @@ DEPENDENCIES
omniauth-shibboleth (~> 1.2.0) omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0) omniauth-twitter (~> 1.2.0)
omniauth_crowd omniauth_crowd
omniauth-azure-oauth2
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
paranoia (~> 2.0) paranoia (~> 2.0)
pg (~> 0.18.2) pg (~> 0.18.2)
...@@ -978,7 +977,6 @@ DEPENDENCIES ...@@ -978,7 +977,6 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0) spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2) spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3) sprockets (~> 2.12.3)
stamp (~> 0.6.0)
state_machines-activerecord (~> 0.3.0) state_machines-activerecord (~> 0.3.0)
task_list (~> 1.0.2) task_list (~> 1.0.2)
teaspoon (~> 1.0.0) teaspoon (~> 1.0.0)
...@@ -999,4 +997,4 @@ DEPENDENCIES ...@@ -999,4 +997,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.10.6 1.11.2
class @CommitsList class @CommitsList
@data = @timer = null
ref: null
limit: 0
offset: 0
@disable = false
@showProgress: ->
$('.loading').show()
@hideProgress: ->
$('.loading').hide()
@init: (ref, limit) -> @init: (ref, limit) ->
$("body").on "click", ".day-commits-table li.commit", (event) -> $("body").on "click", ".day-commits-table li.commit", (event) ->
...@@ -18,38 +8,32 @@ class @CommitsList ...@@ -18,38 +8,32 @@ class @CommitsList
e.stopPropagation() e.stopPropagation()
return false return false
@data.ref = ref Pager.init limit, false
@data.limit = limit
@data.offset = limit @content = $("#commits-list")
@searchField = $("#commits-search")
@initSearch()
this.initLoadMore() @initSearch: ->
this.showProgress() @timer = null
@searchField.keyup =>
clearTimeout(@timer)
@timer = setTimeout(@filterResults, 500)
@filterResults: =>
form = $(".commits-search-form")
search = @searchField.val()
commitsUrl = form.attr("action") + '?' + form.serialize()
@content.fadeTo('fast', 0.5)
@getOld: ->
this.showProgress()
$.ajax $.ajax
type: "GET" type: "GET"
url: location.href url: form.attr("action")
data: @data data: form.serialize()
complete: this.hideProgress complete: =>
success: (data) -> @content.fadeTo('fast', 1.0)
CommitsList.append(data.count, data.html) success: (data) =>
@content.html(data.html)
# Change url so if user reload a page - search results are saved
history.replaceState {page: commitsUrl}, document.title, commitsUrl
dataType: "json" dataType: "json"
@append: (count, html) ->
$("#commits-list").append(html)
if count > 0
@data.offset += count
else
@disable = true
@initLoadMore: ->
$(document).unbind('scroll')
$(document).endlessScroll
bottomPixels: 400
fireDelay: 1000
fireOnce: true
ceaseFire: =>
@disable
callback: =>
this.getOld()
...@@ -72,6 +72,15 @@ ...@@ -72,6 +72,15 @@
> p:last-child { > p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
.block-controls {
float: right;
.control {
float: left;
margin-left: 10px;
}
}
} }
.cover-block { .cover-block {
......
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
} }
} }
.commits-feed-holder {
float: right;
}
li.commit { li.commit {
list-style: none; list-style: none;
...@@ -126,14 +122,14 @@ li.commit { ...@@ -126,14 +122,14 @@ li.commit {
.divergence-graph { .divergence-graph {
padding: 12px 12px 0 0; padding: 12px 12px 0 0;
float: right; float: right;
.graph-side { .graph-side {
position: relative; position: relative;
width: 80px; width: 80px;
height: 22px; height: 22px;
padding: 5px 0 13px; padding: 5px 0 13px;
float: left; float: left;
.bar { .bar {
position: absolute; position: absolute;
height: 4px; height: 4px;
...@@ -149,7 +145,7 @@ li.commit { ...@@ -149,7 +145,7 @@ li.commit {
left: 0; left: 0;
border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0;
} }
.count { .count {
padding-top: 6px; padding-top: 6px;
padding-bottom: 0px; padding-bottom: 0px;
......
...@@ -138,6 +138,7 @@ ...@@ -138,6 +138,7 @@
*/ */
.event-last-push { .event-last-push {
overflow: auto; overflow: auto;
width: 100%;
.event-last-push-text { .event-last-push-text {
@include str-truncated(100%); @include str-truncated(100%);
padding: 5px 0; padding: 5px 0;
......
...@@ -94,8 +94,16 @@ ...@@ -94,8 +94,16 @@
} }
.cross-project-reference { .cross-project-reference {
font-weight: bold;
color: $gl-link-color; color: $gl-link-color;
span {
white-space: nowrap;
width: 85%;
overflow: hidden;
position: relative;
display: inline-block;
text-overflow: ellipsis;
}
button { button {
float: right; float: right;
......
...@@ -415,6 +415,7 @@ ul.nav.nav-projects-tabs { ...@@ -415,6 +415,7 @@ ul.nav.nav-projects-tabs {
border-bottom: 1px solid #EEE; border-bottom: 1px solid #EEE;
margin: 0 -16px; margin: 0 -16px;
padding: 0 $gl-padding; padding: 0 $gl-padding;
height: 57px;
ul.left-top-menu { ul.left-top-menu {
display: inline-block; display: inline-block;
......
...@@ -8,10 +8,16 @@ class Projects::CommitsController < Projects::ApplicationController ...@@ -8,10 +8,16 @@ class Projects::CommitsController < Projects::ApplicationController
before_action :authorize_download_code! before_action :authorize_download_code!
def show def show
@repo = @project.repository
@limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i @limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i
search = params[:search]
@commits =
if search.present?
@repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact
else
@repository.commits(@ref, @path, @limit, @offset)
end
@commits = @repo.commits(@ref, @path, @limit, @offset)
@note_counts = project.notes.where(commit_id: @commits.map(&:id)). @note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count group(:commit_id).count
......
...@@ -206,7 +206,7 @@ module ApplicationHelper ...@@ -206,7 +206,7 @@ module ApplicationHelper
element = content_tag :time, time.to_s, element = content_tag :time, time.to_s,
class: "#{html_class} js-timeago js-timeago-pending", class: "#{html_class} js-timeago js-timeago-pending",
datetime: time.getutc.iso8601, 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' } data: { toggle: 'tooltip', placement: placement, container: 'body' }
unless skip_js unless skip_js
......
...@@ -80,7 +80,7 @@ module IssuesHelper ...@@ -80,7 +80,7 @@ module IssuesHelper
xml.link href: namespace_project_issue_url(issue.project.namespace, xml.link href: namespace_project_issue_url(issue.project.namespace,
issue.project, issue) issue.project, issue)
xml.title truncate(issue.title, length: 80) 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.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
xml.author do |author| xml.author do |author|
xml.name issue.author_name xml.name issue.author_name
......
...@@ -19,7 +19,7 @@ module SortingHelper ...@@ -19,7 +19,7 @@ module SortingHelper
end end
def sort_title_recently_updated def sort_title_recently_updated
'Recently updated' 'Last updated'
end end
def sort_title_oldest_created def sort_title_oldest_created
...@@ -27,7 +27,7 @@ module SortingHelper ...@@ -27,7 +27,7 @@ module SortingHelper
end end
def sort_title_recently_created def sort_title_recently_created
'Recently created' 'Last created'
end end
def sort_title_milestone_soon def sort_title_milestone_soon
......
...@@ -27,9 +27,20 @@ ...@@ -27,9 +27,20 @@
# admin_notification_email :string(255) # admin_notification_email :string(255)
# shared_runners_enabled :boolean default(TRUE), not null # shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null # max_artifacts_size :integer default(100), not null
# runners_registration_token :string(255) # runners_registration_token :string
# require_two_factor_authentication :boolean default(TRUE) # require_two_factor_authentication :boolean default(FALSE)
# two_factor_grace_period :integer default(48) # two_factor_grace_period :integer default(48)
# metrics_enabled :boolean default(FALSE)
# metrics_host :string default("localhost")
# metrics_username :string
# metrics_password :string
# metrics_pool_size :integer default(16)
# metrics_timeout :integer default(10)
# metrics_method_call_threshold :integer default(10)
# recaptcha_enabled :boolean default(FALSE)
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
# #
class ApplicationSetting < ActiveRecord::Base class ApplicationSetting < ActiveRecord::Base
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
# target_url :string(255) # target_url :string(255)
# description :string(255) # description :string(255)
# artifacts_file :text # artifacts_file :text
# gl_project_id :integer
# #
module Ci module Ci
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
# #
# Table name: ci_runner_projects # Table name: ci_runner_projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# runner_id :integer not null # runner_id :integer not null
# project_id :integer not null # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# gl_project_id :integer
# #
module Ci module Ci
......
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
# #
# Table name: ci_triggers # Table name: ci_triggers
# #
# id :integer not null, primary key # id :integer not null, primary key
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer
# deleted_at :datetime # deleted_at :datetime
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# gl_project_id :integer
# #
module Ci module Ci
......
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
# Table name: ci_variables # Table name: ci_variables
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer not null # project_id :integer
# key :string(255) # key :string(255)
# value :text # value :text
# encrypted_value :text # encrypted_value :text
# encrypted_value_salt :string(255) # encrypted_value_salt :string(255)
# encrypted_value_iv :string(255) # encrypted_value_iv :string(255)
# gl_project_id :integer
# #
module Ci module Ci
......
# == Schema Information # == Schema Information
# #
# project_id integer # Table name: ci_builds
# status string #
# finished_at datetime # id :integer not null, primary key
# trace text # project_id :integer
# created_at datetime # status :string(255)
# updated_at datetime # finished_at :datetime
# started_at datetime # trace :text
# runner_id integer # created_at :datetime
# coverage float # updated_at :datetime
# commit_id integer # started_at :datetime
# commands text # runner_id :integer
# job_id integer # coverage :float
# name string # commit_id :integer
# deploy boolean default: false # commands :text
# options text # job_id :integer
# allow_failure boolean default: false, null: false # name :string(255)
# stage string # deploy :boolean default(FALSE)
# trigger_request_id integer # options :text
# stage_idx integer # allow_failure :boolean default(FALSE), not null
# tag boolean # stage :string(255)
# ref string # trigger_request_id :integer
# user_id integer # stage_idx :integer
# type string # tag :boolean
# target_url string # ref :string(255)
# description string # user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
# gl_project_id :integer
# #
class CommitStatus < ActiveRecord::Base class CommitStatus < ActiveRecord::Base
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
# target_url :string(255) # target_url :string(255)
# description :string(255) # description :string(255)
# artifacts_file :text # artifacts_file :text
# gl_project_id :integer
# #
class GenericCommitStatus < CommitStatus class GenericCommitStatus < CommitStatus
......
...@@ -121,9 +121,9 @@ class GlobalMilestone ...@@ -121,9 +121,9 @@ class GlobalMilestone
def expires_at def expires_at
if due_date if due_date
if due_date.past? if due_date.past?
"expired at #{due_date.stamp("Aug 21, 2011")}" "expired on #{due_date.to_s(:medium)}"
else else
"expires at #{due_date.stamp("Aug 21, 2011")}" "expires on #{due_date.to_s(:medium)}"
end end
end end
end end
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
# public :boolean default(FALSE)
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE) # enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# #
class ProjectHook < WebHook class ProjectHook < WebHook
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE) # enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# #
class ServiceHook < WebHook class ServiceHook < WebHook
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE) # enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# #
class SystemHook < WebHook class SystemHook < WebHook
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE) # enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# #
class WebHook < ActiveRecord::Base class WebHook < ActiveRecord::Base
...@@ -60,7 +61,7 @@ class WebHook < ActiveRecord::Base ...@@ -60,7 +61,7 @@ class WebHook < ActiveRecord::Base
basic_auth: auth) basic_auth: auth)
end 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 rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
logger.error("WebHook Error => #{e}") logger.error("WebHook Error => #{e}")
[false, e.to_s] [false, e.to_s]
......
...@@ -2,28 +2,28 @@ ...@@ -2,28 +2,28 @@
# #
# Table name: merge_requests # Table name: merge_requests
# #
# id :integer not null, primary key # id :integer not null, primary key
# target_branch :string(255) not null # target_branch :string(255) not null
# source_branch :string(255) not null # source_branch :string(255) not null
# source_project_id :integer not null # source_project_id :integer not null
# author_id :integer # author_id :integer
# assignee_id :integer # assignee_id :integer
# title :string(255) # title :string(255)
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# milestone_id :integer # milestone_id :integer
# state :string(255) # state :string(255)
# merge_status :string(255) # merge_status :string(255)
# target_project_id :integer not null # target_project_id :integer not null
# iid :integer # iid :integer
# description :text # description :text
# position :integer default(0) # position :integer default(0)
# locked_at :datetime # locked_at :datetime
# updated_by_id :integer # updated_by_id :integer
# merge_error :string(255) # merge_error :string(255)
# merge_params :text (serialized to hash) # merge_params :text
# merge_when_build_succeeds :boolean default(false), not null # merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer # merge_user_id :integer
# #
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
......
...@@ -22,6 +22,7 @@ class Milestone < ActiveRecord::Base ...@@ -22,6 +22,7 @@ class Milestone < ActiveRecord::Base
include InternalId include InternalId
include Sortable include Sortable
include Referable
include StripAttribute include StripAttribute
belongs_to :project belongs_to :project
...@@ -61,6 +62,27 @@ class Milestone < ActiveRecord::Base ...@@ -61,6 +62,27 @@ class Milestone < ActiveRecord::Base
end end
end end
def self.reference_pattern
nil
end
def self.link_reference_pattern
super("milestones", /(?<milestone>\d+)/)
end
def to_reference(from_project = nil)
escaped_title = self.title.gsub("]", "\\]")
h = Gitlab::Application.routes.url_helpers
url = h.namespace_project_milestone_url(self.project.namespace, self.project, self)
"[#{escaped_title}](#{url})"
end
def reference_link_text(from_project = nil)
self.title
end
def expired? def expired?
if due_date if due_date
due_date.past? due_date.past?
...@@ -90,9 +112,9 @@ class Milestone < ActiveRecord::Base ...@@ -90,9 +112,9 @@ class Milestone < ActiveRecord::Base
def expires_at def expires_at
if due_date if due_date
if due_date.past? if due_date.past?
"expired at #{due_date.stamp("Aug 21, 2011")}" "expired on #{due_date.to_s(:medium)}"
else else
"expires at #{due_date.stamp("Aug 21, 2011")}" "expires on #{due_date.to_s(:medium)}"
end end
end end
end end
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
# public :boolean default(FALSE)
# #
class Namespace < ActiveRecord::Base class Namespace < ActiveRecord::Base
......
...@@ -29,6 +29,13 @@ ...@@ -29,6 +29,13 @@
# import_source :string(255) # import_source :string(255)
# commit_count :integer default(0) # commit_count :integer default(0)
# import_error :text # import_error :text
# ci_id :integer
# builds_enabled :boolean default(TRUE), not null
# shared_runners_enabled :boolean default(TRUE), not null
# runners_token :string
# build_coverage_regex :string
# build_allow_git_fetch :boolean default(TRUE), not null
# build_timeout :integer default(3600), not null
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require 'asana' require 'asana'
class AsanaService < Service class AsanaService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class AssemblaService < Service class AssemblaService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class BambooService < CiService class BambooService < CiService
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require "addressable/uri" require "addressable/uri"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class BuildsEmailService < Service class BuildsEmailService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class CampfireService < Service class CampfireService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
# Base class for CI services # Base class for CI services
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class CustomIssueTrackerService < IssueTrackerService class CustomIssueTrackerService < IssueTrackerService
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class DroneCiService < CiService class DroneCiService < CiService
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class EmailsOnPushService < Service class EmailsOnPushService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class ExternalWikiService < Service class ExternalWikiService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require "flowdock-git-hook" require "flowdock-git-hook"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require "gemnasium/gitlab_service" require "gemnasium/gitlab_service"
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed # TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class GitlabIssueTrackerService < IssueTrackerService class GitlabIssueTrackerService < IssueTrackerService
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class HipchatService < Service class HipchatService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require 'uri' require 'uri'
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class IssueTrackerService < Service class IssueTrackerService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class JiraService < IssueTrackerService class JiraService < IssueTrackerService
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class PivotaltrackerService < Service class PivotaltrackerService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class PushoverService < Service class PushoverService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class RedmineService < IssueTrackerService class RedmineService < IssueTrackerService
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class SlackService < Service class SlackService < Service
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
class TeamcityService < CiService class TeamcityService < CiService
......
...@@ -92,9 +92,12 @@ class Repository ...@@ -92,9 +92,12 @@ class Repository
commits commits
end end
def find_commits_by_message(query) def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0)
ref ||= root_ref
# Limited to 1000 commits for now, could be parameterized? # Limited to 1000 commits for now, could be parameterized?
args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query}) args = %W(#{Gitlab.config.git.bin_path} log #{ref} --pretty=%H --skip #{offset} --max-count #{limit} --grep=#{query})
args = args.concat(%W(-- #{path})) if path.present?
git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
commits = git_log_results.map { |c| commit(c) } commits = git_log_results.map { |c| commit(c) }
...@@ -175,7 +178,7 @@ class Repository ...@@ -175,7 +178,7 @@ class Repository
def size def size
cache.fetch(:size) { raw_repository.size } cache.fetch(:size) { raw_repository.size }
end end
def diverging_commit_counts(branch) def diverging_commit_counts(branch)
root_ref_hash = raw_repository.rev_parse_target(root_ref).oid root_ref_hash = raw_repository.rev_parse_target(root_ref).oid
cache.fetch(:"diverging_commit_counts_#{branch.name}") do cache.fetch(:"diverging_commit_counts_#{branch.name}") do
...@@ -183,7 +186,7 @@ class Repository ...@@ -183,7 +186,7 @@ class Repository
# than SHA-1 hashes # than SHA-1 hashes
number_commits_behind = commits_between(branch.target, root_ref_hash).size number_commits_behind = commits_between(branch.target, root_ref_hash).size
number_commits_ahead = commits_between(root_ref_hash, branch.target).size number_commits_ahead = commits_between(root_ref_hash, branch.target).size
{ behind: number_commits_behind, ahead: number_commits_ahead } { behind: number_commits_behind, ahead: number_commits_ahead }
end end
end end
...@@ -192,7 +195,7 @@ class Repository ...@@ -192,7 +195,7 @@ class Repository
%i(size branch_names tag_names commit_count %i(size branch_names tag_names commit_count
readme version contribution_guide changelog license) readme version contribution_guide changelog license)
end end
def branch_cache_keys def branch_cache_keys
branches.map do |branch| branches.map do |branch|
:"diverging_commit_counts_#{branch.name}" :"diverging_commit_counts_#{branch.name}"
...@@ -205,7 +208,7 @@ class Repository ...@@ -205,7 +208,7 @@ class Repository
send(key) send(key)
end end
end end
branches.each do |branch| branches.each do |branch|
unless cache.exist?(:"diverging_commit_counts_#{branch.name}") unless cache.exist?(:"diverging_commit_counts_#{branch.name}")
send(:diverging_commit_counts, branch) send(:diverging_commit_counts, branch)
...@@ -227,10 +230,10 @@ class Repository ...@@ -227,10 +230,10 @@ class Repository
cache_keys.each do |key| cache_keys.each do |key|
cache.expire(key) cache.expire(key)
end end
expire_branch_cache expire_branch_cache
end end
def expire_branch_cache def expire_branch_cache
branches.each do |branch| branches.each do |branch|
cache.expire(:"diverging_commit_counts_#{branch.name}") cache.expire(:"diverging_commit_counts_#{branch.name}")
...@@ -242,7 +245,7 @@ class Repository ...@@ -242,7 +245,7 @@ class Repository
cache.expire(key) cache.expire(key)
send(key) send(key)
end end
branches.each do |branch| branches.each do |branch|
cache.expire(:"diverging_commit_counts_#{branch.name}") cache.expire(:"diverging_commit_counts_#{branch.name}")
diverging_commit_counts(branch) diverging_commit_counts(branch)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
# To add new service you should build a class inherited from Service # To add new service you should build a class inherited from Service
......
...@@ -2,62 +2,63 @@ ...@@ -2,62 +2,63 @@
# #
# Table name: users # Table name: users
# #
# id :integer not null, primary key # id :integer not null, primary key
# email :string(255) default(""), not null # email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null # encrypted_password :string(255) default(""), not null
# reset_password_token :string(255) # reset_password_token :string(255)
# reset_password_sent_at :datetime # reset_password_sent_at :datetime
# remember_created_at :datetime # remember_created_at :datetime
# sign_in_count :integer default(0) # sign_in_count :integer default(0)
# current_sign_in_at :datetime # current_sign_in_at :datetime
# last_sign_in_at :datetime # last_sign_in_at :datetime
# current_sign_in_ip :string(255) # current_sign_in_ip :string(255)
# last_sign_in_ip :string(255) # last_sign_in_ip :string(255)
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# name :string(255) # name :string(255)
# admin :boolean default(FALSE), not null # admin :boolean default(FALSE), not null
# projects_limit :integer default(10) # projects_limit :integer default(10)
# skype :string(255) default(""), not null # skype :string(255) default(""), not null
# linkedin :string(255) default(""), not null # linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null # twitter :string(255) default(""), not null
# authentication_token :string(255) # authentication_token :string(255)
# theme_id :integer default(1), not null # theme_id :integer default(1), not null
# bio :string(255) # bio :string(255)
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# unlock_token :string(255) # username :string(255)
# username :string(255) # can_create_group :boolean default(TRUE), not null
# can_create_group :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null # state :string(255)
# state :string(255) # color_scheme_id :integer default(1), not null
# color_scheme_id :integer default(1), not null # notification_level :integer default(1), not null
# notification_level :integer default(1), not null # password_expires_at :datetime
# password_expires_at :datetime # created_by_id :integer
# created_by_id :integer # last_credential_check_at :datetime
# last_credential_check_at :datetime # avatar :string(255)
# avatar :string(255) # confirmation_token :string(255)
# confirmation_token :string(255) # confirmed_at :datetime
# confirmed_at :datetime # confirmation_sent_at :datetime
# confirmation_sent_at :datetime # unconfirmed_email :string(255)
# unconfirmed_email :string(255) # hide_no_ssh_key :boolean default(FALSE)
# hide_no_ssh_key :boolean default(FALSE) # website_url :string(255) default(""), not null
# website_url :string(255) default(""), not null # notification_email :string(255)
# notification_email :string(255) # hide_no_password :boolean default(FALSE)
# hide_no_password :boolean default(FALSE) # password_automatically_set :boolean default(FALSE)
# password_automatically_set :boolean default(FALSE) # location :string(255)
# location :string(255) # encrypted_otp_secret :string(255)
# encrypted_otp_secret :string(255) # encrypted_otp_secret_iv :string(255)
# encrypted_otp_secret_iv :string(255) # encrypted_otp_secret_salt :string(255)
# encrypted_otp_secret_salt :string(255) # otp_required_for_login :boolean default(FALSE), not null
# otp_required_for_login :boolean default(FALSE), not null # otp_backup_codes :text
# otp_backup_codes :text # public_email :string(255) default(""), not null
# public_email :string(255) default(""), not null # dashboard :integer default(0)
# dashboard :integer default(0) # project_view :integer default(0)
# project_view :integer default(0) # consumed_timestep :integer
# consumed_timestep :integer # layout :integer default(0)
# layout :integer default(0) # hide_project_limit :boolean default(FALSE)
# hide_project_limit :boolean default(FALSE) # unlock_token :string
# otp_grace_period_started_at :datetime
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
......
...@@ -41,7 +41,7 @@ class SystemNoteService ...@@ -41,7 +41,7 @@ class SystemNoteService
# #
# Returns the created Note object # Returns the created Note object
def self.change_assignee(noteable, project, author, assignee) def self.change_assignee(noteable, project, author, assignee)
body = assignee.nil? ? 'Assignee removed' : "Reassigned to @#{assignee.username}" body = assignee.nil? ? 'Assignee removed' : "Reassigned to #{assignee.to_reference}"
create_note(noteable: noteable, project: project, author: author, note: body) create_note(noteable: noteable, project: project, author: author, note: body)
end end
...@@ -66,7 +66,7 @@ class SystemNoteService ...@@ -66,7 +66,7 @@ class SystemNoteService
def self.change_label(noteable, project, author, added_labels, removed_labels) def self.change_label(noteable, project, author, added_labels, removed_labels)
labels_count = added_labels.count + removed_labels.count labels_count = added_labels.count + removed_labels.count
references = ->(label) { "~#{label.id}" } references = ->(label) { label.to_reference(:id) }
added_labels = added_labels.map(&references).join(' ') added_labels = added_labels.map(&references).join(' ')
removed_labels = removed_labels.map(&references).join(' ') removed_labels = removed_labels.map(&references).join(' ')
...@@ -103,7 +103,7 @@ class SystemNoteService ...@@ -103,7 +103,7 @@ class SystemNoteService
# Returns the created Note object # Returns the created Note object
def self.change_milestone(noteable, project, author, milestone) def self.change_milestone(noteable, project, author, milestone)
body = 'Milestone ' body = 'Milestone '
body += milestone.nil? ? 'removed' : "changed to #{milestone.title}" body += milestone.nil? ? 'removed' : "changed to #{milestone.to_reference(project)}"
create_note(noteable: noteable, project: project, author: author, note: body) create_note(noteable: noteable, project: project, author: author, note: body)
end end
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
%li %li
%span.light Created on: %span.light Created on:
%strong %strong
= @group.created_at.stamp("March 1, 1999") = @group.created_at.to_s(:medium)
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
%li %li
%span.light Created on: %span.light Created on:
%strong %strong
= @project.created_at.stamp("March 1, 1999") = @project.created_at.to_s(:medium)
%li %li
%span.light http: %span.light http:
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%ul.well-list %ul.well-list
%li %li
%span.light Member since %span.light Member since
%strong= user.created_at.stamp("Aug 21, 2011") %strong= user.created_at.to_s(:medium)
- unless user.public_email.blank? - unless user.public_email.blank?
%li %li
%span.light E-mail: %span.light E-mail:
......
...@@ -58,12 +58,12 @@ ...@@ -58,12 +58,12 @@
%li %li
%span.light Member since: %span.light Member since:
%strong %strong
= @user.created_at.stamp("Nov 12, 2031") = @user.created_at.to_s(:medium)
- if @user.confirmed_at - if @user.confirmed_at
%li %li
%span.light Confirmed at: %span.light Confirmed at:
%strong %strong
= @user.confirmed_at.stamp("Nov 12, 2031") = @user.confirmed_at.to_s(:medium)
- else - else
%li %li
%span.light Confirmed: %span.light Confirmed:
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
%span.light Current sign-in at: %span.light Current sign-in at:
%strong %strong
- if @user.current_sign_in_at - if @user.current_sign_in_at
= @user.current_sign_in_at.stamp("Nov 12, 2031") = @user.current_sign_in_at.to_s(:medium)
- else - else
never never
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
%span.light Last sign-in at: %span.light Last sign-in at:
%strong %strong
- if @user.last_sign_in_at - if @user.last_sign_in_at
= @user.last_sign_in_at.stamp("Nov 12, 2031") = @user.last_sign_in_at.to_s(:medium)
- else - else
never never
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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(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.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url 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| @issues.each do |issue|
issue_to_atom(xml, issue) issue_to_atom(xml, issue)
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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(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.link href: dashboard_projects_url, rel: "alternate", type: "text/html"
xml.id dashboard_projects_url 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| @events.each do |event|
event_to_atom(xml, event) event_to_atom(xml, event)
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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(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.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url 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| @issues.each do |issue|
issue_to_atom(xml, issue) issue_to_atom(xml, issue)
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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, 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.link href: group_url(@group), rel: "alternate", type: "text/html"
xml.id group_url(@group) 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| @events.each do |event|
event_to_atom(xml, event) event_to_atom(xml, event)
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
%strong #{link_to(commit.short_id, namespace_project_commit_url(@message.project_namespace, @message.project, commit))} %strong #{link_to(commit.short_id, namespace_project_commit_url(@message.project_namespace, @message.project, commit))}
%div %div
%span by #{commit.author_name} %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 %pre.commit-message
= commit.safe_message = commit.safe_message
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
\ \
= @message.reverse_compare? ? "Deleted commits:" : "Commits:" = @message.reverse_compare? ? "Deleted commits:" : "Commits:"
- @message.commits.each do |commit| - @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} #{commit.safe_message}
\- - - - - \- - - - -
\ \
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
%strong= @key.title %strong= @key.title
%li %li
%span.light Created on: %span.light Created on:
%strong= @key.created_at.stamp("Aug 21, 2011") %strong= @key.created_at.to_s(:medium)
.col-md-8 .col-md-8
%p %p
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.col-md-2.hidden-xs.hidden-sm .col-md-2.hidden-xs.hidden-sm
%h5.commits-row-date %h5.commits-row-date
%i.fa.fa-calendar %i.fa.fa-calendar
%span= day.stamp("28 Aug, 2010") %span= day.strftime('%d %b, %Y')
.light .light
= pluralize(commits.count, 'commit') = pluralize(commits.count, 'commit')
.col-md-10.col-sm-12 .col-md-10.col-sm-12
......
...@@ -4,14 +4,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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, 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.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.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| @commits.each do |commit|
xml.entry do xml.entry do
xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id) 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.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
xml.title truncate(commit.title, length: 80) 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.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
xml.author do |author| xml.author do |author|
xml.name commit.author_name xml.name commit.author_name
......
...@@ -10,26 +10,30 @@ ...@@ -10,26 +10,30 @@
.tree-ref-holder .tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits' = render 'shared/ref_switcher', destination: 'commits'
.commits-feed-holder.hidden-xs.hidden-sm .block-controls.hidden-xs.hidden-sm
- if create_mr_button?(@repository.root_ref, @ref) - if create_mr_button?(@repository.root_ref, @ref)
= link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do .control
= icon('plus') = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
Create Merge Request = icon('plus')
Create Merge Request
.control
= form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'pull-left commits-search-form') do
= search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false }
- if current_user && current_user.private_token - if current_user && current_user.private_token
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do .control
= icon("rss") = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'btn' do
= icon("rss")
%ul.breadcrumb.repo-breadcrumb %ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs = commits_breadcrumbs
%div{id: dom_id(@project)} %div{id: dom_id(@project)}
#commits-list= render "commits", project: @project #commits-list.content_list= render "commits", project: @project
.clear .clear
= spinner = spinner
- if @commits.count == @limit :javascript
:javascript CommitsList.init("#{@ref}", #{@limit});
CommitsList.init("#{@ref}", #{@limit});
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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, 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.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_issues_url(@project.namespace, @project) 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| @issues.each do |issue|
issue_to_atom(xml, issue) issue_to_atom(xml, issue)
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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, 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.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_url(@project.namespace, @project) 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| @events.each do |event|
event_to_atom(xml, event) event_to_atom(xml, event)
......
...@@ -54,14 +54,6 @@ ...@@ -54,14 +54,6 @@
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name, = 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" } { 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) = render "shared/issuable/participants", participants: issuable.participants(current_user)
- if current_user - if current_user
...@@ -77,7 +69,16 @@ ...@@ -77,7 +69,16 @@
You're not receiving notifications from this thread. You're not receiving notifications from this thread.
.subscribed{class: ( 'hidden' unless subscribed )} .subscribed{class: ( 'hidden' unless subscribed )}
You're receiving notifications because you're subscribed to this thread. 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
References:
%a{href: '#', title:project_ref}
= project_ref
= clipboard_button(clipboard_target: 'span#cross-project-reference')
:javascript :javascript
new Subscription("#{toggle_subscription_path(issuable)}"); new Subscription("#{toggle_subscription_path(issuable)}");
new IssuableContext(); new IssuableContext();
\ No newline at end of file
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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, :atom), rel: "self", type: "application/atom+xml"
xml.link href: user_url(@user), rel: "alternate", type: "text/html" xml.link href: user_url(@user), rel: "alternate", type: "text/html"
xml.id user_url(@user) 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| @events.each do |event|
event_to_atom(xml, event) event_to_atom(xml, event)
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
%span %span
#{@user.bio}. #{@user.bio}.
%span %span
Member since #{@user.created_at.stamp("Aug 21, 2011")} Member since #{@user.created_at.to_s(:medium)}
.cover-desc .cover-desc
- unless @user.public_email.blank? - unless @user.public_email.blank?
......
# :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'
# Project Services # 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 ## Services
- Assembla | Service | Description |
- [Atlassian Bamboo CI](bamboo.md) An Atlassian product for continuous integration. | ------- | ----------- |
- Build box | Asana | Asana - Teamwork without email |
- Campfire | Assembla | Project Management Software (Source Commits Endpoint) |
- Emails on push | [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server |
- Flowdock | Buildkite | Continuous integration and deployments |
- Gemnasium | Builds emails | Email the builds status to a list of recipients |
- GitLab CI | Campfire | Simple web-based real-time group chat |
- [HipChat](hipchat.md) An Atlassian product for private group chat and instant messaging. | Custom Issue Tracker | Custom issue tracker |
- [Irker](irker.md) An IRC gateway to receive messages on repository updates. | Drone CI | Continuous Integration platform built on Docker, written in Go |
- Pivotal Tracker | Emails on push | Email the commits and diff of each push to a list of recipients |
- Pushover | External Wiki | Replaces the link to the internal wiki with a link to an external wiki |
- Slack | Flowdock | Flowdock is a collaboration web app for technical teams |
- TeamCity | 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 issue tracker |
| Slack | A team communication tool for the 21st century |
...@@ -55,3 +55,8 @@ Feature: Project Commits ...@@ -55,3 +55,8 @@ Feature: Project Commits
Scenario: I browse a commit with an image Scenario: I browse a commit with an image
Given I visit a commit with an image that changed Given I visit a commit with an image that changed
Then The diff links to both the previous and current image Then The diff links to both the previous and current image
@javascript
Scenario: I filter commits by message
When I search "submodules" commits
Then I should see only "submodules" commits
...@@ -28,7 +28,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps ...@@ -28,7 +28,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps
end end
step 'I should see group milestone with descriptions and expiry date' do 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 end
step 'I should see group milestone with all issues and MRs assigned to that milestone' do step 'I should see group milestone with all issues and MRs assigned to that milestone' do
......
...@@ -124,4 +124,13 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps ...@@ -124,4 +124,13 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
expect(page).to have_content "build: pending" expect(page).to have_content "build: pending"
expect(page).to have_content "1 build" expect(page).to have_content "1 build"
end end
step 'I search "submodules" commits' do
fill_in 'commits-search', with: 'submodules'
end
step 'I should see only "submodules" commits' do
expect(page).to have_content "More submodules"
expect(page).not_to have_content "Change some files"
end
end end
...@@ -70,27 +70,31 @@ module Banzai ...@@ -70,27 +70,31 @@ module Banzai
end end
def call def call
# `#123` if object_class.reference_pattern
replace_text_nodes_matching(object_class.reference_pattern) do |content| # `#123`
object_link_filter(content, object_class.reference_pattern) replace_text_nodes_matching(object_class.reference_pattern) do |content|
end object_link_filter(content, object_class.reference_pattern)
end
# `[Issue](#123)`, which is turned into # `[Issue](#123)`, which is turned into
# `<a href="#123">Issue</a>` # `<a href="#123">Issue</a>`
replace_link_nodes_with_href(object_class.reference_pattern) do |link, text| replace_link_nodes_with_href(object_class.reference_pattern) do |link, text|
object_link_filter(link, object_class.reference_pattern, link_text: text) object_link_filter(link, object_class.reference_pattern, link_text: text)
end
end end
# `http://gitlab.example.com/namespace/project/issues/123`, which is turned into if object_class.link_reference_pattern
# `<a href="http://gitlab.example.com/namespace/project/issues/123">http://gitlab.example.com/namespace/project/issues/123</a>` # `http://gitlab.example.com/namespace/project/issues/123`, which is turned into
replace_link_nodes_with_text(object_class.link_reference_pattern) do |text| # `<a href="http://gitlab.example.com/namespace/project/issues/123">http://gitlab.example.com/namespace/project/issues/123</a>`
object_link_filter(text, object_class.link_reference_pattern) replace_link_nodes_with_text(object_class.link_reference_pattern) do |text|
end object_link_filter(text, object_class.link_reference_pattern)
end
# `[Issue](http://gitlab.example.com/namespace/project/issues/123)`, which is turned into # `[Issue](http://gitlab.example.com/namespace/project/issues/123)`, which is turned into
# `<a href="http://gitlab.example.com/namespace/project/issues/123">Issue</a>` # `<a href="http://gitlab.example.com/namespace/project/issues/123">Issue</a>`
replace_link_nodes_with_href(object_class.link_reference_pattern) do |link, text| replace_link_nodes_with_href(object_class.link_reference_pattern) do |link, text|
object_link_filter(link, object_class.link_reference_pattern, link_text: text) object_link_filter(link, object_class.link_reference_pattern, link_text: text)
end
end end
end end
......
require 'banzai'
module Banzai
module Filter
# HTML filter that replaces milestone references with links.
class MilestoneReferenceFilter < AbstractReferenceFilter
def self.object_class
Milestone
end
def find_object(project, id)
project.milestones.find_by(iid: id)
end
def url_for_object(issue, project)
h = Gitlab::Application.routes.url_helpers
h.namespace_project_milestone_url(project.namespace, project, milestone,
only_path: context[:only_path])
end
end
end
end
...@@ -12,13 +12,18 @@ module Banzai ...@@ -12,13 +12,18 @@ module Banzai
# #
# See https://github.com/github/task_list/pull/60 # See https://github.com/github/task_list/pull/60
class TaskListFilter < TaskList::Filter class TaskListFilter < TaskList::Filter
def add_css_class(node, *new_class_names) def add_css_class_with_fix(node, *new_class_names)
if new_class_names.include?('task-list') if new_class_names.include?('task-list')
super if node.children.any? { |c| c['class'] == 'task-list-item' } # Don't add class to all lists
else return
super elsif new_class_names.include?('task-list-item')
add_css_class_without_fix(node.parent, 'task-list')
end end
add_css_class_without_fix(node, *new_class_names)
end end
alias_method_chain :add_css_class, :fix
end end
end end
end end
...@@ -22,6 +22,7 @@ module Banzai ...@@ -22,6 +22,7 @@ module Banzai
Filter::CommitRangeReferenceFilter, Filter::CommitRangeReferenceFilter,
Filter::CommitReferenceFilter, Filter::CommitReferenceFilter,
Filter::LabelReferenceFilter, Filter::LabelReferenceFilter,
Filter::MilestoneReferenceFilter,
Filter::TaskListFilter Filter::TaskListFilter
] ]
......
...@@ -32,8 +32,8 @@ module Gitlab ...@@ -32,8 +32,8 @@ module Gitlab
def transaction_from_env(env) def transaction_from_env(env)
trans = Transaction.new trans = Transaction.new
trans.add_tag(:request_method, env['REQUEST_METHOD']) trans.set(:request_uri, env['REQUEST_URI'])
trans.add_tag(:request_uri, env['REQUEST_URI']) trans.set(:request_method, env['REQUEST_METHOD'])
trans trans
end end
......
...@@ -4,7 +4,7 @@ module Gitlab ...@@ -4,7 +4,7 @@ module Gitlab
class Transaction class Transaction
THREAD_KEY = :_gitlab_metrics_transaction THREAD_KEY = :_gitlab_metrics_transaction
attr_reader :uuid, :tags attr_reader :tags, :values
def self.current def self.current
Thread.current[THREAD_KEY] Thread.current[THREAD_KEY]
...@@ -12,7 +12,6 @@ module Gitlab ...@@ -12,7 +12,6 @@ module Gitlab
def initialize def initialize
@metrics = [] @metrics = []
@uuid = SecureRandom.uuid
@started_at = nil @started_at = nil
@finished_at = nil @finished_at = nil
...@@ -38,7 +37,6 @@ module Gitlab ...@@ -38,7 +37,6 @@ module Gitlab
end end
def add_metric(series, values, tags = {}) def add_metric(series, values, tags = {})
tags = tags.merge(transaction_id: @uuid)
prefix = sidekiq? ? 'sidekiq_' : 'rails_' prefix = sidekiq? ? 'sidekiq_' : 'rails_'
@metrics << Metric.new("#{prefix}#{series}", values, tags) @metrics << Metric.new("#{prefix}#{series}", values, tags)
...@@ -48,6 +46,10 @@ module Gitlab ...@@ -48,6 +46,10 @@ module Gitlab
@values[name] += value @values[name] += value
end end
def set(name, value)
@values[name] = value
end
def add_tag(key, value) def add_tag(key, value)
@tags[key] = value @tags[key] = value
end end
......
...@@ -19,7 +19,7 @@ module Gitlab ...@@ -19,7 +19,7 @@ module Gitlab
super(text, context.merge(project: project)) super(text, context.merge(project: project))
end end
%i(user label merge_request snippet commit commit_range).each do |type| %i(user label milestone merge_request snippet commit commit_range).each do |type|
define_method("#{type}s") do define_method("#{type}s") do
@references[type] ||= references(type, reference_context) @references[type] ||= references(type, reference_context)
end end
......
...@@ -2,25 +2,28 @@ ...@@ -2,25 +2,28 @@
# #
# Table name: merge_requests # Table name: merge_requests
# #
# id :integer not null, primary key # id :integer not null, primary key
# target_branch :string(255) not null # target_branch :string(255) not null
# source_branch :string(255) not null # source_branch :string(255) not null
# source_project_id :integer not null # source_project_id :integer not null
# author_id :integer # author_id :integer
# assignee_id :integer # assignee_id :integer
# title :string(255) # title :string(255)
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# milestone_id :integer # milestone_id :integer
# state :string(255) # state :string(255)
# merge_status :string(255) # merge_status :string(255)
# target_project_id :integer not null # target_project_id :integer not null
# iid :integer # iid :integer
# description :text # description :text
# position :integer default(0) # position :integer default(0)
# locked_at :datetime # locked_at :datetime
# updated_by_id :integer # updated_by_id :integer
# merge_error :string(255) # merge_error :string(255)
# merge_params :text
# merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer
# #
FactoryGirl.define do FactoryGirl.define do
......
...@@ -29,6 +29,13 @@ ...@@ -29,6 +29,13 @@
# import_source :string(255) # import_source :string(255)
# commit_count :integer default(0) # commit_count :integer default(0)
# import_error :text # import_error :text
# ci_id :integer
# builds_enabled :boolean default(TRUE), not null
# shared_runners_enabled :boolean default(TRUE), not null
# runners_token :string
# build_coverage_regex :string
# build_allow_git_fetch :boolean default(TRUE), not null
# build_timeout :integer default(3600), not null
# #
FactoryGirl.define do FactoryGirl.define do
......
...@@ -212,6 +212,7 @@ describe 'GitLab Markdown', feature: true do ...@@ -212,6 +212,7 @@ describe 'GitLab Markdown', feature: true do
expect(doc).to reference_commit_ranges expect(doc).to reference_commit_ranges
expect(doc).to reference_commits expect(doc).to reference_commits
expect(doc).to reference_labels expect(doc).to reference_labels
expect(doc).to reference_milestones
end end
end end
......
...@@ -214,6 +214,13 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e ...@@ -214,6 +214,13 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Ignored in links: [Link to <%= simple_label.to_reference %>](#label-link) - Ignored in links: [Link to <%= simple_label.to_reference %>](#label-link)
- Link to label by reference: [Label](<%= label.to_reference %>) - Link to label by reference: [Label](<%= label.to_reference %>)
#### MilestoneReferenceFilter
- Milestone: <%= milestone.to_reference %>
- Milestone in another project: <%= xmilestone.to_reference(project) %>
- Ignored in code: `<%= milestone.to_reference %>`
- Link to milestone by URL: [Milestone](<%= urls.namespace_project_milestone_url(milestone.project.namespace, milestone.project, milestone) %>)
### Task Lists ### Task Lists
- [ ] Incomplete task 1 - [ ] Incomplete task 1
......
...@@ -240,7 +240,7 @@ describe ApplicationHelper do ...@@ -240,7 +240,7 @@ describe ApplicationHelper do
describe 'time_ago_with_tooltip' do describe 'time_ago_with_tooltip' do
def element(*arguments) def element(*arguments)
Time.zone = 'UTC' 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) element = helper.time_ago_with_tooltip(time, *arguments)
Nokogiri::HTML::DocumentFragment.parse(element).first_element_child Nokogiri::HTML::DocumentFragment.parse(element).first_element_child
...@@ -251,15 +251,15 @@ describe ApplicationHelper do ...@@ -251,15 +251,15 @@ describe ApplicationHelper do
end end
it 'includes the date string' do 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 end
it 'has a datetime attribute' do 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 end
it 'has a formatted title attribute' do 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 end
it 'includes a default js-timeago class' do it 'includes a default js-timeago class' do
......
...@@ -26,10 +26,10 @@ describe 'reopen/close issue', -> ...@@ -26,10 +26,10 @@ describe 'reopen/close issue', ->
fixture.load('issues_show.html') fixture.load('issues_show.html')
@issue = new Issue() @issue = new Issue()
it 'closes an issue', -> it 'closes an issue', ->
$.ajax = (obj) -> spyOn(jQuery, 'ajax').and.callFake (req) ->
expect(obj.type).toBe('PUT') expect(req.type).toBe('PUT')
expect(obj.url).toBe('http://gitlab.com/issues/6/close') expect(req.url).toBe('http://gitlab.com/issues/6/close')
obj.success saved: true req.success saved: true
$btnClose = $('a.btn-close') $btnClose = $('a.btn-close')
$btnReopen = $('a.btn-reopen') $btnReopen = $('a.btn-reopen')
...@@ -46,10 +46,10 @@ describe 'reopen/close issue', -> ...@@ -46,10 +46,10 @@ describe 'reopen/close issue', ->
it 'fails to closes an issue with success:false', -> it 'fails to closes an issue with success:false', ->
$.ajax = (obj) -> spyOn(jQuery, 'ajax').and.callFake (req) ->
expect(obj.type).toBe('PUT') expect(req.type).toBe('PUT')
expect(obj.url).toBe('http://goesnowhere.nothing/whereami') expect(req.url).toBe('http://goesnowhere.nothing/whereami')
obj.success saved: false req.success saved: false
$btnClose = $('a.btn-close') $btnClose = $('a.btn-close')
$btnReopen = $('a.btn-reopen') $btnReopen = $('a.btn-reopen')
...@@ -69,10 +69,10 @@ describe 'reopen/close issue', -> ...@@ -69,10 +69,10 @@ describe 'reopen/close issue', ->
it 'fails to closes an issue with HTTP error', -> it 'fails to closes an issue with HTTP error', ->
$.ajax = (obj) -> spyOn(jQuery, 'ajax').and.callFake (req) ->
expect(obj.type).toBe('PUT') expect(req.type).toBe('PUT')
expect(obj.url).toBe('http://goesnowhere.nothing/whereami') expect(req.url).toBe('http://goesnowhere.nothing/whereami')
obj.error() req.error()
$btnClose = $('a.btn-close') $btnClose = $('a.btn-close')
$btnReopen = $('a.btn-reopen') $btnReopen = $('a.btn-reopen')
...@@ -91,10 +91,10 @@ describe 'reopen/close issue', -> ...@@ -91,10 +91,10 @@ describe 'reopen/close issue', ->
expect($('div.flash-alert').text()).toBe('Unable to update this issue at this time.') expect($('div.flash-alert').text()).toBe('Unable to update this issue at this time.')
it 'reopens an issue', -> it 'reopens an issue', ->
$.ajax = (obj) -> spyOn(jQuery, 'ajax').and.callFake (req) ->
expect(obj.type).toBe('PUT') expect(req.type).toBe('PUT')
expect(obj.url).toBe('http://gitlab.com/issues/6/reopen') expect(req.url).toBe('http://gitlab.com/issues/6/reopen')
obj.success saved: true req.success saved: true
$btnClose = $('a.btn-close') $btnClose = $('a.btn-close')
$btnReopen = $('a.btn-reopen') $btnReopen = $('a.btn-reopen')
......
require 'spec_helper'
describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
include FilterSpecHelper
let(:project) { create(:project, :public) }
let(:milestone) { create(:milestone, project: project) }
it 'requires project context' do
expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
end
%w(pre code a style).each do |elem|
it "ignores valid references contained inside '#{elem}' element" do
exp = act = "<#{elem}>milestone #{milestone.to_reference}</#{elem}>"
expect(reference_filter(act).to_html).to eq exp
end
end
context 'internal reference' do
# Convert the Markdown link to only the URL, since these tests aren't run through the regular Markdown pipeline.
# Milestone reference behavior in the full Markdown pipeline is tested elsewhere.
let(:reference) { milestone.to_reference.gsub(/\[([^\]]+)\]\(([^)]+)\)/, '\2') }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls.
namespace_project_milestone_url(project.namespace, project, milestone)
end
it 'links with adjacent text' do
doc = reference_filter("milestone (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(milestone.title)}<\/a>\.\)/)
end
it 'includes a title attribute' do
doc = reference_filter("milestone #{reference}")
expect(doc.css('a').first.attr('title')).to eq "Milestone: #{milestone.title}"
end
it 'escapes the title attribute' do
milestone.update_attribute(:title, %{"></a>whatever<a title="})
doc = reference_filter("milestone #{reference}")
expect(doc.text).to eq "milestone #{milestone.title}"
end
it 'includes default classes' do
doc = reference_filter("milestone #{reference}")
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone'
end
it 'includes a data-project attribute' do
doc = reference_filter("milestone #{reference}")
link = doc.css('a').first
expect(link).to have_attribute('data-project')
expect(link.attr('data-project')).to eq project.id.to_s
end
it 'includes a data-milestone attribute' do
doc = reference_filter("See #{reference}")
link = doc.css('a').first
expect(link).to have_attribute('data-milestone')
expect(link.attr('data-milestone')).to eq milestone.id.to_s
end
it 'adds to the results hash' do
result = reference_pipeline_result("milestone #{reference}")
expect(result[:references][:milestone]).to eq [milestone]
end
end
end
...@@ -40,9 +40,9 @@ describe Gitlab::Metrics::RackMiddleware do ...@@ -40,9 +40,9 @@ describe Gitlab::Metrics::RackMiddleware do
expect(transaction).to be_an_instance_of(Gitlab::Metrics::Transaction) expect(transaction).to be_an_instance_of(Gitlab::Metrics::Transaction)
end end
it 'tags the transaction with the request method and URI' do it 'stores the request method and URI in the transaction as values' do
expect(transaction.tags[:request_method]).to eq('GET') expect(transaction.values[:request_method]).to eq('GET')
expect(transaction.tags[:request_uri]).to eq('/foo') expect(transaction.values[:request_uri]).to eq('/foo')
end end
end end
......
...@@ -30,9 +30,9 @@ describe Gitlab::Metrics::Transaction do ...@@ -30,9 +30,9 @@ describe Gitlab::Metrics::Transaction do
end end
describe '#add_metric' do describe '#add_metric' do
it 'adds a metric tagged with the transaction UUID' do it 'adds a metric to the transaction' do
expect(Gitlab::Metrics::Metric).to receive(:new). expect(Gitlab::Metrics::Metric).to receive(:new).
with('rails_foo', { number: 10 }, { transaction_id: transaction.uuid }) with('rails_foo', { number: 10 }, {})
transaction.add_metric('foo', number: 10) transaction.add_metric('foo', number: 10)
end end
...@@ -50,6 +50,17 @@ describe Gitlab::Metrics::Transaction do ...@@ -50,6 +50,17 @@ describe Gitlab::Metrics::Transaction do
end end
end end
describe '#set' do
it 'sets a value' do
transaction.set(:number, 10)
expect(transaction).to receive(:add_metric).
with('transactions', { duration: 0.0, number: 10 }, {})
transaction.track_self
end
end
describe '#add_tag' do describe '#add_tag' do
it 'adds a tag' do it 'adds a tag' do
transaction.add_tag(:foo, 'bar') transaction.add_tag(:foo, 'bar')
......
...@@ -2,32 +2,45 @@ ...@@ -2,32 +2,45 @@
# #
# Table name: application_settings # Table name: application_settings
# #
# id :integer not null, primary key # id :integer not null, primary key
# default_projects_limit :integer # default_projects_limit :integer
# signup_enabled :boolean # signup_enabled :boolean
# signin_enabled :boolean # signin_enabled :boolean
# gravatar_enabled :boolean # gravatar_enabled :boolean
# sign_in_text :text # sign_in_text :text
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# home_page_url :string(255) # home_page_url :string(255)
# default_branch_protection :integer default(2) # default_branch_protection :integer default(2)
# twitter_sharing_enabled :boolean default(TRUE) # twitter_sharing_enabled :boolean default(TRUE)
# restricted_visibility_levels :text # restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE) # version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null # max_attachment_size :integer default(10), not null
# default_project_visibility :integer # default_project_visibility :integer
# default_snippet_visibility :integer # default_snippet_visibility :integer
# restricted_signup_domains :text # restricted_signup_domains :text
# user_oauth_applications :boolean default(TRUE) # user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255) # after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null # session_expire_delay :integer default(10080), not null
# import_sources :text # import_sources :text
# help_page_text :text # help_page_text :text
# admin_notification_email :string(255) # admin_notification_email :string(255)
# shared_runners_enabled :boolean default(TRUE), not null # shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null # max_artifacts_size :integer default(100), not null
# runners_registration_token :string(255) # runners_registration_token :string
# require_two_factor_authentication :boolean default(FALSE)
# two_factor_grace_period :integer default(48)
# metrics_enabled :boolean default(FALSE)
# metrics_host :string default("localhost")
# metrics_username :string
# metrics_password :string
# metrics_pool_size :integer default(16)
# metrics_timeout :integer default(10)
# metrics_method_call_threshold :integer default(10)
# recaptcha_enabled :boolean default(FALSE)
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
# tag :boolean default(FALSE) # tag :boolean default(FALSE)
# yaml_errors :text # yaml_errors :text
# committed_at :datetime # committed_at :datetime
# project_id :integer # gl_project_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
# #
# Table name: ci_runner_projects # Table name: ci_runner_projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# runner_id :integer not null # runner_id :integer not null
# project_id :integer not null # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# gl_project_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
# #
# Table name: ci_triggers # Table name: ci_triggers
# #
# id :integer not null, primary key # id :integer not null, primary key
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer
# deleted_at :datetime # deleted_at :datetime
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# gl_project_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
# Table name: ci_variables # Table name: ci_variables
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer not null # project_id :integer
# key :string(255) # key :string(255)
# value :text # value :text
# encrypted_value :text # encrypted_value :text
# encrypted_value_salt :string(255) # encrypted_value_salt :string(255)
# encrypted_value_iv :string(255) # encrypted_value_iv :string(255)
# gl_project_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
# target_url :string(255) # target_url :string(255)
# description :string(255) # description :string(255)
# artifacts_file :text # artifacts_file :text
# gl_project_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
# target_url :string(255) # target_url :string(255)
# description :string(255) # description :string(255)
# artifacts_file :text # artifacts_file :text
# gl_project_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
# public :boolean default(FALSE)
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -77,5 +77,17 @@ describe ProjectHook, models: true do ...@@ -77,5 +77,17 @@ describe ProjectHook, models: true do
expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error'])
end 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
end end
...@@ -2,25 +2,28 @@ ...@@ -2,25 +2,28 @@
# #
# Table name: merge_requests # Table name: merge_requests
# #
# id :integer not null, primary key # id :integer not null, primary key
# target_branch :string(255) not null # target_branch :string(255) not null
# source_branch :string(255) not null # source_branch :string(255) not null
# source_project_id :integer not null # source_project_id :integer not null
# author_id :integer # author_id :integer
# assignee_id :integer # assignee_id :integer
# title :string(255) # title :string(255)
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# milestone_id :integer # milestone_id :integer
# state :string(255) # state :string(255)
# merge_status :string(255) # merge_status :string(255)
# target_project_id :integer not null # target_project_id :integer not null
# iid :integer # iid :integer
# description :text # description :text
# position :integer default(0) # position :integer default(0)
# locked_at :datetime # locked_at :datetime
# updated_by_id :integer # updated_by_id :integer
# merge_error :string(255) # merge_error :string(255)
# merge_params :text
# merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
# public :boolean default(FALSE)
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -29,6 +29,13 @@ ...@@ -29,6 +29,13 @@
# import_source :string(255) # import_source :string(255)
# commit_count :integer default(0) # commit_count :integer default(0)
# import_error :text # import_error :text
# ci_id :integer
# builds_enabled :boolean default(TRUE), not null
# shared_runners_enabled :boolean default(TRUE), not null
# runners_token :string
# build_coverage_regex :string
# build_allow_git_fetch :boolean default(TRUE), not null
# build_timeout :integer default(3600), not null
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# merge_requests_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null # note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -2,62 +2,63 @@ ...@@ -2,62 +2,63 @@
# #
# Table name: users # Table name: users
# #
# id :integer not null, primary key # id :integer not null, primary key
# email :string(255) default(""), not null # email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null # encrypted_password :string(255) default(""), not null
# reset_password_token :string(255) # reset_password_token :string(255)
# reset_password_sent_at :datetime # reset_password_sent_at :datetime
# remember_created_at :datetime # remember_created_at :datetime
# sign_in_count :integer default(0) # sign_in_count :integer default(0)
# current_sign_in_at :datetime # current_sign_in_at :datetime
# last_sign_in_at :datetime # last_sign_in_at :datetime
# current_sign_in_ip :string(255) # current_sign_in_ip :string(255)
# last_sign_in_ip :string(255) # last_sign_in_ip :string(255)
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# name :string(255) # name :string(255)
# admin :boolean default(FALSE), not null # admin :boolean default(FALSE), not null
# projects_limit :integer default(10) # projects_limit :integer default(10)
# skype :string(255) default(""), not null # skype :string(255) default(""), not null
# linkedin :string(255) default(""), not null # linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null # twitter :string(255) default(""), not null
# authentication_token :string(255) # authentication_token :string(255)
# theme_id :integer default(1), not null # theme_id :integer default(1), not null
# bio :string(255) # bio :string(255)
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# unlock_token :string(255) # username :string(255)
# username :string(255) # can_create_group :boolean default(TRUE), not null
# can_create_group :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null # state :string(255)
# state :string(255) # color_scheme_id :integer default(1), not null
# color_scheme_id :integer default(1), not null # notification_level :integer default(1), not null
# notification_level :integer default(1), not null # password_expires_at :datetime
# password_expires_at :datetime # created_by_id :integer
# created_by_id :integer # last_credential_check_at :datetime
# last_credential_check_at :datetime # avatar :string(255)
# avatar :string(255) # confirmation_token :string(255)
# confirmation_token :string(255) # confirmed_at :datetime
# confirmed_at :datetime # confirmation_sent_at :datetime
# confirmation_sent_at :datetime # unconfirmed_email :string(255)
# unconfirmed_email :string(255) # hide_no_ssh_key :boolean default(FALSE)
# hide_no_ssh_key :boolean default(FALSE) # website_url :string(255) default(""), not null
# website_url :string(255) default(""), not null # notification_email :string(255)
# notification_email :string(255) # hide_no_password :boolean default(FALSE)
# hide_no_password :boolean default(FALSE) # password_automatically_set :boolean default(FALSE)
# password_automatically_set :boolean default(FALSE) # location :string(255)
# location :string(255) # encrypted_otp_secret :string(255)
# encrypted_otp_secret :string(255) # encrypted_otp_secret_iv :string(255)
# encrypted_otp_secret_iv :string(255) # encrypted_otp_secret_salt :string(255)
# encrypted_otp_secret_salt :string(255) # otp_required_for_login :boolean default(FALSE), not null
# otp_required_for_login :boolean default(FALSE), not null # otp_backup_codes :text
# otp_backup_codes :text # public_email :string(255) default(""), not null
# public_email :string(255) default(""), not null # dashboard :integer default(0)
# dashboard :integer default(0) # project_view :integer default(0)
# project_view :integer default(0) # consumed_timestep :integer
# consumed_timestep :integer # layout :integer default(0)
# layout :integer default(0) # hide_project_limit :boolean default(FALSE)
# hide_project_limit :boolean default(FALSE) # unlock_token :string
# otp_grace_period_started_at :datetime
# #
require 'spec_helper' require 'spec_helper'
......
...@@ -171,7 +171,7 @@ describe SystemNoteService, services: true do ...@@ -171,7 +171,7 @@ describe SystemNoteService, services: true do
context 'when milestone added' do context 'when milestone added' do
it 'sets the note text' do it 'sets the note text' do
expect(subject.note).to eq "Milestone changed to #{milestone.title}" expect(subject.note).to eq "Milestone changed to #{milestone.to_reference}"
end end
end end
......
...@@ -59,6 +59,10 @@ class MarkdownFeature ...@@ -59,6 +59,10 @@ class MarkdownFeature
@label ||= create(:label, name: 'awaiting feedback', project: project) @label ||= create(:label, name: 'awaiting feedback', project: project)
end end
def milestone
@milestone ||= create(:milestone, project: project)
end
# Cross-references ----------------------------------------------------------- # Cross-references -----------------------------------------------------------
def xproject def xproject
...@@ -93,6 +97,10 @@ class MarkdownFeature ...@@ -93,6 +97,10 @@ class MarkdownFeature
end end
end end
def xmilestone
@xmilestone ||= create(:milestone, project: xproject)
end
def urls def urls
Gitlab::Application.routes.url_helpers Gitlab::Application.routes.url_helpers
end end
......
...@@ -130,6 +130,15 @@ module MarkdownMatchers ...@@ -130,6 +130,15 @@ module MarkdownMatchers
end end
end end
# MilestoneReferenceFilter
matcher :reference_milestones do
set_default_markdown_messages
match do |actual|
expect(actual).to have_selector('a.gfm.gfm-milestone', count: 3)
end
end
# TaskListFilter # TaskListFilter
matcher :parse_task_lists do matcher :parse_task_lists do
set_default_markdown_messages set_default_markdown_messages
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment