mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-10 21:26:07 +10:00
Add option to mirror an upstream repository. Closes internal https://dev.gitlab.org/gitlab/gitlab-ee/issues/279 Depends on gitlab-org/gitlab-shell!29 To do: - [x] Decide on what user should be the author of the activity feed events. The initial project creator perhaps? That makes sense for personal projects, but less so for group projects, where it's even possible that the creator has since left the team. - [x] Write specs! - [x] Write documentation - [x] Port back relevant commits to CE: gitlab-org/gitlab-ce!1822 ---- ## Mirror status on project homepage  ## Settings navigation item  ## Mirroring settings  ## Activity feed with new "pushes" (mirror updates)  I have yet to decide on what user should be the author of these events. The initial project creator perhaps? That makes sense for personal projects, but less so for group projects, where it's even possible that the creator has since left the team. ## Warning that branch has diverged from upstream  ## Commits heading after failed update  Link send user to the mirroring settings if they are a project admin. ## Mirroring settings after failed update  ## New project page  ## Import form after failed import (Screenshot outdated)  Shown when the initial import of a project fails, not when an update of an existing project fails. cc @dzaporozhets @sytses @JobV See merge request !51
276 lines
6.7 KiB
Ruby
276 lines
6.7 KiB
Ruby
class ProjectsController < ApplicationController
|
|
include ExtractsPath
|
|
|
|
prepend_before_action :render_go_import, only: [:show]
|
|
skip_before_action :authenticate_user!, only: [:show, :activity]
|
|
before_action :project, except: [:new, :create]
|
|
before_action :repository, except: [:new, :create]
|
|
before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
|
|
|
|
# Authorize
|
|
before_action :authorize_admin_project!, only: [:edit, :update]
|
|
before_action :event_filter, only: [:show, :activity]
|
|
|
|
layout :determine_layout
|
|
|
|
def index
|
|
redirect_to(current_user ? root_path : explore_root_path)
|
|
end
|
|
|
|
def new
|
|
@project = Project.new
|
|
end
|
|
|
|
def edit
|
|
render 'edit'
|
|
end
|
|
|
|
def create
|
|
@project = ::Projects::CreateService.new(current_user, project_params).execute
|
|
|
|
if @project.saved?
|
|
redirect_to(
|
|
project_path(@project),
|
|
notice: "Project '#{@project.name}' was successfully created."
|
|
)
|
|
else
|
|
render 'new'
|
|
end
|
|
end
|
|
|
|
def update
|
|
status = ::Projects::UpdateService.new(@project, current_user, project_params).execute
|
|
|
|
respond_to do |format|
|
|
if status
|
|
flash[:notice] = "Project '#{@project.name}' was successfully updated."
|
|
format.html do
|
|
redirect_to(
|
|
edit_project_path(@project),
|
|
notice: "Project '#{@project.name}' was successfully updated."
|
|
)
|
|
end
|
|
format.js
|
|
else
|
|
format.html { render 'edit' }
|
|
format.js
|
|
end
|
|
end
|
|
end
|
|
|
|
def transfer
|
|
return access_denied! unless can?(current_user, :change_namespace, @project)
|
|
|
|
namespace = Namespace.find_by(id: params[:new_namespace_id])
|
|
::Projects::TransferService.new(project, current_user).execute(namespace)
|
|
|
|
if @project.errors[:new_namespace].present?
|
|
flash[:alert] = @project.errors[:new_namespace].first
|
|
end
|
|
end
|
|
|
|
def remove_fork
|
|
return access_denied! unless can?(current_user, :remove_fork_project, @project)
|
|
|
|
if @project.unlink_fork
|
|
flash[:notice] = 'The fork relationship has been removed.'
|
|
end
|
|
end
|
|
|
|
def activity
|
|
respond_to do |format|
|
|
format.html
|
|
format.json do
|
|
load_events
|
|
pager_json('events/_events', @events.count)
|
|
end
|
|
end
|
|
end
|
|
|
|
def show
|
|
# If we're importing while we do have a repository, we're simply updating the mirror.
|
|
if @project.import_in_progress? && !@project.updating_mirror?
|
|
redirect_to namespace_project_import_path(@project.namespace, @project)
|
|
return
|
|
end
|
|
|
|
respond_to do |format|
|
|
format.html do
|
|
if @project.repository_exists?
|
|
if @project.empty_repo?
|
|
render 'projects/empty'
|
|
else
|
|
if current_user
|
|
@membership = @project.team.find_member(current_user.id)
|
|
end
|
|
|
|
render :show
|
|
end
|
|
else
|
|
render 'projects/no_repo'
|
|
end
|
|
end
|
|
|
|
format.atom do
|
|
load_events
|
|
render layout: false
|
|
end
|
|
end
|
|
end
|
|
|
|
def destroy
|
|
return access_denied! unless can?(current_user, :remove_project, @project)
|
|
|
|
::Projects::DestroyService.new(@project, current_user, {}).execute
|
|
flash[:alert] = "Project '#{@project.name}' was deleted."
|
|
|
|
redirect_back_or_default(default: dashboard_projects_path, options: {})
|
|
rescue Projects::DestroyService::DestroyError => ex
|
|
redirect_to edit_project_path(@project), alert: ex.message
|
|
end
|
|
|
|
def autocomplete_sources
|
|
note_type = params['type']
|
|
note_id = params['type_id']
|
|
autocomplete = ::Projects::AutocompleteService.new(@project)
|
|
participants = ::Projects::ParticipantsService.new(@project, current_user).execute(note_type, note_id)
|
|
|
|
@suggestions = {
|
|
emojis: autocomplete_emojis,
|
|
issues: autocomplete.issues,
|
|
mergerequests: autocomplete.merge_requests,
|
|
members: participants
|
|
}
|
|
|
|
respond_to do |format|
|
|
format.json { render json: @suggestions }
|
|
end
|
|
end
|
|
|
|
def archive
|
|
return access_denied! unless can?(current_user, :archive_project, @project)
|
|
|
|
@project.archive!
|
|
|
|
respond_to do |format|
|
|
format.html { redirect_to project_path(@project) }
|
|
end
|
|
end
|
|
|
|
def unarchive
|
|
return access_denied! unless can?(current_user, :archive_project, @project)
|
|
|
|
@project.unarchive!
|
|
|
|
respond_to do |format|
|
|
format.html { redirect_to project_path(@project) }
|
|
end
|
|
end
|
|
|
|
def toggle_star
|
|
current_user.toggle_star(@project)
|
|
@project.reload
|
|
|
|
render json: {
|
|
html: view_to_html_string("projects/buttons/_star")
|
|
}
|
|
end
|
|
|
|
def markdown_preview
|
|
text = params[:text]
|
|
|
|
ext = Gitlab::ReferenceExtractor.new(@project, current_user)
|
|
ext.analyze(text)
|
|
|
|
render json: {
|
|
body: view_context.markdown(text),
|
|
references: {
|
|
users: ext.users.map(&:username)
|
|
}
|
|
}
|
|
end
|
|
|
|
private
|
|
|
|
def determine_layout
|
|
if [:new, :create].include?(action_name.to_sym)
|
|
'application'
|
|
elsif [:edit, :update].include?(action_name.to_sym)
|
|
'project_settings'
|
|
else
|
|
'project'
|
|
end
|
|
end
|
|
|
|
def load_events
|
|
@events = @project.events.recent
|
|
@events = event_filter.apply_filter(@events).with_associations
|
|
limit = (params[:limit] || 20).to_i
|
|
@events = @events.limit(limit).offset(params[:offset] || 0)
|
|
end
|
|
|
|
def project_params
|
|
params.require(:project).permit(
|
|
:avatar,
|
|
:builds_enabled,
|
|
:default_branch,
|
|
:description,
|
|
:import_url,
|
|
:issues_enabled,
|
|
:issues_tracker,
|
|
:issues_tracker_id,
|
|
:last_activity_at,
|
|
:merge_requests_enabled,
|
|
:name,
|
|
:namespace_id,
|
|
:path,
|
|
:snippets_enabled,
|
|
:tag_list,
|
|
:visibility_level,
|
|
:wiki_enabled,
|
|
|
|
# EE-only
|
|
:approvals_before_merge,
|
|
:approver_ids,
|
|
:issues_template,
|
|
:merge_requests_ff_only_enabled,
|
|
:merge_requests_rebase_enabled,
|
|
:merge_requests_template,
|
|
:mirror,
|
|
:mirror_user_id,
|
|
:reset_approvals_on_push
|
|
)
|
|
end
|
|
|
|
def autocomplete_emojis
|
|
Rails.cache.fetch("autocomplete-emoji-#{Gemojione::VERSION}") do
|
|
Emoji.emojis.map do |name, emoji|
|
|
{
|
|
name: name,
|
|
path: view_context.image_url("emoji/#{emoji["unicode"]}.png")
|
|
}
|
|
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
|
|
|
|
def repo_exists?
|
|
project.repository_exists? && !project.empty_repo?
|
|
end
|
|
|
|
# Override get_id from ExtractsPath, which returns the branch and file path
|
|
# for the blob/tree, which in this case is just the root of the default branch.
|
|
def get_id
|
|
project.repository.root_ref
|
|
end
|
|
end
|