Commit 21e8f43a authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' into 7-4-stable

Conflicts:
	CHANGELOG
	VERSION
parents 477743a1 6280b53f
...@@ -39,3 +39,4 @@ public/assets/ ...@@ -39,3 +39,4 @@ public/assets/
.envrc .envrc
dump.rdb dump.rdb
tags tags
.gitlab_shell_secret
v 7.5.0
- API: Add support for Hipchat (Kevin Houdebert)
- Add time zone configuration on gitlab.yml (Sullivan Senechal)
- Fix LDAP authentication for Git HTTP access
- Fix LDAP config lookup for provider 'ldap'
v 7.4.2 v 7.4.2
- Fix internal snippet exposing for unauthenticated users - Fix internal snippet exposing for unauthenticated users
......
...@@ -101,7 +101,11 @@ For examples of feedback on merge requests please look at already [closed merge ...@@ -101,7 +101,11 @@ For examples of feedback on merge requests please look at already [closed merge
1. Contains functionality we think other users will benefit from too 1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes 1. Doesn't add configuration options since they complicate future changes
1. Changes after submitting the merge request should be in separate commits (no squashing). You will be asked to squash when the review is over, before merging. 1. Changes after submitting the merge request should be in separate commits (no squashing). You will be asked to squash when the review is over, before merging.
1. It conforms to the following style guides 1. It conforms to the following style guides.
If your change touches a line that does not follow the style,
modify the entire line to follow it. This prevents linting tools from generating warnings.
Don't touch neighbouring lines. As an exception, automatic mass refactoring modifications
may leave style non-compliant.
## Style guides ## Style guides
......
...@@ -55,14 +55,8 @@ Since a manual installation is a lot of work and error prone we strongly recomme ...@@ -55,14 +55,8 @@ Since a manual installation is a lot of work and error prone we strongly recomme
## Third-party applications ## Third-party applications
Access GitLab from multiple platforms with applications below. There are a lot of applications and API wrappers for GitLab.
These applications are maintained by contributors, GitLab B.V. does not offer support for them. Find them [on our website](https://about.gitlab.com/applications/).
- [iPhone app](http://gitlabcontrol.com/)
- [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en)
- [Chrome app](https://chrome.google.com/webstore/detail/chrome-gitlab-notifier/eageapgbnjicdjjihgclpclilenjbobi)
- [Command line client](https://github.com/drewblessing/gitlab-cli)
- [Ruby API wrapper](https://github.com/NARKOZ/gitlab)
### New versions ### New versions
......
class Activities class @Activities
constructor: -> constructor: ->
Pager.init 20, true Pager.init 20, true
$(".event_filter_link").bind "click", (event) => $(".event_filter_link").bind "click", (event) =>
...@@ -27,5 +27,3 @@ class Activities ...@@ -27,5 +27,3 @@ class Activities
event_filters.splice index, 1 event_filters.splice index, 1
$.cookie "event_filter", event_filters.join(","), { path: '/' } $.cookie "event_filter", event_filters.join(","), { path: '/' }
@Activities = Activities
class Admin class @Admin
constructor: -> constructor: ->
$('input#user_force_random_password').on 'change', (elem) -> $('input#user_force_random_password').on 'change', (elem) ->
elems = $('#user_password, #user_password_confirmation') elems = $('#user_password, #user_password_confirmation')
...@@ -51,5 +51,3 @@ class Admin ...@@ -51,5 +51,3 @@ class Admin
$('li.group_member').bind 'ajax:success', -> $('li.group_member').bind 'ajax:success', ->
Turbolinks.visit(location.href) Turbolinks.visit(location.href)
@Admin = Admin
class BlobView class @BlobView
constructor: -> constructor: ->
# handle multi-line select # handle multi-line select
handleMultiSelect = (e) -> handleMultiSelect = (e) ->
...@@ -71,6 +71,3 @@ class BlobView ...@@ -71,6 +71,3 @@ class BlobView
# Highlight the correct lines when the hash part of the URL changes # Highlight the correct lines when the hash part of the URL changes
$(window).on("hashchange", highlightBlobLines) $(window).on("hashchange", highlightBlobLines)
@BlobView = BlobView
class Commit class @Commit
constructor: -> constructor: ->
$('.files .diff-file').each -> $('.files .diff-file').each ->
new CommitFile(this) new CommitFile(this)
@Commit = Commit
class CommitFile class @CommitFile
constructor: (file) -> constructor: (file) ->
if $('.image', file).length if $('.image', file).length
new ImageFile(file) new ImageFile(file)
@CommitFile = CommitFile
class ImageFile class @ImageFile
# Width where images must fits in, for 2-up this gets divided by 2 # Width where images must fits in, for 2-up this gets divided by 2
@availWidth = 900 @availWidth = 900
...@@ -124,5 +124,3 @@ class ImageFile ...@@ -124,5 +124,3 @@ class ImageFile
else else
img.on 'load', => img.on 'load', =>
callback.call(this, domImg.naturalWidth, domImg.naturalHeight) callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
@ImageFile = ImageFile
class CommitsList class @CommitsList
@data = @data =
ref: null ref: null
limit: 0 limit: 0
...@@ -53,5 +53,3 @@ class CommitsList ...@@ -53,5 +53,3 @@ class CommitsList
@disable @disable
callback: => callback: =>
this.getOld() this.getOld()
this.CommitsList = CommitsList
class ConfirmDangerModal class @ConfirmDangerModal
constructor: (form, text) -> constructor: (form, text) ->
@form = form @form = form
$('.js-confirm-text').text(text || '') $('.js-confirm-text').text(text || '')
...@@ -16,5 +16,3 @@ class ConfirmDangerModal ...@@ -16,5 +16,3 @@ class ConfirmDangerModal
$('.js-confirm-danger-submit').on 'click', => $('.js-confirm-danger-submit').on 'click', =>
@form.submit() @form.submit()
@ConfirmDangerModal = ConfirmDangerModal
class Dashboard class @Dashboard
constructor: -> constructor: ->
@initSidebarTab() @initSidebarTab()
...@@ -28,6 +28,3 @@ class Dashboard ...@@ -28,6 +28,3 @@ class Dashboard
# show tab from cookie # show tab from cookie
sidebar_filter = $.cookie(key) sidebar_filter = $.cookie(key)
$("#" + sidebar_filter).tab('show') if sidebar_filter $("#" + sidebar_filter).tab('show') if sidebar_filter
@Dashboard = Dashboard
class Diff class @Diff
UNFOLD_COUNT = 20 UNFOLD_COUNT = 20
constructor: -> constructor: ->
$(document).on('click', '.js-unfold', (event) => $(document).on('click', '.js-unfold', (event) =>
...@@ -41,6 +41,3 @@ class Diff ...@@ -41,6 +41,3 @@ class Diff
lines = line.children().slice(0, 2) lines = line.children().slice(0, 2)
line_numbers = ($(l).attr('data-linenumber') for l in lines) line_numbers = ($(l).attr('data-linenumber') for l in lines)
(parseInt(line_number) for line_number in line_numbers) (parseInt(line_number) for line_number in line_numbers)
@Diff = Diff
...@@ -67,6 +67,8 @@ class Dispatcher ...@@ -67,6 +67,8 @@ class Dispatcher
new TeamMembers() new TeamMembers()
when 'groups:members' when 'groups:members'
new GroupMembers() new GroupMembers()
when 'groups:new', 'groups:edit', 'admin:groups:edit'
new GroupAvatar()
when 'projects:tree:show' when 'projects:tree:show'
new TreeView() new TreeView()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
......
class Flash class @Flash
constructor: (message, type)-> constructor: (message, type)->
flash = $(".flash-container") flash = $(".flash-container")
flash.html("") flash.html("")
...@@ -10,5 +10,3 @@ class Flash ...@@ -10,5 +10,3 @@ class Flash
flash.click -> $(@).fadeOut() flash.click -> $(@).fadeOut()
flash.show() flash.show()
@Flash = Flash
class @GroupAvatar
constructor: ->
$('.js-choose-group-avatar-button').bind "click", ->
form = $(this).closest("form")
form.find(".js-group-avatar-input").click()
$('.js-group-avatar-input').bind "change", ->
form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find(".js-avatar-filename").text(filename)
class GroupMembers class @GroupMembers
constructor: -> constructor: ->
$('li.group_member').bind 'ajax:success', -> $('li.group_member').bind 'ajax:success', ->
$(this).fadeOut() $(this).fadeOut()
@GroupMembers = GroupMembers
$ ->
# avatar
$('.js-choose-group-avatar-button').bind "click", ->
form = $(this).closest("form")
form.find(".js-group-avatar-input").click()
$('.js-group-avatar-input').bind "change", ->
form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find(".js-avatar-filename").text(filename)
class Issue class @Issue
constructor: -> constructor: ->
$('.edit-issue.inline-update input[type="submit"]').hide() $('.edit-issue.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", -> $(".issue-box .inline-update").on "change", "select", ->
...@@ -15,5 +15,3 @@ class Issue ...@@ -15,5 +15,3 @@ class Issue
"issue" "issue"
updateTaskState updateTaskState
) )
@Issue = Issue
class Labels class @Labels
constructor: -> constructor: ->
form = $('.label-form') form = $('.label-form')
@setupLabelForm(form) @setupLabelForm(form)
...@@ -31,5 +31,3 @@ class Labels ...@@ -31,5 +31,3 @@ class Labels
# Notify the form, that color has changed # Notify the form, that color has changed
$('.label-form').trigger('keyup') $('.label-form').trigger('keyup')
e.preventDefault() e.preventDefault()
@Labels = Labels
class MergeRequest class @MergeRequest
constructor: (@opts) -> constructor: (@opts) ->
@initContextWidget() @initContextWidget()
this.$el = $('.merge-request') this.$el = $('.merge-request')
...@@ -132,5 +132,3 @@ class MergeRequest ...@@ -132,5 +132,3 @@ class MergeRequest
this.$('.automerge_widget').hide() this.$('.automerge_widget').hide()
this.$('.merge-in-progress').hide() this.$('.merge-in-progress').hide()
this.$('.automerge_widget.already_cannot_be_merged').show() this.$('.automerge_widget.already_cannot_be_merged').show()
this.MergeRequest = MergeRequest
class Milestone class @Milestone
@updateIssue: (li, issue_url, data) -> @updateIssue: (li, issue_url, data) ->
$.ajax $.ajax
type: "PUT" type: "PUT"
...@@ -115,5 +115,3 @@ class Milestone ...@@ -115,5 +115,3 @@ class Milestone
Milestone.updateMergeRequest(ui.item, merge_request_url, data) Milestone.updateMergeRequest(ui.item, merge_request_url, data)
).disableSelection() ).disableSelection()
@Milestone = Milestone
class Notes class @Notes
@interval: null @interval: null
constructor: (notes_url, note_ids, last_fetched_at) -> constructor: (notes_url, note_ids, last_fetched_at) ->
...@@ -514,7 +514,3 @@ class Notes ...@@ -514,7 +514,3 @@ class Notes
else else
form.find('.js-note-target-reopen').text('Reopen') form.find('.js-note-target-reopen').text('Reopen')
form.find('.js-note-target-close').text('Close') form.find('.js-note-target-close').text('Close')
@Notes = Notes
class NotesVotes class @NotesVotes
updateVotes: -> updateVotes: ->
votes = $("#votes .votes") votes = $("#votes .votes")
notes = $("#notes-list .note .vote") notes = $("#notes-list .note .vote")
...@@ -18,5 +18,3 @@ class NotesVotes ...@@ -18,5 +18,3 @@ class NotesVotes
# replace vote numbers # replace vote numbers
votes.find(".upvotes").text votes.find(".upvotes").text().replace(/\d+/, upvotes) votes.find(".upvotes").text votes.find(".upvotes").text().replace(/\d+/, upvotes)
votes.find(".downvotes").text votes.find(".downvotes").text().replace(/\d+/, downvotes) votes.find(".downvotes").text votes.find(".downvotes").text().replace(/\d+/, downvotes)
@NotesVotes = NotesVotes
class Project class @Project
constructor: -> constructor: ->
$('.project-edit-container').on 'ajax:before', => $('.project-edit-container').on 'ajax:before', =>
$('.project-edit-container').hide() $('.project-edit-container').hide()
...@@ -24,9 +24,6 @@ class Project ...@@ -24,9 +24,6 @@ class Project
else else
$('#project_issues_tracker_id').removeAttr('disabled') $('#project_issues_tracker_id').removeAttr('disabled')
@Project = Project
$ -> $ ->
# Git clone panel switcher # Git clone panel switcher
scope = $ '.git-clone-holder' scope = $ '.git-clone-holder'
......
class ProjectImport class @ProjectImport
constructor: -> constructor: ->
setTimeout -> setTimeout ->
Turbolinks.visit(location.href) Turbolinks.visit(location.href)
, 5000 , 5000
@ProjectImport = ProjectImport
class SearchAutocomplete class @SearchAutocomplete
constructor: (search_autocomplete_path, project_id, project_ref) -> constructor: (search_autocomplete_path, project_id, project_ref) ->
project_id = '' unless project_id project_id = '' unless project_id
project_ref = '' unless project_ref project_ref = '' unless project_ref
...@@ -9,5 +9,3 @@ class SearchAutocomplete ...@@ -9,5 +9,3 @@ class SearchAutocomplete
minLength: 1 minLength: 1
select: (event, ui) -> select: (event, ui) ->
location.href = ui.item.url location.href = ui.item.url
@SearchAutocomplete = SearchAutocomplete
class window.StatGraph class @StatGraph
@log: {} @log: {}
@get_log: -> @get_log: ->
@log @log
......
class window.ContributorsStatGraph class @ContributorsStatGraph
init: (log) -> init: (log) ->
@parsed_log = ContributorsStatGraphUtil.parse_log(log) @parsed_log = ContributorsStatGraphUtil.parse_log(log)
@set_current_field("commits") @set_current_field("commits")
......
class window.ContributorsGraph class @ContributorsGraph
MARGIN: MARGIN:
top: 20 top: 20
right: 20 right: 20
...@@ -44,7 +44,7 @@ class window.ContributorsGraph ...@@ -44,7 +44,7 @@ class window.ContributorsGraph
set_data: (data) -> set_data: (data) ->
@data = data @data = data
class window.ContributorsMasterGraph extends ContributorsGraph class @ContributorsMasterGraph extends ContributorsGraph
constructor: (@data) -> constructor: (@data) ->
@width = $('.container').width() - 70 @width = $('.container').width() - 70
@height = 200 @height = 200
...@@ -117,7 +117,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph ...@@ -117,7 +117,7 @@ class window.ContributorsMasterGraph extends ContributorsGraph
@svg.select("path").attr("d", @area) @svg.select("path").attr("d", @area)
@svg.select(".y.axis").call(@y_axis) @svg.select(".y.axis").call(@y_axis)
class window.ContributorsAuthorGraph extends ContributorsGraph class @ContributorsAuthorGraph extends ContributorsGraph
constructor: (@data) -> constructor: (@data) ->
@width = $('.container').width()/2 - 100 @width = $('.container').width()/2 - 100
@height = 200 @height = 200
......
class TeamMembers class @TeamMembers
constructor: -> constructor: ->
$('.team-members .project-access-select').on "change", -> $('.team-members .project-access-select').on "change", ->
$(this.form).submit() $(this.form).submit()
@TeamMembers = TeamMembers
class TreeView class @TreeView
constructor: -> constructor: ->
@initKeyNav() @initKeyNav()
...@@ -39,5 +39,3 @@ class TreeView ...@@ -39,5 +39,3 @@ class TreeView
else if e.which is 13 else if e.which is 13
path = $('.tree-item.selected .tree-item-file-name a').attr('href') path = $('.tree-item.selected .tree-item-file-name a').attr('href')
Turbolinks.visit(path) Turbolinks.visit(path)
@TreeView = TreeView
class Wikis class @Wikis
constructor: -> constructor: ->
$('.build-new-wiki').bind "click", -> $('.build-new-wiki').bind "click", ->
field = $('#new_wiki_path') field = $('#new_wiki_path')
...@@ -7,6 +7,3 @@ class Wikis ...@@ -7,6 +7,3 @@ class Wikis
if(slug.length > 0) if(slug.length > 0)
location.href = path + "/" + slug location.href = path + "/" + slug
@Wikis = Wikis
/** Typo **/ /** Typo **/
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; $monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif; $regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
} }
.participants { .participants {
margin-bottom: 10px; margin-bottom: 20px;
} }
.issues_bulk_update { .issues_bulk_update {
......
...@@ -113,30 +113,36 @@ ...@@ -113,30 +113,36 @@
font-size: 15px; font-size: 15px;
border-bottom: 1px solid #BBB; border-bottom: 1px solid #BBB;
color: #777; color: #777;
background-color: #F5F5F5;
&.ci-success { &.ci-success {
color: $bg_success; color: $bg_success;
border-color: $border_success; border-color: $border_success;
background-color: #F1FAF1;
} }
&.ci-pending { &.ci-pending {
color: #548; color: #548;
border-color: #548; border-color: #548;
background-color: #F4F1FA;
} }
&.ci-running { &.ci-running {
color: $bg_warning; color: $bg_warning;
border-color: $border_warning; border-color: $border_warning;
background-color: #FAF5F1;
} }
&.ci-failed { &.ci-failed {
color: $bg_danger; color: $bg_danger;
border-color: $border_danger; border-color: $border_danger;
background-color: #FAF1F1;
} }
&.ci-error { &.ci-error {
color: $bg_danger; color: $bg_danger;
border-color: $border_danger; border-color: $border_danger;
background-color: #FAF1F1;
} }
} }
......
...@@ -31,17 +31,11 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -31,17 +31,11 @@ class Admin::ProjectsController < Admin::ApplicationController
protected protected
def project def project
id = params[:project_id] || params[:id] @project = Project.find_with_namespace(params[:id])
@project = Project.find_with_namespace(id)
@project || render_404 @project || render_404
end end
def group def group
@group ||= project.group @group ||= @project.group
end
def repository
@repository ||= project.repository
end end
end end
...@@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base ...@@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base
before_filter :check_password_expiration before_filter :check_password_expiration
before_filter :add_abilities before_filter :add_abilities
before_filter :ldap_security_check before_filter :ldap_security_check
before_filter :dev_tools if Rails.env == 'development'
before_filter :default_headers before_filter :default_headers
before_filter :add_gon_variables before_filter :add_gon_variables
before_filter :configure_permitted_parameters, if: :devise_controller? before_filter :configure_permitted_parameters, if: :devise_controller?
...@@ -81,6 +80,7 @@ class ApplicationController < ActionController::Base ...@@ -81,6 +80,7 @@ class ApplicationController < ActionController::Base
end end
def project def project
unless @project
id = params[:project_id] || params[:id] id = params[:project_id] || params[:id]
# Redirect from # Redirect from
...@@ -104,6 +104,8 @@ class ApplicationController < ActionController::Base ...@@ -104,6 +104,8 @@ class ApplicationController < ActionController::Base
render_404 and return render_404 and return
end end
end end
@project
end
def repository def repository
@repository ||= project.repository @repository ||= project.repository
...@@ -119,14 +121,6 @@ class ApplicationController < ActionController::Base ...@@ -119,14 +121,6 @@ class ApplicationController < ActionController::Base
return access_denied! unless can?(current_user, action, project) return access_denied! unless can?(current_user, action, project)
end end
def authorize_code_access!
return access_denied! unless can?(current_user, :download_code, project)
end
def authorize_push!
return access_denied! unless can?(current_user, :push_code, project)
end
def authorize_labels! def authorize_labels!
# Labels should be accessible for issues and/or merge requests # Labels should be accessible for issues and/or merge requests
authorize_read_issue! || authorize_read_merge_request! authorize_read_issue! || authorize_read_merge_request!
...@@ -170,9 +164,6 @@ class ApplicationController < ActionController::Base ...@@ -170,9 +164,6 @@ class ApplicationController < ActionController::Base
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end end
def dev_tools
end
def default_headers def default_headers
headers['X-Frame-Options'] = 'DENY' headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block' headers['X-XSS-Protection'] = '1; mode=block'
......
...@@ -2,7 +2,7 @@ class Projects::BaseTreeController < Projects::ApplicationController ...@@ -2,7 +2,7 @@ class Projects::BaseTreeController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
end end
...@@ -4,7 +4,7 @@ class Projects::BlameController < Projects::ApplicationController ...@@ -4,7 +4,7 @@ class Projects::BlameController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
......
...@@ -4,9 +4,9 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -4,9 +4,9 @@ class Projects::BlobController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_push!, only: [:destroy] before_filter :authorize_push_code!, only: [:destroy]
before_filter :blob before_filter :blob
......
...@@ -3,8 +3,8 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -3,8 +3,8 @@ class Projects::BranchesController < Projects::ApplicationController
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :authorize_push!, only: [:create, :destroy] before_filter :authorize_push_code!, only: [:create, :destroy]
def index def index
@sort = params[:sort] || 'name' @sort = params[:sort] || 'name'
......
...@@ -4,19 +4,19 @@ ...@@ -4,19 +4,19 @@
class Projects::CommitController < Projects::ApplicationController class Projects::CommitController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :commit before_filter :commit
def show def show
return git_not_found! unless @commit return git_not_found! unless @commit
@line_notes = project.notes.for_commit_id(commit.id).inline @line_notes = @project.notes.for_commit_id(commit.id).inline
@branches = project.repository.branch_names_contains(commit.id) @branches = @project.repository.branch_names_contains(commit.id)
@diffs = @commit.diffs @diffs = @commit.diffs
@note = project.build_commit_note(commit) @note = @project.build_commit_note(commit)
@notes_count = project.notes.for_commit_id(commit.id).count @notes_count = @project.notes.for_commit_id(commit.id).count
@notes = project.notes.for_commit_id(@commit.id).not_inline.fresh @notes = @project.notes.for_commit_id(@commit.id).not_inline.fresh
@noteable = @commit @noteable = @commit
@comments_allowed = @reply_allowed = true @comments_allowed = @reply_allowed = true
@comments_target = { @comments_target = {
...@@ -32,6 +32,6 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -32,6 +32,6 @@ class Projects::CommitController < Projects::ApplicationController
end end
def commit def commit
@commit ||= project.repository.commit(params[:id]) @commit ||= @project.repository.commit(params[:id])
end end
end end
...@@ -5,7 +5,7 @@ class Projects::CommitsController < Projects::ApplicationController ...@@ -5,7 +5,7 @@ class Projects::CommitsController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
......
class Projects::CompareController < Projects::ApplicationController class Projects::CompareController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def index def index
......
...@@ -42,7 +42,7 @@ class Projects::DeployKeysController < Projects::ApplicationController ...@@ -42,7 +42,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
end end
def enable def enable
project.deploy_keys << available_keys.find(params[:id]) @project.deploy_keys << available_keys.find(params[:id])
redirect_to project_deploy_keys_path(@project) redirect_to project_deploy_keys_path(@project)
end end
......
class Projects::EditTreeController < Projects::BaseTreeController class Projects::EditTreeController < Projects::BaseTreeController
before_filter :require_branch_head before_filter :require_branch_head
before_filter :blob before_filter :blob
before_filter :authorize_push! before_filter :authorize_push_code!
before_filter :from_merge_request before_filter :from_merge_request
before_filter :after_edit_path before_filter :after_edit_path
......
class Projects::GraphsController < Projects::ApplicationController class Projects::GraphsController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
......
...@@ -4,7 +4,7 @@ class Projects::NetworkController < Projects::ApplicationController ...@@ -4,7 +4,7 @@ class Projects::NetworkController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
......
class Projects::NewTreeController < Projects::BaseTreeController class Projects::NewTreeController < Projects::BaseTreeController
before_filter :require_branch_head before_filter :require_branch_head
before_filter :authorize_push! before_filter :authorize_push_code!
def show def show
end end
......
...@@ -4,7 +4,7 @@ class Projects::RawController < Projects::ApplicationController ...@@ -4,7 +4,7 @@ class Projects::RawController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
......
...@@ -3,7 +3,7 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -3,7 +3,7 @@ class Projects::RefsController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def switch def switch
......
class Projects::RepositoriesController < Projects::ApplicationController class Projects::RepositoriesController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
def archive def archive
......
...@@ -3,8 +3,8 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -3,8 +3,8 @@ class Projects::TagsController < Projects::ApplicationController
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :authorize_code_access! before_filter :authorize_download_code!
before_filter :authorize_push!, only: [:create] before_filter :authorize_push_code!, only: [:create]
before_filter :authorize_admin_project!, only: [:destroy] before_filter :authorize_admin_project!, only: [:destroy]
def index def index
......
...@@ -10,7 +10,7 @@ class Projects::TeamMembersController < Projects::ApplicationController ...@@ -10,7 +10,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end end
def new def new
@user_project_relation = project.project_members.new @user_project_relation = @project.project_members.new
end end
def create def create
...@@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController ...@@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end end
def update def update
@user_project_relation = project.project_members.find_by(user_id: member) @user_project_relation = @project.project_members.find_by(user_id: member)
@user_project_relation.update_attributes(member_params) @user_project_relation.update_attributes(member_params)
unless @user_project_relation.valid? unless @user_project_relation.valid?
...@@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController ...@@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end end
def destroy def destroy
@user_project_relation = project.project_members.find_by(user_id: member) @user_project_relation = @project.project_members.find_by(user_id: member)
@user_project_relation.destroy @user_project_relation.destroy
respond_to do |format| respond_to do |format|
...@@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController ...@@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end end
def leave def leave
project.project_members.find_by(user_id: current_user).destroy @project.project_members.find_by(user_id: current_user).destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to :back } format.html { redirect_to :back }
......
...@@ -6,7 +6,6 @@ class ProjectsController < ApplicationController ...@@ -6,7 +6,6 @@ class ProjectsController < ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project!, except: [:index, :new, :create] before_filter :authorize_read_project!, except: [:index, :new, :create]
before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import] before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import]
before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
layout 'navless', only: [:new, :create, :fork] layout 'navless', only: [:new, :create, :fork]
before_filter :set_title, only: [:new, :create] before_filter :set_title, only: [:new, :create]
...@@ -76,7 +75,7 @@ class ProjectsController < ApplicationController ...@@ -76,7 +75,7 @@ class ProjectsController < ApplicationController
end end
def import def import
if project.import_finished? if @project.import_finished?
redirect_to @project redirect_to @project
return return
end end
...@@ -98,7 +97,7 @@ class ProjectsController < ApplicationController ...@@ -98,7 +97,7 @@ class ProjectsController < ApplicationController
end end
def destroy def destroy
return access_denied! unless can?(current_user, :remove_project, project) return access_denied! unless can?(current_user, :remove_project, @project)
::Projects::DestroyService.new(@project, current_user, {}).execute ::Projects::DestroyService.new(@project, current_user, {}).execute
...@@ -148,8 +147,8 @@ class ProjectsController < ApplicationController ...@@ -148,8 +147,8 @@ class ProjectsController < ApplicationController
end end
def archive def archive
return access_denied! unless can?(current_user, :archive_project, project) return access_denied! unless can?(current_user, :archive_project, @project)
project.archive! @project.archive!
respond_to do |format| respond_to do |format|
format.html { redirect_to @project } format.html { redirect_to @project }
...@@ -157,8 +156,8 @@ class ProjectsController < ApplicationController ...@@ -157,8 +156,8 @@ class ProjectsController < ApplicationController
end end
def unarchive def unarchive
return access_denied! unless can?(current_user, :archive_project, project) return access_denied! unless can?(current_user, :archive_project, @project)
project.unarchive! @project.unarchive!
respond_to do |format| respond_to do |format|
format.html { redirect_to @project } format.html { redirect_to @project }
......
...@@ -80,7 +80,7 @@ class Note < ActiveRecord::Base ...@@ -80,7 +80,7 @@ class Note < ActiveRecord::Base
note_options = { note_options = {
project: project, project: project,
author: author, author: author,
note: "_mentioned in #{gfm_reference}_", note: cross_reference_note_content(gfm_reference),
system: true system: true
} }
...@@ -174,7 +174,7 @@ class Note < ActiveRecord::Base ...@@ -174,7 +174,7 @@ class Note < ActiveRecord::Base
where(noteable_id: noteable.id) where(noteable_id: noteable.id)
end end
notes.where('note like ?', "_mentioned in #{gfm_reference}_"). notes.where('note like ?', cross_reference_note_content(gfm_reference)).
system.any? system.any?
end end
...@@ -182,8 +182,16 @@ class Note < ActiveRecord::Base ...@@ -182,8 +182,16 @@ class Note < ActiveRecord::Base
where("note like :query", query: "%#{query}%") where("note like :query", query: "%#{query}%")
end end
def cross_reference_note_prefix
'_mentioned in '
end
private private
def cross_reference_note_content(gfm_reference)
cross_reference_note_prefix + "#{gfm_reference}_"
end
# Prepend the mentioner's namespaced project path to the GFM reference for # Prepend the mentioner's namespaced project path to the GFM reference for
# cross-project references. For same-project references, return the # cross-project references. For same-project references, return the
# unmodified GFM reference. # unmodified GFM reference.
...@@ -249,6 +257,10 @@ class Note < ActiveRecord::Base ...@@ -249,6 +257,10 @@ class Note < ActiveRecord::Base
nil nil
end end
def cross_reference?
note.start_with?(self.class.cross_reference_note_prefix)
end
def find_diff def find_diff
return nil unless noteable && noteable.diffs.present? return nil unless noteable && noteable.diffs.present?
......
...@@ -173,7 +173,7 @@ class Project < ActiveRecord::Base ...@@ -173,7 +173,7 @@ class Project < ActiveRecord::Base
end end
def with_push def with_push
includes(:events).where('events.action = ?', Event::PUSHED) joins(:events).where('events.action = ?', Event::PUSHED)
end end
def active def active
......
...@@ -119,7 +119,7 @@ class NotificationService ...@@ -119,7 +119,7 @@ class NotificationService
# ignore gitlab service messages # ignore gitlab service messages
return true if note.note =~ /\A_Status changed to closed_/ return true if note.note =~ /\A_Status changed to closed_/
return true if note.note =~ /\A_mentioned in / && note.system == true return true if note.cross_reference? && note.system == true
opts = { noteable_type: note.noteable_type, project_id: note.project_id } opts = { noteable_type: note.noteable_type, project_id: note.project_id }
......
...@@ -2,39 +2,20 @@ ...@@ -2,39 +2,20 @@
- if @group.errors.any? - if @group.errors.any?
.alert.alert-danger .alert.alert-danger
%span= @group.errors.full_messages.first %span= @group.errors.full_messages.first
.form-group.group_name_holder
= f.label :name, class: 'control-label' do
Group name
.col-sm-10
= f.text_field :name, placeholder: "Example Group", class: "form-control"
.form-group.group-description-holder = render 'shared/group_form', f: f
= f.label :description, "Details", class: 'control-label'
.col-sm-10
= f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
.form-group.group-description-holder .form-group.group-description-holder
= f.label :avatar, "Group avatar", class: 'control-label' = f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10 .col-sm-10
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button = render 'shared/choose_group_avatar_button', f: f
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: "js-group-avatar-input hidden"
.light The maximum file size allowed is 100KB.
- if @group.new_record? - if @group.new_record?
.form-group .form-group
.col-sm-2 .col-sm-2
.col-sm-10 .col-sm-10
.bs-callout.bs-callout-info .bs-callout.bs-callout-info
%ul = render 'shared/group_tips'
%li A group is a collection of several projects
%li Groups are private by default
%li Members of a group may only view projects they have permission to access
%li Group project URLs are prefixed with the group namespace
%li Existing projects may be moved into a group
.form-actions .form-actions
= f.submit 'Create group', class: "btn btn-create" = f.submit 'Create group', class: "btn btn-create"
= link_to 'Cancel', admin_groups_path, class: "btn btn-cancel" = link_to 'Cancel', admin_groups_path, class: "btn btn-cancel"
......
- loggers = [Gitlab::GitLogger, Gitlab::AppLogger,
Gitlab::ProductionLogger, Gitlab::SidekiqLogger]
%ul.nav.nav-tabs.log-tabs %ul.nav.nav-tabs.log-tabs
%li.active - loggers.each do |klass|
= link_to "githost.log", "#githost", 'data-toggle' => 'tab' %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') }
%li = link_to klass::file_name, "##{klass::file_name_noext}",
= link_to "application.log", "#application", 'data-toggle' => 'tab' 'data-toggle' => 'tab'
%li
= link_to "production.log", "#production", 'data-toggle' => 'tab'
%li
= link_to "sidekiq.log", "#sidekiq", 'data-toggle' => 'tab'
%p.light To prevent performance issues admin logs output the last 2000 lines %p.light To prevent performance issues admin logs output the last 2000 lines
.tab-content .tab-content
.tab-pane.active#githost - loggers.each do |klass|
.file-holder#README .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''),
.file-title id: klass::file_name_noext }
%i.fa.fa-file
githost.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
- Gitlab::GitLogger.read_latest.each do |line|
%li
%p= line
.tab-pane#application
.file-holder#README
.file-title
%i.fa.fa-file
application.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
- Gitlab::AppLogger.read_latest.each do |line|
%li
%p= line
.tab-pane#production
.file-holder#README
.file-title
%i.fa.fa-file
production.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
- Gitlab::Logger.read_latest_for('production.log').each do |line|
%li
%p= line
.tab-pane#sidekiq
.file-holder#README .file-holder#README
.file-title .file-title
%i.fa.fa-file %i.fa.fa-file
sidekiq.log = klass::file_name
.pull-right .pull-right
= link_to '#', class: 'log-bottom' do = link_to '#', class: 'log-bottom' do
%i.fa.fa-arrow-down %i.fa.fa-arrow-down
Scroll down Scroll down
.file-content.logs .file-content.logs
%ol %ol
- Gitlab::Logger.read_latest_for('sidekiq.log').each do |line| - klass.read_latest.each do |line|
%li %li
%p= line %p= line
...@@ -46,5 +46,5 @@ ...@@ -46,5 +46,5 @@
%br %br
Public projects are an easy way to allow everyone to have read-only access. Public projects are an easy way to allow everyone to have read-only access.
.link_holder .link_holder
= link_to explore_projects_path, class: "btn btn-new" do = link_to trending_explore_projects_path, class: "btn btn-new" do
Browse public projects » Browse public projects »
...@@ -11,16 +11,7 @@ ...@@ -11,16 +11,7 @@
- if @group.errors.any? - if @group.errors.any?
.alert.alert-danger .alert.alert-danger
%span= @group.errors.full_messages.first %span= @group.errors.full_messages.first
.form-group = render 'shared/group_form', f: f
= f.label :name, class: 'control-label' do
Group name
.col-sm-10
= f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control left"
.form-group.group-description-holder
= f.label :description, "Details", class: 'control-label'
.col-sm-10
= f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
.form-group .form-group
.col-sm-2 .col-sm-2
...@@ -31,13 +22,7 @@ ...@@ -31,13 +22,7 @@
You can change your group avatar here You can change your group avatar here
- else - else
You can upload a group avatar here You can upload a group avatar here
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button = render 'shared/choose_group_avatar_button', f: f
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: "js-group-avatar-input hidden"
.light The maximum file size allowed is 100KB.
- if @group.avatar? - if @group.avatar?
%hr %hr
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar" = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
......
...@@ -2,37 +2,18 @@ ...@@ -2,37 +2,18 @@
- if @group.errors.any? - if @group.errors.any?
.alert.alert-danger .alert.alert-danger
%span= @group.errors.full_messages.first %span= @group.errors.full_messages.first
.form-group
= f.label :name, class: 'control-label' do
Group name
.col-sm-10
= f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control", tabindex: 1, autofocus: true
.form-group.group-description-holder = render 'shared/group_form', f: f, autofocus: true
= f.label :description, "Details", class: 'control-label'
.col-sm-10
= f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4, tabindex: 2
.form-group.group-description-holder .form-group.group-description-holder
= f.label :avatar, "Group avatar", class: 'control-label' = f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10 .col-sm-10
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button = render 'shared/choose_group_avatar_button', f: f
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: "js-group-avatar-input hidden"
.light The maximum file size allowed is 100KB.
.form-group .form-group
.col-sm-2 .col-sm-2
.col-sm-10 .col-sm-10
%ul = render 'shared/group_tips'
%li A group is a collection of several projects
%li Groups are private by default
%li Members of a group may only view projects they have permission to access
%li Group project URLs are prefixed with the group namespace
%li Existing projects may be moved into a group
.form-actions .form-actions
= f.submit 'Create group', class: "btn btn-create", tabindex: 3 = f.submit 'Create group', class: "btn btn-create", tabindex: 3
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
= hidden_field_tag :issue_context = hidden_field_tag :issue_context
= f.submit class: 'btn' = f.submit class: 'btn'
- elsif issue.milestone - elsif issue.milestone
= link_to issue.milestone.title, project_milestone_path = link_to project_milestone_path(@project, @issue.milestone) do
= @issue.milestone.title
- else - else
None None
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
= f.file_field :avatar, class: 'js-group-avatar-input hidden'
.light The maximum file size allowed is 100KB.
.form-group
= f.label :name, class: 'control-label' do
Group name
.col-sm-10
= f.text_field :name, placeholder: 'Example Group', class: 'form-control',
autofocus: local_assigns[:autofocus] || false
.form-group.group-description-holder
= f.label :description, 'Details', class: 'control-label'
.col-sm-10
= f.text_area :description, maxlength: 250,
class: 'form-control js-gfm-input', rows: 4
%ul
%li A group is a collection of several projects
%li Groups are private by default
%li Members of a group may only view projects they have permission to access
%li Group project URLs are prefixed with the group namespace
%li Existing projects may be moved into a group
- groups.each do |group| - groups.each do |group|
= link_to group, class: 'profile-groups-avatars', :title => group.name do = link_to group, class: 'profile-groups-avatars', :title => group.name do
= image_tag group_icon(group.path) - image_tag group_icon(group.path)
...@@ -13,7 +13,6 @@ module Gitlab ...@@ -13,7 +13,6 @@ module Gitlab
# Custom directories with classes and modules you want to be autoloadable. # Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib config.autoload_paths += %W(#{config.root}/lib
#{config.root}/app/finders
#{config.root}/app/models/hooks #{config.root}/app/models/hooks
#{config.root}/app/models/concerns #{config.root}/app/models/concerns
#{config.root}/app/models/project_services #{config.root}/app/models/project_services
...@@ -25,6 +24,7 @@ module Gitlab ...@@ -25,6 +24,7 @@ module Gitlab
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# NOTE: Please prefer set time zone on config/gitlab.yml configuration file.
# config.time_zone = 'Central Time (US & Canada)' # config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
......
...@@ -33,6 +33,11 @@ production: &base ...@@ -33,6 +33,11 @@ production: &base
# Uncomment and customize if you can't use the default user to run GitLab (default: 'git') # Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
# user: git # user: git
## Date & Time settings
# Uncomment and customize if you want to change the default time zone of GitLab application.
# To see all available zones, run `bundle exec rake time:zones:all`
# time_zone: 'UTC'
## Email settings ## Email settings
# Email address used in the "From" field in mails sent by GitLab # Email address used in the "From" field in mails sent by GitLab
email_from: example@example.com email_from: example@example.com
......
...@@ -103,6 +103,7 @@ Settings.gitlab['user_home'] ||= begin ...@@ -103,6 +103,7 @@ Settings.gitlab['user_home'] ||= begin
rescue ArgumentError # no user configured rescue ArgumentError # no user configured
'/home/' + Settings.gitlab['user'] '/home/' + Settings.gitlab['user']
end end
Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= false Settings.gitlab['signup_enabled'] ||= false
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
......
# Be sure to restart your server when you modify this file.
require 'securerandom'
# Your secret key for verifying the gitlab_shell.
secret_file = Rails.root.join('.gitlab_shell_secret')
gitlab_shell_symlink = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret')
unless File.exist? secret_file
# Generate a new token of 16 random hexadecimal characters and store it in secret_file.
token = SecureRandom.hex(16)
File.write(secret_file, token)
end
if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(gitlab_shell_symlink)
FileUtils.symlink(secret_file, gitlab_shell_symlink)
end
\ No newline at end of file
Time.zone = Gitlab.config.gitlab.time_zone || Time.zone
...@@ -21,13 +21,7 @@ ...@@ -21,13 +21,7 @@
## Clients ## Clients
- [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP Find API Clients for GitLab [on our website](https://about.gitlab.com/applications/#api-clients).
- [Laravel API Wrapper for GitLab CE](https://github.com/adamgoose/gitlab) - PHP / [Laravel](http://laravel.com)
- [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
- [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
- [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
- [node-gitlab](https://github.com/moul/node-gitlab) - Node.js
- [NGitLab](https://github.com/Scooletz/NGitLab) - .NET
## Introduction ## Introduction
......
# Services
## GitLab CI
### Edit GitLab CI service
Set GitLab CI service for a project.
```
PUT /projects/:id/services/gitlab-ci
```
Parameters:
- `token` (required) - CI project token
- `project_url` (required) - CI project url
### Delete GitLab CI service
Delete GitLab CI service settings for a project.
```
DELETE /projects/:id/services/gitlab-ci
```
## Hipchat
### Edit Hipchat service
Set Hipchat service for project.
```
PUT /projects/:id/services/hipchat
```
Parameters:
- `token` (required) - Hipchat token
- `room` (required) - Hipchat room name
### Delete Hipchat service
Delete Hipchat service for a project.
```
DELETE /projects/:id/services/hipchat
```
...@@ -6,6 +6,95 @@ The first time a user signs in with LDAP credentials, GitLab will create a new G ...@@ -6,6 +6,95 @@ The first time a user signs in with LDAP credentials, GitLab will create a new G
GitLab user attributes such as nickname and email will be copied from the LDAP user entry. GitLab user attributes such as nickname and email will be copied from the LDAP user entry.
## Configuring GitLab for LDAP integration
To enable GitLab LDAP integration you need to add your LDAP server settings in `/etc/gitlab/gitlab.rb` or `/home/git/gitlab/config/gitlab.yml`.
In GitLab Enterprise Edition you can have multiple LDAP servers connected to one GitLab server.
Please note that before version 7.4, GitLab used a different syntax for configuring LDAP integration.
The old LDAP integration syntax still works in GitLab 7.4.
If your `gitlab.rb` or `gitlab.yml` file contains LDAP settings in both the old syntax and the new syntax, only the __old__ syntax will be used by GitLab.
```ruby
# For omnibus packages
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
main: # 'main' is the GitLab 'provider ID' of this LDAP server
## label
#
# A human-friendly name for your LDAP server. It is OK to change the label later,
# for instance if you find out it is too large to fit on the web page.
#
# Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP'
host: '_your_ldap_server'
port: 636
uid: 'sAMAccountName'
method: 'ssl' # "tls" or "ssl" or "plain"
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user'
# This setting specifies if LDAP server is Active Directory LDAP server.
# For non AD servers it skips the AD specific queries.
# If your LDAP server is not AD, set this to false.
active_directory: true
# If allow_username_or_email_login is enabled, GitLab will ignore everything
# after the first '@' in the LDAP username submitted by the user on login.
#
# Example:
# - the user enters 'jane.doe@example.com' and 'p@ssw0rd' as LDAP credentials;
# - GitLab queries the LDAP server with 'jane.doe' and 'p@ssw0rd'.
#
# If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
# disable this setting, because the userPrincipalName contains an '@'.
allow_username_or_email_login: false
# Base where we can search for users
#
# Ex. ou=People,dc=gitlab,dc=example
#
base: ''
# Filter LDAP users
#
# Format: RFC 4515 http://tools.ietf.org/search/rfc4515
# Ex. (employeeType=developer)
#
# Note: GitLab does not support omniauth-ldap's custom filter syntax.
#
user_filter: ''
# GitLab EE only: add more LDAP servers
# Choose an ID made of a-z and 0-9 . This ID will be stored in the database
# so that GitLab can remember which LDAP server a user belongs to.
# uswest2:
# label:
# host:
# ....
EOS
```
If you are using a GitLab installation from source you can find the LDAP settings in `/home/git/gitlab/config/gitlab.yml`:
```
production:
# snip...
ldap:
enabled: false
servers:
main: # 'main' is the GitLab 'provider ID' of this LDAP server
## label
#
# A human-friendly name for your LDAP server. It is OK to change the label later,
# for instance if you find out it is too large to fit on the web page.
#
# Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP'
# snip...
```
## Enabling LDAP sign-in for existing GitLab users ## Enabling LDAP sign-in for existing GitLab users
When a user signs in to GitLab with LDAP for the first time, and their LDAP email address is the primary email address of an existing GitLab user, then the LDAP DN will be associated with the existing user. When a user signs in to GitLab with LDAP for the first time, and their LDAP email address is the primary email address of an existing GitLab user, then the LDAP DN will be associated with the existing user.
...@@ -24,14 +113,21 @@ If you want to limit all GitLab access to a subset of the LDAP users on your LDA ...@@ -24,14 +113,21 @@ If you want to limit all GitLab access to a subset of the LDAP users on your LDA
The filter must comply with [RFC 4515](http://tools.ietf.org/search/rfc4515). The filter must comply with [RFC 4515](http://tools.ietf.org/search/rfc4515).
```ruby ```ruby
# For omnibus-gitlab # For omnibus packages; new LDAP server syntax
gitlab_rails['ldap_user_filter'] = '(employeeType=developer)' gitlab_rails['ldap_servers'] = YAML.load <<-EOS
main:
# snip...
user_filter: '(employeeType=developer)'
EOS
``` ```
```yaml ```yaml
# For installations from source # For installations from source; new LDAP server syntax
production: production:
ldap: ldap:
servers:
main:
# snip...
user_filter: '(employeeType=developer)' user_filter: '(employeeType=developer)'
``` ```
......
...@@ -510,6 +510,10 @@ Code above produces next output: ...@@ -510,6 +510,10 @@ Code above produces next output:
| cell 1 | cell 2 | | cell 1 | cell 2 |
| cell 3 | cell 4 | | cell 3 | cell 4 |
**Note**
The row of dashes between the table header and body must have at least three dashes in each column.
## References ## References
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). - This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
......
# Import # Import
### Import bare repositories into GitLab project instance ## Import bare repositories into GitLab project instance
Notes: Notes:
* project owner will be a first admin - project owner will be a first admin
* groups will be created as needed - groups will be created as needed
* group owner will be the first admin - group owner will be the first admin
* existing projects will be skipped - existing projects will be skipped
How to use: How to use:
1. copy your bare repos under git repos_path (see `config/gitlab.yml` gitlab_shell -> repos_path) 1. copy your bare repos under git repos_path (see `config/gitlab.yml` gitlab_shell -> repos_path)
2. run the command below 1. run the command below
``` ```
# omnibus-gitlab # omnibus-gitlab
......
...@@ -191,6 +191,7 @@ It is important to do this as soon as possible, so we can catch any errors befor ...@@ -191,6 +191,7 @@ It is important to do this as soon as possible, so we can catch any errors befor
- Ask Dmitriy to add screenshots to the WIP MR. - Ask Dmitriy to add screenshots to the WIP MR.
- Decide with team who will be the MVP user. - Decide with team who will be the MVP user.
- Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible. - Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
- Create a merge request on [GitLab.com](https://gitlab.com/gitlab-com/www-gitlab-com/tree/master)
- Assign to one reviewer who will fix spelling issues by editing the branch (can use the online editor) - Assign to one reviewer who will fix spelling issues by editing the branch (can use the online editor)
- After the reviewer is finished the whole team will be mentioned to give their suggestions via line comments - After the reviewer is finished the whole team will be mentioned to give their suggestions via line comments
......
...@@ -26,6 +26,6 @@ Otherwise include it in the monthly release and note there was a regression fix ...@@ -26,6 +26,6 @@ Otherwise include it in the monthly release and note there was a regression fix
1. Apply the patch to GitLab Cloud and the private GitLab development server 1. Apply the patch to GitLab Cloud and the private GitLab development server
1. [Build new packages with the latest version](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md) 1. [Build new packages with the latest version](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md)
1. Cherry-pick the changelog update back into master 1. Cherry-pick the changelog update back into master
1. Create blog post
1. Send tweets about the release from `@gitlabhq`, tweet should include the most important feature that the release is addressing as well as the link to the changelog 1. Send tweets about the release from `@gitlabhq`, tweet should include the most important feature that the release is addressing as well as the link to the changelog
1. Note in the 'GitLab X.X regressions' issue that the patch was published (CE only) 1. Note in the 'GitLab X.X regressions' issue that the patch was published (CE only)
1. Send out an email to the 'GitLab Newsletter' mailing list on MailChimp (or the 'Subscribers' list if the patch is EE only)
...@@ -74,7 +74,7 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab ...@@ -74,7 +74,7 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
# Enable Redis socket for default Debian / Ubuntu path # Enable Redis socket for default Debian / Ubuntu path
echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf
# Be sure redis group can write to the socket, enable only if supported (>= redis 2.4.0). # Be sure redis group can write to the socket, enable only if supported (>= redis 2.4.0).
sed -i '/# unixsocketperm/ s/^# unixsocketperm.*/unixsocketperm 0775/' /etc/redis/redis.conf sudo sed -i '/# unixsocketperm/ s/^# unixsocketperm.*/unixsocketperm 0775/' /etc/redis/redis.conf
# Activate the changes to redis.conf # Activate the changes to redis.conf
sudo service redis-server restart sudo service redis-server restart
# Add git to the redis group # Add git to the redis group
......
...@@ -67,6 +67,10 @@ module API ...@@ -67,6 +67,10 @@ module API
unauthorized! unless current_user unauthorized! unless current_user
end end
def authenticate_by_gitlab_shell_token!
unauthorized! unless secret_token == params['secret_token']
end
def authenticated_as_admin! def authenticated_as_admin!
forbidden! unless current_user.is_admin? forbidden! unless current_user.is_admin?
end end
...@@ -193,5 +197,9 @@ module API ...@@ -193,5 +197,9 @@ module API
abilities abilities
end end
end end
def secret_token
File.read(Rails.root.join('.gitlab_shell_secret'))
end
end end
end end
module API module API
# Internal access API # Internal access API
class Internal < Grape::API class Internal < Grape::API
before {
authenticate_by_gitlab_shell_token!
}
namespace 'internal' do namespace 'internal' do
# Check if git command is allowed to project # Check if git command is allowed to project
# #
......
...@@ -28,7 +28,7 @@ module API ...@@ -28,7 +28,7 @@ module API
# Delete GitLab CI service settings # Delete GitLab CI service settings
# #
# Example Request: # Example Request:
# DELETE /projects/:id/keys/:id # DELETE /projects/:id/services/gitlab-ci
delete ":id/services/gitlab-ci" do delete ":id/services/gitlab-ci" do
if user_project.gitlab_ci_service if user_project.gitlab_ci_service
user_project.gitlab_ci_service.update_attributes( user_project.gitlab_ci_service.update_attributes(
...@@ -38,7 +38,41 @@ module API ...@@ -38,7 +38,41 @@ module API
) )
end end
end end
# Set Hipchat service for project
#
# Parameters:
# token (required) - Hipchat token
# room (required) - Hipchat room name
#
# Example Request:
# PUT /projects/:id/services/hipchat
put ':id/services/hipchat' do
required_attributes! [:token, :room]
attrs = attributes_for_keys [:token, :room]
user_project.build_missing_services
if user_project.hipchat_service.update_attributes(
attrs.merge(active: true))
true
else
not_found!
end end
end end
end
# Delete Hipchat service settings
#
# Example Request:
# DELETE /projects/:id/services/hipchat
delete ':id/services/hipchat' do
if user_project.hipchat_service
user_project.hipchat_service.update_attributes(
active: false,
token: nil,
room: nil
)
end
end
end
end
end
module Gitlab module Gitlab
class AppLogger < Gitlab::Logger class AppLogger < Gitlab::Logger
def self.file_name def self.file_name_noext
'application.log' 'application'
end end
def format_message(severity, timestamp, progname, msg) def format_message(severity, timestamp, progname, msg)
......
...@@ -90,7 +90,7 @@ module Grack ...@@ -90,7 +90,7 @@ module Grack
when *Gitlab::GitAccess::PUSH_COMMANDS when *Gitlab::GitAccess::PUSH_COMMANDS
if user if user
# Skip user authorization on upload request. # Skip user authorization on upload request.
# It will be serverd by update hook in repository # It will be done by the pre-receive hook in the repository.
true true
else else
false false
......
module Gitlab module Gitlab
class GitLogger < Gitlab::Logger class GitLogger < Gitlab::Logger
def self.file_name def self.file_name_noext
'githost.log' 'githost'
end end
def format_message(severity, timestamp, progname, msg) def format_message(severity, timestamp, progname, msg)
......
module Gitlab module Gitlab
class Logger < ::Logger class Logger < ::Logger
def self.file_name
file_name_noext + '.log'
end
def self.error(message) def self.error(message)
build.error(message) build.error(message)
end end
......
...@@ -202,7 +202,7 @@ module Gitlab ...@@ -202,7 +202,7 @@ module Gitlab
if identifier == "all" if identifier == "all"
link_to("@all", project_url(project), options) link_to("@all", project_url(project), options)
elsif user = User.find_by(username: identifier) elsif User.find_by(username: identifier)
link_to("@#{identifier}", user_url(identifier), options) link_to("@#{identifier}", user_url(identifier), options)
end end
end end
......
module Gitlab
class ProductionLogger < Gitlab::Logger
def self.file_name_noext
'production'
end
end
end
module Gitlab
class SidekiqLogger < Gitlab::Logger
def self.file_name_noext
'sidekiq'
end
end
end
...@@ -60,18 +60,16 @@ server { ...@@ -60,18 +60,16 @@ server {
client_max_body_size 20m; client_max_body_size 20m;
## Strong SSL Security ## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
ssl on; ssl on;
ssl_certificate /etc/nginx/ssl/gitlab.crt; ssl_certificate /etc/nginx/ssl/gitlab.crt;
ssl_certificate_key /etc/nginx/ssl/gitlab.key; ssl_certificate_key /etc/nginx/ssl/gitlab.key;
# GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs # GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4'; ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
## [WARNING] The following header states that the browser should only communicate ## [WARNING] The following header states that the browser should only communicate
## with your server over a secure connection for the next 24 months. ## with your server over a secure connection for the next 24 months.
...@@ -88,11 +86,10 @@ server { ...@@ -88,11 +86,10 @@ server {
# ssl_stapling_verify on; # ssl_stapling_verify on;
# ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt; # ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
# resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired # resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
# resolver_timeout 10s; # resolver_timeout 5s;
## [Optional] Generate a stronger DHE parameter: ## [Optional] Generate a stronger DHE parameter:
## cd /etc/ssl/certs ## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
## sudo openssl dhparam -out dhparam.pem 4096
## ##
# ssl_dhparam /etc/ssl/certs/dhparam.pem; # ssl_dhparam /etc/ssl/certs/dhparam.pem;
......
...@@ -34,7 +34,7 @@ namespace :gitlab do ...@@ -34,7 +34,7 @@ namespace :gitlab do
puts "Processing #{repo_path}".yellow puts "Processing #{repo_path}".yellow
if path =~ /.wiki\Z/ if path =~ /\.wiki\Z/
puts " * Skipping wiki repo" puts " * Skipping wiki repo"
next next
end end
......
...@@ -11,13 +11,13 @@ namespace :gitlab do ...@@ -11,13 +11,13 @@ namespace :gitlab do
home_dir = Rails.env.test? ? Rails.root.join('tmp/tests') : Settings.gitlab.user_home home_dir = Rails.env.test? ? Rails.root.join('tmp/tests') : Settings.gitlab.user_home
gitlab_url = Settings.gitlab.url gitlab_url = Settings.gitlab.url
# gitlab-shell requires a / at the end of the url # gitlab-shell requires a / at the end of the url
gitlab_url += "/" unless gitlab_url.match(/\/$/) gitlab_url += '/' unless gitlab_url.end_with?('/')
repos_path = Gitlab.config.gitlab_shell.repos_path repos_path = Gitlab.config.gitlab_shell.repos_path
target_dir = Gitlab.config.gitlab_shell.path target_dir = Gitlab.config.gitlab_shell.path
# Clone if needed # Clone if needed
unless File.directory?(target_dir) unless File.directory?(target_dir)
sh "git clone '#{args.repo}' '#{target_dir}'" sh(*%W(git clone #{args.repo} #{target_dir}))
end end
# Make sure we're on the right tag # Make sure we're on the right tag
......
...@@ -594,7 +594,9 @@ describe GitlabMarkdownHelper do ...@@ -594,7 +594,9 @@ describe GitlabMarkdownHelper do
end end
it "should generate absolute urls for emoji" do it "should generate absolute urls for emoji" do
markdown(":smile:").should include("src=\"http://localhost/assets/emoji/smile.png") markdown(':smile:').should(
include(%(src="#{Gitlab.config.gitlab.url}/assets/emoji/smile.png))
)
end end
it "should generate absolute urls for emoji if relative url is present" do it "should generate absolute urls for emoji if relative url is present" do
......
...@@ -5,10 +5,11 @@ describe API::API, api: true do ...@@ -5,10 +5,11 @@ describe API::API, api: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:key) { create(:key, user: user) } let(:key) { create(:key, user: user) }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:secret_token) { File.read Rails.root.join('.gitlab_shell_secret') }
describe "GET /internal/check", no_db: true do describe "GET /internal/check", no_db: true do
it do it do
get api("/internal/check") get api("/internal/check"), secret_token: secret_token
response.status.should == 200 response.status.should == 200
json_response['api_version'].should == API::API.version json_response['api_version'].should == API::API.version
...@@ -17,7 +18,7 @@ describe API::API, api: true do ...@@ -17,7 +18,7 @@ describe API::API, api: true do
describe "GET /internal/discover" do describe "GET /internal/discover" do
it do it do
get(api("/internal/discover"), key_id: key.id) get(api("/internal/discover"), key_id: key.id, secret_token: secret_token)
response.status.should == 200 response.status.should == 200
...@@ -159,7 +160,8 @@ describe API::API, api: true do ...@@ -159,7 +160,8 @@ describe API::API, api: true do
api("/internal/allowed"), api("/internal/allowed"),
key_id: key.id, key_id: key.id,
project: project.path_with_namespace, project: project.path_with_namespace,
action: 'git-upload-pack' action: 'git-upload-pack',
secret_token: secret_token
) )
end end
...@@ -169,7 +171,8 @@ describe API::API, api: true do ...@@ -169,7 +171,8 @@ describe API::API, api: true do
changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master', changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
key_id: key.id, key_id: key.id,
project: project.path_with_namespace, project: project.path_with_namespace,
action: 'git-receive-pack' action: 'git-receive-pack',
secret_token: secret_token
) )
end end
...@@ -179,7 +182,8 @@ describe API::API, api: true do ...@@ -179,7 +182,8 @@ describe API::API, api: true do
ref: 'master', ref: 'master',
key_id: key.id, key_id: key.id,
project: project.path_with_namespace, project: project.path_with_namespace,
action: 'git-upload-archive' action: 'git-upload-archive',
secret_token: secret_token
) )
end end
end end
...@@ -27,4 +27,30 @@ describe API::API, api: true do ...@@ -27,4 +27,30 @@ describe API::API, api: true do
project.gitlab_ci_service.should be_nil project.gitlab_ci_service.should be_nil
end end
end end
describe 'PUT /projects/:id/services/hipchat' do
it 'should update hipchat settings' do
put api("/projects/#{project.id}/services/hipchat", user),
token: 'secret-token', room: 'test'
response.status.should == 200
project.hipchat_service.should_not be_nil
end
it 'should return if required fields missing' do
put api("/projects/#{project.id}/services/gitlab-ci", user),
token: 'secret-token', active: true
response.status.should == 400
end
end
describe 'DELETE /projects/:id/services/hipchat' do
it 'should delete hipchat settings' do
delete api("/projects/#{project.id}/services/hipchat", user)
response.status.should == 200
project.hipchat_service.should be_nil
end
end
end end
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