mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-15 15:46:08 +10:00
+1
-1
@@ -877,7 +877,7 @@ Lint/ParenthesesAsGroupedExpression:
|
||||
Checks for method calls with a space before the opening
|
||||
parenthesis.
|
||||
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces'
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
Lint/RequireParentheses:
|
||||
Description: >-
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 7.9.0 (unreleased)
|
||||
- Fix merge request URL passed to Webhooks. (Stan Hu)
|
||||
- Fix bug that caused a server error when editing a comment to "+1" or "-1" (Stan Hu)
|
||||
- Move labels/milestones tabs to sidebar
|
||||
- Upgrade Rails gem to version 4.1.9.
|
||||
- Improve error messages for file edit failures
|
||||
@@ -16,6 +18,8 @@ v 7.9.0 (unreleased)
|
||||
- Allow user confirmation to be skipped for new users via API
|
||||
- Add a service to send updates to an Irker gateway (Romain Coltel)
|
||||
- Ignore case of LDAP user DN when checking group membership.
|
||||
- Add brakeman (security scanner for Ruby on Rails)
|
||||
- Slack username and channel options
|
||||
|
||||
v 7.8.1
|
||||
- Fix run of custom post receive hooks
|
||||
@@ -92,7 +96,6 @@ v 7.8.0
|
||||
- Improve database performance for GitLab
|
||||
- Add Asana service (Jeremy Benoist)
|
||||
- Improve project web hooks with extra data
|
||||
- Slack username and channel options
|
||||
|
||||
v 7.7.2
|
||||
- Update GitLab Shell to version 2.4.2 that fixes a bug when developers can push to protected branch
|
||||
|
||||
@@ -201,6 +201,7 @@ gem "virtus"
|
||||
gem 'addressable'
|
||||
|
||||
group :development do
|
||||
gem 'brakeman', require: false
|
||||
gem "annotate", "~> 2.6.0.beta2"
|
||||
gem "letter_opener"
|
||||
gem 'quiet_assets', '~> 1.0.1'
|
||||
|
||||
@@ -63,6 +63,16 @@ GEM
|
||||
bootstrap-sass (3.3.3)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
brakeman (3.0.1)
|
||||
erubis (~> 2.6)
|
||||
fastercsv (~> 1.5)
|
||||
haml (>= 3.0, < 5.0)
|
||||
highline (~> 1.6.20)
|
||||
multi_json (~> 1.2)
|
||||
ruby2ruby (~> 2.1.1)
|
||||
ruby_parser (~> 3.5.0)
|
||||
sass (~> 3.0)
|
||||
terminal-table (~> 1.4)
|
||||
browser (0.7.2)
|
||||
builder (3.2.2)
|
||||
byebug (3.2.0)
|
||||
@@ -154,6 +164,7 @@ GEM
|
||||
multipart-post (~> 1.2.0)
|
||||
faraday_middleware (0.9.0)
|
||||
faraday (>= 0.7.4, < 0.9)
|
||||
fastercsv (1.5.5)
|
||||
ffaker (1.22.1)
|
||||
ffi (1.9.3)
|
||||
fog (1.21.0)
|
||||
@@ -258,6 +269,7 @@ GEM
|
||||
haml (>= 3.1, < 5.0)
|
||||
railties (>= 4.0.1)
|
||||
hashie (2.1.2)
|
||||
highline (1.6.21)
|
||||
hike (1.2.3)
|
||||
hipchat (1.4.0)
|
||||
httparty
|
||||
@@ -497,6 +509,11 @@ GEM
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
ruby-progressbar (1.7.1)
|
||||
ruby2ruby (2.1.3)
|
||||
ruby_parser (~> 3.1)
|
||||
sexp_processor (~> 4.0)
|
||||
ruby_parser (3.5.0)
|
||||
sexp_processor (~> 4.1)
|
||||
rubyntlm (0.4.0)
|
||||
rubypants (0.2.0)
|
||||
rugged (0.21.4)
|
||||
@@ -522,6 +539,7 @@ GEM
|
||||
select2-rails (3.5.2)
|
||||
thor (~> 0.14)
|
||||
settingslogic (2.0.9)
|
||||
sexp_processor (4.4.5)
|
||||
shoulda-matchers (2.7.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (3.3.0)
|
||||
@@ -577,6 +595,7 @@ GEM
|
||||
temple (0.6.7)
|
||||
term-ansicolor (1.2.2)
|
||||
tins (~> 0.8)
|
||||
terminal-table (1.4.5)
|
||||
test_after_commit (0.2.2)
|
||||
therubyracer (0.12.0)
|
||||
libv8 (~> 3.16.14.0)
|
||||
@@ -656,6 +675,7 @@ DEPENDENCIES
|
||||
better_errors
|
||||
binding_of_caller
|
||||
bootstrap-sass (~> 3.0)
|
||||
brakeman
|
||||
browser
|
||||
byebug
|
||||
cal-heatmap-rails (~> 0.0.1)
|
||||
|
||||
@@ -11,14 +11,15 @@ class @ProjectUsersSelect
|
||||
Api.projectUsers project_id, query.term, (users) ->
|
||||
data = { results: users }
|
||||
|
||||
nullUser = {
|
||||
name: 'Unassigned',
|
||||
avatar: null,
|
||||
username: 'none',
|
||||
id: -1
|
||||
}
|
||||
if query.term.length == 0
|
||||
nullUser = {
|
||||
name: 'Unassigned',
|
||||
avatar: null,
|
||||
username: 'none',
|
||||
id: -1
|
||||
}
|
||||
|
||||
data.results.unshift(nullUser)
|
||||
data.results.unshift(nullUser)
|
||||
|
||||
query.callback(data)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ class Import::BaseController < ApplicationController
|
||||
private
|
||||
|
||||
def get_or_create_namespace
|
||||
existing_namespace = Namespace.find_by("path = ? OR name = ?", @target_namespace, @target_namespace)
|
||||
existing_namespace = Namespace.find_by_path_or_name(@target_namespace)
|
||||
|
||||
if existing_namespace
|
||||
if existing_namespace.owner == current_user
|
||||
|
||||
@@ -26,7 +26,7 @@ class Projects::ImportsController < Projects::ApplicationController
|
||||
def show
|
||||
unless @project.import_in_progress?
|
||||
if @project.import_finished?
|
||||
redirect_to(@project) and return
|
||||
redirect_to(project_path(@project)) and return
|
||||
else
|
||||
redirect_to new_namespace_project_import_path(@project.namespace,
|
||||
@project) && return
|
||||
|
||||
@@ -3,10 +3,10 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
before_filter :authorize_read_note!
|
||||
before_filter :authorize_write_note!, only: [:create]
|
||||
before_filter :authorize_admin_note!, only: [:update, :destroy]
|
||||
before_filter :find_current_user_notes, except: [:destroy, :delete_attachment]
|
||||
|
||||
def index
|
||||
current_fetched_at = Time.now.to_i
|
||||
@notes = NotesFinder.new.execute(project, current_user, params)
|
||||
|
||||
notes_json = { notes: [], last_fetched_at: current_fetched_at }
|
||||
|
||||
@@ -116,4 +116,10 @@ class Projects::NotesController < Projects::ApplicationController
|
||||
:attachment, :line_code, :commit_id
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_current_user_notes
|
||||
@notes = NotesFinder.new.execute(project, current_user, params)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,12 +30,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
|
||||
AuditEventService.new(current_user, @project, details).security_event
|
||||
end
|
||||
|
||||
if params[:redirect_to]
|
||||
redirect_to params[:redirect_to]
|
||||
else
|
||||
redirect_to namespace_project_team_index_path(@project.namespace,
|
||||
@project)
|
||||
end
|
||||
redirect_to namespace_project_team_index_path(@project.namespace, @project)
|
||||
end
|
||||
|
||||
def update
|
||||
|
||||
@@ -97,7 +97,7 @@ class Projects::WikisController < Projects::ApplicationController
|
||||
@project_wiki.wiki
|
||||
rescue ProjectWiki::CouldNotCreateWikiError => ex
|
||||
flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
|
||||
redirect_to @project
|
||||
redirect_to project_path(@project)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class ProjectsController < ApplicationController
|
||||
prepend_before_filter :render_go_import, only: [:show]
|
||||
skip_before_filter :authenticate_user!, only: [:show]
|
||||
before_filter :project, except: [:new, :create]
|
||||
before_filter :repository, except: [:new, :create]
|
||||
@@ -185,4 +186,14 @@ class ProjectsController < ApplicationController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def render_go_import
|
||||
return unless params["go-get"] == "1"
|
||||
|
||||
@namespace = params[:namespace_id]
|
||||
@id = params[:project_id] || params[:id]
|
||||
@id = @id.gsub(/\.git\Z/, "")
|
||||
|
||||
render "go_import", layout: false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,22 +3,53 @@ class UploadsController < ApplicationController
|
||||
before_filter :authorize_access
|
||||
|
||||
def show
|
||||
model = params[:model].camelize.constantize.find(params[:id])
|
||||
uploader = model.send(params[:mounted_as])
|
||||
unless upload_model && upload_mount
|
||||
return not_found!
|
||||
end
|
||||
|
||||
return not_found! if model.respond_to?(:project) && !can?(current_user, :read_project, model.project)
|
||||
model = upload_model.find(params[:id])
|
||||
uploader = model.send(upload_mount)
|
||||
|
||||
return redirect_to uploader.url unless uploader.file_storage?
|
||||
if model.respond_to?(:project) && !can?(current_user, :read_project, model.project)
|
||||
return not_found!
|
||||
end
|
||||
|
||||
return not_found! unless uploader.file.exists?
|
||||
unless uploader.file_storage?
|
||||
return redirect_to uploader.url
|
||||
end
|
||||
|
||||
unless uploader.file.exists?
|
||||
return not_found!
|
||||
end
|
||||
|
||||
disposition = uploader.image? ? 'inline' : 'attachment'
|
||||
send_file uploader.file.path, disposition: disposition
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authorize_access
|
||||
unless params[:mounted_as] == 'avatar'
|
||||
authenticate_user! && reject_blocked!
|
||||
end
|
||||
end
|
||||
|
||||
def upload_model
|
||||
upload_models = {
|
||||
user: User,
|
||||
project: Project,
|
||||
note: Note,
|
||||
group: Group
|
||||
}
|
||||
|
||||
upload_models[params[:model].to_sym]
|
||||
end
|
||||
|
||||
def upload_mount
|
||||
upload_mounts = %w(avatar attachment file)
|
||||
|
||||
if upload_mounts.include?(params[:mounted_as])
|
||||
params[:mounted_as]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,9 +4,9 @@ module NotesHelper
|
||||
(@noteable.class.name == note.noteable_type && !note.for_diff_line?)
|
||||
end
|
||||
|
||||
def note_target_fields
|
||||
hidden_field_tag(:target_type, @target_type) +
|
||||
hidden_field_tag(:target_id, @target_id)
|
||||
def note_target_fields(note)
|
||||
hidden_field_tag(:target_type, note.noteable.class.name.underscore) +
|
||||
hidden_field_tag(:target_id, note.noteable.id)
|
||||
end
|
||||
|
||||
def link_to_commit_diff_line_note(note)
|
||||
|
||||
@@ -48,6 +48,11 @@ class Namespace < ActiveRecord::Base
|
||||
where('lower(path) = :value', value: path.downcase).first
|
||||
end
|
||||
|
||||
# Case insensetive search for namespace by path or name
|
||||
def self.find_by_path_or_name(path)
|
||||
find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
|
||||
end
|
||||
|
||||
def self.search(query)
|
||||
where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
|
||||
end
|
||||
|
||||
@@ -146,7 +146,7 @@ class Repository
|
||||
end
|
||||
|
||||
def timestamps_by_user_log(user)
|
||||
args = %W(git log --author=#{user.email} --since=#{(Date.today - 1.year).to_s} --pretty=format:%cd --date=short)
|
||||
args = %W(git log --author=#{user.email} --since=#{(Date.today - 1.year).to_s} --branches --pretty=format:%cd --date=short)
|
||||
dates = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
|
||||
|
||||
if dates.present?
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
Projects (#{@projects.total_count})
|
||||
.panel-head-actions
|
||||
.dropdown.inline
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%span.light sort:
|
||||
- if @sort.present?
|
||||
= sort_options_hash[@sort]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
.pull-right
|
||||
.dropdown.inline
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%span.light sort:
|
||||
- if @sort.present?
|
||||
= sort_options_hash[@sort]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
.pull-right
|
||||
.dropdown.inline
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%span.light sort:
|
||||
- if @sort.present?
|
||||
= sort_options_hash[@sort]
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
%strong= member.human_access
|
||||
- if show_controls
|
||||
- if can?(current_user, :modify, member)
|
||||
= link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
|
||||
= button_tag class: "btn-tiny btn js-toggle-button",
|
||||
title: 'Edit access level', type: 'button' do
|
||||
%i.fa.fa-pencil-square-o
|
||||
- if can?(current_user, :destroy, member)
|
||||
- if current_user == member.user
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
= link_to reset_access_group_ldap_path(@group), class: 'btn btn-grouped', data: { confirm: "Force GitLab to do LDAP permission checks for all group members? All members besides yourself will be reduced to 'Guest' access until their next interaction with GitLab." }, method: :put do
|
||||
Clear LDAP permission cache
|
||||
|
||||
= link_to '#', class: 'btn btn-new js-toggle-button' do
|
||||
= button_tag class: 'btn btn-new js-toggle-button', type: 'button' do
|
||||
Add members
|
||||
%i.fa.fa-chevron-down
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
New branch
|
||||
|
||||
.dropdown.inline
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%span.light sort:
|
||||
- if @sort.present?
|
||||
= @sort.humanize
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
!!! 5
|
||||
%html
|
||||
%head
|
||||
- web_url = [Gitlab.config.gitlab.url, @namespace, @id].join('/')
|
||||
%meta{name: "go-import", content: "#{web_url.split('://')[1]} git #{web_url}.git"}
|
||||
@@ -1,5 +1,6 @@
|
||||
.note-edit-form
|
||||
= form_for note, url: namespace_project_note_path(@project.namespace, @project, note), method: :put, remote: true, authenticity_token: true do |f|
|
||||
= note_target_fields(note)
|
||||
= render layout: 'projects/md_preview', locals: { preview_class: "note-text" } do
|
||||
= render 'projects/zen', f: f, attr: :note,
|
||||
classes: 'note_text js-note-text'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
= form_for [@project.namespace.becomes(Namespace), @project, @note], remote: true, html: { :'data-type' => 'json', multipart: true, id: nil, class: "new_note js-new-note-form common-note-form gfm-form" }, authenticity_token: true do |f|
|
||||
= note_target_fields
|
||||
= note_target_fields(@note)
|
||||
= f.hidden_field :commit_id
|
||||
= f.hidden_field :line_code
|
||||
= f.hidden_field :noteable_id
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.dropdown.inline
|
||||
%a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn.btn-small{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%i.fa.fa-tags
|
||||
%span.light Group:
|
||||
- if @group.present?
|
||||
@@ -17,7 +17,7 @@
|
||||
= group.name
|
||||
|
||||
.dropdown.inline.prepend-left-10.project-filter
|
||||
%a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn.btn-small{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%i.fa.fa-tags
|
||||
%span.light Project:
|
||||
- if @project.present?
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
disabled: !can?(current_user, :modify_issue, @project)
|
||||
.issues-other-filters
|
||||
.dropdown.inline.assignee-filter
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
|
||||
%i.fa.fa-user
|
||||
%span.light assignee:
|
||||
- if @assignee.present?
|
||||
@@ -45,7 +45,7 @@
|
||||
= user.name
|
||||
|
||||
.dropdown.inline.prepend-left-10.author-filter
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
|
||||
%i.fa.fa-user
|
||||
%span.light author:
|
||||
- if @author.present?
|
||||
@@ -68,7 +68,7 @@
|
||||
= user.name
|
||||
|
||||
.dropdown.inline.prepend-left-10.milestone-filter
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
|
||||
%i.fa.fa-clock-o
|
||||
%span.light milestone:
|
||||
- if @milestone.present?
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
- if @project
|
||||
.dropdown.inline.prepend-left-10.labels-filter
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
|
||||
%i.fa.fa-tags
|
||||
%span.light label:
|
||||
- if params[:label_name].present?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.dropdown.inline.prepend-left-10
|
||||
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
|
||||
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
%span.light sort:
|
||||
- if @sort.present?
|
||||
= sort_options_hash[@sort]
|
||||
|
||||
@@ -37,7 +37,10 @@ bundle install --deployment --path vendor/bundle (Setup)
|
||||
cp config/gitlab.yml.example config/gitlab.yml (Setup)
|
||||
bundle exec rake db:create (Setup)
|
||||
bundle exec rake spinach (Thread #1)
|
||||
bundle exec rake spec (Thread #2)
|
||||
bundle exec rake spec (thread #2)
|
||||
bundle exec rake rubocop (thread #3)
|
||||
bundle exec rake brakeman (thread #4)
|
||||
bundle exec rake jasmine:ci (thread #5)
|
||||
```
|
||||
|
||||
Use rubygems mirror.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Installation
|
||||
# Installation from source
|
||||
|
||||
## Consider the Omnibus package installation
|
||||
|
||||
|
||||
@@ -41,3 +41,9 @@ Feature: Project Commits Comments
|
||||
Given I leave a comment like "XML attached"
|
||||
And I delete a comment
|
||||
Then I should not see a comment saying "XML attached"
|
||||
|
||||
@javascript
|
||||
Scenario: I can edit a comment with +1
|
||||
Given I leave a comment like "XML attached"
|
||||
And I edit the last comment with a +1
|
||||
Then I should see +1 in the description
|
||||
|
||||
@@ -139,6 +139,15 @@ Feature: Project Issues
|
||||
And I leave a comment with task markdown
|
||||
Then I should not see task checkboxes in the comment
|
||||
|
||||
@javascript
|
||||
Scenario: Issue notes should be editable with +1
|
||||
Given project "Shop" has "Tasks-open" open issue with task markdown
|
||||
When I visit issue page "Tasks-open"
|
||||
And I leave a comment with a header containing "Comment with a header"
|
||||
Then The comment with the header should not have an ID
|
||||
And I edit the last comment with a +1
|
||||
Then I should see +1 in the description
|
||||
|
||||
# Task status in issues list
|
||||
|
||||
Scenario: Issues list should display task status
|
||||
|
||||
@@ -29,7 +29,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
|
||||
|
||||
step 'I select user "Mary Jane" from list with role "Reporter"' do
|
||||
user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane")
|
||||
click_link 'Add members'
|
||||
click_button 'Add members'
|
||||
within ".users-group-form" do
|
||||
select2(user.id, from: "#user_ids", multiple: true)
|
||||
select "Reporter", from: "access_level"
|
||||
|
||||
@@ -135,4 +135,21 @@ module SharedNote
|
||||
'li.note div.timeline-content input[type="checkbox"]'
|
||||
)
|
||||
end
|
||||
|
||||
step 'I edit the last comment with a +1' do
|
||||
find(".note").hover
|
||||
find('.js-note-edit').click
|
||||
|
||||
within(".current-note-edit-form") do
|
||||
fill_in 'note[note]', with: '+1 Awesome!'
|
||||
click_button 'Save Comment'
|
||||
sleep 0.05
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should see +1 in the description' do
|
||||
within(".note") do
|
||||
page.should have_content("+1 Awesome!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ module API
|
||||
|
||||
class ProjectEntity < Grape::Entity
|
||||
expose :id, :iid
|
||||
expose (:project_id) { |entity| entity.project.id }
|
||||
expose(:project_id) { |entity| entity.project.id }
|
||||
expose :title, :description
|
||||
expose :state, :created_at, :updated_at
|
||||
end
|
||||
|
||||
+22
-17
@@ -16,6 +16,17 @@ module API
|
||||
#
|
||||
post "/allowed" do
|
||||
status 200
|
||||
|
||||
actor = if params[:key_id]
|
||||
Key.find_by(id: params[:key_id])
|
||||
elsif params[:user_id]
|
||||
User.find_by(id: params[:user_id])
|
||||
end
|
||||
|
||||
unless actor
|
||||
return Gitlab::GitAccessStatus.new(false, 'No such user or key')
|
||||
end
|
||||
|
||||
project_path = params[:project]
|
||||
|
||||
# Check for *.wiki repositories.
|
||||
@@ -32,26 +43,20 @@ module API
|
||||
|
||||
project = Project.find_with_namespace(project_path)
|
||||
|
||||
unless project
|
||||
return Gitlab::GitAccessStatus.new(false, 'No such project')
|
||||
if project
|
||||
status = access.check(
|
||||
actor,
|
||||
params[:action],
|
||||
project,
|
||||
params[:changes]
|
||||
)
|
||||
end
|
||||
|
||||
actor = if params[:key_id]
|
||||
Key.find_by(id: params[:key_id])
|
||||
elsif params[:user_id]
|
||||
User.find_by(id: params[:user_id])
|
||||
end
|
||||
|
||||
unless actor
|
||||
return Gitlab::GitAccessStatus.new(false, 'No such user or key')
|
||||
if project && status && status.allowed?
|
||||
status
|
||||
else
|
||||
Gitlab::GitAccessStatus.new(false, 'No such project')
|
||||
end
|
||||
|
||||
access.check(
|
||||
actor,
|
||||
params[:action],
|
||||
project,
|
||||
params[:changes]
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -10,8 +10,9 @@ module Grack
|
||||
@request = Rack::Request.new(env)
|
||||
@auth = Request.new(env)
|
||||
|
||||
# Need this patch due to the rails mount
|
||||
@gitlab_ci = false
|
||||
|
||||
# Need this patch due to the rails mount
|
||||
# Need this if under RELATIVE_URL_ROOT
|
||||
unless Gitlab.config.gitlab.relative_url_root.empty?
|
||||
# If website is mounted using relative_url_root need to remove it first
|
||||
@@ -22,8 +23,12 @@ module Grack
|
||||
|
||||
@env['SCRIPT_NAME'] = ""
|
||||
|
||||
if project
|
||||
auth!
|
||||
auth!
|
||||
|
||||
if project && authorized_request?
|
||||
@app.call(env)
|
||||
elsif @user.nil? && !@gitlab_ci
|
||||
unauthorized
|
||||
else
|
||||
render_not_found
|
||||
end
|
||||
@@ -32,35 +37,30 @@ module Grack
|
||||
private
|
||||
|
||||
def auth!
|
||||
if @auth.provided?
|
||||
return bad_request unless @auth.basic?
|
||||
return unless @auth.provided?
|
||||
|
||||
# Authentication with username and password
|
||||
login, password = @auth.credentials
|
||||
return bad_request unless @auth.basic?
|
||||
|
||||
# Allow authentication for GitLab CI service
|
||||
# if valid token passed
|
||||
if gitlab_ci_request?(login, password)
|
||||
return @app.call(env)
|
||||
end
|
||||
# Authentication with username and password
|
||||
login, password = @auth.credentials
|
||||
|
||||
@user = authenticate_user(login, password)
|
||||
|
||||
if @user
|
||||
Gitlab::ShellEnv.set_env(@user)
|
||||
@env['REMOTE_USER'] = @auth.username
|
||||
end
|
||||
# Allow authentication for GitLab CI service
|
||||
# if valid token passed
|
||||
if gitlab_ci_request?(login, password)
|
||||
@gitlab_ci = true
|
||||
return
|
||||
end
|
||||
|
||||
if authorized_request?
|
||||
@app.call(env)
|
||||
else
|
||||
unauthorized
|
||||
@user = authenticate_user(login, password)
|
||||
|
||||
if @user
|
||||
Gitlab::ShellEnv.set_env(@user)
|
||||
@env['REMOTE_USER'] = @auth.username
|
||||
end
|
||||
end
|
||||
|
||||
def gitlab_ci_request?(login, password)
|
||||
if login == "gitlab-ci-token" && project.gitlab_ci?
|
||||
if login == "gitlab-ci-token" && project && project.gitlab_ci?
|
||||
token = project.gitlab_ci_service.token
|
||||
|
||||
if token.present? && token == password && git_cmd == 'git-upload-pack'
|
||||
@@ -107,6 +107,8 @@ module Grack
|
||||
end
|
||||
|
||||
def authorized_request?
|
||||
return true if @gitlab_ci
|
||||
|
||||
case git_cmd
|
||||
when *Gitlab::GitAccess::DOWNLOAD_COMMANDS
|
||||
if user
|
||||
@@ -141,7 +143,9 @@ module Grack
|
||||
end
|
||||
|
||||
def project
|
||||
@project ||= project_by_path(@request.path_info)
|
||||
return @project if defined?(@project)
|
||||
|
||||
@project = project_by_path(@request.path_info)
|
||||
end
|
||||
|
||||
def project_by_path(path)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module Gitlab
|
||||
class UrlBuilder
|
||||
include Rails.application.routes.url_helpers
|
||||
include GitlabRoutingHelper
|
||||
|
||||
def initialize(type)
|
||||
@type = type
|
||||
@@ -9,18 +10,22 @@ module Gitlab
|
||||
def build(id)
|
||||
case @type
|
||||
when :issue
|
||||
issue_url(id)
|
||||
build_issue_url(id)
|
||||
when :merge_request
|
||||
build_merge_request_url(id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def issue_url(id)
|
||||
def build_issue_url(id)
|
||||
issue = Issue.find(id)
|
||||
namespace_project_issue_url(namespace_id: issue.project.namespace,
|
||||
id: issue.iid,
|
||||
project_id: issue.project,
|
||||
host: Gitlab.config.gitlab['url'])
|
||||
issue_url(issue, host: Gitlab.config.gitlab['url'])
|
||||
end
|
||||
|
||||
def build_merge_request_url(id)
|
||||
merge_request = MergeRequest.find(id)
|
||||
merge_request_url(merge_request, host: Gitlab.config.gitlab['url'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -77,16 +77,6 @@ server {
|
||||
proxy_pass http://gitlab;
|
||||
}
|
||||
|
||||
## If ``go get`` detected, return go-import meta tag.
|
||||
## This works for public and for private repositories.
|
||||
## See also http://golang.org/cmd/go/#hdr-Remote_import_paths
|
||||
if ($http_user_agent ~* "Go") {
|
||||
return 200 "
|
||||
<!DOCTYPE html>
|
||||
<head><meta content='$host$uri git $scheme://$host$uri.git' name='go-import'></head>
|
||||
</html>";
|
||||
}
|
||||
|
||||
## If a file, which is not found in the root folder is requested,
|
||||
## then the proxy passes the request to the upsteam (gitlab unicorn).
|
||||
location @gitlab {
|
||||
|
||||
@@ -123,16 +123,6 @@ server {
|
||||
proxy_pass http://gitlab;
|
||||
}
|
||||
|
||||
## If ``go get`` detected, return go-import meta tag.
|
||||
## This works for public and for private repositories.
|
||||
## See also http://golang.org/cmd/go/#hdr-Remote_import_paths
|
||||
if ($http_user_agent ~* "Go") {
|
||||
return 200 "
|
||||
<!DOCTYPE html>
|
||||
<head><meta content='$host$uri git $scheme://$host$uri.git' name='go-import'></head>
|
||||
</html>";
|
||||
}
|
||||
|
||||
## If a file, which is not found in the root folder is requested,
|
||||
## then the proxy passes the request to the upsteam (gitlab unicorn).
|
||||
location @gitlab {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
desc 'Security check via brakeman'
|
||||
task :brakeman do
|
||||
if system("brakeman --skip-files lib/backup/repository.rb -w3 -z")
|
||||
exit 0
|
||||
else
|
||||
puts 'Security check failed'
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
+1
-1
@@ -9,5 +9,5 @@ unless Rails.env.production?
|
||||
require 'coveralls/rake/task'
|
||||
Coveralls::RakeTask.new
|
||||
desc "GITLAB | Run all tests on CI with simplecov"
|
||||
task :test_ci => [:rubocop, :spinach, :spec, 'coveralls:push']
|
||||
task :test_ci => [:rubocop, :brakeman, 'jasmine:ci', :spinach, :spec, 'coveralls:push']
|
||||
end
|
||||
|
||||
@@ -7,6 +7,22 @@ describe ProjectsController do
|
||||
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
|
||||
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
|
||||
|
||||
describe "GET show" do
|
||||
|
||||
context "when requested by `go get`" do
|
||||
render_views
|
||||
|
||||
it "renders the go-import meta tag" do
|
||||
get :show, "go-get" => "1", namespace_id: "bogus_namespace", id: "bogus_project"
|
||||
|
||||
expect(response.body).to include("name='go-import'")
|
||||
|
||||
content = "localhost/bogus_namespace/bogus_project git http://localhost/bogus_namespace/bogus_project.git"
|
||||
expect(response.body).to include("content='#{content}'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST #toggle_star" do
|
||||
it "toggles star if user is signed in" do
|
||||
sign_in(user)
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe Grack::Auth do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
||||
let(:app) { lambda { |env| [200, {}, "Success!"] } }
|
||||
let!(:auth) { Grack::Auth.new(app) }
|
||||
let(:env) {
|
||||
{
|
||||
"rack.input" => "",
|
||||
"REQUEST_METHOD" => "GET",
|
||||
"QUERY_STRING" => "service=git-upload-pack"
|
||||
}
|
||||
}
|
||||
let(:status) { auth.call(env).first }
|
||||
|
||||
describe "#call" do
|
||||
context "when the project doesn't exist" do
|
||||
before do
|
||||
env["PATH_INFO"] = "doesnt/exist.git"
|
||||
end
|
||||
|
||||
context "when no authentication is provided" do
|
||||
it "responds with status 401" do
|
||||
expect(status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context "when username and password are provided" do
|
||||
context "when authentication fails" do
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, "nope")
|
||||
end
|
||||
|
||||
it "responds with status 401" do
|
||||
expect(status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context "when authentication succeeds" do
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
|
||||
end
|
||||
|
||||
it "responds with status 404" do
|
||||
expect(status).to eq(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the project exists" do
|
||||
before do
|
||||
env["PATH_INFO"] = project.path_with_namespace + ".git"
|
||||
end
|
||||
|
||||
context "when the project is public" do
|
||||
before do
|
||||
project.update_attribute(:visibility_level, Project::PUBLIC)
|
||||
end
|
||||
|
||||
it "responds with status 200" do
|
||||
expect(status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the project is private" do
|
||||
before do
|
||||
project.update_attribute(:visibility_level, Project::PRIVATE)
|
||||
end
|
||||
|
||||
context "when no authentication is provided" do
|
||||
it "responds with status 401" do
|
||||
expect(status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context "when username and password are provided" do
|
||||
context "when authentication fails" do
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, "nope")
|
||||
end
|
||||
|
||||
it "responds with status 401" do
|
||||
expect(status).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context "when authentication succeeds" do
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
|
||||
end
|
||||
|
||||
context "when the user has access to the project" do
|
||||
before do
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
context "when the user is blocked" do
|
||||
before do
|
||||
user.block
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
it "responds with status 404" do
|
||||
expect(status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the user isn't blocked" do
|
||||
it "responds with status 200" do
|
||||
expect(status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the user doesn't have access to the project" do
|
||||
it "responds with status 404" do
|
||||
expect(status).to eq(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when a gitlab ci token is provided" do
|
||||
let(:token) { "123" }
|
||||
|
||||
before do
|
||||
gitlab_ci_service = project.build_gitlab_ci_service
|
||||
gitlab_ci_service.active = true
|
||||
gitlab_ci_service.token = token
|
||||
gitlab_ci_service.project_url = "http://google.com"
|
||||
gitlab_ci_service.save
|
||||
|
||||
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials("gitlab-ci-token", token)
|
||||
end
|
||||
|
||||
it "responds with status 200" do
|
||||
expect(status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,4 +8,12 @@ describe Gitlab::UrlBuilder do
|
||||
expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
|
||||
end
|
||||
end
|
||||
|
||||
describe 'When asking for an merge request' do
|
||||
it 'returns the merge request url' do
|
||||
merge_request = create(:merge_request)
|
||||
url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id)
|
||||
expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -75,4 +75,14 @@ describe Namespace do
|
||||
expect(namespace.rm_dir).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe :find_by_path_or_name do
|
||||
before do
|
||||
@namespace = create(:namespace, name: 'WoW', path: 'woW')
|
||||
end
|
||||
|
||||
it { expect(Namespace.find_by_path_or_name('wow')).to eq(@namespace) }
|
||||
it { expect(Namespace.find_by_path_or_name('WOW')).to eq(@namespace) }
|
||||
it { expect(Namespace.find_by_path_or_name('unknown')).to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user