summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2016-11-04 22:37:44 +0800
committerLin Jen-Shin <godfat@godfat.org>2016-11-04 22:37:44 +0800
commitfb9a0e5277f9825d7faf991c0600a7247b268fe8 (patch)
tree35000cd71ebf5de840c2c931d2f1c7a9b7357dad
parentce1dc4c25d3464b7a9a1b21d93157c9fed98f705 (diff)
parent5368b9f249485e254a90fe7daa551d61412bee26 (diff)
downloadgitlab-ce-fb9a0e5277f9825d7faf991c0600a7247b268fe8.tar.gz
Merge remote-tracking branch 'upstream/master' into show-status-from-branch
* upstream/master: (35 commits) Only skip group when it's actually a group in the "Share with group" select Fix: Todos Filter Shows All Users Fix: Guest sees some repository details and gets 404 Move shared params to a helper GrapeDSL for project hooks Update commits.scss updated styling commit SHA on branches page + added to changelog change build list height to show 6,5 builds + improve padding of list, with first/last child selectors Ignore builds directory from eslint Add changelog entry Document multiple repository storage paths Allow multiple repository storage shards to be enabled, and automatically round-robin between them Cleaned up global namespace JS Add tip for using Chrome to run and debug teaspoon tests. Add CHANGELOG entry file Add jquery.timeago.js to application.js Update match-regex to fix filename convention Move jquery.timeago to vendor directory Change a bunch of doc links to either relative or https://docs.gitlab.com. Show log corresponding to env in admin/logs ...
-rw-r--r--.eslintignore2
-rw-r--r--.eslintrc2
-rw-r--r--CHANGELOG.md10
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock8
-rw-r--r--README.md4
-rw-r--r--app/assets/javascripts/api.js12
-rw-r--r--app/assets/javascripts/application.js178
-rw-r--r--app/assets/javascripts/awards_handler.js2
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js2
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.es614
-rw-r--r--app/assets/javascripts/gl_form.js2
-rw-r--r--app/assets/javascripts/groups_select.js7
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js75
-rw-r--r--app/assets/javascripts/members.js.es62
-rw-r--r--app/assets/javascripts/project_new.js13
-rw-r--r--app/assets/javascripts/project_select.js4
-rw-r--r--app/assets/javascripts/search.js2
-rw-r--r--app/assets/javascripts/users_select.js4
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss8
-rw-r--r--app/assets/stylesheets/framework/selects.scss6
-rw-r--r--app/assets/stylesheets/pages/commits.scss17
-rw-r--r--app/assets/stylesheets/pages/editor.scss4
-rw-r--r--app/assets/stylesheets/pages/icons.scss12
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss15
-rw-r--r--app/assets/stylesheets/pages/status.scss3
-rw-r--r--app/controllers/admin/application_settings_controller.rb2
-rw-r--r--app/controllers/autocomplete_controller.rb6
-rw-r--r--app/controllers/projects/group_links_controller.rb2
-rw-r--r--app/helpers/application_settings_helper.rb4
-rw-r--r--app/helpers/ci_status_helper.rb4
-rw-r--r--app/helpers/dropdowns_helper.rb2
-rw-r--r--app/models/application_setting.rb39
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/project.rb2
-rw-r--r--app/models/user.rb1
-rw-r--r--app/views/admin/application_settings/_form.html.haml4
-rw-r--r--app/views/admin/logs/show.html.haml2
-rw-r--r--app/views/dashboard/issues.atom.builder2
-rw-r--r--app/views/dashboard/issues.html.haml4
-rw-r--r--app/views/dashboard/todos/index.html.haml2
-rw-r--r--app/views/groups/issues.atom.builder2
-rw-r--r--app/views/groups/issues.html.haml4
-rw-r--r--app/views/layouts/devise.html.haml4
-rw-r--r--app/views/projects/blob/_editor.html.haml8
-rw-r--r--app/views/projects/blob/_upload.html.haml2
-rw-r--r--app/views/projects/branches/_commit.html.haml2
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml2
-rw-r--r--app/views/projects/edit.html.haml4
-rw-r--r--app/views/projects/issues/index.atom.builder2
-rw-r--r--app/views/projects/issues/index.html.haml4
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/tree/_tree_content.html.haml2
-rw-r--r--app/views/shared/icons/_icon_status_canceled.svg (renamed from app/views/shared/icons/_icon_status_cancel.svg)2
-rw-r--r--app/views/shared/icons/_icon_status_created.svg2
-rw-r--r--app/views/shared/icons/_icon_status_skipped.svg1
-rw-r--r--app/views/shared/issuable/_form.html.haml1
-rw-r--r--app/views/shared/issuable/_label_dropdown.html.haml2
-rw-r--r--changelogs/unreleased/22588-todos-filter-shows-all-users.yml4
-rw-r--r--changelogs/unreleased/22947-fix_issues_atom_feed_url.yml4
-rw-r--r--changelogs/unreleased/23961-can-t-share-project-with-groups.yml4
-rw-r--r--changelogs/unreleased/24056-guest-sees-some-project-details-and-gets-404.yml4
-rw-r--r--changelogs/unreleased/24059-round-robin-repository-storage.yml4
-rw-r--r--changelogs/unreleased/24102-cannot-unselect-remove-source-branch-when-editing-merge-request.yml4
-rw-r--r--changelogs/unreleased/fix-invalid-filename-eslint.yml4
-rw-r--r--db/migrate/20161103171205_rename_repository_storage_column.rb29
-rw-r--r--db/schema.rb4
-rw-r--r--doc/administration/img/repository_storages_admin_ui.pngbin17081 -> 54043 bytes
-rw-r--r--doc/administration/logs.md3
-rw-r--r--doc/administration/repository_storages.md3
-rw-r--r--doc/api/groups.md8
-rw-r--r--doc/api/settings.md4
-rw-r--r--doc/ci/docker/using_docker_build.md2
-rw-r--r--doc/development/doc_styleguide.md1
-rw-r--r--doc/development/frontend.md6
-rw-r--r--doc/development/rake_tasks.md8
-rw-r--r--doc/install/installation.md6
-rw-r--r--doc/university/README.md22
-rw-r--r--doc/university/glossary/README.md2
-rw-r--r--doc/university/support/README.md36
-rw-r--r--features/steps/admin/logs.rb2
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/groups.rb3
-rw-r--r--lib/api/project_hooks.rb153
-rw-r--r--lib/api/settings.rb4
-rw-r--r--lib/gitlab/environment_logger.rb (renamed from lib/gitlab/production_logger.rb)4
-rw-r--r--lib/tasks/gitlab/generate_docs.rake7
-rw-r--r--spec/bin/changelog_spec.rb56
-rw-r--r--spec/features/admin/admin_runners_spec.rb27
-rw-r--r--spec/features/atom/dashboard_issues_spec.rb11
-rw-r--r--spec/features/atom/issues_spec.rb29
-rw-r--r--spec/features/commits_spec.rb8
-rw-r--r--spec/features/dashboard_issues_spec.rb20
-rw-r--r--spec/features/issues/filter_issues_spec.rb34
-rw-r--r--spec/features/merge_requests/edit_mr_spec.rb14
-rw-r--r--spec/features/projects/builds_spec.rb38
-rw-r--r--spec/features/projects/features_visibility_spec.rb15
-rw-r--r--spec/features/todos/todos_filtering_spec.rb53
-rw-r--r--spec/javascripts/merge_request_widget_spec.js2
-rw-r--r--spec/models/application_setting_spec.rb56
-rw-r--r--spec/models/project_spec.rb15
-rw-r--r--spec/models/user_spec.rb14
-rw-r--r--spec/requests/api/groups_spec.rb13
-rw-r--r--spec/requests/api/merge_request_diffs_spec.rb32
-rw-r--r--spec/requests/api/merge_requests_spec.rb16
-rw-r--r--spec/requests/api/settings_spec.rb1
-rw-r--r--spec/requests/ci/api/builds_spec.rb25
-rw-r--r--spec/requests/ci/api/runners_spec.rb10
-rw-r--r--vendor/assets/javascripts/jquery.timeago.js (renamed from app/assets/javascripts/lib/utils/jquery.timeago.js)0
109 files changed, 878 insertions, 486 deletions
diff --git a/.eslintignore b/.eslintignore
index a57137b4d70..d9c2233c9d7 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,4 +2,4 @@
/public/
/tmp/
/vendor/
-
+/builds/
diff --git a/.eslintrc b/.eslintrc
index b58007d90a9..fd26215b843 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -4,7 +4,7 @@
"filenames"
],
"rules": {
- "filenames/match-regex": [2, "^[a-z_]+$"]
+ "filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"]
},
"globals": {
"$": false,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7efa9efa4f8..9411cc62003 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ entry.
## 8.14.0 (2016-11-22)
+- Show correct environment log in admin/logs (@duk3luk3 !7191)
- Fix Milestone dropdown not stay selected for `Upcoming` and `No Milestone` option !7117
- Backups do not fail anymore when using tar on annex and custom_hooks only. !5814
- Adds user project membership expired event to clarify why user was removed (Callum Dryden)
@@ -17,6 +18,7 @@ entry.
- Fix mobile layout issues in admin user overview page !7087
- Fix HipChat notifications rendering (airatshigapov, eisnerd)
- Remove 'Edit' button from wiki edit view !7143 (Hiroyuki Sato)
+- Cleaned up global namespace JS !19661 (Jose Ivan Vargas)
- Refactor Jira service to use jira-ruby gem
- Improved todos empty state
- Add hover to trash icon in notes !7008 (blackst0ne)
@@ -26,6 +28,7 @@ entry.
- Fix sidekiq stats in admin area (blackst0ne)
- Added label description as tooltip to issue board list title
- Created cycle analytics bundle JavaScript file
+- Hides container registry when repository is disabled
- API: Fix booleans not recognized as such when using the `to_boolean` helper
- Removed delete branch tooltip !6954
- Stop unauthorized users dragging on milestone page (blackst0ne)
@@ -45,6 +48,8 @@ entry.
- New issue board list dropdown stays open after adding a new list
- Fix: Backup restore doesn't clear cache
- Optimize Event queries by removing default order
+- Add new icon for skipped builds
+- Show created icon in pipeline mini-graph
- Remove duplicate links from sidebar
- API: Fix project deploy keys 400 and 500 errors when adding an existing key. !6784 (Joshua Welsh)
- Add Rake task to create/repair GitLab Shell hooks symlinks !5634
@@ -62,11 +67,16 @@ entry.
- Improve search query parameter naming in /admin/users !7115 (YarNayar)
- Fix table pagination to be responsive
- Allow to search for user by secondary email address in the admin interface(/admin/users) !7115 (YarNayar)
+- Updated commit SHA styling on the branches page.
## 8.13.3 (2016-11-02)
- Removes any symlinks before importing a project export file. CVE-2016-9086
- Fixed Import/Export foreign key issue to do with project members.
+- Fix relative links in Markdown wiki when displayed in "Project" tab !7218
+- Reduce the overhead to calculate number of open/closed issues and merge requests within the group or project
+- Fix project features default values
+- Changed build dropdown list length to be 6,5 builds long in the pipeline graph
## 8.13.2 (2016-10-31)
diff --git a/Gemfile b/Gemfile
index af82ae16a56..78748d0e9f8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -104,7 +104,7 @@ gem 'deckar01-task_list', '1.0.5', require: 'task_list/railtie'
gem 'gitlab-markup', '~> 1.5.0'
gem 'redcarpet', '~> 3.3.3'
gem 'RedCloth', '~> 4.3.2'
-gem 'rdoc', '~>3.6'
+gem 'rdoc', '~> 4.2'
gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
@@ -260,9 +260,6 @@ group :development do
gem 'better_errors', '~> 1.0.1'
gem 'binding_of_caller', '~> 0.7.2'
- # Docs generator
- gem 'sdoc', '~> 0.3.20'
-
# thin instead webrick
gem 'thin', '~> 1.7.0'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 888fa6b2bf5..3ecff5f6a68 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -567,7 +567,7 @@ GEM
ffi (>= 0.5.0)
rblineprof (0.3.6)
debugger-ruby_core_source (~> 1.3)
- rdoc (3.12.2)
+ rdoc (4.2.2)
json (~> 1.4)
recaptcha (3.0.0)
json
@@ -663,9 +663,6 @@ GEM
scss_lint (0.47.1)
rake (>= 0.9, < 11)
sass (~> 3.4.15)
- sdoc (0.3.20)
- json (>= 1.1.3)
- rdoc (~> 3.10)
seed-fu (2.3.6)
activerecord (>= 3.1)
activesupport (>= 3.1)
@@ -936,7 +933,7 @@ DEPENDENCIES
rails-deprecated_sanitizer (~> 1.0.3)
rainbow (~> 2.1.0)
rblineprof (~> 0.3.6)
- rdoc (~> 3.6)
+ rdoc (~> 4.2)
recaptcha (~> 3.0)
redcarpet (~> 3.3.3)
redis (~> 3.2)
@@ -956,7 +953,6 @@ DEPENDENCIES
sanitize (~> 2.0)
sass-rails (~> 5.0.6)
scss_lint (~> 0.47.0)
- sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
sentry-raven (~> 2.0.0)
diff --git a/README.md b/README.md
index 46492f4b9c8..dbe6db3ebed 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,7 @@ GitLab is a Ruby on Rails application that runs on the following software:
- Redis 2.8+
- MySQL or PostgreSQL
-For more information please see the [architecture documentation](http://doc.gitlab.com/ce/development/architecture.html).
+For more information please see the [architecture documentation](https://docs.gitlab.com/ce/development/architecture.html).
## Third-party applications
@@ -96,7 +96,7 @@ For upgrading information please see our [update page](https://about.gitlab.com/
## Documentation
-All documentation can be found on [doc.gitlab.com/ce/](http://doc.gitlab.com/ce/).
+All documentation can be found on [docs.gitlab.com/ce/](https://docs.gitlab.com/ce/).
## Getting help
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 7ebe1599fca..1cab66e109e 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -22,16 +22,14 @@
});
},
// Return groups list. Filtered by query
- // Only active groups retrieved
- groups: function(query, skip_ldap, skip_groups, callback) {
+ groups: function(query, options, callback) {
var url = Api.buildUrl(Api.groupsPath);
return $.ajax({
url: url,
- data: {
- search: query,
- skip_groups: skip_groups,
- per_page: 20
- },
+ data: $.extend({
+ search: query,
+ per_page: 20
+ }, options),
dataType: "json"
}).done(function(groups) {
return callback(groups);
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 7dd9adac736..7d942de0184 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -13,6 +13,7 @@
/*= require jquery-ui/sortable */
/*= require jquery_ujs */
/*= require jquery.endless-scroll */
+/*= require jquery.timeago */
/*= require jquery.highlight */
/*= require jquery.waitforimages */
/*= require jquery.atwho */
@@ -54,125 +55,53 @@
/*= require_directory . */
/*= require fuzzaldrin-plus */
-(function() {
- window.slugify = function(text) {
- return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase();
- };
-
- window.ajaxGet = function(url) {
- return $.ajax({
- type: "GET",
- url: url,
- dataType: "script"
- });
- };
-
- window.split = function(val) {
- return val.split(/,\s*/);
- };
-
- window.extractLast = function(term) {
- return split(term).pop();
- };
-
- window.rstrip = function(val) {
- if (val) {
- return val.replace(/\s+$/, '');
- } else {
- return val;
- }
- };
-
- // Disable button if text field is empty
- window.disableButtonIfEmptyField = function(field_selector, button_selector, event_name) {
- event_name = event_name || 'input';
- var closest_submit, field;
- field = $(field_selector);
- closest_submit = field.closest('form').find(button_selector);
- if (rstrip(field.val()) === "") {
- closest_submit.disable();
- }
- return field.on(event_name, function() {
- if (rstrip($(this).val()) === "") {
- return closest_submit.disable();
- } else {
- return closest_submit.enable();
- }
- });
- };
+(function () {
+ document.addEventListener('page:fetch', gl.utils.cleanupBeforeFetch);
+ window.addEventListener('hashchange', gl.utils.shiftWindow);
- // Disable button if any input field with given selector is empty
- window.disableButtonIfAnyEmptyField = function(form, form_selector, button_selector) {
- var closest_submit, updateButtons;
- closest_submit = form.find(button_selector);
- updateButtons = function() {
- var filled;
- filled = true;
- form.find('input').filter(form_selector).each(function() {
- return filled = rstrip($(this).val()) !== "" || !$(this).attr('required');
- });
- if (filled) {
- return closest_submit.enable();
- } else {
- return closest_submit.disable();
- }
- };
- updateButtons();
- return form.keyup(updateButtons);
- };
-
- window.sanitize = function(str) {
- return str.replace(/<(?:.|\n)*?>/gm, '');
- };
-
- window.shiftWindow = function() {
- return scrollBy(0, -100);
- };
-
- document.addEventListener("page:fetch", gl.utils.cleanupBeforeFetch);
-
- window.addEventListener("hashchange", shiftWindow);
-
- window.onload = function() {
+ window.onload = function () {
// Scroll the window to avoid the topnav bar
// https://github.com/twitter/bootstrap/issues/1768
if (location.hash) {
- return setTimeout(shiftWindow, 100);
+ return setTimeout(gl.utils.shiftWindow, 100);
}
};
- $(function() {
- var $body, $document, $sidebarGutterToggle, $window, bootstrapBreakpoint, checkInitialSidebarSize, fitSidebarForSize, flash;
- $document = $(document);
- $window = $(window);
- $body = $('body');
+ $(function () {
+ var $body = $('body');
+ var $document = $(document);
+ var $window = $(window);
+ var $sidebarGutterToggle = $('.js-sidebar-toggle');
+ var $flash = $('.flash-container');
+ var bootstrapBreakpoint = bp.getBreakpointSize();
+ var checkInitialSidebarSize;
+ var fitSidebarForSize;
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';
gl.utils.preventDisabledButtons();
- bootstrapBreakpoint = bp.getBreakpointSize();
- $(".nav-sidebar").niceScroll({
+ $('.nav-sidebar').niceScroll({
cursoropacitymax: '0.4',
cursorcolor: '#FFF',
- cursorborder: "1px solid #FFF"
+ cursorborder: '1px solid #FFF'
});
- $(".js-select-on-focus").on("focusin", function() {
- return $(this).select().one('mouseup', function(e) {
+ $('.js-select-on-focus').on('focusin', function () {
+ return $(this).select().one('mouseup', function (e) {
return e.preventDefault();
});
// Click a .js-select-on-focus field, select the contents
// Prevent a mouseup event from deselecting the input
});
- $('.remove-row').bind('ajax:success', function() {
+ $('.remove-row').bind('ajax:success', function () {
$(this).tooltip('destroy')
.closest('li')
.fadeOut();
});
- $('.js-remove-tr').bind('ajax:before', function() {
+ $('.js-remove-tr').bind('ajax:before', function () {
return $(this).hide();
});
- $('.js-remove-tr').bind('ajax:success', function() {
+ $('.js-remove-tr').bind('ajax:success', function () {
return $(this).closest('tr').fadeOut();
});
$('select.select2').select2({
@@ -180,8 +109,8 @@
// Initialize select2 selects
dropdownAutoWidth: true
});
- $('.js-select2').bind('select2-close', function() {
- return setTimeout((function() {
+ $('.js-select2').bind('select2-close', function () {
+ return setTimeout((function () {
$('.select2-container-active').removeClass('select2-container-active');
return $(':focus').blur();
}), 1);
@@ -191,24 +120,24 @@
$.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover';
$body.tooltip({
selector: '.has-tooltip, [data-toggle="tooltip"]',
- placement: function(_, el) {
+ placement: function (_, el) {
return $(el).data('placement') || 'bottom';
}
});
- $('.trigger-submit').on('change', function() {
+ $('.trigger-submit').on('change', function () {
return $(this).parents('form').submit();
// Form submitter
});
gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true);
// Flash
- if ((flash = $(".flash-container")).length > 0) {
- flash.click(function() {
+ if ($flash.length > 0) {
+ $flash.click(function () {
return $(this).fadeOut();
});
- flash.show();
+ $flash.show();
}
// Disable form buttons while a form is submitting
- $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function(e) {
+ $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function (e) {
var buttons;
buttons = $('[type="submit"]', this);
switch (e.type) {
@@ -219,36 +148,36 @@
return buttons.enable();
}
});
- $(document).ajaxError(function(e, xhrObj, xhrSetting, xhrErrorText) {
- var ref;
+ $(document).ajaxError(function (e, xhrObj) {
+ var ref = xhrObj.status;
if (xhrObj.status === 401) {
return new Flash('You need to be logged in.', 'alert');
- } else if ((ref = xhrObj.status) === 404 || ref === 500) {
+ } else if (ref === 404 || ref === 500) {
return new Flash('Something went wrong on our end.', 'alert');
}
});
- $('.account-box').hover(function() {
+ $('.account-box').hover(function () {
// Show/Hide the profile menu when hovering the account box
return $(this).toggleClass('hover');
});
- $document.on('click', '.diff-content .js-show-suppressed-diff', function() {
+ $document.on('click', '.diff-content .js-show-suppressed-diff', function () {
var $container;
$container = $(this).parent();
$container.next('table').show();
return $container.remove();
// Commit show suppressed diff
});
- $('.navbar-toggle').on('click', function() {
+ $('.navbar-toggle').on('click', function () {
$('.header-content .title').toggle();
$('.header-content .header-logo').toggle();
$('.header-content .navbar-collapse').toggle();
return $('.navbar-toggle').toggleClass('active');
});
// Show/hide comments on diff
- $body.on("click", ".js-toggle-diff-comments", function(e) {
+ $body.on('click', '.js-toggle-diff-comments', function (e) {
var $this = $(this);
- $this.toggleClass('active');
var notesHolders = $this.closest('.diff-file').find('.notes_holder');
+ $this.toggleClass('active');
if ($this.hasClass('active')) {
notesHolders.show().find('.hide').show();
} else {
@@ -257,30 +186,27 @@
$this.trigger('blur');
return e.preventDefault();
});
- $document.off("click", '.js-confirm-danger');
- $document.on("click", '.js-confirm-danger', function(e) {
- var btn, form, text;
+ $document.off('click', '.js-confirm-danger');
+ $document.on('click', '.js-confirm-danger', function (e) {
+ var btn = $(e.target);
+ var form = btn.closest('form');
+ var text = btn.data('confirm-danger-message');
e.preventDefault();
- btn = $(e.target);
- text = btn.data("confirm-danger-message");
- form = btn.closest("form");
return new ConfirmDangerModal(form, text);
});
- $document.on('click', 'button', function() {
+ $document.on('click', 'button', function () {
return $(this).blur();
});
- $('input[type="search"]').each(function() {
- var $this;
- $this = $(this);
+ $('input[type="search"]').each(function () {
+ var $this = $(this);
$this.attr('value', $this.val());
});
- $document.off('keyup', 'input[type="search"]').on('keyup', 'input[type="search"]', function(e) {
+ $document.off('keyup', 'input[type="search"]').on('keyup', 'input[type="search"]', function () {
var $this;
$this = $(this);
return $this.attr('value', $this.val());
});
- $sidebarGutterToggle = $('.js-sidebar-toggle');
- $document.off('breakpoint:change').on('breakpoint:change', function(e, breakpoint) {
+ $document.off('breakpoint:change').on('breakpoint:change', function (e, breakpoint) {
var $gutterIcon;
if (breakpoint === 'sm' || breakpoint === 'xs') {
$gutterIcon = $sidebarGutterToggle.find('i');
@@ -289,7 +215,7 @@
}
}
});
- fitSidebarForSize = function() {
+ fitSidebarForSize = function () {
var oldBootstrapBreakpoint;
oldBootstrapBreakpoint = bootstrapBreakpoint;
bootstrapBreakpoint = bp.getBreakpointSize();
@@ -297,13 +223,13 @@
return $document.trigger('breakpoint:change', [bootstrapBreakpoint]);
}
};
- checkInitialSidebarSize = function() {
+ checkInitialSidebarSize = function () {
bootstrapBreakpoint = bp.getBreakpointSize();
- if (bootstrapBreakpoint === "xs" || "sm") {
+ if (bootstrapBreakpoint === 'xs' || 'sm') {
return $document.trigger('breakpoint:change', [bootstrapBreakpoint]);
}
};
- $window.off("resize.app").on("resize.app", function(e) {
+ $window.off('resize.app').on('resize.app', function () {
return fitSidebarForSize();
});
gl.awardsHandler = new AwardsHandler();
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index 8bdb0965f99..d7cda977845 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -1,7 +1,7 @@
/* eslint-disable */
(function() {
this.AwardsHandler = (function() {
- const FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence
+ var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence
function AwardsHandler() {
this.aliases = gl.emojiAliases();
$(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) {
diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js
index 230a1b95c52..143d21adb37 100644
--- a/app/assets/javascripts/confirm_danger_modal.js
+++ b/app/assets/javascripts/confirm_danger_modal.js
@@ -12,7 +12,7 @@
submit.disable();
$('.js-confirm-danger-input').off('input');
$('.js-confirm-danger-input').on('input', function() {
- if (rstrip($(this).val()) === project_path) {
+ if (gl.utils.rstrip($(this).val()) === project_path) {
return submit.enable();
} else {
return submit.disable();
diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js.es6
index 31df51ac03a..824413bf20f 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.es6
+++ b/app/assets/javascripts/gfm_auto_complete.js.es6
@@ -126,8 +126,8 @@
}
return {
username: m.username,
- title: sanitize(title),
- search: sanitize(m.username + " " + m.name)
+ title: gl.utils.sanitize(title),
+ search: gl.utils.sanitize(m.username + " " + m.name)
};
});
}
@@ -159,7 +159,7 @@
}
return {
id: i.iid,
- title: sanitize(i.title),
+ title: gl.utils.sanitize(i.title),
search: i.iid + " " + i.title
};
});
@@ -189,7 +189,7 @@
}
return {
id: m.iid,
- title: sanitize(m.title),
+ title: gl.utils.sanitize(m.title),
search: "" + m.title
};
});
@@ -222,7 +222,7 @@
}
return {
id: m.iid,
- title: sanitize(m.title),
+ title: gl.utils.sanitize(m.title),
search: m.iid + " " + m.title
};
});
@@ -240,9 +240,9 @@
var sanitizeLabelTitle;
sanitizeLabelTitle = function(title) {
if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) {
- return "\"" + (sanitize(title)) + "\"";
+ return "\"" + (gl.utils.sanitize(title)) + "\"";
} else {
- return sanitize(title);
+ return gl.utils.sanitize(title);
}
};
return $.map(merges, function(m) {
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index 742807d93ad..ce54c34492d 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -24,8 +24,8 @@
if (isNewForm) {
this.form.find('.div-dropzone').remove();
this.form.addClass('gfm-form');
- disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
// remove notify commit author checkbox for non-commit notes
+ gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
GitLab.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
new DropzoneInput(this.form);
autosize(this.textarea);
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index b275620c799..e3c39c895ba 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -6,15 +6,16 @@
function GroupsSelect() {
$('.ajax-groups-select').each((function(_this) {
return function(i, select) {
- var skip_ldap, skip_groups;
- skip_ldap = $(select).hasClass('skip_ldap');
+ var all_available, skip_groups;
+ all_available = $(select).data('all-available');
skip_groups = $(select).data('skip-groups') || [];
return $(select).select2({
placeholder: "Search for a group",
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query: function(query) {
- return Api.groups(query.term, skip_ldap, skip_groups, function(groups) {
+ options = { all_available: all_available, skip_groups: skip_groups };
+ return Api.groups(query.term, options, function(groups) {
var data;
data = {
results: groups
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 21efe2d76dd..8447421195d 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -24,6 +24,81 @@
return null;
}
};
+
+ w.gl.utils.ajaxGet = function(url) {
+ return $.ajax({
+ type: "GET",
+ url: url,
+ dataType: "script"
+ });
+ };
+
+ w.gl.utils.split = function(val) {
+ return val.split(/,\s*/);
+ };
+
+ w.gl.utils.extractLast = function(term) {
+ return this.split(term).pop();
+ };
+
+ w.gl.utils.rstrip = function rstrip(val) {
+ if (val) {
+ return val.replace(/\s+$/, '');
+ } else {
+ return val;
+ }
+ };
+
+ w.gl.utils.disableButtonIfEmptyField = function(field_selector, button_selector, event_name) {
+ event_name = event_name || 'input';
+ var closest_submit, field, that;
+ that = this;
+ field = $(field_selector);
+ closest_submit = field.closest('form').find(button_selector);
+ if (this.rstrip(field.val()) === "") {
+ closest_submit.disable();
+ }
+ return field.on(event_name, function() {
+ if (that.rstrip($(this).val()) === "") {
+ return closest_submit.disable();
+ } else {
+ return closest_submit.enable();
+ }
+ });
+ };
+
+ w.gl.utils.disableButtonIfAnyEmptyField = function(form, form_selector, button_selector) {
+ var closest_submit, updateButtons;
+ closest_submit = form.find(button_selector);
+ updateButtons = function() {
+ var filled;
+ filled = true;
+ form.find('input').filter(form_selector).each(function() {
+ return filled = this.rstrip($(this).val()) !== "" || !$(this).attr('required');
+ });
+ if (filled) {
+ return closest_submit.enable();
+ } else {
+ return closest_submit.disable();
+ }
+ };
+ updateButtons();
+ return form.keyup(updateButtons);
+ };
+
+ w.gl.utils.sanitize = function(str) {
+ return str.replace(/<(?:.|\n)*?>/gm, '');
+ };
+
+ w.gl.utils.unbindEvents = function() {
+ return $(document).off('scroll');
+ };
+
+ w.gl.utils.shiftWindow = function() {
+ return w.scrollBy(0, -100);
+ };
+
+
gl.utils.updateTooltipTitle = function($tooltipEl, newTitle) {
return $tooltipEl.tooltip('destroy').attr('title', newTitle).tooltip('fixTitle');
};
diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js.es6
index 371abd09e78..895bc10784f 100644
--- a/app/assets/javascripts/members.js.es6
+++ b/app/assets/javascripts/members.js.es6
@@ -11,7 +11,7 @@
$('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow);
$('.js-member-update-control').off('change').on('change', this.formSubmit);
$('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess);
- disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change');
+ gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change');
}
removeRow(e) {
diff --git a/app/assets/javascripts/project_new.js b/app/assets/javascripts/project_new.js
index 40575caa57f..0d3fb31a9cf 100644
--- a/app/assets/javascripts/project_new.js
+++ b/app/assets/javascripts/project_new.js
@@ -45,7 +45,9 @@
};
ProjectNew.prototype.toggleRepoVisibility = function () {
- var $repoAccessLevel = $('.js-repo-access-level select');
+ var $repoAccessLevel = $('.js-repo-access-level select'),
+ containerRegistry = document.querySelectorAll('.js-container-registry')[0],
+ containerRegistryCheckbox = document.getElementById('project_container_registry_enabled');
this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']")
.nextAll()
@@ -70,8 +72,17 @@
if (selectedVal) {
this.$repoSelects.removeClass('disabled');
+
+ if (containerRegistry) {
+ containerRegistry.style.display = '';
+ }
} else {
this.$repoSelects.addClass('disabled');
+
+ if (containerRegistry) {
+ containerRegistry.style.display = 'none';
+ containerRegistryCheckbox.checked = false;
+ }
}
}.bind(this));
};
diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js
index b74b4ae68ff..e1acf3c8232 100644
--- a/app/assets/javascripts/project_select.js
+++ b/app/assets/javascripts/project_select.js
@@ -24,7 +24,7 @@
data = groups.concat(projects);
return finalCallback(data);
};
- return Api.groups(term, false, false, groupsCallback);
+ return Api.groups(term, {}, groupsCallback);
};
} else {
projectsCallback = finalCallback;
@@ -73,7 +73,7 @@
data = groups.concat(projects);
return finalCallback(data);
};
- return Api.groups(query.term, false, false, groupsCallback);
+ return Api.groups(query.term, {}, groupsCallback);
};
} else {
projectsCallback = finalCallback;
diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js
index 6c2389f202f..d79e6f014f6 100644
--- a/app/assets/javascripts/search.js
+++ b/app/assets/javascripts/search.js
@@ -11,7 +11,7 @@
filterable: true,
fieldName: 'group_id',
data: function(term, callback) {
- return Api.groups(term, false, false, function(data) {
+ return Api.groups(term, {}, function(data) {
data.unshift({
name: 'Any'
});
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index 3847278e80a..7a2221dbaf5 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -23,6 +23,8 @@
$dropdown = $(dropdown);
options.projectId = $dropdown.data('project-id');
options.showCurrentUser = $dropdown.data('current-user');
+ options.todoFilter = $dropdown.data('todo-filter');
+ options.todoStateFilter = $dropdown.data('todo-state-filter');
showNullUser = $dropdown.data('null-user');
showMenuAbove = $dropdown.data('showMenuAbove');
showAnyUser = $dropdown.data('any-user');
@@ -394,6 +396,8 @@
project_id: options.projectId || null,
group_id: options.groupId || null,
skip_ldap: options.skipLdap || null,
+ todo_filter: options.todoFilter || null,
+ todo_state_filter: options.todoStateFilter || null,
current_user: options.showCurrentUser || null,
push_code_to_protected_branches: options.pushCodeToProtectedBranches || null,
author_id: options.authorId || null,
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index baa38ab60c8..3e34ec98427 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -36,7 +36,7 @@
color: $dropdown-toggle-color;
font-size: 15px;
text-align: left;
- border: 1px solid $dropdown-toggle-border-color;
+ border: 1px solid $border-color;
border-radius: $border-radius-base;
outline: 0;
text-overflow: ellipsis;
@@ -45,11 +45,9 @@
.fa {
position: absolute;
- top: 50%;
- right: 6px;
- margin-top: -6px;
+ top: 10px;
+ right: 8px;
color: $dropdown-toggle-icon-color;
- font-size: 10px;
&.fa-spinner {
font-size: 16px;
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index ecdf0be1a05..13749f1b7bd 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -27,9 +27,9 @@
height: 0;
margin-left: 2px;
vertical-align: middle;
- border-top: $caret-width-base dashed;
- border-right: $caret-width-base solid transparent;
- border-left: $caret-width-base solid transparent;
+ border-top: 5px dashed;
+ border-right: 5px solid transparent;
+ border-left: 5px solid transparent;
color: $gray-darkest;
}
}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 52d6a39bd59..98a84351a3d 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -164,7 +164,22 @@
.branch-commit {
color: $gl-gray;
- .commit-id,
+ .commit-icon {
+ text-align: center;
+ display: inline-block;
+
+ svg {
+ height: 14px;
+ width: 14px;
+ vertical-align: middle;
+ fill: $table-text-gray;
+ }
+ }
+
+ .commit-id {
+ color: $gl-link-color;
+ }
+
.commit-row-message {
color: $gl-gray;
}
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index cb8cefaca97..778126bcfb7 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -55,6 +55,10 @@
float: left;
}
+ .file-buttons {
+ font-size: 0;
+ }
+
.select2 {
float: right;
}
diff --git a/app/assets/stylesheets/pages/icons.scss b/app/assets/stylesheets/pages/icons.scss
new file mode 100644
index 00000000000..407c8db211d
--- /dev/null
+++ b/app/assets/stylesheets/pages/icons.scss
@@ -0,0 +1,12 @@
+// CI icon colors
+
+.ci-status-icon {
+ &-created {
+ fill: $gray-darkest;
+ }
+
+ &-skipped,
+ &-canceled {
+ fill: $gl-text-color;
+ }
+}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index a8e8bbcb208..bf3cb6e7ad9 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -85,6 +85,11 @@
}
.commit-link {
+ a {
+ &:focus {
+ text-decoration: none;
+ }
+ }
.ci-status {
@@ -439,7 +444,7 @@
}
.grouped-pipeline-dropdown {
- padding: 8px 0;
+ padding: 0;
width: 186px;
left: auto;
right: -197px;
@@ -448,6 +453,14 @@
ul {
max-height: 245px;
overflow: auto;
+
+ li:first-child {
+ padding-top: 8px;
+ }
+
+ li:last-child {
+ padding-bottom: 8px;
+ }
}
a {
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index 01426e28e92..92997eae8b9 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -6,7 +6,8 @@
white-space: nowrap;
border-radius: 4px;
- &:hover {
+ &:hover,
+ &:focus {
text-decoration: none;
}
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 6ef7cf0bae6..86e808314f4 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -116,8 +116,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_packet_size,
:send_user_confirmation_email,
:container_registry_token_expire_delay,
- :repository_storage,
:enabled_git_access_protocol,
+ repository_storages: [],
restricted_visibility_levels: [],
import_sources: [],
disabled_oauth_sign_in_sources: []
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index b48668eea87..daa82336208 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -11,9 +11,13 @@ class AutocompleteController < ApplicationController
@users = @users.reorder(:name)
@users = @users.page(params[:page])
+ if params[:todo_filter].present?
+ @users = @users.todo_authors(current_user.id, params[:todo_state_filter])
+ end
+
if params[:search].blank?
# Include current user if available to filter by "Me"
- if params[:current_user] && current_user
+ if params[:current_user].present? && current_user
@users = [*@users, current_user]
end
diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb
index ae060abee5c..9eaf26a0dbf 100644
--- a/app/controllers/projects/group_links_controller.rb
+++ b/app/controllers/projects/group_links_controller.rb
@@ -7,7 +7,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
@group_links = project.project_group_links.all
@skip_groups = @group_links.pluck(:group_id)
- @skip_groups << project.group.try(:id)
+ @skip_groups << project.namespace_id unless project.personal?
end
def create
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 6229384817b..45a567a1eba 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -93,11 +93,11 @@ module ApplicationSettingsHelper
end
end
- def repository_storage_options_for_select
+ def repository_storages_options_for_select
options = Gitlab.config.repositories.storages.map do |name, path|
["#{name} - #{path}", name]
end
- options_for_select(options, @application_setting.repository_storage)
+ options_for_select(options, @application_setting.repository_storages)
end
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 3decedace4f..895c3d728ad 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -47,8 +47,10 @@ module CiStatusHelper
'icon_play'
when 'created'
'icon_status_created'
+ when 'skipped'
+ 'icon_status_skipped'
else
- 'icon_status_cancel'
+ 'icon_status_canceled'
end
custom_icon(icon_name)
diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb
index 81e0b6bb5ae..cbab1fd5967 100644
--- a/app/helpers/dropdowns_helper.rb
+++ b/app/helpers/dropdowns_helper.rb
@@ -43,7 +43,7 @@ module DropdownsHelper
default_label = data_attr[:default_label]
content_tag(:button, class: "dropdown-menu-toggle #{options[:toggle_class] if options.has_key?(:toggle_class)}", id: (options[:id] if options.has_key?(:id)), type: "button", data: data_attr) do
output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}")
- output << icon('chevron-down')
+ output << icon('caret-down')
output.html_safe
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index c99aa7772bb..6e7a90e7d9c 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -18,6 +18,7 @@ class ApplicationSetting < ActiveRecord::Base
serialize :disabled_oauth_sign_in_sources, Array
serialize :domain_whitelist, Array
serialize :domain_blacklist, Array
+ serialize :repository_storages
cache_markdown_field :sign_in_text
cache_markdown_field :help_page_text
@@ -74,9 +75,8 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
numericality: { only_integer: true, greater_than: 0 }
- validates :repository_storage,
- presence: true,
- inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
+ validates :repository_storages, presence: true
+ validate :check_repository_storages
validates :enabled_git_access_protocol,
inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true }
@@ -166,7 +166,7 @@ class ApplicationSetting < ActiveRecord::Base
disabled_oauth_sign_in_sources: [],
send_user_confirmation_email: false,
container_registry_token_expire_delay: 5,
- repository_storage: 'default',
+ repository_storages: ['default'],
user_default_external: false,
)
end
@@ -201,6 +201,29 @@ class ApplicationSetting < ActiveRecord::Base
self.domain_blacklist_raw = file.read
end
+ def repository_storages
+ value = read_attribute(:repository_storages)
+ value = [value] if value.is_a?(String)
+ value = [] if value.nil?
+
+ value
+ end
+
+ # repository_storage is still required in the API. Remove in 9.0
+ def repository_storage
+ repository_storages.first
+ end
+
+ def repository_storage=(value)
+ self.repository_storages = [value]
+ end
+
+ # Choose one of the available repository storage options. Currently all have
+ # equal weighting.
+ def pick_repository_storage
+ repository_storages.sample
+ end
+
def runners_registration_token
ensure_runners_registration_token!
end
@@ -208,4 +231,12 @@ class ApplicationSetting < ActiveRecord::Base
def health_check_access_token
ensure_health_check_access_token!
end
+
+ private
+
+ def check_repository_storages
+ invalid = repository_storages - Gitlab.config.repositories.storages.keys
+ errors.add(:repository_storages, "can't include: #{invalid.join(", ")}") unless
+ invalid.empty?
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 0397c57f935..6b8ac3fb48b 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -441,11 +441,11 @@ class MergeRequest < ActiveRecord::Base
end
def should_remove_source_branch?
- merge_params['should_remove_source_branch'].present?
+ Gitlab::Utils.to_boolean(merge_params['should_remove_source_branch'])
end
def force_remove_source_branch?
- merge_params['force_remove_source_branch'].present?
+ Gitlab::Utils.to_boolean(merge_params['force_remove_source_branch'])
end
def remove_source_branch?
diff --git a/app/models/project.rb b/app/models/project.rb
index d5512dfaf9c..cf931f64c03 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -28,7 +28,7 @@ class Project < ActiveRecord::Base
default_value_for :archived, false
default_value_for :visibility_level, gitlab_config_features.visibility_level
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
- default_value_for(:repository_storage) { current_application_settings.repository_storage }
+ default_value_for(:repository_storage) { current_application_settings.pick_repository_storage }
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
default_value_for :issues_enabled, gitlab_config_features.issues
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
diff --git a/app/models/user.rb b/app/models/user.rb
index af3c0b7dc02..65e96ee6b2e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -173,6 +173,7 @@ class User < ActiveRecord::Base
scope :active, -> { with_state(:active) }
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
+ scope :todo_authors, ->(user_id, state) { where(id: Todo.where(user_id: user_id, state: state).select(:author_id)) }
def self.with_two_factor
joins("LEFT OUTER JOIN u2f_registrations AS u2f ON u2f.user_id = users.id").
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index c4c68cd7891..28003e5f509 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -353,9 +353,9 @@
%fieldset
%legend Repository Storage
.form-group
- = f.label :repository_storage, 'Storage path for new projects', class: 'control-label col-sm-2'
+ = f.label :repository_storages, 'Storage paths for new projects', class: 'control-label col-sm-2'
.col-sm-10
- = f.select :repository_storage, repository_storage_options_for_select, {}, class: 'form-control'
+ = f.select :repository_storages, repository_storages_options_for_select, {include_hidden: false}, multiple: true, class: 'form-control'
.help-block
Manage repository storage paths. Learn more in the
= succeed "." do
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index 676812121d7..824edd171f3 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -1,7 +1,7 @@
- @no_container = true
- page_title "Logs"
- loggers = [Gitlab::GitLogger, Gitlab::AppLogger,
- Gitlab::ProductionLogger, Gitlab::SidekiqLogger,
+ Gitlab::EnvironmentLogger, Gitlab::SidekiqLogger,
Gitlab::RepositoryCheckLogger]
= render 'admin/background_jobs/head'
diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder
index 0404d0728ea..bdea1064096 100644
--- a/app/views/dashboard/issues.atom.builder
+++ b/app/views/dashboard/issues.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{current_user.name} issues"
- xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
+ xml.link href: url_for(params), rel: "self", type: "application/atom+xml"
xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url
xml.updated @issues.first.created_at.xmlschema if @issues.reorder(nil).any?
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 1eec4db45a0..3caaf827ff5 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -2,13 +2,13 @@
- header_title "Issues", issues_dashboard_path(assignee_id: current_user.id)
= content_for :meta_tags do
- if current_user
- = auto_discovery_link_tag(:atom, issues_dashboard_url(format: :atom, private_token: current_user.private_token), title: "#{current_user.name} issues")
+ = auto_discovery_link_tag(:atom, url_for(params.merge(format: :atom, private_token: current_user.private_token)), title: "#{current_user.name} issues")
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls
- if current_user
- = link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: 'btn' do
+ = link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn' do
= icon('rss')
%span.icon-label
Subscribe
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 2411cc45724..e247eebc3fc 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -37,7 +37,7 @@
- if params[:author_id].present?
= hidden_field_tag(:author_id, params[:author_id])
= dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit',
- placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author' } })
+ placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author', todo_filter: true, todo_state_filter: params[:state] || 'pending' } })
.filter-item.inline
- if params[:type].present?
= hidden_field_tag(:type, params[:type])
diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder
index b1628040325..0cc6466d34e 100644
--- a/app/views/groups/issues.atom.builder
+++ b/app/views/groups/issues.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@group.name} issues"
- xml.link href: issues_group_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
+ xml.link href: url_for(params), rel: "self", type: "application/atom+xml"
xml.link href: issues_group_url, rel: "alternate", type: "text/html"
xml.id issues_group_url
xml.updated @issues.first.created_at.xmlschema if @issues.reorder(nil).any?
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index 4434f1cbd35..dc6c1bb69de 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -1,13 +1,13 @@
- page_title "Issues"
= content_for :meta_tags do
- if current_user
- = auto_discovery_link_tag(:atom, issues_group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} issues")
+ = auto_discovery_link_tag(:atom, url_for(params.merge(format: :atom, private_token: current_user.private_token)), title: "#{@group.name} issues")
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls
- if current_user
- = link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
+ = link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn' do
= icon('rss')
%span.icon-label
Subscribe
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index 6922f1e153f..afd9958f073 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -26,8 +26,8 @@
Perform code reviews and enhance collaboration with merge requests.
Each project can also have an issue tracker and a wiki.
- - if current_application_settings.sign_in_text.present?
- = markdown_field(current_application_settings, :sign_in_text)
+ - if current_application_settings.sign_in_text.present?
+ = markdown_field(current_application_settings, :sign_in_text)
%hr.footer-fixed
.container.footer-container
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index d4f59764a70..4a6aa92e3f3 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -14,13 +14,13 @@
= text_field_tag 'file_name', params[:file_name], placeholder: "File name",
required: true, class: 'form-control new-file-name'
- .pull-right
+ .pull-right.file-buttons
.license-selector.js-license-selector-wrap.hidden
- = dropdown_tag("Choose a License template", options: { toggle_class: 'js-license-selector', title: "Choose a license", filter: true, placeholder: "Filter", data: { data: licenses_for_select, project: @project.name, fullname: @project.namespace.human_name } } )
+ = dropdown_tag("Choose a License template", options: { toggle_class: 'btn js-license-selector', title: "Choose a license", filter: true, placeholder: "Filter", data: { data: licenses_for_select, project: @project.name, fullname: @project.namespace.human_name } } )
.gitignore-selector.js-gitignore-selector-wrap.hidden
- = dropdown_tag("Choose a .gitignore template", options: { toggle_class: 'js-gitignore-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } )
+ = dropdown_tag("Choose a .gitignore template", options: { toggle_class: 'btn js-gitignore-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } )
.gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.hidden
- = dropdown_tag("Choose a GitLab CI Yaml template", options: { toggle_class: 'js-gitlab-ci-yml-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } )
+ = dropdown_tag("Choose a GitLab CI Yaml template", options: { toggle_class: 'btn js-gitlab-ci-yml-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } )
= button_tag class: 'soft-wrap-toggle btn', type: 'button' do
%span.no-wrap
= custom_icon('icon_no_wrap')
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index b1f50eb5f34..57a27ec904e 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -26,6 +26,6 @@
:javascript
- disableButtonIfEmptyField($('.js-upload-blob-form').find('.js-commit-message'), '.btn-upload-file');
+ gl.utils.disableButtonIfEmptyField($('.js-upload-blob-form').find('.js-commit-message'), '.btn-upload-file');
new BlobFileDropzone($('.js-upload-blob-form'), '#{method}');
new NewCommitForm($('.js-upload-blob-form'))
diff --git a/app/views/projects/branches/_commit.html.haml b/app/views/projects/branches/_commit.html.haml
index d54c76ff9c8..de607772df6 100644
--- a/app/views/projects/branches/_commit.html.haml
+++ b/app/views/projects/branches/_commit.html.haml
@@ -1,4 +1,6 @@
.branch-commit
+ .icon-container.commit-icon
+ = custom_icon("icon_commit")
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-id monospace"
&middot;
%span.str-truncated
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index 840f468dc05..1f748d73d06 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -41,7 +41,7 @@
- else
Cant find HEAD commit for this branch
- - stages_status = pipeline.statuses.relevant.latest.stages_status
+ - stages_status = pipeline.statuses.latest.stages_status
%td.stage-cell
- stages.each do |stage|
- status = stages_status[stage]
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index c40ad06969e..a5422966617 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -102,7 +102,7 @@
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
- if Gitlab.config.registry.enabled
- .form-group
+ .form-group.js-container-registry{ style: ("display: none;" if @project.project_feature.send(:repository_access_level) == 0) }
.checkbox
= f.label :container_registry_enabled do
= f.check_box :container_registry_enabled
@@ -290,4 +290,4 @@
Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
-= render 'shared/confirm_modal', phrase: @project.path \ No newline at end of file
+= render 'shared/confirm_modal', phrase: @project.path
diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder
index 36957560de0..a0df0db77c5 100644
--- a/app/views/projects/issues/index.atom.builder
+++ b/app/views/projects/issues/index.atom.builder
@@ -1,7 +1,7 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name} issues"
- xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
+ xml.link href: url_for(params), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_issues_url(@project.namespace, @project)
xml.updated @issues.first.created_at.xmlschema if @issues.reorder(nil).any?
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index cc57cfdb342..c493ff3585b 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -8,7 +8,7 @@
= content_for :meta_tags do
- if current_user
- = auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
+ = auto_discovery_link_tag(:atom, url_for(params.merge(format: :atom, private_token: current_user.private_token)), title: "#{@project.name} issues")
%div{ class: (container_class) }
- if @project.issues.any?
@@ -16,7 +16,7 @@
= render 'shared/issuable/nav', type: :issues
.nav-controls
- if current_user
- = link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
+ = link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn append-right-10' do
= icon('rss')
%span.icon-label
Subscribe
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 69a3bc5f046..4de95036eef 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -12,7 +12,7 @@
= render 'projects/last_push'
= render "home_panel"
-- if @project.feature_available?(:repository, current_user)
+- if current_user && can?(current_user, :download_code, @project)
%nav.project-stats{ class: container_class }
%ul.nav
%li
diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml
index 0f7d629ab98..21e378b8735 100644
--- a/app/views/projects/tree/_tree_content.html.haml
+++ b/app/views/projects/tree/_tree_content.html.haml
@@ -37,5 +37,5 @@
:javascript
// Load last commit log for each file in tree
$('#tree-slider').waitForImages(function() {
- ajaxGet("#{escape_javascript(@logs_path)}");
+ gl.utils.ajaxGet("#{escape_javascript(@logs_path)}");
});
diff --git a/app/views/shared/icons/_icon_status_cancel.svg b/app/views/shared/icons/_icon_status_canceled.svg
index fd1ebbcbabd..1b2d0891244 100644
--- a/app/views/shared/icons/_icon_status_cancel.svg
+++ b/app/views/shared/icons/_icon_status_canceled.svg
@@ -1,4 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" class="ci-status-icon-canceled" viewBox="0 0 14 14">
<g fill="#5C5C5C" fill-rule="evenodd">
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
<rect width="8" height="2" x="3" y="6" transform="rotate(45 7 7)" rx=".5"/>
diff --git a/app/views/shared/icons/_icon_status_created.svg b/app/views/shared/icons/_icon_status_created.svg
index 1f5c3b51b03..dca5d289767 100644
--- a/app/views/shared/icons/_icon_status_created.svg
+++ b/app/views/shared/icons/_icon_status_created.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" enable-background="new 0 0 14 14"><path d="M12.5,7 C12.5,4 10,1.5 7,1.5 C4,1.5 1.5,4 1.5,7 C1.5,10 4,12.5 7,12.5 C10,12.5 12.5,10 12.5,7 L12.5,7 Z M0,7 C0,3.1 3.1,0 7,0 C10.9,0 14,3.1 14,7 C14,10.9 10.9,14 7,14 C3.1,14 0,10.9 0,7 L0,7 Z" /><circle cx="7" cy="7" r="3.25"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" class="ci-status-icon-created" viewBox="0 0 14 14" enable-background="new 0 0 14 14"><path d="M12.5,7 C12.5,4 10,1.5 7,1.5 C4,1.5 1.5,4 1.5,7 C1.5,10 4,12.5 7,12.5 C10,12.5 12.5,10 12.5,7 L12.5,7 Z M0,7 C0,3.1 3.1,0 7,0 C10.9,0 14,3.1 14,7 C14,10.9 10.9,14 7,14 C3.1,14 0,10.9 0,7 L0,7 Z" /><circle cx="7" cy="7" r="3.25"/></svg>
diff --git a/app/views/shared/icons/_icon_status_skipped.svg b/app/views/shared/icons/_icon_status_skipped.svg
new file mode 100644
index 00000000000..014ca86b61b
--- /dev/null
+++ b/app/views/shared/icons/_icon_status_skipped.svg
@@ -0,0 +1 @@
+<svg width="20" height="20" class="ci-status-icon-skipped" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Group Copy 31</title><g fill="#5C5C5C" fill-rule="evenodd"><path d="M10 17.857c4.286 0 7.857-3.571 7.857-7.857S14.286 2.143 10 2.143 2.143 5.714 2.143 10 5.714 17.857 10 17.857M10 0c5.571 0 10 4.429 10 10s-4.429 10-10 10S0 15.571 0 10 4.429 0 10 0"/><path d="M10.986 11l-1.293 1.293a1 1 0 0 0 1.414 1.414l2.644-2.644a1.505 1.505 0 0 0 0-2.126l-2.644-2.644a1 1 0 0 0-1.414 1.414L10.986 9H6.4a1 1 0 0 0 0 2h4.586z"/></g></svg>
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index d410755cad1..0ace6be8f4e 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -142,6 +142,7 @@
.col-sm-10.col-sm-offset-2
.checkbox
= label_tag 'merge_request[force_remove_source_branch]' do
+ = hidden_field_tag 'merge_request[force_remove_source_branch]', '0'
= check_box_tag 'merge_request[force_remove_source_branch]', '1', @merge_request.force_remove_source_branch?
Remove source branch when merge request is accepted.
diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml
index 22b5a6aa11b..1d778bc88de 100644
--- a/app/views/shared/issuable/_label_dropdown.html.haml
+++ b/app/views/shared/issuable/_label_dropdown.html.haml
@@ -22,7 +22,7 @@
%button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data}
%span.dropdown-toggle-text{ class: ("is-default" if selected.nil? || selected.empty?) }
= multi_label_name(selected, "Labels")
- = icon('chevron-down')
+ = icon('caret-down')
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
= render partial: "shared/issuable/label_page_default", locals: { title: dropdown_title, show_footer: show_footer, show_create: show_create }
- if show_create && project && can?(current_user, :admin_label, project)
diff --git a/changelogs/unreleased/22588-todos-filter-shows-all-users.yml b/changelogs/unreleased/22588-todos-filter-shows-all-users.yml
new file mode 100644
index 00000000000..1da72142880
--- /dev/null
+++ b/changelogs/unreleased/22588-todos-filter-shows-all-users.yml
@@ -0,0 +1,4 @@
+---
+title: 'Fix: Todos Filter Shows All Users'
+merge_request:
+author:
diff --git a/changelogs/unreleased/22947-fix_issues_atom_feed_url.yml b/changelogs/unreleased/22947-fix_issues_atom_feed_url.yml
new file mode 100644
index 00000000000..2312afdb3d7
--- /dev/null
+++ b/changelogs/unreleased/22947-fix_issues_atom_feed_url.yml
@@ -0,0 +1,4 @@
+---
+title: Issues atom feed url reflect filters on dashboard
+merge_request: 7114
+author: Lucas Deschamps
diff --git a/changelogs/unreleased/23961-can-t-share-project-with-groups.yml b/changelogs/unreleased/23961-can-t-share-project-with-groups.yml
new file mode 100644
index 00000000000..b3bfcbda4b7
--- /dev/null
+++ b/changelogs/unreleased/23961-can-t-share-project-with-groups.yml
@@ -0,0 +1,4 @@
+---
+title: Only skip group when it's actually a group in the "Share with group" select
+merge_request: 7262
+author:
diff --git a/changelogs/unreleased/24056-guest-sees-some-project-details-and-gets-404.yml b/changelogs/unreleased/24056-guest-sees-some-project-details-and-gets-404.yml
new file mode 100644
index 00000000000..8ca0c5beab3
--- /dev/null
+++ b/changelogs/unreleased/24056-guest-sees-some-project-details-and-gets-404.yml
@@ -0,0 +1,4 @@
+---
+title: 'Fix: Guest sees some repository details and gets 404'
+merge_request:
+author:
diff --git a/changelogs/unreleased/24059-round-robin-repository-storage.yml b/changelogs/unreleased/24059-round-robin-repository-storage.yml
new file mode 100644
index 00000000000..109536114ff
--- /dev/null
+++ b/changelogs/unreleased/24059-round-robin-repository-storage.yml
@@ -0,0 +1,4 @@
+---
+title: Introduce round-robin project creation to spread load over multiple shards
+merge_request: 7266
+author:
diff --git a/changelogs/unreleased/24102-cannot-unselect-remove-source-branch-when-editing-merge-request.yml b/changelogs/unreleased/24102-cannot-unselect-remove-source-branch-when-editing-merge-request.yml
new file mode 100644
index 00000000000..50d018170f1
--- /dev/null
+++ b/changelogs/unreleased/24102-cannot-unselect-remove-source-branch-when-editing-merge-request.yml
@@ -0,0 +1,4 @@
+---
+title: Ensure merge request's "remove branch" accessors return booleans
+merge_request: 7267
+author:
diff --git a/changelogs/unreleased/fix-invalid-filename-eslint.yml b/changelogs/unreleased/fix-invalid-filename-eslint.yml
new file mode 100644
index 00000000000..eea21149c90
--- /dev/null
+++ b/changelogs/unreleased/fix-invalid-filename-eslint.yml
@@ -0,0 +1,4 @@
+---
+title: Fix invalid filename validation on eslint
+merge_request: 7281
+author:
diff --git a/db/migrate/20161103171205_rename_repository_storage_column.rb b/db/migrate/20161103171205_rename_repository_storage_column.rb
new file mode 100644
index 00000000000..e9f992793b4
--- /dev/null
+++ b/db/migrate/20161103171205_rename_repository_storage_column.rb
@@ -0,0 +1,29 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RenameRepositoryStorageColumn < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ # When a migration requires downtime you **must** uncomment the following
+ # constant and define a short and easy to understand explanation as to why the
+ # migration requires downtime.
+ # DOWNTIME_REASON = ''
+
+ # When using the methods "add_concurrent_index" or "add_column_with_default"
+ # you must disable the use of transactions as these methods can not run in an
+ # existing transaction. When using "add_concurrent_index" make sure that this
+ # method is the _only_ method called in the migration, any other changes
+ # should go in a separate migration. This ensures that upon failure _only_ the
+ # index creation fails and can be retried or reverted easily.
+ #
+ # To disable transactions uncomment the following line and remove these
+ # comments:
+ # disable_ddl_transaction!
+
+ def change
+ rename_column :application_settings, :repository_storage, :repository_storages
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 54b5fc83be0..dc088925d97 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20161025231710) do
+ActiveRecord::Schema.define(version: 20161103171205) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -88,7 +88,7 @@ ActiveRecord::Schema.define(version: 20161025231710) do
t.integer "container_registry_token_expire_delay", default: 5
t.text "after_sign_up_text"
t.boolean "user_default_external", default: false, null: false
- t.string "repository_storage", default: "default"
+ t.string "repository_storages", default: "default"
t.string "enabled_git_access_protocol"
t.boolean "domain_blacklist_enabled", default: false
t.text "domain_blacklist"
diff --git a/doc/administration/img/repository_storages_admin_ui.png b/doc/administration/img/repository_storages_admin_ui.png
index 599350bc098..6481baca1ad 100644
--- a/doc/administration/img/repository_storages_admin_ui.png
+++ b/doc/administration/img/repository_storages_admin_ui.png
Binary files differ
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 737b39db16c..d757a3c2a66 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -13,7 +13,8 @@ This guide talks about how to read and use these system log files.
This file lives in `/var/log/gitlab/gitlab-rails/production.log` for
omnibus package or in `/home/git/gitlab/log/production.log` for
-installations from source.
+installations from source. (When Gitlab is running in an environment
+other than production, the corresponding logfile is shown here.)
It contains information about all performed requests. You can see the
URL and type of request, IP address and what exactly parts of code were
diff --git a/doc/administration/repository_storages.md b/doc/administration/repository_storages.md
index 55b054fc1a4..ab70557b69a 100644
--- a/doc/administration/repository_storages.md
+++ b/doc/administration/repository_storages.md
@@ -91,6 +91,9 @@ be stored via the **Application Settings** in the Admin area.
![Choose repository storage path in Admin area](img/repository_storages_admin_ui.png)
+Beginning with GitLab 8.13.4, multiple paths can be chosen. New projects will be
+randomly placed on one of the selected paths.
+
[ce-4578]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4578
[restart gitlab]: restart_gitlab.md#installations-from-source
[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
diff --git a/doc/api/groups.md b/doc/api/groups.md
index e81d6f9de4b..b56d74d25e0 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -2,7 +2,12 @@
## List groups
-Get a list of groups. (As user: my groups, as admin: all groups)
+Get a list of groups. (As user: my groups or all available, as admin: all groups).
+
+Parameters:
+
+- `all_available` (optional) - if passed, show all groups you have access to
+- `skip_groups` (optional)(array of group IDs) - if passed, skip groups
```
GET /groups
@@ -21,7 +26,6 @@ GET /groups
You can search for groups by name or path, see below.
-
## List a group's projects
Get a list of projects in this group.
diff --git a/doc/api/settings.md b/doc/api/settings.md
index f7ad3b4cc8e..218546aafea 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -42,6 +42,7 @@ Example response:
"sign_in_text" : null,
"container_registry_token_expire_delay": 5,
"repository_storage": "default",
+ "repository_storages": ["default"],
"koding_enabled": false,
"koding_url": null
}
@@ -73,7 +74,8 @@ PUT /application/settings
| `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider |
| `after_sign_out_path` | string | no | Where to redirect users after logout |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes |
-| `repository_storage` | string | no | Storage path for new projects. The value should be the name of one of the repository storage paths defined in your gitlab.yml |
+| `repository_storages` | array of strings | no | A list of names of enabled storage paths, taken from `gitlab.yml`. New projects will be created in one of these stores, chosen at random. |
+| `repository_storage` | string | no | The first entry in `repository_storages`. Deprecated, but retained for compatibility reasons |
| `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols. |
| `koding_enabled` | boolean | no | Enable Koding integration. Default is `false`. |
| `koding_url` | string | yes (if `koding_enabled` is `true`) | The Koding instance URL for integration. |
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index a313c31e7ee..959741f7338 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -226,7 +226,7 @@ e.g. `docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_ap
> **Note:**
This feature requires GitLab 8.8 and GitLab Runner 1.2.
-Once you've built a Docker image, you can push it up to the built-in [GitLab Container Registry](../../container_registry/README.md). For example, if you're using
+Once you've built a Docker image, you can push it up to the built-in [GitLab Container Registry](../../user/project/container_registry.md). For example, if you're using
docker-in-docker on your runners, this is how your `.gitlab-ci.yml` could look:
diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md
index 2cfa30f652e..b137e6ae82e 100644
--- a/doc/development/doc_styleguide.md
+++ b/doc/development/doc_styleguide.md
@@ -465,6 +465,7 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "domain
[cURL]: http://curl.haxx.se/ "cURL website"
[single spaces]: http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html
[gfm]: http://docs.gitlab.com/ce/user/markdown.html#newlines "GitLab flavored markdown documentation"
+[ce-1242]: https://gitlab.com/gitlab-org/gitlab-ce/issues/1242
[doc-restart]: ../administration/restart_gitlab.md "GitLab restart documentation"
[ce-3349]: https://gitlab.com/gitlab-org/gitlab-ce/issues/3349 "Documentation restructure"
[graffle]: https://gitlab.com/gitlab-org/gitlab-design/blob/d8d39f4a87b90fb9ae89ca12dc565347b4900d5e/production/resources/gitlab-map.graffle
diff --git a/doc/development/frontend.md b/doc/development/frontend.md
index ece8f880542..1d7d9127a64 100644
--- a/doc/development/frontend.md
+++ b/doc/development/frontend.md
@@ -196,6 +196,12 @@ It consists of two subtasks:
As long as the fixtures don't change, `rake teaspoon:tests` is sufficient
(and saves you some time).
+If you need to debug your tests and/or application code while they're
+running, navigate to [localhost:3000/teaspoon](http://localhost:3000/teaspoon)
+in your browser, open DevTools, and run tests for individual files by clicking
+on them. This is also much faster than setting up and running tests from the
+command line.
+
Please note: Not all of the frontend fixtures are generated. Some are still static
files. These will not be touched by `rake teaspoon:fixtures`.
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index a7175f3f87e..827db7e99b8 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -42,14 +42,6 @@ To run several tests inside one directory:
If you want to use [Spring](https://github.com/rails/spring) set
`ENABLE_SPRING=1` in your environment.
-## Generate searchable docs for source code
-
-You can find results under the `doc/code` directory.
-
-```
-bundle exec rake gitlab:generate_docs
-```
-
## Generate API documentation for project services (e.g. Slack)
```
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 83090f46271..7e947e4b2ba 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -479,10 +479,14 @@ Copy the example site config:
sudo cp lib/support/nginx/gitlab /etc/nginx/sites-available/gitlab
sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab
-Make sure to edit the config file to match your setup:
+Make sure to edit the config file to match your setup. Also, ensure that you match your paths to GitLab, especially if installing for a user other than the 'git' user:
# Change YOUR_SERVER_FQDN to the fully-qualified
# domain name of your host serving GitLab.
+ #
+ # Remember to match your paths to GitLab, especially
+ # if installing for a user other than 'git'.
+ #
# If using Ubuntu default nginx install:
# either remove the default_server from the listen line
# or else sudo rm -f /etc/nginx/sites-enabled/default
diff --git a/doc/university/README.md b/doc/university/README.md
index f5a0dab39fe..510b753f70d 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -2,7 +2,7 @@
GitLab University is the best place to learn about **Version Control with Git and GitLab**.
-It doesn't replace, but accompanies our great [Documentation](http://docs.gitlab.com)
+It doesn't replace, but accompanies our great [Documentation](https://docs.gitlab.com)
and [Blog Articles](https://about.gitlab.com/blog/).
Would you like to contribute to GitLab University? Then please take a look at our contribution [process](/process) for more information.
@@ -31,7 +31,7 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project
1. [An Overview of GitLab.com - Video](https://www.youtube.com/watch?v=WaiL5DGEMR4)
1. [Why Use Git and GitLab - Slides](https://docs.google.com/a/gitlab.com/presentation/d/1RcZhFmn5VPvoFu6UMxhMOy7lAsToeBZRjLRn0LIdaNc/edit?usp=drive_web)
-1. [GitLab Basics - Article](http://doc.gitlab.com/ce/gitlab-basics/README.html)
+1. [GitLab Basics - Article](../gitlab-basics/README.md)
1. [Git and GitLab Basics - Video](https://www.youtube.com/watch?v=03wb9FvO4Ak&index=5&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e)
1. [Git and GitLab Basics - Online Course](https://courses.platzi.com/classes/git-gitlab/concepto/part-1/part-23370/material/)
1. [Comparison of GitLab Versions](https://about.gitlab.com/features/#compare)
@@ -51,10 +51,10 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project
#### 1.5. Migrating from other Source Control
-1. [Migrating from BitBucket/Stash](http://doc.gitlab.com/ee/workflow/importing/import_projects_from_bitbucket.html)
-1. [Migrating from GitHub](http://doc.gitlab.com/ee/workflow/importing/import_projects_from_github.html)
-1. [Migrating from SVN](http://doc.gitlab.com/ee/workflow/importing/migrating_from_svn.html)
-1. [Migrating from Fogbugz](http://doc.gitlab.com/ee/workflow/importing/import_projects_from_fogbugz.html)
+1. [Migrating from BitBucket/Stash](https://docs.gitlab.com/ee/workflow/importing/import_projects_from_bitbucket.html)
+1. [Migrating from GitHub](https://docs.gitlab.com/ee/workflow/importing/import_projects_from_github.html)
+1. [Migrating from SVN](https://docs.gitlab.com/ee/workflow/importing/migrating_from_svn.html)
+1. [Migrating from Fogbugz](https://docs.gitlab.com/ee/workflow/importing/import_projects_from_fogbugz.html)
#### 1.6. GitLab Inc.
@@ -91,11 +91,11 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project
1. [Using any Static Site Generator with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/)
1. [Securing GitLab Pages with SSL](https://about.gitlab.com/2016/06/24/secure-gitlab-pages-with-startssl/)
-1. [GitLab Pages Documentation](http://doc.gitlab.com/ee/pages/README.html)
+1. [GitLab Pages Documentation](https://docs.gitlab.com/ee/pages/README.html)
#### 2.2. GitLab Issues
-1. [Markdown in GitLab](http://doc.gitlab.com/ce/markdown/markdown.html)
+1. [Markdown in GitLab](../user/markdown.md)
1. [Issues and Merge Requests - Video](https://www.youtube.com/watch?v=raXvuwet78M)
1. [Due Dates and Milestones fro GitLab Issues](https://about.gitlab.com/2016/08/05/feature-highlight-set-dates-for-issues/)
1. [How to Use GitLab Labels](https://about.gitlab.com/2016/08/17/using-gitlab-labels/)
@@ -129,7 +129,7 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project
1. [GitLab Flow vs Forking in GitLab - Video](https://www.youtube.com/watch?v=UGotqAUACZA)
1. [GitLab Flow Overview](https://about.gitlab.com/2014/09/29/gitlab-flow/)
1. [Always Start with an Issue](https://about.gitlab.com/2016/03/03/start-with-an-issue/)
-1. [GitLab Flow Documentation](http://doc.gitlab.com/ee/workflow/gitlab_flow.html)
+1. [GitLab Flow Documentation](https://docs.gitlab.com/ee/workflow/gitlab_flow.html)
#### 2.5. GitLab Comparisons
@@ -189,8 +189,8 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project
#### 3.9. <a name="integrations"></a> Integrations
1. [How to Integrate JIRA and Jenkins with GitLab - Video](https://gitlabmeetings.webex.com/gitlabmeetings/ldr.php?RCID=44b548147a67ab4d8a62274047146415)
-1. [How to Integrate Jira with GitLab](http://doc.gitlab.com/ee/integration/jira.html)
-1. [How to Integrate Jenkins with GitLab](http://doc.gitlab.com/ee/integration/jenkins.html)
+1. [How to Integrate Jira with GitLab](https://docs.gitlab.com/ee/integration/jira.html)
+1. [How to Integrate Jenkins with GitLab](https://docs.gitlab.com/ee/integration/jenkins.html)
1. [How to Integrate Bamboo with GitLab](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/project_services/bamboo.md)
1. [How to Integrate Slack with GitLab](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/slack.md)
1. [How to Integrate Convox with GitLab](https://about.gitlab.com/2016/06/09/continuous-delivery-with-gitlab-and-convox/)
diff --git a/doc/university/glossary/README.md b/doc/university/glossary/README.md
index cf836667fac..20e7ea1987f 100644
--- a/doc/university/glossary/README.md
+++ b/doc/university/glossary/README.md
@@ -10,7 +10,7 @@ User authentication by combination of 2 different steps during login. This allow
### Access Levels
-Process of selective restriction to create, view, modify or delete a resource based on a set of assigned permissions. See [GitLab's Permission Guidelines](http://doc.gitlab.com/ce/permissions/permissions.html)
+Process of selective restriction to create, view, modify or delete a resource based on a set of assigned permissions. See [GitLab's Permission Guidelines](../../permissions/permissions.md
### Active Directory (AD)
diff --git a/doc/university/support/README.md b/doc/university/support/README.md
index da991e56370..6e415e4d219 100644
--- a/doc/university/support/README.md
+++ b/doc/university/support/README.md
@@ -58,28 +58,28 @@ Sometimes we need to upgrade customers from old versions of GitLab to latest, so
- Users
- Groups
- Projects
- - [Backup using our Backup rake task](http://docs.gitlab.com/ce/raketasks/backup_restore.html#create-a-backup-of-the-gitlab-system)
+ - [Backup using our Backup rake task](https://docs.gitlab.com/ce/raketasks/backup_restore.html#create-a-backup-of-the-gitlab-system)
- [Upgrade to 5.0 source using our Upgrade documentation](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/update/4.2-to-5.0.md)
- [Upgrade to 5.1 source](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/update/5.0-to-5.1.md)
- [Upgrade to 6.0 source](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/update/5.1-to-6.0.md)
- [Upgrade to 7.14 source](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/update/6.x-or-7.x-to-7.14.md)
- - [Backup using our Backup rake task](http://docs.gitlab.com/ce/raketasks/backup_restore.html#create-a-backup-of-the-gitlab-system)
- - [Perform the MySQL to PostgreSQL migration to convert your backup](http://docs.gitlab.com/ce/update/mysql_to_postgresql.html#converting-a-gitlab-backup-file-from-mysql-to-postgres)
- - [Upgrade to Omnibus 7.14](http://doc.gitlab.com/omnibus/update/README.html#upgrading-from-a-non-omnibus-installation-to-an-omnibus-installation)
- - [Restore backup using our Restore rake task](http://docs.gitlab.com/ce/raketasks/backup_restore.html#restore-a-previously-created-backup)
+ - [Backup using our Backup rake task](https://docs.gitlab.com/ce/raketasks/backup_restore.html#create-a-backup-of-the-gitlab-system)
+ - [Perform the MySQL to PostgreSQL migration to convert your backup](https://docs.gitlab.com/ce/update/mysql_to_postgresql.html#converting-a-gitlab-backup-file-from-mysql-to-postgres)
+ - [Upgrade to Omnibus 7.14](https://docs.gitlab.com/omnibus/update/README.html#upgrading-from-a-non-omnibus-installation-to-an-omnibus-installation)
+ - [Restore backup using our Restore rake task](https://docs.gitlab.com/ce/raketasks/backup_restore.html#restore-a-previously-created-backup)
- [Upgrade to latest EE](https://about.gitlab.com/downloads-ee)
- (GitLab inc. only) Acquire and apply a license for the Enterprise Edition product, ask in #support
-- Perform a downgrade from [EE to CE](http://doc.gitlab.com/ee/downgrade_ee_to_ce/README.html)
+- Perform a downgrade from [EE to CE](https://docs.gitlab.com/ee/downgrade_ee_to_ce/README.html)
#### Start to learn about some of the integrations that we support
Our integrations add great value to GitLab. User questions often relate to integrating GitLab with existing external services and the configuration involved
- Learn about our Integrations (specially, not only):
- - [LDAP](http://doc.gitlab.com/ee/integration/ldap.html)
- - [JIRA](http://doc.gitlab.com/ee/project_services/jira.html)
- - [Jenkins](http://doc.gitlab.com/ee/integration/jenkins.html)
- - [SAML](http://doc.gitlab.com/ce/integration/saml.html)
+ - [LDAP](https://docs.gitlab.com/ee/integration/ldap.html)
+ - [JIRA](https://docs.gitlab.com/ee/project_services/jira.html)
+ - [Jenkins](https://docs.gitlab.com/ee/integration/jenkins.html)
+ - [SAML](https://docs.gitlab.com/ce/integration/saml.html)
#### Goals
@@ -91,8 +91,8 @@ Our integrations add great value to GitLab. User questions often relate to integ
#### Understand the gathering of diagnostics for GitLab instances
- Learn about the GitLab checks that are available
- - [Environment Information and maintenance checks](http://docs.gitlab.com/ce/raketasks/maintenance.html)
- - [GitLab check](http://docs.gitlab.com/ce/raketasks/check.html)
+ - [Environment Information and maintenance checks](https://docs.gitlab.com/ce/raketasks/maintenance.html)
+ - [GitLab check](https://docs.gitlab.com/ce/raketasks/check.html)
- Omnibus commands
- [Status](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/maintenance/README.md#get-service-status)
- [Starting and stopping services](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/maintenance/README.md#starting-and-stopping)
@@ -167,12 +167,12 @@ Some tickets need specific knowledge or a deep understanding of a particular com
Move on to understanding some of GitLab's more advanced features. You can make use of GitLab.com to understand the features from an end-user perspective and then use your own instance to understand setup and configuration of the feature from an Administrative perspective
-- Set up and try [Git Annex](http://doc.gitlab.com/ee/workflow/git_annex.html)
-- Set up and try [Git LFS](http://doc.gitlab.com/ee/workflow/lfs/manage_large_binaries_with_git_lfs.html)
-- Get to know the [GitLab API](http://doc.gitlab.com/ee/api/README.html), its capabilities and shortcomings
-- Learn how to [migrate from SVN to Git](http://doc.gitlab.com/ee/workflow/importing/migrating_from_svn.html)
-- Set up [GitLab CI](http://doc.gitlab.com/ee/ci/quick_start/README.html)
-- Create your first [GitLab Page](http://doc.gitlab.com/ee/pages/administration.html)
+- Set up and try [Git Annex](https://docs.gitlab.com/ee/workflow/git_annex.html)
+- Set up and try [Git LFS](https://docs.gitlab.com/ee/workflow/lfs/manage_large_binaries_with_git_lfs.html)
+- Get to know the [GitLab API](https://docs.gitlab.com/ee/api/README.html), its capabilities and shortcomings
+- Learn how to [migrate from SVN to Git](https://docs.gitlab.com/ee/workflow/importing/migrating_from_svn.html)
+- Set up [GitLab CI](https://docs.gitlab.com/ee/ci/quick_start/README.html)
+- Create your first [GitLab Page](https://docs.gitlab.com/ee/pages/administration.html)
- Get to know the GitLab Codebase by reading through the source code:
- Find the differences between the [EE codebase](https://gitlab.com/gitlab-org/gitlab-ce)
and the [CE codebase](https://gitlab.com/gitlab-org/gitlab-ce)
diff --git a/features/steps/admin/logs.rb b/features/steps/admin/logs.rb
index f9e49588c75..63881d69146 100644
--- a/features/steps/admin/logs.rb
+++ b/features/steps/admin/logs.rb
@@ -4,7 +4,7 @@ class Spinach::Features::AdminLogs < Spinach::FeatureSteps
include SharedAdmin
step 'I should see tabs with available logs' do
- expect(page).to have_content 'production.log'
+ expect(page).to have_content 'test.log'
expect(page).to have_content 'githost.log'
expect(page).to have_content 'application.log'
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index d52496451a2..1f378ba1635 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -509,6 +509,7 @@ module API
expose :after_sign_out_path
expose :container_registry_token_expire_delay
expose :repository_storage
+ expose :repository_storages
expose :koding_enabled
expose :koding_url
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index bfb89475025..a13e353b7f5 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -8,11 +8,14 @@ module API
#
# Parameters:
# skip_groups (optional) - Array of group ids to exclude from list
+ # all_available (optional, boolean) - Show all group that you have access to
# Example Request:
# GET /groups
get do
@groups = if current_user.admin
Group.all
+ elsif params[:all_available]
+ GroupsFinder.new.execute(current_user)
else
current_user.groups
end
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index dd93a85dc54..eef343c2ac6 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -1,114 +1,99 @@
module API
# Projects API
class ProjectHooks < Grape::API
+ helpers do
+ params :project_hook_properties do
+ requires :url, type: String, desc: "The URL to send the request to"
+ optional :push_events, type: Boolean, desc: "Trigger hook on push events"
+ optional :issues_events, type: Boolean, desc: "Trigger hook on issues events"
+ optional :merge_requests_events, type: Boolean, desc: "Trigger hook on merge request events"
+ optional :tag_push_events, type: Boolean, desc: "Trigger hook on tag push events"
+ optional :note_events, type: Boolean, desc: "Trigger hook on note(comment) events"
+ optional :build_events, type: Boolean, desc: "Trigger hook on build events"
+ optional :pipeline_events, type: Boolean, desc: "Trigger hook on pipeline events"
+ optional :wiki_events, type: Boolean, desc: "Trigger hook on wiki events"
+ optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
+ optional :token, type: String, desc: "Secret token to validate received payloads; this will not be returned in the response"
+ end
+ end
+
before { authenticate! }
before { authorize_admin_project }
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
resource :projects do
- # Get project hooks
- #
- # Parameters:
- # id (required) - The ID of a project
- # Example Request:
- # GET /projects/:id/hooks
+ desc 'Get project hooks' do
+ success Entities::ProjectHook
+ end
get ":id/hooks" do
- @hooks = paginate user_project.hooks
- present @hooks, with: Entities::ProjectHook
+ hooks = paginate user_project.hooks
+
+ present hooks, with: Entities::ProjectHook
end
- # Get a project hook
- #
- # Parameters:
- # id (required) - The ID of a project
- # hook_id (required) - The ID of a project hook
- # Example Request:
- # GET /projects/:id/hooks/:hook_id
+ desc 'Get a project hook' do
+ success Entities::ProjectHook
+ end
+ params do
+ requires :hook_id, type: Integer, desc: 'The ID of a project hook'
+ end
get ":id/hooks/:hook_id" do
- @hook = user_project.hooks.find(params[:hook_id])
- present @hook, with: Entities::ProjectHook
+ hook = user_project.hooks.find(params[:hook_id])
+ present hook, with: Entities::ProjectHook
end
- # Add hook to project
- #
- # Parameters:
- # id (required) - The ID of a project
- # url (required) - The hook URL
- # Example Request:
- # POST /projects/:id/hooks
+ desc 'Add hook to project' do
+ success Entities::ProjectHook
+ end
+ params do
+ use :project_hook_properties
+ end
post ":id/hooks" do
- required_attributes! [:url]
- attrs = attributes_for_keys [
- :url,
- :push_events,
- :issues_events,
- :merge_requests_events,
- :tag_push_events,
- :note_events,
- :build_events,
- :pipeline_events,
- :wiki_page_events,
- :enable_ssl_verification,
- :token
- ]
- @hook = user_project.hooks.new(attrs)
+ new_hook_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h
+ hook = user_project.hooks.new(new_hook_params)
- if @hook.save
- present @hook, with: Entities::ProjectHook
+ if hook.save
+ present hook, with: Entities::ProjectHook
else
- if @hook.errors[:url].present?
- error!("Invalid url given", 422)
- end
- not_found!("Project hook #{@hook.errors.messages}")
+ error!("Invalid url given", 422) if hook.errors[:url].present?
+
+ not_found!("Project hook #{hook.errors.messages}")
end
end
- # Update an existing project hook
- #
- # Parameters:
- # id (required) - The ID of a project
- # hook_id (required) - The ID of a project hook
- # url (required) - The hook URL
- # Example Request:
- # PUT /projects/:id/hooks/:hook_id
+ desc 'Update an existing project hook' do
+ success Entities::ProjectHook
+ end
+ params do
+ requires :hook_id, type: Integer, desc: "The ID of the hook to update"
+ use :project_hook_properties
+ end
put ":id/hooks/:hook_id" do
- @hook = user_project.hooks.find(params[:hook_id])
- required_attributes! [:url]
- attrs = attributes_for_keys [
- :url,
- :push_events,
- :issues_events,
- :merge_requests_events,
- :tag_push_events,
- :note_events,
- :build_events,
- :pipeline_events,
- :wiki_page_events,
- :enable_ssl_verification,
- :token
- ]
+ hook = user_project.hooks.find(params[:hook_id])
+
+ new_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h
+ new_params.delete('hook_id')
- if @hook.update_attributes attrs
- present @hook, with: Entities::ProjectHook
+ if hook.update_attributes(new_params)
+ present hook, with: Entities::ProjectHook
else
- if @hook.errors[:url].present?
- error!("Invalid url given", 422)
- end
- not_found!("Project hook #{@hook.errors.messages}")
+ error!("Invalid url given", 422) if hook.errors[:url].present?
+
+ not_found!("Project hook #{hook.errors.messages}")
end
end
- # Deletes project hook. This is an idempotent function.
- #
- # Parameters:
- # id (required) - The ID of a project
- # hook_id (required) - The ID of hook to delete
- # Example Request:
- # DELETE /projects/:id/hooks/:hook_id
+ desc 'Deletes project hook' do
+ success Entities::ProjectHook
+ end
+ params do
+ requires :hook_id, type: Integer, desc: 'The ID of the hook to delete'
+ end
delete ":id/hooks/:hook_id" do
- required_attributes! [:hook_id]
-
begin
- @hook = user_project.hooks.destroy(params[:hook_id])
+ present user_project.hooks.destroy(params[:hook_id]), with: Entities::ProjectHook
rescue
# ProjectHook can raise Error if hook_id not found
not_found!("Error deleting hook #{params[:hook_id]}")
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index c885fcd7ea3..c4cb1c7924a 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -17,12 +17,12 @@ module API
present current_settings, with: Entities::ApplicationSetting
end
- # Modify applicaiton settings
+ # Modify application settings
#
# Example Request:
# PUT /application/settings
put "application/settings" do
- attributes = current_settings.attributes.keys - ["id"]
+ attributes = ["repository_storage"] + current_settings.attributes.keys - ["id"]
attrs = attributes_for_keys(attributes)
if current_settings.update_attributes(attrs)
diff --git a/lib/gitlab/production_logger.rb b/lib/gitlab/environment_logger.rb
index 89ce7144b1b..407cc572656 100644
--- a/lib/gitlab/production_logger.rb
+++ b/lib/gitlab/environment_logger.rb
@@ -1,7 +1,7 @@
module Gitlab
- class ProductionLogger < Gitlab::Logger
+ class EnvironmentLogger < Gitlab::Logger
def self.file_name_noext
- 'production'
+ Rails.env
end
end
end
diff --git a/lib/tasks/gitlab/generate_docs.rake b/lib/tasks/gitlab/generate_docs.rake
deleted file mode 100644
index f6448c38e10..00000000000
--- a/lib/tasks/gitlab/generate_docs.rake
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace :gitlab do
- desc "GitLab | Generate sdocs for project"
- task generate_docs: :environment do
- system(*%W(bundle exec sdoc -o doc/code app lib))
- end
-end
-
diff --git a/spec/bin/changelog_spec.rb b/spec/bin/changelog_spec.rb
index 8c8bc1b0f1c..7f4298db59f 100644
--- a/spec/bin/changelog_spec.rb
+++ b/spec/bin/changelog_spec.rb
@@ -10,54 +10,38 @@ describe 'bin/changelog' do
expect(options.amend).to eq true
end
- it 'parses --force' do
- options = described_class.parse(%w[foo --force bar])
+ it 'parses --force and -f' do
+ %w[--force -f].each do |flag|
+ options = described_class.parse(%W[foo #{flag} bar])
- expect(options.force).to eq true
+ expect(options.force).to eq true
+ end
end
- it 'parses -f' do
- options = described_class.parse(%w[foo -f bar])
+ it 'parses --merge-request and -m' do
+ %w[--merge-request -m].each do |flag|
+ options = described_class.parse(%W[foo #{flag} 1234 bar])
- expect(options.force).to eq true
+ expect(options.merge_request).to eq 1234
+ end
end
- it 'parses --merge-request' do
- options = described_class.parse(%w[foo --merge-request 1234 bar])
+ it 'parses --dry-run and -n' do
+ %w[--dry-run -n].each do |flag|
+ options = described_class.parse(%W[foo #{flag} bar])
- expect(options.merge_request).to eq 1234
+ expect(options.dry_run).to eq true
+ end
end
- it 'parses -m' do
- options = described_class.parse(%w[foo -m 4321 bar])
-
- expect(options.merge_request).to eq 4321
- end
-
- it 'parses --dry-run' do
- options = described_class.parse(%w[foo --dry-run bar])
-
- expect(options.dry_run).to eq true
- end
-
- it 'parses -n' do
- options = described_class.parse(%w[foo -n bar])
-
- expect(options.dry_run).to eq true
- end
-
- it 'parses --git-username' do
+ it 'parses --git-username and -u' do
allow(described_class).to receive(:git_user_name).and_return('Jane Doe')
- options = described_class.parse(%w[foo --git-username bar])
-
- expect(options.author).to eq 'Jane Doe'
- end
- it 'parses -u' do
- allow(described_class).to receive(:git_user_name).and_return('John Smith')
- options = described_class.parse(%w[foo -u bar])
+ %w[--git-username -u].each do |flag|
+ options = described_class.parse(%W[foo #{flag} bar])
- expect(options.author).to eq 'John Smith'
+ expect(options.author).to eq 'Jane Doe'
+ end
end
it 'parses -h' do
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 2f82fafc13a..d92c66b689d 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -7,15 +7,16 @@ describe "Admin Runners" do
describe "Runners page" do
before do
- runner = FactoryGirl.create(:ci_runner)
+ runner = FactoryGirl.create(:ci_runner, contacted_at: Time.now)
pipeline = FactoryGirl.create(:ci_pipeline)
FactoryGirl.create(:ci_build, pipeline: pipeline, runner_id: runner.id)
visit admin_runners_path
end
- it { page.has_text? "Manage Runners" }
- it { page.has_text? "To register a new runner" }
- it { page.has_text? "Runners with last contact less than a minute ago: 1" }
+ it 'has all necessary texts' do
+ expect(page).to have_text "To register a new Runner"
+ expect(page).to have_text "Runners with last contact less than a minute ago: 1"
+ end
describe 'search' do
before do
@@ -27,8 +28,10 @@ describe "Admin Runners" do
search_form.click_button 'Search'
end
- it { expect(page).to have_content("runner-foo") }
- it { expect(page).not_to have_content("runner-bar") }
+ it 'shows correct runner' do
+ expect(page).to have_content("runner-foo")
+ expect(page).not_to have_content("runner-bar")
+ end
end
end
@@ -46,8 +49,10 @@ describe "Admin Runners" do
end
describe 'projects' do
- it { expect(page).to have_content(@project1.name_with_namespace) }
- it { expect(page).to have_content(@project2.name_with_namespace) }
+ it 'contains project names' do
+ expect(page).to have_content(@project1.name_with_namespace)
+ expect(page).to have_content(@project2.name_with_namespace)
+ end
end
describe 'search' do
@@ -57,8 +62,10 @@ describe "Admin Runners" do
search_form.click_button 'Search'
end
- it { expect(page).to have_content(@project1.name_with_namespace) }
- it { expect(page).not_to have_content(@project2.name_with_namespace) }
+ it 'contains name of correct project' do
+ expect(page).to have_content(@project1.name_with_namespace)
+ expect(page).not_to have_content(@project2.name_with_namespace)
+ end
end
describe 'enable/create' do
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index 4dd9548cfc5..21ee6cedbae 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -19,6 +19,17 @@ describe "Dashboard Issues Feed", feature: true do
expect(body).to have_selector('title', text: "#{user.name} issues")
end
+ it "renders atom feed with url parameters" do
+ visit issues_dashboard_path(:atom, private_token: user.private_token, state: 'opened', assignee_id: user.id)
+
+ link = find('link[type="application/atom+xml"]')
+ params = CGI::parse(URI.parse(link[:href]).query)
+
+ expect(params).to include('private_token' => [user.private_token])
+ expect(params).to include('state' => ['opened'])
+ expect(params).to include('assignee_id' => [user.id.to_s])
+ end
+
context "issue with basic fields" do
let!(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'test desc') }
diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb
index 09c140868fb..863412d18eb 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/features/atom/issues_spec.rb
@@ -3,10 +3,14 @@ require 'spec_helper'
describe 'Issues Feed', feature: true do
describe 'GET /issues' do
let!(:user) { create(:user) }
+ let!(:group) { create(:group) }
let!(:project) { create(:project) }
let!(:issue) { create(:issue, author: user, project: project) }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ group.add_developer(user)
+ end
context 'when authenticated' do
it 'renders atom feed' do
@@ -33,5 +37,28 @@ describe 'Issues Feed', feature: true do
expect(body).to have_selector('entry summary', text: issue.title)
end
end
+
+ it "renders atom feed with url parameters for project issues" do
+ visit namespace_project_issues_path(project.namespace, project,
+ :atom, private_token: user.private_token, state: 'opened', assignee_id: user.id)
+
+ link = find('link[type="application/atom+xml"]')
+ params = CGI::parse(URI.parse(link[:href]).query)
+
+ expect(params).to include('private_token' => [user.private_token])
+ expect(params).to include('state' => ['opened'])
+ expect(params).to include('assignee_id' => [user.id.to_s])
+ end
+
+ it "renders atom feed with url parameters for group issues" do
+ visit issues_group_path(group, :atom, private_token: user.private_token, state: 'opened', assignee_id: user.id)
+
+ link = find('link[type="application/atom+xml"]')
+ params = CGI::parse(URI.parse(link[:href]).query)
+
+ expect(params).to include('private_token' => [user.private_token])
+ expect(params).to include('state' => ['opened'])
+ expect(params).to include('assignee_id' => [user.id.to_s])
+ end
end
end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index cd53a485ef4..44646ffc602 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -77,9 +77,11 @@ describe 'Commits' do
visit ci_status_path(pipeline)
end
- it { expect(page).to have_content pipeline.sha[0..7] }
- it { expect(page).to have_content pipeline.git_commit_message }
- it { expect(page).to have_content pipeline.git_author_name }
+ it 'shows pipeline`s data' do
+ expect(page).to have_content pipeline.sha[0..7]
+ expect(page).to have_content pipeline.git_commit_message
+ expect(page).to have_content pipeline.git_author_name
+ end
end
context 'Download artifacts' do
diff --git a/spec/features/dashboard_issues_spec.rb b/spec/features/dashboard_issues_spec.rb
index 9b54b5301e5..b898f9bc64f 100644
--- a/spec/features/dashboard_issues_spec.rb
+++ b/spec/features/dashboard_issues_spec.rb
@@ -44,6 +44,22 @@ describe "Dashboard Issues filtering", feature: true, js: true do
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_selector('.issue', count: 1)
end
+
+ it 'updates atom feed link' do
+ visit_issues(milestone_title: '', assignee_id: user.id)
+
+ link = find('.nav-controls a', text: 'Subscribe')
+ params = CGI::parse(URI.parse(link[:href]).query)
+ auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
+ auto_discovery_params = CGI::parse(URI.parse(auto_discovery_link[:href]).query)
+
+ expect(params).to include('private_token' => [user.private_token])
+ expect(params).to include('milestone_title' => [''])
+ expect(params).to include('assignee_id' => [user.id.to_s])
+ expect(auto_discovery_params).to include('private_token' => [user.private_token])
+ expect(auto_discovery_params).to include('milestone_title' => [''])
+ expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s])
+ end
end
def show_milestone_dropdown
@@ -51,7 +67,7 @@ describe "Dashboard Issues filtering", feature: true, js: true do
expect(page).to have_selector('.dropdown-content', visible: true)
end
- def visit_issues
- visit issues_dashboard_path
+ def visit_issues(*args)
+ visit issues_dashboard_path(*args)
end
end
diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 78208aed46d..2798db92f0f 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -4,6 +4,7 @@ describe 'Filter issues', feature: true do
include WaitForAjax
let!(:project) { create(:project) }
+ let!(:group) { create(:group) }
let!(:user) { create(:user)}
let!(:milestone) { create(:milestone, project: project) }
let!(:label) { create(:label, project: project) }
@@ -11,6 +12,7 @@ describe 'Filter issues', feature: true do
before do
project.team << [user, :master]
+ group.add_developer(user)
login_as(user)
create(:issue, project: project)
end
@@ -347,4 +349,36 @@ describe 'Filter issues', feature: true do
end
end
end
+
+ it 'updates atom feed link for project issues' do
+ visit namespace_project_issues_path(project.namespace, project, milestone_title: '', assignee_id: user.id)
+
+ link = find('.nav-controls a', text: 'Subscribe')
+ params = CGI::parse(URI.parse(link[:href]).query)
+ auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
+ auto_discovery_params = CGI::parse(URI.parse(auto_discovery_link[:href]).query)
+
+ expect(params).to include('private_token' => [user.private_token])
+ expect(params).to include('milestone_title' => [''])
+ expect(params).to include('assignee_id' => [user.id.to_s])
+ expect(auto_discovery_params).to include('private_token' => [user.private_token])
+ expect(auto_discovery_params).to include('milestone_title' => [''])
+ expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s])
+ end
+
+ it 'updates atom feed link for group issues' do
+ visit issues_group_path(group, milestone_title: '', assignee_id: user.id)
+
+ link = find('.nav-controls a', text: 'Subscribe')
+ params = CGI::parse(URI.parse(link[:href]).query)
+ auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
+ auto_discovery_params = CGI::parse(URI.parse(auto_discovery_link[:href]).query)
+
+ expect(params).to include('private_token' => [user.private_token])
+ expect(params).to include('milestone_title' => [''])
+ expect(params).to include('assignee_id' => [user.id.to_s])
+ expect(auto_discovery_params).to include('private_token' => [user.private_token])
+ expect(auto_discovery_params).to include('milestone_title' => [''])
+ expect(auto_discovery_params).to include('assignee_id' => [user.id.to_s])
+ end
end
diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb
index c77e719c5df..c46bd8d449f 100644
--- a/spec/features/merge_requests/edit_mr_spec.rb
+++ b/spec/features/merge_requests/edit_mr_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
feature 'Edit Merge Request', feature: true do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
- let(:merge_request) { create(:merge_request, :with_diffs, source_project: project) }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project) }
before do
project.team << [user, :master]
@@ -28,5 +28,17 @@ feature 'Edit Merge Request', feature: true do
expect(page).to have_content 'Someone edited the merge request the same time you did'
end
+
+ it 'allows to unselect "Remove source branch"' do
+ merge_request.update(merge_params: { 'force_remove_source_branch' => '1' })
+ expect(merge_request.merge_params['force_remove_source_branch']).to be_truthy
+
+ visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ uncheck 'Remove source branch when merge request is accepted'
+
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Remove source branch'
+ end
end
end
diff --git a/spec/features/projects/builds_spec.rb b/spec/features/projects/builds_spec.rb
index 63a23a14f20..a8022a5361f 100644
--- a/spec/features/projects/builds_spec.rb
+++ b/spec/features/projects/builds_spec.rb
@@ -79,12 +79,14 @@ describe "Builds" do
click_link "Cancel running"
end
- it { expect(page).to have_selector('.nav-links li.active', text: 'All') }
- it { expect(page).to have_content 'canceled' }
- it { expect(page).to have_content @build.short_sha }
- it { expect(page).to have_content @build.ref }
- it { expect(page).to have_content @build.name }
- it { expect(page).not_to have_link 'Cancel running' }
+ it 'shows all necessary content' do
+ expect(page).to have_selector('.nav-links li.active', text: 'All')
+ expect(page).to have_content 'canceled'
+ expect(page).to have_content @build.short_sha
+ expect(page).to have_content @build.ref
+ expect(page).to have_content @build.name
+ expect(page).not_to have_link 'Cancel running'
+ end
end
describe "GET /:project/builds/:id" do
@@ -93,10 +95,12 @@ describe "Builds" do
visit namespace_project_build_path(@project.namespace, @project, @build)
end
- it { expect(page.status_code).to eq(200) }
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
+ it 'shows commit`s data' do
+ expect(page.status_code).to eq(200)
+ expect(page).to have_content @commit.sha[0..7]
+ expect(page).to have_content @commit.git_commit_message
+ expect(page).to have_content @commit.git_author_name
+ end
end
context "Build from other project" do
@@ -167,7 +171,7 @@ describe "Builds" do
describe 'Variables' do
before do
- @trigger_request = create :ci_trigger_request_with_variables
+ @trigger_request = create :ci_trigger_request_with_variables
@build = create :ci_build, pipeline: @commit, trigger_request: @trigger_request
visit namespace_project_build_path(@project.namespace, @project, @build)
end
@@ -176,14 +180,14 @@ describe "Builds" do
expect(page).to have_css('.reveal-variables')
expect(page).not_to have_css('.js-build-variable')
expect(page).not_to have_css('.js-build-value')
-
+
click_button 'Reveal Variables'
expect(page).not_to have_css('.reveal-variables')
expect(page).to have_selector('.js-build-variable', text: 'TRIGGER_KEY_1')
expect(page).to have_selector('.js-build-value', text: 'TRIGGER_VALUE_1')
end
- end
+ end
end
describe "POST /:project/builds/:id/cancel" do
@@ -194,9 +198,11 @@ describe "Builds" do
click_link "Cancel"
end
- it { expect(page.status_code).to eq(200) }
- it { expect(page).to have_content 'canceled' }
- it { expect(page).to have_content 'Retry' }
+ it 'loads the page and shows all needed controls' do
+ expect(page.status_code).to eq(200)
+ expect(page).to have_content 'canceled'
+ expect(page).to have_content 'Retry'
+ end
end
context "Build from other project" do
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index e796ee570b7..09aa6758b5c 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -183,4 +183,19 @@ describe 'Edit Project Settings', feature: true do
end
end
end
+
+ # Regression spec for https://gitlab.com/gitlab-org/gitlab-ce/issues/24056
+ describe 'project statistic visibility' do
+ let!(:project) { create(:project, :private) }
+
+ before do
+ project.team << [member, :guest]
+ login_as(member)
+ visit namespace_project_path(project.namespace, project)
+ end
+
+ it "does not show project statistic for guest" do
+ expect(page).not_to have_selector('.project-stats')
+ end
+ end
end
diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/todos/todos_filtering_spec.rb
index b9e66243d84..d1f2bc78884 100644
--- a/spec/features/todos/todos_filtering_spec.rb
+++ b/spec/features/todos/todos_filtering_spec.rb
@@ -36,17 +36,54 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
expect(page).not_to have_content project_2.name_with_namespace
end
- it 'filters by author' do
- click_button 'Author'
- within '.dropdown-menu-author' do
- fill_in 'Search authors', with: user_1.name
- click_link user_1.name
+ context "Author filter" do
+ it 'filters by author' do
+ click_button 'Author'
+
+ within '.dropdown-menu-author' do
+ fill_in 'Search authors', with: user_1.name
+ click_link user_1.name
+ end
+
+ wait_for_ajax
+
+ expect(find('.todos-list')).to have_content user_1.name
+ expect(find('.todos-list')).not_to have_content user_2.name
end
- wait_for_ajax
+ it "shows only authors of existing todos" do
+ click_button 'Author'
+
+ within '.dropdown-menu-author' do
+ # It should contain two users + "Any Author"
+ expect(page).to have_selector('.dropdown-menu-user-link', count: 3)
+ expect(page).to have_content(user_1.name)
+ expect(page).to have_content(user_2.name)
+ end
+ end
- expect(find('.todos-list')).to have_content user_1.name
- expect(find('.todos-list')).not_to have_content user_2.name
+ it "shows only authors of existing done todos" do
+ user_3 = create :user
+ user_4 = create :user
+ create(:todo, user: user_1, author: user_3, project: project_1, target: issue, action: 1, state: :done)
+ create(:todo, user: user_1, author: user_4, project: project_2, target: merge_request, action: 2, state: :done)
+
+ project_1.team << [user_3, :developer]
+ project_2.team << [user_4, :developer]
+
+ visit dashboard_todos_path(state: 'done')
+
+ click_button 'Author'
+
+ within '.dropdown-menu-author' do
+ # It should contain two users + "Any Author"
+ expect(page).to have_selector('.dropdown-menu-user-link', count: 3)
+ expect(page).to have_content(user_3.name)
+ expect(page).to have_content(user_4.name)
+ expect(page).not_to have_content(user_1.name)
+ expect(page).not_to have_content(user_2.name)
+ end
+ end
end
it 'filters by type' do
diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js
index 1e2072f370a..49dfeab61d8 100644
--- a/spec/javascripts/merge_request_widget_spec.js
+++ b/spec/javascripts/merge_request_widget_spec.js
@@ -1,6 +1,6 @@
/* eslint-disable */
/*= require merge_request_widget */
-/*= require lib/utils/jquery.timeago.js */
+/*= require jquery.timeago.js */
(function() {
describe('MergeRequestWidget', function() {
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index cc215d252f9..2b76e056f3c 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -41,14 +41,62 @@ describe ApplicationSetting, models: true do
subject { setting }
end
- context 'repository storages inclussion' do
+ # Upgraded databases will have this sort of content
+ context 'repository_storages is a String, not an Array' do
+ before { setting.__send__(:raw_write_attribute, :repository_storages, 'default') }
+
+ it { expect(setting.repository_storages_before_type_cast).to eq('default') }
+ it { expect(setting.repository_storages).to eq(['default']) }
+ end
+
+ context 'repository storages' do
before do
- storages = { 'custom' => 'tmp/tests/custom_repositories' }
+ storages = {
+ 'custom1' => 'tmp/tests/custom_repositories_1',
+ 'custom2' => 'tmp/tests/custom_repositories_2',
+ 'custom3' => 'tmp/tests/custom_repositories_3',
+
+ }
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
end
- it { is_expected.to allow_value('custom').for(:repository_storage) }
- it { is_expected.not_to allow_value('alternative').for(:repository_storage) }
+ describe 'inclusion' do
+ it { is_expected.to allow_value('custom1').for(:repository_storages) }
+ it { is_expected.to allow_value(['custom2', 'custom3']).for(:repository_storages) }
+ it { is_expected.not_to allow_value('alternative').for(:repository_storages) }
+ it { is_expected.not_to allow_value(['alternative', 'custom1']).for(:repository_storages) }
+ end
+
+ describe 'presence' do
+ it { is_expected.not_to allow_value([]).for(:repository_storages) }
+ it { is_expected.not_to allow_value("").for(:repository_storages) }
+ it { is_expected.not_to allow_value(nil).for(:repository_storages) }
+ end
+
+ describe '.pick_repository_storage' do
+ it 'uses Array#sample to pick a random storage' do
+ array = double('array', sample: 'random')
+ expect(setting).to receive(:repository_storages).and_return(array)
+
+ expect(setting.pick_repository_storage).to eq('random')
+ end
+
+ describe '#repository_storage' do
+ it 'returns the first storage' do
+ setting.repository_storages = ['good', 'bad']
+
+ expect(setting.repository_storage).to eq('good')
+ end
+ end
+
+ describe '#repository_storage=' do
+ it 'overwrites repository_storages' do
+ setting.repository_storage = 'overwritten'
+
+ expect(setting.repository_storages).to eq(['overwritten'])
+ end
+ end
+ end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index aef277357cf..0245897938c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -837,16 +837,19 @@ describe Project, models: true do
context 'repository storage by default' do
let(:project) { create(:empty_project) }
- subject { project.repository_storage }
-
before do
- storages = { 'alternative_storage' => '/some/path' }
+ storages = {
+ 'default' => 'tmp/tests/repositories',
+ 'picked' => 'tmp/tests/repositories',
+ }
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
- stub_application_setting(repository_storage: 'alternative_storage')
- allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(true)
end
- it { is_expected.to eq('alternative_storage') }
+ it 'picks storage from ApplicationSetting' do
+ expect_any_instance_of(ApplicationSetting).to receive(:pick_repository_storage).and_return('picked')
+
+ expect(project.repository_storage).to eq('picked')
+ end
end
context 'shared runners by default' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index d1ed774a914..ba47479a2e1 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -256,6 +256,20 @@ describe User, models: true do
expect(users_without_two_factor).not_to include(user_with_2fa.id)
end
end
+
+ describe '.todo_authors' do
+ it 'filters users' do
+ create :user
+ user_2 = create :user
+ user_3 = create :user
+ current_user = create :user
+ create(:todo, user: current_user, author: user_2, state: :done)
+ create(:todo, user: current_user, author: user_3, state: :pending)
+
+ expect(User.todo_authors(current_user.id, 'pending')).to eq [user_3]
+ expect(User.todo_authors(current_user.id, 'done')).to eq [user_2]
+ end
+ end
end
describe "Respond to" do
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 3ba257256a0..7b47bf5afc1 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -37,7 +37,7 @@ describe API::API, api: true do
end
end
- context "when authenticated as admin" do
+ context "when authenticated as admin" do
it "admin: returns an array of all groups" do
get api("/groups", admin)
expect(response).to have_http_status(200)
@@ -55,6 +55,17 @@ describe API::API, api: true do
expect(json_response.length).to eq(1)
end
end
+
+ context "when using all_available in request" do
+ it "returns all groups you have access to" do
+ public_group = create :group, :public
+ get api("/groups", user1), all_available: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['name']).to eq(public_group.name)
+ end
+ end
end
describe "GET /groups/:id" do
diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb
index 8f1e5ac9891..131c2d406ea 100644
--- a/spec/requests/api/merge_request_diffs_spec.rb
+++ b/spec/requests/api/merge_request_diffs_spec.rb
@@ -14,14 +14,14 @@ describe API::API, 'MergeRequestDiffs', api: true do
end
describe 'GET /projects/:id/merge_requests/:merge_request_id/versions' do
- context 'valid merge request' do
- before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user) }
- let(:merge_request_diff) { merge_request.merge_request_diffs.first }
-
- it { expect(response.status).to eq 200 }
- it { expect(json_response.size).to eq(merge_request.merge_request_diffs.size) }
- it { expect(json_response.first['id']).to eq(merge_request_diff.id) }
- it { expect(json_response.first['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) }
+ it 'returns 200 for a valid merge request' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user)
+ merge_request_diff = merge_request.merge_request_diffs.first
+
+ expect(response.status).to eq 200
+ expect(json_response.size).to eq(merge_request.merge_request_diffs.size)
+ expect(json_response.first['id']).to eq(merge_request_diff.id)
+ expect(json_response.first['head_commit_sha']).to eq(merge_request_diff.head_commit_sha)
end
it 'returns a 404 when merge_request_id not found' do
@@ -31,14 +31,14 @@ describe API::API, 'MergeRequestDiffs', api: true do
end
describe 'GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id' do
- context 'valid merge request' do
- before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user) }
- let(:merge_request_diff) { merge_request.merge_request_diffs.first }
-
- it { expect(response.status).to eq 200 }
- it { expect(json_response['id']).to eq(merge_request_diff.id) }
- it { expect(json_response['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) }
- it { expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size) }
+ it 'returns a 200 for a valid merge request' do
+ merge_request_diff = merge_request.merge_request_diffs.first
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user)
+
+ expect(response.status).to eq 200
+ expect(json_response['id']).to eq(merge_request_diff.id)
+ expect(json_response['head_commit_sha']).to eq(merge_request_diff.head_commit_sha)
+ expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size)
end
it 'returns a 404 when merge_request_id not found' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index b813ee967f8..bae4fa11ec2 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -186,14 +186,14 @@ describe API::API, api: true do
end
describe 'GET /projects/:id/merge_requests/:merge_request_id/commits' do
- context 'valid merge request' do
- before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/commits", user) }
- let(:commit) { merge_request.commits.first }
-
- it { expect(response.status).to eq 200 }
- it { expect(json_response.size).to eq(merge_request.commits.size) }
- it { expect(json_response.first['id']).to eq(commit.id) }
- it { expect(json_response.first['title']).to eq(commit.title) }
+ it 'returns a 200 when merge request is valid' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/commits", user)
+ commit = merge_request.commits.first
+
+ expect(response.status).to eq 200
+ expect(json_response.size).to eq(merge_request.commits.size)
+ expect(json_response.first['id']).to eq(commit.id)
+ expect(json_response.first['title']).to eq(commit.title)
end
it 'returns a 404 when merge_request_id not found' do
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index f4903d8e0be..096a8ebab70 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -33,6 +33,7 @@ describe API::API, 'Settings', api: true do
expect(json_response['default_projects_limit']).to eq(3)
expect(json_response['signin_enabled']).to be_falsey
expect(json_response['repository_storage']).to eq('custom')
+ expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['koding_enabled']).to be_truthy
expect(json_response['koding_url']).to eq('http://koding.example.com')
end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 7b7d62feb2c..6d49c42c215 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -220,26 +220,33 @@ describe Ci::API::API do
end
context 'when request is valid' do
- it { expect(response.status).to eq 202 }
+ it 'gets correct response' do
+ expect(response.status).to eq 202
+ expect(response.header).to have_key 'Range'
+ expect(response.header).to have_key 'Build-Status'
+ end
+
it { expect(build.reload.trace).to eq 'BUILD TRACE appended' }
- it { expect(response.header).to have_key 'Range' }
- it { expect(response.header).to have_key 'Build-Status' }
end
context 'when content-range start is too big' do
let(:headers_with_range) { headers.merge({ 'Content-Range' => '15-20' }) }
- it { expect(response.status).to eq 416 }
- it { expect(response.header).to have_key 'Range' }
- it { expect(response.header['Range']).to eq '0-11' }
+ it 'gets correct response' do
+ expect(response.status).to eq 416
+ expect(response.header).to have_key 'Range'
+ expect(response.header['Range']).to eq '0-11'
+ end
end
context 'when content-range start is too small' do
let(:headers_with_range) { headers.merge({ 'Content-Range' => '8-20' }) }
- it { expect(response.status).to eq 416 }
- it { expect(response.header).to have_key 'Range' }
- it { expect(response.header['Range']).to eq '0-11' }
+ it 'gets correct response' do
+ expect(response.status).to eq 416
+ expect(response.header).to have_key 'Range'
+ expect(response.header['Range']).to eq '0-11'
+ end
end
context 'when Content-Range header is missing' do
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 43596f07cb5..d6c26fd8a94 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -109,10 +109,12 @@ describe Ci::API::API do
end
describe "DELETE /runners/delete" do
- let!(:runner) { FactoryGirl.create(:ci_runner) }
- before { delete ci_api("/runners/delete"), token: runner.token }
+ it 'returns 200' do
+ runner = FactoryGirl.create(:ci_runner)
+ delete ci_api("/runners/delete"), token: runner.token
- it { expect(response).to have_http_status 200 }
- it { expect(Ci::Runner.count).to eq(0) }
+ expect(response).to have_http_status 200
+ expect(Ci::Runner.count).to eq(0)
+ end
end
end
diff --git a/app/assets/javascripts/lib/utils/jquery.timeago.js b/vendor/assets/javascripts/jquery.timeago.js
index de76cdd2ea7..de76cdd2ea7 100644
--- a/app/assets/javascripts/lib/utils/jquery.timeago.js
+++ b/vendor/assets/javascripts/jquery.timeago.js