Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into task_list_refactor

This commit is contained in:
Simon Knox 2017-02-16 13:10:32 +11:00
commit 8a928af0fc
290 changed files with 7522 additions and 3244 deletions

View File

@ -12,12 +12,18 @@
"localStorage": false
},
"plugins": [
"filenames"
"filenames",
"import"
],
"settings": {
"import/resolver": {
"webpack": {
"config": "./config/webpack.config.js"
}
}
},
"rules": {
"filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"],
"no-multiple-empty-lines": ["error", { "max": 1 }],
"import/no-extraneous-dependencies": "off",
"import/no-unresolved": "off"
"no-multiple-empty-lines": ["error", { "max": 1 }]
}
}

View File

@ -107,7 +107,10 @@ setup-test-env:
<<: *dedicated-runner
stage: prepare
script:
- npm install
- node --version
- yarn --version
- yarn install --pure-lockfile
- yarn check # ensure that yarn.lock matches package.json
- bundle exec rake gitlab:assets:compile
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts:
@ -246,13 +249,12 @@ karma:
<<: *use-db
<<: *dedicated-runner
script:
- npm link istanbul
- bundle exec rake karma
artifacts:
name: coverage-javascript
expire_in: 31d
paths:
- coverage-javascript/default/
- coverage-javascript/
lint-doc:
stage: test
@ -325,11 +327,9 @@ lint:javascript:
paths:
- node_modules/
stage: test
image: "node:7.1"
before_script:
- npm install
before_script: []
script:
- npm --silent run eslint
- yarn run eslint
lint:javascript:report:
<<: *dedicated-runner
@ -337,12 +337,10 @@ lint:javascript:report:
paths:
- node_modules/
stage: post-test
image: "node:7.1"
before_script:
- npm install
before_script: []
script:
- find app/ spec/ -name '*.js' -or -name '*.js.es6' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files
- npm --silent run eslint-report || true # ignore exit code
- yarn run eslint-report || true # ignore exit code
artifacts:
name: eslint-report
expire_in: 31d
@ -395,7 +393,7 @@ pages:
- mv public/ .public/
- mkdir public/
- mv coverage/ public/coverage-ruby/ || true
- mv coverage-javascript/default/ public/coverage-javascript/ || true
- mv coverage-javascript/ public/coverage-javascript/ || true
- mv eslint-report.html public/ || true
artifacts:
paths:

View File

@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 8.16.5 (2017-02-14)
- Patch Asciidocs rendering to block XSS.
- Fix XSS vulnerability in SVG attachments.
- Prevent the GitHub importer from assigning labels and comments to merge requests or issues belonging to other projects.
- Patch XSS vulnerability in RDOC support.
## 8.16.4 (2017-02-02)
- Support non-ASCII characters in GFM autocomplete. !8729
@ -174,6 +181,13 @@ entry.
- Add margin to markdown math blocks.
- Add hover state to MR comment reply button.
## 8.15.6 (2017-02-14)
- Patch Asciidocs rendering to block XSS.
- Fix XSS vulnerability in SVG attachments.
- Prevent the GitHub importer from assigning labels and comments to merge requests or issues belonging to other projects.
- Patch XSS vulnerability in RDOC support.
## 8.15.4 (2017-01-09)
- Make successful pipeline emails off for watchers. !8176
@ -437,6 +451,13 @@ entry.
- Whitelist next project names: help, ci, admin, search. !8227
- Adds back CSS for progress-bars. !8237
## 8.14.9 (2017-02-14)
- Patch Asciidocs rendering to block XSS.
- Fix XSS vulnerability in SVG attachments.
- Prevent the GitHub importer from assigning labels and comments to merge requests or issues belonging to other projects.
- Patch XSS vulnerability in RDOC support.
## 8.14.8 (2017-01-25)
- Accept environment variables from the `pre-receive` script. !7967

View File

@ -29,6 +29,7 @@ gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.2'
gem 'omniauth-google-oauth2', '~> 0.4.1'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-oauth2-generic', '~> 0.2.2'
gem 'omniauth-saml', '~> 1.7.0'
gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0'

View File

@ -483,6 +483,8 @@ GEM
omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-oauth2-generic (0.2.2)
omniauth-oauth2 (~> 1.0)
omniauth-saml (1.7.0)
omniauth (~> 1.3)
ruby-saml (~> 1.4)
@ -931,6 +933,7 @@ DEPENDENCIES
omniauth-gitlab (~> 1.0.2)
omniauth-google-oauth2 (~> 0.4.1)
omniauth-kerberos (~> 0.3.0)
omniauth-oauth2-generic (~> 0.2.2)
omniauth-saml (~> 1.7.0)
omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0)

View File

@ -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 () {

View File

@ -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);
});

View File

@ -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);
}
});

View File

@ -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);
}

View File

@ -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>

View File

@ -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);
});

View File

@ -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);

View File

@ -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()));
}
}

View File

@ -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);
});

View File

@ -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();

View File

@ -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,

View File

@ -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');
};

View File

@ -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);

View File

@ -193,7 +193,6 @@
top: $header-height;
bottom: 0;
right: 0;
z-index: 8;
transition: width .3s;
background: $gray-light;
padding: 10px 20px;

View File

@ -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%;

View File

@ -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;

View File

@ -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 {

View File

@ -171,6 +171,8 @@
.tree-controls {
float: right;
margin-top: 11px;
position: relative;
z-index: 2;
.project-action-button {
margin-left: $btn-side-margin;

View File

@ -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

View File

@ -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),

View File

@ -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
)

View File

@ -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 = [

View File

@ -63,7 +63,7 @@ module SubmoduleHelper
namespace = components.pop.gsub(/^\.\.$/, '')
if namespace.empty?
namespace = @project.namespace.path
namespace = @project.namespace.full_path
end
[

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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}/#{path}"
"#{url}/#{url_path}"
end
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

View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -207,6 +207,10 @@ class WikiPage
'projects/wikis/wiki_page'
end
def id
page.version.to_s
end
private
def set_attributes

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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)}

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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' />")

View File

@ -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'));

View File

@ -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

View File

@ -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"),

View File

@ -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 &amp; 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.

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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},

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
---
title: Move /projects/fork/:id to /projects/:id/fork
merge_request: 8940
author:

View File

@ -0,0 +1,4 @@
---
title: Execute web hooks for WikiPage delete operation
merge_request: 8198
author:

View File

@ -0,0 +1,4 @@
---
title: Add discussion events to contributions calendar
merge_request: 8821
author:

View File

@ -0,0 +1,4 @@
---
title: 'API: Consolidate /projects endpoint'
merge_request: 8962
author:

View File

@ -0,0 +1,4 @@
---
title: Added 'Most Recent Activity' header to the User Profile page
merge_request: 9189
author: Jan Christophersen

View File

@ -0,0 +1,4 @@
---
title: Add Links to Branches in Calendar Activity
merge_request: 9224
author: Jan Christophersen

View File

@ -0,0 +1,4 @@
---
title: Specify in the documentation that only projects owners can transfer projects
merge_request:
author:

View File

@ -0,0 +1,3 @@
title: Add the oauth2_generic OmniAuth strategy
merge_request: 9048
author: Joe Marty

View File

@ -0,0 +1,4 @@
---
title: "Fix small height of activity header page"
merge_request: 8952
author: Pavel Sorokin

View File

@ -0,0 +1,4 @@
---
title: Update doc for enabling or disabling GitLab CI
merge_request: 8965
author: Takuya Noguchi

View File

@ -0,0 +1,5 @@
---
title: Fix regression where cmd-click stopped working for todos and merge request
tabs
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Set maximum width for mini pipeline graph text so it is not truncated to early
merge_request: 9188
author:

View File

@ -0,0 +1,4 @@
---
title: Fix stray pipelines API request when showing MR
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Fix Merge request pipelines displays JSON
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Display loading indicator when filtering ref switcher dropdown
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Fix z index issues with sidebar
merge_request:
author:

View File

@ -0,0 +1,5 @@
---
title: Centers loading icon vertically and horizontally in pipelines table in commit
view
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Alphabetically sort tags on runner list
merge_request: 8922
author: blackst0ne

View File

@ -0,0 +1,4 @@
---
title: "Use an entity for RepoBranch commits and enhance RepoCommit"
merge_request: 7138
author: Ben Boeckel

View File

@ -0,0 +1,4 @@
---
title: Reintroduce coverage report for JavaScript
merge_request: 9133
author: winniehell

View File

@ -0,0 +1,4 @@
---
title: Replace static fixture for right_sidebar_spec.js
merge_request: 9211
author: winniehell

View File

@ -0,0 +1,4 @@
---
title: Don't connect in Gitlab::Database.adapter_name
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Show notifications settings dropdown even if repository feature is disabled
merge_request: 9180
author:

View File

@ -0,0 +1,4 @@
---
title: Fix timezone on issue boards due date
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Disable invalid service templates
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Move tag services to Tags namespace
merge_request:
author: dixpac

View File

@ -0,0 +1,4 @@
---
title: Make it possible to pass coverage value to commit status API
merge_request: 9214
author: wendy0402

View File

@ -0,0 +1,4 @@
---
title: Remove inactive default email services
merge_request: 8987
author:

View File

@ -0,0 +1,4 @@
---
title: replace npm with yarn and add yarn.lock
merge_request: 9055
author:

View File

@ -0,0 +1,4 @@
---
title: Replace static fixture for behaviors/requires_input_spec.js
merge_request: 9162
author: winniehell

View File

@ -0,0 +1,4 @@
---
title: Remove deprecated GitlabCiService
merge_request:
author:

View File

@ -15,6 +15,13 @@ module.exports = function(config) {
preprocessors: {
'spec/javascripts/**/*.js?(.es6)': ['webpack', 'sourcemap'],
},
reporters: ['progress', 'coverage-istanbul'],
coverageIstanbulReporter: {
reports: ['html', 'text-summary'],
dir: 'coverage-javascript/',
subdir: '.',
fixWebpackSourcePaths: true
},
webpack: webpackConfig,
webpackMiddleware: { stats: 'errors-only' },
});

Some files were not shown because too many files have changed in this diff Show More