Commit 0fd7d3eb authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into ce-to-ee

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parents c3a24cb8 151d9fb3
Please view this file on the master branch, on stable branches it's out of date.
v 7.14.0 (unreleased)
- Show incompatible projects in Bitbucket import status (Stan Hu)
- Fix coloring of diffs on MR Discussion-tab (Gert Goet)
- Fix "Network" and "Graphs" pages for branches with encoded slashes (Stan Hu)
- Fix errors deleting and creating branches with encoded slashes (Stan Hu)
- Always add current user to autocomplete controller to support filter by "Me" (Stan Hu)
- Fix multi-line syntax highlighting (Stan Hu)
- Fix network graph when branch name has single quotes (Stan Hu)
- Add "Confirm user" button in user admin page (Stan Hu)
- Upgrade gitlab_git to version 7.2.6 to fix Error 500 when creating network graphs (Stan Hu)
- Add support for Unicode filenames in relative links (Hiroyuki Sato)
- Fix URL used for refreshing notes if relative_url is present (Bartłomiej Święcki)
......@@ -17,8 +23,11 @@ v 7.14.0 (unreleased)
- Fix OAuth provider bug where GitLab would not go return to the redirect_uri after sign-in (Stan Hu)
- Fix file upload dialog for comment editing (Daniel Gerhardt)
- Set OmniAuth full_host parameter to ensure redirect URIs are correct (Stan Hu)
- Return comments in created order in merge request API (Stan Hu)
- Expire Rails cache entries after two weeks to prevent endless Redis growth
- Add support for destroying project milestones (Stan Hu)
- Add fetch command to the MR page.
- Allow custom backup archive permissions
- Add fetch command to the MR page
- Add project star and fork count, group avatar URL and user/group web URL attributes to API
- Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
......@@ -26,8 +35,26 @@ v 7.14.0 (unreleased)
- Fix bug causing "Remove source-branch" option not to work for merge requests from the same project.
- Fix approvals for forks. Now you can change approvals settings on the new merge request form
- Suggested approvers are shown on the new merge request form
- Show who last edited a comment if it wasn't the original author
- Send notification to all participants when MR is merged.
- Add ability to manage user email addresses via the API.
- Show buttons to add license, changelog and contribution guide if they're missing.
- Tweak project page buttons.
- Disabled autocapitalize and autocorrect on login field (Daryl Chan)
- Mention group and project name in creation, update and deletion notices (Achilleas Pipinellis)
- Update gravatar link on profile page to link to configured gravatar host (Ben Bodenmiller)
- Remove redis-store TTL monkey patch
- Add support for CI skipped status
- Fetch code from forks to refs/merge-requests/:id/head when merge request created
- Remove satellites
- Remove comments and email addresses when publicly exposing ssh keys (Zeger-Jan van de Weg)
- Improve MR merge widget text and UI consistency.
- Improve text in MR "How To Merge" modal.
- Cache all events
v 7.13.3
- Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
- Allow users to send abuse reports
v 7.13.2
- Fix randomly failed spec
......@@ -52,7 +79,6 @@ v 7.13.1
v 7.13.0
- Remove repository graph log to fix slow cache updates after push event (Stan Hu)
- Return comments in created order in merge request API (Stan Hu)
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
- Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu)
- Fix redirection to home page URL for unauthorized users (Daniel Gerhardt)
......@@ -79,15 +105,15 @@ v 7.13.0
- Update ssl_ciphers in Nginx example to remove DHE settings. This will deny forward secrecy for Android 2.3.7, Java 6 and OpenSSL 0.9.8
- Admin can edit and remove user identities
- Convert CRLF newlines to LF when committing using the web editor.
- API request /projects/:project_id/merge_requests?state=closed will return only closed merge requests without merged one. If you need ones that were merged - use state=merged.
- API request /projects/:project_id/merge_requests?state=closed will return only closed merge requests without merged one. If you need ones that were merged - use state=merged.
- Allow Administrators to filter the user list by those with or without Two-factor Authentication enabled.
- Show a user's Two-factor Authentication status in the administration area.
- Explicit error when commit not found in the CI
- Improve performance for issue and merge request pages
- Improve performance for issue and merge request pages
- Users with guest access level can not set assignee, labels or milestones for issue and merge request
- Reporter role can manage issue tracker now: edit any issue, set assignee or milestone and manage labels
- Better performance for pages with events list, issues list and commits list
- Faster automerge check and merge itself when source and target branches are in same repository
- Faster automerge check and merge itself when source and target branches are in same repository
- Correctly show anonymous authorized applications under Profile > Applications.
- Query Optimization in MySQL.
- Allow users to be blocked and unblocked via the API
......@@ -95,17 +121,17 @@ v 7.13.0
- Redesign project page. Show README as default instead of activity. Move project activity to separate page
- Make left menu more hierarchical and less contextual by adding back item at top
- A fork can’t have a visibility level that is greater than the original project.
- Faster code search in repository and wiki. Fixes search page timeout for big repositories
- Faster code search in repository and wiki. Fixes search page timeout for big repositories
- Allow administrators to disable 2FA for a specific user
- Add error message for SSH key linebreaks
- Store commits count in database (will populate with valid values only after first push)
- Rebuild cache after push to repository in background job
- Fix transferring of project to another group using the API.
v 7.12.2
- Correctly show anonymous authorized applications under Profile > Applications.
- Faster automerge check and merge itself when source and target branches are in same repository
- Audit log for user authentication
- Fix transferring of project to another group using the API.
- Allow custom label to be set for authentication providers.
v 7.12.1
......@@ -114,7 +140,7 @@ v 7.12.1
- Add SAML to list of social_provider (Matt Firtion)
- Fix merge requests API scope to keep compatibility in 7.12.x patch release (Dmitriy Zaporozhets)
- Fix closed merge request scope at milestone page (Dmitriy Zaporozhets)
- Revert merge request states renaming
- Revert merge request states renaming
- Fix hooks for web based events with external issue references (Daniel Gerhardt)
- Improve performance for issue and merge request pages
- Compress database dumps to reduce backup size
......
......@@ -154,7 +154,7 @@ GEM
doorkeeper (2.1.3)
railties (>= 3.2)
dotenv (0.9.0)
dropzonejs-rails (0.4.14)
dropzonejs-rails (0.7.1)
rails (> 3.1)
email_spec (1.6.0)
launchy (~> 2.1)
......@@ -374,7 +374,7 @@ GEM
mini_portile (0.6.2)
minitest (5.3.5)
mousetrap-rails (1.4.6)
multi_json (1.11.1)
multi_json (1.11.2)
multi_xml (0.5.5)
multipart-post (1.2.0)
mysql2 (0.3.16)
......@@ -509,7 +509,7 @@ GEM
rdoc (3.12.2)
json (~> 1.4)
redcarpet (3.3.2)
redis (3.1.0)
redis (3.2.1)
redis-actionpack (4.0.0)
actionpack (~> 4)
redis-rack (~> 1.5.0)
......@@ -526,7 +526,7 @@ GEM
redis-actionpack (~> 4)
redis-activesupport (~> 4)
redis-store (~> 1.1.0)
redis-store (1.1.4)
redis-store (1.1.6)
redis (>= 2.2)
request_store (1.0.5)
rerun (0.10.0)
......@@ -878,4 +878,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.10.5
1.10.4
# GitLab
[![build status](https://ci.gitlab.com/projects/1/status.png?ref=master)](https://ci.gitlab.com/projects/1?ref=master)
[![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq)
[![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
......@@ -95,7 +95,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.0 or 2.1
- Ruby (MRI) 2.1
- Git 1.7.10+
- Redis 2.0+
- MySQL or PostgreSQL
......
......@@ -8,6 +8,7 @@ class @DropzoneInput
divAlert = "<div class=\"" + alertClass + "\"></div>"
iconPaperclip = "<i class=\"fa fa-paperclip div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
uploadProgress = $("<div class=\"div-dropzone-progress\"></div>")
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_uploads_path = window.project_uploads_path or null
markdown_preview_path = window.markdown_preview_path or null
......@@ -28,6 +29,7 @@ class @DropzoneInput
form_dropzone.find(".div-dropzone-hover").append iconPaperclip
form_dropzone.append divSpinner
form_dropzone.find(".div-dropzone-spinner").append iconSpinner
form_dropzone.find(".div-dropzone-spinner").append uploadProgress
form_dropzone.find(".div-dropzone-spinner").css
"opacity": 0
"display": "none"
......@@ -112,13 +114,18 @@ class @DropzoneInput
$(".div-dropzone-alert").append btnAlert + errorMessage
return
totaluploadprogress: (totalUploadProgress) ->
uploadProgress.text Math.round(totalUploadProgress) + "%"
return
sending: ->
form_dropzone.find(".div-dropzone-spinner").css
"opacity": 0.7
"display": "inherit"
return
complete: ->
queuecomplete: ->
uploadProgress.text ""
$(".dz-preview").remove()
$(".markdown-area").trigger "input"
$(".div-dropzone-spinner").css
......
......@@ -19,7 +19,7 @@ class @MergeRequestWidget
when 'merged'
location.reload()
else
setTimeout(merge_request_widget.mergeInProgress, 3000)
setTimeout(merge_request_widget.mergeInProgress, 2000)
dataType: 'json'
getMergeStatus: ->
......@@ -36,7 +36,7 @@ class @MergeRequestWidget
showCiState: (state) ->
$('.ci_widget').hide()
allowed_states = ["failed", "canceled", "running", "pending", "success", "not_found"]
allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"]
if state in allowed_states
$('.ci_widget.ci-' + state).show()
switch state
......@@ -49,10 +49,8 @@ class @MergeRequestWidget
@setMergeButtonClass('btn-danger')
showCiCoverage: (coverage) ->
cov_html = $('<span>')
cov_html.addClass('ci-coverage')
cov_html.text('Coverage ' + coverage + '%')
$('.ci_widget:visible').append(cov_html)
text = 'Coverage ' + coverage + '%'
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
$('.accept_merge_request').removeClass("btn-create").addClass(css_class)
class @Project
constructor: ->
# Git clone panel switcher
scope = $ '.git-clone-holder'
if scope.length > 0
$('a, button', scope).click ->
$('a, button', scope).removeClass 'active'
cloneHolder = $('.git-clone-holder')
if cloneHolder.length
$('a, button', cloneHolder).click ->
$('a, button', cloneHolder).removeClass 'active'
$(@).addClass 'active'
$('#project_clone', scope).val $(@).data 'clone'
$('#project_clone', cloneHolder).val $(@).data 'clone'
$(".clone").text("").append $(@).data 'clone'
# Ref switcher
......@@ -24,3 +24,8 @@ class @Project
$.cookie('hide_no_password_message', 'false', { path: path })
$(@).parents('.no-password-message').remove()
e.preventDefault()
$('.js-toggle-clone-holder').on 'click', (e) ->
cloneHolder.toggle()
cloneHolder.hide() unless $('.empty-project').length
......@@ -70,7 +70,7 @@
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
padding: 0;
padding: 1px 2px;
}
kbd {
......
......@@ -40,6 +40,15 @@
font-size: inherit;
}
.div-dropzone-progress {
position: absolute;
top: 7px;
left: -40px;
width: 35px;
font-size: 13px;
text-align: right;
}
.dz-preview {
display: none;
}
......
......@@ -48,6 +48,10 @@
display: block;
}
.project-home-desc {
font-size: 21px;
}
.project-repo-buttons,
.git-clone-holder {
display: none;
......
......@@ -38,6 +38,10 @@ code {
}
}
a > code {
color: $link-color;
}
/**
* Wiki typography
*
......
/**
* MR -> show: Automerge widget
/**
* MR -> show: Automerge widget
*
*/
.mr-state-widget {
background: #FAFAFA;
margin-bottom: 20px;
color: #666;
border: 1px solid #e5e5e5;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
@include border-radius(3px);
form {
margin-bottom: 0;
.clearfix {
......@@ -20,22 +26,71 @@
display: inline-block;
margin: 0;
margin-left: 20px;
padding: 10px 0;
padding: 5px;
line-height: 20px;
font-weight: bold;
.remove_source_checkbox {
margin: 0;
font-weight: bold;
}
}
}
.ci_widget {
border-bottom: 1px solid #EEE;
i {
margin-right: 4px;
}
&.ci-success {
color: $gl-success;
}
&.ci-skipped {
background-color: #eee;
color: #888;
}
&.ci-pending,
&.ci-running {
color: $gl-warning;
}
&.ci-failed,
&.ci-canceled,
&.ci-error {
color: $gl-danger;
}
}
.mr-widget-body,
.ci_widget,
.mr-widget-footer {
padding: 15px;
}
.mr-widget-body {
h4 {
font-weight: bold;
margin: 5px 0;
}
p:last-child {
margin-bottom: 0;
}
}
.mr-widget-footer {
border-top: 1px solid #EEE;
}
.ci-coverage {
float: right;
}
}
@media(min-width: $screen-sm-max) {
.merge-request .merge-request-tabs{
margin: 20px 0;
li {
a {
padding: 15px 40px;
......@@ -45,6 +100,11 @@
}
}
.merge-request .merge-request-tabs{
margin-top: 30px;
margin-bottom: 20px;
}
.mr_source_commit,
.mr_target_commit {
.commit {
......@@ -58,23 +118,10 @@
}
.label-branch {
@include border-radius(4px);
padding: 3px 4px;
border: none;
background: $hover;
color: #333;
color: #222;
font-family: $monospace_font;
font-weight: normal;
font-weight: bold;
overflow: hidden;
.label-project {
@include border-radius-left(4px);
padding: 3px 4px;
background: #279;
position: relative;
left: -4px;
letter-spacing: -1px;
}
}
.mr-list {
......@@ -121,59 +168,6 @@
display: none;
}
.mr-state-widget {
font-size: 13px;
background: #FAFAFA;
margin-bottom: 20px;
color: #666;
border: 1px solid #e5e5e5;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
@include border-radius(3px);
.ci_widget {
padding: 10px 15px;
font-size: 15px;
border-bottom: 1px solid #EEE;
&.ci-success {
color: $gl-success;
}
&.ci-pending,
&.ci-running {
color: $gl-warning;
}
&.ci-failed,
&.ci-canceled,
&.ci-error {
color: $gl-danger;
}
}
.mr-widget-body {
padding: 10px 15px;
h4 {
font-weight: bold;
margin: 5px 0;
}
p:last-child {
margin-bottom: 0;
}
}
.mr-widget-footer {
padding: 10px 15px;
border-top: 1px solid #EEE;
}
.ci-coverage {
float: right;
}
}
.merge-request-show-labels {
a {
margin-right: 5px;
......@@ -188,3 +182,7 @@
.merge-request-form .select2-container {
width: 250px !important;
}
#modal_merge_info .modal-dialog {
width: 600px;
}
......@@ -16,7 +16,6 @@
.project-home-panel {
text-align: center;
margin-bottom: 20px;
.project-identicon-holder {
margin-bottom: 15px;
......@@ -31,7 +30,13 @@
}
}
.lead {
.project-home-desc {
h1 {
margin: 0;
margin-bottom: 10px;
font-size: 26px;
}
p {
display: inline;
}
......@@ -39,7 +44,7 @@
.git-clone-holder {
max-width: 600px;
margin: 0 auto;
margin: 20px auto;
}
.visibility-level-label {
......@@ -297,6 +302,15 @@ table.table.protected-branches-list tr.no-border {
ul.nav-pills { display:inline-block; }
li { display:inline; }
a { float:left; }
li.missing a {
color: #bbb;
border: 1px dashed #ccc;
&:hover {
background-color: #FAFAFA;
}
}
}
pre.light-well {
......
class AbuseReportsController < ApplicationController
def new
@abuse_report = AbuseReport.new
@abuse_report.user_id = params[:user_id]
end
def create
@abuse_report = AbuseReport.new(report_params)
@abuse_report.reporter = current_user
if @abuse_report.save
message = "Thank you for your report. A GitLab administrator will look into it shortly."
redirect_to root_path, notice: message
else
render :new
end
end
private
def report_params
params.require(:abuse_report).permit(:user_id, :message)
end
end
class Admin::AbuseReportsController < Admin::ApplicationController
def index
@abuse_reports = AbuseReport.order(id: :desc).page(params[:page])
end
def destroy
AbuseReport.find(params[:id]).destroy
redirect_to admin_abuse_reports_path, notice: 'Report was removed'
end
end
......@@ -55,6 +55,14 @@ class Admin::UsersController < Admin::ApplicationController
end
end
def confirm
if user.confirm!
redirect_to :back, notice: "Successfully confirmed"
else
redirect_to :back, alert: "Error occurred. User was not confirmed"
end
end
def disable_two_factor
user.disable_two_factor!
redirect_to admin_user_path(user),
......
......@@ -34,6 +34,8 @@ class AutocompleteController < ApplicationController
@users = @users.search(params[:search]) if params[:search].present?
@users = @users.active
@users = @users.page(params[:page]).per(PER_PAGE)
# Always include current user if available to filter by "Me"
@users = User.find(@users.pluck(:id) + [current_user.id]).uniq if current_user
render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
end
......
......@@ -22,6 +22,7 @@ class Import::BitbucketController < Import::BaseController
def status
@repos = client.projects
@incompatible_repos = client.incompatible_projects
@already_added_projects = current_user.created_projects.where(import_type: "bitbucket")
already_added_projects_names = @already_added_projects.pluck(:import_source)
......
......@@ -17,7 +17,9 @@ class Projects::BranchesController < Projects::ApplicationController
def create
branch_name = sanitize(strip_tags(params[:branch_name]))
branch_name = Addressable::URI.unescape(branch_name)
ref = sanitize(strip_tags(params[:ref]))
ref = Addressable::URI.unescape(ref)
result = CreateBranchService.new(project, current_user).
execute(branch_name, ref)
......@@ -32,9 +34,8 @@ class Projects::BranchesController < Projects::ApplicationController
end
def destroy
status = DeleteBranchService.new(project, current_user).execute(params[:id])
@branch_name = params[:id]
@branch_name = Addressable::URI.unescape(params[:id])
status = DeleteBranchService.new(project, current_user).execute(@branch_name)
respond_to do |format|
format.html do
redirect_to namespace_project_branches_path(@project.namespace,
......
......@@ -13,13 +13,8 @@ class Projects::CompareController < Projects::ApplicationController
base_ref = Addressable::URI.unescape(params[:from])
@ref = head_ref = Addressable::URI.unescape(params[:to])
compare_result = CompareService.new.execute(
current_user,
@project,
head_ref,
@project,
base_ref
)
compare_result = CompareService.new.
execute(@project, head_ref, @project, base_ref)
@commits = compare_result.commits
@diffs = compare_result.diffs
......
require 'gitlab/satellite/satellite'
class Projects::MergeRequestsController < Projects::ApplicationController
before_action :module_enabled
before_action :merge_request, only: [
:edit, :update, :show, :diffs, :commits, :automerge, :automerge_check,
:edit, :update, :show, :diffs, :commits, :merge, :merge_check,
:ci_status, :toggle_subscription, :approve
]
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits]
......@@ -141,7 +139,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
def automerge_check
def merge_check
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
......@@ -151,12 +149,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render partial: "projects/merge_requests/widget/show.html.haml", layout: false
end
def automerge
def merge
return access_denied! unless @merge_request.can_be_merged_by?(current_user)
return render_404 unless @merge_request.approved?
if @merge_request.automergeable?
AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params)
if @merge_request.mergeable?
MergeWorker.perform_async(@merge_request.id, current_user.id, params)
@status = true
else
@status = false
......
......@@ -30,13 +30,10 @@ class Projects::NotesController < Projects::ApplicationController
end
def update
if note.editable?
note.update_attributes(note_params)
note.reset_events_cache
end
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
respond_to do |format|
format.json { render_note_json(note) }
format.json { render_note_json(@note) }
format.html { redirect_to :back }
end
end
......
......@@ -43,21 +43,6 @@ module IssuesHelper
end
end
def issue_timestamp(issue)
# Shows the created at time and the updated at time if different
ts = time_ago_with_tooltip(issue.created_at, placement: 'bottom', html_class: 'note_created_ago')
if issue.updated_at != issue.created_at
ts << capture_haml do
haml_tag :span do
haml_concat '&middot;'
haml_concat icon('edit', title: 'edited')
haml_concat time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
end
end
end
ts.html_safe
end
def bulk_update_milestone_options
options_for_select([['None (backlog)', -1]]) +
options_from_collection_for_select(project_active_milestones, 'id',
......
......@@ -106,4 +106,14 @@ module MergeRequestsHelper
str
end
def source_branch_with_namespace(merge_request)
if merge_request.for_fork?
namespace = link_to(merge_request.source_project_namespace,
project_path(merge_request.source_project))
namespace + ":#{merge_request.source_branch}"
else
merge_request.source_branch
end
end
end
......@@ -23,21 +23,6 @@ module NotesHelper
end
end
def note_timestamp(note)
# Shows the created at time and the updated at time if different
ts = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
if note.updated_at != note.created_at
ts << capture_haml do
haml_tag :span do
haml_concat '&middot;'
haml_concat icon('edit', title: 'edited')
haml_concat time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
end
end
end
ts.html_safe
end
def noteable_json(noteable)
{
id: noteable.id,
......
......@@ -21,7 +21,7 @@ module ProjectsHelper
end
def link_to_member(project, author, opts = {})
default_opts = { avatar: true, name: true, size: 16 }
default_opts = { avatar: true, name: true, size: 16, author_class: 'author' }
opts = default_opts.merge(opts)
return "(deleted)" unless author
......@@ -32,7 +32,7 @@ module ProjectsHelper
author_html << image_tag(avatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
# Build name span tag
author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name]
author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
author_html = author_html.html_safe
......@@ -184,7 +184,43 @@ module ProjectsHelper
end
end
def contribution_guide_url(project)
def add_contribution_guide_path(project)
if project && !project.repository.contribution_guide
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch,
file_name: "CONTRIBUTING.md",
commit_message: "Add contribution guide"
)
end
end
def add_changelog_path(project)
if project && !project.repository.changelog
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch,
file_name: "CHANGELOG",
commit_message: "Add changelog"
)
end
end
def add_license_path(project)
if project && !project.repository.license
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch,
file_name: "LICENSE",
commit_message: "Add license"
)
end
end
def contribution_guide_path(project)
if project && contribution_guide = project.repository.contribution_guide
namespace_project_blob_path(
project.namespace,
......@@ -195,7 +231,7 @@ module ProjectsHelper
end
end
def changelog_url(project)
def changelog_path(project)
if project && changelog = project.repository.changelog
namespace_project_blob_path(
project.namespace,
......@@ -206,7 +242,7 @@ module ProjectsHelper
end
end
def license_url(project)
def license_path(project)
if project && license = project.repository.license
namespace_project_blob_path(
project.namespace,
......@@ -217,7 +253,7 @@ module ProjectsHelper
end
end
def version_url(project)
def version_path(project)
if project && version = project.repository.version
namespace_project_blob_path(
project.namespace,
......
class AbuseReport < ActiveRecord::Base
belongs_to :reporter, class_name: "User"
belongs_to :user
validates :reporter, presence: true
validates :user, presence: true
validates :message, presence: true
validates :user_id, uniqueness: { scope: :reporter_id }
end
......@@ -15,13 +15,14 @@
# twitter_sharing_enabled :boolean default(TRUE)
# help_text :text
# restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null
# session_expire_delay :integer default(10080), not null
# default_project_visibility :integer
# default_snippet_visibility :integer
# restricted_signup_domains :text
# user_oauth_applications :bool default(TRUE)
# user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
#
class ApplicationSetting < ActiveRecord::Base
......
# == Schema Information
#
# Table name: audit_events
#
# id :integer not null, primary key
# author_id :integer not null
# type :string(255) not null
# entity_id :integer not null
# entity_type :string(255) not null
# details :text
# created_at :datetime
# updated_at :datetime
#
class AuditEvent < ActiveRecord::Base
serialize :details, Hash
......
......@@ -12,6 +12,7 @@ module Issuable
included do
belongs_to :author, class_name: "User"
belongs_to :assignee, class_name: "User"
belongs_to :updated_by, class_name: "User"
belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy
has_many :label_links, as: :target, dependent: :destroy
......
......@@ -84,6 +84,22 @@ class Group < Namespace
self.add_user(user, Gitlab::Access::OWNER, current_user, skip_notification: skip_notification)
end
def add_guest(user, current_user = nil)
add_user(user, Gitlab::Access::GUEST, current_user)
end
def add_reporter(user, current_user = nil)
add_user(user, Gitlab::Access::REPORTER, current_user)
end
def add_developer(user, current_user = nil)
add_user(user, Gitlab::Access::DEVELOPER, current_user)
end
def add_master(user, current_user = nil)
add_user(user, Gitlab::Access::MASTER, current_user)
end
def has_owner?(user)
owners.include?(user)
end
......
......@@ -41,6 +41,11 @@ class Key < ActiveRecord::Base
self.key = key.strip unless key.blank?
end
def publishable_key
#Removes anything beyond the keytype and key itself
self.key.split[0..1].join(' ')
end
# projects that has this key
def projects
user.authorized_projects
......
......@@ -43,11 +43,6 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
attr_accessor :should_remove_source_branch
# If true, merge request should rebase before merging
attr_accessor :should_rebase
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
attr_accessor :allow_broken
......@@ -62,7 +57,7 @@ class MergeRequest < ActiveRecord::Base
transition [:reopened, :opened] => :closed
end
event :merge do
event :mark_as_merged do
transition [:reopened, :opened, :locked] => :merged
end
......@@ -211,11 +206,7 @@ class MergeRequest < ActiveRecord::Base
def check_if_can_be_merged
can_be_merged =
if for_fork?
Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
else
project.repository.can_be_merged?(source_branch, target_branch)
end
project.repository.can_be_merged?(source_sha, target_branch)
if can_be_merged
mark_as_mergeable
......@@ -232,18 +223,6 @@ class MergeRequest < ActiveRecord::Base
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
end
def automerge!(current_user, commit_message = nil)
return unless automergeable?
MergeRequests::AutoMergeService.
new(target_project, current_user).
execute(self, commit_message)
end
def remove_source_branch?
self.should_remove_source_branch && !self.source_project.root_ref?(self.source_branch) && !self.for_fork?
end
def open?
opened? || reopened?
end
......@@ -252,11 +231,11 @@ class MergeRequest < ActiveRecord::Base
title =~ /\A\[?WIP\]?:? /i
end
def automergeable?
def mergeable?
open? && !work_in_progress? && can_be_merged?
end
def automerge_status
def gitlab_merge_status
if work_in_progress?
"work_in_progress"
else
......@@ -283,14 +262,14 @@ class MergeRequest < ActiveRecord::Base
#
# see "git diff"
def to_diff(current_user)
Gitlab::Satellite::MergeAction.new(current_user, self).diff_in_satellite
target_project.repository.diff_text(target_branch, source_sha)
end
# Returns the commit as a series of email patches.
#
# see "git format-patch"
def to_patch(current_user)
Gitlab::Satellite::MergeAction.new(current_user, self).format_patch
target_project.repository.format_patch(target_branch, source_sha)
end
def hook_attrs
......@@ -493,4 +472,30 @@ class MergeRequest < ActiveRecord::Base
approvers.find_or_initialize_by(user_id: user_id, target_id: id)
end
end
def target_sha
@target_sha ||= target_project.
repository.commit(target_branch).sha
end
def source_sha
commits.first.sha
end
def fetch_ref
target_project.repository.fetch_ref(
source_project.repository.path_to_repo,
"refs/heads/#{source_branch}",
"refs/merge-requests/#{iid}/head"
)
end
def in_locked_state
begin
lock_mr
yield
ensure
unlock_mr if locked?
end
end
end
......@@ -16,9 +16,8 @@ require Rails.root.join("app/models/commit")
class MergeRequestDiff < ActiveRecord::Base
include Sortable
# Prevent store of diff
# if commits amount more then 200
COMMITS_SAFE_SIZE = 200
# Prevent store of diff if commits amount more then 500
COMMITS_SAFE_SIZE = 500
attr_reader :commits, :diffs
......@@ -124,12 +123,12 @@ class MergeRequestDiff < ActiveRecord::Base
if new_diffs.any?
if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES
self.state = :overflow_diff_files_limit
new_diffs = []
new_diffs = new_diffs.first[Commit::DIFF_HARD_LIMIT_LINES]
end
if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES
self.state = :overflow_diff_lines_limit
new_diffs = []
new_diffs = new_diffs.first[Commit::DIFF_HARD_LIMIT_LINES]
end
end
......@@ -160,12 +159,21 @@ class MergeRequestDiff < ActiveRecord::Base
private
def compare_result
@compare_result ||= CompareService.new.execute(
merge_request.author,
merge_request.source_project,
merge_request.source_branch,
merge_request.target_project,
merge_request.target_branch,
)
@compare_result ||=
begin
# Update ref for merge request
merge_request.fetch_ref
# Get latest sha of branch from source project
source_sha = merge_request.source_project.commit(source_branch).sha
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
merge_request.target_project.repository.raw_repository,
merge_request.target_branch,
source_sha,
)
)
end
end
end
......@@ -114,13 +114,15 @@ class Namespace < ActiveRecord::Base
end
def move_dir
# Ensure old directory exists before moving it
gitlab_shell.add_namespace(path_was)
if gitlab_shell.mv_namespace(path_was, path)
# If repositories moved successfully we need to remove old satellites
# and send update instructions to users.
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions
begin
gitlab_shell.rm_satellites(path_was)
send_update_instructions
rescue
# Returning false does not rollback after_* transaction but gives
......
......@@ -31,8 +31,9 @@ class Note < ActiveRecord::Base
participant :author, :mentioned_users
belongs_to :project
belongs_to :noteable, polymorphic: true, touch: true
belongs_to :noteable, polymorphic: true
belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
delegate :name, to: :project, prefix: true
delegate :name, :email, to: :author, prefix: true
......
......@@ -21,12 +21,13 @@
# import_url :string(255)
# visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# avatar :string(255)
# import_status :string(255)
# repository_size :float default(0.0)
# star_count :integer default(0), not null
# import_type :string(255)
# import_source :string(255)
# avatar :string(255)
# commit_count :integer default(0)
#
require 'carrierwave/orm/activerecord'
......@@ -539,14 +540,6 @@ class Project < ActiveRecord::Base
!repository.exists? || repository.empty?
end
def ensure_satellite_exists
self.satellite.create unless self.satellite.exists?
end
def satellite
@satellite ||= Gitlab::Satellite::Satellite.new(self)
end
def repo
repository.raw
end
......@@ -616,14 +609,11 @@ class Project < ActiveRecord::Base
new_path_with_namespace = File.join(namespace_dir, path)
if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace)
# If repository moved successfully we need to remove old satellite
# and send update instructions to users.
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions
begin
gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
gitlab_shell.rm_satellites(old_path_with_namespace)
ensure_satellite_exists
send_move_instructions
reset_events_cache
rescue
......@@ -729,7 +719,6 @@ class Project < ActiveRecord::Base
def create_repository
if forked?
if gitlab_shell.fork_repository(forked_from_project.path_with_namespace, self.namespace.path)
ensure_satellite_exists
true
else
errors.add(:base, 'Failed to fork repository via gitlab-shell')
......
......@@ -41,7 +41,7 @@ class CiService < Service
# Return string with build status or :error symbol
#
# Allowed states: 'success', 'failed', 'running', 'pending'
# Allowed states: 'success', 'failed', 'running', 'pending', 'skipped'
#
#
# Ex.
......
......@@ -74,6 +74,8 @@ class GitlabCiService < CiService
else
:error
end
rescue Errno::ECONNREFUSED
:error
end
def fork_registration(new_project, private_token)
......@@ -103,6 +105,8 @@ class GitlabCiService < CiService
if response.code == 200 and response["coverage"]
response["coverage"]
end
rescue Errno::ECONNREFUSED
nil
end
def build_page(sha, ref)
......
......@@ -411,15 +411,36 @@ class Repository
}
end
def can_be_merged?(source_branch, target_branch)
def can_be_merged?(source_sha, target_branch)
our_commit = rugged.branches[target_branch].target
their_commit = rugged.branches[source_branch].target
their_commit = rugged.lookup(source_sha)
if our_commit && their_commit
!rugged.merge_commits(our_commit, their_commit).conflicts?
else
false
end
end
def merge(source_sha, target_branch, options = {})
our_commit = rugged.branches[target_branch].target
their_commit = rugged.lookup(source_sha)
raise "Invalid merge target" if our_commit.nil?
raise "Invalid merge source" if their_commit.nil?
merge_index = rugged.merge_commits(our_commit, their_commit)
return false if merge_index.conflicts?
actual_options = options.merge(
parents: [our_commit, their_commit],
tree: merge_index.write_tree(rugged),
update_ref: "refs/heads/#{target_branch}"
)
Rugged::Commit.create(rugged, actual_options)
end
def search_files(query, ref)
offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
......@@ -453,6 +474,11 @@ class Repository
)
end
def fetch_ref(source_path, source_ref, target_ref)
args = %W(git fetch #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
end
private
def cache
......
# == Schema Information
#
# Table name: audit_events
#
# id :integer not null, primary key
# author_id :integer not null
# type :string(255) not null
# entity_id :integer not null
# entity_type :string(255) not null
# details :text
# created_at :datetime
# updated_at :datetime
#
class SecurityEvent < AuditEvent
end
......@@ -57,6 +57,7 @@
# otp_backup_codes :text
# public_email :string(255) default(""), not null
# dashboard :integer default(0)
# project_view :integer default(0)
#
require 'carrierwave/orm/activerecord'
......@@ -647,7 +648,7 @@ class User < ActiveRecord::Base
end
def all_ssh_keys
keys.map(&:key)
keys.map(&:publishable_key)
end
def temp_oauth_email?
......
......@@ -31,6 +31,10 @@ class BaseService
SystemHooksService.new
end
def repository
project.repository
end
# Add an error to the specified model for restricted visibility levels
def deny_visibility_level(model, denied_visibility_level = nil)
denied_visibility_level ||= model.visibility_level
......
require 'securerandom'
# Compare 2 branches for one repo or between repositories
# and return Gitlab::CompareResult object that responds to commits and diffs
class CompareService
def execute(current_user, source_project, source_branch, target_project, target_branch)
# Try to compare branches to get commits list and diffs
#
# Note: Use satellite only when need to compare between two repos
# because satellites are slower than operations on bare repo
if target_project == source_project
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
source_branch,
)
def execute(source_project, source_branch, target_project, target_branch)
source_sha = source_project.commit(source_branch).sha
# If compare with other project we need to fetch ref first
unless target_project == source_project
random_string = SecureRandom.hex
target_project.repository.fetch_ref(
source_project.repository.path_to_repo,
"refs/heads/#{source_branch}",
"refs/tmp/#{random_string}/head"
)
else
Gitlab::Satellite::CompareAction.new(
current_user,
target_project,
target_branch,
source_project,
source_branch
).result
end
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
source_sha,
)
)
end
end
......@@ -42,10 +42,7 @@ module Files
end
def after_commit(sha, branch)
commit = repository.commit(sha)
full_ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}"
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
PostCommitService.new(project, current_user).execute(sha, branch)
end
def current_branch
......
......@@ -10,16 +10,14 @@ class GitPushService
#
# Next, this method:
# 1. Creates the push event
# 2. Ensures that the project satellite exists
# 3. Updates merge requests
# 4. Recognizes cross-references from commit messages
# 5. Executes the project's web hooks
# 6. Executes the project's services
# 2. Updates merge requests
# 3. Recognizes cross-references from commit messages
# 4. Executes the project's web hooks
# 5. Executes the project's services
#
def execute(project, user, oldrev, newrev, ref)
@project, @user = project, user
project.ensure_satellite_exists
project.repository.expire_cache
if push_remove_branch?(ref, newrev)
......
......@@ -14,7 +14,7 @@ module Issues
filter_params
old_labels = issue.labels.to_a
if params.present? && issue.update_attributes(params)
if params.present? && issue.update_attributes(params.merge(updated_by: current_user))
issue.reset_events_cache
if issue.labels != old_labels
......
module MergeRequests
# AutoMergeService class
#
# Do git merge in satellite and in case of success
# mark merge request as merged and execute all hooks and notifications
# Called when you do merge via GitLab UI
class AutoMergeService < BaseMergeService
attr_reader :merge_request, :commit_message
def execute(merge_request, commit_message)
@commit_message = commit_message
@merge_request = merge_request
merge_request.lock_mr
if merge!
merge_request.merge
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge')
true
else
merge_request.unlock_mr
false
end
rescue
merge_request.unlock_mr if merge_request.locked?
merge_request.mark_as_unmergeable
false
end
def merge!
if merge_request.for_fork?
Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
else
# Merge local branches using rugged instead of satellites
if sha = commit
after_commit(sha, merge_request.target_branch)
if merge_request.remove_source_branch?
DeleteBranchService.new(merge_request.source_project, current_user).execute(merge_request.source_branch)
end
true
else
false
end
end
end
def commit
committer = repository.user_to_comitter(current_user)
options = {
message: commit_message,
author: committer,
committer: committer
}
repository.merge(merge_request.source_branch, merge_request.target_branch, options)
end
def after_commit(sha, branch)
commit = repository.commit(sha)
full_ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}"
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
def repository
project.repository
end
end
end
module MergeRequests
class BaseMergeService < MergeRequests::BaseService
private
def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user)
end
end
end
......@@ -12,12 +12,16 @@ module MergeRequests
merge_request.target_project ||= (project.forked_from_project || project)
merge_request.target_branch ||= merge_request.target_project.default_branch
unless merge_request.target_branch && merge_request.source_branch
return build_failed(merge_request, nil)
if merge_request.target_branch.blank? || merge_request.source_branch.blank?
message =
if params[:source_branch] || params[:target_branch]
"You must select source and target branch"
end
return build_failed(merge_request, message)
end
compare_result = CompareService.new.execute(
current_user,
merge_request.source_project,
merge_request.source_branch,
merge_request.target_project,
......@@ -40,7 +44,6 @@ module MergeRequests
merge_request.compare_diffs = diffs
elsif diffs == false
# satellite timeout return false
merge_request.can_be_created = false
merge_request.compare_failed = true
end
......@@ -64,9 +67,6 @@ module MergeRequests
end
merge_request
rescue Gitlab::Satellite::BranchesWithoutParent
return build_failed(merge_request, "Selected branches have no common commit so they cannot be merged.")
end
def build_failed(merge_request, message)
......
module MergeRequests
# MergeService class
#
# Mark existing merge request as merged
# and execute all hooks and notifications
# Called when you do merge via command line and push code
# to target branch
class MergeService < BaseMergeService
# Do git merge and in case of success
# mark merge request as merged and execute all hooks and notifications
# Executed when you do merge via GitLab UI
#
class MergeService < MergeRequests::BaseService
attr_reader :merge_request, :commit_message
def execute(merge_request, commit_message)
merge_request.merge
@commit_message = commit_message
@merge_request = merge_request
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge')
unless @merge_request.mergeable?
return error('Merge request is not mergeable')
end
merge_request.in_locked_state do
if merge_changes
after_merge
success
else
error('Can not merge changes')
end
end
end
private
def merge_changes
if sha = commit
after_commit(sha, merge_request.target_branch)
end
end
def commit
committer = repository.user_to_comitter(current_user)
options = {
message: commit_message,
author: committer,
committer: committer
}
repository.merge(merge_request.source_sha, merge_request.target_branch, options)
end
def after_commit(sha, branch)
PostCommitService.new(project, current_user).execute(sha, branch)
end
true
rescue
false
def after_merge
MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
end
end
end
module MergeRequests
# PostMergeService class
#
# Mark existing merge request as merged
# and execute all hooks and notifications
#
class PostMergeService < MergeRequests::BaseService
def execute(merge_request)
merge_request.mark_as_merged
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
execute_hooks(merge_request, 'merge')
end
private
def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user)
end
end
end
......@@ -34,9 +34,9 @@ module MergeRequests
merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::MergeService.
MergeRequests::PostMergeService.
new(merge_request.target_project, @current_user).
execute(merge_request, nil)
execute(merge_request)
end
end
......
......@@ -24,7 +24,7 @@ module MergeRequests
filter_params
old_labels = merge_request.labels.to_a
if params.present? && merge_request.update_attributes(params)
if params.present? && merge_request.update_attributes(params.merge(updated_by: current_user))
merge_request.reset_events_cache
if merge_request.labels != old_labels
......
module Notes
class UpdateService < BaseService
def execute
note = project.notes.find(params[:note_id])
note.note = params[:note]
if note.save
notification_service.new_note(note)
def execute(note)
return note unless note.editable?
# Skip system notes, like status changes and cross-references.
unless note.system
event_service.leave_note(note, note.author)
note.update_attributes(params.merge(updated_by: current_user))
# Create a cross-reference note if this Note contains GFM that
# names an issue, merge request, or commit.
note.references.each do |mentioned|
SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end
end
end
note.reset_events_cache
note
end
......
......@@ -70,12 +70,6 @@ class NotificationService
reassign_resource_email(merge_request, merge_request.target_project, current_user, 'reassigned_merge_request_email')
end
# When we close a merge request we should send next emails:
#
# * merge_request author if their notification level is not Disabled
# * merge_request assignee if their notification level is not Disabled
# * project team members with notification level higher then Participating
#
def close_mr(merge_request, current_user)
close_resource_email(merge_request, merge_request.target_project, current_user, 'closed_merge_request_email')
end
......@@ -84,26 +78,8 @@ class NotificationService
reopen_resource_email(issue, issue.project, current_user, 'issue_status_changed_email', 'reopened')
end
# When we merge a merge request we should send next emails:
#
# * merge_request author if their notification level is not Disabled
# * merge_request assignee if their notification level is not Disabled
# * project team members with notification level higher then Participating
#
def merge_mr(merge_request, current_user)
recipients = [merge_request.author, merge_request.assignee]
recipients = add_project_watchers(recipients, merge_request.target_project)
recipients = reject_muted_users(recipients, merge_request.target_project)
recipients = add_subscribed_users(recipients, merge_request)
recipients = reject_unsubscribed_users(recipients, merge_request)
recipients.delete(current_user)
recipients.each do |recipient|
mailer.merged_merge_request_email(recipient.id, merge_request.id, current_user.id)
end
close_resource_email(merge_request, merge_request.target_project, current_user, 'merged_merge_request_email')
end
def reopen_mr(merge_request, current_user)
......@@ -364,8 +340,7 @@ class NotificationService
end
def new_resource_email(target, project, method)
recipients = build_recipients(target, project)
recipients.delete(target.author)
recipients = build_recipients(target, project, target.author)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id)
......@@ -373,8 +348,7 @@ class NotificationService
end
def close_resource_email(target, project, current_user, method)
recipients = build_recipients(target, project)
recipients.delete(current_user)
recipients = build_recipients(target, project, current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, current_user.id)
......@@ -383,8 +357,7 @@ class NotificationService
def reassign_resource_email(target, project, current_user, method)
assignee_id_was = previous_record(target, "assignee_id")
recipients = build_recipients(target, project)
recipients.delete(current_user)
recipients = build_recipients(target, project, current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, assignee_id_was, current_user.id)
......@@ -392,21 +365,15 @@ class NotificationService
end
def reopen_resource_email(target, project, current_user, method, status)
recipients = build_recipients(target, project)
recipients.delete(current_user)
recipients = build_recipients(target, project, current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, status, current_user.id)
end
end
def build_recipients(target, project)
recipients =
if target.respond_to?(:participants)
target.participants
else
[target.author, target.assignee]
end
def build_recipients(target, project, current_user)
recipients = target.participants(current_user)
recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project)
......@@ -415,6 +382,8 @@ class NotificationService
recipients = add_subscribed_users(recipients, target)
recipients = reject_unsubscribed_users(recipients, target)
recipients.delete(current_user)
recipients
end
......
class PostCommitService < BaseService
include Gitlab::Popen
attr_reader :changes, :repo_path
def execute(sha, branch)
commit = repository.commit(sha)
full_ref = Gitlab::Git::BRANCH_REF_PREFIX + branch
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
@changes = "#{old_sha} #{sha} #{full_ref}"
@repo_path = repository.path_to_repo
post_receive
end
private
def post_receive
hook = hook_file('post-receive', repo_path)
return true if hook.nil?
call_receive_hook(hook)
end
def call_receive_hook(hook)
# function will return true if succesful
exit_status = false
vars = {
'GL_ID' => Gitlab::ShellEnv.gl_id(current_user),
'PWD' => repo_path
}
options = {
chdir: repo_path
}
# we combine both stdout and stderr as we don't know what stream
# will be used by the custom hook
Open3.popen2e(vars, hook, options) do |stdin, stdout_stderr, wait_thr|
exit_status = true
stdin.sync = true
# in git, pre- and post- receive hooks may just exit without
# reading stdin. We catch the exception to avoid a broken pipe
# warning
begin
# inject all the changes as stdin to the hook
changes.lines do |line|
stdin.puts line
end
rescue Errno::EPIPE
end
# need to close stdin before reading stdout
stdin.close
# only output stdut_stderr if scripts doesn't return 0
unless wait_thr.value == 0
exit_status = false
end
end
exit_status
end
def hook_file(hook_type, repo_path)
hook_path = File.join(repo_path.strip, 'hooks')
hook_file = "#{hook_path}/#{hook_type}"
hook_file if File.exist?(hook_file)
end
end
......@@ -27,7 +27,6 @@ module Projects
end
end
project.satellite.destroy
log_info("Project \"#{project.name}\" was removed")
system_hook_service.execute_hooks_for(project, :destroy)
true
......
......@@ -33,9 +33,6 @@ module Projects
raise TransferError.new("Project with same path in target namespace already exists")
end
# Remove old satellite
project.satellite.destroy
# Apply new namespace id
project.namespace = new_namespace
project.save!
......@@ -51,9 +48,6 @@ module Projects
# Move wiki repo also if present
gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki")
# Create a new satellite (reload project from DB)
Project.find(project.id).ensure_satellite_exists
# clear project cached events
project.reset_events_cache
......
- page_title "Report abuse"
%h3.page-title Report abuse
%p Please use this form to report users who create spam issues, comments or behave inappropriately.
%hr
= form_for @abuse_report, html: { class: 'form-horizontal'} do |f|
= f.hidden_field :user_id
- if @abuse_report.errors.any?
.alert.alert-danger
- @abuse_report.errors.full_messages.each do |msg|
%p= msg
.form-group
= f.label :user_id, class: 'control-label'
.col-sm-10
- name = "#{@abuse_report.user.name} (@#{@abuse_report.user.username})"
= text_field_tag :user_name, name, class: "form-control", readonly: true
.form-group
= f.label :message, class: 'control-label'
.col-sm-10
= f.text_area :message, class: "form-control", rows: 2, required: true
.help-block
Explain the problem with this user. If appropriate, provide a link to the relevant issue or comment.
.form-actions
= f.submit "Send report", class: "btn btn-create"
- reporter = abuse_report.reporter
- user = abuse_report.user
%tr
%td
- if reporter
= link_to reporter.name, [:admin, reporter]
- else
(removed)
%td
= abuse_report.created_at.to_s(:short)
%td
= abuse_report.message
%td
- if user
= link_to user.name, [:admin, user]
- else
(removed)
%td
- if user
= link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs btn-warning"
= link_to 'Remove user', [:admin, user], data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-xs btn-remove"
%td
= link_to 'Remove report', [:admin, abuse_report], method: :delete, class: "btn btn-xs btn-close"
- page_title "Abuse Reports"
%h3.page-title Abuse Reports
%hr
- if @abuse_reports.present?
%table.table
%thead
%tr
%th Reported by
%th Reported at
%th Message
%th User
%th
%th
= render @abuse_reports
= paginate @abuse_reports
- else
%h4 There are no abuse reports
......@@ -105,6 +105,16 @@
.col-md-6
- unless @user == current_user
- unless @user.confirmed?
.panel.panel-info
.panel-heading
Confirm user
.panel-body
- if @user.unconfirmed_email.present?
- email = " (#{@user.unconfirmed_email})"
%p This user has an unconfirmed email address#{email}. You may force a confirmation.
%br
= link_to 'Confirm user', confirm_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' }
- if @user.blocked?
.panel.panel-info
.panel-heading
......
......@@ -3,13 +3,11 @@
.event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
- if event.created_project?
= cache [event, current_user] do
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
= render "events/event/created_project", event: event
- else
= cache [event, "v1"] do
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
- if event.push?
- if event.created_project?
= render "events/event/created_project", event: event
- elsif event.push?
= render "events/event/push", event: event
- elsif event.commented?
= render "events/event/note", event: event
......
......@@ -8,8 +8,8 @@
- else
= event.project_name
- if current_user == event.author && !event.project.private? && twitter_sharing_enabled?
.event-body
- if !event.project.private? && twitter_sharing_enabled?
.event-body{"data-user-is" => event.author_id}
.event-note
.md
%p
......
......@@ -17,7 +17,7 @@
- few_commits.each do |commit|
= render "events/commit", commit: commit, project: project
- create_mr = current_user == event.author && event.new_ref? && create_mr_button?(event.project.default_branch, event.ref_name, event.project)
- create_mr = event.new_ref? && create_mr_button?(event.project.default_branch, event.ref_name, event.project)
- if event.commits_count > 1
%li.commits-stat
- if event.commits_count > 2
......@@ -34,10 +34,11 @@
Compare #{from_label}...#{truncate_sha(event.commit_to)}
- if create_mr
or
= link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
create a merge request
%span{"data-user-is" => event.author_id, "data-display" => "inline"}
or
= link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
create a merge request
- elsif create_mr
%li.commits-stat
%li.commits-stat{"data-user-is" => event.author_id}
= link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
Create Merge Request
......@@ -9,8 +9,8 @@
.project-info
- if project.description.present?
%p.project-description.str-truncated
= project.description
.project-description.str-truncated
= markdown(project.description, pipeline: :description)
.repo-info
- unless project.empty_repo?
......
......@@ -3,11 +3,16 @@
%i.fa.fa-bitbucket
Import projects from Bitbucket
%p.light
Select projects you want to import.
%hr
%p
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
- if @repos.any?
%p.light
Select projects you want to import.
%hr
%p
- if @incompatible_repos.any?
= button_tag 'Import all compatible projects', class: "btn btn-success js-import-all"
- else
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
%table.table.import-jobs
%thead
......@@ -41,6 +46,24 @@
= "#{repo["owner"]}/#{repo["slug"]}"
%td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import"
- @incompatible_repos.each do |repo|
%tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
%td
= link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
%td.import-target
%td.import-actions-job-status
= label_tag "Incompatible Project", nil, class: "label label-danger"
- if @incompatible_repos.any?
%p
One or more of your Bitbucket projects cannot be imported into GitLab
directly because they use Subversion or Mercurial for version control,
rather than Git. Please convert
= link_to "them to Git,", "https://www.atlassian.com/git/tutorials/migrating-overview"
and go through the
= link_to "import flow", status_import_bitbucket_path
again.
:coffeescript
new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}")
......@@ -27,7 +27,7 @@
= favicon_link_tag 'touch-icon-ipad-retina.png', rel: 'apple-touch-icon', sizes: '152x152'
-# Windows 8 pinned site tile
%meta{name: 'msapplication-TileImage', content: image_url('msapplication-tile.png')}
%meta{name: 'msapplication-TileImage', content: image_path('msapplication-tile.png')}
%meta{name: 'msapplication-TileColor', content: '#30353E'}
= yield :meta_tags
......@@ -35,3 +35,5 @@
= render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
= render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id')
= render 'layouts/bootlint' if Rails.env.development?
= render 'layouts/user_styles'
:css
[data-user-is] {
display: none !important;
}
[data-user-is="#{current_user.try(:id)}"] {
display: block !important;
}
[data-user-is="#{current_user.try(:id)}"][data-display="inline"] {
display: inline !important;
}
[data-user-is-not] {
display: block !important;
}
[data-user-is-not][data-display="inline"] {
display: inline !important;
}
[data-user-is-not="#{current_user.try(:id)}"] {
display: none !important;
}
......@@ -67,6 +67,13 @@
%span
Service Templates
= nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse reports" do
= icon('exclamation-circle fw')
%span
Abuse Reports
%span.count= AbuseReport.count(:all)
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings', data: {placement: 'right'} do
= icon('cogs fw')
......
......@@ -82,12 +82,12 @@
You can change your avatar here
- if Gitlab.config.gravatar.enabled
%br
or remove the current avatar to revert to #{link_to "gravatar.com", "http://gravatar.com"}
or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host}
- else
You can upload an avatar here
- if Gitlab.config.gravatar.enabled
%br
or change it at #{link_to "gravatar.com", "http://gravatar.com"}
or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host}
%hr
%a.choose-btn.btn.btn-sm.js-choose-user-avatar-button
%i.fa.fa-paperclip
......
......@@ -3,6 +3,7 @@
.project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.project-home-desc.lead
%h1= @project.name
- if @project.description.present?
= markdown(@project.description, pipeline: :description)
......@@ -19,9 +20,15 @@
Forked from
= forked_from_project.namespace.try(:name)
- if can? current_user, :download_code, @project
= link_to "#", class: 'btn js-toggle-clone-holder' do
= icon('cloud-download fw')
Clone
- if can? current_user, :download_code, @project
= link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.fa.fa-download
= icon('download fw')
Download
= render 'projects/buttons/dropdown'
......
- if current_user
%span.dropdown
%a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
%i.fa.fa-plus
= icon('plus')
%ul.dropdown-menu
- if @project.issues_enabled && can?(current_user, :create_issue, @project)
- if can?(current_user, :create_issue, @project)
%li
= link_to url_for_new_issue, title: "New Issue" do
= link_to url_for_new_issue do
= icon('exclamation-circle fw')
New issue
- if @project.merge_requests_enabled && can?(current_user, :create_merge_request, @project)
- if can?(current_user, :create_merge_request, @project)
%li
= link_to new_namespace_project_merge_request_path(@project.namespace, @project), title: "New Merge Request" do
= link_to new_namespace_project_merge_request_path(@project.namespace, @project) do
= icon('tasks fw')
New merge request
- if @project.snippets_enabled && can?(current_user, :create_snippet, @project)
- if can?(current_user, :create_snippet, @project)
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
= link_to new_namespace_project_snippet_path(@project.namespace, @project) do
= icon('file-text-o fw')
New snippet
- if can?(current_user, :admin_project_member, @project)
%li
= link_to namespace_project_project_members_path(@project.namespace, @project), title: "New project member" do
New project member
- if can? current_user, :push_code, @project
- if can?(current_user, :push_code, @project)
%li.divider
%li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do
New git branch
= icon('code-fork fw')
New branch
%li
= link_to new_namespace_project_tag_path(@project.namespace, @project) do
New git tag
= icon('tags fw')
New tag
- if current_user && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn' do
= icon('code-fork')
= icon('code-fork fw')
Fork
%span.count
= @project.forks_count
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn' do
= icon('code-fork')
= icon('code-fork fw')
Fork
%span.count
= @project.forks_count
- if current_user
= link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star', method: :post, remote: true do
= icon('star')
= icon('star fw')
- if current_user.starred?(@project)
Unstar
- else
......@@ -16,7 +16,7 @@
- else
= link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do
= icon('star')
= icon('star fw')
Star
%span.count
= @project.star_count
......@@ -9,7 +9,13 @@
Open
Issue ##{@issue.iid}
%small.creator
&middot; created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
&middot; created by #{link_to_member(@project, @issue.author)}
= time_ago_with_tooltip(@issue.created_at, placement: 'bottom', html_class: 'issue_created_ago')
- if @issue.updated_at != @issue.created_at
%span
&middot;
= icon('edit', title: 'edited')
= time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
.pull-right
- if can?(current_user, :create_issue, @project)
......
......@@ -35,7 +35,7 @@
- if @merge_request.compare_failed
.alert.alert-danger
%h4 Compare failed
%p We can't compare selected branches. It may be because of huge diff or satellite timeout. Please try again or select different branches.
%p We can't compare selected branches. It may be because of huge diff. Please try again or select different branches.
- else
.light-well
.center
......
......@@ -24,7 +24,7 @@
= icon('history')
Commits
%span.badge= @commits.size
%li.diffs-tab
%li.diffs-tab.active
= link_to url_for(params), data: {target: '#diffs', action: 'diffs', toggle: 'tab'} do
= icon('list-alt')
Changes
......@@ -33,7 +33,7 @@
.tab-content
#commits.commits.tab-pane
= render "projects/commits/commits", project: @project
#diffs.diffs.tab-pane
#diffs.diffs.tab-pane.active
- if @diffs.present?
= render "projects/diffs/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
......
......@@ -6,40 +6,25 @@
= render "projects/merge_requests/show/mr_box"
%hr
.append-bottom-20
.slead
%span From
- if @merge_request.for_fork?
%strong.label-branch<
- if @merge_request.source_project
= link_to @merge_request.source_project_namespace, namespace_project_path(@merge_request.source_project.namespace, @merge_request.source_project)
- else
\ #{@merge_request.source_project_namespace}
\:#{@merge_request.source_branch}
- if @merge_request.open?
.btn-group.btn-group-sm.pull-right
%a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
= icon('download')
Download as
%span.caret
%ul.dropdown-menu
%li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
%li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
.light
%div
%span From
%span.label-branch #{source_branch_with_namespace(@merge_request)}
%span into
%strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
- else
%strong.label-branch #{@merge_request.source_branch}
%span into
%strong.label-branch #{@merge_request.target_branch}
- if @merge_request.open?
.btn-group.btn-group-sm.pull-right
%a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
= icon('download')
Download as
%span.caret
%ul.dropdown-menu
%li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
%li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- if @merge_request.open? and @merge_request.source_branch_exists?
.append-bottom-20
.slead
%span
Fetch the branch with
%strong.label-branch<
git fetch
\ #{@merge_request.source_project.http_url_to_repo}
\ #{@merge_request.source_branch}
%span.label-branch #{@merge_request.target_branch}
- if @merge_request.open? && !@merge_request.branch_missing?
%div
If you want to try or merge this request manually, you can use the
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
= render "projects/merge_requests/show/how_to_merge"
= render "projects/merge_requests/widget/show.html.haml"
......
= render "projects/commits/commits", project: @merge_request.source_project
= render "projects/commits/commits", project: @merge_request.project
- if @merge_request_diff.collected?
= render "projects/diffs/diffs", diffs: @merge_request.diffs, project: @merge_request.source_project
= render "projects/diffs/diffs", diffs: @merge_request.diffs, project: @merge_request.project
- elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else
......
......@@ -3,42 +3,45 @@
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 How to merge
%h3 Check out, review and merge locally
.modal-body
- if @merge_request.for_fork?
- source_remote = @merge_request.source_project.namespace.nil? ? "source" :@merge_request.source_project.namespace.path
- target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path
%p
%strong Step 1.
Fetch the code and create a new branch pointing to it
%pre.dark
%p
%strong Step 1.
Fetch and check out the branch for this merge request
%pre.dark
- if @merge_request.for_fork?
:preserve
git fetch #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch}
git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} FETCH_HEAD
%p
%strong Step 2.
Merge the branch and push the changes to GitLab
%pre.dark
:preserve
git checkout #{@merge_request.target_branch}
git merge --no-ff #{@merge_request.source_project_path}-#{@merge_request.source_branch}
git push origin #{@merge_request.target_branch}
- else
%p
%strong Step 1.
Update the repo and checkout the branch we are going to merge
%pre.dark
- else
:preserve
git fetch origin
git checkout -b #{@merge_request.source_branch} origin/#{@merge_request.source_branch}
%p
%strong Step 2.
Merge the branch and push the changes to GitLab
%pre.dark
%p
%strong Step 2.
Review the changes locally
%p
%strong Step 3.
Merge the branch and fix any conflicts that come up
%pre.dark
- if @merge_request.for_fork?
:preserve
git checkout #{@merge_request.target_branch}
git merge --no-ff #{@merge_request.source_project_path}-#{@merge_request.source_branch}
- else
:preserve
git checkout #{@merge_request.target_branch}
git merge --no-ff #{@merge_request.source_branch}
git push origin #{@merge_request.target_branch}
%p
%strong Step 4.
Push the result of the merge to GitLab
%pre.dark
:preserve
git push origin #{@merge_request.target_branch}
- unless @merge_request.can_be_merged_by?(current_user)
%p
Note that pushing to GitLab requires write access to this repository.
:javascript
$(function(){
......
%h4.page-title
.issue-box{ class: issue_box_class(@merge_request) }
= @merge_request.state_human_name
= "Merge Request ##{@merge_request.iid}"
Merge Request ##{@merge_request.iid}
%small.creator
&middot;
created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
created by #{link_to_member(@project, @merge_request.author)}
= time_ago_with_tooltip(@merge_request.created_at)
- if @merge_request.updated_at != @merge_request.created_at
%span
&middot;
= icon('edit', title: 'edited')
= time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom')
.issue-btn-group.pull-right
- if can?(current_user, :update_merge_request, @merge_request)
......
......@@ -6,4 +6,7 @@
- if @merge_request.closed_event
by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
%p Changes were not merged into target branch
%p
= succeed '.' do
The changes were not merged into
%span.label-branch= @merge_request.target_branch
- if @merge_request.has_ci?
.mr-widget-heading
.ci_widget.ci-success{style: "display:none"}
= icon("check")
%span CI build passed
for #{@merge_request.last_commit_short_sha}.
= link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
.ci_widget.ci-failed{style: "display:none"}
= icon("times")
%span CI build failed
for #{@merge_request.last_commit_short_sha}.
= link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
- [:running, :pending].each do |status|
- [:success, :skipped, :canceled, :failed, :running, :pending].each do |status|
.ci_widget{class: "ci-#{status}", style: "display:none"}
= icon("clock-o")
- if status == :success
- status = "passed"
= icon("check-circle")
- else
= icon("circle")
%span CI build #{status}
for #{@merge_request.last_commit_short_sha}.
= link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
%span.ci-coverage
= link_to "View build details", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
.ci_widget
= icon("spinner spin")
Checking for CI status for #{@merge_request.last_commit_short_sha}
Checking CI status for #{@merge_request.last_commit_short_sha}&hellip;
.ci_widget.ci-not_found{style: "display:none"}
= icon("times")
%span Can not find commit in the CI server
for #{@merge_request.last_commit_short_sha}.
.ci_widget.ci-canceled{style: "display:none"}
= icon("times")
%span CI build canceled
for #{@merge_request.last_commit_short_sha}.
= link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
= icon("times-circle")
Could not find CI status for #{@merge_request.last_commit_short_sha}.
.ci_widget.ci-error{style: "display:none"}
= icon("times")
%span Cannot connect to the CI server. Please check your settings and try again.
= icon("times-circle")
Could not connect to the CI server. Please check your settings and try again.
:coffeescript
$ ->
......
......@@ -2,7 +2,8 @@
= render 'projects/merge_requests/widget/heading'
.mr-widget-body
%h4
Merge in progress...
= icon("spinner spin")
Merge in progress&hellip;
%p
Merging is in progress. While merging this request is locked and cannot be closed.
This merge request is in the process of being merged, during which time it is locked and cannot be closed.
......@@ -7,23 +7,31 @@
by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
%div
- if @source_branch.blank?
Source branch has been removed
- if !@merge_request.source_branch_exists?
= succeed '.' do
The changes were merged into
%span.label-branch= @merge_request.target_branch
The source branch has been removed.
- elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && @merge_request.merged?
- elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch)
.remove_source_branch_widget
%p Changes merged into #{@merge_request.target_branch}. You can remove source branch now
%p
= succeed '.' do
The changes were merged into
%span.label-branch= @merge_request.target_branch
You can remove the source branch now.
= link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-sm remove_source_branch" do
%i.fa.fa-times
Remove Source Branch
.remove_source_branch_widget.failed.hide
Failed to remove source branch '#{@merge_request.source_branch}'
%p
Failed to remove source branch '#{@merge_request.source_branch}'.
.remove_source_branch_in_progress.hide
%i.fa.fa-spinner.fa-spin
&nbsp;
Removing source branch '#{@merge_request.source_branch}'. Please wait. Page will be automatically reloaded. &nbsp;
%p
= icon('spinner spin')
Removing source branch '#{@merge_request.source_branch}'. Please wait. This page will be automatically reload.
:coffeescript
$('.remove_source_branch').on 'click', ->
......
......@@ -3,8 +3,6 @@
.mr-widget-body
- if @project.archived?
= render 'projects/merge_requests/widget/open/archived'
- elsif !@project.satellite.exists?
= render 'projects/merge_requests/widget/open/no_satellite'
- elsif @merge_request.commits.blank?
= render 'projects/merge_requests/widget/open/nothing'
- elsif @merge_request.branch_missing?
......@@ -26,7 +24,7 @@
.mr-widget-footer
%span
%i.fa.fa-check
Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
Accepting this merge request will close #{"issue".pluralize(@closes_issues.size)}
= succeed '.' do
!= gfm(issues_sentence(@closes_issues))
......
......@@ -11,10 +11,10 @@
var merge_request_widget;
merge_request_widget = new MergeRequestWidget({
url_to_automerge_check: "#{automerge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
check_enable: #{@merge_request.unchecked? ? "true" : "false"},
url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
ci_enable: #{@project.ci_service ? "true" : "false"},
current_status: "#{@merge_request.automerge_status}",
current_status: "#{@merge_request.gitlab_merge_status}",
});
= form_for [:automerge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f|
= form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f|
= hidden_field_tag :authenticity_token, form_authenticity_token
.accept-merge-holder.clearfix.js-toggle-container
.accept-action
......@@ -8,28 +8,22 @@
.accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch
Remove source-branch
Remove source branch
- if @merge_request.target_project.merge_requests_rebase_enabled && can_rebase?(@merge_request.target_project, @merge_request.target_branch)
.accept-control.remove_branch_holder.checkbox
= label_tag :should_rebase do
= check_box_tag :should_rebase, "1", @project.merge_requests_rebase_default
%strong Rebase before merge
Rebase before merge
.accept-control
= link_to "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message" do
%i.fa.fa-edit
= link_to "#", class: "modify-merge-commit-link js-toggle-button" do
= icon('edit')
Modify commit message
.js-toggle-content.hide.prepend-top-20
= render 'shared/commit_message_container', params: params,
text: @merge_request.merge_commit_message,
rows: 14, hint: true
%br
.light
If you want to merge this request manually, you can use the
%strong
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
:coffeescript
$('.accept-mr-form').on 'ajax:before', ->
btn = $('.accept_merge_request')
......
%h4
Project is archived
%p
%strong Archived projects do not provide commit access.
This merge request cannot be merged because archived projects cannot be written to.
%strong
%i.fa.fa-spinner.fa-spin
Checking automatic merge…
= icon("spinner spin")
Checking ability to merge automatically&hellip;
:coffeescript
$ ->
......
- if @merge_request.can_be_merged_by?(current_user)
%h4
This merge request contains merge conflicts that must be resolved.
You can try it manually on the
%strong
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- else
%strong This merge request contains merge conflicts that must be resolved.
Only those with write access to this repository can merge merge requests.
%h4
= icon("exclamation-triangle")
This merge request contains merge conflicts
%p
Please resolve these conflicts or
- if @merge_request.can_be_merged_by?(current_user)
#{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}.
- else
ask someone with write access to this repository to merge this request manually.
%h4
Can't be merged
%p
This merge request can not be accepted because branch
- unless @merge_request.source_branch_exists?
%span.label.label-inverse= @merge_request.source_branch
does not exist in
%span.label.label-info= @merge_request.source_project_path
- else
%span.label.label-inverse= @merge_request.target_branch
does not exist in
%span.label.label-info= @merge_request.target_project_path
%br
%strong Please close this merge request or change branches with existing one
- unless @merge_request.source_branch_exists?
%h4
= icon("exclamation-triangle")
Source branch
%span.label-branch= source_branch_with_namespace(@merge_request)
does not exist
%p
Please restore the source branch or close this merge request and open a new merge request with a different source branch.
- else
%h4
= icon("exclamation-triangle")
Target branch
%span.label-branch= @merge_request.target_branch
does not exist
%p
Please restore the target branch or use a different target branch.
%p
%span
%strong This repository does not have a satellite. Please ask an administrator to fix this issue!
%strong This request can be merged automatically.
Only those with write access to this repository can merge merge requests.
%h4
Ready to be merged automatically
%p
Ask someone with write access to this repository to merge this request.
%h4 Nothing to merge
%p
%h4
= icon("exclamation-triangle")
Nothing to merge from
%span.label-branch #{@merge_request.source_branch}
to
%span.label-branch #{@merge_request.target_branch}
%br
Try to use different branches or push new code.
%span.label-branch= source_branch_with_namespace(@merge_request)
into
%span.label-branch= @merge_request.target_branch
%p
Please push new commits to the source branch or use a different target branch.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment