summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG10
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Gemfile9
-rw-r--r--Gemfile.lock28
-rw-r--r--README.md2
-rw-r--r--VERSION2
-rw-r--r--app/controllers/profiles_controller.rb15
-rw-r--r--app/models/user.rb10
-rw-r--r--app/views/admin/teams/projects/new.html.haml2
-rw-r--r--app/views/help/index.html.haml2
-rw-r--r--app/views/projects/teams/available.html.haml2
-rw-r--r--config/puma.rb.example7
-rw-r--r--config/unicorn.rb.example102
-rw-r--r--doc/api/README.md24
-rw-r--r--doc/api/projects.md25
-rw-r--r--doc/install/installation.md22
-rw-r--r--lib/api/entities.rb7
-rw-r--r--lib/api/helpers.rb6
-rw-r--r--lib/api/projects.rb36
-rw-r--r--spec/requests/api/projects_spec.rb67
20 files changed, 331 insertions, 49 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 7d1ada97c57..c20f27ad7db 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+v 5.4.0
+ - Ability to edit own comments
+ - Documentation improvements
+ - Improve dashboard projects page
+ - Fixed nav for empty repos
+ - GitLab Markdown help page
+ - Misspelling fixes
+ - Added suppoort of unicorn and fog gems
+ - Added client list to API doc
+
v 5.3.0
- Refactored services
- Campfire service added
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 761cfe3e261..2a6eb71b654 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,7 +18,7 @@ The [issue tracker](https://github.com/gitlabhq/gitlabhq/issues) is only for obv
Do not use the issue tracker for feature requests. We have a specific [feedback and suggestions forum](http://feedback.gitlab.com) for this purpose.
-Please send a pull request with a tested solution or a pull request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
+Please send a pull request with a tested solution or a pull request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
### Issue tracker guidelines
diff --git a/Gemfile b/Gemfile
index 0150ffb94ea..03d3f5c1c23 100644
--- a/Gemfile
+++ b/Gemfile
@@ -59,8 +59,9 @@ gem "haml-rails"
# Files attachments
gem "carrierwave"
+
# for aws storage
-# gem "fog", "~> 1.3.1"
+gem "fog", "~> 1.3.1", group: :aws
# Authorization
gem "six"
@@ -76,7 +77,8 @@ gem "github-markup", "~> 0.7.4", require: 'github/markup'
gem "asciidoctor"
# Servers
-gem "puma", '~> 2.0.1'
+gem "puma", '~> 2.3.1', group: :puma
+gem "unicorn", '~> 4.6.3', group: :unicorn
# State machine
gem "state_machine"
@@ -116,6 +118,9 @@ gem "d3_rails", "~> 3.1.4"
# underscore-rails
gem "underscore-rails", "~> 1.4.4"
+# Sanitize user input
+gem "sanitize"
+
group :assets do
gem "sass-rails"
gem "coffee-rails"
diff --git a/Gemfile.lock b/Gemfile.lock
index 313d2ffbca5..c26eeede69f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -116,6 +116,7 @@ GEM
erubis (2.7.0)
escape_utils (0.2.4)
eventmachine (1.0.3)
+ excon (0.13.4)
execjs (1.4.0)
multi_json (~> 1.0)
factory_girl (4.2.0)
@@ -131,6 +132,16 @@ GEM
eventmachine (>= 0.12.0)
ffaker (1.16.0)
ffi (1.8.1)
+ fog (1.3.1)
+ builder
+ excon (~> 0.13.0)
+ formatador (~> 0.2.0)
+ mime-types
+ multi_json (~> 1.0)
+ net-scp (~> 1.0.4)
+ net-ssh (>= 2.1.3)
+ nokogiri (~> 1.5.0)
+ ruby-hmac
font-awesome-rails (3.1.1.3)
railties (>= 3.2, < 5.0)
foreman (0.63.0)
@@ -243,6 +254,7 @@ GEM
kaminari (0.14.1)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
+ kgio (2.8.0)
launchy (2.2.0)
addressable (~> 2.3)
letter_opener (1.1.0)
@@ -267,6 +279,9 @@ GEM
multipart-post (1.2.0)
mysql2 (0.3.11)
net-ldap (0.3.1)
+ net-scp (1.0.4)
+ net-ssh (>= 1.99.1)
+ net-ssh (2.6.8)
nokogiri (1.5.9)
oauth (0.4.7)
oauth2 (0.8.1)
@@ -305,7 +320,7 @@ GEM
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
- puma (2.0.1)
+ puma (2.3.1)
rack (>= 1.1, < 2.0)
pygments.rb (0.4.2)
posix-spawn (~> 0.3.6)
@@ -354,6 +369,7 @@ GEM
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
+ raindrops (0.11.0)
rake (10.0.4)
rb-fsevent (0.9.3)
rb-inotify (0.9.0)
@@ -400,6 +416,7 @@ GEM
rspec-core (~> 2.13.0)
rspec-expectations (~> 2.13.0)
rspec-mocks (~> 2.13.0)
+ ruby-hmac (0.4.0)
ruby-progressbar (1.0.2)
rubyntlm (0.1.1)
rubyzip (0.9.9)
@@ -499,6 +516,10 @@ GEM
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
underscore-rails (1.4.4)
+ unicorn (4.6.3)
+ kgio (~> 2.6)
+ rack
+ raindrops (~> 0.7)
virtus (0.5.4)
backports (~> 2.6.1)
descendants_tracker (~> 0.0.1)
@@ -536,6 +557,7 @@ DEPENDENCIES
enumerize
factory_girl_rails
ffaker
+ fog (~> 1.3.1)
font-awesome-rails (~> 3.1.1)
foreman
gemoji (~> 1.2.1)
@@ -574,7 +596,7 @@ DEPENDENCIES
pg
poltergeist (~> 1.3.0)
pry
- puma (~> 2.0.1)
+ puma (~> 2.3.1)
quiet_assets (~> 1.0.1)
rack-mini-profiler
rails (= 3.2.13)
@@ -586,6 +608,7 @@ DEPENDENCIES
redcarpet (~> 2.2.2)
redis-rails
rspec-rails
+ sanitize
sass-rails
sdoc
seed-fu
@@ -608,4 +631,5 @@ DEPENDENCIES
turbolinks
uglifier
underscore-rails (~> 1.4.4)
+ unicorn (~> 4.6.3)
webmock
diff --git a/README.md b/README.md
index b5b39648a01..de773cce0eb 100644
--- a/README.md
+++ b/README.md
@@ -145,7 +145,7 @@ or start each component separately
* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) contains solutions to common problems.
-* [Support forum](https://groups.google.com/forum/#!forum/gitlabhq) and [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) are the best places to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and has resolved it. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix.
+* [Mailing list](https://groups.google.com/forum/#!forum/gitlabhq) and [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) are the best places to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and has resolved it. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix.
* [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
diff --git a/VERSION b/VERSION
index 03f488b076a..c5e18371adf 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-5.3.0
+5.4.0.pre
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 686edd8af80..6fa635d0e36 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -17,7 +17,7 @@ class ProfilesController < ApplicationController
end
def update
- if @user.update_attributes(user_attributes)
+ if @user.update_attributes(params[:user])
flash[:notice] = "Profile was successfully updated"
else
flash[:alert] = "Failed to update profile"
@@ -69,19 +69,6 @@ class ProfilesController < ApplicationController
@user = current_user
end
- def user_attributes
- user_attributes = params[:user]
-
- # Sanitize user input because we dont have strict
- # validation for this fields
- %w(name skype linkedin twitter bio).each do |attr|
- value = user_attributes[attr]
- user_attributes[attr] = sanitize(strip_tags(value)) if value.present?
- end
-
- user_attributes
- end
-
def authorize_change_password!
return render_404 if @user.ldap_user?
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 6de8d2d4c39..ddbdec8acfc 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -116,7 +116,10 @@ class User < ActiveRecord::Base
validate :namespace_uniq, if: ->(user) { user.username_changed? }
before_validation :generate_password, on: :create
+ before_validation :sanitize_attrs
+
before_save :ensure_authentication_token
+
alias_attribute :private_token, :authentication_token
delegate :path, to: :namespace, allow_nil: true, prefix: true
@@ -371,4 +374,11 @@ class User < ActiveRecord::Base
def created_by
User.find_by_id(created_by_id) if created_by_id
end
+
+ def sanitize_attrs
+ %w(name username skype linkedin twitter bio).each do |attr|
+ value = self.send(attr)
+ self.send("#{attr}=", Sanitize.clean(value)) if value.present?
+ end
+ end
end
diff --git a/app/views/admin/teams/projects/new.html.haml b/app/views/admin/teams/projects/new.html.haml
index dcb3dbbc433..21bf65f9c3d 100644
--- a/app/views/admin/teams/projects/new.html.haml
+++ b/app/views/admin/teams/projects/new.html.haml
@@ -8,7 +8,7 @@
.input
= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
- %h6 Choose greatest user acces for your team in this projects:
+ %h6 Choose greatest user access for your team in these projects:
.clearfix
= label_tag :greatest_project_access, "Greatest Access"
.input
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 1685c6eec53..80ddc05b503 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -26,7 +26,7 @@
on the top of this page
%li
Ask in our
- = link_to "support forum", "https://groups.google.com/forum/#!forum/gitlabhq"
+ = link_to "mailing list", "https://groups.google.com/forum/#!forum/gitlabhq"
or on
= link_to "Stack Overflow", "http://stackoverflow.com/questions/tagged/gitlab"
%li
diff --git a/app/views/projects/teams/available.html.haml b/app/views/projects/teams/available.html.haml
index 29fe8ed25cd..880a02aeaf5 100644
--- a/app/views/projects/teams/available.html.haml
+++ b/app/views/projects/teams/available.html.haml
@@ -10,7 +10,7 @@
.padded
= label_tag :team_id, "Team"
.input= select_tag(:team_id, options_from_collection_for_select(@teams, :id, :name), prompt: "Select team", class: "chosen xxlarge", required: true)
- %p.slead Choose greatest user acces in team you want to assign:
+ %p.slead Choose greatest user access for your team in this project:
.padded
= label_tag :team_ids, "Permission"
.input= select_tag :greatest_project_access, options_for_select(UserTeam.access_roles), {class: "project-access-select chosen span3" }
diff --git a/config/puma.rb.example b/config/puma.rb.example
index ad5e3e23501..08eace369fd 100644
--- a/config/puma.rb.example
+++ b/config/puma.rb.example
@@ -93,6 +93,13 @@ bind "unix://#{application_path}/tmp/sockets/gitlab.socket"
#
# workers 2
+# GitLab cluster mode recommendations
+# If you have more than 1 GB RAM, uncomment one of the following lines:
+#
+# workers 2 # if you have at least 1.5 GB RAM
+# workers 3 # if you have at least 2 GB RAM
+# workers 4 # if you have at least 2.5 GB RAM
+
# Code to run when a worker boots to setup the process before booting
# the app.
#
diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example
new file mode 100644
index 00000000000..00c509dd829
--- /dev/null
+++ b/config/unicorn.rb.example
@@ -0,0 +1,102 @@
+# Sample verbose configuration file for Unicorn (not Rack)
+#
+# This configuration file documents many features of Unicorn
+# that may not be needed for some applications. See
+# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
+# for a much simpler configuration file.
+#
+# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
+# documentation.
+
+# Use at least one worker per core if you're on a dedicated server,
+# more will usually help for _short_ waits on databases/caches.
+worker_processes 2
+
+# Since Unicorn is never exposed to outside clients, it does not need to
+# run on the standard HTTP port (80), there is no reason to start Unicorn
+# as root unless it's from system init scripts.
+# If running the master process as root and the workers as an unprivileged
+# user, do this to switch euid/egid in the workers (also chowns logs):
+# user "unprivileged_user", "unprivileged_group"
+
+# Help ensure your application will always spawn in the symlinked
+# "current" directory that Capistrano sets up.
+working_directory "/home/git/gitlab/current" # available in 0.94.0+
+
+# listen on both a Unix domain socket and a TCP port,
+# we use a shorter backlog for quicker failover when busy
+listen "/home/git/gitlab/tmp/sockets/gitlab.socket", :backlog => 64
+listen 8080, :tcp_nopush => true
+
+# nuke workers after 30 seconds instead of 60 seconds (the default)
+timeout 30
+
+# feel free to point this anywhere accessible on the filesystem
+pid "/home/git/gitlab/tmp/pids/unicorn.pid"
+
+# By default, the Unicorn logger will write to stderr.
+# Additionally, ome applications/frameworks log to stderr or stdout,
+# so prevent them from going to /dev/null when daemonized here:
+stderr_path "/home/git/gitlab/log/unicorn.stderr.log"
+stdout_path "/home/git/gitlab/log/unicorn.stdout.log"
+
+# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
+# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
+preload_app true
+GC.respond_to?(:copy_on_write_friendly=) and
+ GC.copy_on_write_friendly = true
+
+# Enable this flag to have unicorn test client connections by writing the
+# beginning of the HTTP headers before calling the application. This
+# prevents calling the application for connections that have disconnected
+# while queued. This is only guaranteed to detect clients on the same
+# host unicorn runs on, and unlikely to detect disconnects even on a
+# fast LAN.
+check_client_connection false
+
+before_fork do |server, worker|
+ # the following is highly recomended for Rails + "preload_app true"
+ # as there's no need for the master process to hold a connection
+ defined?(ActiveRecord::Base) and
+ ActiveRecord::Base.connection.disconnect!
+
+ # The following is only recommended for memory/DB-constrained
+ # installations. It is not needed if your system can house
+ # twice as many worker_processes as you have configured.
+ #
+ # # This allows a new master process to incrementally
+ # # phase out the old master process with SIGTTOU to avoid a
+ # # thundering herd (especially in the "preload_app false" case)
+ # # when doing a transparent upgrade. The last worker spawned
+ # # will then kill off the old master process with a SIGQUIT.
+ # old_pid = "#{server.config[:pid]}.oldbin"
+ # if old_pid != server.pid
+ # begin
+ # sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
+ # Process.kill(sig, File.read(old_pid).to_i)
+ # rescue Errno::ENOENT, Errno::ESRCH
+ # end
+ # end
+ #
+ # Throttle the master from forking too quickly by sleeping. Due
+ # to the implementation of standard Unix signal handlers, this
+ # helps (but does not completely) prevent identical, repeated signals
+ # from being lost when the receiving process is busy.
+ # sleep 1
+end
+
+after_fork do |server, worker|
+ # per-process listener ports for debugging/admin/migrations
+ # addr = "127.0.0.1:#{9293 + worker.nr}"
+ # server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true)
+
+ # the following is *required* for Rails + "preload_app true",
+ defined?(ActiveRecord::Base) and
+ ActiveRecord::Base.establish_connection
+
+ # if preload_app is true, then you may also want to check and
+ # restart any other shared sockets/descriptors such as Memcached,
+ # and Redis. TokyoCabinet file handles are safe to reuse
+ # between any number of forked children (assuming your kernel
+ # correctly implements pread()/pwrite() system calls)
+end
diff --git a/doc/api/README.md b/doc/api/README.md
index 4bcd89949df..9d6e229e4cb 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -69,18 +69,18 @@ When listing resources you can pass the following parameters:
## Contents
-+ [Users](users.md)
-+ [Session](session.md)
-+ [Projects](projects.md)
-+ [Project Snippets](project_snippets.md)
-+ [Repositories](repositories.md)
-+ [Issues](issues.md)
-+ [Milestones](milestones.md)
-+ [Notes](notes.md)
-+ [Deploy Keys](deploy_keys.md)
-+ [System Hooks](system_hooks.md)
-+ [Groups](groups.md)
-+ [User Teams](user_teams.md)
++ [Users](api/users.md)
++ [Session](api/session.md)
++ [Projects](api/projects.md)
++ [Project Snippets](api/project_snippets.md)
++ [Repositories](api/repositories.md)
++ [Issues](api/issues.md)
++ [Milestones](api/milestones.md)
++ [Notes](api/notes.md)
++ [Deploy Keys](api/deploy_keys.md)
++ [System Hooks](api/system_hooks.md)
++ [Groups](api/groups.md)
++ [User Teams](api/user_teams.md)
## Clients
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 323c0be63a4..41b6b6add39 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -453,3 +453,28 @@ Parameters:
+ `id` (required) - The ID of the project.
+ `branch` (required) - The name of the branch.
+
+## Admin fork relation
+
+Allows modification of the forked relationship between existing projects. . Available only for admins.
+
+### Create a forked from/to relation between existing projects.
+
+```
+POST /projects/:id/fork/:forked_from_id
+```
+
+Parameters:
+
++ `id` (required) - The ID of the project
++ `forked_from_id:` (required) - The ID of the project that was forked from
+
+### Delete an existing forked from relationship
+
+```
+DELETE /projects/:id/fork
+```
+
+Parameter:
+
++ `id` (required) - The ID of the project \ No newline at end of file
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 146f45f7cd6..6cad280acaf 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -42,11 +42,13 @@ up-to-date and install it.
apt-get install sudo -y
**Note:**
-Vim is an editor that is used here whenever there are files that need to be
-edited by hand. But, you can use any editor you like instead.
+During this installation some files will need to be edited manually.
+If you are familiar with vim set it as default editor with the commands below.
+If you are not familiar with vim please skip this and keep using the default editor.
- # Install vim
+ # Install vim and set as default editor
sudo apt-get install -y vim
+ sudo update-alternatives --set editor /usr/bin/vim.basic
Install the required packages:
@@ -123,7 +125,7 @@ GitLab Shell is a ssh access and repository management software developed specia
# Edit config and replace gitlab_url
# with something like 'http://domain.com/'
- sudo -u git -H vim config.yml
+ sudo -u git -H editor config.yml
# Do setup
sudo -u git -H ./bin/install
@@ -162,7 +164,7 @@ You can change `5-3-stable` to `master` if you want the *bleeding edge* version,
# Make sure to change "localhost" to the fully-qualified domain name of your
# host serving GitLab where necessary
- sudo -u git -H vim config/gitlab.yml
+ sudo -u git -H editor config/gitlab.yml
# Make sure GitLab can write to the log/ and tmp/ directories
sudo chown -R git log/
@@ -188,7 +190,7 @@ You can change `5-3-stable` to `master` if you want the *bleeding edge* version,
# Enable cluster mode if you expect to have a high load instance
# Ex. change amount of workers to 3 for 2GB RAM server
- sudo -u git -H vim config/puma.rb
+ sudo -u git -H editor config/puma.rb
# Configure Git global settings for git user, useful when editing via web
# Edit user.email according to what is set in gitlab.yml
@@ -214,7 +216,7 @@ Make sure to edit both `gitlab.yml` and `puma.rb` to match your setup.
# Change 'root' to 'gitlab'
# Change 'secure password' with the value you have given to $password
# You can keep the double quotes around the password
- sudo -u git -H vim config/database.yml
+ sudo -u git -H editor config/database.yml
# Make config/database.yml readable to git only
sudo -u git -H chmod o-rwx config/database.yml
@@ -226,10 +228,10 @@ Make sure to edit both `gitlab.yml` and `puma.rb` to match your setup.
sudo gem install charlock_holmes --version '0.6.9.4'
# For MySQL (note, the option says "without ... postgres")
- sudo -u git -H bundle install --deployment --without development test postgres
+ sudo -u git -H bundle install --deployment --without development test postgres unicorn aws
# Or for PostgreSQL (note, the option says "without ... mysql")
- sudo -u git -H bundle install --deployment --without development test mysql
+ sudo -u git -H bundle install --deployment --without development test mysql unicorn aws
## Initialize Database and Activate Advanced Features
@@ -295,7 +297,7 @@ Make sure to edit the config file to match your setup:
# Change YOUR_SERVER_FQDN to the fully-qualified
# domain name of your host serving GitLab.
- sudo vim /etc/nginx/sites-available/gitlab
+ sudo editor /etc/nginx/sites-available/gitlab
## Restart
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 0d8cac5c8fd..dea5771d6b6 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -25,6 +25,12 @@ module API
expose :id, :url, :created_at
end
+ class ForkedFromProject < Grape::Entity
+ expose :id
+ expose :name, :name_with_namespace
+ expose :path, :path_with_namespace
+ end
+
class Project < Grape::Entity
expose :id, :description, :default_branch, :public, :ssh_url_to_repo, :http_url_to_repo, :web_url
expose :owner, using: Entities::UserBasic
@@ -32,6 +38,7 @@ module API
expose :path, :path_with_namespace
expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at, :last_activity_at
expose :namespace
+ expose :forked_from_project, using: Entities::ForkedFromProject, :if => lambda{ | project, options | project.forked? }
end
class ProjectMember < UserBasic
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 94cf4f2e69f..f857d4133b2 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -5,12 +5,12 @@ module API
end
def user_project
- @project ||= find_project
+ @project ||= find_project(params[:id])
@project || not_found!
end
- def find_project
- project = Project.find_by_id(params[:id]) || Project.find_with_namespace(params[:id])
+ def find_project(id)
+ project = Project.find_by_id(id) || Project.find_with_namespace(id)
if project && can?(current_user, :read_project, project)
project
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 6dc051e4ba2..d5709f5cb59 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -121,6 +121,42 @@ module API
end
+ # Mark this project as forked from another
+ #
+ # Parameters:
+ # id: (required) - The ID of the project being marked as a fork
+ # forked_from_id: (required) - The ID of the project it was forked from
+ # Example Request:
+ # POST /projects/:id/fork/:forked_from_id
+ post ":id/fork/:forked_from_id" do
+ authenticated_as_admin!
+ forked_from_project = find_project(params[:forked_from_id])
+ unless forked_from_project.nil?
+ if user_project.forked_from_project.nil?
+ user_project.create_forked_project_link(forked_to_project_id: user_project.id, forked_from_project_id: forked_from_project.id)
+ else
+ render_api_error!("Project already forked", 409)
+ end
+ else
+ not_found!
+ end
+
+ end
+
+ # Remove a forked_from relationship
+ #
+ # Parameters:
+ # id: (required) - The ID of the project being marked as a fork
+ # Example Request:
+ # DELETE /projects/:id/fork
+ delete ":id/fork" do
+ authenticated_as_admin!
+ unless user_project.forked_project_link.nil?
+ user_project.forked_project_link.destroy
+ end
+ end
+
+
# Get a project team members
#
# Parameters:
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 31075149647..a6612af83eb 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -595,4 +595,71 @@ describe API::API do
end
end
end
+
+ describe :fork_admin do
+ let(:project_fork_target) { create(:project) }
+ let(:project_fork_source) { create(:project, public: true) }
+
+ describe "POST /projects/:id/fork/:forked_from_id" do
+ let(:new_project_fork_source) { create(:project, public: true) }
+
+ it "shouldn't available for non admin users" do
+ post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
+ response.status.should == 403
+ end
+
+ it "should allow project to be forked from an existing project" do
+ project_fork_target.forked?.should_not be_true
+ post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
+ response.status.should == 201
+ project_fork_target.reload
+ project_fork_target.forked_from_project.id.should == project_fork_source.id
+ project_fork_target.forked_project_link.should_not be_nil
+ project_fork_target.forked?.should be_true
+ end
+
+ it "should fail if forked_from project which does not exist" do
+ post api("/projects/#{project_fork_target.id}/fork/9999", admin)
+ response.status.should == 404
+ end
+
+ it "should fail with 409 if already forked" do
+ post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
+ project_fork_target.reload
+ project_fork_target.forked_from_project.id.should == project_fork_source.id
+ post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
+ response.status.should == 409
+ project_fork_target.reload
+ project_fork_target.forked_from_project.id.should == project_fork_source.id
+ project_fork_target.forked?.should be_true
+ end
+ end
+
+ describe "DELETE /projects/:id/fork" do
+
+ it "shouldn't available for non admin users" do
+ delete api("/projects/#{project_fork_target.id}/fork", user)
+ response.status.should == 403
+ end
+
+ it "should make forked project unforked" do
+ post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
+ project_fork_target.reload
+ project_fork_target.forked_from_project.should_not be_nil
+ project_fork_target.forked?.should be_true
+ delete api("/projects/#{project_fork_target.id}/fork", admin)
+ response.status.should == 200
+ project_fork_target.reload
+ project_fork_target.forked_from_project.should be_nil
+ project_fork_target.forked?.should_not be_true
+ end
+
+ it "should be idempotent if not forked" do
+ project_fork_target.forked_from_project.should be_nil
+ delete api("/projects/#{project_fork_target.id}/fork", admin)
+ response.status.should == 200
+ project_fork_target.reload.forked_from_project.should be_nil
+ end
+ end
+ end
end