Merge remote-tracking branch 'upstream/master' into artifacts-from-ref-and-build-name
* upstream/master: (107 commits) Fix external issue tracker "Issues" link leading to 404s Fix CHANGELOG entries related to 8.11 release. Fix changelog Reduce contributions calendar data payload Add lock_version to merge_requests table Add hover color to emoji icon Fix wrong Koding link Capitalize mentioned issue timeline notes Fix groups sort dropdown alignment Use icon helper Fix inline emoji text alignment Adds response mime type to transaction metric action when it's not HTML Moved two 8.11 changelog entries to 8.12 Fix markdown link in doc_styleguide.md Display project icon from default branch Reduce number of database queries on builds tab Update CHANGELOG Update Issue board documentation Label list shows all issues (opened or closed) with that label Update CHANGELOG ...
This commit is contained in:
commit
de80cbfe3f
52
CHANGELOG
52
CHANGELOG
|
@ -1,13 +1,56 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.12.0 (unreleased)
|
||||
- Add two-factor recovery endpoint to internal API !5510
|
||||
- Change merge_error column from string to text type
|
||||
- Reduce contributions calendar data payload (ClemMakesApps)
|
||||
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
|
||||
- Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling)
|
||||
- Add hover color to emoji icon (ClemMakesApps)
|
||||
- Optimistic locking for Issues and Merge Requests (title and description overriding prevention)
|
||||
- Add `wiki_page_events` to project hook APIs (Ben Boeckel)
|
||||
- Remove Gitorious import
|
||||
- Add Sentry logging to API calls
|
||||
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
|
||||
- Fix groups sort dropdown alignment (ClemMakesApps)
|
||||
- Added tests for diff notes
|
||||
- Add a button to download latest successful artifacts for branches and tags !5142
|
||||
|
||||
v 8.11.1 (unreleased)
|
||||
- Add delimiter to project stars and forks count (ClemMakesApps)
|
||||
- Fix badge count alignment (ClemMakesApps)
|
||||
- Fix branch title trailing space on hover (ClemMakesApps)
|
||||
- Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
|
||||
- Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
|
||||
- Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
|
||||
- Update merge_requests.md with a simpler way to check out a merge request. !5944
|
||||
- Fix button missing type (ClemMakesApps)
|
||||
- Move to project dropdown with infinite scroll for better performance
|
||||
- Load branches asynchronously in Cherry Pick and Revert dialogs.
|
||||
- Add merge request versions !5467
|
||||
- Change using size to use count and caching it for number of group members. !5935
|
||||
- Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck)
|
||||
- Reduce number of database queries on builds tab
|
||||
- Capitalize mentioned issue timeline notes (ClemMakesApps)
|
||||
- Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger)
|
||||
- Adds response mime type to transaction metric action when it's not HTML
|
||||
|
||||
v 8.11.3 (unreleased)
|
||||
- Allow system info page to handle case where info is unavailable
|
||||
- Label list shows all issues (opened or closed) with that label
|
||||
- Don't show resolve conflicts link before MR status is updated
|
||||
- Don't prevent viewing the MR when git refs for conflicts can't be found on disk
|
||||
- Fix external issue tracker "Issues" link leading to 404s
|
||||
|
||||
v 8.11.2
|
||||
- Show "Create Merge Request" widget for push events to fork projects on the source project. !5978
|
||||
- Use gitlab-workhorse 0.7.11 !5983
|
||||
- Does not halt the GitHub import process when an error occurs. !5763
|
||||
- Fix file links on project page when default view is Files !5933
|
||||
- Fixed enter key in search input not working !5888
|
||||
|
||||
v 8.11.1
|
||||
- Pulled due to packaging error.
|
||||
|
||||
v 8.11.0
|
||||
- Use test coverage value from the latest successful pipeline in badge. !5862
|
||||
|
@ -16,7 +59,6 @@ v 8.11.0
|
|||
- Add Koding (online IDE) integration
|
||||
- Ability to specify branches for Pivotal Tracker integration (Egor Lynko)
|
||||
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
|
||||
- Add delimiter to project stars and forks count (ClemMakesApps)
|
||||
- Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
|
||||
- Fix adding line comments on the initial commit to a repo !5900
|
||||
- Fix the title of the toggle dropdown button. !5515 (herminiotorres)
|
||||
|
@ -32,7 +74,6 @@ v 8.11.0
|
|||
- Use long options for curl examples in documentation !5703 (winniehell)
|
||||
- Added tooltip listing label names to the labels value in the collapsed issuable sidebar
|
||||
- Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell)
|
||||
- Fix badge count alignment (ClemMakesApps)
|
||||
- GitLab Performance Monitoring can now track custom events such as the number of tags pushed to a repository
|
||||
- Add support for relative links starting with ./ or / to RelativeLinkFilter (winniehell)
|
||||
- Allow naming U2F devices !5833
|
||||
|
@ -73,7 +114,6 @@ v 8.11.0
|
|||
- Enforce 2FA restrictions on API authentication endpoints !5820
|
||||
- Limit git rev-list output count to one in forced push check
|
||||
- Show deployment status on merge requests with external URLs
|
||||
- Fix branch title trailing space on hover (ClemMakesApps)
|
||||
- Clean up unused routes (Josef Strzibny)
|
||||
- Fix issue on empty project to allow developers to only push to protected branches if given permission
|
||||
- API: Add enpoints for pipelines
|
||||
|
@ -90,7 +130,6 @@ v 8.11.0
|
|||
- Fix devise deprecation warnings.
|
||||
- Check for 2FA when using Git over HTTP and only allow PersonalAccessTokens as password in that case !5764
|
||||
- Update version_sorter and use new interface for faster tag sorting
|
||||
- Load branches asynchronously in Cherry Pick and Revert dialogs.
|
||||
- Optimize checking if a user has read access to a list of issues !5370
|
||||
- Store all DB secrets in secrets.yml, under descriptive names !5274
|
||||
- Fix syntax highlighting in file editor
|
||||
|
@ -111,8 +150,6 @@ v 8.11.0
|
|||
- Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le)
|
||||
- Load project invited groups and members eagerly in `ProjectTeam#fetch_members`
|
||||
- Add pipeline events hook
|
||||
- Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
|
||||
- Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
|
||||
- Bump gitlab_git to speedup DiffCollection iterations
|
||||
- Rewrite description of a blocked user in admin settings. (Elias Werberich)
|
||||
- Make branches sortable without push permission !5462 (winniehell)
|
||||
|
@ -124,14 +161,12 @@ v 8.11.0
|
|||
- Fix search for notes which belongs to deleted objects
|
||||
- Allow Akismet to be trained by submitting issues as spam or ham !5538
|
||||
- Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska)
|
||||
- Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
|
||||
- Allow branch names ending with .json for graph and network page !5579 (winniehell)
|
||||
- Add the `sprockets-es6` gem
|
||||
- Improve OAuth2 client documentation (muteor)
|
||||
- Fix diff comments inverted toggle bug (ClemMakesApps)
|
||||
- Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska)
|
||||
- Profile requests when a header is passed
|
||||
- Fix button missing type (ClemMakesApps)
|
||||
- Avoid calculation of line_code and position for _line partial when showing diff notes on discussion tab.
|
||||
- Speedup DiffNote#active? on discussions, preloading noteables and avoid touching git repository to return diff_refs when possible
|
||||
- Add commit stats in commit api. !5517 (dixpac)
|
||||
|
@ -140,7 +175,6 @@ v 8.11.0
|
|||
- edit_blob_link will use blob passed onto the options parameter
|
||||
- Make error pages responsive (Takuya Noguchi)
|
||||
- The performance of the project dropdown used for moving issues has been improved
|
||||
- Move to project dropdown with infinite scroll for better performance
|
||||
- Fix skip_repo parameter being ignored when destroying a namespace
|
||||
- Add all builds into stage/job dropdowns on builds page
|
||||
- Change requests_profiles resource constraint to catch virtually any file
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.7.10
|
||||
0.7.11
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -349,5 +349,5 @@ gem 'paranoia', '~> 2.0'
|
|||
gem 'health_check', '~> 2.1.0'
|
||||
|
||||
# System information
|
||||
gem 'vmstat', '~> 2.1.1'
|
||||
gem 'vmstat', '~> 2.2'
|
||||
gem 'sys-filesystem', '~> 1.1.6'
|
||||
|
|
|
@ -772,7 +772,7 @@ GEM
|
|||
coercible (~> 1.0)
|
||||
descendants_tracker (~> 0.0, >= 0.0.3)
|
||||
equalizer (~> 0.0, >= 0.0.9)
|
||||
vmstat (2.1.1)
|
||||
vmstat (2.2.0)
|
||||
warden (1.2.6)
|
||||
rack (>= 1.0)
|
||||
web-console (2.3.0)
|
||||
|
@ -980,7 +980,7 @@ DEPENDENCIES
|
|||
unicorn-worker-killer (~> 0.4.2)
|
||||
version_sorter (~> 2.1.0)
|
||||
virtus (~> 1.0.1)
|
||||
vmstat (~> 2.1.1)
|
||||
vmstat (~> 2.2)
|
||||
web-console (~> 2.0)
|
||||
webmock (~> 1.21.0)
|
||||
wikicloth (= 0.8.1)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# GitLab
|
||||
|
||||
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
|
||||
[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
|
||||
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||
|
||||
## Canonical source
|
||||
|
@ -69,7 +70,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
|
|||
GitLab is a Ruby on Rails application that runs on the following software:
|
||||
|
||||
- Ubuntu/Debian/CentOS/RHEL
|
||||
- Ruby (MRI) 2.1
|
||||
- Ruby (MRI) 2.3
|
||||
- Git 2.7.4+
|
||||
- Redis 2.8+
|
||||
- MySQL or PostgreSQL
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
window.gl = window.gl || {};
|
||||
((global) => {
|
||||
const MAX_MESSAGE_LENGTH = 500;
|
||||
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
|
||||
|
@ -36,4 +35,4 @@ window.gl = window.gl || {};
|
|||
}
|
||||
|
||||
global.AbuseReports = AbuseReports;
|
||||
})(window.gl);
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
event_filters = $.cookie("event_filter");
|
||||
filter = sender.attr("id").split("_")[0];
|
||||
$.cookie("event_filter", (event_filters !== filter ? filter : ""), {
|
||||
path: '/'
|
||||
path: gon.relative_url_root || '/'
|
||||
});
|
||||
if (event_filters !== filter) {
|
||||
return sender.closest('li').toggleClass("active");
|
||||
|
|
|
@ -288,7 +288,7 @@
|
|||
new Aside();
|
||||
if ($window.width() < 1024 && $.cookie('pin_nav') === 'true') {
|
||||
$.cookie('pin_nav', 'false', {
|
||||
path: '/',
|
||||
path: gon.relative_url_root || '/',
|
||||
expires: 365 * 10
|
||||
});
|
||||
$('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned');
|
||||
|
@ -313,7 +313,7 @@
|
|||
$topNav.removeClass('header-pinned-nav').toggleClass('header-collapsed header-expanded');
|
||||
}
|
||||
$.cookie('pin_nav', doPinNav, {
|
||||
path: '/',
|
||||
path: gon.relative_url_root || '/',
|
||||
expires: 365 * 10
|
||||
});
|
||||
if ($.cookie('pin_nav') === 'true' || doPinNav) {
|
||||
|
|
|
@ -320,6 +320,7 @@
|
|||
frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
|
||||
frequentlyUsedEmojis.push(emoji);
|
||||
return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), {
|
||||
path: gon.relative_url_root || '/',
|
||||
expires: 365
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
(function() {
|
||||
(function(w) {
|
||||
$(function() {
|
||||
return $("body").on("click", ".js-toggle-button", function(e) {
|
||||
$(this).find('i').toggleClass('fa fa-chevron-down').toggleClass('fa fa-chevron-up');
|
||||
$(this).closest(".js-toggle-container").find(".js-toggle-content").toggle();
|
||||
return e.preventDefault();
|
||||
$('.js-toggle-button').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(this)
|
||||
.find('.fa')
|
||||
.toggleClass('fa-chevron-down fa-chevron-up')
|
||||
.end()
|
||||
.closest('.js-toggle-container')
|
||||
.find('.js-toggle-content')
|
||||
.toggle()
|
||||
;
|
||||
});
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
// If we're accessing a permalink, ensure it is not inside a
|
||||
// closed js-toggle-container!
|
||||
var hash = w.gl.utils.getLocationHash();
|
||||
var anchor = hash && document.getElementById(hash);
|
||||
var container = anchor && $(anchor).closest('.js-toggle-container');
|
||||
|
||||
if (container && container.find('.js-toggle-content').is(':hidden')) {
|
||||
container.find('.js-toggle-button').trigger('click');
|
||||
anchor.scrollIntoView();
|
||||
}
|
||||
});
|
||||
})(window);
|
||||
|
|
|
@ -67,6 +67,14 @@
|
|||
$.timeago.settings.strings = tmpLocale;
|
||||
};
|
||||
|
||||
w.gl.utils.getDayDifference = function(a, b) {
|
||||
var millisecondsPerDay = 1000 * 60 * 60 * 24;
|
||||
var date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
|
||||
var date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
|
||||
|
||||
return Math.floor((date2 - date1) / millisecondsPerDay);
|
||||
}
|
||||
|
||||
})(window);
|
||||
|
||||
}).call(this);
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
}
|
||||
return newUrl;
|
||||
};
|
||||
return w.gl.utils.removeParamQueryString = function(url, param) {
|
||||
w.gl.utils.removeParamQueryString = function(url, param) {
|
||||
var urlVariables, variables;
|
||||
url = decodeURIComponent(url);
|
||||
urlVariables = url.split('&');
|
||||
|
@ -59,6 +59,16 @@
|
|||
return results;
|
||||
})()).join('&');
|
||||
};
|
||||
w.gl.utils.getLocationHash = function(url) {
|
||||
var hashIndex;
|
||||
if (typeof url === 'undefined') {
|
||||
// Note: We can't use window.location.hash here because it's
|
||||
// not consistent across browsers - Firefox will pre-decode it
|
||||
url = window.location.href;
|
||||
}
|
||||
hashIndex = url.indexOf('#');
|
||||
return hashIndex === -1 ? null : url.substring(hashIndex + 1);
|
||||
};
|
||||
})(window);
|
||||
|
||||
}).call(this);
|
||||
|
|
|
@ -17,19 +17,15 @@
|
|||
return $(this).parents('form').submit();
|
||||
});
|
||||
$('.hide-no-ssh-message').on('click', function(e) {
|
||||
var path;
|
||||
path = '/';
|
||||
$.cookie('hide_no_ssh_message', 'false', {
|
||||
path: path
|
||||
path: gon.relative_url_root || '/'
|
||||
});
|
||||
$(this).parents('.no-ssh-key-message').remove();
|
||||
return e.preventDefault();
|
||||
});
|
||||
$('.hide-no-password-message').on('click', function(e) {
|
||||
var path;
|
||||
path = '/';
|
||||
$.cookie('hide_no_password_message', 'false', {
|
||||
path: path
|
||||
path: gon.relative_url_root || '/'
|
||||
});
|
||||
$(this).parents('.no-password-message').remove();
|
||||
return e.preventDefault();
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
}
|
||||
if (!triggered) {
|
||||
return $.cookie("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed'), {
|
||||
path: '/'
|
||||
path: gon.relative_url_root || '/'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
});
|
||||
this.initTabs();
|
||||
$('.hide-project-limit-message').on('click', function(e) {
|
||||
var path;
|
||||
path = '/';
|
||||
$.cookie('hide_project_limit_message', 'false', {
|
||||
path: path
|
||||
path: gon.relative_url_root || '/'
|
||||
});
|
||||
$(this).parents('.project-limit-message').remove();
|
||||
return e.preventDefault();
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
this.Calendar = (function() {
|
||||
function Calendar(timestamps, calendar_activities_path) {
|
||||
var group, i;
|
||||
this.calendar_activities_path = calendar_activities_path;
|
||||
this.clickDay = bind(this.clickDay, this);
|
||||
this.currentSelectedDate = '';
|
||||
|
@ -13,26 +12,36 @@
|
|||
this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
this.months = [];
|
||||
this.timestampsTmp = [];
|
||||
i = 0;
|
||||
group = 0;
|
||||
_.each(timestamps, (function(_this) {
|
||||
return function(count, date) {
|
||||
var day, innerArray, newDate;
|
||||
newDate = new Date(parseInt(date) * 1000);
|
||||
day = newDate.getDay();
|
||||
if ((day === 0 && i !== 0) || i === 0) {
|
||||
_this.timestampsTmp.push([]);
|
||||
group++;
|
||||
}
|
||||
innerArray = _this.timestampsTmp[group - 1];
|
||||
innerArray.push({
|
||||
count: count,
|
||||
date: newDate,
|
||||
day: day
|
||||
});
|
||||
return i++;
|
||||
};
|
||||
})(this));
|
||||
var group = 0;
|
||||
|
||||
var today = new Date()
|
||||
today.setHours(0, 0, 0, 0, 0);
|
||||
|
||||
var oneYearAgo = new Date(today);
|
||||
oneYearAgo.setFullYear(today.getFullYear() - 1);
|
||||
|
||||
var days = gl.utils.getDayDifference(oneYearAgo, today);
|
||||
|
||||
for(var i = 0; i <= days; i++) {
|
||||
var date = new Date(oneYearAgo);
|
||||
date.setDate(date.getDate() + i);
|
||||
|
||||
var day = date.getDay();
|
||||
var count = timestamps[date.getTime() * 0.001];
|
||||
|
||||
if ((day === 0 && i !== 0) || i === 0) {
|
||||
this.timestampsTmp.push([]);
|
||||
group++;
|
||||
}
|
||||
|
||||
var innerArray = this.timestampsTmp[group - 1];
|
||||
innerArray.push({
|
||||
count: count || 0,
|
||||
date: date,
|
||||
day: day
|
||||
});
|
||||
}
|
||||
|
||||
this.colorKey = this.initColorKey();
|
||||
this.color = this.initColor();
|
||||
this.renderSvg(group);
|
||||
|
|
|
@ -248,7 +248,7 @@ li.note {
|
|||
|
||||
img.emoji {
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
vertical-align: top;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
|
||||
.btn-link {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.open {
|
||||
|
|
|
@ -150,7 +150,7 @@
|
|||
border-top: 1px solid $border-color;
|
||||
border-bottom: 1px solid $border-color;
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
|
|
|
@ -1,22 +1,3 @@
|
|||
i.icon-gitorious {
|
||||
display: inline-block;
|
||||
background-position: 0 0;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
i.icon-gitorious-small {
|
||||
background-image: image-url('gitorious-logo-blue.png');
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
i.icon-gitorious-big {
|
||||
background-image: image-url('gitorious-logo-black.png');
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.import-jobs-from-col,
|
||||
.import-jobs-to-col {
|
||||
width: 40%;
|
||||
|
|
|
@ -269,7 +269,7 @@
|
|||
|
||||
.builds {
|
||||
.table-holder {
|
||||
overflow-x: scroll;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,6 +375,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
.mr-version-switch {
|
||||
background: $background-color;
|
||||
padding: $gl-btn-padding;
|
||||
color: $gl-placeholder-color;
|
||||
|
||||
a.btn-link {
|
||||
color: $gl-dark-link-color;
|
||||
}
|
||||
}
|
||||
|
||||
.merge-request-details {
|
||||
|
||||
.title {
|
||||
|
|
|
@ -281,19 +281,13 @@ ul.notes {
|
|||
font-size: 17px;
|
||||
}
|
||||
|
||||
&.js-note-delete {
|
||||
i {
|
||||
&:hover {
|
||||
color: $gl-text-red;
|
||||
}
|
||||
&:hover {
|
||||
.danger-highlight {
|
||||
color: $gl-text-red;
|
||||
}
|
||||
}
|
||||
|
||||
&.js-note-edit {
|
||||
i {
|
||||
&:hover {
|
||||
color: $gl-link-color;
|
||||
}
|
||||
.link-highlight {
|
||||
color: $gl-link-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,7 +254,6 @@
|
|||
width: 100%;
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
max-height: 500px;
|
||||
transition: max-height 0.3s, padding 0.3s;
|
||||
|
||||
&.graph-collapsed {
|
||||
|
@ -265,7 +264,6 @@
|
|||
|
||||
.pipeline-visualization {
|
||||
position: relative;
|
||||
min-width: 1220px;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
|
|
|
@ -29,7 +29,8 @@ class Admin::SystemInfoController < Admin::ApplicationController
|
|||
]
|
||||
|
||||
def show
|
||||
system_info = Vmstat.snapshot
|
||||
@cpus = Vmstat.cpu rescue nil
|
||||
@memory = Vmstat.memory rescue nil
|
||||
mounts = Sys::Filesystem.mounts
|
||||
|
||||
@disks = []
|
||||
|
@ -50,10 +51,5 @@ class Admin::SystemInfoController < Admin::ApplicationController
|
|||
rescue Sys::Filesystem::Error
|
||||
end
|
||||
end
|
||||
|
||||
@cpus = system_info.cpus.length
|
||||
|
||||
@mem_used = system_info.memory.active_bytes
|
||||
@mem_total = system_info.memory.total_bytes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@ class ApplicationController < ActionController::Base
|
|||
include Gitlab::GonHelper
|
||||
include GitlabRoutingHelper
|
||||
include PageLayoutHelper
|
||||
include SentryHelper
|
||||
include WorkhorseHelper
|
||||
|
||||
before_action :authenticate_user_from_private_token!
|
||||
|
@ -24,7 +25,7 @@ class ApplicationController < ActionController::Base
|
|||
protect_from_forgery with: :exception
|
||||
|
||||
helper_method :abilities, :can?, :current_application_settings
|
||||
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?
|
||||
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?
|
||||
|
||||
rescue_from Encoding::CompatibilityError do |exception|
|
||||
log_exception(exception)
|
||||
|
@ -46,28 +47,6 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
protected
|
||||
|
||||
def sentry_context
|
||||
if Rails.env.production? && current_application_settings.sentry_enabled
|
||||
if current_user
|
||||
Raven.user_context(
|
||||
id: current_user.id,
|
||||
email: current_user.email,
|
||||
username: current_user.username,
|
||||
)
|
||||
end
|
||||
|
||||
Raven.tags_context(program: sentry_program_context)
|
||||
end
|
||||
end
|
||||
|
||||
def sentry_program_context
|
||||
if Sidekiq.server?
|
||||
'sidekiq'
|
||||
else
|
||||
'rails'
|
||||
end
|
||||
end
|
||||
|
||||
# This filter handles both private tokens and personal access tokens
|
||||
def authenticate_user_from_private_token!
|
||||
token_string = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence
|
||||
|
@ -271,10 +250,6 @@ class ApplicationController < ActionController::Base
|
|||
Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
|
||||
end
|
||||
|
||||
def gitorious_import_enabled?
|
||||
current_application_settings.import_sources.include?('gitorious')
|
||||
end
|
||||
|
||||
def google_code_import_enabled?
|
||||
current_application_settings.import_sources.include?('google_code')
|
||||
end
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
class Import::GitoriousController < Import::BaseController
|
||||
before_action :verify_gitorious_import_enabled
|
||||
|
||||
def new
|
||||
redirect_to client.authorize_url(callback_import_gitorious_url)
|
||||
end
|
||||
|
||||
def callback
|
||||
session[:gitorious_repos] = params[:repos]
|
||||
redirect_to status_import_gitorious_path
|
||||
end
|
||||
|
||||
def status
|
||||
@repos = client.repos
|
||||
|
||||
@already_added_projects = current_user.created_projects.where(import_type: "gitorious")
|
||||
already_added_projects_names = @already_added_projects.pluck(:import_source)
|
||||
|
||||
@repos.reject! { |repo| already_added_projects_names.include? repo.full_name }
|
||||
end
|
||||
|
||||
def jobs
|
||||
jobs = current_user.created_projects.where(import_type: "gitorious").to_json(only: [:id, :import_status])
|
||||
render json: jobs
|
||||
end
|
||||
|
||||
def create
|
||||
@repo_id = params[:repo_id]
|
||||
repo = client.repo(@repo_id)
|
||||
@target_namespace = params[:new_namespace].presence || repo.namespace
|
||||
@project_name = repo.name
|
||||
|
||||
namespace = get_or_create_namespace || (render and return)
|
||||
|
||||
@project = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, current_user).execute
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def client
|
||||
@client ||= Gitlab::GitoriousImport::Client.new(session[:gitorious_repos])
|
||||
end
|
||||
|
||||
def verify_gitorious_import_enabled
|
||||
render_404 unless gitorious_import_enabled?
|
||||
end
|
||||
end
|
|
@ -4,7 +4,7 @@ class Projects::AvatarsController < Projects::ApplicationController
|
|||
before_action :authorize_admin_project!, only: [:destroy]
|
||||
|
||||
def show
|
||||
@blob = @repository.blob_at_branch('master', @project.avatar_in_git)
|
||||
@blob = @repository.blob_at_branch(@repository.root_ref, @project.avatar_in_git)
|
||||
if @blob
|
||||
headers['X-Content-Type-Options'] = 'nosniff'
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
if action_name == 'new'
|
||||
redirect_to external.new_issue_path
|
||||
else
|
||||
redirect_to external.issues_url
|
||||
redirect_to external.project_path
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -83,12 +83,22 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
def diffs
|
||||
apply_diff_view_cookie!
|
||||
|
||||
@merge_request_diff = @merge_request.merge_request_diff
|
||||
@merge_request_diff =
|
||||
if params[:diff_id]
|
||||
@merge_request.merge_request_diffs.find(params[:diff_id])
|
||||
else
|
||||
@merge_request.merge_request_diff
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html { define_discussion_vars }
|
||||
format.json do
|
||||
@diffs = @merge_request.diffs(diff_options)
|
||||
unless @merge_request_diff.latest?
|
||||
# Disable comments if browsing older version of the diff
|
||||
@diff_notes_disabled = true
|
||||
end
|
||||
|
||||
@diffs = @merge_request_diff.diffs(diff_options)
|
||||
|
||||
render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") }
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
before_action :project, except: [:new, :create]
|
||||
before_action :repository, except: [:new, :create]
|
||||
before_action :assign_ref_vars, only: [:show], if: :repo_exists?
|
||||
before_action :assign_tree_vars, only: [:show], if: [:repo_exists?, :project_view_files?]
|
||||
before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?]
|
||||
|
||||
# Authorize
|
||||
before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
|
||||
|
@ -332,11 +332,4 @@ class ProjectsController < Projects::ApplicationController
|
|||
def get_id
|
||||
project.repository.root_ref
|
||||
end
|
||||
|
||||
# ExtractsPath will set @id = project.path on the show route, but it has to be the
|
||||
# branch name for the tree view to work correctly.
|
||||
def assign_tree_vars
|
||||
@id = get_id
|
||||
tree
|
||||
end
|
||||
end
|
||||
|
|
|
@ -116,6 +116,17 @@ module ProjectsHelper
|
|||
license.nickname || license.name
|
||||
end
|
||||
|
||||
def last_push_event
|
||||
return unless current_user
|
||||
|
||||
project_ids = [@project.id]
|
||||
if fork = current_user.fork_of(@project)
|
||||
project_ids << fork.id
|
||||
end
|
||||
|
||||
current_user.recent_push(project_ids)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_project_nav_tabs(project, current_user)
|
||||
|
@ -351,16 +362,6 @@ module ProjectsHelper
|
|||
namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'LICENSE')
|
||||
end
|
||||
|
||||
def last_push_event
|
||||
return unless current_user
|
||||
|
||||
if fork = current_user.fork_of(@project)
|
||||
current_user.recent_push(fork.id)
|
||||
else
|
||||
current_user.recent_push(@project.id)
|
||||
end
|
||||
end
|
||||
|
||||
def readme_cache_key
|
||||
sha = @project.commit.try(:sha) || 'nil'
|
||||
[@project.path_with_namespace, sha, "readme"].join('-')
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
module SentryHelper
|
||||
def sentry_enabled?
|
||||
Rails.env.production? && current_application_settings.sentry_enabled?
|
||||
end
|
||||
|
||||
def sentry_context
|
||||
return unless sentry_enabled?
|
||||
|
||||
if current_user
|
||||
Raven.user_context(
|
||||
id: current_user.id,
|
||||
email: current_user.email,
|
||||
username: current_user.username,
|
||||
)
|
||||
end
|
||||
|
||||
Raven.tags_context(program: sentry_program_context)
|
||||
end
|
||||
|
||||
def sentry_program_context
|
||||
if Sidekiq.server?
|
||||
'sidekiq'
|
||||
else
|
||||
'rails'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -146,7 +146,7 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
|
||||
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
|
||||
domain_whitelist: Settings.gitlab['domain_whitelist'],
|
||||
import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project],
|
||||
import_sources: %w[github bitbucket gitlab google_code fogbugz git gitlab_project],
|
||||
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
|
||||
max_artifacts_size: Settings.artifacts['max_size'],
|
||||
require_two_factor_authentication: false,
|
||||
|
|
|
@ -352,7 +352,7 @@ module Ci
|
|||
end
|
||||
|
||||
def artifacts?
|
||||
!artifacts_expired? && artifacts_file.exists?
|
||||
!artifacts_expired? && self[:artifacts_file].present?
|
||||
end
|
||||
|
||||
def artifacts_metadata?
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Ci
|
||||
class Pipeline < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
include Statuseable
|
||||
include HasStatus
|
||||
|
||||
self.table_name = 'ci_commits'
|
||||
|
||||
|
@ -83,7 +83,7 @@ module Ci
|
|||
end
|
||||
|
||||
def stages_with_latest_statuses
|
||||
statuses.latest.order(:stage_idx).group_by(&:stage)
|
||||
statuses.latest.includes(project: :namespace).order(:stage_idx).group_by(&:stage)
|
||||
end
|
||||
|
||||
def project_id
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class CommitStatus < ActiveRecord::Base
|
||||
include Statuseable
|
||||
include HasStatus
|
||||
include Importable
|
||||
|
||||
self.table_name = 'ci_builds'
|
||||
|
@ -25,6 +25,8 @@ class CommitStatus < ActiveRecord::Base
|
|||
scope :retried, -> { where.not(id: latest) }
|
||||
scope :ordered, -> { order(:name) }
|
||||
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
|
||||
scope :latest_ci_stages, -> { latest.ordered.includes(project: :namespace) }
|
||||
scope :retried_ci_stages, -> { retried.ordered.includes(project: :namespace) }
|
||||
|
||||
state_machine :status do
|
||||
event :enqueue do
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module Statuseable
|
||||
module HasStatus
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped]
|
|
@ -10,14 +10,16 @@ class MergeRequest < ActiveRecord::Base
|
|||
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
|
||||
belongs_to :merge_user, class_name: "User"
|
||||
|
||||
has_one :merge_request_diff, dependent: :destroy
|
||||
has_many :merge_request_diffs, dependent: :destroy
|
||||
has_one :merge_request_diff,
|
||||
-> { order('merge_request_diffs.id DESC') }
|
||||
|
||||
has_many :events, as: :target, dependent: :destroy
|
||||
|
||||
serialize :merge_params, Hash
|
||||
|
||||
after_create :create_merge_request_diff, unless: :importing?
|
||||
after_update :update_merge_request_diff
|
||||
after_create :ensure_merge_request_diff, unless: :importing?
|
||||
after_update :reload_diff_if_branch_changed
|
||||
|
||||
delegate :commits, :real_size, to: :merge_request_diff, prefix: nil
|
||||
|
||||
|
@ -170,10 +172,10 @@ class MergeRequest < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def diffs(diff_options = nil)
|
||||
if self.compare
|
||||
self.compare.diffs(diff_options)
|
||||
if compare
|
||||
compare.diffs(diff_options)
|
||||
else
|
||||
Gitlab::Diff::FileCollection::MergeRequest.new(self, diff_options: diff_options)
|
||||
merge_request_diff.diffs(diff_options)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -184,8 +186,8 @@ class MergeRequest < ActiveRecord::Base
|
|||
def diff_base_commit
|
||||
if persisted?
|
||||
merge_request_diff.base_commit
|
||||
elsif diff_start_commit && diff_head_commit
|
||||
self.target_project.merge_base_commit(diff_start_sha, diff_head_sha)
|
||||
else
|
||||
branch_merge_base_commit
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -246,6 +248,15 @@ class MergeRequest < ActiveRecord::Base
|
|||
target_project.repository.commit(target_branch) if target_branch_ref
|
||||
end
|
||||
|
||||
def branch_merge_base_commit
|
||||
start_sha = target_branch_sha
|
||||
head_sha = source_branch_sha
|
||||
|
||||
if start_sha && head_sha
|
||||
target_project.merge_base_commit(start_sha, head_sha)
|
||||
end
|
||||
end
|
||||
|
||||
def target_branch_sha
|
||||
@target_branch_sha || target_branch_head.try(:sha)
|
||||
end
|
||||
|
@ -267,16 +278,16 @@ class MergeRequest < ActiveRecord::Base
|
|||
# Return diff_refs instance trying to not touch the git repository
|
||||
def diff_sha_refs
|
||||
if merge_request_diff && merge_request_diff.diff_refs_by_sha?
|
||||
return Gitlab::Diff::DiffRefs.new(
|
||||
base_sha: merge_request_diff.base_commit_sha,
|
||||
start_sha: merge_request_diff.start_commit_sha,
|
||||
head_sha: merge_request_diff.head_commit_sha
|
||||
)
|
||||
merge_request_diff.diff_refs
|
||||
else
|
||||
diff_refs
|
||||
end
|
||||
end
|
||||
|
||||
def branch_merge_base_sha
|
||||
branch_merge_base_commit.try(:sha)
|
||||
end
|
||||
|
||||
def validate_branches
|
||||
if target_project == source_project && target_branch == source_branch
|
||||
errors.add :branch_conflict, "You can not use same project/branch for source and target"
|
||||
|
@ -309,21 +320,31 @@ class MergeRequest < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def update_merge_request_diff
|
||||
def ensure_merge_request_diff
|
||||
merge_request_diff || create_merge_request_diff
|
||||
end
|
||||
|
||||
def create_merge_request_diff
|
||||
merge_request_diffs.create
|
||||
reload_merge_request_diff
|
||||
end
|
||||
|
||||
def reload_merge_request_diff
|
||||
merge_request_diff(true)
|
||||
end
|
||||
|
||||
def reload_diff_if_branch_changed
|
||||
if source_branch_changed? || target_branch_changed?
|
||||
reload_diff
|
||||
end
|
||||
end
|
||||
|
||||
def reload_diff
|
||||
return unless merge_request_diff && open?
|
||||
return unless open?
|
||||
|
||||
old_diff_refs = self.diff_refs
|
||||
|
||||
merge_request_diff.reload_content
|
||||
|
||||
create_merge_request_diff
|
||||
MergeRequests::MergeRequestDiffCacheService.new.execute(self)
|
||||
|
||||
new_diff_refs = self.diff_refs
|
||||
|
||||
update_diff_notes_positions(
|
||||
|
@ -779,8 +800,12 @@ class MergeRequest < ActiveRecord::Base
|
|||
return @conflicts_can_be_resolved_in_ui = false unless has_complete_diff_refs?
|
||||
|
||||
begin
|
||||
@conflicts_can_be_resolved_in_ui = conflicts.files.each(&:lines)
|
||||
rescue Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing
|
||||
# Try to parse each conflict. If the MR's mergeable status hasn't been updated,
|
||||
# ensure that we don't say there are conflicts to resolve when there are no conflict
|
||||
# files.
|
||||
conflicts.files.each(&:lines)
|
||||
@conflicts_can_be_resolved_in_ui = conflicts.files.length > 0
|
||||
rescue Rugged::OdbError, Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing
|
||||
@conflicts_can_be_resolved_in_ui = false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,8 +8,6 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
|
||||
belongs_to :merge_request
|
||||
|
||||
delegate :source_branch_sha, :target_branch_sha, :target_branch, :source_branch, to: :merge_request, prefix: nil
|
||||
|
||||
state_machine :state, initial: :empty do
|
||||
state :collected
|
||||
state :overflow
|
||||
|
@ -24,12 +22,47 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
serialize :st_commits
|
||||
serialize :st_diffs
|
||||
|
||||
after_create :reload_content, unless: :importing?
|
||||
after_save :keep_around_commits, unless: :importing?
|
||||
# All diff information is collected from repository after object is created.
|
||||
# It allows you to override variables like head_commit_sha before getting diff.
|
||||
after_create :save_git_content, unless: :importing?
|
||||
|
||||
def reload_content
|
||||
def self.select_without_diff
|
||||
select(column_names - ['st_diffs'])
|
||||
end
|
||||
|
||||
# Collect information about commits and diff from repository
|
||||
# and save it to the database as serialized data
|
||||
def save_git_content
|
||||
ensure_commits_sha
|
||||
save_commits
|
||||
reload_commits
|
||||
reload_diffs
|
||||
save_diffs
|
||||
keep_around_commits
|
||||
end
|
||||
|
||||
def ensure_commits_sha
|
||||
merge_request.fetch_ref
|
||||
self.start_commit_sha ||= merge_request.target_branch_sha
|
||||
self.head_commit_sha ||= merge_request.source_branch_sha
|
||||
self.base_commit_sha ||= find_base_sha
|
||||
save
|
||||
end
|
||||
|
||||
# Override head_commit_sha to keep compatibility with merge request diff
|
||||
# created before version 8.4 that does not store head_commit_sha in separate db field.
|
||||
def head_commit_sha
|
||||
if persisted? && super.nil?
|
||||
last_commit.try(:sha)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# This method will rely on repository branch sha
|
||||
# in case start_commit_sha is nil. Its necesarry for old merge request diff
|
||||
# created before version 8.4 to work
|
||||
def safe_start_commit_sha
|
||||
start_commit_sha || merge_request.target_branch_sha
|
||||
end
|
||||
|
||||
def size
|
||||
|
@ -38,14 +71,11 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
|
||||
def raw_diffs(options = {})
|
||||
if options[:ignore_whitespace_change]
|
||||
@raw_diffs_no_whitespace ||= begin
|
||||
compare = Gitlab::Git::Compare.new(
|
||||
@diffs_no_whitespace ||=
|
||||
Gitlab::Git::Compare.new(
|
||||
repository.raw_repository,
|
||||
self.start_commit_sha || self.target_branch_sha,
|
||||
self.head_commit_sha || self.source_branch_sha,
|
||||
)
|
||||
compare.diffs(options)
|
||||
end
|
||||
safe_start_commit_sha,
|
||||
head_commit_sha).diffs(options)
|
||||
else
|
||||
@raw_diffs ||= {}
|
||||
@raw_diffs[options] ||= load_diffs(st_diffs, options)
|
||||
|
@ -56,6 +86,11 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
@commits ||= load_commits(st_commits || [])
|
||||
end
|
||||
|
||||
def reload_commits
|
||||
@commits = nil
|
||||
commits
|
||||
end
|
||||
|
||||
def last_commit
|
||||
commits.first
|
||||
end
|
||||
|
@ -65,55 +100,60 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def base_commit
|
||||
return unless self.base_commit_sha
|
||||
return unless base_commit_sha
|
||||
|
||||
project.commit(self.base_commit_sha)
|
||||
project.commit(base_commit_sha)
|
||||
end
|
||||
|
||||
def start_commit
|
||||
return unless self.start_commit_sha
|
||||
return unless start_commit_sha
|
||||
|
||||
project.commit(self.start_commit_sha)
|
||||
project.commit(start_commit_sha)
|
||||
end
|
||||
|
||||
def head_commit
|
||||
return last_commit unless self.head_commit_sha
|
||||
return unless head_commit_sha
|
||||
|
||||
project.commit(self.head_commit_sha)
|
||||
project.commit(head_commit_sha)
|
||||
end
|
||||
|
||||
def diff_refs
|
||||
return unless start_commit_sha || base_commit_sha
|
||||
|
||||
Gitlab::Diff::DiffRefs.new(
|
||||
base_sha: base_commit_sha,
|
||||
start_sha: start_commit_sha,
|
||||
head_sha: head_commit_sha
|
||||
)
|
||||
end
|
||||
|
||||
def diff_refs_by_sha?
|
||||
base_commit_sha? && head_commit_sha? && start_commit_sha?
|
||||
end
|
||||
|
||||
def diffs(diff_options = nil)
|
||||
Gitlab::Diff::FileCollection::MergeRequestDiff.new(self, diff_options: diff_options)
|
||||
end
|
||||
|
||||
def project
|
||||
merge_request.target_project
|
||||
end
|
||||
|
||||
def compare
|
||||
@compare ||=
|
||||
begin
|
||||
# Update ref for merge request
|
||||
merge_request.fetch_ref
|
||||
Gitlab::Git::Compare.new(
|
||||
repository.raw_repository,
|
||||
safe_start_commit_sha,
|
||||
head_commit_sha
|
||||
)
|
||||
end
|
||||
|
||||
Gitlab::Git::Compare.new(
|
||||
repository.raw_repository,
|
||||
self.target_branch_sha,
|
||||
self.source_branch_sha
|
||||
)
|
||||
end
|
||||
def latest?
|
||||
self == merge_request.merge_request_diff
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Collect array of Git::Commit objects
|
||||
# between target and source branches
|
||||
def unmerged_commits
|
||||
commits = compare.commits
|
||||
|
||||
if commits.present?
|
||||
commits = Commit.decorate(commits, merge_request.source_project).reverse
|
||||
end
|
||||
|
||||
commits
|
||||
end
|
||||
|
||||
def dump_commits(commits)
|
||||
commits.map(&:to_hash)
|
||||
end
|
||||
|
@ -122,26 +162,21 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash), merge_request.source_project) }
|
||||
end
|
||||
|
||||
# Reload all commits related to current merge request from repo
|
||||
# Load all commits related to current merge request diff from repo
|
||||
# and save it as array of hashes in st_commits db field
|
||||
def reload_commits
|
||||
def save_commits
|
||||
new_attributes = {}
|
||||
|
||||
commit_objects = unmerged_commits
|
||||
commits = compare.commits
|
||||
|
||||
if commit_objects.present?
|
||||
new_attributes[:st_commits] = dump_commits(commit_objects)
|
||||
if commits.present?
|
||||
commits = Commit.decorate(commits, merge_request.source_project).reverse
|
||||
new_attributes[:st_commits] = dump_commits(commits)
|
||||
end
|
||||
|
||||
update_columns_serialized(new_attributes)
|
||||
end
|
||||
|
||||
# Collect array of Git::Diff objects
|
||||
# between target and source branches
|
||||
def unmerged_diffs
|
||||
compare.diffs(Commit.max_diff_options)
|
||||
end
|
||||
|
||||
def dump_diffs(diffs)
|
||||
if diffs.respond_to?(:map)
|
||||
diffs.map(&:to_hash)
|
||||
|
@ -162,16 +197,16 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
# Reload diffs between branches related to current merge request from repo
|
||||
# Load diffs between branches related to current merge request diff from repo
|
||||
# and save it as array of hashes in st_diffs db field
|
||||
def reload_diffs
|
||||
def save_diffs
|
||||
new_attributes = {}
|
||||
new_diffs = []
|
||||
|
||||
if commits.size.zero?
|
||||
new_attributes[:state] = :empty
|
||||
else
|
||||
diff_collection = unmerged_diffs
|
||||
diff_collection = compare.diffs(Commit.max_diff_options)
|
||||
|
||||
if diff_collection.overflow?
|
||||
# Set our state to 'overflow' to make the #empty? and #collected?
|
||||
|
@ -188,32 +223,17 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
end
|
||||
|
||||
new_attributes[:st_diffs] = new_diffs
|
||||
|
||||
new_attributes[:start_commit_sha] = self.target_branch_sha
|
||||
new_attributes[:head_commit_sha] = self.source_branch_sha
|
||||
new_attributes[:base_commit_sha] = branch_base_sha
|
||||
|
||||
update_columns_serialized(new_attributes)
|
||||
|
||||
keep_around_commits
|
||||
end
|
||||
|
||||
def project
|
||||
merge_request.target_project
|
||||
end
|
||||
|
||||
def repository
|
||||
project.repository
|
||||
end
|
||||
|
||||
def branch_base_commit
|
||||
return unless self.source_branch_sha && self.target_branch_sha
|
||||
def find_base_sha
|
||||
return unless head_commit_sha && start_commit_sha
|
||||
|
||||
project.merge_base_commit(self.source_branch_sha, self.target_branch_sha)
|
||||
end
|
||||
|
||||
def branch_base_sha
|
||||
branch_base_commit.try(:sha)
|
||||
project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha)
|
||||
end
|
||||
|
||||
def utf8_st_diffs
|
||||
|
@ -248,8 +268,8 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def keep_around_commits
|
||||
repository.keep_around(target_branch_sha)
|
||||
repository.keep_around(source_branch_sha)
|
||||
repository.keep_around(branch_base_sha)
|
||||
repository.keep_around(start_commit_sha)
|
||||
repository.keep_around(head_commit_sha)
|
||||
repository.keep_around(base_commit_sha)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -471,8 +471,6 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def reset_cache_and_import_attrs
|
||||
update(import_error: nil)
|
||||
|
||||
ProjectCacheWorker.perform_async(self.id)
|
||||
|
||||
self.import_data.destroy if self.import_data
|
||||
|
@ -1037,6 +1035,7 @@ class Project < ActiveRecord::Base
|
|||
"refs/heads/#{branch}",
|
||||
force: true)
|
||||
repository.copy_gitattributes(branch)
|
||||
repository.expire_avatar_cache(branch)
|
||||
reload_default_branch
|
||||
end
|
||||
|
||||
|
|
|
@ -1065,7 +1065,7 @@ class Repository
|
|||
|
||||
@avatar ||= cache.fetch(:avatar) do
|
||||
AVATAR_FILES.find do |file|
|
||||
blob_at_branch('master', file)
|
||||
blob_at_branch(root_ref, file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -489,10 +489,10 @@ class User < ActiveRecord::Base
|
|||
(personal_projects.count.to_f / projects_limit) * 100
|
||||
end
|
||||
|
||||
def recent_push(project_id = nil)
|
||||
def recent_push(project_ids = nil)
|
||||
# Get push events not earlier than 2 hours ago
|
||||
events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
|
||||
events = events.where(project_id: project_id) if project_id
|
||||
events = events.where(project_id: project_ids) if project_ids
|
||||
|
||||
# Use the latest event that has not been pushed or merged recently
|
||||
events.recent.find do |event|
|
||||
|
|
|
@ -36,7 +36,12 @@ module Boards
|
|||
end
|
||||
|
||||
def set_state
|
||||
params[:state] = list.done? ? 'closed' : 'opened'
|
||||
params[:state] =
|
||||
case list.list_type.to_sym
|
||||
when :backlog then 'opened'
|
||||
when :done then 'closed'
|
||||
else 'all'
|
||||
end
|
||||
end
|
||||
|
||||
def board_label_ids
|
||||
|
|
|
@ -34,7 +34,7 @@ module Ci
|
|||
end
|
||||
|
||||
def process_build(build, current_status)
|
||||
return false unless Statuseable::COMPLETED_STATUSES.include?(current_status)
|
||||
return false unless HasStatus::COMPLETED_STATUSES.include?(current_status)
|
||||
|
||||
if valid_statuses_for_when(build.when).include?(current_status)
|
||||
build.enqueue
|
||||
|
|
|
@ -269,11 +269,11 @@ module SystemNoteService
|
|||
#
|
||||
# Example Note text:
|
||||
#
|
||||
# "mentioned in #1"
|
||||
# "Mentioned in #1"
|
||||
#
|
||||
# "mentioned in !2"
|
||||
# "Mentioned in !2"
|
||||
#
|
||||
# "mentioned in 54f7727c"
|
||||
# "Mentioned in 54f7727c"
|
||||
#
|
||||
# See cross_reference_note_content.
|
||||
#
|
||||
|
@ -308,7 +308,7 @@ module SystemNoteService
|
|||
|
||||
# Check if a cross-reference is disallowed
|
||||
#
|
||||
# This method prevents adding a "mentioned in !1" note on every single commit
|
||||
# This method prevents adding a "Mentioned in !1" note on every single commit
|
||||
# in a merge request. Additionally, it prevents the creation of references to
|
||||
# external issues (which would fail).
|
||||
#
|
||||
|
@ -417,7 +417,7 @@ module SystemNoteService
|
|||
end
|
||||
|
||||
def cross_reference_note_prefix
|
||||
'mentioned in '
|
||||
'Mentioned in '
|
||||
end
|
||||
|
||||
def cross_reference_note_content(gfm_reference)
|
||||
|
|
|
@ -148,7 +148,8 @@ class TodoService
|
|||
def mark_todos_as_done_by_ids(ids, current_user)
|
||||
todos = current_user.todos.where(id: ids)
|
||||
|
||||
marked_todos = todos.update_all(state: :done)
|
||||
# Only return those that are not really on that state
|
||||
marked_todos = todos.where.not(state: :done).update_all(state: :done)
|
||||
current_user.update_todos_count_cache
|
||||
marked_todos
|
||||
end
|
||||
|
|
|
@ -9,12 +9,20 @@
|
|||
.light-well
|
||||
%h4 CPU
|
||||
.data
|
||||
%h1= "#{@cpus} cores"
|
||||
- if @cpus
|
||||
%h1= "#{@cpus.length} cores"
|
||||
- else
|
||||
= icon('warning', class: 'text-warning')
|
||||
Unable to collect CPU info
|
||||
.col-sm-4
|
||||
.light-well
|
||||
%h4 Memory
|
||||
.data
|
||||
%h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}"
|
||||
- if @memory
|
||||
%h1= "#{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}"
|
||||
- else
|
||||
= icon('warning', class: 'text-warning')
|
||||
Unable to collect memory info
|
||||
.col-sm-4
|
||||
.light-well
|
||||
%h4 Disks
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
- else
|
||||
= sort_title_recently_created
|
||||
%b.caret
|
||||
%ul.dropdown-menu
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
%li
|
||||
= link_to explore_groups_path(sort: sort_value_recently_created) do
|
||||
= sort_title_recently_created
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
.panel-heading
|
||||
%strong #{@group.name}
|
||||
group members
|
||||
%span.badge= @members.size
|
||||
%span.badge= @members.total_count
|
||||
.controls
|
||||
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
|
||||
.form-group
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
- page_title "Gitorious import"
|
||||
- header_title "Projects", root_path
|
||||
%h3.page-title
|
||||
%i.icon-gitorious.icon-gitorious-big
|
||||
Import projects from Gitorious.org
|
||||
|
||||
%p.light
|
||||
Select projects you want to import.
|
||||
%hr
|
||||
%p
|
||||
= button_tag class: "btn btn-import btn-success js-import-all" do
|
||||
Import all projects
|
||||
= icon("spinner spin", class: "loading-icon")
|
||||
|
||||
.table-responsive
|
||||
%table.table.import-jobs
|
||||
%colgroup.import-jobs-from-col
|
||||
%colgroup.import-jobs-to-col
|
||||
%colgroup.import-jobs-status-col
|
||||
%thead
|
||||
%tr
|
||||
%th From Gitorious.org
|
||||
%th To GitLab
|
||||
%th Status
|
||||
%tbody
|
||||
- @already_added_projects.each do |project|
|
||||
%tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
|
||||
%td
|
||||
= link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
|
||||
%td
|
||||
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span
|
||||
%i.fa.fa-check
|
||||
done
|
||||
- elsif project.import_status == 'started'
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
started
|
||||
- else
|
||||
= project.human_import_status_name
|
||||
|
||||
- @repos.each do |repo|
|
||||
%tr{id: "repo_#{repo.id}"}
|
||||
%td
|
||||
= link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
|
||||
%td.import-target
|
||||
= repo.full_name
|
||||
%td.import-actions.job-status
|
||||
= button_tag class: "btn btn-import js-add-to-import" do
|
||||
Import
|
||||
= icon("spinner spin", class: "loading-icon")
|
||||
|
||||
.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitorious_path}", import_path: "#{import_gitorious_path}" } }
|
|
@ -8,8 +8,8 @@
|
|||
- if stage
|
||||
|
||||
= stage.titleize
|
||||
= render statuses.latest.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
|
||||
= render statuses.retried.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
|
||||
= render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
|
||||
= render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
|
||||
%tr
|
||||
%td{colspan: 10}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
- if @merge_request_diff.collected?
|
||||
= render 'projects/merge_requests/show/versions'
|
||||
= render "projects/diffs/diffs", diffs: @diffs
|
||||
- elsif @merge_request_diff.empty?
|
||||
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
- merge_request_diffs = @merge_request.merge_request_diffs.select_without_diff
|
||||
|
||||
- if merge_request_diffs.size > 1
|
||||
.mr-version-switch
|
||||
Version:
|
||||
%span.dropdown.inline
|
||||
%a.btn-link.dropdown-toggle{ data: {toggle: :dropdown} }
|
||||
%strong.monospace<
|
||||
- if @merge_request_diff.latest?
|
||||
#{"latest"}
|
||||
- else
|
||||
#{@merge_request_diff.head_commit.short_id}
|
||||
%span.caret
|
||||
%ul.dropdown-menu.dropdown-menu-selectable
|
||||
- merge_request_diffs.each do |merge_request_diff|
|
||||
%li
|
||||
= link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id), class: ('is-active' if merge_request_diff == @merge_request_diff) do
|
||||
%strong.monospace
|
||||
#{merge_request_diff.head_commit.short_id}
|
||||
%br
|
||||
%small
|
||||
#{number_with_delimiter(merge_request_diff.commits.count)} #{'commit'.pluralize(merge_request_diff.commits.count)},
|
||||
= time_ago_with_tooltip(merge_request_diff.created_at)
|
||||
|
||||
- unless @merge_request_diff.latest?
|
||||
%span.prepend-left-default
|
||||
= icon('info-circle')
|
||||
This version is not the latest one. Comments are disabled
|
||||
.pull-right
|
||||
%span.monospace
|
||||
#{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id}
|
|
@ -59,11 +59,6 @@
|
|||
= icon('gitlab', text: 'GitLab.com')
|
||||
- unless gitlab_import_configured?
|
||||
= render 'gitlab_import_modal'
|
||||
%div
|
||||
- if gitorious_import_enabled?
|
||||
= link_to new_import_gitorious_path, class: 'btn import_gitorious' do
|
||||
%i.icon-gitorious.icon-gitorious-small
|
||||
Gitorious.org
|
||||
%div
|
||||
- if google_code_import_enabled?
|
||||
= link_to new_import_google_code_path, class: 'btn import_google_code' do
|
||||
|
|
|
@ -52,11 +52,11 @@
|
|||
- if note.emoji_awardable?
|
||||
= link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do
|
||||
= icon('spinner spin')
|
||||
= icon('smile-o')
|
||||
= icon('smile-o', class: 'link-highlight')
|
||||
|
||||
- if note_editable
|
||||
= link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do
|
||||
= icon('pencil')
|
||||
= icon('pencil', class: 'link-highlight')
|
||||
= link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do
|
||||
= icon('trash-o')
|
||||
.note-body{class: note_editable ? 'js-task-list-container' : ''}
|
||||
|
|
|
@ -14,6 +14,8 @@ class RepositoryImportWorker
|
|||
import_url: @project.import_url,
|
||||
path: @project.path_with_namespace)
|
||||
|
||||
project.update_column(:import_error, nil)
|
||||
|
||||
result = Projects::ImportService.new(project, current_user).execute
|
||||
|
||||
if result[:status] == :error
|
||||
|
|
|
@ -212,7 +212,7 @@ Settings.gitlab.default_projects_features['builds'] = true if Settin
|
|||
Settings.gitlab.default_projects_features['container_registry'] = true if Settings.gitlab.default_projects_features['container_registry'].nil?
|
||||
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
|
||||
Settings.gitlab['domain_whitelist'] ||= []
|
||||
Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project]
|
||||
Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab google_code fogbugz git gitlab_project]
|
||||
Settings.gitlab['trusted_proxies'] ||= []
|
||||
|
||||
#
|
||||
|
|
|
@ -157,12 +157,6 @@ Rails.application.routes.draw do
|
|||
get :jobs
|
||||
end
|
||||
|
||||
resource :gitorious, only: [:create, :new], controller: :gitorious do
|
||||
get :status
|
||||
get :callback
|
||||
get :jobs
|
||||
end
|
||||
|
||||
resource :google_code, only: [:create, :new], controller: :google_code do
|
||||
get :status
|
||||
post :callback
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class MergeRequestDiffRemoveUniq < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
disable_ddl_transaction!
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
if index_exists?(:merge_request_diffs, :merge_request_id)
|
||||
remove_index :merge_request_diffs, :merge_request_id
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
unless index_exists?(:merge_request_diffs, :merge_request_id)
|
||||
add_concurrent_index :merge_request_diffs, :merge_request_id, unique: true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class MergeRequestDiffAddIndex < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
disable_ddl_transaction!
|
||||
|
||||
# Set this constant to true if this migration requires downtime.
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
add_concurrent_index :merge_request_diffs, :merge_request_id
|
||||
end
|
||||
|
||||
def down
|
||||
if index_exists?(:merge_request_diffs, :merge_request_id)
|
||||
remove_index :merge_request_diffs, :merge_request_id
|
||||
end
|
||||
end
|
||||
end
|
|
@ -593,7 +593,7 @@ ActiveRecord::Schema.define(version: 20160823081327) do
|
|||
t.string "start_commit_sha"
|
||||
end
|
||||
|
||||
add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree
|
||||
add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", using: :btree
|
||||
|
||||
create_table "merge_requests", force: :cascade do |t|
|
||||
t.string "target_branch", null: false
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
## User documentation
|
||||
|
||||
- [Account Security](user/account/security.md) Securing your account via two-factor authentication, etc.
|
||||
- [API](api/README.md) Automate GitLab via a simple and powerful API.
|
||||
- [CI/CD](ci/README.md) GitLab Continuous Integration (CI) and Continuous Delivery (CD) getting started, `.gitlab-ci.yml` options, and examples.
|
||||
- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
|
||||
|
@ -18,7 +19,6 @@
|
|||
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
|
||||
- [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
|
||||
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
|
||||
- [Koding](user/project/koding.md) Learn how to use Koding, the online IDE.
|
||||
|
||||
## Administrator documentation
|
||||
|
||||
|
|
|
@ -79,7 +79,8 @@ Example response:
|
|||
"labels" : [],
|
||||
"subscribed" : false,
|
||||
"user_notes_count": 1,
|
||||
"due_date": "2016-07-22"
|
||||
"due_date": "2016-07-22",
|
||||
"web_url": "http://example.com/example/example/issues/6"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -156,7 +157,8 @@ Example response:
|
|||
"created_at" : "2016-01-04T15:31:46.176Z",
|
||||
"subscribed" : false,
|
||||
"user_notes_count": 1,
|
||||
"due_date": null
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -235,7 +237,8 @@ Example response:
|
|||
"created_at" : "2016-01-04T15:31:46.176Z",
|
||||
"subscribed" : false,
|
||||
"user_notes_count": 1,
|
||||
"due_date": "2016-07-22"
|
||||
"due_date": "2016-07-22",
|
||||
"web_url": "http://example.com/example/example/issues/1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -299,7 +302,8 @@ Example response:
|
|||
"created_at" : "2016-01-04T15:31:46.176Z",
|
||||
"subscribed": false,
|
||||
"user_notes_count": 1,
|
||||
"due_date": null
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -323,8 +327,8 @@ POST /projects/:id/issues
|
|||
| `assignee_id` | integer | no | The ID of a user to assign issue |
|
||||
| `milestone_id` | integer | no | The ID of a milestone to assign issue |
|
||||
| `labels` | string | no | Comma-separated label names for an issue |
|
||||
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
|
||||
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
|
||||
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
|
||||
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
|
||||
|
||||
```bash
|
||||
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
|
||||
|
@ -357,7 +361,8 @@ Example response:
|
|||
"milestone" : null,
|
||||
"subscribed" : true,
|
||||
"user_notes_count": 0,
|
||||
"due_date": null
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/14"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -384,8 +389,8 @@ PUT /projects/:id/issues/:issue_id
|
|||
| `milestone_id` | integer | no | The ID of a milestone to assign the issue to |
|
||||
| `labels` | string | no | Comma-separated label names for an issue |
|
||||
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
|
||||
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
|
||||
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
|
||||
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
|
||||
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
|
||||
|
||||
```bash
|
||||
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close
|
||||
|
@ -418,7 +423,8 @@ Example response:
|
|||
"milestone" : null,
|
||||
"subscribed" : true,
|
||||
"user_notes_count": 0,
|
||||
"due_date": "2016-07-22"
|
||||
"due_date": "2016-07-22",
|
||||
"web_url": "http://example.com/example/example/issues/15"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -496,7 +502,8 @@ Example response:
|
|||
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
|
||||
"web_url": "https://gitlab.example.com/u/solon.cremin"
|
||||
},
|
||||
"due_date": null
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/11"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -551,7 +558,8 @@ Example response:
|
|||
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
|
||||
"web_url": "https://gitlab.example.com/u/solon.cremin"
|
||||
},
|
||||
"due_date": null
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/11"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -607,7 +615,8 @@ Example response:
|
|||
"web_url": "https://gitlab.example.com/u/orville"
|
||||
},
|
||||
"subscribed": false,
|
||||
"due_date": null
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/12"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -693,7 +702,9 @@ Example response:
|
|||
"subscribed": true,
|
||||
"user_notes_count": 7,
|
||||
"upvotes": 0,
|
||||
"downvotes": 0
|
||||
"downvotes": 0,
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/example/example/issues/110"
|
||||
},
|
||||
"target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/issues/10",
|
||||
"body": "Vel voluptas atque dicta mollitia adipisci qui at.",
|
||||
|
|
|
@ -70,7 +70,8 @@ Parameters:
|
|||
"subscribed" : false,
|
||||
"user_notes_count": 1,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -136,7 +137,8 @@ Parameters:
|
|||
"subscribed" : true,
|
||||
"user_notes_count": 1,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -239,6 +241,7 @@ Parameters:
|
|||
"user_notes_count": 1,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1",
|
||||
"changes": [
|
||||
{
|
||||
"old_path": "VERSION",
|
||||
|
@ -321,7 +324,8 @@ Parameters:
|
|||
"subscribed" : true,
|
||||
"user_notes_count": 0,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -395,7 +399,8 @@ Parameters:
|
|||
"subscribed" : true,
|
||||
"user_notes_count": 1,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -496,7 +501,8 @@ Parameters:
|
|||
"subscribed" : true,
|
||||
"user_notes_count": 1,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -565,7 +571,8 @@ Parameters:
|
|||
"subscribed" : true,
|
||||
"user_notes_count": 1,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -886,7 +893,8 @@ Example response:
|
|||
"subscribed": true,
|
||||
"user_notes_count": 7,
|
||||
"should_remove_source_branch": true,
|
||||
"force_remove_source_branch": false
|
||||
"force_remove_source_branch": false,
|
||||
"web_url": "http://example.com/example/example/merge_requests/1"
|
||||
},
|
||||
"target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/merge_requests/7",
|
||||
"body": "Et voluptas laudantium minus nihil recusandae ut accusamus earum aut non.",
|
||||
|
@ -894,3 +902,112 @@ Example response:
|
|||
"created_at": "2016-07-01T11:14:15.530Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Get MR diff versions
|
||||
|
||||
Get a list of merge request diff versions.
|
||||
|
||||
```
|
||||
GET /projects/:id/merge_requests/:merge_request_id/versions
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------- | -------- | --------------------- |
|
||||
| `id` | String | yes | The ID of the project |
|
||||
| `merge_request_id` | integer | yes | The ID of the merge request |
|
||||
|
||||
```bash
|
||||
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
[{
|
||||
"id": 110,
|
||||
"head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
|
||||
"base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
|
||||
"start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
|
||||
"created_at": "2016-07-26T14:44:48.926Z",
|
||||
"merge_request_id": 105,
|
||||
"state": "collected",
|
||||
"real_size": "1"
|
||||
}, {
|
||||
"id": 108,
|
||||
"head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24",
|
||||
"base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
|
||||
"start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
|
||||
"created_at": "2016-07-25T14:21:33.028Z",
|
||||
"merge_request_id": 105,
|
||||
"state": "collected",
|
||||
"real_size": "1"
|
||||
}]
|
||||
```
|
||||
|
||||
## Get a single MR diff version
|
||||
|
||||
Get a single merge request diff version.
|
||||
|
||||
```
|
||||
GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------- | -------- | --------------------- |
|
||||
| `id` | String | yes | The ID of the project |
|
||||
| `merge_request_id` | integer | yes | The ID of the merge request |
|
||||
| `version_id` | integer | yes | The ID of the merge request diff version |
|
||||
|
||||
```bash
|
||||
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions/1
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 110,
|
||||
"head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
|
||||
"base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
|
||||
"start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd",
|
||||
"created_at": "2016-07-26T14:44:48.926Z",
|
||||
"merge_request_id": 105,
|
||||
"state": "collected",
|
||||
"real_size": "1",
|
||||
"commits": [{
|
||||
"id": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
|
||||
"short_id": "33e2ee85",
|
||||
"title": "Change year to 2018",
|
||||
"author_name": "Administrator",
|
||||
"author_email": "admin@example.com",
|
||||
"created_at": "2016-07-26T17:44:29.000+03:00",
|
||||
"message": "Change year to 2018"
|
||||
}, {
|
||||
"id": "aa24655de48b36335556ac8a3cd8bb521f977cbd",
|
||||
"short_id": "aa24655d",
|
||||
"title": "Update LICENSE",
|
||||
"author_name": "Administrator",
|
||||
"author_email": "admin@example.com",
|
||||
"created_at": "2016-07-25T17:21:53.000+03:00",
|
||||
"message": "Update LICENSE"
|
||||
}, {
|
||||
"id": "3eed087b29835c48015768f839d76e5ea8f07a24",
|
||||
"short_id": "3eed087b",
|
||||
"title": "Add license",
|
||||
"author_name": "Administrator",
|
||||
"author_email": "admin@example.com",
|
||||
"created_at": "2016-07-25T17:21:20.000+03:00",
|
||||
"message": "Add license"
|
||||
}],
|
||||
"diffs": [{
|
||||
"old_path": "LICENSE",
|
||||
"new_path": "LICENSE",
|
||||
"a_mode": "0",
|
||||
"b_mode": "100644",
|
||||
"diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2018 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n",
|
||||
"new_file": true,
|
||||
"renamed_file": false,
|
||||
"deleted_file": false
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
|
|
@ -53,7 +53,8 @@ Parameters:
|
|||
},
|
||||
"expires_at": null,
|
||||
"updated_at": "2012-06-28T10:52:04Z",
|
||||
"created_at": "2012-06-28T10:52:04Z"
|
||||
"created_at": "2012-06-28T10:52:04Z",
|
||||
"web_url": "http://example.com/example/example/snippets/1"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -84,7 +84,8 @@ Parameters:
|
|||
"star_count": 0,
|
||||
"runners_token": "b8547b1dc37721d05889db52fa2f02",
|
||||
"public_builds": true,
|
||||
"shared_with_groups": []
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
|
@ -144,7 +145,8 @@ Parameters:
|
|||
"star_count": 0,
|
||||
"runners_token": "b8547b1dc37721d05889db52fa2f02",
|
||||
"public_builds": true,
|
||||
"shared_with_groups": []
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -280,7 +282,8 @@ Parameters:
|
|||
"group_name": "Gitlab Org",
|
||||
"group_access_level": 10
|
||||
}
|
||||
]
|
||||
],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -448,6 +451,7 @@ Parameters:
|
|||
- `visibility_level` (optional)
|
||||
- `import_url` (optional)
|
||||
- `public_builds` (optional)
|
||||
- `only_allow_merge_if_build_succeeds` (optional)
|
||||
|
||||
### Create project for user
|
||||
|
||||
|
@ -473,6 +477,7 @@ Parameters:
|
|||
- `visibility_level` (optional)
|
||||
- `import_url` (optional)
|
||||
- `public_builds` (optional)
|
||||
- `only_allow_merge_if_build_succeeds` (optional)
|
||||
|
||||
### Edit project
|
||||
|
||||
|
@ -499,6 +504,7 @@ Parameters:
|
|||
- `public` (optional) - if `true` same as setting visibility_level = 20
|
||||
- `visibility_level` (optional)
|
||||
- `public_builds` (optional)
|
||||
- `only_allow_merge_if_build_succeeds` (optional)
|
||||
|
||||
On success, method returns 200 with the updated project. If parameters are
|
||||
invalid, 400 is returned.
|
||||
|
@ -577,7 +583,8 @@ Example response:
|
|||
"forks_count": 0,
|
||||
"star_count": 1,
|
||||
"public_builds": true,
|
||||
"shared_with_groups": []
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -643,7 +650,8 @@ Example response:
|
|||
"forks_count": 0,
|
||||
"star_count": 0,
|
||||
"public_builds": true,
|
||||
"shared_with_groups": []
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -729,7 +737,8 @@ Example response:
|
|||
"star_count": 0,
|
||||
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
|
||||
"public_builds": true,
|
||||
"shared_with_groups": []
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -815,7 +824,8 @@ Example response:
|
|||
"star_count": 0,
|
||||
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
|
||||
"public_builds": true,
|
||||
"shared_with_groups": []
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_build_succeeds": false
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -914,7 +924,11 @@ Parameters:
|
|||
"push_events": true,
|
||||
"issues_events": true,
|
||||
"merge_requests_events": true,
|
||||
"tag_push_events": true,
|
||||
"note_events": true,
|
||||
"build_events": true,
|
||||
"pipeline_events": true,
|
||||
"wiki_page_events": true,
|
||||
"enable_ssl_verification": true,
|
||||
"created_at": "2012-10-12T17:04:47Z"
|
||||
}
|
||||
|
@ -937,6 +951,9 @@ Parameters:
|
|||
- `merge_requests_events` - Trigger hook on merge_requests events
|
||||
- `tag_push_events` - Trigger hook on push_tag events
|
||||
- `note_events` - Trigger hook on note events
|
||||
- `build_events` - Trigger hook on build events
|
||||
- `pipeline_events` - Trigger hook on pipeline events
|
||||
- `wiki_page_events` - Trigger hook on wiki page events
|
||||
- `enable_ssl_verification` - Do SSL verification when triggering the hook
|
||||
|
||||
### Edit project hook
|
||||
|
@ -957,6 +974,9 @@ Parameters:
|
|||
- `merge_requests_events` - Trigger hook on merge_requests events
|
||||
- `tag_push_events` - Trigger hook on push_tag events
|
||||
- `note_events` - Trigger hook on note events
|
||||
- `build_events` - Trigger hook on build events
|
||||
- `pipeline_events` - Trigger hook on pipeline events
|
||||
- `wiki_page_events` - Trigger hook on wiki page events
|
||||
- `enable_ssl_verification` - Do SSL verification when triggering the hook
|
||||
|
||||
### Delete project hook
|
||||
|
|
|
@ -6,7 +6,7 @@ it organized and easy to find.
|
|||
## Location and naming of documents
|
||||
|
||||
>**Note:**
|
||||
These guidelines derive from the discussion taken place in issue [#3349](ce-3349).
|
||||
These guidelines derive from the discussion taken place in issue [#3349][ce-3349].
|
||||
|
||||
The documentation hierarchy can be vastly improved by providing a better layout
|
||||
and organization of directories.
|
||||
|
|
|
@ -397,7 +397,7 @@ If you are not using Linux you may have to run `gmake` instead of
|
|||
cd /home/git
|
||||
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
|
||||
cd gitlab-workhorse
|
||||
sudo -u git -H git checkout v0.7.10
|
||||
sudo -u git -H git checkout v0.7.11
|
||||
sudo -u git -H make
|
||||
|
||||
### Initialize Database and Activate Advanced Features
|
||||
|
|
|
@ -32,7 +32,7 @@ Please consider using a virtual machine to run GitLab.
|
|||
|
||||
## Ruby versions
|
||||
|
||||
GitLab requires Ruby (MRI) 2.1.x and currently does not work with versions 2.2 or 2.3.
|
||||
GitLab requires Ruby (MRI) 2.3. Support for Ruby versions below 2.3 (2.1, 2.2) will stop with GitLab 8.13.
|
||||
|
||||
You will have to use the standard MRI implementation of Ruby.
|
||||
We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/) but GitLab
|
||||
|
|
|
@ -15,7 +15,7 @@ See the documentation below for details on how to configure these services.
|
|||
- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
|
||||
- [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users
|
||||
- [Akismet](akismet.md) Configure Akismet to stop spam
|
||||
- [Koding](koding.md) Configure Koding to use IDE integration
|
||||
- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration
|
||||
|
||||
GitLab Enterprise Edition contains [advanced Jenkins support][jenkins].
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Account Security
|
||||
|
||||
- [Two-Factor Authentication](two_factor_authentication.md)
|
|
@ -0,0 +1,68 @@
|
|||
# Two-Factor Authentication
|
||||
|
||||
## Recovery options
|
||||
|
||||
If you lose your code generation device (such as your mobile phone) and you need
|
||||
to disable two-factor authentication on your account, you have several options.
|
||||
|
||||
### Use a saved recovery code
|
||||
|
||||
When you enabled two-factor authentication for your account, a series of
|
||||
recovery codes were generated. If you saved those codes somewhere safe, you
|
||||
may use one to sign in.
|
||||
|
||||
First, enter your username/email and password on the GitLab sign in page. When
|
||||
prompted for a two-factor code, enter one of the recovery codes you saved
|
||||
previously.
|
||||
|
||||
> **Note:** Once a particular recovery code has been used, it cannot be used again.
|
||||
You may still use the other saved recovery codes at a later time.
|
||||
|
||||
### Generate new recovery codes using SSH
|
||||
|
||||
It's not uncommon for users to forget to save the recovery codes when enabling
|
||||
two-factor authentication. If you have an SSH key added to your GitLab account,
|
||||
you can generate a new set of recovery codes using SSH.
|
||||
|
||||
Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to
|
||||
confirm that you wish to generate new codes. If you choose to continue, any
|
||||
previously saved codes will be invalidated.
|
||||
|
||||
```bash
|
||||
$ ssh git@gitlab.example.com 2fa_recovery_codes
|
||||
Are you sure you want to generate new two-factor recovery codes?
|
||||
Any existing recovery codes you saved will be invalidated. (yes/no)
|
||||
yes
|
||||
|
||||
Your two-factor authentication recovery codes are:
|
||||
|
||||
119135e5a3ebce8e
|
||||
11f6v2a498810dcd
|
||||
3924c7ab2089c902
|
||||
e79a3398bfe4f224
|
||||
34bd7b74adbc8861
|
||||
f061691d5107df1a
|
||||
169bf32a18e63e7f
|
||||
b510e7422e81c947
|
||||
20dbed24c5e74663
|
||||
df9d3b9403b9c9f0
|
||||
|
||||
During sign in, use one of the codes above when prompted for
|
||||
your two-factor code. Then, visit your Profile Settings and add
|
||||
a new device so you do not lose access to your account again.
|
||||
```
|
||||
|
||||
Next, go to the GitLab sign in page and enter your username/email and password.
|
||||
When prompted for a two-factor code, enter one of the recovery codes obtained
|
||||
from the command line output.
|
||||
|
||||
> **Note:** After signing in, you should immediately visit your **Profile Settings
|
||||
-> Account** to set up two-factor authentication with a new device.
|
||||
|
||||
### Ask a GitLab administrator to disable two-factor on your account
|
||||
|
||||
If the above two methods are not possible, you may ask a GitLab global
|
||||
administrator to disable two-factor authentication for your account. Please
|
||||
be aware that this will temporarily leave your account in a less secure state.
|
||||
You should sign in and re-enable two-factor authentication as soon as possible
|
||||
after the administrator disables it.
|
Binary file not shown.
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 269 KiB |
|
@ -31,10 +31,9 @@ Below is a table of the definitions used for GitLab's Issue Board.
|
|||
There are three types of lists, the ones you create based on your labels, and
|
||||
two default:
|
||||
|
||||
- **Backlog** (default): shows all issues that do not fall in one of the other
|
||||
lists. Always appears on the very left.
|
||||
- **Done** (default): shows all closed issues. Always appears on the very right.
|
||||
- Label list: a list based on a label. It shows all issues with that label.
|
||||
- **Backlog** (default): shows all opened issues that do not fall in one of the other lists. Always appears on the very left.
|
||||
- **Done** (default): shows all closed issues that do not fall in one of the other lists. Always appears on the very right.
|
||||
- Label list: a list based on a label. It shows all opened or closed issues with that label.
|
||||
|
||||
![GitLab Issue Board](img/issue_board.png)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ this is similar to performing `git checkout feature; git merge master` locally.
|
|||
GitLab allows resolving conflicts in a file where all of the below are true:
|
||||
|
||||
- The file is text, not binary
|
||||
- The file is in a UTF-8 compatible encoding
|
||||
- The file does not already contain conflict markers
|
||||
- The file, with conflict markers added, is not over 200 KB in size
|
||||
- The file exists under the same path in both branches
|
||||
|
|
|
@ -115,7 +115,7 @@ In this flow it is not common to have a production branch (or git flow master br
|
|||
|
||||
Merge or pull requests are created in a git management application and ask an assigned person to merge two branches.
|
||||
Tools such as GitHub and Bitbucket choose the name pull request since the first manual action would be to pull the feature branch.
|
||||
Tools such as GitLab and Gitorious choose the name merge request since that is the final action that is requested of the assignee.
|
||||
Tools such as GitLab and others choose the name merge request since that is the final action that is requested of the assignee.
|
||||
In this article we'll refer to them as merge requests.
|
||||
|
||||
If you work on a feature branch for more than a few hours it is good to share the intermediate result with the rest of the team.
|
||||
|
|
|
@ -15,6 +15,25 @@ Please note that you need to have builds configured to enable this feature.
|
|||
|
||||
## Checkout merge requests locally
|
||||
|
||||
### By adding a git alias
|
||||
|
||||
Add the following alias to your `~/.gitconfig`:
|
||||
|
||||
```
|
||||
[alias]
|
||||
mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' -
|
||||
```
|
||||
|
||||
Now you can check out a particular merge request from any repository and any remote, e.g. to check out a merge request number 5 as shown in GitLab from the `upstream` remote, do:
|
||||
|
||||
```
|
||||
$ git mr upstream 5
|
||||
```
|
||||
|
||||
This will fetch the merge request into a local `mr-upstream-5` branch and check it out.
|
||||
|
||||
### By modifying `.git/config` for a given repository
|
||||
|
||||
Locate the section for your GitLab remote in the `.git/config` file. It looks like this:
|
||||
|
||||
```
|
||||
|
@ -34,7 +53,7 @@ It should look like this:
|
|||
fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
|
||||
```
|
||||
|
||||
Now you can fetch all the merge requests requests:
|
||||
Now you can fetch all the merge requests:
|
||||
|
||||
```
|
||||
$ git fetch origin
|
||||
|
@ -61,3 +80,11 @@ If you click the "Hide whitespace changes" button, you can see the diff without
|
|||
It is also working on commits compare view.
|
||||
|
||||
![Commit Compare](merge_requests/commit_compare.png)
|
||||
|
||||
## Merge Requests versions
|
||||
|
||||
Every time you push to merge request branch, a new version of merge request diff
|
||||
is created. When you visit the merge request page you see latest version of changes.
|
||||
However you can select an older one from version dropdown
|
||||
|
||||
![Merge Request Versions](merge_requests/versions.png)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
|
@ -24,7 +24,7 @@ Feature: Project Merge Requests
|
|||
Scenario: I should see target branch when it is different from default
|
||||
Given project "Shop" have "Bug NS-06" open merge request
|
||||
When I visit project "Shop" merge requests page
|
||||
Then I should see "other_branch" branch
|
||||
Then I should see "feature_conflict" branch
|
||||
|
||||
Scenario: I should not see the numbers of diverged commits if the branch is rebased on the target
|
||||
Given project "Shop" have "Bug NS-07" open merge request with rebased branch
|
||||
|
|
|
@ -18,7 +18,6 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps
|
|||
expect(page).to have_link('GitHub')
|
||||
expect(page).to have_link('Bitbucket')
|
||||
expect(page).to have_link('GitLab.com')
|
||||
expect(page).to have_link('Gitorious.org')
|
||||
expect(page).to have_link('Google Code')
|
||||
expect(page).to have_link('Repo by URL')
|
||||
end
|
||||
|
|
|
@ -58,8 +58,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
expect(find('.merge-request-info')).not_to have_content "master"
|
||||
end
|
||||
|
||||
step 'I should see "other_branch" branch' do
|
||||
expect(page).to have_content "other_branch"
|
||||
step 'I should see "feature_conflict" branch' do
|
||||
expect(page).to have_content "feature_conflict"
|
||||
end
|
||||
|
||||
step 'I should see "Bug NS-04" in merge requests' do
|
||||
|
@ -124,7 +124,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
source_project: project,
|
||||
target_project: project,
|
||||
source_branch: 'fix',
|
||||
target_branch: 'other_branch',
|
||||
target_branch: 'feature_conflict',
|
||||
author: project.users.first,
|
||||
description: "# Description header"
|
||||
)
|
||||
|
|
|
@ -179,7 +179,7 @@ module SharedIssuable
|
|||
project = Project.find_by(name: from_project_name)
|
||||
|
||||
expect(page).to have_content(user_name)
|
||||
expect(page).to have_content("mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}")
|
||||
expect(page).to have_content("Mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}")
|
||||
end
|
||||
|
||||
def expect_sidebar_content(content)
|
||||
|
|
|
@ -18,22 +18,14 @@ module API
|
|||
end
|
||||
|
||||
rescue_from :all do |exception|
|
||||
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
|
||||
# why is this not wrapped in something reusable?
|
||||
trace = exception.backtrace
|
||||
|
||||
message = "\n#{exception.class} (#{exception.message}):\n"
|
||||
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
||||
message << " " << trace.join("\n ")
|
||||
|
||||
API.logger.add Logger::FATAL, message
|
||||
rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500)
|
||||
handle_api_exception(exception)
|
||||
end
|
||||
|
||||
format :json
|
||||
content_type :txt, "text/plain"
|
||||
|
||||
# Ensure the namespace is right, otherwise we might load Grape::API::Helpers
|
||||
helpers ::SentryHelper
|
||||
helpers ::API::Helpers
|
||||
|
||||
mount ::API::AccessRequests
|
||||
|
@ -75,5 +67,6 @@ module API
|
|||
mount ::API::Triggers
|
||||
mount ::API::Users
|
||||
mount ::API::Variables
|
||||
mount ::API::MergeRequestDiffs
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,7 +49,7 @@ module API
|
|||
class ProjectHook < Hook
|
||||
expose :project_id, :push_events
|
||||
expose :issues_events, :merge_requests_events, :tag_push_events
|
||||
expose :note_events, :build_events, :pipeline_events
|
||||
expose :note_events, :build_events, :pipeline_events, :wiki_page_events
|
||||
expose :enable_ssl_verification
|
||||
end
|
||||
|
||||
|
@ -90,6 +90,7 @@ module API
|
|||
expose :shared_with_groups do |project, options|
|
||||
SharedGroup.represent(project.project_group_links.all, options)
|
||||
end
|
||||
expose :only_allow_merge_if_build_succeeds
|
||||
end
|
||||
|
||||
class Member < UserBasic
|
||||
|
@ -177,6 +178,10 @@ module API
|
|||
|
||||
# TODO (rspeicher): Deprecated; remove in 9.0
|
||||
expose(:expires_at) { |snippet| nil }
|
||||
|
||||
expose :web_url do |snippet, options|
|
||||
Gitlab::UrlBuilder.build(snippet)
|
||||
end
|
||||
end
|
||||
|
||||
class ProjectEntity < Grape::Entity
|
||||
|
@ -206,6 +211,10 @@ module API
|
|||
expose :user_notes_count
|
||||
expose :upvotes, :downvotes
|
||||
expose :due_date
|
||||
|
||||
expose :web_url do |issue, options|
|
||||
Gitlab::UrlBuilder.build(issue)
|
||||
end
|
||||
end
|
||||
|
||||
class ExternalIssue < Grape::Entity
|
||||
|
@ -229,6 +238,10 @@ module API
|
|||
expose :user_notes_count
|
||||
expose :should_remove_source_branch?, as: :should_remove_source_branch
|
||||
expose :force_remove_source_branch?, as: :force_remove_source_branch
|
||||
|
||||
expose :web_url do |merge_request, options|
|
||||
Gitlab::UrlBuilder.build(merge_request)
|
||||
end
|
||||
end
|
||||
|
||||
class MergeRequestChanges < MergeRequest
|
||||
|
@ -237,6 +250,19 @@ module API
|
|||
end
|
||||
end
|
||||
|
||||
class MergeRequestDiff < Grape::Entity
|
||||
expose :id, :head_commit_sha, :base_commit_sha, :start_commit_sha,
|
||||
:created_at, :merge_request_id, :state, :real_size
|
||||
end
|
||||
|
||||
class MergeRequestDiffFull < MergeRequestDiff
|
||||
expose :commits, using: Entities::RepoCommit
|
||||
|
||||
expose :diffs, using: Entities::RepoDiff do |compare, _|
|
||||
compare.raw_diffs(all_diffs: true).to_a
|
||||
end
|
||||
end
|
||||
|
||||
class SSHKey < Grape::Entity
|
||||
expose :id, :title, :key, :created_at
|
||||
end
|
||||
|
|
|
@ -279,6 +279,24 @@ module API
|
|||
error!({ 'message' => message }, status)
|
||||
end
|
||||
|
||||
def handle_api_exception(exception)
|
||||
if sentry_enabled? && report_exception?(exception)
|
||||
define_params_for_grape_middleware
|
||||
sentry_context
|
||||
Raven.capture_exception(exception)
|
||||
end
|
||||
|
||||
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
|
||||
trace = exception.backtrace
|
||||
|
||||
message = "\n#{exception.class} (#{exception.message}):\n"
|
||||
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
||||
message << " " << trace.join("\n ")
|
||||
|
||||
API.logger.add Logger::FATAL, message
|
||||
rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500)
|
||||
end
|
||||
|
||||
# Projects helpers
|
||||
|
||||
def filter_projects(projects)
|
||||
|
@ -419,5 +437,19 @@ module API
|
|||
Entities::Issue
|
||||
end
|
||||
end
|
||||
|
||||
# The Grape Error Middleware only has access to env but no params. We workaround this by
|
||||
# defining a method that returns the right value.
|
||||
def define_params_for_grape_middleware
|
||||
self.define_singleton_method(:params) { Rack::Request.new(env).params.symbolize_keys }
|
||||
end
|
||||
|
||||
# We could get a Grape or a standard Ruby exception. We should only report anything that
|
||||
# is clearly an error.
|
||||
def report_exception?(exception)
|
||||
return true unless exception.respond_to?(:status)
|
||||
|
||||
exception.status == 500
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -101,6 +101,31 @@ module API
|
|||
{}
|
||||
end
|
||||
end
|
||||
|
||||
post '/two_factor_recovery_codes' do
|
||||
status 200
|
||||
|
||||
key = Key.find(params[:key_id])
|
||||
user = key.user
|
||||
|
||||
# Make sure this isn't a deploy key
|
||||
unless key.type.nil?
|
||||
return { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
|
||||
end
|
||||
|
||||
unless user.present?
|
||||
return { success: false, message: 'Could not find a user for the given key' }
|
||||
end
|
||||
|
||||
unless user.two_factor_enabled?
|
||||
return { success: false, message: 'Two-factor authentication is not enabled for this user' }
|
||||
end
|
||||
|
||||
codes = user.generate_otp_backup_codes!
|
||||
user.save!
|
||||
|
||||
{ success: true, recovery_codes: codes }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
module API
|
||||
# MergeRequestDiff API
|
||||
class MergeRequestDiffs < Grape::API
|
||||
before { authenticate! }
|
||||
|
||||
resource :projects do
|
||||
desc 'Get a list of merge request diff versions' do
|
||||
detail 'This feature was introduced in GitLab 8.12.'
|
||||
success Entities::MergeRequestDiff
|
||||
end
|
||||
|
||||
params do
|
||||
requires :id, type: String, desc: 'The ID of a project'
|
||||
requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
|
||||
end
|
||||
|
||||
get ":id/merge_requests/:merge_request_id/versions" do
|
||||
merge_request = user_project.merge_requests.
|
||||
find(params[:merge_request_id])
|
||||
|
||||
authorize! :read_merge_request, merge_request
|
||||
present merge_request.merge_request_diffs, with: Entities::MergeRequestDiff
|
||||
end
|
||||
|
||||
desc 'Get a single merge request diff version' do
|
||||
detail 'This feature was introduced in GitLab 8.12.'
|
||||
success Entities::MergeRequestDiffFull
|
||||
end
|
||||
|
||||
params do
|
||||
requires :id, type: String, desc: 'The ID of a project'
|
||||
requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
|
||||
requires :version_id, type: Integer, desc: 'The ID of a merge request diff version'
|
||||
end
|
||||
|
||||
get ":id/merge_requests/:merge_request_id/versions/:version_id" do
|
||||
merge_request = user_project.merge_requests.
|
||||
find(params[:merge_request_id])
|
||||
|
||||
authorize! :read_merge_request, merge_request
|
||||
present merge_request.merge_request_diffs.find(params[:version_id]), with: Entities::MergeRequestDiffFull
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -46,6 +46,7 @@ module API
|
|||
:note_events,
|
||||
:build_events,
|
||||
:pipeline_events,
|
||||
:wiki_page_events,
|
||||
:enable_ssl_verification
|
||||
]
|
||||
@hook = user_project.hooks.new(attrs)
|
||||
|
@ -80,6 +81,7 @@ module API
|
|||
:note_events,
|
||||
:build_events,
|
||||
:pipeline_events,
|
||||
:wiki_page_events,
|
||||
:enable_ssl_verification
|
||||
]
|
||||
|
||||
|
|
|
@ -123,7 +123,8 @@ module API
|
|||
:public,
|
||||
:visibility_level,
|
||||
:import_url,
|
||||
:public_builds]
|
||||
:public_builds,
|
||||
:only_allow_merge_if_build_succeeds]
|
||||
attrs = map_public_to_visibility_level(attrs)
|
||||
@project = ::Projects::CreateService.new(current_user, attrs).execute
|
||||
if @project.saved?
|
||||
|
@ -172,7 +173,8 @@ module API
|
|||
:public,
|
||||
:visibility_level,
|
||||
:import_url,
|
||||
:public_builds]
|
||||
:public_builds,
|
||||
:only_allow_merge_if_build_succeeds]
|
||||
attrs = map_public_to_visibility_level(attrs)
|
||||
@project = ::Projects::CreateService.new(user, attrs).execute
|
||||
if @project.saved?
|
||||
|
@ -234,7 +236,8 @@ module API
|
|||
:shared_runners_enabled,
|
||||
:public,
|
||||
:visibility_level,
|
||||
:public_builds]
|
||||
:public_builds,
|
||||
:only_allow_merge_if_build_succeeds]
|
||||
attrs = map_public_to_visibility_level(attrs)
|
||||
authorize_admin_project
|
||||
authorize! :rename_project, user_project if attrs[:name].present?
|
||||
|
|
|
@ -9,22 +9,14 @@ module Ci
|
|||
end
|
||||
|
||||
rescue_from :all do |exception|
|
||||
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
|
||||
# why is this not wrapped in something reusable?
|
||||
trace = exception.backtrace
|
||||
|
||||
message = "\n#{exception.class} (#{exception.message}):\n"
|
||||
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
||||
message << " " << trace.join("\n ")
|
||||
|
||||
API.logger.add Logger::FATAL, message
|
||||
rack_response({ 'message' => '500 Internal Server Error' }, 500)
|
||||
handle_api_exception(exception)
|
||||
end
|
||||
|
||||
content_type :txt, 'text/plain'
|
||||
content_type :json, 'application/json'
|
||||
format :json
|
||||
|
||||
helpers ::SentryHelper
|
||||
helpers ::Ci::API::Helpers
|
||||
helpers ::API::Helpers
|
||||
helpers Gitlab::CurrentSettings
|
||||
|
|
|
@ -94,9 +94,7 @@ module ExtractsPath
|
|||
@options = params.select {|key, value| allowed_options.include?(key) && !value.blank? }
|
||||
@options = HashWithIndifferentAccess.new(@options)
|
||||
|
||||
@id = params[:id] || params[:ref]
|
||||
@id += "/" + params[:path] unless params[:path].blank?
|
||||
|
||||
@id = get_id
|
||||
@ref, @path = extract_ref(@id)
|
||||
@repo = @project.repository
|
||||
if @options[:extended_sha1].blank?
|
||||
|
@ -118,4 +116,13 @@ module ExtractsPath
|
|||
def tree
|
||||
@tree ||= @repo.tree(@commit.id, @path)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# overriden in subclasses, do not remove
|
||||
def get_id
|
||||
id = params[:id] || params[:ref]
|
||||
id += "/" + params[:path] unless params[:path].blank?
|
||||
id
|
||||
end
|
||||
end
|
||||
|
|
|
@ -181,6 +181,17 @@ module Gitlab
|
|||
sections: sections
|
||||
}
|
||||
end
|
||||
|
||||
# Don't try to print merge_request or repository.
|
||||
def inspect
|
||||
instance_variables = [:merge_file_result, :their_path, :our_path, :our_mode].map do |instance_variable|
|
||||
value = instance_variable_get("@#{instance_variable}")
|
||||
|
||||
"#{instance_variable}=\"#{value}\""
|
||||
end
|
||||
|
||||
"#<#{self.class} #{instance_variables.join(' ')}>"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,10 +13,19 @@ module Gitlab
|
|||
class UnmergeableFile < ParserError
|
||||
end
|
||||
|
||||
class UnsupportedEncoding < ParserError
|
||||
end
|
||||
|
||||
def parse(text, our_path:, their_path:, parent_file: nil)
|
||||
raise UnmergeableFile if text.blank? # Typically a binary file
|
||||
raise UnmergeableFile if text.length > 102400
|
||||
|
||||
begin
|
||||
text.to_json
|
||||
rescue Encoding::UndefinedConversionError
|
||||
raise UnsupportedEncoding
|
||||
end
|
||||
|
||||
line_obj_index = 0
|
||||
line_old = 1
|
||||
line_new = 1
|
||||
|
|
|
@ -23,7 +23,6 @@ module Gitlab
|
|||
|
||||
dates.each do |date|
|
||||
date_id = date.to_time.to_i.to_s
|
||||
@timestamps[date_id] = 0
|
||||
day_events = events.find { |day_events| day_events["date"] == date }
|
||||
|
||||
if day_events
|
||||
|
|
|
@ -41,7 +41,7 @@ module Gitlab
|
|||
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
|
||||
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
|
||||
domain_whitelist: Settings.gitlab['domain_whitelist'],
|
||||
import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project],
|
||||
import_sources: %w[github bitbucket gitlab google_code fogbugz git gitlab_project],
|
||||
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
|
||||
max_artifacts_size: Settings.artifacts['max_size'],
|
||||
require_two_factor_authentication: false,
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
module Gitlab
|
||||
module Diff
|
||||
module FileCollection
|
||||
class MergeRequest < Base
|
||||
def initialize(merge_request, diff_options:)
|
||||
@merge_request = merge_request
|
||||
class MergeRequestDiff < Base
|
||||
def initialize(merge_request_diff, diff_options:)
|
||||
@merge_request_diff = merge_request_diff
|
||||
|
||||
super(merge_request,
|
||||
project: merge_request.project,
|
||||
super(merge_request_diff,
|
||||
project: merge_request_diff.project,
|
||||
diff_options: diff_options,
|
||||
diff_refs: merge_request.diff_refs)
|
||||
diff_refs: merge_request_diff.diff_refs)
|
||||
end
|
||||
|
||||
def diff_files
|
||||
|
@ -61,11 +61,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def cacheable?
|
||||
@merge_request.merge_request_diff.present?
|
||||
@merge_request_diff.present?
|
||||
end
|
||||
|
||||
def cache_key
|
||||
[@merge_request.merge_request_diff, 'highlighted-diff-files', diff_options]
|
||||
[@merge_request_diff, 'highlighted-diff-files', diff_options]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,12 +3,13 @@ module Gitlab
|
|||
class Importer
|
||||
include Gitlab::ShellAdapter
|
||||
|
||||
attr_reader :client, :project, :repo, :repo_url
|
||||
attr_reader :client, :errors, :project, :repo, :repo_url
|
||||
|
||||
def initialize(project)
|
||||
@project = project
|
||||
@repo = project.import_source
|
||||
@repo_url = project.import_url
|
||||
@errors = []
|
||||
|
||||
if credentials
|
||||
@client = Client.new(credentials[:user])
|
||||
|
@ -18,8 +19,14 @@ module Gitlab
|
|||
end
|
||||
|
||||
def execute
|
||||
import_labels && import_milestones && import_issues &&
|
||||
import_pull_requests && import_wiki
|
||||
import_labels
|
||||
import_milestones
|
||||
import_issues
|
||||
import_pull_requests
|
||||
import_wiki
|
||||
handle_errors
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -28,22 +35,37 @@ module Gitlab
|
|||
@credentials ||= project.import_data.credentials if project.import_data
|
||||
end
|
||||
|
||||
def handle_errors
|
||||
return unless errors.any?
|
||||
|
||||
project.update_column(:import_error, {
|
||||
message: 'The remote data could not be fully imported.',
|
||||
errors: errors
|
||||
}.to_json)
|
||||
end
|
||||
|
||||
def import_labels
|
||||
labels = client.labels(repo, per_page: 100)
|
||||
labels.each { |raw| LabelFormatter.new(project, raw).create! }
|
||||
|
||||
true
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
raise Projects::ImportService::Error, e.message
|
||||
labels.each do |raw|
|
||||
begin
|
||||
LabelFormatter.new(project, raw).create!
|
||||
rescue => e
|
||||
errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def import_milestones
|
||||
milestones = client.milestones(repo, state: :all, per_page: 100)
|
||||
milestones.each { |raw| MilestoneFormatter.new(project, raw).create! }
|
||||
|
||||
true
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
raise Projects::ImportService::Error, e.message
|
||||
milestones.each do |raw|
|
||||
begin
|
||||
MilestoneFormatter.new(project, raw).create!
|
||||
rescue => e
|
||||
errors << { type: :milestone, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def import_issues
|
||||
|
@ -53,15 +75,15 @@ module Gitlab
|
|||
gh_issue = IssueFormatter.new(project, raw)
|
||||
|
||||
if gh_issue.valid?
|
||||
issue = gh_issue.create!
|
||||
apply_labels(issue)
|
||||
import_comments(issue) if gh_issue.has_comments?
|
||||
begin
|
||||
issue = gh_issue.create!
|
||||
apply_labels(issue)
|
||||
import_comments(issue) if gh_issue.has_comments?
|
||||
rescue => e
|
||||
errors << { type: :issue, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
raise Projects::ImportService::Error, e.message
|
||||
end
|
||||
|
||||
def import_pull_requests
|
||||
|
@ -77,14 +99,12 @@ module Gitlab
|
|||
apply_labels(merge_request)
|
||||
import_comments(merge_request)
|
||||
import_comments_on_diff(merge_request)
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
raise Projects::ImportService::Error, e.message
|
||||
rescue => e
|
||||
errors << { type: :pull_request, url: Gitlab::UrlSanitizer.sanitize(pull_request.url), errors: e.message }
|
||||
ensure
|
||||
clean_up_restored_branches(pull_request)
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def restore_source_branch(pull_request)
|
||||
|
@ -98,7 +118,7 @@ module Gitlab
|
|||
def remove_branch(name)
|
||||
project.repository.delete_branch(name)
|
||||
rescue Rugged::ReferenceError
|
||||
nil
|
||||
errors << { type: :remove_branch, name: name }
|
||||
end
|
||||
|
||||
def clean_up_restored_branches(pull_request)
|
||||
|
@ -112,9 +132,10 @@ module Gitlab
|
|||
issue = client.issue(repo, issuable.iid)
|
||||
|
||||
if issue.labels.count > 0
|
||||
label_ids = issue.labels.map do |raw|
|
||||
Label.find_by(LabelFormatter.new(project, raw).attributes).try(:id)
|
||||
end
|
||||
label_ids = issue.labels
|
||||
.map { |raw| LabelFormatter.new(project, raw).attributes }
|
||||
.map { |attrs| Label.find_by(attrs).try(:id) }
|
||||
.compact
|
||||
|
||||
issuable.update_attribute(:label_ids, label_ids)
|
||||
end
|
||||
|
@ -132,8 +153,12 @@ module Gitlab
|
|||
|
||||
def create_comments(issuable, comments)
|
||||
comments.each do |raw|
|
||||
comment = CommentFormatter.new(project, raw)
|
||||
issuable.notes.create!(comment.attributes)
|
||||
begin
|
||||
comment = CommentFormatter.new(project, raw)
|
||||
issuable.notes.create!(comment.attributes)
|
||||
rescue => e
|
||||
errors << { type: :comment, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -143,16 +168,12 @@ module Gitlab
|
|||
gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url)
|
||||
project.update_attribute(:wiki_enabled, true)
|
||||
end
|
||||
|
||||
true
|
||||
rescue Gitlab::Shell::Error => e
|
||||
# GitHub error message when the wiki repo has not been created,
|
||||
# this means that repo has wiki enabled, but have no pages. So,
|
||||
# we can skip the import.
|
||||
if e.message !~ /repository not exported/
|
||||
raise Projects::ImportService::Error, e.message
|
||||
else
|
||||
true
|
||||
errors << { type: :wiki, errors: e.message }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,6 +56,10 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def url
|
||||
raw_data.url
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assigned?
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
module Gitlab
|
||||
module GitoriousImport
|
||||
GITORIOUS_HOST = "https://gitorious.org"
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
module Gitlab
|
||||
module GitoriousImport
|
||||
class Client
|
||||
attr_reader :repo_list
|
||||
|
||||
def initialize(repo_list)
|
||||
@repo_list = repo_list
|
||||
end
|
||||
|
||||
def authorize_url(redirect_uri)
|
||||
"#{GITORIOUS_HOST}/gitlab-import?callback_url=#{redirect_uri}"
|
||||
end
|
||||
|
||||
def repos
|
||||
@repos ||= repo_names.map { |full_name| GitoriousImport::Repository.new(full_name) }
|
||||
end
|
||||
|
||||
def repo(id)
|
||||
repos.find { |repo| repo.id == id }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def repo_names
|
||||
repo_list.to_s.split(',').map(&:strip).reject(&:blank?)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue