Commit db25c170 authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge remote-tracking branch 'origin/master' into send-incremental-build-log

parents 74520f23 e3911a18
Please view this file on the master branch, on stable branches it's out of date.
v 8.8.0 (unreleased)
- Fix error when using link to uploads in global snippets
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
- Use a case-insensitive comparison in sanitizing URI schemes
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
- Improve multiple branch push performance by memoizing permission checking
- Log to application.log when an admin starts and stops impersonating a user
- Updated gitlab_git to 10.1.0
- GitAccess#protected_tag? no longer loads all tags just to check if a single one exists
......@@ -19,10 +23,13 @@ v 8.8.0 (unreleased)
- Update SVG sanitizer to conform to SVG 1.1
- Updated search UI
- Display informative message when new milestone is created
- Sanitize milestones and labels titles
- Support multi-line tag messages. !3833 (Calin Seciu)
- Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea)
- Added button to toggle whitespaces changes on diff view
- Backport GitHub Enterprise import support from EE
- Create tags using Rugged for performance reasons. !3745
- API: Expose Issue#user_notes_count. !3126 (Anton Popov)
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
- Added multiple colors for labels in dropdowns when dups happen.
......@@ -31,6 +38,11 @@ v 8.8.0 (unreleased)
- Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
- Expire repository exists? and has_visible_content? caches after a push if necessary
- Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi)
- Fix adding a todo for private group members (Ahmad Sherif)
v 8.7.4
- Fix always showing build notification message when switching between merge requests
- Links for Redmine issue references are generated correctly again (Benedikt Huss)
v 8.7.3
- Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented
......
......@@ -242,7 +242,6 @@ group :development do
gem "foreman"
gem 'brakeman', '~> 3.2.0', require: false
gem "annotate", "~> 2.7.0"
gem 'letter_opener_web', '~> 1.3.0'
gem 'quiet_assets', '~> 1.0.2'
gem 'rerun', '~> 0.11.0'
......
......@@ -51,9 +51,6 @@ GEM
activerecord (>= 3.0)
akismet (2.0.0)
allocations (1.0.4)
annotate (2.7.0)
activerecord (>= 3.2, < 6.0)
rake (~> 10.4)
arel (6.0.3)
asana (0.4.0)
faraday (~> 0.9)
......@@ -893,7 +890,6 @@ DEPENDENCIES
after_commit_queue
akismet (~> 2.0)
allocations (~> 1.0)
annotate (~> 2.7.0)
asana (~> 0.4.0)
asciidoctor (~> 1.5.2)
attr_encrypted (~> 1.3.4)
......@@ -1061,4 +1057,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.12.1
1.12.3
......@@ -35,11 +35,11 @@ There are two editions of GitLab:
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
- [Subscriptions](https://about.gitlab.com/subscription/)
- [Subscriptions](https://about.gitlab.com/pricing/)
- [Consultancy](https://about.gitlab.com/consultancy/)
- [Community](https://about.gitlab.com/community/)
- [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service
- [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations.
- [GitLab Enterprise Edition](https://about.gitlab.com/features/#enterprise) with additional features aimed at larger organizations.
- [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
## Requirements
......
......@@ -204,6 +204,7 @@ $ ->
$('.header-content .title').toggle()
$('.header-content .navbar-collapse').toggle()
$('.navbar-toggle').toggleClass('active')
$('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left")
# Show/hide comments on diff
$("body").on "click", ".js-toggle-diff-comments", (e) ->
......
# This is a manifest file that'll be compiled into application.js, which will include all the files
# listed below.
#
# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
#
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
# WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
# GO AFTER THE REQUIRES BELOW.
#
#= require pager
#= require jquery_nested_form
#= require_tree .
#
$(document).on 'click', '.edit-runner-link', (event) ->
event.preventDefault()
descr = $(this).closest('.runner-description').first()
descr.addClass('hide')
form = descr.next('.runner-description-form')
descrInput = form.find('input.description')
originalValue = descrInput.val()
form.removeClass('hide')
form.find('.cancel').on 'click', (event) ->
event.preventDefault()
form.addClass('hide')
descrInput.val(originalValue)
descr.removeClass('hide')
$(document).on 'click', '.assign-all-runner', ->
$(this).replaceWith('<i class="fa fa-refresh fa-spin"></i> Assign in progress..')
......
......@@ -9,11 +9,12 @@ class @MergeRequestWidget
constructor: (@opts) ->
$('#modal_merge_info').modal(show: false)
@firstCICheck = true
@readyForCICheck = true
@readyForCICheck = false
clearInterval @fetchBuildStatusInterval
@clearEventListeners()
@addEventListeners()
@getCIStatus(false)
@pollCIStatus()
notifyPermissions()
......@@ -71,7 +72,7 @@ class @MergeRequestWidget
if data.status is ''
return
if @firstCiCheck || data.status isnt @opts.ci_status and data.status?
if @firstCICheck || data.status isnt @opts.ci_status and data.status?
@opts.ci_status = data.status
@showCIStatus data.status
if data.coverage
......@@ -79,7 +80,7 @@ class @MergeRequestWidget
# The first check should only update the UI, a notification
# should only be displayed on status changes
if showNotification and not @firstCiCheck
if showNotification and not @firstCICheck
status = @ciLabelForStatus(data.status)
if status is "preparing"
......@@ -102,7 +103,7 @@ class @MergeRequestWidget
@close()
Turbolinks.visit _this.opts.builds_path
)
@firstCiCheck = false
@firstCICheck = false
showCIStatus: (state) ->
$('.ci_widget').hide()
......
......@@ -12,7 +12,7 @@ toggleSidebar = ->
niceScrollBars.updateScrollBar();
), 300
$(document).on("click", '.toggle-nav-collapse', (e) ->
$(document).on("click", '.toggle-nav-collapse, .side-nav-toggle', (e) ->
e.preventDefault()
toggleSidebar()
......
......@@ -24,6 +24,10 @@
background-color: $color-darker;
a {
color: #fff;
h3 {
color: #fff;
}
}
}
}
......
......@@ -8,7 +8,7 @@ header {
&.navbar-empty {
height: 58px;
background: #fff;
border-bottom: 1px solid #eee;
border-bottom: 1px solid $btn-gray-hover;
.center-logo {
margin: 11px 0;
......@@ -22,14 +22,18 @@ header {
}
&.navbar-gitlab {
padding: 0 20px;
padding: 0 16px;
z-index: 100;
margin-bottom: 0;
min-height: $header-height;
height: $header-height;
background-color: $background-color;
border: none;
border-bottom: 1px solid $border-color;
@media (max-width: $screen-xs-min) {
padding: 0 16px;
}
&.with-horizontal-nav {
border-bottom: none;
}
......@@ -60,16 +64,44 @@ header {
margin: 6px 0;
border-radius: 0;
position: absolute;
right: 2px;
right: -10px;
padding: 6px 10px;
&:hover {
background-color: #eee;
background-color: $btn-gray-hover;
}
&.active {
color: $gl-icon-color;
}
}
}
&.header-collapsed {
padding: 0 16px;
}
.side-nav-toggle {
display: none;
position: absolute;
left: -10px;
margin: 6px 0;
padding: 6px 10px;
border: none;
background-color: $background-color;
&:hover {
background-color: $btn-gray-hover;
}
&:focus {
outline: none;
}
@media (max-width: $screen-xs-min) {
display: block;
}
}
}
.header-content {
......@@ -77,6 +109,10 @@ header {
height: $header-height;
padding-right: 40px;
@media (max-width: $screen-xs-min) {
padding-left: 40px;
}
@media (min-width: $screen-sm-min) {
padding-right: 0;
}
......@@ -145,6 +181,10 @@ header {
@media (min-width: $screen-md-min) {
@include collapsed-header;
}
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
}
.header-expanded {
......@@ -153,6 +193,10 @@ header {
@media (min-width: $screen-md-min) {
margin-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
}
@media (max-width: $screen-xs-max) {
......
......@@ -201,9 +201,13 @@
border-bottom: 1px solid $border-color;
transition-duration: .3s;
.container-fluid {
position: relative;
}
.controls {
float: right;
padding: 7px 5px 0 0;
padding: 7px 0 0;
i {
color: $layout-link-gray;
......
......@@ -98,7 +98,7 @@
}
.sidebar-user {
padding: 9px 22px;
padding: 7px 22px;
position: fixed;
bottom: 40px;
width: $sidebar_width;
......@@ -210,15 +210,33 @@
}
}
.sidebar-wrapper {
&.hidden-nav {
width: 0;
}
}
.page-sidebar-collapsed {
padding-left: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-left: 0;
}
.sidebar-wrapper {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
.header-logo {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
a {
padding-left: ($sidebar_collapsed_width - 36) / 2;
......@@ -244,12 +262,22 @@
.collapse-nav a {
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
}
}
.sidebar-user {
padding-left: ($sidebar_collapsed_width - 36) / 2;
width: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
width: 0;
padding-left: 0;
padding-right: 0;
}
.username {
display: none;
}
......@@ -258,6 +286,10 @@
.layout-nav {
padding-right: $sidebar_collapsed_width;
@media (max-width: $screen-xs-min) {
padding-right: 0;;
}
}
}
......@@ -268,6 +300,10 @@
padding-left: $sidebar_width;
}
@media (max-width: $screen-xs-min) {
padding-left: 0;
}
.sidebar-wrapper {
width: $sidebar_width;
......@@ -287,7 +323,17 @@
}
.layout-nav {
padding-right: $sidebar_width;
@media (max-width: $screen-xs-min) {
padding-right: 0;;
}
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
padding-right: 62px;
}
@media (min-width: $screen-md-min) {
padding-right: $sidebar_width;
}
}
}
......
......@@ -215,6 +215,7 @@ $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color;
$btn-active-gray: #ececec;
$btn-placeholder-gray: #c7c7c7;
$btn-white-active: #848484;
$btn-gray-hover: #eee;
/*
* Award emoji
......
......@@ -218,7 +218,7 @@
.btn {
display: inline-block;
width: 48%;
width: 46%;
}
}
}
......
class Dashboard::LabelsController < Dashboard::ApplicationController
def index
labels = Label.where(project_id: projects).select(:title, :color).uniq(:title)
labels = Label.where(project_id: projects).select(:id, :title, :color).uniq(:title)
respond_to do |format|
format.json { render json: labels }
......
......@@ -205,7 +205,8 @@ module ProjectsHelper
end
def default_url_to_repo(project = @project)
if default_clone_protocol == "ssh"
case default_clone_protocol
when 'ssh'
project.ssh_url_to_repo
else
project.http_url_to_repo
......
# == Schema Information
#
# Table name: abuse_reports
#
# id :integer not null, primary key
# reporter_id :integer
# user_id :integer
# message :text
# created_at :datetime
# updated_at :datetime
#
class AbuseReport < ActiveRecord::Base
belongs_to :reporter, class_name: 'User'
belongs_to :user
......
# == Schema Information
#
# Table name: appearances
#
# id :integer not null, primary key
# title :string
# description :text
# header_logo :string
# logo :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Appearance < ActiveRecord::Base
validates :title, presence: true
validates :description, presence: true
......
# == Schema Information
#
# Table name: application_settings
#
# id :integer not null, primary key
# default_projects_limit :integer
# signup_enabled :boolean
# signin_enabled :boolean
# gravatar_enabled :boolean
# sign_in_text :text
# created_at :datetime
# updated_at :datetime
# home_page_url :string
# default_branch_protection :integer default(2)
# restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null
# default_project_visibility :integer
# default_snippet_visibility :integer
# restricted_signup_domains :text
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string
# session_expire_delay :integer default(10080), not null
# import_sources :text
# help_page_text :text
# admin_notification_email :string
# shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null
# 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_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)
# metrics_sample_interval :integer default(15)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
# akismet_enabled :boolean default(FALSE)
# akismet_api_key :string
# email_author_in_body :boolean default(FALSE)
# default_group_visibility :integer
# repository_checks_enabled :boolean default(FALSE)
# metrics_packet_size :integer default(1)
# shared_runners_text :text
#
class ApplicationSetting < ActiveRecord::Base
include TokenAuthenticatable
add_authentication_token_field :runners_registration_token
......
# == Schema Information
#
# Table name: audit_events
#
# id :integer not null, primary key
# author_id :integer not null
# type :string not null
# entity_id :integer not null
# entity_type :string not null
# details :text
# created_at :datetime
# updated_at :datetime
#
class AuditEvent < ActiveRecord::Base
serialize :details, Hash
......
# == Schema Information
#
# Table name: broadcast_messages
#
# id :integer not null, primary key
# message :text not null
# starts_at :datetime
# ends_at :datetime
# created_at :datetime
# updated_at :datetime
# color :string
# font :string
#
class BroadcastMessage < ActiveRecord::Base
include Sortable
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string
# user_id :integer
# type :string
# target_url :string
# description :string
# artifacts_file :text
# gl_project_id :integer
# artifacts_metadata :text
# erased_by_id :integer
# erased_at :datetime
#
module Ci
class Build < CommitStatus
belongs_to :runner, class_name: 'Ci::Runner'
......
# == Schema Information
#
# Table name: ci_commits
#
# id :integer not null, primary key
# project_id :integer
# ref :string
# sha :string
# before_sha :string
# push_data :text
# created_at :datetime
# updated_at :datetime
# tag :boolean default(FALSE)
# yaml_errors :text
# committed_at :datetime
# gl_project_id :integer
# status :string
# started_at :datetime
# finished_at :datetime
# duration :integer
#
module Ci
class Commit < ActiveRecord::Base
extend Ci::Model
......
# == Schema Information
#
# Table name: ci_runners
#
# id :integer not null, primary key
# token :string
# created_at :datetime
# updated_at :datetime
# description :string
# contacted_at :datetime
# active :boolean default(TRUE), not null
# is_shared :boolean default(FALSE)
# name :string
# version :string
# revision :string
# platform :string
# architecture :string
#
module Ci
class Runner < ActiveRecord::Base
extend Ci::Model
......
# == Schema Information
#
# Table name: ci_runner_projects
#
# id :integer not null, primary key
# runner_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# gl_project_id :integer
#
module Ci
class RunnerProject < ActiveRecord::Base
extend Ci::Model
......
# == Schema Information
#
# Table name: ci_triggers
#
# id :integer not null, primary key
# token :string
# project_id :integer
# deleted_at :datetime
# created_at :datetime
# updated_at :datetime
# gl_project_id :integer
#
module Ci
class Trigger < ActiveRecord::Base
extend Ci::Model
......
# == Schema Information
#
# Table name: ci_trigger_requests
#
# id :integer not null, primary key
# trigger_id :integer not null
# variables :text
# created_at :datetime
# updated_at :datetime
# commit_id :integer
#
module Ci
class TriggerRequest < ActiveRecord::Base
extend Ci::Model
......
# == Schema Information
#
# Table name: ci_variables
#
# id :integer not null, primary key
# project_id :integer
# key :string
# value :text
# encrypted_value :text
# encrypted_value_salt :string
# encrypted_value_iv :string
# gl_project_id :integer
#
module Ci
class Variable < ActiveRecord::Base
extend Ci::Model
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string
# user_id :integer
# type :string
# target_url :string
# description :string
# artifacts_file :text
# gl_project_id :integer
# artifacts_metadata :text
# erased_by_id :integer
# erased_at :datetime
#
class CommitStatus < ActiveRecord::Base
include Statuseable
......
......@@ -160,6 +160,10 @@ module Issuable
notes.awards.where(note: "thumbsup").count
end
def user_notes_count
notes.user.count
end
def subscribed_without_subscriptions?(user)
participants(user).include?(user)
end
......
......@@ -43,8 +43,8 @@ module Mentionable
self
end
def all_references(current_user = self.author, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user, self.author)
def all_references(current_user = nil, text = nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user || self.author, self.author)
if text
ext.analyze(text)
......
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string
# type :string
# fingerprint :string
# public :boolean default(FALSE), not null
#
class DeployKey < Key
has_many :deploy_keys_projects, dependent: :destroy
has_many :projects, through: :deploy_keys_projects
......
# == Schema Information
#
# Table name: deploy_keys_projects
#
# id :integer not null, primary key
# deploy_key_id :integer not null
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class DeployKeysProject < ActiveRecord::Base
belongs_to :project
belongs_to :deploy_key
......
# == Schema Information
#
# Table name: emails
#
# id :integer not null, primary key
# user_id :integer not null
# email :string not null
# created_at :datetime
# updated_at :datetime
#
class Email < ActiveRecord::Base
include Sortable
......
# == Schema Information
#
# Table name: events
#
# id :integer not null, primary key
# target_type :string
# target_id :integer
# title :string
# data :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
# action :integer
# author_id :integer
#
class Event < ActiveRecord::Base
include Sortable
default_scope { where.not(author_id: nil) }
......
# == Schema Information
#
# Table name: forked_project_links
#
# id :integer not null, primary key
# forked_to_project_id :integer not null
# forked_from_project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class ForkedProjectLink < ActiveRecord::Base
belongs_to :forked_to_project, class_name: Project
belongs_to :forked_from_project, class_name: Project
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string
# user_id :integer
# type :string
# target_url :string
# description :string
# artifacts_file :text
# gl_project_id :integer
# artifacts_metadata :text
# erased_by_id :integer
# erased_at :datetime
#
class GenericCommitStatus < CommitStatus
before_validation :set_default_values
......
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string not null
# path :string not null
# owner_id :integer
# created_at :datetime
# updated_at :datetime
# type :string
# description :string default(""), not null
# avatar :string
# share_with_group_lock :boolean default(FALSE)
# visibility_level :integer default(20), not null
#
require 'carrierwave/orm/activerecord'
class Group < Namespace
......
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# wiki_page_events :boolean default(FALSE), not null
# token :string
#
class ProjectHook < WebHook
belongs_to :project
......
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# wiki_page_events :boolean default(FALSE), not null
# token :string
#
class ServiceHook < WebHook
belongs_to :service
......
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# wiki_page_events :boolean default(FALSE), not null
# token :string
#
class SystemHook < WebHook
def async_execute(data, hook_name)
Sidekiq::Client.enqueue(SystemHookWorker, id, data, hook_name)
......
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(2000)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# type :string default("ProjectHook")
# service_id :integer
# push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
# wiki_page_events :boolean default(FALSE), not null
# token :string
#
class WebHook < ActiveRecord::Base
include Sortable
include HTTParty
......
# == Schema Information
#
# Table name: identities
#
# id :integer not null, primary key
# extern_uid :string
# provider :string
# user_id :integer
# created_at :datetime
# updated_at :datetime
#
class Identity < ActiveRecord::Base
include Sortable
include CaseSensitivity
......
# == Schema Information
#
# Table name: issues
#
# id :integer not null, primary key
# title :string
# assignee_id :integer
# author_id :integer
# project_id :integer
# created_at :datetime
# updated_at :datetime
# position :integer default(0)
# branch_name :string
# description :text
# milestone_id :integer
# state :string
# iid :integer
# updated_by_id :integer
# moved_to_id :integer
# confidential :boolean default(FALSE)
# deleted_at :datetime
# due_date :date
#
require 'carrierwave/orm/activerecord'
class Issue < ActiveRecord::Base
......
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string
# type :string
# fingerprint :string
# public :boolean default(FALSE), not null
#
require 'digest/md5'
class Key < ActiveRecord::Base
......
# == Schema Information
#
# Table name: labels
#
# id :integer not null, primary key
# title :string
# color :string
# project_id :integer
# created_at :datetime
# updated_at :datetime
# template :boolean default(FALSE)
# description :string
#
class Label < ActiveRecord::Base
include Referable
include Subscribable
......@@ -117,6 +103,10 @@ class Label < ActiveRecord::Base
LabelsHelper::text_color_for_bg(self.color)
end
def title=(value)
write_attribute(:title, Sanitize.clean(value.to_s)) if value.present?
end
private
def label_format_reference(format = :id)
......
# == Schema Information
#
# Table name: label_links
#
# id :integer not null, primary key
# label_id :integer
# target_id :integer
# target_type :string
# created_at :datetime
# updated_at :datetime
#
class LabelLink < ActiveRecord::Base
belongs_to :target, polymorphic: true
belongs_to :label
......
# == Schema Information
#
# Table name: lfs_objects
#
# id :integer not null, primary key
# oid :string not null
# size :integer not null
# created_at :datetime
# updated_at :datetime
# file :string
#
class LfsObject < ActiveRecord::Base
has_many :lfs_objects_projects, dependent: :destroy
has_many :projects, through: :lfs_objects_projects
......
# == Schema Information
#
# Table name: lfs_objects_projects
#
# id :integer not null, primary key
# lfs_object_id :integer not null
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class LfsObjectsProject < ActiveRecord::Base
belongs_to :project
belongs_to :lfs_object
......
# == Schema Information
#
# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
# source_type :string not null
# user_id :integer
# notification_level :integer not null
# type :string
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
# invite_email :string
# invite_token :string
# invite_accepted_at :datetime
#
class Member < ActiveRecord::Base
include Sortable
include Gitlab::Access
......
# == Schema Information
#
# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
# source_type :string not null
# user_id :integer
# notification_level :integer not null
# type :string
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
# invite_email :string
# invite_token :string
# invite_accepted_at :datetime
#
class GroupMember < Member
SOURCE_TYPE = 'Namespace'
......
# == Schema Information
#
# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
# source_type :string not null
# user_id :integer
# notification_level :integer not null
# type :string
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
# invite_email :string
# invite_token :string
# invite_accepted_at :datetime
#
class ProjectMember < Member
SOURCE_TYPE = 'Project'
......
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string not null
# source_branch :string not null
# source_project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string
# created_at :datetime
# updated_at :datetime
# milestone_id :integer
# state :string
# merge_status :string
# target_project_id :integer not null
# iid :integer
# description :text
# position :integer default(0)
# locked_at :datetime
# updated_by_id :integer
# merge_error :string
# merge_params :text
# merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer
# merge_commit_sha :string
# deleted_at :datetime
#
class MergeRequest < ActiveRecord::Base
include InternalId
include Issuable
......
# == Schema Information
#
# Table name: merge_request_diffs
#
# id :integer not null, primary key
# state :string
# st_commits :text
# st_diffs :text
# merge_request_id :integer not null
# created_at :datetime
# updated_at :datetime
# base_commit_sha :string
# real_size :string
#
class MergeRequestDiff < ActiveRecord::Base
include Sortable
......
# == Schema Information
#
# Table name: milestones
#
# id :integer not null, primary key
# title :string not null
# project_id :integer not null
# description :text
# due_date :date
# created_at :datetime
# updated_at :datetime
# state :string
# iid :integer
#
class Milestone < ActiveRecord::Base
# Represents a "No Milestone" state used for filtering Issues and Merge
# Requests that have no milestone assigned.
......@@ -129,6 +114,10 @@ class Milestone < ActiveRecord::Base
nil
end
def title=(value)
write_attribute(:title, Sanitize.clean(value.to_s)) if value.present?
end
# Sorts the issues for the given IDs.
#
# This method runs a single SQL query using a CASE statement to update the
......
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string not null
# path :string not null
# owner_id :integer
# created_at :datetime
# updated_at :datetime
# type :string
# description :string default(""), not null
# avatar :string
# share_with_group_lock :boolean default(FALSE)
# visibility_level :integer default(20), not null
#
class Namespace < ActiveRecord::Base
include Sortable
include Gitlab::ShellAdapter
......
# == Schema Information
#
# Table name: notes
#
# id :integer not null, primary key
# note :text
# noteable_type :string
# author_id :integer
# created_at :datetime
# updated_at :datetime
# project_id :integer
# attachment :string
# line_code :string
# commit_id :string
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
# updated_by_id :integer
# is_award :boolean default(FALSE), not null
#
require 'carrierwave/orm/activerecord'
class Note < ActiveRecord::Base
......
# == Schema Information
#
# Table name: notification_settings
#
# id :integer not null, primary key
# user_id :integer not null
# source_id :integer not null
# source_type :string not null
# level :integer default(0), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class NotificationSetting < ActiveRecord::Base
enum level: { disabled: 0, participating: 1, watch: 2, global: 3, mention: 4 }
......
# == Schema Information
#
# Table name: oauth_access_tokens
#
# id :integer not null, primary key
# resource_owner_id :integer
# application_id :integer
# token :string not null
# refresh_token :string
# expires_in :integer
# revoked_at :datetime
# created_at :datetime not null
# scopes :string
#
class OauthAccessToken < ActiveRecord::Base
belongs_to :resource_owner, class_name: 'User'
belongs_to :application, class_name: 'Doorkeeper::Application'
......
# == Schema Information
#
# Table name: snippets
#
# id :integer not null, primary key
# title :string
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# file_name :string
# type :string
# visibility_level :integer default(0), not null
#
class PersonalSnippet < Snippet
end
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string
# path :string
# description :text
# created_at :datetime
# updated_at :datetime
# creator_id :integer
# issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
# issues_tracker :string default("gitlab"), not null
# issues_tracker_id :string
# snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime
# import_url :string
# visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# avatar :string
# import_status :string
# repository_size :float default(0.0)
# star_count :integer default(0), not null
# import_type :string
# import_source :string
# commit_count :integer default(0)
# 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
# pending_delete :boolean default(FALSE)
# public_builds :boolean default(TRUE), not null
# main_language :string
# pushes_since_gc :integer default(0)
# last_repository_check_failed :boolean
# last_repository_check_at :datetime
#
require 'carrierwave/orm/activerecord'
class Project < ActiveRecord::Base
......@@ -67,7 +21,6 @@ class Project < ActiveRecord::Base
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
default_value_for :builds_enabled, gitlab_config_features.builds
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :wall_enabled, false
default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
......@@ -767,7 +720,7 @@ class Project < ActiveRecord::Base
# Check if current branch name is marked as protected in the system
def protected_branch?(branch_name)
protected_branches.where(name: branch_name).any?
protected_branch_names.include?(branch_name)
end
def developers_can_push_to_protected_branch?(branch_name)
......
# == Schema Information
#
# Table name: project_group_links
#
# id :integer not null, primary key
# project_id :integer not null
# group_id :integer not null
# created_at :datetime
# updated_at :datetime
# group_access :integer default(30), not null
#
class ProjectGroupLink < ActiveRecord::Base
GUEST = 10
REPORTER = 20
......
# == Schema Information
#
# Table name: project_import_data
#
# id :integer not null, primary key
# project_id :integer
# data :text
# encrypted_credentials :text
# encrypted_credentials_iv :string
# encrypted_credentials_salt :string
#
require 'carrierwave/orm/activerecord'
class ProjectImportData < ActiveRecord::Base
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
require 'asana'
class AsanaService < Service
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class AssemblaService < Service
include HTTParty
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class BambooService < CiService
include HTTParty
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
require "addressable/uri"
class BuildkiteService < CiService
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class BuildsEmailService < Service
prop_accessor :recipients
boolean_accessor :add_pusher
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class CampfireService < Service
prop_accessor :token, :subdomain, :room
validates :token, presence: true, if: :activated?
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
# Base class for CI services
# List methods you need to implement to get your CI service
# working with GitLab Merge Requests
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class CustomIssueTrackerService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class DroneCiService < CiService
prop_accessor :drone_url, :token, :enable_ssl_verification
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class EmailsOnPushService < Service
prop_accessor :send_from_committer_email
prop_accessor :disable_diffs
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class ExternalWikiService < Service
include HTTParty
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
require "flowdock-git-hook"
class FlowdockService < Service
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
require "gemnasium/gitlab_service"
class GemnasiumService < Service
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed
class GitlabCiService < CiService
# We override the active accessor to always make GitLabCiService disabled
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class GitlabIssueTrackerService < IssueTrackerService
include Gitlab::Routing.url_helpers
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class HipchatService < Service
MAX_COMMITS = 3
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
require 'uri'
class IrkerService < Service
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class IssueTrackerService < Service
validates :project_url, :issues_url, :new_issue_url, presence: true, url: true, if: :activated?
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class JiraService < IssueTrackerService
include HTTParty
include Gitlab::Routing.url_helpers
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class PivotaltrackerService < Service
include HTTParty
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class PushoverService < Service
include HTTParty
base_uri 'https://api.pushover.net/1'
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class RedmineService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class SlackService < Service
prop_accessor :webhook, :username, :channel
boolean_accessor :notify_only_broken_builds
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
class TeamcityService < CiService
include HTTParty
......
# == Schema Information
#
# Table name: snippets
#
# id :integer not null, primary key
# title :string
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# file_name :string
# type :string
# visibility_level :integer default(0), not null
#
class ProjectSnippet < Snippet
belongs_to :project
belongs_to :author, class_name: "User"
......
# == Schema Information
#
# Table name: protected_branches
#
# id :integer not null, primary key
# project_id :integer not null
# name :string not null
# created_at :datetime
# updated_at :datetime
# developers_can_push :boolean default(FALSE), not null
#
class ProtectedBranch < ActiveRecord::Base
include Gitlab::ShellAdapter
......
# == Schema Information
#
# Table name: releases
#
# id :integer not null, primary key
# tag :string
# description :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
#
class Release < ActiveRecord::Base
belongs_to :project
......
# == Schema Information
#
# Table name: audit_events
#
# id :integer not null, primary key
# author_id :integer not null
# type :string not null
# entity_id :integer not null
# entity_type :string not null
# details :text
# created_at :datetime
# updated_at :datetime
#
class SecurityEvent < AuditEvent
end
# == Schema Information
#
# Table name: sent_notifications
#
# id :integer not null, primary key
# project_id :integer
# noteable_id :integer
# noteable_type :string
# recipient_id :integer
# commit_id :string
# reply_key :string not null
# line_code :string
#
class SentNotification < ActiveRecord::Base
belongs_to :project
belongs_to :noteable, polymorphic: true
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string
# title :string
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
# category :string default("common"), not null
# default :boolean default(FALSE)
# wiki_page_events :boolean default(TRUE)
#
# To add new service you should build a class inherited from Service
# and implement a set of methods
class Service < ActiveRecord::Base
......
# == Schema Information
#
# Table name: snippets
#
# id :integer not null, primary key
# title :string
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# file_name :string
# type :string
# visibility_level :integer default(0), not null
#
class Snippet < ActiveRecord::Base
include Gitlab::VisibilityLevel
include Linguist::BlobHelper
......
# == Schema Information
#
# Table name: spam_logs
#
# id :integer not null, primary key
# user_id :integer
# source_ip :string
# user_agent :string
# via_api :boolean
# project_id :integer
# noteable_type :string
# title :string
# description :text
# created_at :datetime not null
# updated_at :datetime not null
#
class SpamLog < ActiveRecord::Base
belongs_to :user
......
# == Schema Information
#
# Table name: subscriptions
#
# id :integer not null, primary key
# user_id :integer
# subscribable_id :integer
# subscribable_type :string
# subscribed :boolean
# created_at :datetime
# updated_at :datetime
#
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :subscribable, polymorphic: true
......
# == Schema Information
#
# Table name: todos
#
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
# target_id :integer
# target_type :string not null
# author_id :integer
# action :integer not null
# state :string not null
# created_at :datetime
# updated_at :datetime
# note_id :integer
# commit_id :string
#
class Todo < ActiveRecord::Base
ASSIGNED = 1
MENTIONED = 2
......
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string default(""), not null
# encrypted_password :string default(""), not null
# reset_password_token :string
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0)
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string
# last_sign_in_ip :string
# created_at :datetime
# updated_at :datetime
# name :string
# admin :boolean default(FALSE), not null
# projects_limit :integer default(10)
# skype :string default(""), not null
# linkedin :string default(""), not null
# twitter :string default(""), not null
# authentication_token :string
# theme_id :integer default(1), not null
# bio :string
# failed_attempts :integer default(0)
# locked_at :datetime
# username :string
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
# state :string
# color_scheme_id :integer default(1), not null
# notification_level :integer default(1), not null
# password_expires_at :datetime
# created_by_id :integer
# last_credential_check_at :datetime
# avatar :string
# confirmation_token :string
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string
# hide_no_ssh_key :boolean default(FALSE)
# website_url :string default(""), not null
# notification_email :string
# hide_no_password :boolean default(FALSE)
# password_automatically_set :boolean default(FALSE)
# location :string
# encrypted_otp_secret :string
# encrypted_otp_secret_iv :string
# encrypted_otp_secret_salt :string
# otp_required_for_login :boolean default(FALSE), not null
# otp_backup_codes :text
# public_email :string default(""), not null
# dashboard :integer default(0)
# project_view :integer default(0)
# consumed_timestep :integer
# layout :integer default(0)
# hide_project_limit :boolean default(FALSE)
# unlock_token :string
# otp_grace_period_started_at :datetime
# ldap_email :boolean default(FALSE), not null
# external :boolean default(FALSE)
#
require 'carrierwave/orm/activerecord'
class User < ActiveRecord::Base
......@@ -86,7 +21,7 @@ class User < ActiveRecord::Base
default_value_for :theme_id, gitlab_config.default_theme
devise :two_factor_authenticatable,
otp_secret_encryption_key: File.read(Rails.root.join('.secret')).chomp
otp_secret_encryption_key: Gitlab::Application.config.secret_key_base
alias_attribute :two_factor_enabled, :otp_required_for_login
devise :two_factor_backupable, otp_number_of_backup_codes: 10
......
# == Schema Information
#
# Table name: users_star_projects
#
# id :integer not null, primary key
# project_id :integer not null
# user_id :integer not null
# created_at :datetime
# updated_at :datetime
#
class UsersStarProject < ActiveRecord::Base
belongs_to :project, counter_cache: :star_count, touch: true
belongs_to :user
......
......@@ -351,7 +351,7 @@ class SystemNoteService
# Returns an Array of Strings
def self.new_commit_summary(new_commits)
new_commits.collect do |commit|
"* #{commit.short_id} - #{commit.title}"
"* #{commit.short_id} - #{escape_html(commit.title)}"
end
end
......@@ -433,4 +433,8 @@ class SystemNoteService
body = "Moved #{direction} #{cross_reference}"
create_note(noteable: noteable, project: project, author: author, note: body)
end
def self.escape_html(text)
Rack::Utils.escape_html(text)
end
end
......@@ -11,18 +11,10 @@
= link_to admin_runner_path(runner) do
= runner.short_sha
%td
.runner-description
= runner.description
%span (#{link_to 'edit', '#', class: 'edit-runner-link'})
.runner-description-form.hide
= form_for [:admin, runner], remote: true, html: { class: 'form-inline' } do |f|
.form-group
= f.text_field :description, class: 'form-control'
= f.submit 'Save', class: 'btn'
%span (#{link_to 'cancel', '#', class: 'cancel'})
= runner.description
%td
- if runner.shared?
\-
n/a
- else
= runner.projects.count(:all)
%td
......
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
%div{ class: fluid_layout ? "container-fluid" : "container-fluid" }
.header-content
%button.navbar-toggle{type: 'button'}
%button.side-nav-toggle{type: 'button'}
%span.sr-only Toggle navigation
= icon('bars')
%button.navbar-toggle{type: 'button'}
%span.sr-only Toggle navigation
= icon('angle-left')
.navbar-collapse.collapse
%ul.nav.navbar-nav
......
......@@ -28,16 +28,10 @@
= downvotes
- note_count = issue.notes.user.nonawards.count
- if note_count > 0
%li
= link_to issue_path(issue) + "#notes" do
= icon('comments')
= note_count
- else
%li
= link_to issue_path(issue) + "#notes", class: "issue-no-comments" do
= icon('comments')
= note_count
%li
= link_to issue_path(issue, anchor: 'notes'), class: ('issue-no-comments' if note_count.zero?) do
= icon('comments')
= note_count
.issue-info
#{issue.to_reference} &middot;
......
......@@ -36,16 +36,10 @@
= downvotes
- note_count = merge_request.mr_and_commit_notes.user.nonawards.count
- if note_count > 0
%li
= link_to merge_request_path(merge_request) + "#notes" do
= icon('comments')
= note_count
- else
%li
= link_to merge_request_path(merge_request) + "#notes", class: "merge-request-no-comments" do
= icon('comments')
= note_count
%li
= link_to merge_request_path(merge_request, anchor: 'notes'), class: ('merge-request-no-comments' if note_count.zero?) do
= icon('comments')
= note_count
.merge-request-info
#{merge_request.to_reference} &middot;
......
......@@ -41,9 +41,4 @@
.ci_widget.ci-error{style: "display:none"}
= icon("times-circle")
Could not connect to the CI server. Please check your settings and try again.
:javascript
$(function() {
merge_request_widget.getCIStatus(false);
});
Could not connect to the CI server. Please check your settings and try again.
\ No newline at end of file
......@@ -23,7 +23,7 @@
.form-group
= label_tag :message, nil, class: 'control-label'
.col-sm-10
= text_field_tag :message, nil, required: false, tabindex: 3, class: 'form-control'
= text_area_tag :message, nil, required: false, tabindex: 3, class: 'form-control', rows: 5
.help-block Optionally, enter a message to create an annotated tag.
%hr
.form-group
......
......@@ -19,15 +19,13 @@
%i.fa.fa-trash-o
.title
%span.item-title= @tag.name
- if @tag.message.present?
%span.light
&nbsp;
= strip_gpg_signature(@tag.message)
- if @commit
= render 'projects/branches/commit', commit: @commit, project: @project
- else
Cant find HEAD commit for this tag
- if @tag.message.present?
%pre.body
= strip_gpg_signature(@tag.message)
.append-bottom-default.prepend-top-default
- if @release.description.present?
......
......@@ -15,7 +15,6 @@ production: &base
issues: true
merge_requests: true
wiki: true
wall: false
snippets: false
visibility_level: "private" # can be "private" | "internal" | "public"
......
Rails.application.config.action_dispatch.trusted_proxies =
Rails.application.config.action_dispatch.trusted_proxies = (
[ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies)
).map { |proxy| IPAddr.new(proxy) }
class RemoveWallEnabledFromProjects < ActiveRecord::Migration
def change
remove_column :projects, :wall_enabled, :boolean, default: true, null: false
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160421130527) do
ActiveRecord::Schema.define(version: 20160508194200) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -728,7 +728,6 @@ ActiveRecord::Schema.define(version: 20160421130527) do
t.datetime "updated_at"
t.integer "creator_id"
t.boolean "issues_enabled", default: true, null: false
t.boolean "wall_enabled", default: true, null: false
t.boolean "merge_requests_enabled", default: true, null: false
t.boolean "wiki_enabled", default: true, null: false
t.integer "namespace_id"
......
......@@ -101,8 +101,18 @@ DELETE /projects/:id/triggers/:token
| Attribute | Type | required | Description |
|-----------|---------|----------|--------------------------|
| `id` | integer | yes | The ID of a project |
| `token` | string | yes | The `token` of a project |
| `token` | string | yes | The `token` of a trigger |
```
curl -X DELETE -H "PRIVATE_TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/triggers/7b9148c158980bbd9bcea92c17522d"
```
```json
{
"created_at": "2015-12-23T16:25:56.760Z",
"deleted_at": "2015-12-24T12:32:20.100Z",
"last_used": null,
"token": "7b9148c158980bbd9bcea92c17522d",
"updated_at": "2015-12-24T12:32:20.100Z"
}
```
......@@ -77,7 +77,8 @@ Example response:
"created_at" : "2016-01-04T15:31:51.081Z",
"iid" : 6,
"labels" : [],
"subscribed" : false
"subscribed" : false,
"user_notes_count": 1
}
]
```
......@@ -154,7 +155,8 @@ Example response:
"title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false
"subscribed" : false,
"user_notes_count": 1
}
]
```
......@@ -216,7 +218,8 @@ Example response:
"title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
"updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z",
"subscribed": false
"subscribed": false,
"user_notes_count": 1
}
```
......@@ -271,7 +274,8 @@ Example response:
"description" : null,
"updated_at" : "2016-01-07T12:44:33.959Z",
"milestone" : null,
"subscribed" : true
"subscribed" : true,
"user_notes_count": 0
}
```
......@@ -329,7 +333,8 @@ Example response:
"id" : 85,
"assignee" : null,
"milestone" : null,
"subscribed" : true
"subscribed" : true,
"user_notes_count": 0
}
```
......
......@@ -67,7 +67,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : false
"subscribed" : false,
"user_notes_count": 1
}
]
```
......@@ -130,7 +131,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true
"subscribed" : true,
"user_notes_count": 1
}
```
......@@ -230,6 +232,7 @@ Parameters:
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true,
"user_notes_count": 1,
"changes": [
{
"old_path": "VERSION",
......@@ -308,7 +311,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true
"subscribed" : true,
"user_notes_count": 0
}
```
......@@ -378,7 +382,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true
"subscribed" : true,
"user_notes_count": 1
}
```
......@@ -472,7 +477,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true
"subscribed" : true,
"user_notes_count": 1
}
```
......@@ -537,7 +543,8 @@ Parameters:
},
"merge_when_build_succeeds": true,
"merge_status": "can_be_merged",
"subscribed" : true
"subscribed" : true,
"user_notes_count": 1
}
```
......@@ -602,7 +609,8 @@ Example response:
"title" : "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.",
"created_at" : "2016-01-04T15:31:51.081Z",
"iid" : 6,
"labels" : []
"labels" : [],
"user_notes_count": 1
},
]
```
......
......@@ -15,7 +15,7 @@ GET /projects/:id/issues/:issue_id/notes
Parameters:
- `id` (required) - The ID of a project
- `issue_id` (required) - The IID of an issue (not ID)
- `issue_id` (required) - The ID of an issue
```json
[
......@@ -73,7 +73,7 @@ GET /projects/:id/issues/:issue_id/notes/:note_id
Parameters:
- `id` (required) - The ID of a project
- `issue_id` (required) - The IID of a project issue (not ID)
- `issue_id` (required) - The ID of a project issue
- `note_id` (required) - The ID of an issue note
### Create new issue note
......@@ -87,7 +87,7 @@ POST /projects/:id/issues/:issue_id/notes
Parameters:
- `id` (required) - The ID of a project
- `issue_id` (required) - The IID of an issue (not ID)
- `issue_id` (required) - The ID of an issue
- `body` (required) - The content of a note
- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z
......@@ -102,7 +102,7 @@ PUT /projects/:id/issues/:issue_id/notes/:note_id
Parameters:
- `id` (required) - The ID of a project
- `issue_id` (required) - The IID of an issue (not ID)
- `issue_id` (required) - The ID of an issue
- `note_id` (required) - The ID of a note
- `body` (required) - The content of a note
......@@ -120,7 +120,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `issue_id` | integer | yes | The IID of an issue |
| `issue_id` | integer | yes | The ID of an issue |
| `note_id` | integer | yes | The ID of a note |
```bash
......
# Instrumenting Ruby Code
GitLab Performance Monitoring allows instrumenting of custom blocks of Ruby
code. This can be used to measure the time spent in a specific part of a larger
chunk of code. The resulting data is stored as a field in the transaction that
executed the block.
GitLab Performance Monitoring allows instrumenting of both methods and custom
blocks of Ruby code. Method instrumentation is the primary form of
instrumentation with block-based instrumentation only being used when we want to
drill down to specific regions of code within a method.
To start measuring a block of Ruby code you should use `Gitlab::Metrics.measure`
and give it a name:
## Instrumenting Methods
Instrumenting methods is done by using the `Gitlab::Metrics::Instrumentation`
module. This module offers a few different methods that can be used to
instrument code:
* `instrument_method`: instruments a single class method.
* `instrument_instance_method`: instruments a single instance method.
* `instrument_class_hierarchy`: given a Class this method will recursively
instrument all sub-classes (both class and instance methods).
* `instrument_methods`: instruments all public class methods of a Module.
* `instrument_instance_methods`: instruments all public instance methods of a
Module.
To remove the need for typing the full `Gitlab::Metrics::Instrumentation`
namespace you can use the `configure` class method. This method simply yields
the supplied block while passing `Gitlab::Metrics::Instrumentation` as its
argument. An example:
```
Gitlab::Metrics::Instrumentation.configure do |conf|
conf.instrument_method(Foo, :bar)
conf.instrument_method(Foo, :baz)
end
```
Using this method is in general preferred over directly calling the various
instrumentation methods.
Method instrumentation should be added in the initializer
`config/initializers/metrics.rb`.
### Examples
Instrumenting a single method:
```
Gitlab::Metrics::Instrumentation.configure do |conf|
conf.instrument_method(User, :find_by)
end
```
Instrumenting an entire class hierarchy:
```
Gitlab::Metrics::Instrumentation.configure do |conf|
conf.instrument_class_hierarchy(ActiveRecord::Base)
end
```
Instrumenting all public class methods:
```
Gitlab::Metrics::Instrumentation.configure do |conf|
conf.instrument_methods(User)
end
```
### Checking Instrumented Methods
The easiest way to check if a method has been instrumented is to check its
source location. For example:
```
method = Rugged::TagCollection.instance_method(:[])
method.source_location
```
If the source location points to `lib/gitlab/metrics/instrumentation.rb` you
know the method has been instrumented.
If you're using Pry you can use the `$` command to display the source code of a
method (along with its source location), this is easier than running the above
Ruby code. In case of the above snippet you'd run the following:
```
$ Rugged::TagCollection#[]
```
This will print out something along the lines of:
```
From: /path/to/your/gitlab/lib/gitlab/metrics/instrumentation.rb @ line 148:
Owner: #<Module:0x0055f0865c6d50>
Visibility: public
Number of lines: 21
def #{name}(#{args_signature})
trans = Gitlab::Metrics::Instrumentation.transaction
if trans
start = Time.now
retval = super
duration = (Time.now - start) * 1000.0
if duration >= Gitlab::Metrics.method_call_threshold
trans.increment(:method_duration, duration)
trans.add_metric(Gitlab::Metrics::Instrumentation::SERIES,
{ duration: duration },
method: #{label.inspect})
end
retval
else
super
end
end
```
## Instrumenting Ruby Blocks
Measuring blocks of Ruby code is done by calling `Gitlab::Metrics.measure` and
passing it a block. For example:
```ruby
Gitlab::Metrics.measure(:foo) do
......@@ -14,6 +127,10 @@ Gitlab::Metrics.measure(:foo) do
end
```
The block is executed and the execution time is stored as a set of fields in the
currently running transaction. If no transaction is present the block is yielded
without measuring anything.
3 values are measured for a block:
1. The real time elapsed, stored in NAME_real_time.
......
......@@ -152,4 +152,4 @@ If you are using OS X you can use `osxkeychain` to store and encrypt your creden
For Windows, you can use `wincred` or Microsoft's [Git Credential Manager for Windows](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases).
More details about various methods of storing the user credentials can be found
on [Git Credential Storage documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
\ No newline at end of file
on [Git Credential Storage documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
@project_commits
Feature: Project Commits Tags
Background:
Given I sign in as a user
And I own project "Shop"
Given I visit project tags page
Scenario: I can see all git tags
Then I should see "Shop" all tags list
Scenario: I create a tag
And I click new tag link
And I submit new tag form
Then I should see new tag created
Scenario: I create a tag with release notes
Given I click new tag link
And I submit new tag form with release notes
Then I should see new tag created
And I should see tag release notes
Scenario: I create a tag with invalid name
And I click new tag link
And I submit new tag form with invalid name
Then I should see new an error that tag is invalid
Scenario: I create a tag with invalid reference
And I click new tag link
And I submit new tag form with invalid reference
Then I should see new an error that tag ref is invalid
Scenario: I create a tag that already exists
And I click new tag link
And I submit new tag form with tag that already exists
Then I should see new an error that tag already exists
Scenario: I delete a tag
Given I visit tag 'v1.1.0' page
Given I delete tag 'v1.1.0'
Then I should not see tag 'v1.1.0'
Scenario: I add release notes to the tag
Given I visit tag 'v1.1.0' page
When I click edit tag link
And I fill release notes and submit form
Then I should see tag release notes
......@@ -6,21 +6,9 @@ Feature: Project Create
@javascript
Scenario: User create a project
Given I sign in as a user
When I visit new project page
And I have an ssh key
And fill project form with valid data
Then I should see project page
And I should see empty project instuctions
@javascript
Scenario: Empty project instructions
Given I sign in as a user
And I have an ssh key
When I visit new project page
And fill project form with valid data
Then I see empty project instuctions
And I click on HTTP
Then Remote url should update to http link
And If I click on SSH
Then Remote url should update to ssh link
Then I should see project page
And I should see empty project instructions
class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
step 'I should see "Shop" all tags list' do
expect(page).to have_content "Tags"
expect(page).to have_content "v1.0.0"
end
step 'I click new tag link' do
click_link 'New tag'
end
step 'I submit new tag form' do
fill_in 'tag_name', with: 'v7.0'
fill_in 'ref', with: 'master'
click_button 'Create tag'
end
step 'I submit new tag form with release notes' do
fill_in 'tag_name', with: 'v7.0'
fill_in 'ref', with: 'master'
fill_in 'release_description', with: 'Awesome release notes'
click_button 'Create tag'
end
step 'I fill release notes and submit form' do
fill_in 'release_description', with: 'Awesome release notes'
click_button 'Save changes'
end
step 'I submit new tag form with invalid name' do
fill_in 'tag_name', with: 'v 1.0'
fill_in 'ref', with: 'master'
click_button 'Create tag'
end
step 'I submit new tag form with invalid reference' do
fill_in 'tag_name', with: 'foo'
fill_in 'ref', with: 'foo'
click_button 'Create tag'
end
step 'I submit new tag form with tag that already exists' do
fill_in 'tag_name', with: 'v1.0.0'
fill_in 'ref', with: 'master'
click_button 'Create tag'
end
step 'I should see new tag created' do
expect(page).to have_content 'v7.0'
end
step 'I should see new an error that tag is invalid' do
expect(page).to have_content 'Tag name invalid'
end
step 'I should see new an error that tag ref is invalid' do
expect(page).to have_content 'Target foo is invalid'
end
step 'I should see new an error that tag already exists' do
expect(page).to have_content 'Tag v1.0.0 already exists'
end
step "I visit tag 'v1.1.0' page" do
click_link 'v1.1.0'
end
step "I delete tag 'v1.1.0'" do
page.within('.content') do
first('.btn-remove').click
end
end
step "I should not see tag 'v1.1.0'" do
page.within '.tags' do
expect(page).not_to have_link 'v1.1.0'
end
end
step 'I click edit tag link' do
click_link 'Edit release notes'
end
step 'I should see tag release notes' do
expect(page).to have_content 'Awesome release notes'
end
end
......@@ -13,33 +13,9 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
expect(current_path).to eq namespace_project_path(Project.last.namespace, Project.last)
end
step 'I should see empty project instuctions' do
step 'I should see empty project instructions' do
expect(page).to have_content "git init"
expect(page).to have_content "git remote"
expect(page).to have_content Project.last.url_to_repo
end
step 'I see empty project instuctions' do
expect(page).to have_content "git init"
expect(page).to have_content "git remote"
expect(page).to have_content Project.last.url_to_repo
end
step 'I click on HTTP' do
find('#clone-dropdown').click
find('.http-selector').click
end
step 'Remote url should update to http link' do
expect(page).to have_content "git remote add origin #{Project.last.http_url_to_repo}"
end
step 'If I click on SSH' do
find('#clone-dropdown').click
find('.ssh-selector').click
end
step 'Remote url should update to ssh link' do
expect(page).to have_content "git remote add origin #{Project.last.url_to_repo}"
end
end
......@@ -170,10 +170,10 @@ module API
expose :label_names, as: :labels
expose :milestone, using: Entities::Milestone
expose :assignee, :author, using: Entities::UserBasic
expose :subscribed do |issue, options|
issue.subscribed?(options[:current_user])
end
expose :user_notes_count
end
class MergeRequest < ProjectEntity
......@@ -187,10 +187,10 @@ module API
expose :milestone, using: Entities::Milestone
expose :merge_when_build_succeeds
expose :merge_status
expose :subscribed do |merge_request, options|
merge_request.subscribed?(options[:current_user])
end
expose :user_notes_count
end
class MergeRequestChanges < MergeRequest
......
......@@ -10,6 +10,9 @@ module Banzai
end
def self.user_can_see_reference?(user, node, context)
# It is not possible to check access rights for external issue trackers
return true if context[:project].try(:external_issue_tracker)
issue = Issue.find(node.attr('data-issue')) rescue nil
Ability.abilities.allowed?(user, :read_issue, issue)
end
......
......@@ -63,7 +63,7 @@ module Banzai
begin
uri = Addressable::URI.parse(node['href'])
uri.scheme.strip! if uri.scheme
uri.scheme = uri.scheme.strip.downcase if uri.scheme
node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(uri.scheme)
rescue Addressable::URI::InvalidURIError
......
......@@ -8,6 +8,8 @@ module Banzai
#
class UploadLinkFilter < HTML::Pipeline::Filter
def call
return doc unless project
doc.search('a').each do |el|
process_link_attr el.attribute('href')
end
......@@ -31,7 +33,11 @@ module Banzai
end
def build_url(uri)
File.join(Gitlab.config.gitlab.url, context[:project].path_with_namespace, uri)
File.join(Gitlab.config.gitlab.url, project.path_with_namespace, uri)
end
def project
context[:project]
end
# Ensure that a :project key exists in context
......
......@@ -122,6 +122,11 @@ module Gitlab
build_status_object(true)
end
def can_user_do_action?(action)
@permission_cache ||= {}
@permission_cache[action] ||= user.can?(action, project)
end
def change_access_check(change)
oldrev, newrev, ref = change.split(' ')
......@@ -135,7 +140,7 @@ module Gitlab
:push_code
end
unless user.can?(action, project)
unless can_user_do_action?(action)
status =
case action
when :force_push_code_to_protected_branches
......
if Rails.env.development?
task :set_annotation_options do
# You can override any of these by setting an environment variable of the
# same name.
Annotate.set_defaults(
'routes' => 'false',
'position_in_routes' => 'before',
'position_in_class' => 'before',
'position_in_test' => 'before',
'position_in_fixture' => 'before',
'position_in_factory' => 'before',
'position_in_serializer' => 'before',
'show_foreign_keys' => 'true',
'show_indexes' => 'false',
'simple_indexes' => 'false',
'model_dir' => 'app/models',
'root_dir' => '',
'include_version' => 'false',
'require' => '',
'exclude_tests' => 'true',
'exclude_fixtures' => 'true',
'exclude_factories' => 'true',
'exclude_serializers' => 'true',
'exclude_scaffolds' => 'true',
'exclude_controllers' => 'true',
'exclude_helpers' => 'true',
'ignore_model_sub_dir' => 'false',
'ignore_columns' => nil,
'ignore_unknown_models' => 'false',
'hide_limit_column_types' => 'integer,boolean',
'skip_on_db_migrate' => 'false',
'format_bare' => 'true',
'format_rdoc' => 'false',
'format_markdown' => 'false',
'sort' => 'false',
'force' => 'false',
'trace' => 'false',
'wrapper_open' => nil,
'wrapper_close' => nil,
)
end
Annotate.load_tasks
end
......@@ -29,10 +29,12 @@ namespace :gitlab do
tables.delete 'schema_migrations'
# Truncate schema_migrations to ensure migrations re-run
connection.execute('TRUNCATE schema_migrations')
# Drop tables with cascade to avoid dependent table errors
# PG: http://www.postgresql.org/docs/current/static/ddl-depend.html
# MySQL: http://dev.mysql.com/doc/refman/5.7/en/drop-table.html
tables.each { |t| connection.execute("DROP TABLE #{t} CASCADE") }
# Add `IF EXISTS` because cascade could have already deleted a table.
tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{t} CASCADE") }
end
end
end
# == Schema Information
#
# Table name: abuse_reports
#
# id :integer not null, primary key
# reporter_id :integer
# user_id :integer
# message :text
# created_at :datetime
# updated_at :datetime
#
FactoryGirl.define do
factory :abuse_report do
reporter factory: :user
......
# == Schema Information
#
# Table name: broadcast_messages
#
# id :integer not null, primary key
# message :text not null
# starts_at :datetime
# ends_at :datetime
# created_at :datetime
# updated_at :datetime
# color :string(255)
# font :string(255)
#
FactoryGirl.define do
factory :broadcast_message do
message "MyText"
......
# == Schema Information
#
# Table name: forked_project_links
#
# id :integer not null, primary key
# forked_to_project_id :integer not null
# forked_from_project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
FactoryGirl.define do
factory :forked_project_link do
association :forked_to_project, factory: :project
......
# == Schema Information
#
# Table name: label_links
#
# id :integer not null, primary key
# label_id :integer
# target_id :integer
# target_type :string(255)
# created_at :datetime
# updated_at :datetime
#
FactoryGirl.define do
factory :label_link do
label
......
# == Schema Information
#
# Table name: labels
#
# id :integer not null, primary key
# title :string(255)
# color :string(255)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# template :boolean default(FALSE)
#
FactoryGirl.define do
factory :label do
sequence(:title) { |n| "label#{n}" }
......
# == Schema Information
#
# Table name: lfs_objects
#
# id :integer not null, primary key
# oid :string(255) not null
# size :integer not null
# created_at :datetime
# updated_at :datetime
# file :string(255)
#
include ActionDispatch::TestProcess
FactoryGirl.define do
......
# == Schema Information
#
# Table name: lfs_objects_projects
#
# id :integer not null, primary key
# lfs_object_id :integer not null
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
FactoryGirl.define do
factory :lfs_objects_project do
lfs_object
......
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string(255) not null
# source_branch :string(255) not null
# source_project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string(255)
# created_at :datetime
# updated_at :datetime
# milestone_id :integer
# state :string(255)
# merge_status :string(255)
# target_project_id :integer not null
# iid :integer
# description :text
# position :integer default(0)
# locked_at :datetime
# updated_by_id :integer
# merge_error :string(255)
# merge_params :text
# merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer
# merge_commit_sha :string
#
FactoryGirl.define do
factory :merge_request do
title
......
# == Schema Information
#
# Table name: notes
#
# id :integer not null, primary key
# note :text
# noteable_type :string(255)
# author_id :integer
# created_at :datetime
# updated_at :datetime
# project_id :integer
# attachment :string(255)
# line_code :string(255)
# commit_id :string(255)
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
# updated_by_id :integer
# is_award :boolean default(FALSE), not null
#
require_relative '../support/repo_helpers'
include ActionDispatch::TestProcess
......
# == Schema Information
#
# Table name: oauth_access_tokens
#
# id :integer not null, primary key
# resource_owner_id :integer
# application_id :integer
# token :string not null
# refresh_token :string
# expires_in :integer
# revoked_at :datetime
# created_at :datetime not null
# scopes :string
#
FactoryGirl.define do
factory :oauth_access_token do
resource_owner
......
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255)
# path :string(255)
# description :text
# created_at :datetime
# updated_at :datetime
# creator_id :integer
# issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
# issues_tracker :string(255) default("gitlab"), not null
# issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime
# import_url :string(255)
# visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# avatar :string(255)
# import_status :string(255)
# repository_size :float default(0.0)
# star_count :integer default(0), not null
# import_type :string(255)
# import_source :string(255)
# commit_count :integer default(0)
# 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
# Project without repository
#
......@@ -61,6 +21,12 @@ FactoryGirl.define do
trait :private do
visibility_level Gitlab::VisibilityLevel::PRIVATE
end
trait :empty_repo do
after(:create) do |project|
project.create_repository
end
end
end
# Project with empty repository
......@@ -68,9 +34,7 @@ FactoryGirl.define do
# This is a case when you just created a project
# but not pushed any code there yet
factory :project_empty_repo, parent: :empty_project do
after :create do |project|
project.create_repository
end
empty_repo
end
# Project with test repository
......
# == Schema Information
#
# Table name: releases
#
# id :integer not null, primary key
# tag :string(255)
# description :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
#
FactoryGirl.define do
factory :release do
tag "v1.1.0"
......
# == Schema Information
#
# Table name: todos
#
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
# target_id :integer
# target_type :string not null
# author_id :integer
# action :integer not null
# state :string not null
# created_at :datetime
# updated_at :datetime
# note_id :integer
# commit_id :string
#
FactoryGirl.define do
factory :todo do
project
......
require 'rails_helper'
feature 'Developer views empty project instructions', feature: true do
let(:project) { create(:empty_project, :empty_repo) }
let(:developer) { create(:user) }
background do
project.team << [developer, :developer]
login_as(developer)
end
context 'without an SSH key' do
scenario 'defaults to HTTP' do
visit_project
expect_instructions_for('http')
end
scenario 'switches to SSH', js: true do
visit_project
select_protocol('SSH')
expect_instructions_for('ssh')
end
end
context 'with an SSH key' do
background do
create(:personal_key, user: developer)
end
scenario 'defaults to SSH' do
visit_project
expect_instructions_for('ssh')
end
scenario 'switches to HTTP', js: true do
visit_project
select_protocol('HTTP')
expect_instructions_for('http')
end
end
def visit_project
visit namespace_project_path(project.namespace, project)
end
def select_protocol(protocol)
find('#clone-dropdown').click
find(".#{protocol.downcase}-selector").click
end
def expect_instructions_for(protocol)
msg = :"#{protocol.downcase}_url_to_repo"
expect(page).to have_content("git clone #{project.send(msg)}")
end
end
require 'spec_helper'
feature 'Master creates tag', feature: true do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
project.team << [user, :master]
login_with(user)
visit namespace_project_tags_path(project.namespace, project)
end
scenario 'with an invalid name displays an error' do
create_tag_in_form(tag: 'v 1.0', ref: 'master')
expect(page).to have_content 'Tag name invalid'
end
scenario 'with an invalid reference displays an error' do
create_tag_in_form(tag: 'v2.0', ref: 'foo')
expect(page).to have_content 'Target foo is invalid'
end
scenario 'that already exists displays an error' do
create_tag_in_form(tag: 'v1.1.0', ref: 'master')
expect(page).to have_content 'Tag v1.1.0 already exists'
end
scenario 'with multiline message displays the message in a <pre> block' do
create_tag_in_form(tag: 'v3.0', ref: 'master', message: "Awesome tag message\n\n- hello\n- world")
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v3.0'))
expect(page).to have_content 'v3.0'
page.within 'pre.body' do
expect(page).to have_content "Awesome tag message\n\n- hello\n- world"
end
end
scenario 'with multiline release notes parses the release note as Markdown' do
create_tag_in_form(tag: 'v4.0', ref: 'master', desc: "Awesome release notes\n\n- hello\n- world")
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v4.0'))
expect(page).to have_content 'v4.0'
page.within '.description' do
expect(page).to have_content 'Awesome release notes'
expect(page).to have_selector('ul li', count: 2)
end
end
def create_tag_in_form(tag:, ref:, message: nil, desc: nil)
click_link 'New tag'
fill_in 'tag_name', with: tag
fill_in 'ref', with: ref
fill_in 'message', with: message unless message.nil?
fill_in 'release_description', with: desc unless desc.nil?
click_button 'Create tag'
end
end
require 'spec_helper'
feature 'Master deletes tag', feature: true do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
project.team << [user, :master]
login_with(user)
visit namespace_project_tags_path(project.namespace, project)
end
context 'from the tags list page' do
scenario 'deletes the tag' do
expect(page).to have_content 'v1.1.0'
page.within('.content') do
first('.btn-remove').click
end
expect(current_path).to eq(
namespace_project_tags_path(project.namespace, project))
expect(page).not_to have_content 'v1.1.0'
end
end
context 'from a specific tag page' do
scenario 'deletes the tag' do
click_on 'v1.0.0'
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
click_on 'Delete tag'
expect(current_path).to eq(
namespace_project_tags_path(project.namespace, project))
expect(page).not_to have_content 'v1.0.0'
end
end
end
require 'spec_helper'
feature 'Master updates tag', feature: true do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
project.team << [user, :master]
login_with(user)
visit namespace_project_tags_path(project.namespace, project)
end
context 'from the tags list page' do
scenario 'updates the release notes' do
page.within(first('.controls')) do
click_link 'Edit release notes'
end
fill_in 'release_description', with: 'Awesome release notes'
click_button 'Save changes'
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v1.1.0'))
expect(page).to have_content 'v1.1.0'
expect(page).to have_content 'Awesome release notes'
end
end
context 'from a specific tag page' do
scenario 'updates the release notes' do
click_on 'v1.1.0'
click_link 'Edit release notes'
fill_in 'release_description', with: 'Awesome release notes'
click_button 'Save changes'
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v1.1.0'))
expect(page).to have_content 'v1.1.0'
expect(page).to have_content 'Awesome release notes'
end
end
end
require 'spec_helper'
feature 'Master views tags', feature: true do
let(:user) { create(:user) }
before do
project.team << [user, :master]
login_with(user)
end
context 'when project has no tags' do
let(:project) { create(:project_empty_repo) }
before do
visit namespace_project_path(project.namespace, project)
click_on 'README'
fill_in :commit_message, with: 'Add a README file', visible: true
# Remove pre-receive hook so we can push without auth
FileUtils.rm_f(File.join(project.repository.path, 'hooks', 'pre-receive'))
click_button 'Commit Changes'
visit namespace_project_tags_path(project.namespace, project)
end
scenario 'displays a specific message' do
expect(page).to have_content 'Repository has no tags yet.'
end
end
context 'when project has tags' do
let(:project) { create(:project, namespace: user.namespace) }
before do
visit namespace_project_tags_path(project.namespace, project)
end
scenario 'views the tags list page' do
expect(page).to have_content 'v1.0.0'
end
scenario 'views a specific tag page' do
click_on 'v1.0.0'
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
expect(page).to have_content 'v1.0.0'
expect(page).to have_content 'This tag has no release notes.'
end
describe 'links on the tag page' do
scenario 'has a button to browse files' do
click_on 'v1.0.0'
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
click_on 'Browse files'
expect(current_path).to eq(
namespace_project_tree_path(project.namespace, project, 'v1.0.0'))
end
scenario 'has a button to browse commits' do
click_on 'v1.0.0'
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
click_on 'Browse commits'
expect(current_path).to eq(
namespace_project_commits_path(project.namespace, project, 'v1.0.0'))
end
end
end
end
......@@ -88,18 +88,18 @@ describe ProjectsHelper do
end
describe 'default_clone_protocol' do
describe 'using HTTP' do
context 'when user is not logged in and gitlab protocol is HTTP' do
it 'returns HTTP' do
expect(helper).to receive(:current_user).and_return(nil)
allow(helper).to receive(:current_user).and_return(nil)
expect(helper.send(:default_clone_protocol)).to eq('http')
end
end
describe 'using HTTPS' do
context 'when user is not logged in and gitlab protocol is HTTPS' do
it 'returns HTTPS' do
allow(Gitlab.config.gitlab).to receive(:protocol).and_return('https')
expect(helper).to receive(:current_user).and_return(nil)
stub_config_setting(protocol: 'https')
allow(helper).to receive(:current_user).and_return(nil)
expect(helper.send(:default_clone_protocol)).to eq('https')
end
......
require 'spec_helper'
describe 'trusted_proxies', lib: true do
context 'with default config' do
before do
set_trusted_proxies([])
end
it 'preserves private IPs as remote_ip' do
request = stub_request('HTTP_X_FORWARDED_FOR' => '10.1.5.89')
expect(request.remote_ip).to eq('10.1.5.89')
end
it 'filters out localhost from remote_ip' do
request = stub_request('HTTP_X_FORWARDED_FOR' => '1.1.1.1, 10.1.5.89, 127.0.0.1')
expect(request.remote_ip).to eq('10.1.5.89')
end
end
context 'with private IP ranges added' do
before do
set_trusted_proxies([ "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" ])
end
it 'filters out private and local IPs from remote_ip' do
request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 10.1.5.89, 127.0.0.1')
expect(request.remote_ip).to eq('1.1.1.1')
end
end
context 'with proxy IP added' do
before do
set_trusted_proxies([ "60.98.25.47" ])
end
it 'filters out proxy IP from remote_ip' do
request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 60.98.25.47, 127.0.0.1')
expect(request.remote_ip).to eq('1.1.1.1')
end
end
def stub_request(headers = {})
ActionDispatch::RemoteIp.new(Proc.new { }, false, Rails.application.config.action_dispatch.trusted_proxies).call(headers)
ActionDispatch::Request.new(headers)
end
def set_trusted_proxies(proxies = [])
stub_config_setting('trusted_proxies' => proxies)
load File.join(__dir__, '../../config/initializers/trusted_proxies.rb')
end
end
......@@ -47,3 +47,9 @@ describe 'MergeRequestWidget', ->
spy = spyOn(@class, 'showCICoverage').and.stub()
@class.getCIStatus(false)
expect(spy).not.toHaveBeenCalled()
it 'should not display a notification on the first check after the widget has been created', ->
spy = spyOn(window, 'notify')
@class = new MergeRequestWidget(@opts)
@class.getCIStatus(true)
expect(spy).not.toHaveBeenCalled()
......@@ -43,7 +43,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
milestone.update_attribute(:title, %{"></a>whatever<a title="})
doc = reference_filter("milestone #{reference}")
expect(doc.text).to eq "milestone #{milestone.title}"
expect(doc.text).to eq "milestone \">whatever"
end
it 'includes default classes' do
......
......@@ -22,6 +22,12 @@ describe Banzai::Filter::SanitizationFilter, lib: true do
expect(filter(act).to_html).to eq exp
end
it 'sanitizes mixed-cased javascript in attributes' do
act = %q(<a href="javaScript:alert('foo')">Text</a>)
exp = '<a>Text</a>'
expect(filter(act).to_html).to eq exp
end
it 'allows whitelisted HTML tags from the user' do
exp = act = "<dl>\n<dt>Term</dt>\n<dd>Definition</dd>\n</dl>"
expect(filter(act).to_html).to eq exp
......
......@@ -8,6 +8,10 @@ describe Banzai::Filter::UploadLinkFilter, lib: true do
project: project
})
raw_filter(doc, contexts)
end
def raw_filter(doc, contexts = {})
described_class.call(doc, contexts)
end
......@@ -70,4 +74,18 @@ describe Banzai::Filter::UploadLinkFilter, lib: true do
expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
end
end
context 'when project context does not exist' do
let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
it 'does not raise error' do
expect { raw_filter(upload_link, project: nil) }.not_to raise_error
end
it 'does not rewrite link' do
doc = raw_filter(upload_link, project: nil)
expect(doc.to_html).to eq upload_link
end
end
end
# == Schema Information
#
# Table name: abuse_reports
#
# id :integer not null, primary key
# reporter_id :integer
# user_id :integer
# message :text
# created_at :datetime
# updated_at :datetime
#
require 'rails_helper'
RSpec.describe AbuseReport, type: :model do
......
# == Schema Information
#
# Table name: application_settings
#
# id :integer not null, primary key
# default_projects_limit :integer
# signup_enabled :boolean
# signin_enabled :boolean
# gravatar_enabled :boolean
# sign_in_text :text
# created_at :datetime
# updated_at :datetime
# home_page_url :string(255)
# default_branch_protection :integer default(2)
# restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null
# default_project_visibility :integer
# default_snippet_visibility :integer
# restricted_signup_domains :text
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
# import_sources :text
# help_page_text :text
# admin_notification_email :string(255)
# shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null
# 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)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
#
require 'spec_helper'
describe ApplicationSetting, models: true do
......
# == Schema Information
#
# Table name: broadcast_messages
#
# id :integer not null, primary key
# message :text not null
# starts_at :datetime
# ends_at :datetime
# created_at :datetime
# updated_at :datetime
# color :string(255)
# font :string(255)
#
require 'spec_helper'
describe BroadcastMessage, models: true do
......
# == Schema Information
#
# Table name: ci_commits
#
# id :integer not null, primary key
# project_id :integer
# ref :string(255)
# sha :string(255)
# before_sha :string(255)
# push_data :text
# created_at :datetime
# updated_at :datetime
# tag :boolean default(FALSE)
# yaml_errors :text
# committed_at :datetime
# gl_project_id :integer
#
require 'spec_helper'
describe Ci::Commit, models: true do
......
# == Schema Information
#
# Table name: ci_runner_projects
#
# id :integer not null, primary key
# runner_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# gl_project_id :integer
#
require 'spec_helper'
describe Ci::RunnerProject, models: true do
......
# == Schema Information
#
# Table name: ci_runners
#
# id :integer not null, primary key
# token :string(255)
# created_at :datetime
# updated_at :datetime
# description :string(255)
# contacted_at :datetime
# active :boolean default(TRUE), not null
# is_shared :boolean default(FALSE)
# name :string(255)
# version :string(255)
# revision :string(255)
# platform :string(255)
# architecture :string(255)
#
require 'spec_helper'
describe Ci::Runner, models: true do
......
# == Schema Information
#
# Table name: ci_triggers
#
# id :integer not null, primary key
# token :string(255)
# project_id :integer
# deleted_at :datetime
# created_at :datetime
# updated_at :datetime
# gl_project_id :integer
#
require 'spec_helper'
describe Ci::Trigger, models: true do
......
# == Schema Information
#
# Table name: ci_variables
#
# id :integer not null, primary key
# project_id :integer
# key :string(255)
# value :text
# encrypted_value :text
# encrypted_value_salt :string(255)
# encrypted_value_iv :string(255)
# gl_project_id :integer
#
require 'spec_helper'
describe Ci::Variable, models: true do
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
# gl_project_id :integer
#
require 'spec_helper'
describe CommitStatus, models: true do
......
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string(255)
# type :string(255)
# fingerprint :string(255)
# public :boolean default(FALSE), not null
#
require 'spec_helper'
describe DeployKey, models: true do
......
# == Schema Information
#
# Table name: deploy_keys_projects
#
# id :integer not null, primary key
# deploy_key_id :integer not null
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper'
describe DeployKeysProject, models: true do
......
# == Schema Information
#
# Table name: emails
#
# id :integer not null, primary key
# user_id :integer not null
# email :string(255) not null
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper'
describe Email, models: true do
......
# == Schema Information
#
# Table name: events
#
# id :integer not null, primary key
# target_type :string(255)
# target_id :integer
# title :string(255)
# data :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
# action :integer
# author_id :integer
#
require 'spec_helper'
describe Event, models: true do
......
# == Schema Information
#
# Table name: forked_project_links
#
# id :integer not null, primary key
# forked_to_project_id :integer not null
# forked_from_project_id :integer not null
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper'
describe ForkedProjectLink, "add link on fork" do
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
# gl_project_id :integer
#
require 'spec_helper'
describe GenericCommitStatus, models: true do
......
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
# path :string(255) not null
# owner_id :integer
# created_at :datetime
# updated_at :datetime
# type :string(255)
# description :string(255) default(""), not null
# avatar :string(255)
#
require 'spec_helper'
describe Group, models: true do
......
# == Schema Information
#
# Table name: identities
#
# id :integer not null, primary key
# extern_uid :string(255)
# provider :string(255)
# user_id :integer
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper'
RSpec.describe Identity, models: true do
......
# == Schema Information
#
# Table name: issues
#
# id :integer not null, primary key
# title :string(255)
# assignee_id :integer
# author_id :integer
# project_id :integer
# created_at :datetime
# updated_at :datetime
# position :integer default(0)
# branch_name :string(255)
# description :text
# milestone_id :integer
# state :string(255)
# iid :integer
# updated_by_id :integer
#
require 'spec_helper'
describe Issue, models: true do
......
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string(255)
# type :string(255)
# fingerprint :string(255)
# public :boolean default(FALSE), not null
#
require 'spec_helper'
describe Key, models: true do
......
# == Schema Information
#
# Table name: label_links
#
# id :integer not null, primary key
# label_id :integer
# target_id :integer
# target_type :string(255)
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper'
describe LabelLink, models: true do
......
# == Schema Information
#
# Table name: labels
#
# id :integer not null, primary key
# title :string(255)
# color :string(255)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# template :boolean default(FALSE)
#
require 'spec_helper'
describe Label, models: true do
......@@ -55,6 +42,14 @@ describe Label, models: true do
end
end
describe "#title" do
let(:label) { create(:label, title: "<b>test</b>") }
it "sanitizes title" do
expect(label.title).to eq("test")
end
end
describe '#to_reference' do
context 'using id' do
it 'returns a String reference to the object' do
......
# == Schema Information
#
# Table name: members
#
# id :integer not null, primary key
# access_level :integer not null
# source_id :integer not null
# source_type :string(255) not null
# user_id :integer
# notification_level :integer not null
# type :string(255)
# created_at :datetime
# updated_at :datetime
# created_by_id :integer
# invite_email :string(255)
# invite_token :string(255)
# invite_accepted_at :datetime
#
require 'spec_helper'
describe Member, models: true do
......
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string(255) not null
# source_branch :string(255) not null
# source_project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string(255)
# created_at :datetime
# updated_at :datetime
# milestone_id :integer
# state :string(255)
# merge_status :string(255)
# target_project_id :integer not null
# iid :integer
# description :text
# position :integer default(0)
# locked_at :datetime
# updated_by_id :integer
# merge_error :string(255)
# merge_params :text
# merge_when_build_succeeds :boolean default(FALSE), not null
# merge_user_id :integer
# merge_commit_sha :string
#
require 'spec_helper'
describe MergeRequest, models: true do
......
# == Schema Information
#
# Table name: milestones
#
# id :integer not null, primary key
# title :string(255) not null
# project_id :integer not null
# description :text
# due_date :date
# created_at :datetime
# updated_at :datetime
# state :string(255)
# iid :integer
#
require 'spec_helper'
describe Milestone, models: true do
......@@ -34,6 +19,14 @@ describe Milestone, models: true do
let(:issue) { create(:issue) }
let(:user) { create(:user) }
describe "#title" do
let(:milestone) { create(:milestone, title: "<b>test</b>") }
it "sanitizes title" do
expect(milestone.title).to eq("test")
end
end
describe "unique milestone title per project" do
it "shouldn't accept the same title in a project twice" do
new_milestone = Milestone.new(project: milestone.project, title: milestone.title)
......
# == Schema Information
#
# Table name: namespaces
#
# id :integer not null, primary key
# name :string(255) not null
# path :string(255) not null
# owner_id :integer
# created_at :datetime
# updated_at :datetime
# type :string(255)
# description :string(255) default(""), not null
# avatar :string(255)
#
require 'spec_helper'
describe Namespace, models: true do
......
# == Schema Information
#
# Table name: notes
#
# id :integer not null, primary key
# note :text
# noteable_type :string(255)
# author_id :integer
# created_at :datetime
# updated_at :datetime
# project_id :integer
# attachment :string(255)
# line_code :string(255)
# commit_id :string(255)
# noteable_id :integer
# system :boolean default(FALSE), not null
# st_diff :text
# updated_by_id :integer
# is_award :boolean default(FALSE), not null
#
require 'spec_helper'
describe Note, models: true do
......
# == Schema Information
#
# Table name: snippets
#
# id :integer not null, primary key
# title :string(255)
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# file_name :string(255)
# type :string(255)
# visibility_level :integer default(0), not null
#
require 'spec_helper'
describe ProjectSnippet, models: true do
......
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255)
# path :string(255)
# description :text
# created_at :datetime
# updated_at :datetime
# creator_id :integer
# issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
# issues_tracker :string(255) default("gitlab"), not null
# issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime
# import_url :string(255)
# visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# avatar :string(255)
# import_status :string(255)
# repository_size :float default(0.0)
# star_count :integer default(0), not null
# import_type :string(255)
# import_source :string(255)
# commit_count :integer default(0)
# 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'
describe Project, models: true do
......
# == Schema Information
#
# Table name: protected_branches
#
# id :integer not null, primary key
# project_id :integer not null
# name :string(255) not null
# created_at :datetime
# updated_at :datetime
# developers_can_push :boolean default(FALSE), not null
#
require 'spec_helper'
describe ProtectedBranch, models: true do
......
# == Schema Information
#
# Table name: releases
#
# id :integer not null, primary key
# tag :string(255)
# description :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
#
require 'rails_helper'
RSpec.describe Release, type: :model do
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
# template :boolean default(FALSE)
# push_events :boolean default(TRUE)
# issues_events :boolean default(TRUE)
# merge_requests_events :boolean default(TRUE)
# tag_push_events :boolean default(TRUE)
# note_events :boolean default(TRUE), not null
# build_events :boolean default(FALSE), not null
#
require 'spec_helper'
describe Service, models: true do
......
# == Schema Information
#
# Table name: snippets
#
# id :integer not null, primary key
# title :string(255)
# content :text
# author_id :integer not null
# project_id :integer
# created_at :datetime
# updated_at :datetime
# file_name :string(255)
# type :string(255)
# visibility_level :integer default(0), not null
#
require 'spec_helper'
describe Snippet, models: true do
......
# == Schema Information
#
# Table name: todos
#
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
# target_id :integer
# target_type :string not null
# author_id :integer
# action :integer not null
# state :string not null
# created_at :datetime
# updated_at :datetime
# note_id :integer
# commit_id :string
#
require 'spec_helper'
describe Todo, models: true do
......
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0)
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# created_at :datetime
# updated_at :datetime
# name :string(255)
# admin :boolean default(FALSE), not null
# projects_limit :integer default(10)
# skype :string(255) default(""), not null
# linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null
# authentication_token :string(255)
# theme_id :integer default(1), not null
# bio :string(255)
# failed_attempts :integer default(0)
# locked_at :datetime
# username :string(255)
# can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null
# state :string(255)
# color_scheme_id :integer default(1), not null
# notification_level :integer default(1), not null
# password_expires_at :datetime
# created_by_id :integer
# last_credential_check_at :datetime
# avatar :string(255)
# confirmation_token :string(255)
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string(255)
# hide_no_ssh_key :boolean default(FALSE)
# website_url :string(255) default(""), not null
# notification_email :string(255)
# hide_no_password :boolean default(FALSE)
# password_automatically_set :boolean default(FALSE)
# location :string(255)
# encrypted_otp_secret :string(255)
# encrypted_otp_secret_iv :string(255)
# encrypted_otp_secret_salt :string(255)
# otp_required_for_login :boolean default(FALSE), not null
# otp_backup_codes :text
# public_email :string(255) default(""), not null
# dashboard :integer default(0)
# project_view :integer default(0)
# consumed_timestep :integer
# layout :integer default(0)
# hide_project_limit :boolean default(FALSE)
# unlock_token :string
# otp_grace_period_started_at :datetime
#
require 'spec_helper'
describe User, models: true do
......
......@@ -39,6 +39,7 @@ describe API::API, api: true do
let!(:empty_milestone) do
create(:milestone, title: '2.0.0', project: project)
end
let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) }
before { project.team << [user, :reporter] }
......@@ -232,8 +233,28 @@ describe API::API, api: true do
end
describe "GET /projects/:id/issues/:issue_id" do
it 'exposes known attributes' do
get api("/projects/#{project.id}/issues/#{issue.id}", user)
expect(response.status).to eq(200)
expect(json_response['id']).to eq(issue.id)
expect(json_response['iid']).to eq(issue.iid)
expect(json_response['project_id']).to eq(issue.project.id)
expect(json_response['title']).to eq(issue.title)
expect(json_response['description']).to eq(issue.description)
expect(json_response['state']).to eq(issue.state)
expect(json_response['created_at']).to be_present
expect(json_response['updated_at']).to be_present
expect(json_response['labels']).to eq(issue.label_names)
expect(json_response['milestone']).to be_a Hash
expect(json_response['assignee']).to be_a Hash
expect(json_response['author']).to be_a Hash
expect(json_response['user_notes_count']).to be(1)
end
it "should return a project issue by id" do
get api("/projects/#{project.id}/issues/#{issue.id}", user)
expect(response.status).to eq(200)
expect(json_response['title']).to eq(issue.title)
expect(json_response['iid']).to eq(issue.iid)
......
......@@ -113,6 +113,34 @@ describe API::API, api: true do
end
describe "GET /projects/:id/merge_requests/:merge_request_id" do
it 'exposes known attributes' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
expect(response.status).to eq(200)
expect(json_response['id']).to eq(merge_request.id)
expect(json_response['iid']).to eq(merge_request.iid)
expect(json_response['project_id']).to eq(merge_request.project.id)
expect(json_response['title']).to eq(merge_request.title)
expect(json_response['description']).to eq(merge_request.description)
expect(json_response['state']).to eq(merge_request.state)
expect(json_response['created_at']).to be_present
expect(json_response['updated_at']).to be_present
expect(json_response['labels']).to eq(merge_request.label_names)
expect(json_response['milestone']).to be_nil
expect(json_response['assignee']).to be_a Hash
expect(json_response['author']).to be_a Hash
expect(json_response['target_branch']).to eq(merge_request.target_branch)
expect(json_response['source_branch']).to eq(merge_request.source_branch)
expect(json_response['upvotes']).to eq(0)
expect(json_response['downvotes']).to eq(0)
expect(json_response['source_project_id']).to eq(merge_request.source_project.id)
expect(json_response['target_project_id']).to eq(merge_request.target_project.id)
expect(json_response['work_in_progress']).to be_falsy
expect(json_response['merge_when_build_succeeds']).to be_falsy
expect(json_response['merge_status']).to eq('can_be_merged')
expect(json_response['user_notes_count']).to be(2)
end
it "should return merge_request" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
expect(response.status).to eq(200)
......
......@@ -506,6 +506,15 @@ describe SystemNoteService, services: true do
end
end
describe '.new_commit_summary' do
it 'escapes HTML titles' do
commit = double(title: '<pre>This is a test</pre>', short_id: '12345678')
escaped = '* 12345678 - &lt;pre&gt;This is a test&lt;&#x2F;pre&gt;'
expect(described_class.new_commit_summary([commit])).to eq([escaped])
end
end
include JiraServiceHelper
describe 'JIRA integration' do
......
......@@ -55,6 +55,25 @@ describe TodoService, services: true do
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
end
context 'when a private group is mentioned' do
let(:group) { create :group, :private }
let(:project) { create :project, :private, group: group }
let(:issue) { create :issue, author: author, project: project, description: group.to_reference }
before do
group.add_owner(author)
group.add_user(member, Gitlab::Access::DEVELOPER)
group.add_user(john_doe, Gitlab::Access::DEVELOPER)
service.new_issue(issue, author)
end
it 'creates a todo for group members' do
should_create_todo(user: member, target: issue)
should_create_todo(user: john_doe, target: issue)
end
end
end
describe '#update_issue' do
......
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