Merge branch 'master' into rails-4.1.9
Conflicts: app/views/projects/commits/_commit.html.haml app/views/projects/issues/_issue.html.haml app/views/projects/issues/_issue_context.html.haml app/views/projects/merge_requests/_merge_request.html.haml app/views/projects/merge_requests/show/_context.html.haml
This commit is contained in:
commit
2a9eed6620
|
@ -1,7 +1,10 @@
|
|||
v 7.9.0 (unreleased)
|
||||
- Fix broken access control for note attachments (Hannes Rosenögger)
|
||||
- Move labels/milestones tabs to sidebar
|
||||
- Improve UI for commits, issues and merge request lists
|
||||
- Fix commit comments on first line of diff not rendering in Merge Request Discussion view.
|
||||
|
||||
v 7.8.0 (unreleased)
|
||||
- Fix access control and protection against XSS for note attachments and other uploads.
|
||||
- Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
|
||||
- Make project search case insensitive (Hannes Rosenögger)
|
||||
- Include issue/mr participants in list of recipients for reassign/close/reopen emails
|
||||
|
@ -64,6 +67,8 @@ v 7.8.0 (unreleased)
|
|||
- Remove deprecated Group#owner_id from API
|
||||
- Show projects user contributed to on user page. Show stars near project on user page.
|
||||
- Improve database performance for GitLab
|
||||
- Add Asana service (Jeremy Benoist)
|
||||
- Improve project web hooks with extra data
|
||||
|
||||
v 7.7.2
|
||||
- Update GitLab Shell to version 2.4.2 that fixes a bug when developers can push to protected branch
|
||||
|
|
|
@ -16,11 +16,8 @@ class @calendar
|
|||
subDomain: "day"
|
||||
range: 12
|
||||
tooltip: true
|
||||
domainDynamicDimension: false
|
||||
colLimit: 4
|
||||
label:
|
||||
position: "top"
|
||||
domainMargin: 1
|
||||
legend: [
|
||||
0
|
||||
1
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
.commit-title{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.commit-title{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.commit-author, .commit-committer{
|
||||
display: block;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.commit-author strong, .commit-committer strong{
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.commit-description {
|
||||
background: none;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.commit-stat-summary {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.commit-info-row {
|
||||
margin-bottom: 10px;
|
||||
.avatar {
|
||||
@extend .avatar-inline;
|
||||
}
|
||||
.commit-committer-link,
|
||||
.commit-author-link {
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-committer-link,
|
||||
.commit-author-link {
|
||||
font-size: 13px;
|
||||
color: #555;
|
||||
&:hover {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-box {
|
||||
margin: 10px 0;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 20px 0;
|
||||
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.commit-description {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.file-stats a {
|
||||
color: $style_color;
|
||||
}
|
||||
|
||||
.file-stats {
|
||||
.new-file {
|
||||
a {
|
||||
color: #090;
|
||||
}
|
||||
i {
|
||||
color: #1BCF00;
|
||||
}
|
||||
}
|
||||
.renamed-file {
|
||||
i {
|
||||
color: #FE9300;
|
||||
}
|
||||
}
|
||||
.deleted-file {
|
||||
a {
|
||||
color: #B00;
|
||||
}
|
||||
i {
|
||||
color: #EE0000;
|
||||
}
|
||||
}
|
||||
.edit-file{
|
||||
i{
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit message textarea for web editor and
|
||||
* custom merge request message
|
||||
*/
|
||||
.commit-message-container {
|
||||
background-color: $body-bg;
|
||||
position: relative;
|
||||
font-family: $monospace_font;
|
||||
$left: 12px;
|
||||
.max-width-marker {
|
||||
width: 72ch;
|
||||
color: rgba(0, 0, 0, 0.0);
|
||||
font-family: inherit;
|
||||
left: $left;
|
||||
height: 100%;
|
||||
border-right: 1px solid mix($input-border, white);
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
> textarea {
|
||||
background-color: rgba(0, 0, 0, 0.0);
|
||||
font-family: inherit;
|
||||
padding-left: $left;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
|
@ -1,77 +1,3 @@
|
|||
/**
|
||||
* Commit file
|
||||
*/
|
||||
.commit-committer-link,
|
||||
.commit-author-link {
|
||||
font-size: 13px;
|
||||
color: #555;
|
||||
&:hover {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
/** COMMIT BLOCK **/
|
||||
.commit-title{
|
||||
display: block;
|
||||
}
|
||||
.commit-title{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.commit-author, .commit-committer{
|
||||
display: block;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
.commit-author strong, .commit-committer strong{
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
.file-stats a {
|
||||
color: $style_color;
|
||||
}
|
||||
|
||||
.file-stats {
|
||||
.new-file {
|
||||
a {
|
||||
color: #090;
|
||||
}
|
||||
i {
|
||||
color: #1BCF00;
|
||||
}
|
||||
}
|
||||
.renamed-file {
|
||||
i {
|
||||
color: #FE9300;
|
||||
}
|
||||
}
|
||||
.deleted-file {
|
||||
a {
|
||||
color: #B00;
|
||||
}
|
||||
i {
|
||||
color: #EE0000;
|
||||
}
|
||||
}
|
||||
.edit-file{
|
||||
i{
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label_commit {
|
||||
@include border-radius(4px);
|
||||
padding: 2px 4px;
|
||||
font-size: 13px;
|
||||
background: #474D57;
|
||||
color: #fff;
|
||||
font-family: $monospace_font;
|
||||
}
|
||||
|
||||
|
||||
.commits-compare-switch{
|
||||
background: image-url("switch_icon.png") no-repeat center center;
|
||||
width: 32px;
|
||||
|
@ -85,60 +11,40 @@
|
|||
background-color: #EEE;
|
||||
}
|
||||
|
||||
.commit-description {
|
||||
background: none;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.commit-box {
|
||||
margin: 10px 0;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 20px 0;
|
||||
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.commit-description {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.commit-stat-summary {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.commit-info-row {
|
||||
margin-bottom: 10px;
|
||||
.avatar {
|
||||
@extend .avatar-inline;
|
||||
}
|
||||
.commit-committer-link,
|
||||
.commit-author-link {
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.lists-separator {
|
||||
margin: 10px 0;
|
||||
border-top: 1px dashed #CCC;
|
||||
border-color: #DDD;
|
||||
}
|
||||
|
||||
.commits-row {
|
||||
ul {
|
||||
margin: 0;
|
||||
|
||||
li.commit {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.commits-row-date {
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.commits-feed-holder {
|
||||
float: right;
|
||||
|
||||
.btn {
|
||||
padding: 4px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* COMMIT ROW
|
||||
*/
|
||||
li.commit {
|
||||
.commit-row-title {
|
||||
font-size: $list-font-size;
|
||||
line-height: 20px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
.notes_count {
|
||||
|
@ -156,9 +62,9 @@ li.commit {
|
|||
}
|
||||
|
||||
.commit-row-message {
|
||||
color: #333;
|
||||
color: #444;
|
||||
|
||||
&:hover {
|
||||
color: #444;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
@ -193,13 +99,14 @@ li.commit {
|
|||
|
||||
.commit-row-info {
|
||||
color: #777;
|
||||
line-height: 24px;
|
||||
|
||||
a {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.committed_ago {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,34 +121,3 @@ li.commit {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.commits-feed-holder {
|
||||
float: right;
|
||||
.btn {
|
||||
padding: 4px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-message-container {
|
||||
background-color: $body-bg;
|
||||
position: relative;
|
||||
font-family: $monospace_font;
|
||||
$left: 12px;
|
||||
.max-width-marker {
|
||||
width: 72ch;
|
||||
color: rgba(0, 0, 0, 0.0);
|
||||
font-family: inherit;
|
||||
left: $left;
|
||||
height: 100%;
|
||||
border-right: 1px solid mix($input-border, white);
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
> textarea {
|
||||
background-color: rgba(0, 0, 0, 0.0);
|
||||
font-family: inherit;
|
||||
padding-left: $left;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,3 +23,19 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.issuable-context-title {
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.avatar {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
color: #666;
|
||||
font-weight: normal;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
.issue-title {
|
||||
margin-bottom: 5px;
|
||||
font-size: $list-font-size;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.issue-info {
|
||||
|
@ -170,9 +171,9 @@ form.edit-issue {
|
|||
}
|
||||
}
|
||||
|
||||
h3.issue-title {
|
||||
h2.issue-title {
|
||||
margin-top: 0;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.context .select2-container {
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
.merge-request-title {
|
||||
margin-bottom: 5px;
|
||||
font-size: $list-font-size;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.merge-request-info {
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
.sidebar-wrapper {
|
||||
z-index: 99;
|
||||
overflow-y: auto;
|
||||
background: #F5F5F5;
|
||||
}
|
||||
|
||||
|
@ -41,7 +40,7 @@
|
|||
.nav-sidebar li {
|
||||
&.active a {
|
||||
color: #333;
|
||||
background: #FFF;
|
||||
background: #FFF !important;
|
||||
font-weight: bold;
|
||||
border: 1px solid #EEE;
|
||||
border-right: 1px solid transparent;
|
||||
|
@ -78,7 +77,7 @@
|
|||
&:hover {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
background: #DDD;
|
||||
background: #EEE;
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
|
@ -126,7 +125,6 @@
|
|||
|
||||
.sidebar-wrapper {
|
||||
width: 52px;
|
||||
overflow-x: hidden;
|
||||
|
||||
.nav-sidebar {
|
||||
margin-top: 20px;
|
||||
|
@ -140,6 +138,7 @@
|
|||
padding: 8px 15px;
|
||||
text-align: center;
|
||||
|
||||
|
||||
& > span {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@
|
|||
color: #999;
|
||||
background: #FFF;
|
||||
padding: 5px;
|
||||
margin-top: -7px;
|
||||
margin-top: -11px;
|
||||
border: 1px solid #DDD;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
class Import::GitoriousController < Import::BaseController
|
||||
|
||||
def new
|
||||
redirect_to client.authorize_url(callback_import_gitorious_url)
|
||||
end
|
||||
|
||||
def callback
|
||||
session[:gitorious_repos] = params[:repos]
|
||||
redirect_to status_import_gitorious_url
|
||||
end
|
||||
|
||||
def status
|
||||
@repos = client.repos
|
||||
|
||||
@already_added_projects = current_user.created_projects.where(import_type: "gitorious")
|
||||
already_added_projects_names = @already_added_projects.pluck(:import_source)
|
||||
|
||||
@repos.to_a.reject! { |repo| already_added_projects_names.include? repo.full_name }
|
||||
end
|
||||
|
||||
def jobs
|
||||
jobs = current_user.created_projects.where(import_type: "gitorious").to_json(only: [:id, :import_status])
|
||||
render json: jobs
|
||||
end
|
||||
|
||||
def create
|
||||
@repo_id = params[:repo_id]
|
||||
repo = client.repo(@repo_id)
|
||||
@target_namespace = params[:new_namespace].presence || repo.namespace
|
||||
@project_name = repo.name
|
||||
|
||||
namespace = get_or_create_namespace || (render and return)
|
||||
|
||||
@project = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, current_user).execute
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client
|
||||
@client ||= Gitlab::GitoriousImport::Client.new(session[:gitorious_repos])
|
||||
end
|
||||
|
||||
end
|
|
@ -2,9 +2,9 @@
|
|||
class Projects::BlameController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
def show
|
||||
@blob = @repository.blob_at(@commit.id, @path)
|
||||
|
|
|
@ -5,8 +5,8 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
# Raised when given an invalid file path
|
||||
class InvalidPathError < StandardError; end
|
||||
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project, except: [:new, :create]
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :authorize_push_code!, only: [:destroy]
|
||||
before_filter :assign_blob_vars
|
||||
before_filter :commit, except: [:new, :create]
|
||||
|
|
|
@ -2,7 +2,6 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
include ActionView::Helpers::SanitizeHelper
|
||||
# Authorize
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :authorize_push_code!, only: [:create, :destroy]
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
# Not to be confused with CommitsController, plural.
|
||||
class Projects::CommitController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :commit
|
||||
|
||||
def show
|
||||
|
|
|
@ -3,9 +3,9 @@ require "base64"
|
|||
class Projects::CommitsController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
def show
|
||||
@repo = @project.repository
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Projects::CompareController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :authorize_download_code!
|
||||
|
||||
def index
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Projects::ForksController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :authorize_download_code!
|
||||
|
||||
def new
|
||||
@namespaces = current_user.manageable_namespaces
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Projects::GraphsController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :authorize_download_code!
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
|
|
|
@ -2,9 +2,9 @@ class Projects::NetworkController < Projects::ApplicationController
|
|||
include ExtractsPath
|
||||
include ApplicationHelper
|
||||
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
class Projects::RawController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
def show
|
||||
@blob = @repository.blob_at(@commit.id, @path)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
class Projects::RefsController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
def switch
|
||||
respond_to do |format|
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Projects::RepositoriesController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project, except: :create
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :authorize_admin_project!, only: :create
|
||||
|
||||
def create
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
class Projects::TreeController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :require_non_empty_project, except: [:new, :create]
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project, except: [:new, :create]
|
||||
|
||||
def show
|
||||
if tree.entries.empty?
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
class Projects::UploadsController < Projects::ApplicationController
|
||||
layout "project"
|
||||
|
||||
before_filter :project
|
||||
|
||||
def show
|
||||
path = File.join(project.path_with_namespace, params[:secret])
|
||||
uploader = FileUploader.new('uploads', path)
|
||||
|
||||
uploader.retrieve_from_store!(params[:filename])
|
||||
|
||||
if uploader.file.exists?
|
||||
# Right now, these are always images, so we can safely render them inline.
|
||||
send_file uploader.file.path, disposition: 'inline'
|
||||
else
|
||||
not_found!
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class UploadsController < ApplicationController
|
||||
def show
|
||||
model = params[:model].camelize.constantize.find(params[:id])
|
||||
uploader = model.send(params[:mounted_as])
|
||||
|
||||
if uploader.file_storage?
|
||||
if !model.respond_to?(:project) || can?(current_user, :read_project, model.project)
|
||||
disposition = uploader.image? ? 'inline' : 'attachment'
|
||||
send_file uploader.file.path, disposition: disposition
|
||||
else
|
||||
not_found!
|
||||
end
|
||||
else
|
||||
redirect_to uploader.url
|
||||
end
|
||||
end
|
||||
end
|
|
@ -409,19 +409,19 @@ class Note < ActiveRecord::Base
|
|||
prev_lines = []
|
||||
|
||||
diff_lines.each do |line|
|
||||
if generate_line_code(line) != self.line_code
|
||||
if line.type == "match"
|
||||
prev_lines.clear
|
||||
prev_match_line = line
|
||||
else
|
||||
prev_lines.push(line)
|
||||
prev_lines.shift if prev_lines.length >= max_number_of_lines
|
||||
end
|
||||
if line.type == "match"
|
||||
prev_lines.clear
|
||||
prev_match_line = line
|
||||
else
|
||||
prev_lines << line
|
||||
return prev_lines
|
||||
|
||||
break if generate_line_code(line) == self.line_code
|
||||
|
||||
prev_lines.shift if prev_lines.length >= max_number_of_lines
|
||||
end
|
||||
end
|
||||
|
||||
prev_lines
|
||||
end
|
||||
|
||||
def diff_lines
|
||||
|
|
|
@ -16,9 +16,6 @@ module MergeRequests
|
|||
return build_failed(merge_request, nil)
|
||||
end
|
||||
|
||||
# Generate suggested MR title based on source branch name
|
||||
merge_request.title = merge_request.source_branch.titleize.humanize
|
||||
|
||||
compare_result = CompareService.new.execute(
|
||||
current_user,
|
||||
merge_request.source_project,
|
||||
|
@ -52,6 +49,15 @@ module MergeRequests
|
|||
merge_request.compare_failed = false
|
||||
end
|
||||
|
||||
commits = merge_request.compare_commits
|
||||
if commits && commits.count == 1
|
||||
commit = commits.first
|
||||
merge_request.title = commit.title
|
||||
merge_request.description = commit.description.try(:strip)
|
||||
else
|
||||
merge_request.title = merge_request.source_branch.titleize.humanize
|
||||
end
|
||||
|
||||
merge_request
|
||||
|
||||
rescue Gitlab::Satellite::BranchesWithoutParent
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
%h3.page-title
|
||||
%i.fa.fa-gitorious
|
||||
Import repositories from Gitorious.org
|
||||
|
||||
%p.light
|
||||
Select projects you want to import.
|
||||
%hr
|
||||
%p
|
||||
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
|
||||
|
||||
%table.table.import-jobs
|
||||
%thead
|
||||
%tr
|
||||
%th From Gitorious
|
||||
%th To GitLab
|
||||
%th Status
|
||||
%tbody
|
||||
- @already_added_projects.each do |project|
|
||||
%tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
|
||||
%td= project.import_source
|
||||
%td
|
||||
%strong= link_to project.path_with_namespace, project
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span.cgreen
|
||||
%i.fa.fa-check
|
||||
done
|
||||
- else
|
||||
= project.human_import_status_name
|
||||
|
||||
- @repos.each do |repo|
|
||||
%tr{id: "repo_#{repo.id}"}
|
||||
%td= repo.full_name
|
||||
%td.import-target
|
||||
= repo.full_name
|
||||
%td.import-actions.job-status
|
||||
= button_tag "Import", class: "btn js-add-to-import"
|
||||
|
||||
:coffeescript
|
||||
$ ->
|
||||
new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}")
|
|
@ -1,12 +1,5 @@
|
|||
%head
|
||||
%meta{charset: "utf-8"}
|
||||
|
||||
-# Go repository retrieval support
|
||||
-# Need to be the fist thing in the head
|
||||
-# Since Go is using an XML parser to process HTML5
|
||||
-# https://github.com/gitlabhq/gitlabhq/pull/5958#issuecomment-45397555
|
||||
- if controller_name == 'projects' && action_name == 'show'
|
||||
%meta{name: "go-import", content: "#{@project.web_url_without_protocol} git #{@project.web_url}.git"}
|
||||
%meta{content: "GitLab Community Edition", name: "description"}
|
||||
|
||||
%title
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
%li.commit.js-toggle-container
|
||||
.commit-row-title
|
||||
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
|
||||
|
||||
%span.str-truncated
|
||||
%strong.str-truncated
|
||||
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
|
||||
- if commit.description?
|
||||
%a.text-expander.js-toggle-button ...
|
||||
|
||||
= link_to_browse_code(project, commit)
|
||||
.pull-right
|
||||
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
|
||||
|
||||
.notes_count
|
||||
- if @note_counts
|
||||
|
@ -17,8 +16,9 @@
|
|||
- note_count = notes.count
|
||||
|
||||
- if note_count > 0
|
||||
%span.label.label-gray
|
||||
%i.fa.fa-comment= note_count
|
||||
%span.light
|
||||
%i.fa.fa-comments
|
||||
= note_count
|
||||
|
||||
- if commit.description?
|
||||
.commit-row-description.js-toggle-content
|
||||
|
@ -26,6 +26,8 @@
|
|||
= preserve(gfm(escape_once(commit.description)))
|
||||
|
||||
.commit-row-info
|
||||
= commit_author_link(commit, avatar: true, size: 16)
|
||||
= commit_author_link(commit, avatar: true, size: 24)
|
||||
authored
|
||||
.committed_ago
|
||||
#{time_ago_with_tooltip(commit.committed_date)}
|
||||
= link_to_browse_code(project, commit)
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
- @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits|
|
||||
.row.commits-row
|
||||
.col-md-2
|
||||
%h4
|
||||
.col-md-2.hidden-xs.hidden-sm
|
||||
%h5.commits-row-date
|
||||
%i.fa.fa-calendar
|
||||
%span= day.stamp("28 Aug, 2010")
|
||||
%p= pluralize(commits.count, 'commit')
|
||||
.col-md-10
|
||||
.light
|
||||
= pluralize(commits.count, 'commit')
|
||||
.col-md-10.col-sm-12
|
||||
%ul.bordered-list
|
||||
= render commits, project: project
|
||||
%hr.lists-separator
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
.row
|
||||
.col-md-9
|
||||
.participants
|
||||
%cite.cgray
|
||||
= pluralize(@issue.participants.count, 'participant')
|
||||
%span= pluralize(@issue.participants.count, 'participant')
|
||||
- @issue.participants.each do |participant|
|
||||
= link_to_member(@project, participant, name: false, size: 24)
|
||||
|
||||
|
@ -20,8 +19,7 @@
|
|||
= cross_project_reference(@project, @issue)
|
||||
%hr
|
||||
.context
|
||||
%cite.cgray
|
||||
= render partial: 'issue_context', locals: { issue: @issue }
|
||||
= render partial: 'issue_context', locals: { issue: @issue }
|
||||
%hr
|
||||
.clearfix
|
||||
.votes-holder
|
||||
|
|
|
@ -6,9 +6,15 @@
|
|||
.issue-title
|
||||
%span.str-truncated
|
||||
= link_to_gfm issue.title, namespace_project_issue_path(issue.project.namespace, issue.project, issue), class: "row_title"
|
||||
- if issue.closed?
|
||||
%small.pull-right
|
||||
CLOSED
|
||||
.pull-right.light
|
||||
- if issue.closed?
|
||||
%span
|
||||
CLOSED
|
||||
- if issue.notes.any?
|
||||
|
||||
%span
|
||||
%i.fa.fa-comments
|
||||
= issue.notes.count
|
||||
|
||||
.issue-info
|
||||
%span.light= "##{issue.iid}"
|
||||
|
@ -16,10 +22,6 @@
|
|||
assigned to #{link_to_member(@project, issue.assignee)}
|
||||
- if issue.votes_count > 0
|
||||
= render 'votes/votes_inline', votable: issue
|
||||
- if issue.notes.any?
|
||||
%span
|
||||
%i.fa.fa-comments
|
||||
= issue.notes.count
|
||||
- if issue.milestone
|
||||
%span
|
||||
%i.fa.fa-clock-o
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
|
||||
%div.prepend-top-20
|
||||
%p
|
||||
Assignee:
|
||||
.issuable-context-title
|
||||
%label
|
||||
Assignee:
|
||||
- if issue.assignee
|
||||
= link_to_member(@project, @issue.assignee)
|
||||
%strong= link_to_member(@project, @issue.assignee, size: 24)
|
||||
- else
|
||||
none
|
||||
- if can?(current_user, :modify_issue, @issue)
|
||||
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id)
|
||||
|
||||
%div.prepend-top-20
|
||||
%p
|
||||
Milestone:
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Milestone:
|
||||
- if issue.milestone
|
||||
#{link_to @issue.milestone.title, namespace_project_milestone_path(@project.namespace, @project, @issue.milestone)}
|
||||
%span.back-to-milestone
|
||||
= link_to namespace_project_milestone_path(@project.namespace, @project, @issue.milestone) do
|
||||
%strong
|
||||
%i.fa.fa-clock-o
|
||||
= @issue.milestone.title
|
||||
- else
|
||||
none
|
||||
- if can?(current_user, :modify_issue, @issue)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
Edit
|
||||
|
||||
%hr
|
||||
%h3.issue-title
|
||||
%h2.issue-title
|
||||
= gfm escape_once(@issue.title)
|
||||
%div
|
||||
- if @issue.description.present?
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
= cross_project_reference(@project, @merge_request)
|
||||
%hr
|
||||
.context
|
||||
%cite.cgray
|
||||
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
|
||||
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
|
||||
%hr
|
||||
.votes-holder
|
||||
%h6 Votes
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
%li{ class: mr_css_classes(merge_request) }
|
||||
.merge-request-title
|
||||
= link_to_gfm truncate(merge_request.title, length: 80), namespace_project_merge_request_path(merge_request.target_project.namespace, merge_request.target_project, merge_request), class: "row_title"
|
||||
- if merge_request.merged?
|
||||
%small.pull-right
|
||||
%i.fa.fa-check
|
||||
MERGED
|
||||
- else
|
||||
%span.pull-right.hidden-xs
|
||||
- if merge_request.for_fork?
|
||||
%span.light
|
||||
#{merge_request.source_project_namespace}:
|
||||
= truncate merge_request.source_branch, length: 25
|
||||
%i.fa.fa-angle-right.light
|
||||
= merge_request.target_branch
|
||||
%span.str-truncated
|
||||
= link_to_gfm merge_request.title, namespace_project_merge_request_path(merge_request.target_project.namespace, merge_request.target_project, merge_request), class: "row_title"
|
||||
.pull-right.light
|
||||
- if merge_request.merged?
|
||||
%span
|
||||
%i.fa.fa-check
|
||||
MERGED
|
||||
- elsif merge_request.closed?
|
||||
%span
|
||||
%i.fa.fa-close
|
||||
CLOSED
|
||||
- else
|
||||
%span.hidden-xs.hidden-sm
|
||||
%span.label-branch<
|
||||
%i.fa.fa-code-fork
|
||||
%span= merge_request.target_branch
|
||||
- if merge_request.notes.any?
|
||||
|
||||
%span
|
||||
%i.fa.fa-comments
|
||||
= merge_request.mr_and_commit_notes.count
|
||||
.merge-request-info
|
||||
%span.light= "##{merge_request.iid}"
|
||||
- if merge_request.assignee
|
||||
|
@ -21,10 +29,6 @@
|
|||
Unassigned
|
||||
- if merge_request.votes_count > 0
|
||||
= render 'votes/votes_inline', votable: merge_request
|
||||
- if merge_request.notes.any?
|
||||
%span
|
||||
%i.fa.fa-comments
|
||||
= merge_request.mr_and_commit_notes.count
|
||||
- if merge_request.milestone_id?
|
||||
%span
|
||||
%i.fa.fa-clock-o
|
||||
|
@ -33,6 +37,7 @@
|
|||
%span.task-status
|
||||
= merge_request.task_status
|
||||
|
||||
|
||||
.pull-right.hidden-xs
|
||||
%small updated #{time_ago_with_tooltip(merge_request.updated_at, 'bottom', 'merge_request_updated_ago')}
|
||||
|
||||
|
|
|
@ -1,23 +1,30 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f|
|
||||
%div.prepend-top-20
|
||||
%p
|
||||
Assignee:
|
||||
.issuable-context-title
|
||||
%label
|
||||
Assignee:
|
||||
- if @merge_request.assignee
|
||||
= link_to_member(@project, @merge_request.assignee)
|
||||
%strong= link_to_member(@project, @merge_request.assignee, size: 24)
|
||||
- else
|
||||
none
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id)
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id)
|
||||
|
||||
%div.prepend-top-20
|
||||
%p
|
||||
Milestone:
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Milestone:
|
||||
- if @merge_request.milestone
|
||||
%span.back-to-milestone
|
||||
#{link_to @merge_request.milestone.title, namespace_project_milestone_path(@project.namespace, @project, @merge_request.milestone)}
|
||||
= link_to namespace_project_milestone_path(@project.namespace, @project, @merge_request.milestone) do
|
||||
%strong
|
||||
%i.fa.fa-clock-o
|
||||
= @merge_request.milestone.title
|
||||
- else
|
||||
none
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :merge_request_context
|
||||
= f.submit class: 'btn'
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :merge_request_context
|
||||
= f.submit class: 'btn'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
%h3.issue-title
|
||||
%h2.issue-title
|
||||
= gfm escape_once(@merge_request.title)
|
||||
|
||||
%div
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.participants
|
||||
%cite.cgray #{@merge_request.participants.count} participants
|
||||
%span #{@merge_request.participants.count} participants
|
||||
- @merge_request.participants.each do |participant|
|
||||
= link_to_member(@project, participant, name: false, size: 24)
|
||||
|
|
|
@ -53,18 +53,26 @@
|
|||
Import projects from GitHub
|
||||
= render 'github_import_modal'
|
||||
|
||||
- unless request.host == 'gitlab.com'
|
||||
.project-import.form-group
|
||||
.col-sm-2
|
||||
.col-sm-10
|
||||
- if gitlab_import_enabled?
|
||||
= link_to status_import_gitlab_path do
|
||||
%i.fa.fa-heart
|
||||
Import projects from GitLab.com
|
||||
- else
|
||||
= link_to '#', class: 'how_to_import_link light' do
|
||||
%i.fa.fa-heart
|
||||
Import projects from GitLab.com
|
||||
= render 'gitlab_import_modal'
|
||||
|
||||
.project-import.form-group
|
||||
.col-sm-2
|
||||
.col-sm-10
|
||||
- if gitlab_import_enabled?
|
||||
= link_to status_import_gitlab_path do
|
||||
%i.fa.fa-heart
|
||||
Import projects from GitLab.com
|
||||
- elsif request.host != 'gitlab.com'
|
||||
= link_to '#', class: 'how_to_import_link light' do
|
||||
%i.fa.fa-heart
|
||||
Import projects from GitLab.com
|
||||
= render 'gitlab_import_modal'
|
||||
= link_to new_import_gitorious_path do
|
||||
%i.fa.fa-heart
|
||||
Import projects from Gitorious.org
|
||||
|
||||
%hr.prepend-botton-10
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
app = Rails.application
|
||||
|
||||
if app.config.serve_static_assets
|
||||
# The `ActionDispatch::Static` middleware intercepts requests for static files
|
||||
# by checking if they exist in the `/public` directory.
|
||||
# We're replacing it with our `Gitlab::Middleware::Static` that does the same,
|
||||
# except ignoring `/uploads`, letting those go through to the GitLab Rails app.
|
||||
|
||||
app.config.middleware.swap(
|
||||
ActionDispatch::Static,
|
||||
Gitlab::Middleware::Static,
|
||||
app.paths["public"].first,
|
||||
app.config.static_cache_control
|
||||
)
|
||||
end
|
|
@ -67,9 +67,29 @@ Gitlab::Application.routes.draw do
|
|||
get :callback
|
||||
get :jobs
|
||||
end
|
||||
|
||||
resource :gitorious, only: [:create, :new], controller: :gitorious do
|
||||
get :status
|
||||
get :callback
|
||||
get :jobs
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Uploads
|
||||
#
|
||||
|
||||
scope path: :uploads do
|
||||
# Note attachments and User/Group/Project avatars
|
||||
get ":model/:mounted_as/:id/:filename",
|
||||
to: "uploads#show",
|
||||
constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: /.+/ }
|
||||
|
||||
# Project markdown uploads
|
||||
get ":id/:secret/:filename",
|
||||
to: "projects/uploads#show",
|
||||
constraints: { id: /[a-zA-Z.0-9_\-]+\/[a-zA-Z.0-9_\-]+/, filename: /.+/ }
|
||||
end
|
||||
|
||||
#
|
||||
# Explore area
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
# Projects
|
||||
|
||||
|
||||
### Project visibility level
|
||||
|
||||
Project in GitLab has be either private, internal or public.
|
||||
You can determine it by `visibility_level` field in project.
|
||||
|
||||
Constants for project visibility levels are next:
|
||||
|
||||
* Private. `visibility_level` is `0`.
|
||||
Project access must be granted explicitly for each user.
|
||||
|
||||
* Internal. `visibility_level` is `10`.
|
||||
The project can be cloned by any logged in user.
|
||||
|
||||
* Public. `visibility_level` is `20`.
|
||||
The project can be cloned without any authentication.
|
||||
|
||||
|
||||
## List projects
|
||||
|
||||
Get a list of projects accessible by the authenticated user.
|
||||
|
|
|
@ -164,8 +164,6 @@ git diff 6-0-stable:config/gitlab.yml.example 7-8-stable:config/gitlab.yml.examp
|
|||
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/config/gitlab.yml.example but with your settings.
|
||||
* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/config/unicorn.rb.example but with your settings.
|
||||
* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.4.3/config.yml.example but with your settings.
|
||||
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/lib/support/nginx/gitlab but with your settings.
|
||||
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stablef/lib/support/nginx/gitlab-ssl but with your settings.
|
||||
* Copy rack attack middleware config
|
||||
|
||||
```bash
|
||||
|
@ -178,6 +176,12 @@ sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers
|
|||
sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
|
||||
```
|
||||
|
||||
### Change Nginx settings
|
||||
|
||||
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/lib/support/nginx/gitlab but with your settings.
|
||||
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stablef/lib/support/nginx/gitlab-ssl but with your settings.
|
||||
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
|
||||
|
||||
## 9. Start application
|
||||
|
||||
sudo service gitlab start
|
||||
|
|
|
@ -75,8 +75,9 @@ git diff origin/7-6-stable:config/gitlab.yml.example origin/7-8-stable:config/gi
|
|||
|
||||
#### Change Nginx settings
|
||||
|
||||
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings
|
||||
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your setting
|
||||
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings.
|
||||
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your settings.
|
||||
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
|
||||
|
||||
#### Setup time zone (optional)
|
||||
|
||||
|
|
|
@ -24,16 +24,19 @@ Triggered when you push to the repository except when pushing tags.
|
|||
"project_id": 15,
|
||||
"repository": {
|
||||
"name": "Diaspora",
|
||||
"url": "git@example.com:diaspora.git",
|
||||
"url": "git@example.com:mike/diasporadiaspora.git",
|
||||
"description": "",
|
||||
"homepage": "http://example.com/diaspora"
|
||||
"homepage": "http://example.com/mike/diaspora",
|
||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
||||
"visibility_level":0
|
||||
},
|
||||
"commits": [
|
||||
{
|
||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||
"message": "Update Catalan translation to e38cb41.",
|
||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
||||
"url": "http://example.com/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||
"author": {
|
||||
"name": "Jordi Mallach",
|
||||
"email": "jordi@softcatala.org"
|
||||
|
@ -43,7 +46,7 @@ Triggered when you push to the repository except when pushing tags.
|
|||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"message": "fixed readme",
|
||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
||||
"url": "http://example.com/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"author": {
|
||||
"name": "GitLab dev user",
|
||||
"email": "gitlabdev@dv6700.(none)"
|
||||
|
@ -72,8 +75,13 @@ Triggered when you create (or delete) tags to the repository.
|
|||
"name": "jsmith",
|
||||
"url": "ssh://git@example.com/jsmith/example.git",
|
||||
"description": "",
|
||||
"homepage": "http://example.com/jsmith/example"
|
||||
}
|
||||
"homepage": "http://example.com/jsmith/example",
|
||||
"git_http_url":"http://example.com/jsmith/example.git",
|
||||
"git_ssh_url":"git@example.com:jsmith/example.git",
|
||||
"visibility_level":0
|
||||
},
|
||||
"commits": [],
|
||||
"total_commits_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ module Gitlab
|
|||
line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
|
||||
line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
|
||||
|
||||
next if line_old == 1 && line_new == 1 #top of file
|
||||
next if line_old <= 1 && line_new <= 1 #top of file
|
||||
lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
|
||||
line_obj_index += 1
|
||||
next
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
module Gitlab
|
||||
module GitoriousImport
|
||||
GITORIOUS_HOST = "https://gitorious.org"
|
||||
|
||||
class Client
|
||||
attr_reader :repo_list
|
||||
|
||||
def initialize(repo_list)
|
||||
@repo_list = repo_list
|
||||
end
|
||||
|
||||
def authorize_url(redirect_uri)
|
||||
"#{GITORIOUS_HOST}/gitlab-import?callback_url=#{redirect_uri}"
|
||||
end
|
||||
|
||||
def repos
|
||||
@repos ||= repo_names.map { |full_name| Repository.new(full_name) }
|
||||
end
|
||||
|
||||
def repo(id)
|
||||
repos.find { |repo| repo.id == id }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def repo_names
|
||||
repo_list.to_s.split(',').map(&:strip).reject(&:blank?)
|
||||
end
|
||||
end
|
||||
|
||||
Repository = Struct.new(:full_name) do
|
||||
def id
|
||||
Digest::SHA1.hexdigest(full_name)
|
||||
end
|
||||
|
||||
def namespace
|
||||
segments.first
|
||||
end
|
||||
|
||||
def path
|
||||
segments.last
|
||||
end
|
||||
|
||||
def name
|
||||
path.titleize
|
||||
end
|
||||
|
||||
def description
|
||||
""
|
||||
end
|
||||
|
||||
def import_url
|
||||
"#{GITORIOUS_HOST}/#{full_name}.git"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def segments
|
||||
full_name.split('/')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
module Gitlab
|
||||
module GitoriousImport
|
||||
class ProjectCreator
|
||||
attr_reader :repo, :namespace, :current_user
|
||||
|
||||
def initialize(repo, namespace, current_user)
|
||||
@repo = repo
|
||||
@namespace = namespace
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def execute
|
||||
@project = Project.new(
|
||||
name: repo.name,
|
||||
path: repo.path,
|
||||
description: repo.description,
|
||||
namespace: namespace,
|
||||
creator: current_user,
|
||||
visibility_level: Gitlab::VisibilityLevel::PUBLIC,
|
||||
import_type: "gitorious",
|
||||
import_source: repo.full_name,
|
||||
import_url: repo.import_url
|
||||
)
|
||||
|
||||
if @project.save!
|
||||
@project.reload
|
||||
|
||||
if @project.import_failed?
|
||||
@project.import_retry
|
||||
else
|
||||
@project.import_start
|
||||
end
|
||||
end
|
||||
|
||||
@project
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module Gitlab
|
||||
module Middleware
|
||||
class Static < ActionDispatch::Static
|
||||
UPLOADS_REGEX = /\A\/uploads(\/|\z)/.freeze
|
||||
|
||||
def call(env)
|
||||
return @app.call(env) if env['PATH_INFO'] =~ UPLOADS_REGEX
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -41,6 +41,9 @@ module Gitlab
|
|||
url: project.url_to_repo,
|
||||
description: project.description,
|
||||
homepage: project.web_url,
|
||||
git_http_url: project.http_url_to_repo,
|
||||
git_ssh_url: project.ssh_url_to_repo,
|
||||
visibility_level: project.visibility_level
|
||||
},
|
||||
commits: [],
|
||||
total_commits_count: commits_count
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## GitLab
|
||||
## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller
|
||||
## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller, DouweM
|
||||
##
|
||||
## Lines starting with two hashes (##) are comments with information.
|
||||
## Lines starting with one hash (#) are configuration parameters that can be uncommented.
|
||||
|
@ -56,6 +56,37 @@ server {
|
|||
try_files $uri $uri/index.html $uri.html @gitlab;
|
||||
}
|
||||
|
||||
## We route uploads through GitLab to prevent XSS and enforce access control.
|
||||
location /uploads/ {
|
||||
## If you use HTTPS make sure you disable gzip compression
|
||||
## to be safe against BREACH attack.
|
||||
# gzip off;
|
||||
|
||||
## https://github.com/gitlabhq/gitlabhq/issues/694
|
||||
## Some requests take more than 30 seconds.
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_redirect off;
|
||||
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Frame-Options SAMEORIGIN;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## GitLab
|
||||
## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller
|
||||
## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller, DouweM
|
||||
##
|
||||
## Modified from nginx http version
|
||||
## Modified from http://blog.phusion.nl/2012/04/21/tutorial-setting-up-gitlab-on-debian-6/
|
||||
|
@ -101,6 +101,38 @@ server {
|
|||
try_files $uri $uri/index.html $uri.html @gitlab;
|
||||
}
|
||||
|
||||
## We route uploads through GitLab to prevent XSS and enforce access control.
|
||||
location /uploads/ {
|
||||
## If you use HTTPS make sure you disable gzip compression
|
||||
## to be safe against BREACH attack.
|
||||
gzip off;
|
||||
|
||||
## https://github.com/gitlabhq/gitlabhq/issues/694
|
||||
## Some requests take more than 30 seconds.
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_redirect off;
|
||||
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Ssl on;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Frame-Options SAMEORIGIN;
|
||||
|
||||
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,67 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Import::GitoriousController do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
describe "GET new" do
|
||||
it "redirects to import endpoint on gitorious.org" do
|
||||
get :new
|
||||
|
||||
expect(controller).to redirect_to("https://gitorious.org/gitlab-import?callback_url=http://test.host/import/gitorious/callback")
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET callback" do
|
||||
it "stores repo list in session" do
|
||||
get :callback, repos: 'foo/bar,baz/qux'
|
||||
|
||||
expect(session[:gitorious_repos]).to eq('foo/bar,baz/qux')
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET status" do
|
||||
before do
|
||||
@repo = OpenStruct.new(full_name: 'asd/vim')
|
||||
end
|
||||
|
||||
it "assigns variables" do
|
||||
@project = create(:project, import_type: 'gitorious', creator_id: user.id)
|
||||
controller.stub_chain(:client, :repos).and_return([@repo])
|
||||
|
||||
get :status
|
||||
|
||||
expect(assigns(:already_added_projects)).to eq([@project])
|
||||
expect(assigns(:repos)).to eq([@repo])
|
||||
end
|
||||
|
||||
it "does not show already added project" do
|
||||
@project = create(:project, import_type: 'gitorious', creator_id: user.id, import_source: 'asd/vim')
|
||||
controller.stub_chain(:client, :repos).and_return([@repo])
|
||||
|
||||
get :status
|
||||
|
||||
expect(assigns(:already_added_projects)).to eq([@project])
|
||||
expect(assigns(:repos)).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST create" do
|
||||
before do
|
||||
@repo = Gitlab::GitoriousImport::Repository.new('asd/vim')
|
||||
end
|
||||
|
||||
it "takes already existing namespace" do
|
||||
namespace = create(:namespace, name: "asd", owner: user)
|
||||
expect(Gitlab::GitoriousImport::ProjectCreator).
|
||||
to receive(:new).with(@repo, namespace, user).
|
||||
and_return(double(execute: true))
|
||||
controller.stub_chain(:client, :repo).and_return(@repo)
|
||||
|
||||
post :create, format: :js
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitoriousImport::ProjectCreator do
|
||||
let(:user) { create(:user) }
|
||||
let(:repo) { Gitlab::GitoriousImport::Repository.new('foo/bar-baz-qux') }
|
||||
let(:namespace){ create(:namespace) }
|
||||
|
||||
it 'creates project' do
|
||||
allow_any_instance_of(Project).to receive(:add_import_job)
|
||||
|
||||
project_creator = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, user)
|
||||
project_creator.execute
|
||||
project = Project.last
|
||||
|
||||
expect(project.name).to eq("Bar Baz Qux")
|
||||
expect(project.path).to eq("bar-baz-qux")
|
||||
expect(project.namespace).to eq(namespace)
|
||||
expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
|
||||
expect(project.import_type).to eq("gitorious")
|
||||
expect(project.import_source).to eq("foo/bar-baz-qux")
|
||||
expect(project.import_url).to eq("https://gitorious.org/foo/bar-baz-qux.git")
|
||||
end
|
||||
end
|
|
@ -13,6 +13,9 @@ describe 'Gitlab::PushDataBuilder' do
|
|||
it { expect(data[:after]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
|
||||
it { expect(data[:ref]).to eq('refs/heads/master') }
|
||||
it { expect(data[:commits].size).to eq(3) }
|
||||
it { expect(data[:repository][:git_http_url]).to eq(project.http_url_to_repo) }
|
||||
it { expect(data[:repository][:git_ssh_url]).to eq(project.ssh_url_to_repo) }
|
||||
it { expect(data[:repository][:visibility_level]).to eq(project.visibility_level) }
|
||||
it { expect(data[:total_commits_count]).to eq(3) }
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue