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. Please view this file on the master branch, on stable branches it's out of date.
v 7.14.0 (unreleased) 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 multi-line syntax highlighting (Stan Hu)
- Fix network graph when branch name has single quotes (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) - 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) - 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) - Fix URL used for refreshing notes if relative_url is present (Bartłomiej Święcki)
...@@ -17,8 +23,11 @@ v 7.14.0 (unreleased) ...@@ -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 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) - Fix file upload dialog for comment editing (Daniel Gerhardt)
- Set OmniAuth full_host parameter to ensure redirect URIs are correct (Stan Hu) - 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 - Expire Rails cache entries after two weeks to prevent endless Redis growth
- Add support for destroying project milestones (Stan Hu) - 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 fetch command to the MR page
- Add project star and fork count, group avatar URL and user/group web URL attributes to API - 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. - Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
...@@ -26,8 +35,26 @@ v 7.14.0 (unreleased) ...@@ -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 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 - 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 - 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) - Disabled autocapitalize and autocorrect on login field (Daryl Chan)
- Mention group and project name in creation, update and deletion notices (Achilleas Pipinellis) - 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 v 7.13.2
- Fix randomly failed spec - Fix randomly failed spec
...@@ -52,7 +79,6 @@ v 7.13.1 ...@@ -52,7 +79,6 @@ v 7.13.1
v 7.13.0 v 7.13.0
- Remove repository graph log to fix slow cache updates after push event (Stan Hu) - 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) - Only enable HSTS header for HTTPS and port 443 (Stan Hu)
- Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu) - Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu)
- Fix redirection to home page URL for unauthorized users (Daniel Gerhardt) - Fix redirection to home page URL for unauthorized users (Daniel Gerhardt)
...@@ -79,15 +105,15 @@ v 7.13.0 ...@@ -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 - 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 - Admin can edit and remove user identities
- Convert CRLF newlines to LF when committing using the web editor. - 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. - 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. - Show a user's Two-factor Authentication status in the administration area.
- Explicit error when commit not found in the CI - 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 - 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 - 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 - 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. - Correctly show anonymous authorized applications under Profile > Applications.
- Query Optimization in MySQL. - Query Optimization in MySQL.
- Allow users to be blocked and unblocked via the API - Allow users to be blocked and unblocked via the API
...@@ -95,17 +121,17 @@ v 7.13.0 ...@@ -95,17 +121,17 @@ v 7.13.0
- Redesign project page. Show README as default instead of activity. Move project activity to separate page - 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 - 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. - 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 - Allow administrators to disable 2FA for a specific user
- Add error message for SSH key linebreaks - Add error message for SSH key linebreaks
- Store commits count in database (will populate with valid values only after first push) - Store commits count in database (will populate with valid values only after first push)
- Rebuild cache after push to repository in background job - Rebuild cache after push to repository in background job
- Fix transferring of project to another group using the API.
v 7.12.2 v 7.12.2
- Correctly show anonymous authorized applications under Profile > Applications. - Correctly show anonymous authorized applications under Profile > Applications.
- 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
- Audit log for user authentication - Audit log for user authentication
- Fix transferring of project to another group using the API.
- Allow custom label to be set for authentication providers. - Allow custom label to be set for authentication providers.
v 7.12.1 v 7.12.1
...@@ -114,7 +140,7 @@ v 7.12.1 ...@@ -114,7 +140,7 @@ v 7.12.1
- Add SAML to list of social_provider (Matt Firtion) - 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 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) - 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) - Fix hooks for web based events with external issue references (Daniel Gerhardt)
- Improve performance for issue and merge request pages - Improve performance for issue and merge request pages
- Compress database dumps to reduce backup size - Compress database dumps to reduce backup size
......
...@@ -154,7 +154,7 @@ GEM ...@@ -154,7 +154,7 @@ GEM
doorkeeper (2.1.3) doorkeeper (2.1.3)
railties (>= 3.2) railties (>= 3.2)
dotenv (0.9.0) dotenv (0.9.0)
dropzonejs-rails (0.4.14) dropzonejs-rails (0.7.1)
rails (> 3.1) rails (> 3.1)
email_spec (1.6.0) email_spec (1.6.0)
launchy (~> 2.1) launchy (~> 2.1)
...@@ -374,7 +374,7 @@ GEM ...@@ -374,7 +374,7 @@ GEM
mini_portile (0.6.2) mini_portile (0.6.2)
minitest (5.3.5) minitest (5.3.5)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.11.1) multi_json (1.11.2)
multi_xml (0.5.5) multi_xml (0.5.5)
multipart-post (1.2.0) multipart-post (1.2.0)
mysql2 (0.3.16) mysql2 (0.3.16)
...@@ -509,7 +509,7 @@ GEM ...@@ -509,7 +509,7 @@ GEM
rdoc (3.12.2) rdoc (3.12.2)
json (~> 1.4) json (~> 1.4)
redcarpet (3.3.2) redcarpet (3.3.2)
redis (3.1.0) redis (3.2.1)
redis-actionpack (4.0.0) redis-actionpack (4.0.0)
actionpack (~> 4) actionpack (~> 4)
redis-rack (~> 1.5.0) redis-rack (~> 1.5.0)
...@@ -526,7 +526,7 @@ GEM ...@@ -526,7 +526,7 @@ GEM
redis-actionpack (~> 4) redis-actionpack (~> 4)
redis-activesupport (~> 4) redis-activesupport (~> 4)
redis-store (~> 1.1.0) redis-store (~> 1.1.0)
redis-store (1.1.4) redis-store (1.1.6)
redis (>= 2.2) redis (>= 2.2)
request_store (1.0.5) request_store (1.0.5)
rerun (0.10.0) rerun (0.10.0)
...@@ -878,4 +878,4 @@ DEPENDENCIES ...@@ -878,4 +878,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.10.5 1.10.4
# GitLab # GitLab
[![build status](https://ci.gitlab.com/projects/1/status.png?ref=master)](https://ci.gitlab.com/projects/1?ref=master) [![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) [![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) [![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 ...@@ -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: GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL - Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.0 or 2.1 - Ruby (MRI) 2.1
- Git 1.7.10+ - Git 1.7.10+
- Redis 2.0+ - Redis 2.0+
- MySQL or PostgreSQL - MySQL or PostgreSQL
......
...@@ -8,6 +8,7 @@ class @DropzoneInput ...@@ -8,6 +8,7 @@ class @DropzoneInput
divAlert = "<div class=\"" + alertClass + "\"></div>" divAlert = "<div class=\"" + alertClass + "\"></div>"
iconPaperclip = "<i class=\"fa fa-paperclip div-dropzone-icon\"></i>" iconPaperclip = "<i class=\"fa fa-paperclip div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"fa fa-spinner fa-spin 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>" btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_uploads_path = window.project_uploads_path or null project_uploads_path = window.project_uploads_path or null
markdown_preview_path = window.markdown_preview_path or null markdown_preview_path = window.markdown_preview_path or null
...@@ -28,6 +29,7 @@ class @DropzoneInput ...@@ -28,6 +29,7 @@ class @DropzoneInput
form_dropzone.find(".div-dropzone-hover").append iconPaperclip form_dropzone.find(".div-dropzone-hover").append iconPaperclip
form_dropzone.append divSpinner form_dropzone.append divSpinner
form_dropzone.find(".div-dropzone-spinner").append iconSpinner form_dropzone.find(".div-dropzone-spinner").append iconSpinner
form_dropzone.find(".div-dropzone-spinner").append uploadProgress
form_dropzone.find(".div-dropzone-spinner").css form_dropzone.find(".div-dropzone-spinner").css
"opacity": 0 "opacity": 0
"display": "none" "display": "none"
...@@ -112,13 +114,18 @@ class @DropzoneInput ...@@ -112,13 +114,18 @@ class @DropzoneInput
$(".div-dropzone-alert").append btnAlert + errorMessage $(".div-dropzone-alert").append btnAlert + errorMessage
return return
totaluploadprogress: (totalUploadProgress) ->
uploadProgress.text Math.round(totalUploadProgress) + "%"
return
sending: -> sending: ->
form_dropzone.find(".div-dropzone-spinner").css form_dropzone.find(".div-dropzone-spinner").css
"opacity": 0.7 "opacity": 0.7
"display": "inherit" "display": "inherit"
return return
complete: -> queuecomplete: ->
uploadProgress.text ""
$(".dz-preview").remove() $(".dz-preview").remove()
$(".markdown-area").trigger "input" $(".markdown-area").trigger "input"
$(".div-dropzone-spinner").css $(".div-dropzone-spinner").css
......
...@@ -19,7 +19,7 @@ class @MergeRequestWidget ...@@ -19,7 +19,7 @@ class @MergeRequestWidget
when 'merged' when 'merged'
location.reload() location.reload()
else else
setTimeout(merge_request_widget.mergeInProgress, 3000) setTimeout(merge_request_widget.mergeInProgress, 2000)
dataType: 'json' dataType: 'json'
getMergeStatus: -> getMergeStatus: ->
...@@ -36,7 +36,7 @@ class @MergeRequestWidget ...@@ -36,7 +36,7 @@ class @MergeRequestWidget
showCiState: (state) -> showCiState: (state) ->
$('.ci_widget').hide() $('.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 if state in allowed_states
$('.ci_widget.ci-' + state).show() $('.ci_widget.ci-' + state).show()
switch state switch state
...@@ -49,10 +49,8 @@ class @MergeRequestWidget ...@@ -49,10 +49,8 @@ class @MergeRequestWidget
@setMergeButtonClass('btn-danger') @setMergeButtonClass('btn-danger')
showCiCoverage: (coverage) -> showCiCoverage: (coverage) ->
cov_html = $('<span>') text = 'Coverage ' + coverage + '%'
cov_html.addClass('ci-coverage') $('.ci_widget:visible .ci-coverage').text(text)
cov_html.text('Coverage ' + coverage + '%')
$('.ci_widget:visible').append(cov_html)
setMergeButtonClass: (css_class) -> setMergeButtonClass: (css_class) ->
$('.accept_merge_request').removeClass("btn-create").addClass(css_class) $('.accept_merge_request').removeClass("btn-create").addClass(css_class)
class @Project class @Project
constructor: -> constructor: ->
# Git clone panel switcher # Git clone panel switcher
scope = $ '.git-clone-holder' cloneHolder = $('.git-clone-holder')
if scope.length > 0 if cloneHolder.length
$('a, button', scope).click -> $('a, button', cloneHolder).click ->
$('a, button', scope).removeClass 'active' $('a, button', cloneHolder).removeClass 'active'
$(@).addClass 'active' $(@).addClass 'active'
$('#project_clone', scope).val $(@).data 'clone' $('#project_clone', cloneHolder).val $(@).data 'clone'
$(".clone").text("").append $(@).data 'clone' $(".clone").text("").append $(@).data 'clone'
# Ref switcher # Ref switcher
...@@ -24,3 +24,8 @@ class @Project ...@@ -24,3 +24,8 @@ class @Project
$.cookie('hide_no_password_message', 'false', { path: path }) $.cookie('hide_no_password_message', 'false', { path: path })
$(@).parents('.no-password-message').remove() $(@).parents('.no-password-message').remove()
e.preventDefault() e.preventDefault()
$('.js-toggle-clone-holder').on 'click', (e) ->
cloneHolder.toggle()
cloneHolder.hide() unless $('.empty-project').length
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
font-family: $monospace_font; font-family: $monospace_font;
white-space: pre; white-space: pre;
word-wrap: normal; word-wrap: normal;
padding: 0; padding: 1px 2px;
} }
kbd { kbd {
......
...@@ -40,6 +40,15 @@ ...@@ -40,6 +40,15 @@
font-size: inherit; font-size: inherit;
} }
.div-dropzone-progress {
position: absolute;
top: 7px;
left: -40px;
width: 35px;
font-size: 13px;
text-align: right;
}
.dz-preview { .dz-preview {
display: none; display: none;
} }
......
...@@ -48,6 +48,10 @@ ...@@ -48,6 +48,10 @@
display: block; display: block;
} }
.project-home-desc {
font-size: 21px;
}
.project-repo-buttons, .project-repo-buttons,
.git-clone-holder { .git-clone-holder {
display: none; display: none;
......
...@@ -38,6 +38,10 @@ code { ...@@ -38,6 +38,10 @@ code {
} }
} }
a > code {
color: $link-color;
}
/** /**
* Wiki typography * Wiki typography
* *
......
/**
/** * MR -> show: Automerge widget
* MR -> show: Automerge widget
* *
*/ */
.mr-state-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 { form {
margin-bottom: 0; margin-bottom: 0;
.clearfix { .clearfix {
...@@ -20,22 +26,71 @@ ...@@ -20,22 +26,71 @@
display: inline-block; display: inline-block;
margin: 0; margin: 0;
margin-left: 20px; margin-left: 20px;
padding: 10px 0; padding: 5px;
line-height: 20px; line-height: 20px;
font-weight: bold;
.remove_source_checkbox { .remove_source_checkbox {
margin: 0; 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) { @media(min-width: $screen-sm-max) {
.merge-request .merge-request-tabs{ .merge-request .merge-request-tabs{
margin: 20px 0;
li { li {
a { a {
padding: 15px 40px; padding: 15px 40px;
...@@ -45,6 +100,11 @@ ...@@ -45,6 +100,11 @@
} }
} }
.merge-request .merge-request-tabs{
margin-top: 30px;
margin-bottom: 20px;
}
.mr_source_commit, .mr_source_commit,
.mr_target_commit { .mr_target_commit {
.commit { .commit {
...@@ -58,23 +118,10 @@ ...@@ -58,23 +118,10 @@
} }
.label-branch { .label-branch {
@include border-radius(4px); color: #222;
padding: 3px 4px;
border: none;
background: $hover;
color: #333;
font-family: $monospace_font; font-family: $monospace_font;
font-weight: normal; font-weight: bold;
overflow: hidden; overflow: hidden;
.label-project {
@include border-radius-left(4px);
padding: 3px 4px;
background: #279;
position: relative;
left: -4px;
letter-spacing: -1px;
}
} }
.mr-list { .mr-list {
...@@ -121,59 +168,6 @@ ...@@ -121,59 +168,6 @@
display: none; 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 { .merge-request-show-labels {
a { a {
margin-right: 5px; margin-right: 5px;
...@@ -188,3 +182,7 @@ ...@@ -188,3 +182,7 @@
.merge-request-form .select2-container { .merge-request-form .select2-container {
width: 250px !important; width: 250px !important;
} }
#modal_merge_info .modal-dialog {
width: 600px;
}
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
.project-home-panel { .project-home-panel {
text-align: center; text-align: center;
margin-bottom: 20px;
.project-identicon-holder { .project-identicon-holder {
margin-bottom: 15px; margin-bottom: 15px;
...@@ -31,7 +30,13 @@ ...@@ -31,7 +30,13 @@
} }
} }
.lead { .project-home-desc {
h1 {
margin: 0;
margin-bottom: 10px;
font-size: 26px;
}
p { p {
display: inline; display: inline;
} }
...@@ -39,7 +44,7 @@ ...@@ -39,7 +44,7 @@
.git-clone-holder { .git-clone-holder {
max-width: 600px; max-width: 600px;
margin: 0 auto; margin: 20px auto;
} }
.visibility-level-label { .visibility-level-label {
...@@ -297,6 +302,15 @@ table.table.protected-branches-list tr.no-border { ...@@ -297,6 +302,15 @@ table.table.protected-branches-list tr.no-border {
ul.nav-pills { display:inline-block; } ul.nav-pills { display:inline-block; }
li { display:inline; } li { display:inline; }
a { float:left; } a { float:left; }
li.missing a {
color: #bbb;
border: 1px dashed #ccc;
&:hover {
background-color: #FAFAFA;
}
}
} }
pre.light-well { 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 ...@@ -55,6 +55,14 @@ class Admin::UsersController < Admin::ApplicationController
end end
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 def disable_two_factor
user.disable_two_factor! user.disable_two_factor!
redirect_to admin_user_path(user), redirect_to admin_user_path(user),
......
...@@ -34,6 +34,8 @@ class AutocompleteController < ApplicationController ...@@ -34,6 +34,8 @@ class AutocompleteController < ApplicationController
@users = @users.search(params[:search]) if params[:search].present? @users = @users.search(params[:search]) if params[:search].present?
@users = @users.active @users = @users.active
@users = @users.page(params[:page]).per(PER_PAGE) @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] render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
end end
......
...@@ -22,6 +22,7 @@ class Import::BitbucketController < Import::BaseController ...@@ -22,6 +22,7 @@ class Import::BitbucketController < Import::BaseController
def status def status
@repos = client.projects @repos = client.projects
@incompatible_repos = client.incompatible_projects
@already_added_projects = current_user.created_projects.where(import_type: "bitbucket") @already_added_projects = current_user.created_projects.where(import_type: "bitbucket")
already_added_projects_names = @already_added_projects.pluck(:import_source) already_added_projects_names = @already_added_projects.pluck(:import_source)
......
...@@ -17,7 +17,9 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -17,7 +17,9 @@ class Projects::BranchesController < Projects::ApplicationController
def create def create
branch_name = sanitize(strip_tags(params[:branch_name])) branch_name = sanitize(strip_tags(params[:branch_name]))
branch_name = Addressable::URI.unescape(branch_name)
ref = sanitize(strip_tags(params[:ref])) ref = sanitize(strip_tags(params[:ref]))
ref = Addressable::URI.unescape(ref)
result = CreateBranchService.new(project, current_user). result = CreateBranchService.new(project, current_user).
execute(branch_name, ref) execute(branch_name, ref)
...@@ -32,9 +34,8 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -32,9 +34,8 @@ class Projects::BranchesController < Projects::ApplicationController
end end
def destroy def destroy
status = DeleteBranchService.new(project, current_user).execute(params[:id]) @branch_name = Addressable::URI.unescape(params[:id])
@branch_name = params[:id] status = DeleteBranchService.new(project, current_user).execute(@branch_name)
respond_to do |format| respond_to do |format|
format.html do format.html do
redirect_to namespace_project_branches_path(@project.namespace, redirect_to namespace_project_branches_path(@project.namespace,
......
...@@ -13,13 +13,8 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -13,13 +13,8 @@ class Projects::CompareController < Projects::ApplicationController
base_ref = Addressable::URI.unescape(params[:from]) base_ref = Addressable::URI.unescape(params[:from])
@ref = head_ref = Addressable::URI.unescape(params[:to]) @ref = head_ref = Addressable::URI.unescape(params[:to])
compare_result = CompareService.new.execute( compare_result = CompareService.new.
current_user, execute(@project, head_ref, @project, base_ref)
@project,
head_ref,
@project,
base_ref
)
@commits = compare_result.commits @commits = compare_result.commits
@diffs = compare_result.diffs @diffs = compare_result.diffs
......
require 'gitlab/satellite/satellite'
class Projects::MergeRequestsController < Projects::ApplicationController class Projects::MergeRequestsController < Projects::ApplicationController
before_action :module_enabled before_action :module_enabled
before_action :merge_request, only: [ 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 :ci_status, :toggle_subscription, :approve
] ]
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits] before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits]
...@@ -141,7 +139,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -141,7 +139,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
end end
def automerge_check def merge_check
if @merge_request.unchecked? if @merge_request.unchecked?
@merge_request.check_if_can_be_merged @merge_request.check_if_can_be_merged
end end
...@@ -151,12 +149,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -151,12 +149,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render partial: "projects/merge_requests/widget/show.html.haml", layout: false render partial: "projects/merge_requests/widget/show.html.haml", layout: false
end end
def automerge def merge
return access_denied! unless @merge_request.can_be_merged_by?(current_user) return access_denied! unless @merge_request.can_be_merged_by?(current_user)
return render_404 unless @merge_request.approved? return render_404 unless @merge_request.approved?
if @merge_request.automergeable? if @merge_request.mergeable?
AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params) MergeWorker.perform_async(@merge_request.id, current_user.id, params)
@status = true @status = true
else else
@status = false @status = false
......
...@@ -30,13 +30,10 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -30,13 +30,10 @@ class Projects::NotesController < Projects::ApplicationController
end end
def update def update
if note.editable? @note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
note.update_attributes(note_params)
note.reset_events_cache
end
respond_to do |format| respond_to do |format|
format.json { render_note_json(note) } format.json { render_note_json(@note) }
format.html { redirect_to :back } format.html { redirect_to :back }
end end
end end
......
...@@ -43,21 +43,6 @@ module IssuesHelper ...@@ -43,21 +43,6 @@ module IssuesHelper
end end
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 def bulk_update_milestone_options
options_for_select([['None (backlog)', -1]]) + options_for_select([['None (backlog)', -1]]) +
options_from_collection_for_select(project_active_milestones, 'id', options_from_collection_for_select(project_active_milestones, 'id',
......
...@@ -106,4 +106,14 @@ module MergeRequestsHelper ...@@ -106,4 +106,14 @@ module MergeRequestsHelper
str str
end 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 end
...@@ -23,21 +23,6 @@ module NotesHelper ...@@ -23,21 +23,6 @@ module NotesHelper
end end
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) def noteable_json(noteable)
{ {
id: noteable.id, id: noteable.id,
......
...@@ -21,7 +21,7 @@ module ProjectsHelper ...@@ -21,7 +21,7 @@ module ProjectsHelper
end end
def link_to_member(project, author, opts = {}) 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) opts = default_opts.merge(opts)
return "(deleted)" unless author return "(deleted)" unless author
...@@ -32,7 +32,7 @@ module ProjectsHelper ...@@ -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] 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 # 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 author_html = author_html.html_safe
...@@ -184,7 +184,43 @@ module ProjectsHelper ...@@ -184,7 +184,43 @@ module ProjectsHelper
end end
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 if project && contribution_guide = project.repository.contribution_guide
namespace_project_blob_path( namespace_project_blob_path(
project.namespace, project.namespace,
...@@ -195,7 +231,7 @@ module ProjectsHelper ...@@ -195,7 +231,7 @@ module ProjectsHelper
end end
end end
def changelog_url(project) def changelog_path(project)
if project && changelog = project.repository.changelog if project && changelog = project.repository.changelog
namespace_project_blob_path( namespace_project_blob_path(
project.namespace, project.namespace,
...@@ -206,7 +242,7 @@ module ProjectsHelper ...@@ -206,7 +242,7 @@ module ProjectsHelper
end end
end end
def license_url(project) def license_path(project)
if project && license = project.repository.license if project && license = project.repository.license
namespace_project_blob_path( namespace_project_blob_path(
project.namespace, project.namespace,
...@@ -217,7 +253,7 @@ module ProjectsHelper ...@@ -217,7 +253,7 @@ module ProjectsHelper
end end
end end
def version_url(project) def version_path(project)
if project && version = project.repository.version if project && version = project.repository.version
namespace_project_blob_path( namespace_project_blob_path(
project.namespace, 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 @@ ...@@ -15,13 +15,14 @@
# twitter_sharing_enabled :boolean default(TRUE) # twitter_sharing_enabled :boolean default(TRUE)
# help_text :text # help_text :text
# restricted_visibility_levels :text # restricted_visibility_levels :text
# version_check_enabled :boolean default(TRUE)
# max_attachment_size :integer default(10), not null # max_attachment_size :integer default(10), not null
# session_expire_delay :integer default(10080), not null
# default_project_visibility :integer # default_project_visibility :integer
# default_snippet_visibility :integer # default_snippet_visibility :integer
# restricted_signup_domains :text # restricted_signup_domains :text
# user_oauth_applications :bool default(TRUE) # user_oauth_applications :boolean default(TRUE)
# after_sign_out_path :string(255) # after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
# #
class ApplicationSetting < ActiveRecord::Base 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 class AuditEvent < ActiveRecord::Base
serialize :details, Hash serialize :details, Hash
......
...@@ -12,6 +12,7 @@ module Issuable ...@@ -12,6 +12,7 @@ module Issuable
included do included do
belongs_to :author, class_name: "User" belongs_to :author, class_name: "User"
belongs_to :assignee, class_name: "User" belongs_to :assignee, class_name: "User"
belongs_to :updated_by, class_name: "User"
belongs_to :milestone belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy has_many :notes, as: :noteable, dependent: :destroy
has_many :label_links, as: :target, dependent: :destroy has_many :label_links, as: :target, dependent: :destroy
......
...@@ -84,6 +84,22 @@ class Group < Namespace ...@@ -84,6 +84,22 @@ class Group < Namespace
self.add_user(user, Gitlab::Access::OWNER, current_user, skip_notification: skip_notification) self.add_user(user, Gitlab::Access::OWNER, current_user, skip_notification: skip_notification)
end 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) def has_owner?(user)
owners.include?(user) owners.include?(user)
end end
......
...@@ -41,6 +41,11 @@ class Key < ActiveRecord::Base ...@@ -41,6 +41,11 @@ class Key < ActiveRecord::Base
self.key = key.strip unless key.blank? self.key = key.strip unless key.blank?
end end
def publishable_key
#Removes anything beyond the keytype and key itself
self.key.split[0..1].join(' ')
end
# projects that has this key # projects that has this key
def projects def projects
user.authorized_projects user.authorized_projects
......
...@@ -43,11 +43,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -43,11 +43,6 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil 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 # When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests # It allows us to close or modify broken merge requests
attr_accessor :allow_broken attr_accessor :allow_broken
...@@ -62,7 +57,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -62,7 +57,7 @@ class MergeRequest < ActiveRecord::Base
transition [:reopened, :opened] => :closed transition [:reopened, :opened] => :closed
end end
event :merge do event :mark_as_merged do
transition [:reopened, :opened, :locked] => :merged transition [:reopened, :opened, :locked] => :merged
end end
...@@ -211,11 +206,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -211,11 +206,7 @@ class MergeRequest < ActiveRecord::Base
def check_if_can_be_merged def check_if_can_be_merged
can_be_merged = can_be_merged =
if for_fork? project.repository.can_be_merged?(source_sha, target_branch)
Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
else
project.repository.can_be_merged?(source_branch, target_branch)
end
if can_be_merged if can_be_merged
mark_as_mergeable mark_as_mergeable
...@@ -232,18 +223,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -232,18 +223,6 @@ class MergeRequest < ActiveRecord::Base
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
end 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? def open?
opened? || reopened? opened? || reopened?
end end
...@@ -252,11 +231,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -252,11 +231,11 @@ class MergeRequest < ActiveRecord::Base
title =~ /\A\[?WIP\]?:? /i title =~ /\A\[?WIP\]?:? /i
end end
def automergeable? def mergeable?
open? && !work_in_progress? && can_be_merged? open? && !work_in_progress? && can_be_merged?
end end
def automerge_status def gitlab_merge_status
if work_in_progress? if work_in_progress?
"work_in_progress" "work_in_progress"
else else
...@@ -283,14 +262,14 @@ class MergeRequest < ActiveRecord::Base ...@@ -283,14 +262,14 @@ class MergeRequest < ActiveRecord::Base
# #
# see "git diff" # see "git diff"
def to_diff(current_user) 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 end
# Returns the commit as a series of email patches. # Returns the commit as a series of email patches.
# #
# see "git format-patch" # see "git format-patch"
def to_patch(current_user) def to_patch(current_user)
Gitlab::Satellite::MergeAction.new(current_user, self).format_patch target_project.repository.format_patch(target_branch, source_sha)
end end
def hook_attrs def hook_attrs
...@@ -493,4 +472,30 @@ class MergeRequest < ActiveRecord::Base ...@@ -493,4 +472,30 @@ class MergeRequest < ActiveRecord::Base
approvers.find_or_initialize_by(user_id: user_id, target_id: id) approvers.find_or_initialize_by(user_id: user_id, target_id: id)
end end
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 end
...@@ -16,9 +16,8 @@ require Rails.root.join("app/models/commit") ...@@ -16,9 +16,8 @@ require Rails.root.join("app/models/commit")
class MergeRequestDiff < ActiveRecord::Base class MergeRequestDiff < ActiveRecord::Base
include Sortable include Sortable
# Prevent store of diff # Prevent store of diff if commits amount more then 500
# if commits amount more then 200 COMMITS_SAFE_SIZE = 500
COMMITS_SAFE_SIZE = 200
attr_reader :commits, :diffs attr_reader :commits, :diffs
...@@ -124,12 +123,12 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -124,12 +123,12 @@ class MergeRequestDiff < ActiveRecord::Base
if new_diffs.any? if new_diffs.any?
if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES
self.state = :overflow_diff_files_limit self.state = :overflow_diff_files_limit
new_diffs = [] new_diffs = new_diffs.first[Commit::DIFF_HARD_LIMIT_LINES]
end end
if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES
self.state = :overflow_diff_lines_limit self.state = :overflow_diff_lines_limit
new_diffs = [] new_diffs = new_diffs.first[Commit::DIFF_HARD_LIMIT_LINES]
end end
end end
...@@ -160,12 +159,21 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -160,12 +159,21 @@ class MergeRequestDiff < ActiveRecord::Base
private private
def compare_result def compare_result
@compare_result ||= CompareService.new.execute( @compare_result ||=
merge_request.author, begin
merge_request.source_project, # Update ref for merge request
merge_request.source_branch, merge_request.fetch_ref
merge_request.target_project,
merge_request.target_branch, # 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
end end
...@@ -114,13 +114,15 @@ class Namespace < ActiveRecord::Base ...@@ -114,13 +114,15 @@ class Namespace < ActiveRecord::Base
end end
def move_dir 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 gitlab_shell.mv_namespace(path_was, path)
# If repositories moved successfully we need to remove old satellites # If repositories moved successfully we need to
# and send update instructions to users. # send update instructions to users.
# However we cannot allow rollback since we moved namespace dir # However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions # So we basically we mute exceptions in next actions
begin begin
gitlab_shell.rm_satellites(path_was)
send_update_instructions send_update_instructions
rescue rescue
# Returning false does not rollback after_* transaction but gives # Returning false does not rollback after_* transaction but gives
......
...@@ -31,8 +31,9 @@ class Note < ActiveRecord::Base ...@@ -31,8 +31,9 @@ class Note < ActiveRecord::Base
participant :author, :mentioned_users participant :author, :mentioned_users
belongs_to :project belongs_to :project
belongs_to :noteable, polymorphic: true, touch: true belongs_to :noteable, polymorphic: true
belongs_to :author, class_name: "User" belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
delegate :name, to: :project, prefix: true delegate :name, to: :project, prefix: true
delegate :name, :email, to: :author, prefix: true delegate :name, :email, to: :author, prefix: true
......
...@@ -21,12 +21,13 @@ ...@@ -21,12 +21,13 @@
# import_url :string(255) # import_url :string(255)
# visibility_level :integer default(0), not null # visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null # archived :boolean default(FALSE), not null
# avatar :string(255)
# import_status :string(255) # import_status :string(255)
# repository_size :float default(0.0) # repository_size :float default(0.0)
# star_count :integer default(0), not null # star_count :integer default(0), not null
# import_type :string(255) # import_type :string(255)
# import_source :string(255) # import_source :string(255)
# avatar :string(255) # commit_count :integer default(0)
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
...@@ -539,14 +540,6 @@ class Project < ActiveRecord::Base ...@@ -539,14 +540,6 @@ class Project < ActiveRecord::Base
!repository.exists? || repository.empty? !repository.exists? || repository.empty?
end end
def ensure_satellite_exists
self.satellite.create unless self.satellite.exists?
end
def satellite
@satellite ||= Gitlab::Satellite::Satellite.new(self)
end
def repo def repo
repository.raw repository.raw
end end
...@@ -616,14 +609,11 @@ class Project < ActiveRecord::Base ...@@ -616,14 +609,11 @@ class Project < ActiveRecord::Base
new_path_with_namespace = File.join(namespace_dir, path) new_path_with_namespace = File.join(namespace_dir, path)
if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace) if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace)
# If repository moved successfully we need to remove old satellite # If repository moved successfully we need to send update instructions to users.
# and send update instructions to users.
# However we cannot allow rollback since we moved repository # However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions # So we basically we mute exceptions in next actions
begin begin
gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") 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 send_move_instructions
reset_events_cache reset_events_cache
rescue rescue
...@@ -729,7 +719,6 @@ class Project < ActiveRecord::Base ...@@ -729,7 +719,6 @@ class Project < ActiveRecord::Base
def create_repository def create_repository
if forked? if forked?
if gitlab_shell.fork_repository(forked_from_project.path_with_namespace, self.namespace.path) if gitlab_shell.fork_repository(forked_from_project.path_with_namespace, self.namespace.path)
ensure_satellite_exists
true true
else else
errors.add(:base, 'Failed to fork repository via gitlab-shell') errors.add(:base, 'Failed to fork repository via gitlab-shell')
......
...@@ -41,7 +41,7 @@ class CiService < Service ...@@ -41,7 +41,7 @@ class CiService < Service
# Return string with build status or :error symbol # Return string with build status or :error symbol
# #
# Allowed states: 'success', 'failed', 'running', 'pending' # Allowed states: 'success', 'failed', 'running', 'pending', 'skipped'
# #
# #
# Ex. # Ex.
......
...@@ -74,6 +74,8 @@ class GitlabCiService < CiService ...@@ -74,6 +74,8 @@ class GitlabCiService < CiService
else else
:error :error
end end
rescue Errno::ECONNREFUSED
:error
end end
def fork_registration(new_project, private_token) def fork_registration(new_project, private_token)
...@@ -103,6 +105,8 @@ class GitlabCiService < CiService ...@@ -103,6 +105,8 @@ class GitlabCiService < CiService
if response.code == 200 and response["coverage"] if response.code == 200 and response["coverage"]
response["coverage"] response["coverage"]
end end
rescue Errno::ECONNREFUSED
nil
end end
def build_page(sha, ref) def build_page(sha, ref)
......
...@@ -411,15 +411,36 @@ class Repository ...@@ -411,15 +411,36 @@ class Repository
} }
end end
def can_be_merged?(source_branch, target_branch) def can_be_merged?(source_sha, target_branch)
our_commit = rugged.branches[target_branch].target 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 if our_commit && their_commit
!rugged.merge_commits(our_commit, their_commit).conflicts? !rugged.merge_commits(our_commit, their_commit).conflicts?
else
false
end end
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) def search_files(query, ref)
offset = 2 offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref}) args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
...@@ -453,6 +474,11 @@ class Repository ...@@ -453,6 +474,11 @@ class Repository
) )
end 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 private
def cache 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 class SecurityEvent < AuditEvent
end end
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
# otp_backup_codes :text # otp_backup_codes :text
# public_email :string(255) default(""), not null # public_email :string(255) default(""), not null
# dashboard :integer default(0) # dashboard :integer default(0)
# project_view :integer default(0)
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
...@@ -647,7 +648,7 @@ class User < ActiveRecord::Base ...@@ -647,7 +648,7 @@ class User < ActiveRecord::Base
end end
def all_ssh_keys def all_ssh_keys
keys.map(&:key) keys.map(&:publishable_key)
end end
def temp_oauth_email? def temp_oauth_email?
......
...@@ -31,6 +31,10 @@ class BaseService ...@@ -31,6 +31,10 @@ class BaseService
SystemHooksService.new SystemHooksService.new
end end
def repository
project.repository
end
# Add an error to the specified model for restricted visibility levels # Add an error to the specified model for restricted visibility levels
def deny_visibility_level(model, denied_visibility_level = nil) def deny_visibility_level(model, denied_visibility_level = nil)
denied_visibility_level ||= model.visibility_level denied_visibility_level ||= model.visibility_level
......
require 'securerandom'
# Compare 2 branches for one repo or between repositories # Compare 2 branches for one repo or between repositories
# and return Gitlab::CompareResult object that responds to commits and diffs # and return Gitlab::CompareResult object that responds to commits and diffs
class CompareService class CompareService
def execute(current_user, source_project, source_branch, target_project, target_branch) def execute(source_project, source_branch, target_project, target_branch)
# Try to compare branches to get commits list and diffs source_sha = source_project.commit(source_branch).sha
#
# Note: Use satellite only when need to compare between two repos # If compare with other project we need to fetch ref first
# because satellites are slower than operations on bare repo unless target_project == source_project
if target_project == source_project random_string = SecureRandom.hex
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new( target_project.repository.fetch_ref(
target_project.repository.raw_repository, source_project.repository.path_to_repo,
target_branch, "refs/heads/#{source_branch}",
source_branch, "refs/tmp/#{random_string}/head"
)
) )
else
Gitlab::Satellite::CompareAction.new(
current_user,
target_project,
target_branch,
source_project,
source_branch
).result
end end
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
source_sha,
)
)
end end
end end
...@@ -42,10 +42,7 @@ module Files ...@@ -42,10 +42,7 @@ module Files
end end
def after_commit(sha, branch) def after_commit(sha, branch)
commit = repository.commit(sha) PostCommitService.new(project, current_user).execute(sha, branch)
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 end
def current_branch def current_branch
......
...@@ -10,16 +10,14 @@ class GitPushService ...@@ -10,16 +10,14 @@ class GitPushService
# #
# Next, this method: # Next, this method:
# 1. Creates the push event # 1. Creates the push event
# 2. Ensures that the project satellite exists # 2. Updates merge requests
# 3. Updates merge requests # 3. Recognizes cross-references from commit messages
# 4. Recognizes cross-references from commit messages # 4. Executes the project's web hooks
# 5. Executes the project's web hooks # 5. Executes the project's services
# 6. Executes the project's services
# #
def execute(project, user, oldrev, newrev, ref) def execute(project, user, oldrev, newrev, ref)
@project, @user = project, user @project, @user = project, user
project.ensure_satellite_exists
project.repository.expire_cache project.repository.expire_cache
if push_remove_branch?(ref, newrev) if push_remove_branch?(ref, newrev)
......
...@@ -14,7 +14,7 @@ module Issues ...@@ -14,7 +14,7 @@ module Issues
filter_params filter_params
old_labels = issue.labels.to_a 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 issue.reset_events_cache
if issue.labels != old_labels 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 ...@@ -12,12 +12,16 @@ module MergeRequests
merge_request.target_project ||= (project.forked_from_project || project) merge_request.target_project ||= (project.forked_from_project || project)
merge_request.target_branch ||= merge_request.target_project.default_branch merge_request.target_branch ||= merge_request.target_project.default_branch
unless merge_request.target_branch && merge_request.source_branch if merge_request.target_branch.blank? || merge_request.source_branch.blank?
return build_failed(merge_request, nil) message =
if params[:source_branch] || params[:target_branch]
"You must select source and target branch"
end
return build_failed(merge_request, message)
end end
compare_result = CompareService.new.execute( compare_result = CompareService.new.execute(
current_user,
merge_request.source_project, merge_request.source_project,
merge_request.source_branch, merge_request.source_branch,
merge_request.target_project, merge_request.target_project,
...@@ -40,7 +44,6 @@ module MergeRequests ...@@ -40,7 +44,6 @@ module MergeRequests
merge_request.compare_diffs = diffs merge_request.compare_diffs = diffs
elsif diffs == false elsif diffs == false
# satellite timeout return false
merge_request.can_be_created = false merge_request.can_be_created = false
merge_request.compare_failed = true merge_request.compare_failed = true
end end
...@@ -64,9 +67,6 @@ module MergeRequests ...@@ -64,9 +67,6 @@ module MergeRequests
end end
merge_request merge_request
rescue Gitlab::Satellite::BranchesWithoutParent
return build_failed(merge_request, "Selected branches have no common commit so they cannot be merged.")
end end
def build_failed(merge_request, message) def build_failed(merge_request, message)
......
module MergeRequests module MergeRequests
# MergeService class # MergeService class
# #
# Mark existing merge request as merged # Do git merge and in case of success
# and execute all hooks and notifications # mark merge request as merged and execute all hooks and notifications
# Called when you do merge via command line and push code # Executed when you do merge via GitLab UI
# to target branch #
class MergeService < BaseMergeService class MergeService < MergeRequests::BaseService
attr_reader :merge_request, :commit_message
def execute(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) unless @merge_request.mergeable?
create_note(merge_request) return error('Merge request is not mergeable')
notification_service.merge_mr(merge_request, current_user) end
execute_hooks(merge_request, 'merge')
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 def after_merge
rescue MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
false
end end
end 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 ...@@ -34,9 +34,9 @@ module MergeRequests
merge_requests.uniq.select(&:source_project).each do |merge_request| merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::MergeService. MergeRequests::PostMergeService.
new(merge_request.target_project, @current_user). new(merge_request.target_project, @current_user).
execute(merge_request, nil) execute(merge_request)
end end
end end
......
...@@ -24,7 +24,7 @@ module MergeRequests ...@@ -24,7 +24,7 @@ module MergeRequests
filter_params filter_params
old_labels = merge_request.labels.to_a 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 merge_request.reset_events_cache
if merge_request.labels != old_labels if merge_request.labels != old_labels
......
module Notes module Notes
class UpdateService < BaseService class UpdateService < BaseService
def execute def execute(note)
note = project.notes.find(params[:note_id]) return note unless note.editable?
note.note = params[:note]
if note.save
notification_service.new_note(note)
# Skip system notes, like status changes and cross-references. note.update_attributes(params.merge(updated_by: current_user))
unless note.system
event_service.leave_note(note, note.author)
# Create a cross-reference note if this Note contains GFM that note.reset_events_cache
# names an issue, merge request, or commit.
note.references.each do |mentioned|
SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end
end
end
note note
end end
......
...@@ -70,12 +70,6 @@ class NotificationService ...@@ -70,12 +70,6 @@ class NotificationService
reassign_resource_email(merge_request, merge_request.target_project, current_user, 'reassigned_merge_request_email') reassign_resource_email(merge_request, merge_request.target_project, current_user, 'reassigned_merge_request_email')
end 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) def close_mr(merge_request, current_user)
close_resource_email(merge_request, merge_request.target_project, current_user, 'closed_merge_request_email') close_resource_email(merge_request, merge_request.target_project, current_user, 'closed_merge_request_email')
end end
...@@ -84,26 +78,8 @@ class NotificationService ...@@ -84,26 +78,8 @@ class NotificationService
reopen_resource_email(issue, issue.project, current_user, 'issue_status_changed_email', 'reopened') reopen_resource_email(issue, issue.project, current_user, 'issue_status_changed_email', 'reopened')
end 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) def merge_mr(merge_request, current_user)
recipients = [merge_request.author, merge_request.assignee] close_resource_email(merge_request, merge_request.target_project, current_user, 'merged_merge_request_email')
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
end end
def reopen_mr(merge_request, current_user) def reopen_mr(merge_request, current_user)
...@@ -364,8 +340,7 @@ class NotificationService ...@@ -364,8 +340,7 @@ class NotificationService
end end
def new_resource_email(target, project, method) def new_resource_email(target, project, method)
recipients = build_recipients(target, project) recipients = build_recipients(target, project, target.author)
recipients.delete(target.author)
recipients.each do |recipient| recipients.each do |recipient|
mailer.send(method, recipient.id, target.id) mailer.send(method, recipient.id, target.id)
...@@ -373,8 +348,7 @@ class NotificationService ...@@ -373,8 +348,7 @@ class NotificationService
end end
def close_resource_email(target, project, current_user, method) def close_resource_email(target, project, current_user, method)
recipients = build_recipients(target, project) recipients = build_recipients(target, project, current_user)
recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, current_user.id) mailer.send(method, recipient.id, target.id, current_user.id)
...@@ -383,8 +357,7 @@ class NotificationService ...@@ -383,8 +357,7 @@ class NotificationService
def reassign_resource_email(target, project, current_user, method) def reassign_resource_email(target, project, current_user, method)
assignee_id_was = previous_record(target, "assignee_id") assignee_id_was = previous_record(target, "assignee_id")
recipients = build_recipients(target, project) recipients = build_recipients(target, project, current_user)
recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, assignee_id_was, current_user.id) mailer.send(method, recipient.id, target.id, assignee_id_was, current_user.id)
...@@ -392,21 +365,15 @@ class NotificationService ...@@ -392,21 +365,15 @@ class NotificationService
end end
def reopen_resource_email(target, project, current_user, method, status) def reopen_resource_email(target, project, current_user, method, status)
recipients = build_recipients(target, project) recipients = build_recipients(target, project, current_user)
recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, status, current_user.id) mailer.send(method, recipient.id, target.id, status, current_user.id)
end end
end end
def build_recipients(target, project) def build_recipients(target, project, current_user)
recipients = recipients = target.participants(current_user)
if target.respond_to?(:participants)
target.participants
else
[target.author, target.assignee]
end
recipients = add_project_watchers(recipients, project) recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project) recipients = reject_mention_users(recipients, project)
...@@ -415,6 +382,8 @@ class NotificationService ...@@ -415,6 +382,8 @@ class NotificationService
recipients = add_subscribed_users(recipients, target) recipients = add_subscribed_users(recipients, target)
recipients = reject_unsubscribed_users(recipients, target) recipients = reject_unsubscribed_users(recipients, target)
recipients.delete(current_user)
recipients recipients
end 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 ...@@ -27,7 +27,6 @@ module Projects
end end
end end
project.satellite.destroy
log_info("Project \"#{project.name}\" was removed") log_info("Project \"#{project.name}\" was removed")
system_hook_service.execute_hooks_for(project, :destroy) system_hook_service.execute_hooks_for(project, :destroy)
true true
......
...@@ -33,9 +33,6 @@ module Projects ...@@ -33,9 +33,6 @@ module Projects
raise TransferError.new("Project with same path in target namespace already exists") raise TransferError.new("Project with same path in target namespace already exists")
end end
# Remove old satellite
project.satellite.destroy
# Apply new namespace id # Apply new namespace id
project.namespace = new_namespace project.namespace = new_namespace
project.save! project.save!
...@@ -51,9 +48,6 @@ module Projects ...@@ -51,9 +48,6 @@ module Projects
# Move wiki repo also if present # Move wiki repo also if present
gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") 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 # clear project cached events
project.reset_events_cache 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 @@ ...@@ -105,6 +105,16 @@
.col-md-6 .col-md-6
- unless @user == current_user - 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? - if @user.blocked?
.panel.panel-info .panel.panel-info
.panel-heading .panel-heading
......
...@@ -3,13 +3,11 @@ ...@@ -3,13 +3,11 @@
.event-item-timestamp .event-item-timestamp
#{time_ago_with_tooltip(event.created_at)} #{time_ago_with_tooltip(event.created_at)}
- if event.created_project? = cache [event, "v1"] do
= 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
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:'' = 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 = render "events/event/push", event: event
- elsif event.commented? - elsif event.commented?
= render "events/event/note", event: event = render "events/event/note", event: event
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
- else - else
= event.project_name = event.project_name
- if current_user == event.author && !event.project.private? && twitter_sharing_enabled? - if !event.project.private? && twitter_sharing_enabled?
.event-body .event-body{"data-user-is" => event.author_id}
.event-note .event-note
.md .md
%p %p
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
- few_commits.each do |commit| - few_commits.each do |commit|
= render "events/commit", commit: commit, project: project = 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 - if event.commits_count > 1
%li.commits-stat %li.commits-stat
- if event.commits_count > 2 - if event.commits_count > 2
...@@ -34,10 +34,11 @@ ...@@ -34,10 +34,11 @@
Compare #{from_label}...#{truncate_sha(event.commit_to)} Compare #{from_label}...#{truncate_sha(event.commit_to)}
- if create_mr - if create_mr
or %span{"data-user-is" => event.author_id, "data-display" => "inline"}
= link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do or
create a merge request = link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
create a merge request
- elsif create_mr - 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 = link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
Create Merge Request Create Merge Request
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
.project-info .project-info
- if project.description.present? - if project.description.present?
%p.project-description.str-truncated .project-description.str-truncated
= project.description = markdown(project.description, pipeline: :description)
.repo-info .repo-info
- unless project.empty_repo? - unless project.empty_repo?
......
...@@ -3,11 +3,16 @@ ...@@ -3,11 +3,16 @@
%i.fa.fa-bitbucket %i.fa.fa-bitbucket
Import projects from Bitbucket Import projects from Bitbucket
%p.light - if @repos.any?
Select projects you want to import. %p.light
%hr Select projects you want to import.
%p %hr
= button_tag 'Import all projects', class: "btn btn-success js-import-all" %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 %table.table.import-jobs
%thead %thead
...@@ -41,6 +46,24 @@ ...@@ -41,6 +46,24 @@
= "#{repo["owner"]}/#{repo["slug"]}" = "#{repo["owner"]}/#{repo["slug"]}"
%td.import-actions.job-status %td.import-actions.job-status
= button_tag "Import", class: "btn js-add-to-import" = 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 :coffeescript
new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}") new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}")
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
= favicon_link_tag 'touch-icon-ipad-retina.png', rel: 'apple-touch-icon', sizes: '152x152' = favicon_link_tag 'touch-icon-ipad-retina.png', rel: 'apple-touch-icon', sizes: '152x152'
-# Windows 8 pinned site tile -# 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'} %meta{name: 'msapplication-TileColor', content: '#30353E'}
= yield :meta_tags = yield :meta_tags
...@@ -35,3 +35,5 @@ ...@@ -35,3 +35,5 @@
= render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id') = 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/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id')
= render 'layouts/bootlint' if Rails.env.development? = 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 @@ ...@@ -67,6 +67,13 @@
%span %span
Service Templates 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 = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings', data: {placement: 'right'} do = link_to admin_application_settings_path, title: 'Settings', data: {placement: 'right'} do
= icon('cogs fw') = icon('cogs fw')
......
...@@ -82,12 +82,12 @@ ...@@ -82,12 +82,12 @@
You can change your avatar here You can change your avatar here
- if Gitlab.config.gravatar.enabled - if Gitlab.config.gravatar.enabled
%br %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 - else
You can upload an avatar here You can upload an avatar here
- if Gitlab.config.gravatar.enabled - if Gitlab.config.gravatar.enabled
%br %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 %hr
%a.choose-btn.btn.btn-sm.js-choose-user-avatar-button %a.choose-btn.btn.btn-sm.js-choose-user-avatar-button
%i.fa.fa-paperclip %i.fa.fa-paperclip
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
.project-identicon-holder .project-identicon-holder
= project_icon(@project, alt: '', class: 'project-avatar avatar s90') = project_icon(@project, alt: '', class: 'project-avatar avatar s90')
.project-home-desc.lead .project-home-desc.lead
%h1= @project.name
- if @project.description.present? - if @project.description.present?
= markdown(@project.description, pipeline: :description) = markdown(@project.description, pipeline: :description)
...@@ -19,9 +20,15 @@ ...@@ -19,9 +20,15 @@
Forked from Forked from
= forked_from_project.namespace.try(:name) = 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 - 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 = 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' = render 'projects/buttons/dropdown'
......
- if current_user - if current_user
%span.dropdown %span.dropdown
%a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
%i.fa.fa-plus = icon('plus')
%ul.dropdown-menu %ul.dropdown-menu
- if @project.issues_enabled && can?(current_user, :create_issue, @project) - if can?(current_user, :create_issue, @project)
%li %li
= link_to url_for_new_issue, title: "New Issue" do = link_to url_for_new_issue do
= icon('exclamation-circle fw')
New issue New issue
- if @project.merge_requests_enabled && can?(current_user, :create_merge_request, @project) - if can?(current_user, :create_merge_request, @project)
%li %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 New merge request
- if @project.snippets_enabled && can?(current_user, :create_snippet, @project) - if can?(current_user, :create_snippet, @project)
%li %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 New snippet
- if can?(current_user, :admin_project_member, @project) - if can?(current_user, :push_code, @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
%li.divider %li.divider
%li %li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do = link_to new_namespace_project_branch_path(@project.namespace, @project) do
New git branch = icon('code-fork fw')
New branch
%li %li
= link_to new_namespace_project_tag_path(@project.namespace, @project) do = 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 && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2 - 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 = 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 Fork
%span.count %span.count
= @project.forks_count = @project.forks_count
- else - else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn' do = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn' do
= icon('code-fork') = icon('code-fork fw')
Fork Fork
%span.count %span.count
= @project.forks_count = @project.forks_count
- if current_user - if current_user
= link_to toggle_star_namespace_project_path(@project.namespace, @project), class: 'btn star-btn toggle-star', method: :post, remote: true do = 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) - if current_user.starred?(@project)
Unstar Unstar
- else - else
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
- else - else
= link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do = 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 Star
%span.count %span.count
= @project.star_count = @project.star_count
...@@ -9,7 +9,13 @@ ...@@ -9,7 +9,13 @@
Open Open
Issue ##{@issue.iid} Issue ##{@issue.iid}
%small.creator %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 .pull-right
- if can?(current_user, :create_issue, @project) - if can?(current_user, :create_issue, @project)
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
- if @merge_request.compare_failed - if @merge_request.compare_failed
.alert.alert-danger .alert.alert-danger
%h4 Compare failed %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 - else
.light-well .light-well
.center .center
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
= icon('history') = icon('history')
Commits Commits
%span.badge= @commits.size %span.badge= @commits.size
%li.diffs-tab %li.diffs-tab.active
= link_to url_for(params), data: {target: '#diffs', action: 'diffs', toggle: 'tab'} do = link_to url_for(params), data: {target: '#diffs', action: 'diffs', toggle: 'tab'} do
= icon('list-alt') = icon('list-alt')
Changes Changes
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
.tab-content .tab-content
#commits.commits.tab-pane #commits.commits.tab-pane
= render "projects/commits/commits", project: @project = render "projects/commits/commits", project: @project
#diffs.diffs.tab-pane #diffs.diffs.tab-pane.active
- if @diffs.present? - if @diffs.present?
= render "projects/diffs/diffs", diffs: @diffs, project: @project = render "projects/diffs/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
......
...@@ -6,40 +6,25 @@ ...@@ -6,40 +6,25 @@
= render "projects/merge_requests/show/mr_box" = render "projects/merge_requests/show/mr_box"
%hr %hr
.append-bottom-20 .append-bottom-20
.slead - if @merge_request.open?
%span From .btn-group.btn-group-sm.pull-right
- if @merge_request.for_fork? %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
%strong.label-branch< = icon('download')
- if @merge_request.source_project Download as
= link_to @merge_request.source_project_namespace, namespace_project_path(@merge_request.source_project.namespace, @merge_request.source_project) %span.caret
- else %ul.dropdown-menu
\ #{@merge_request.source_project_namespace} %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
\:#{@merge_request.source_branch} %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 %span into
%strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch} %span.label-branch #{@merge_request.target_branch}
- else - if @merge_request.open? && !@merge_request.branch_missing?
%strong.label-branch #{@merge_request.source_branch} %div
%span into If you want to try or merge this request manually, you can use the
%strong.label-branch #{@merge_request.target_branch} = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- 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}
= render "projects/merge_requests/show/how_to_merge" = render "projects/merge_requests/show/how_to_merge"
= render "projects/merge_requests/widget/show.html.haml" = 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? - 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? - elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else - else
......
...@@ -3,42 +3,45 @@ ...@@ -3,42 +3,45 @@
.modal-content .modal-content
.modal-header .modal-header
%a.close{href: "#", "data-dismiss" => "modal"} × %a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 How to merge %h3 Check out, review and merge locally
.modal-body .modal-body
- if @merge_request.for_fork? %p
- source_remote = @merge_request.source_project.namespace.nil? ? "source" :@merge_request.source_project.namespace.path %strong Step 1.
- target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path Fetch and check out the branch for this merge request
%p %pre.dark
%strong Step 1. - if @merge_request.for_fork?
Fetch the code and create a new branch pointing to it
%pre.dark
:preserve :preserve
git fetch #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch} 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 git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} FETCH_HEAD
%p - else
%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
:preserve :preserve
git fetch origin git fetch origin
git checkout -b #{@merge_request.source_branch} origin/#{@merge_request.source_branch} git checkout -b #{@merge_request.source_branch} origin/#{@merge_request.source_branch}
%p %p
%strong Step 2. %strong Step 2.
Merge the branch and push the changes to GitLab Review the changes locally
%pre.dark
%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 :preserve
git checkout #{@merge_request.target_branch} git checkout #{@merge_request.target_branch}
git merge --no-ff #{@merge_request.source_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 :javascript
$(function(){ $(function(){
......
%h4.page-title %h4.page-title
.issue-box{ class: issue_box_class(@merge_request) } .issue-box{ class: issue_box_class(@merge_request) }
= @merge_request.state_human_name = @merge_request.state_human_name
= "Merge Request ##{@merge_request.iid}" Merge Request ##{@merge_request.iid}
%small.creator %small.creator
&middot; &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 .issue-btn-group.pull-right
- if can?(current_user, :update_merge_request, @merge_request) - if can?(current_user, :update_merge_request, @merge_request)
......
...@@ -6,4 +6,7 @@ ...@@ -6,4 +6,7 @@
- if @merge_request.closed_event - if @merge_request.closed_event
by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)} by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.closed_event.created_at)} #{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? - if @merge_request.has_ci?
.mr-widget-heading .mr-widget-heading
.ci_widget.ci-success{style: "display:none"} - [:success, :skipped, :canceled, :failed, :running, :pending].each do |status|
= 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|
.ci_widget{class: "ci-#{status}", style: "display:none"} .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} %span CI build #{status}
for #{@merge_request.last_commit_short_sha}. 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 .ci_widget
= icon("spinner spin") = 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"} .ci_widget.ci-not_found{style: "display:none"}
= icon("times") = icon("times-circle")
%span Can not find commit in the CI server Could not find CI status for #{@merge_request.last_commit_short_sha}.
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"
.ci_widget.ci-error{style: "display:none"} .ci_widget.ci-error{style: "display:none"}
= icon("times") = icon("times-circle")
%span Cannot connect to the CI server. Please check your settings and try again. Could not connect to the CI server. Please check your settings and try again.
:coffeescript :coffeescript
$ -> $ ->
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
= render 'projects/merge_requests/widget/heading' = render 'projects/merge_requests/widget/heading'
.mr-widget-body .mr-widget-body
%h4 %h4
Merge in progress... = icon("spinner spin")
Merge in progress&hellip;
%p %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 @@ ...@@ -7,23 +7,31 @@
by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)} by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)} #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
%div %div
- if @source_branch.blank? - if !@merge_request.source_branch_exists?
Source branch has been removed = 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 .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 = 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 %i.fa.fa-times
Remove Source Branch Remove Source Branch
.remove_source_branch_widget.failed.hide .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 .remove_source_branch_in_progress.hide
%i.fa.fa-spinner.fa-spin %p
&nbsp; = icon('spinner spin')
Removing source branch '#{@merge_request.source_branch}'. Please wait. Page will be automatically reloaded. &nbsp; Removing source branch '#{@merge_request.source_branch}'. Please wait. This page will be automatically reload.
:coffeescript :coffeescript
$('.remove_source_branch').on 'click', -> $('.remove_source_branch').on 'click', ->
......
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
.mr-widget-body .mr-widget-body
- if @project.archived? - if @project.archived?
= render 'projects/merge_requests/widget/open/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? - elsif @merge_request.commits.blank?
= render 'projects/merge_requests/widget/open/nothing' = render 'projects/merge_requests/widget/open/nothing'
- elsif @merge_request.branch_missing? - elsif @merge_request.branch_missing?
...@@ -26,7 +24,7 @@ ...@@ -26,7 +24,7 @@
.mr-widget-footer .mr-widget-footer
%span %span
%i.fa.fa-check %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 = succeed '.' do
!= gfm(issues_sentence(@closes_issues)) != gfm(issues_sentence(@closes_issues))
......
...@@ -11,10 +11,10 @@ ...@@ -11,10 +11,10 @@
var merge_request_widget; var merge_request_widget;
merge_request_widget = new MergeRequestWidget({ 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"}, check_enable: #{@merge_request.unchecked? ? "true" : "false"},
url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
ci_enable: #{@project.ci_service ? "true" : "false"}, 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 = hidden_field_tag :authenticity_token, form_authenticity_token
.accept-merge-holder.clearfix.js-toggle-container .accept-merge-holder.clearfix.js-toggle-container
.accept-action .accept-action
...@@ -8,28 +8,22 @@ ...@@ -8,28 +8,22 @@
.accept-control.checkbox .accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch = 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) - 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 .accept-control.remove_branch_holder.checkbox
= label_tag :should_rebase do = label_tag :should_rebase do
= check_box_tag :should_rebase, "1", @project.merge_requests_rebase_default = check_box_tag :should_rebase, "1", @project.merge_requests_rebase_default
%strong Rebase before merge Rebase before merge
.accept-control .accept-control
= link_to "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message" do = link_to "#", class: "modify-merge-commit-link js-toggle-button" do
%i.fa.fa-edit = icon('edit')
Modify commit message Modify commit message
.js-toggle-content.hide.prepend-top-20 .js-toggle-content.hide.prepend-top-20
= render 'shared/commit_message_container', params: params, = render 'shared/commit_message_container', params: params,
text: @merge_request.merge_commit_message, text: @merge_request.merge_commit_message,
rows: 14, hint: true 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 :coffeescript
$('.accept-mr-form').on 'ajax:before', -> $('.accept-mr-form').on 'ajax:before', ->
btn = $('.accept_merge_request') btn = $('.accept_merge_request')
......
%h4
Project is archived
%p %p
%strong Archived projects do not provide commit access. This merge request cannot be merged because archived projects cannot be written to.
%strong %strong
%i.fa.fa-spinner.fa-spin = icon("spinner spin")
Checking automatic merge… Checking ability to merge automatically&hellip;
:coffeescript :coffeescript
$ -> $ ->
......
- if @merge_request.can_be_merged_by?(current_user) %h4
%h4 = icon("exclamation-triangle")
This merge request contains merge conflicts that must be resolved. This merge request contains merge conflicts
You can try it manually on the
%strong %p
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" Please resolve these conflicts or
- else - if @merge_request.can_be_merged_by?(current_user)
%strong This merge request contains merge conflicts that must be resolved. #{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}.
Only those with write access to this repository can merge merge requests. - else
ask someone with write access to this repository to merge this request manually.
%h4 - unless @merge_request.source_branch_exists?
Can't be merged %h4
%p = icon("exclamation-triangle")
This merge request can not be accepted because branch Source branch
- unless @merge_request.source_branch_exists? %span.label-branch= source_branch_with_namespace(@merge_request)
%span.label.label-inverse= @merge_request.source_branch does not exist
does not exist in %p
%span.label.label-info= @merge_request.source_project_path Please restore the source branch or close this merge request and open a new merge request with a different source branch.
- else - else
%span.label.label-inverse= @merge_request.target_branch %h4
does not exist in = icon("exclamation-triangle")
%span.label.label-info= @merge_request.target_project_path Target branch
%br %span.label-branch= @merge_request.target_branch
%strong Please close this merge request or change branches with existing one 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. %h4
Only those with write access to this repository can merge merge requests. Ready to be merged automatically
%p
Ask someone with write access to this repository to merge this request.
%h4 Nothing to merge %h4
%p = icon("exclamation-triangle")
Nothing to merge from Nothing to merge from
%span.label-branch #{@merge_request.source_branch} %span.label-branch= source_branch_with_namespace(@merge_request)
to into
%span.label-branch #{@merge_request.target_branch} %span.label-branch= @merge_request.target_branch
%br %p
Try to use different branches or push new code. 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