Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
f40d4e66
Commit
f40d4e66
authored
May 02, 2013
by
Dmitriy Zaporozhets
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3597 from amacarthur/fork-pull-request
updated fork feature to use gitlab-shell for v5 of gitlab
parents
36efe0f5
ec638048
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
293 additions
and
6 deletions
+293
-6
app/contexts/projects/fork_context.rb
app/contexts/projects/fork_context.rb
+45
-0
app/controllers/projects_controller.rb
app/controllers/projects_controller.rb
+15
-0
app/models/ability.rb
app/models/ability.rb
+3
-1
app/models/forked_project_link.rb
app/models/forked_project_link.rb
+8
-0
app/models/project.rb
app/models/project.rb
+7
-0
app/observers/project_observer.rb
app/observers/project_observer.rb
+7
-5
app/views/projects/_clone_panel.html.haml
app/views/projects/_clone_panel.html.haml
+3
-0
config/routes.rb
config/routes.rb
+1
-0
db/migrate/20130319214458_create_forked_project_links.rb
db/migrate/20130319214458_create_forked_project_links.rb
+11
-0
db/schema.rb
db/schema.rb
+9
-0
features/project/fork_project.feature
features/project/fork_project.feature
+14
-0
features/steps/project/project_fork.rb
features/steps/project/project_fork.rb
+30
-0
lib/gitlab/backend/shell.rb
lib/gitlab/backend/shell.rb
+12
-0
spec/contexts/fork_context_spec.rb
spec/contexts/fork_context_spec.rb
+57
-0
spec/factories/forked_project_links.rb
spec/factories/forked_project_links.rb
+8
-0
spec/lib/gitlab/backend/shell_spec.rb
spec/lib/gitlab/backend/shell_spec.rb
+1
-0
spec/models/forked_project_link_spec.rb
spec/models/forked_project_link_spec.rb
+56
-0
spec/models/project_spec.rb
spec/models/project_spec.rb
+1
-0
spec/routing/project_routing_spec.rb
spec/routing/project_routing_spec.rb
+5
-0
No files found.
app/contexts/projects/fork_context.rb
0 → 100644
View file @
f40d4e66
module
Projects
class
ForkContext
<
BaseContext
include
Gitlab
::
ShellAdapter
def
initialize
(
project
,
user
)
@from_project
,
@current_user
=
project
,
user
end
def
execute
project
=
Project
.
new
project
.
initialize_dup
(
@from_project
)
project
.
name
=
@from_project
.
name
project
.
path
=
@from_project
.
path
project
.
namespace
=
current_user
.
namespace
project
.
creator
=
current_user
# If the project cannot save, we do not want to trigger the project destroy
# as this can have the side effect of deleting a repo attached to an existing
# project with the same name and namespace
if
project
.
valid?
begin
Project
.
transaction
do
#First save the DB entries as they can be rolled back if the repo fork fails
project
.
build_forked_project_link
(
forked_to_project_id:
project
.
id
,
forked_from_project_id:
@from_project
.
id
)
if
project
.
save
project
.
users_projects
.
create
(
project_access:
UsersProject
::
MASTER
,
user:
current_user
)
end
#Now fork the repo
unless
gitlab_shell
.
fork_repository
(
@from_project
.
path_with_namespace
,
project
.
namespace
.
path
)
raise
"forking failed in gitlab-shell"
end
project
.
ensure_satellite_exists
end
rescue
=>
ex
project
.
errors
.
add
(
:base
,
"Fork transaction failed."
)
project
.
destroy
end
else
project
.
errors
.
add
(
:base
,
"Invalid fork destination"
)
end
project
end
end
end
app/controllers/projects_controller.rb
View file @
f40d4e66
...
@@ -78,4 +78,19 @@ class ProjectsController < ProjectResourceController
...
@@ -78,4 +78,19 @@ class ProjectsController < ProjectResourceController
format
.
html
{
redirect_to
root_path
}
format
.
html
{
redirect_to
root_path
}
end
end
end
end
def
fork
@project
=
::
Projects
::
ForkContext
.
new
(
project
,
current_user
).
execute
respond_to
do
|
format
|
format
.
html
do
if
@project
.
saved?
&&
@project
.
forked?
redirect_to
(
@project
,
notice:
'Project was successfully forked.'
)
else
render
action:
"new"
end
end
format
.
js
end
end
end
end
app/models/ability.rb
View file @
f40d4e66
...
@@ -67,7 +67,9 @@ class Ability
...
@@ -67,7 +67,9 @@ class Ability
def
project_report_rules
def
project_report_rules
project_guest_rules
+
[
project_guest_rules
+
[
:download_code
,
:download_code
,
:write_snippet
:write_snippet
,
:fork_project
]
]
end
end
...
...
app/models/forked_project_link.rb
0 → 100644
View file @
f40d4e66
class
ForkedProjectLink
<
ActiveRecord
::
Base
attr_accessible
:forked_from_project_id
,
:forked_to_project_id
# Relations
belongs_to
:forked_to_project
,
class_name:
Project
belongs_to
:forked_from_project
,
class_name:
Project
end
app/models/project.rb
View file @
f40d4e66
...
@@ -45,6 +45,8 @@ class Project < ActiveRecord::Base
...
@@ -45,6 +45,8 @@ class Project < ActiveRecord::Base
has_one
:last_event
,
class_name:
'Event'
,
order:
'events.created_at DESC'
,
foreign_key:
'project_id'
has_one
:last_event
,
class_name:
'Event'
,
order:
'events.created_at DESC'
,
foreign_key:
'project_id'
has_one
:gitlab_ci_service
,
dependent: :destroy
has_one
:gitlab_ci_service
,
dependent: :destroy
has_one
:forked_project_link
,
dependent: :destroy
,
foreign_key:
"forked_to_project_id"
has_one
:forked_from_project
,
through: :forked_project_link
has_many
:events
,
dependent: :destroy
has_many
:events
,
dependent: :destroy
has_many
:merge_requests
,
dependent: :destroy
has_many
:merge_requests
,
dependent: :destroy
...
@@ -402,4 +404,9 @@ class Project < ActiveRecord::Base
...
@@ -402,4 +404,9 @@ class Project < ActiveRecord::Base
def
protected_branch?
branch_name
def
protected_branch?
branch_name
protected_branches_names
.
include?
(
branch_name
)
protected_branches_names
.
include?
(
branch_name
)
end
end
def
forked?
!
(
forked_project_link
.
nil?
||
forked_project_link
.
forked_from_project
.
nil?
)
end
end
end
app/observers/project_observer.rb
View file @
f40d4e66
class
ProjectObserver
<
BaseObserver
class
ProjectObserver
<
BaseObserver
def
after_create
(
project
)
def
after_create
(
project
)
unless
project
.
forked?
GitlabShellWorker
.
perform_async
(
GitlabShellWorker
.
perform_async
(
:add_repository
,
:add_repository
,
project
.
path_with_namespace
project
.
path_with_namespace
...
@@ -7,6 +8,7 @@ class ProjectObserver < BaseObserver
...
@@ -7,6 +8,7 @@ class ProjectObserver < BaseObserver
log_info
(
"
#{
project
.
owner
.
name
}
created a new project
\"
#{
project
.
name_with_namespace
}
\"
"
)
log_info
(
"
#{
project
.
owner
.
name
}
created a new project
\"
#{
project
.
name_with_namespace
}
\"
"
)
end
end
end
def
after_update
(
project
)
def
after_update
(
project
)
project
.
send_move_instructions
if
project
.
namespace_id_changed?
project
.
send_move_instructions
if
project
.
namespace_id_changed?
...
...
app/views/projects/_clone_panel.html.haml
View file @
f40d4e66
...
@@ -5,6 +5,9 @@
...
@@ -5,6 +5,9 @@
.span3.pull-right
.span3.pull-right
.pull-right
.pull-right
-
unless
@project
.
empty_repo?
-
unless
@project
.
empty_repo?
-
if
can?
current_user
,
:fork_project
,
@project
=
link_to
fork_project_path
(
@project
),
title:
"Fork"
,
class:
"btn small grouped"
,
method:
"POST"
do
Fork
-
if
can?
current_user
,
:download_code
,
@project
-
if
can?
current_user
,
:download_code
,
@project
=
link_to
archive_project_repository_path
(
@project
),
class:
"btn grouped"
do
=
link_to
archive_project_repository_path
(
@project
),
class:
"btn grouped"
do
%i
.icon-download-alt
%i
.icon-download-alt
...
...
config/routes.rb
View file @
f40d4e66
...
@@ -167,6 +167,7 @@ Gitlab::Application.routes.draw do
...
@@ -167,6 +167,7 @@ Gitlab::Application.routes.draw do
resources
:projects
,
constraints:
{
id:
/(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/
},
except:
[
:new
,
:create
,
:index
],
path:
"/"
do
resources
:projects
,
constraints:
{
id:
/(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/
},
except:
[
:new
,
:create
,
:index
],
path:
"/"
do
member
do
member
do
put
:transfer
put
:transfer
post
:fork
end
end
resources
:blob
,
only:
[
:show
],
constraints:
{
id:
/.+/
}
resources
:blob
,
only:
[
:show
],
constraints:
{
id:
/.+/
}
...
...
db/migrate/20130319214458_create_forked_project_links.rb
0 → 100644
View file @
f40d4e66
class
CreateForkedProjectLinks
<
ActiveRecord
::
Migration
def
change
create_table
:forked_project_links
do
|
t
|
t
.
integer
:forked_to_project_id
,
null:
false
t
.
integer
:forked_from_project_id
,
null:
false
t
.
timestamps
end
add_index
:forked_project_links
,
:forked_to_project_id
,
unique:
true
end
end
db/schema.rb
View file @
f40d4e66
...
@@ -32,6 +32,15 @@ ActiveRecord::Schema.define(:version => 20130410175022) do
...
@@ -32,6 +32,15 @@ ActiveRecord::Schema.define(:version => 20130410175022) do
add_index
"events"
,
[
"target_id"
],
:name
=>
"index_events_on_target_id"
add_index
"events"
,
[
"target_id"
],
:name
=>
"index_events_on_target_id"
add_index
"events"
,
[
"target_type"
],
:name
=>
"index_events_on_target_type"
add_index
"events"
,
[
"target_type"
],
:name
=>
"index_events_on_target_type"
create_table
"forked_project_links"
,
:force
=>
true
do
|
t
|
t
.
integer
"forked_to_project_id"
,
:null
=>
false
t
.
integer
"forked_from_project_id"
,
:null
=>
false
t
.
datetime
"created_at"
,
:null
=>
false
t
.
datetime
"updated_at"
,
:null
=>
false
end
add_index
"forked_project_links"
,
[
"forked_to_project_id"
],
:name
=>
"index_forked_project_links_on_forked_to_project_id"
,
:unique
=>
true
create_table
"issues"
,
:force
=>
true
do
|
t
|
create_table
"issues"
,
:force
=>
true
do
|
t
|
t
.
string
"title"
t
.
string
"title"
t
.
integer
"assignee_id"
t
.
integer
"assignee_id"
...
...
features/project/fork_project.feature
0 → 100644
View file @
f40d4e66
Feature
:
Fork Project
Background
:
Given
I sign in as a user
And
I am a member of project
"Shop"
When
I visit project
"Shop"
page
Scenario
:
User fork a project
Given
I click link
"Fork"
Then
I should see the forked project page
Scenario
:
User already has forked the project
Given
I already have a project named
"Shop"
in my namespace
And
I click link
"Fork"
Then
I should see a
"Name has already been taken"
warning
features/steps/project/project_fork.rb
0 → 100644
View file @
f40d4e66
class
ForkProject
<
Spinach
::
FeatureSteps
include
SharedAuthentication
include
SharedPaths
include
SharedProject
step
'I click link "Fork"'
do
Gitlab
::
Shell
.
any_instance
.
stub
(
:fork_repository
).
and_return
(
true
)
click_link
"Fork"
end
step
'I am a member of project "Shop"'
do
@project
=
Project
.
find_by_name
"Shop"
@project
||=
create
(
:project_with_code
,
name:
"Shop"
)
@project
.
team
<<
[
@user
,
:reporter
]
end
step
'I should see the forked project page'
do
page
.
should
have_content
"Project was successfully forked."
current_path
.
should
include
current_user
.
namespace
.
path
end
step
'I already have a project named "Shop" in my namespace'
do
@my_project
=
create
(
:project_with_code
,
name:
"Shop"
,
namespace:
current_user
.
namespace
)
end
step
'I should see a "Name has already been taken" warning'
do
page
.
should
have_content
"Name has already been taken"
end
end
\ No newline at end of file
lib/gitlab/backend/shell.rb
View file @
f40d4e66
...
@@ -36,6 +36,18 @@ module Gitlab
...
@@ -36,6 +36,18 @@ module Gitlab
system
(
"
#{
gitlab_shell_user_home
}
/gitlab-shell/bin/gitlab-projects mv-project
#{
path
}
.git
#{
new_path
}
.git"
)
system
(
"
#{
gitlab_shell_user_home
}
/gitlab-shell/bin/gitlab-projects mv-project
#{
path
}
.git
#{
new_path
}
.git"
)
end
end
# Fork repository to new namespace
#
# path - project path with namespace
# fork_namespace - namespace for forked project
#
# Ex.
# fork_repository("gitlab/gitlab-ci", "randx")
#
def
fork_repository
(
path
,
fork_namespace
)
system
(
"
#{
gitlab_shell_user_home
}
/gitlab-shell/bin/gitlab-projects fork-project
#{
path
}
.git
#{
fork_namespace
}
"
)
end
# Remove repository from file system
# Remove repository from file system
#
#
# name - project path with namespace
# name - project path with namespace
...
...
spec/contexts/fork_context_spec.rb
0 → 100644
View file @
f40d4e66
require
'spec_helper'
describe
Projects
::
ForkContext
do
describe
:fork_by_user
do
before
do
@from_namespace
=
create
(
:namespace
)
@from_user
=
create
(
:user
,
namespace:
@from_namespace
)
@from_project
=
create
(
:project
,
creator_id:
@from_user
.
id
,
namespace:
@from_namespace
)
@to_namespace
=
create
(
:namespace
)
@to_user
=
create
(
:user
,
namespace:
@to_namespace
)
end
context
'fork project'
do
it
"successfully creates project in the user namespace"
do
@to_project
=
fork_project
(
@from_project
,
@to_user
)
@to_project
.
owner
.
should
==
@to_user
@to_project
.
namespace
.
should
==
@to_user
.
namespace
end
end
context
'fork project failure'
do
it
"fails due to transaction failure"
do
# make the mock gitlab-shell fail
@to_project
=
fork_project
(
@from_project
,
@to_user
,
false
)
@to_project
.
errors
.
should_not
be_empty
@to_project
.
errors
[
:base
].
should
include
(
"Fork transaction failed."
)
end
end
context
'project already exists'
do
it
"should fail due to validation, not transaction failure"
do
@existing_project
=
create
(
:project
,
creator_id:
@to_user
.
id
,
name:
@from_project
.
name
,
namespace:
@to_namespace
)
@to_project
=
fork_project
(
@from_project
,
@to_user
)
@existing_project
.
persisted?
.
should
be_true
@to_project
.
errors
[
:base
].
should
include
(
"Invalid fork destination"
)
@to_project
.
errors
[
:base
].
should_not
include
(
"Fork transaction failed."
)
end
end
end
def
fork_project
(
from_project
,
user
,
fork_success
=
true
)
context
=
Projects
::
ForkContext
.
new
(
from_project
,
user
)
shell
=
mock
(
"gitlab_shell"
)
shell
.
stub
(
fork_repository:
fork_success
)
context
.
stub
(
gitlab_shell:
shell
)
context
.
execute
end
end
spec/factories/forked_project_links.rb
0 → 100644
View file @
f40d4e66
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl
.
define
do
factory
:forked_project_link
do
association
:forked_to_project
,
factory: :project
association
:forked_from_project
,
factory: :project
end
end
spec/lib/gitlab/backend/shell_spec.rb
View file @
f40d4e66
...
@@ -12,6 +12,7 @@ describe Gitlab::Shell do
...
@@ -12,6 +12,7 @@ describe Gitlab::Shell do
it
{
should
respond_to
:remove_key
}
it
{
should
respond_to
:remove_key
}
it
{
should
respond_to
:add_repository
}
it
{
should
respond_to
:add_repository
}
it
{
should
respond_to
:remove_repository
}
it
{
should
respond_to
:remove_repository
}
it
{
should
respond_to
:fork_repository
}
it
{
gitlab_shell
.
url_to_repo
(
'diaspora'
).
should
==
Gitlab
.
config
.
gitlab_shell
.
ssh_path_prefix
+
"diaspora.git"
}
it
{
gitlab_shell
.
url_to_repo
(
'diaspora'
).
should
==
Gitlab
.
config
.
gitlab_shell
.
ssh_path_prefix
+
"diaspora.git"
}
end
end
spec/models/forked_project_link_spec.rb
0 → 100644
View file @
f40d4e66
require
'spec_helper'
describe
ForkedProjectLink
,
"add link on fork"
do
let
(
:project_from
)
{
create
(
:project
)}
let
(
:namespace
)
{
create
(
:namespace
)}
let
(
:user
)
{
create
(
:user
,
namespace:
namespace
)}
before
do
@project_to
=
fork_project
(
project_from
,
user
)
end
it
"project_to should know it is forked"
do
@project_to
.
forked?
.
should
be_true
end
it
"project should know who it is forked from"
do
@project_to
.
forked_from_project
.
should
==
project_from
end
end
describe
:forked_from_project
do
let
(
:forked_project_link
)
{
build
(
:forked_project_link
)}
let
(
:project_from
)
{
create
(
:project
)}
let
(
:project_to
)
{
create
(
:project
,
forked_project_link:
forked_project_link
)}
before
:each
do
forked_project_link
.
forked_from_project
=
project_from
forked_project_link
.
forked_to_project
=
project_to
forked_project_link
.
save!
end
it
"project_to should know it is forked"
do
project_to
.
forked?
.
should
be_true
end
it
"project_from should not be forked"
do
project_from
.
forked?
.
should
be_false
end
it
"project_to.destroy should destroy fork_link"
do
forked_project_link
.
should_receive
(
:destroy
)
project_to
.
destroy
end
end
def
fork_project
(
from_project
,
user
)
context
=
Projects
::
ForkContext
.
new
(
from_project
,
user
)
shell
=
mock
(
"gitlab_shell"
)
shell
.
stub
(
fork_repository:
true
)
context
.
stub
(
gitlab_shell:
shell
)
context
.
execute
end
spec/models/project_spec.rb
View file @
f40d4e66
...
@@ -40,6 +40,7 @@ describe Project do
...
@@ -40,6 +40,7 @@ describe Project do
it
{
should
have_many
(
:deploy_keys
).
dependent
(
:destroy
)
}
it
{
should
have_many
(
:deploy_keys
).
dependent
(
:destroy
)
}
it
{
should
have_many
(
:hooks
).
dependent
(
:destroy
)
}
it
{
should
have_many
(
:hooks
).
dependent
(
:destroy
)
}
it
{
should
have_many
(
:protected_branches
).
dependent
(
:destroy
)
}
it
{
should
have_many
(
:protected_branches
).
dependent
(
:destroy
)
}
it
{
should
have_one
(
:forked_project_link
).
dependent
(
:destroy
)
}
end
end
describe
"Mass assignment"
do
describe
"Mass assignment"
do
...
...
spec/routing/project_routing_spec.rb
View file @
f40d4e66
...
@@ -55,6 +55,7 @@ end
...
@@ -55,6 +55,7 @@ end
# projects POST /projects(.:format) projects#create
# projects POST /projects(.:format) projects#create
# new_project GET /projects/new(.:format) projects#new
# new_project GET /projects/new(.:format) projects#new
# fork_project POST /:id/fork(.:format) projects#fork
# wall_project GET /:id/wall(.:format) projects#wall
# wall_project GET /:id/wall(.:format) projects#wall
# files_project GET /:id/files(.:format) projects#files
# files_project GET /:id/files(.:format) projects#files
# edit_project GET /:id/edit(.:format) projects#edit
# edit_project GET /:id/edit(.:format) projects#edit
...
@@ -70,6 +71,10 @@ describe ProjectsController, "routing" do
...
@@ -70,6 +71,10 @@ describe ProjectsController, "routing" do
get
(
"/projects/new"
).
should
route_to
(
'projects#new'
)
get
(
"/projects/new"
).
should
route_to
(
'projects#new'
)
end
end
it
"to #fork"
do
post
(
"/gitlabhq/fork"
).
should
route_to
(
'projects#fork'
,
id:
'gitlabhq'
)
end
it
"to #wall"
do
it
"to #wall"
do
get
(
"/gitlabhq/wall"
).
should
route_to
(
'walls#show'
,
project_id:
'gitlabhq'
)
get
(
"/gitlabhq/wall"
).
should
route_to
(
'walls#show'
,
project_id:
'gitlabhq'
)
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment