diff options
Diffstat (limited to 'app')
63 files changed, 255 insertions, 199 deletions
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index c9612784f9b..4b5c9686cab 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -56,8 +56,7 @@ requireAll(require.context('./u2f', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./droplab', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('.', false, /^\.\/(?!application\.js).*\.(js|es6)$/)); require('vendor/fuzzaldrin-plus'); -window.ES6Promise = require('vendor/es6-promise.auto'); -window.ES6Promise.polyfill(); +require('es6-promise').polyfill(); (function () { document.addEventListener('beforeunload', function () { diff --git a/app/assets/javascripts/boards/filters/due_date_filters.js.es6 b/app/assets/javascripts/boards/filters/due_date_filters.js.es6 index ac2966cef5d..03425bb145b 100644 --- a/app/assets/javascripts/boards/filters/due_date_filters.js.es6 +++ b/app/assets/javascripts/boards/filters/due_date_filters.js.es6 @@ -3,5 +3,5 @@ Vue.filter('due-date', (value) => { const date = new Date(value); - return dateFormat(date, 'mmm d, yyyy'); + return dateFormat(date, 'mmm d, yyyy', true); }); diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 index fbfec7743c7..b5a988df897 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 @@ -20,7 +20,10 @@ $(() => { gl.commits.PipelinesTableBundle.$destroy(true); } - gl.commits.pipelines.PipelinesTableBundle = new gl.commits.pipelines.PipelinesTableView({ - el: document.querySelector('#commit-pipeline-table-view'), - }); + const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); + gl.commits.pipelines.PipelinesTableBundle = new gl.commits.pipelines.PipelinesTableView(); + + if (pipelineTableViewEl && pipelineTableViewEl.dataset.disableInitialization === undefined) { + gl.commits.pipelines.PipelinesTableBundle.$mount(pipelineTableViewEl); + } }); diff --git a/app/assets/javascripts/commit/pipelines/pipelines_service.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_service.js.es6 index 483b414126a..8ae98f9bf97 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_service.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_service.js.es6 @@ -8,7 +8,22 @@ * Uses Vue.Resource */ class PipelinesService { - constructor(endpoint) { + + /** + * FIXME: The url provided to request the pipelines in the new merge request + * page already has `.json`. + * This should be fixed when the endpoint is improved. + * + * @param {String} root + */ + constructor(root) { + let endpoint; + + if (root.indexOf('.json') === -1) { + endpoint = `${root}.json`; + } else { + endpoint = root; + } this.pipelines = Vue.resource(endpoint); } diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_table.js.es6 index ce0dbd4d56b..5c1a7eb1052 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_table.js.es6 @@ -56,15 +56,14 @@ require('./pipelines_store'); }, /** - * When the component is created the service to fetch the data will be - * initialized with the correct endpoint. + * When the component is about to be mounted, tell the service to fetch the data * * A request to fetch the pipelines will be made. * In case of a successfull response we will store the data in the provided * store, in case of a failed response we need to warn the user. * */ - created() { + beforeMount() { const pipelinesService = new gl.commits.pipelines.PipelinesService(this.endpoint); this.isLoading = true; @@ -82,8 +81,8 @@ require('./pipelines_store'); }, template: ` - <div> - <div class="pipelines realtime-loading" v-if="isLoading"> + <div class="pipelines"> + <div class="realtime-loading" v-if="isLoading"> <i class="fa fa-spinner fa-spin"></i> </div> diff --git a/app/assets/javascripts/due_date_select.js.es6 b/app/assets/javascripts/due_date_select.js.es6 index ab5ce23d261..9169fcd7328 100644 --- a/app/assets/javascripts/due_date_select.js.es6 +++ b/app/assets/javascripts/due_date_select.js.es6 @@ -48,7 +48,7 @@ const calendar = new Pikaday({ field: $dueDateInput.get(0), theme: 'gitlab-theme', - format: 'YYYY-MM-DD', + format: 'yyyy-mm-dd', onSelect: (dateText) => { const formattedDate = dateFormat(new Date(dateText), 'yyyy-mm-dd'); @@ -63,6 +63,7 @@ } }); + calendar.setDate(new Date($dueDateInput.val())); this.$datePicker.append(calendar.el); this.$datePicker.data('pikaday', calendar); } @@ -169,11 +170,12 @@ const calendar = new Pikaday({ field: $datePicker.get(0), theme: 'gitlab-theme', - format: 'YYYY-MM-DD', + format: 'yyyy-mm-dd', onSelect(dateText) { $datePicker.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); } }); + calendar.setDate(new Date($datePicker.val())); $datePicker.data('pikaday', calendar); }); diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index 77fa662892a..0d618caf350 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -47,9 +47,11 @@ } // Only filter asynchronously only if option remote is set if (this.options.remote) { + $inputContainer.parent().addClass('is-loading'); clearTimeout(timeout); return timeout = setTimeout(function() { return this.options.query(this.input.val(), function(data) { + $inputContainer.parent().removeClass('is-loading'); return this.options.callback(data); }.bind(this)); }.bind(this), 250); diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 2ec545db665..c7c744ef61f 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -40,11 +40,12 @@ calendar = new Pikaday({ field: $issuableDueDate.get(0), theme: 'gitlab-theme', - format: 'YYYY-MM-DD', + format: 'yyyy-mm-dd', onSelect: function(dateText) { $issuableDueDate.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); } }); + calendar.setDate(new Date($issuableDueDate.val())); } } diff --git a/app/assets/javascripts/member_expiration_date.js.es6 b/app/assets/javascripts/member_expiration_date.js.es6 index f57d4a20498..efe7c78a8ec 100644 --- a/app/assets/javascripts/member_expiration_date.js.es6 +++ b/app/assets/javascripts/member_expiration_date.js.es6 @@ -19,7 +19,7 @@ const calendar = new Pikaday({ field: $input.get(0), theme: 'gitlab-theme', - format: 'YYYY-MM-DD', + format: 'yyyy-mm-dd', minDate: new Date(), onSelect(dateText) { $input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); @@ -30,6 +30,7 @@ }, }); + calendar.setDate(new Date($input.val())); $input.data('pikaday', calendar); }); diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6 index cc049e00477..190336dbd20 100644 --- a/app/assets/javascripts/merge_request_tabs.js.es6 +++ b/app/assets/javascripts/merge_request_tabs.js.es6 @@ -61,6 +61,7 @@ require('./flash'); constructor({ action, setUrl, stubLocation } = {}) { this.diffsLoaded = false; + this.pipelinesLoaded = false; this.commitsLoaded = false; this.fixedLayoutPref = null; @@ -102,9 +103,10 @@ require('./flash'); } clickTab(e) { - if (e.target && gl.utils.isMetaClick(e)) { - const targetLink = e.target.getAttribute('href'); + if (e.currentTarget && gl.utils.isMetaClick(e)) { + const targetLink = e.currentTarget.getAttribute('href'); e.stopImmediatePropagation(); + e.preventDefault(); window.open(targetLink, '_blank'); } } @@ -128,6 +130,13 @@ require('./flash'); $.scrollTo('.merge-request-details .merge-request-tabs', { offset: 0, }); + } else if (action === 'pipelines') { + if (this.pipelinesLoaded) { + return; + } + const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); + gl.commits.pipelines.PipelinesTableBundle.$mount(pipelineTableViewEl); + this.pipelinesLoaded = true; } else { this.expandView(); this.resetViewContainer(); diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js index 514556ade0b..2ae5617206e 100644 --- a/app/assets/javascripts/namespace_select.js +++ b/app/assets/javascripts/namespace_select.js @@ -29,7 +29,7 @@ if (selected.id == null) { return selected.text; } else { - return selected.kind + ": " + selected.path; + return selected.kind + ": " + selected.full_path; } }, data: function(term, dataCallback) { @@ -50,7 +50,7 @@ if (namespace.id == null) { return namespace.text; } else { - return namespace.kind + ": " + namespace.path; + return namespace.kind + ": " + namespace.full_path; } }, renderRow: this.renderRow, diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index e12a45adc9f..553ced4fa55 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -905,9 +905,10 @@ require('./task_list'); }; Notes.prototype.toggleCommitList = function(e) { - const $element = $(e.target); + const $element = $(e.currentTarget); const $closestSystemCommitList = $element.siblings('.system-note-commit-list'); + $element.find('.fa').toggleClass('fa-angle-down').toggleClass('fa-angle-up'); $closestSystemCommitList.toggleClass('hide-shade'); }; diff --git a/app/assets/javascripts/todos.js.es6 b/app/assets/javascripts/todos.js.es6 index b07e62a8c30..ded683f2ca1 100644 --- a/app/assets/javascripts/todos.js.es6 +++ b/app/assets/javascripts/todos.js.es6 @@ -147,24 +147,21 @@ goToTodoUrl(e) { const todoLink = this.dataset.url; - let targetLink = e.target.getAttribute('href'); - - if (e.target.tagName === 'IMG') { // See if clicked target was Avatar - targetLink = e.target.parentElement.getAttribute('href'); // Parent of Avatar is link - } if (!todoLink) { return; } if (gl.utils.isMetaClick(e)) { + const windowTarget = '_blank'; + const selected = e.target; e.preventDefault(); - // Meta-Click on username leads to different URL than todoLink. - // Turbolinks can resolve that URL, but window.open requires URL manually. - if (targetLink !== todoLink) { - return window.open(targetLink, '_blank'); + + if (selected.tagName === 'IMG') { + const avatarUrl = selected.parentElement.getAttribute('href'); + return window.open(avatarUrl, windowTarget); } else { - return window.open(todoLink, '_blank'); + return window.open(todoLink, windowTarget); } } else { return gl.utils.visitUrl(todoLink); diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index da5c44b5fdc..a53cc27fac9 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -193,7 +193,6 @@ top: $header-height; bottom: 0; right: 0; - z-index: 8; transition: width .3s; background: $gray-light; padding: 10px 20px; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index f310cc72da0..aa130a1abb0 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -72,6 +72,7 @@ ul.notes { overflow: hidden; .system-note-commit-list-toggler { + color: $gl-link-color; display: none; padding: 10px 0 0; cursor: pointer; @@ -107,16 +108,6 @@ ul.notes { display: none; } - p:last-child { - a { - color: $gl-text-color; - - &:hover { - color: $gl-link-color; - } - } - } - &::after { content: ''; width: 100%; diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 0c7019dc64f..00eb5b30fd5 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -864,7 +864,7 @@ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; - width: 90px; + max-width: 70%; color: $gl-text-color-secondary; margin-left: 2px; display: inline-block; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 8b59c20cb65..9a72148f408 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -35,12 +35,8 @@ margin-bottom: 10px; } - .project-path { - padding-right: 0; - - .form-control { - border-radius: $border-radius-base; - } + .project-path .form-control { + border-radius: $border-radius-base; } .input-group > div { diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 8fafe472621..948921efc0b 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -171,6 +171,8 @@ .tree-controls { float: right; margin-top: 11px; + position: relative; + z-index: 2; .project-action-button { margin-left: $btn-side-margin; diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index e2d9d5ed460..33379659d73 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -27,7 +27,7 @@ class Projects::TagsController < Projects::ApplicationController end def create - result = CreateTagService.new(@project, current_user). + result = Tags::CreateService.new(@project, current_user). execute(params[:tag_name], params[:ref], params[:message], params[:release_description]) if result[:status] == :success @@ -41,7 +41,7 @@ class Projects::TagsController < Projects::ApplicationController end def destroy - DeleteTagService.new(project, current_user).execute(params[:id]) + Tags::DestroyService.new(project, current_user).execute(params[:id]) respond_to do |format| format.html do diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 0faa71c4d7d..2d8064c9878 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -84,7 +84,7 @@ class Projects::WikisController < Projects::ApplicationController def destroy @page = @project_wiki.find_page(params[:id]) - @page&.delete + WikiPages::DestroyService.new(@project, current_user).execute(@page) redirect_to( namespace_project_wiki_path(@project.namespace, @project, :home), diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index b5f8c23a667..7d8505d704e 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -75,10 +75,10 @@ module MergeRequestsHelper new_namespace_project_merge_request_path( @project.namespace, @project, merge_request: { - source_project_id: @merge_request.source_project_id, - target_project_id: @merge_request.target_project_id, - source_branch: @merge_request.source_branch, - target_branch: @merge_request.target_branch, + source_project_id: merge_request.source_project_id, + target_project_id: merge_request.target_project_id, + source_branch: merge_request.source_branch, + target_branch: merge_request.target_branch, }, change_branches: true ) diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index e0b8dc1393b..0676767d910 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -10,7 +10,7 @@ module NamespacesHelper data_attr_users = { 'data-options-parent' => 'users' } group_opts = [ - "Groups", groups.sort_by(&:human_name).map { |g| [display_path ? g.path : g.human_name, g.id, data_attr_group] } + "Groups", groups.sort_by(&:human_name).map { |g| [display_path ? g.full_path : g.human_name, g.id, data_attr_group] } ] users_opts = [ diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index b3f50ceebe4..9a748aaaf33 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -63,7 +63,7 @@ module SubmoduleHelper namespace = components.pop.gsub(/^\.\.$/, '') if namespace.empty? - namespace = @project.namespace.path + namespace = @project.namespace.full_path end [ diff --git a/app/models/event.rb b/app/models/event.rb index cf89ac5207f..e5027df3f8a 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -45,9 +45,10 @@ class Event < ActiveRecord::Base class << self # Update Gitlab::ContributionsCalendar#activity_dates if this changes def contributions - where("action = ? OR (target_type in (?) AND action in (?))", - Event::PUSHED, ["MergeRequest", "Issue"], - [Event::CREATED, Event::CLOSED, Event::MERGED]) + where("action = ? OR (target_type IN (?) AND action IN (?)) OR (target_type = ? AND action = ?)", + Event::PUSHED, + ["MergeRequest", "Issue"], [Event::CREATED, Event::CLOSED, Event::MERGED], + "Note", Event::COMMENTED) end def limit_recent(limit = 20, offset = nil) diff --git a/app/models/group.rb b/app/models/group.rb index cc6624ff4aa..240a17f1dc1 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -81,7 +81,7 @@ class Group < Namespace end def to_reference(_from_project = nil, full: nil) - "#{self.class.reference_prefix}#{name}" + "#{self.class.reference_prefix}#{full_path}" end def web_url diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 38646eba3ac..204d2b153ad 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -598,7 +598,7 @@ class MergeRequest < ActiveRecord::Base def source_project_namespace if source_project && source_project.namespace - source_project.namespace.path + source_project.namespace.full_path else "(removed)" end @@ -606,7 +606,7 @@ class MergeRequest < ActiveRecord::Base def target_project_namespace if target_project && target_project.namespace - target_project.namespace.path + target_project.namespace.full_path else "(removed)" end diff --git a/app/models/project.rb b/app/models/project.rb index aa408b4556e..ed43fc2e575 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -454,7 +454,7 @@ class Project < ActiveRecord::Base if forked? job_id = RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path, forked_from_project.path_with_namespace, - self.namespace.path) + self.namespace.full_path) else job_id = RepositoryImportWorker.perform_async(self.id) end @@ -942,8 +942,8 @@ class Project < ActiveRecord::Base Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" - Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path) - Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.path) + Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path) + Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path) end # Expires various caches before a project is renamed. @@ -1150,19 +1150,25 @@ class Project < ActiveRecord::Base end def pages_url + subdomain, _, url_path = full_path.partition('/') + # The hostname always needs to be in downcased # All web servers convert hostname to lowercase - host = "#{namespace.path}.#{Settings.pages.host}".downcase + host = "#{subdomain}.#{Settings.pages.host}".downcase # The host in URL always needs to be downcased url = Gitlab.config.pages.url.sub(/^https?:\/\//) do |prefix| - "#{prefix}#{namespace.path}." + "#{prefix}#{subdomain}." end.downcase # If the project path is the same as host, we serve it as group page - return url if host == path + return url if host == url_path + + "#{url}/#{url_path}" + end - "#{url}/#{path}" + def pages_subdomain + full_path.partition('/').first end def pages_path @@ -1179,8 +1185,8 @@ class Project < ActiveRecord::Base # 3. We asynchronously remove pages with force temp_path = "#{path}.#{SecureRandom.hex}.deleted" - if Gitlab::PagesTransfer.new.rename_project(path, temp_path, namespace.path) - PagesWorker.perform_in(5.minutes, :remove, namespace.path, temp_path) + if Gitlab::PagesTransfer.new.rename_project(path, temp_path, namespace.full_path) + PagesWorker.perform_in(5.minutes, :remove, namespace.full_path, temp_path) end end @@ -1230,7 +1236,7 @@ class Project < ActiveRecord::Base end def ensure_dir_exist - gitlab_shell.add_namespace(repository_storage_path, namespace.path) + gitlab_shell.add_namespace(repository_storage_path, namespace.full_path) end def predefined_variables @@ -1238,7 +1244,7 @@ class Project < ActiveRecord::Base { key: 'CI_PROJECT_ID', value: id.to_s, public: true }, { key: 'CI_PROJECT_NAME', value: path, public: true }, { key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true }, - { key: 'CI_PROJECT_NAMESPACE', value: namespace.path, public: true }, + { key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true }, { key: 'CI_PROJECT_URL', value: web_url, public: true } ] end diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb index 0a217d8caba..942ec9371e5 100644 --- a/app/models/project_services/drone_ci_service.rb +++ b/app/models/project_services/drone_ci_service.rb @@ -12,7 +12,7 @@ class DroneCiService < CiService def compose_service_hook hook = service_hook || build_service_hook # If using a service template, project may not be available - hook.url = [drone_url, "/api/hook", "?owner=#{project.namespace.path}", "&name=#{project.path}", "&access_token=#{token}"].join if project + hook.url = [drone_url, "/api/hook", "?owner=#{project.namespace.full_path}", "&name=#{project.path}", "&access_token=#{token}"].join if project hook.enable_ssl_verification = !!enable_ssl_verification hook.save end @@ -38,7 +38,7 @@ class DroneCiService < CiService def commit_status_path(sha, ref) url = [drone_url, - "gitlab/#{project.namespace.path}/#{project.path}/commits/#{sha}", + "gitlab/#{project.full_path}/commits/#{sha}", "?branch=#{URI::encode(ref.to_s)}&access_token=#{token}"] URI.join(*url).to_s @@ -73,7 +73,7 @@ class DroneCiService < CiService def build_page(sha, ref) url = [drone_url, - "gitlab/#{project.namespace.path}/#{project.path}/redirect/commits/#{sha}", + "gitlab/#{project.full_path}/redirect/commits/#{sha}", "?branch=#{URI::encode(ref.to_s)}"] URI.join(*url).to_s diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb deleted file mode 100644 index bbc312f5215..00000000000 --- a/app/models/project_services/gitlab_ci_service.rb +++ /dev/null @@ -1,8 +0,0 @@ -# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed -class GitlabCiService < CiService - # We override the active accessor to always make GitLabCiService disabled - # Otherwise the GitLabCiService can be picked, but should never be since it's deprecated - def active - false - end -end diff --git a/app/models/service.rb b/app/models/service.rb index 043be222f3a..facaaf9b331 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -27,7 +27,7 @@ class Service < ActiveRecord::Base validates :project_id, presence: true, unless: Proc.new { |service| service.template? } - scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) } + scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') } scope :issue_trackers, -> { where(category: 'issue_tracker') } scope :external_wikis, -> { where(type: 'ExternalWikiService').active } scope :active, -> { where(active: true) } diff --git a/app/models/user.rb b/app/models/user.rb index 1649bf04eaa..ad997ce2b13 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -335,7 +335,7 @@ class User < ActiveRecord::Base def reference_pattern %r{ #{Regexp.escape(reference_prefix)} - (?<user>#{Gitlab::Regex::NAMESPACE_REGEX_STR}) + (?<user>#{Gitlab::Regex::NAMESPACE_REF_REGEX_STR}) }x end end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 6347b274341..2caebb496db 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -207,6 +207,10 @@ class WikiPage 'projects/wikis/wiki_page' end + def id + page.version.to_s + end + private def set_attributes diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb deleted file mode 100644 index 6c75d1f04ff..00000000000 --- a/app/services/create_tag_service.rb +++ /dev/null @@ -1,30 +0,0 @@ -class CreateTagService < BaseService - def execute(tag_name, target, message, release_description = nil) - valid_tag = Gitlab::GitRefValidator.validate(tag_name) - return error('Tag name invalid') unless valid_tag - - repository = project.repository - message&.strip! - - new_tag = nil - - begin - new_tag = repository.add_tag(current_user, tag_name, target, message) - rescue Rugged::TagError - return error("Tag #{tag_name} already exists") - rescue GitHooksService::PreReceiveError => ex - return error(ex.message) - end - - if new_tag - if release_description - CreateReleaseService.new(@project, @current_user). - execute(tag_name, release_description) - end - - success.merge(tag: new_tag) - else - error("Target #{target} is invalid") - end - end -end diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb deleted file mode 100644 index eb726cb04b1..00000000000 --- a/app/services/delete_tag_service.rb +++ /dev/null @@ -1,42 +0,0 @@ -class DeleteTagService < BaseService - def execute(tag_name) - repository = project.repository - tag = repository.find_tag(tag_name) - - unless tag - return error('No such tag', 404) - end - - if repository.rm_tag(current_user, tag_name) - release = project.releases.find_by(tag: tag_name) - release&.destroy - - push_data = build_push_data(tag) - EventCreateService.new.push(project, current_user, push_data) - project.execute_hooks(push_data.dup, :tag_push_hooks) - project.execute_services(push_data.dup, :tag_push_hooks) - - success('Tag was removed') - else - error('Failed to remove tag') - end - end - - def error(message, return_code = 400) - super(message).merge(return_code: return_code) - end - - def success(message) - super().merge(message: message) - end - - def build_push_data(tag) - Gitlab::DataBuilder::Push.build( - project, - current_user, - tag.dereferenced_target.sha, - Gitlab::Git::BLANK_SHA, - "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", - []) - end -end diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb index 96c363c8d1a..e6193fcacee 100644 --- a/app/services/projects/participants_service.rb +++ b/app/services/projects/participants_service.rb @@ -36,7 +36,7 @@ module Projects def groups current_user.authorized_groups.sort_by(&:path).map do |group| count = group.users.count - { username: group.path, name: group.name, count: count, avatar_url: group.avatar_url } + { username: group.full_path, name: group.full_name, count: count, avatar_url: group.avatar_url } end end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 484700c8c29..20dfbddc823 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -30,7 +30,7 @@ module Projects Project.transaction do old_path = project.path_with_namespace old_group = project.group - new_path = File.join(new_namespace.try(:path) || '', project.path) + new_path = File.join(new_namespace.try(:full_path) || '', project.path) if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present? raise TransferError.new("Project with same path in target namespace already exists") @@ -63,10 +63,10 @@ module Projects Labels::TransferService.new(current_user, old_group, project).execute # Move uploads - Gitlab::UploadsTransfer.new.move_project(project.path, old_namespace.path, new_namespace.path) + Gitlab::UploadsTransfer.new.move_project(project.path, old_namespace.full_path, new_namespace.full_path) # Move pages - Gitlab::PagesTransfer.new.move_project(project.path, old_namespace.path, new_namespace.path) + Gitlab::PagesTransfer.new.move_project(project.path, old_namespace.full_path, new_namespace.full_path) project.old_path_with_namespace = old_path diff --git a/app/services/tags/create_service.rb b/app/services/tags/create_service.rb new file mode 100644 index 00000000000..1756da9e519 --- /dev/null +++ b/app/services/tags/create_service.rb @@ -0,0 +1,32 @@ +module Tags + class CreateService < BaseService + def execute(tag_name, target, message, release_description = nil) + valid_tag = Gitlab::GitRefValidator.validate(tag_name) + return error('Tag name invalid') unless valid_tag + + repository = project.repository + message&.strip! + + new_tag = nil + + begin + new_tag = repository.add_tag(current_user, tag_name, target, message) + rescue Rugged::TagError + return error("Tag #{tag_name} already exists") + rescue GitHooksService::PreReceiveError => ex + return error(ex.message) + end + + if new_tag + if release_description + CreateReleaseService.new(@project, @current_user). + execute(tag_name, release_description) + end + + success.merge(tag: new_tag) + else + error("Target #{target} is invalid") + end + end + end +end diff --git a/app/services/tags/destroy_service.rb b/app/services/tags/destroy_service.rb new file mode 100644 index 00000000000..910b4f5e361 --- /dev/null +++ b/app/services/tags/destroy_service.rb @@ -0,0 +1,44 @@ +module Tags + class DestroyService < BaseService + def execute(tag_name) + repository = project.repository + tag = repository.find_tag(tag_name) + + unless tag + return error('No such tag', 404) + end + + if repository.rm_tag(current_user, tag_name) + release = project.releases.find_by(tag: tag_name) + release&.destroy + + push_data = build_push_data(tag) + EventCreateService.new.push(project, current_user, push_data) + project.execute_hooks(push_data.dup, :tag_push_hooks) + project.execute_services(push_data.dup, :tag_push_hooks) + + success('Tag was removed') + else + error('Failed to remove tag') + end + end + + def error(message, return_code = 400) + super(message).merge(return_code: return_code) + end + + def success(message) + super().merge(message: message) + end + + def build_push_data(tag) + Gitlab::DataBuilder::Push.build( + project, + current_user, + tag.dereferenced_target.sha, + Gitlab::Git::BLANK_SHA, + "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", + []) + end + end +end diff --git a/app/services/wiki_pages/destroy_service.rb b/app/services/wiki_pages/destroy_service.rb new file mode 100644 index 00000000000..6b93fb2f6d7 --- /dev/null +++ b/app/services/wiki_pages/destroy_service.rb @@ -0,0 +1,11 @@ +module WikiPages + class DestroyService < WikiPages::BaseService + def execute(page) + if page&.delete + execute_hooks(page, 'delete') + end + + page + end + end +end diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb index 47bef7cd1e4..23b7318827c 100644 --- a/app/uploaders/file_uploader.rb +++ b/app/uploaders/file_uploader.rb @@ -36,7 +36,7 @@ class FileUploader < GitlabUploader escaped_filename = filename.gsub("]", "\\]") markdown = "[#{escaped_filename}](#{self.secure_url})" - markdown.prepend("!") if image_or_video? + markdown.prepend("!") if image_or_video? || dangerous? { alt: filename, diff --git a/app/uploaders/uploader_helper.rb b/app/uploaders/uploader_helper.rb index fbaea2744a3..35fd1ed23f8 100644 --- a/app/uploaders/uploader_helper.rb +++ b/app/uploaders/uploader_helper.rb @@ -1,12 +1,15 @@ # Extra methods for uploader module UploaderHelper - IMAGE_EXT = %w[png jpg jpeg gif bmp tiff svg] + IMAGE_EXT = %w[png jpg jpeg gif bmp tiff] # We recommend using the .mp4 format over .mov. Videos in .mov format can # still be used but you really need to make sure they are served with the # proper MIME type video/mp4 and not video/quicktime or your videos won't play # on IE >= 9. # http://archive.sublimevideo.info/20150912/docs.sublimevideo.net/troubleshooting.html VIDEO_EXT = %w[mp4 m4v mov webm ogv] + # These extension types can contain dangerous code and should only be embedded inline with + # proper filtering. They should always be tagged as "Content-Disposition: attachment", not "inline". + DANGEROUS_EXT = %w[svg] def image? extension_match?(IMAGE_EXT) @@ -20,6 +23,10 @@ module UploaderHelper image? || video? end + def dangerous? + extension_match?(DANGEROUS_EXT) + end + def extension_match?(extensions) return false unless file diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 5238623e936..e67ad663720 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -163,6 +163,6 @@ - @groups.each do |group| %p = link_to [:admin, group], class: 'str-truncated-60' do - = group.name + = group.full_name %span.light.pull-right #{time_ago_with_tooltip(group.created_at)} diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index cf8d438670b..cdef63daca9 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -30,7 +30,7 @@ - toggle_text = 'Namespace' - if params[:namespace_id].present? - namespace = Namespace.find(params[:namespace_id]) - - toggle_text = "#{namespace.kind}: #{namespace.path}" + - toggle_text = "#{namespace.kind}: #{namespace.full_path}" = dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { toggle_class: 'js-namespace-select large' }) .dropdown-menu.dropdown-select.dropdown-menu-align-right = dropdown_title('Namespaces') diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml index 975bd950ae1..deb62845e1c 100644 --- a/app/views/admin/runners/_runner.html.haml +++ b/app/views/admin/runners/_runner.html.haml @@ -22,7 +22,7 @@ %td #{runner.builds.count(:all)} %td - - runner.tag_list.each do |tag| + - runner.tag_list.sort.each do |tag| %span.label.label-primary = tag %td diff --git a/app/views/dashboard/_activity_head.html.haml b/app/views/dashboard/_activity_head.html.haml index 02b94beee92..68a46f61eb7 100644 --- a/app/views/dashboard/_activity_head.html.haml +++ b/app/views/dashboard/_activity_head.html.haml @@ -1,7 +1,8 @@ -%ul.nav-links - %li{ class: ("active" unless params[:filter]) }> - = link_to activity_dashboard_path, class: 'shortcuts-activity', data: {placement: 'right'} do - Your Projects - %li{ class: ("active" if params[:filter] == 'starred') }> - = link_to activity_dashboard_path(filter: 'starred'), data: {placement: 'right'} do - Starred Projects +.top-area + %ul.nav-links + %li{ class: ("active" unless params[:filter]) }> + = link_to activity_dashboard_path, class: 'shortcuts-activity', data: {placement: 'right'} do + Your Projects + %li{ class: ("active" if params[:filter] == 'starred') }> + = link_to activity_dashboard_path(filter: 'starred'), data: {placement: 'right'} do + Starred Projects diff --git a/app/views/import/base/unauthorized.js.haml b/app/views/import/base/unauthorized.js.haml index 36f8069c1f7..ada5f99f4e2 100644 --- a/app/views/import/base/unauthorized.js.haml +++ b/app/views/import/base/unauthorized.js.haml @@ -4,7 +4,7 @@ import_button = tr.find(".btn-import") origin_target = target_field.text() project_name = "#{@project_name}" - origin_namespace = "#{@target_namespace.path}" + origin_namespace = "#{@target_namespace.full_path}" target_field.empty() target_field.append("<p class='alert alert-danger'>This namespace has already been taken! Please choose another one.</p>") target_field.append("<input type='text' name='target_namespace' />") diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml index 2c006e1712d..b10f5fc08e2 100644 --- a/app/views/profiles/personal_access_tokens/index.html.haml +++ b/app/views/profiles/personal_access_tokens/index.html.haml @@ -91,7 +91,7 @@ new Pikaday({ field: $dateField.get(0), theme: 'gitlab-theme', - format: 'YYYY-MM-DD', + format: 'yyyy-mm-dd', minDate: new Date(), onSelect: function(dateText) { $dateField.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 1b9d87e9969..79a0dc1b959 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -28,9 +28,11 @@ .project-clone-holder = render "shared/clone_panel" - - if current_user && can?(current_user, :download_code, @project) - = render 'projects/buttons/download', project: @project, ref: @ref - = render 'projects/buttons/dropdown' + - if current_user + - if can?(current_user, :download_code, @project) + = render 'projects/buttons/download', project: @project, ref: @ref + = render 'projects/buttons/dropdown' + = render 'projects/buttons/koding' + = render 'shared/notifications/button', notification_setting: @notification_setting - = render 'projects/buttons/koding' = render 'shared/members/access_request_buttons', source: @project diff --git a/app/views/projects/commit/_pipelines_list.haml b/app/views/projects/commit/_pipelines_list.haml index aae2cb8a04b..33917513f37 100644 --- a/app/views/projects/commit/_pipelines_list.haml +++ b/app/views/projects/commit/_pipelines_list.haml @@ -1,4 +1,7 @@ -#commit-pipeline-table-view{ data: { endpoint: endpoint } } +- disable_initialization = local_assigns.fetch(:disable_initialization, false) +#commit-pipeline-table-view{ data: { disable_initialization: disable_initialization, + endpoint: endpoint, +} } .pipeline-svgs{ data: { "commit_icon_svg" => custom_icon("icon_commit"), "icon_status_canceled" => custom_icon("icon_status_canceled"), "icon_status_running" => custom_icon("icon_status_running"), diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 9c5c1a6d707..b9300efd04f 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -6,7 +6,7 @@ .col-lg-9 .project-edit-errors = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f| - %fieldset.append-bottom-0 + %fieldset .row .form-group.col-md-9 = f.label :name, class: 'label-light', for: 'project_name_edit' do @@ -33,7 +33,7 @@ = f.text_field :tag_list, value: @project.tag_list.to_s, maxlength: 2000, class: "form-control" %p.help-block Separate tags with commas. %hr - %fieldset.append-bottom-0 + %fieldset %h5.prepend-top-0 Sharing & Permissions .form_group.prepend-top-20.sharing-and-permissions @@ -232,7 +232,7 @@ .form-group .input-group .input-group-addon - #{URI.join(root_url, @project.namespace.path)}/ + #{URI.join(root_url, @project.namespace.full_path)}/ = f.text_field :path, class: 'form-control' %ul %li Be careful. Renaming a project's repository can have unintended side effects. diff --git a/app/views/projects/group_links/_index.html.haml b/app/views/projects/group_links/_index.html.haml index 99d0df2ac34..b6116dbec41 100644 --- a/app/views/projects/group_links/_index.html.haml +++ b/app/views/projects/group_links/_index.html.haml @@ -39,7 +39,7 @@ = icon("folder-open-o", class: "settings-list-icon") .pull-left = link_to group do - = group.name + = group.full_name %br up to #{group_link.human_access} - if group_link.expires? diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index dd615d3036c..521b0694ca9 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -94,7 +94,7 @@ -# This tab is always loaded via AJAX #pipelines.pipelines.tab-pane - if @pipelines.any? - = render 'projects/commit/pipelines_list', endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) + = render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) #diffs.diffs.tab-pane -# This tab is always loaded via AJAX diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 41473fae4de..a07885537b9 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -12,7 +12,7 @@ Create or Import your project from popular Git services .col-lg-9 = form_for @project, html: { class: 'new_project' } do |f| - %fieldset.append-bottom-0 + .row .form-group.col-xs-12.col-sm-6 = f.label :namespace_id, class: 'label-light' do %span diff --git a/app/views/projects/notes/_hints.html.haml b/app/views/projects/notes/_hints.html.haml index 6c14f48d41b..81d97eabe65 100644 --- a/app/views/projects/notes/_hints.html.haml +++ b/app/views/projects/notes/_hints.html.haml @@ -1,7 +1,6 @@ - supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false) .comment-toolbar.clearfix .toolbar-text - Styling with = link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1 - if supports_slash_commands and diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 21494e21be3..a73e8f345e0 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -77,6 +77,7 @@ - if note.system .system-note-commit-list-toggler Toggle commit list + %i.fa.fa-angle-down - if note.attachment.url .note-attachment - if note.attachment.image? diff --git a/app/views/projects/pages_domains/show.html.haml b/app/views/projects/pages_domains/show.html.haml index 52dddb052a7..876cac0dacb 100644 --- a/app/views/projects/pages_domains/show.html.haml +++ b/app/views/projects/pages_domains/show.html.haml @@ -17,7 +17,7 @@ %p To access the domain create a new DNS record: %pre - #{@domain.domain} CNAME #{@domain.project.namespace.path}.#{Settings.pages.host}. + #{@domain.domain} CNAME #{@domain.project.pages_subdomain}.#{Settings.pages.host}. %tr %td Certificate diff --git a/app/views/projects/runners/_form.html.haml b/app/views/projects/runners/_form.html.haml index 98e72f6c547..2ef1f98ba48 100644 --- a/app/views/projects/runners/_form.html.haml +++ b/app/views/projects/runners/_form.html.haml @@ -32,7 +32,7 @@ = label_tag :tag_list, class: 'control-label' do Tags .col-sm-10 - = f.text_field :tag_list, value: runner.tag_list.to_s, class: 'form-control' + = f.text_field :tag_list, value: runner.tag_list.sort.join(', '), class: 'form-control' .help-block You can setup jobs to only use Runners with specific tags .form-actions = f.submit 'Save changes', class: 'btn btn-save' diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml index 7036b8a5ccc..deeadb609f6 100644 --- a/app/views/projects/runners/_runner.html.haml +++ b/app/views/projects/runners/_runner.html.haml @@ -31,6 +31,6 @@ = runner.description - if runner.tag_list.present? %p - - runner.tag_list.each do |tag| + - runner.tag_list.sort.each do |tag| %span.label.label-primary = tag diff --git a/app/views/projects/runners/show.html.haml b/app/views/projects/runners/show.html.haml index 61b99f35d74..49415ba557b 100644 --- a/app/views/projects/runners/show.html.haml +++ b/app/views/projects/runners/show.html.haml @@ -28,7 +28,7 @@ %tr %td Tags %td - - @runner.tag_list.each do |tag| + - @runner.tag_list.sort.each do |tag| %span.label.label-primary = tag %tr diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index 81b5bc1de30..1d5a61cffce 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -6,7 +6,7 @@ %span.list-item-name = image_tag group_icon(group), class: "avatar s40", alt: '' %strong - = link_to group.name, group_path(group) + = link_to group.full_name, group_path(group) .cgray Joined #{time_ago_with_tooltip(group.created_at)} - if group_link.expires? diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml index 6228245d8d0..57b8845c55d 100644 --- a/app/views/users/calendar.html.haml +++ b/app/views/users/calendar.html.haml @@ -1,7 +1,7 @@ .clearfix.calendar .js-contrib-calendar .calendar-hint - Summary of issues, merge requests, and push events + Summary of issues, merge requests, push events, and comments :javascript new Calendar( #{@activity_dates.to_json}, diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml index b09782749f5..4afd31f788b 100644 --- a/app/views/users/calendar_activities.html.haml +++ b/app/views/users/calendar_activities.html.haml @@ -10,11 +10,17 @@ %i.fa.fa-clock-o = event.created_at.to_s(:time) - if event.push? - #{event.action_name} #{event.ref_type} #{event.ref_name} + #{event.action_name} #{event.ref_type} + %strong + - commits_path = namespace_project_commits_path(event.project.namespace, event.project, event.ref_name) + = link_to_if event.project.repository.branch_exists?(event.ref_name), event.ref_name, commits_path - else = event_action_name(event) - - if event.target - %strong= link_to "#{event.target.to_reference}", [event.project.namespace.becomes(Namespace), event.project, event.target] + %strong + - if event.note? + = link_to event.note_target.to_reference, event_note_target_path(event) + - elsif event.target + = link_to event.target.to_reference, [event.project.namespace.becomes(Namespace), event.project, event.target] at %strong diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 44254040e4e..dc2fea450bd 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -106,6 +106,8 @@ %i.fa.fa-spinner.fa-spin .user-calendar-activities + %h4.prepend-top-20 + Most Recent Activity .content_list{ data: { href: user_path } } = spinner |