Merge branch 'master' into rename-repo-files
This commit is contained in:
commit
85e50301b4
92 changed files with 12437 additions and 7517 deletions
11
CHANGELOG
11
CHANGELOG
|
@ -1,6 +1,9 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
v 8.11.0 (unreleased)
|
||||
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
|
||||
|
||||
v 8.10.0 (unreleased)
|
||||
- Fix profile activity heatmap to show correct day name (eanplatter)
|
||||
- Expose {should,force}_remove_source_branch (Ben Boeckel)
|
||||
- Add the functionality to be able to rename a file. !5049 (tiagonbotelho)
|
||||
- Disable PostgreSQL statement timeout during migrations
|
||||
|
@ -26,6 +29,7 @@ v 8.10.0 (unreleased)
|
|||
- Add a new column `artifacts_size` to table `ci_builds` !4964
|
||||
- Let Workhorse serve format-patch diffs
|
||||
- Display tooltip for mentioned users and groups !5261 (winniehell)
|
||||
- Allow build email service to be tested
|
||||
- Added day name to contribution calendar tooltips
|
||||
- Make images fit to the size of the viewport !4810
|
||||
- Fix check for New Branch button on Issue page !4630 (winniehell)
|
||||
|
@ -34,6 +38,7 @@ v 8.10.0 (unreleased)
|
|||
- Fix issue, preventing users w/o push access to sort tags !5105 (redetection)
|
||||
- Add Spring EmojiOne updates.
|
||||
- Fix fetching LFS objects for private CI projects
|
||||
- Add the new 2016 Emoji! Adds 72 new emoji including bacon, facepalm, and selfie. !5237
|
||||
- Add syntax for multiline blockquote using `>>>` fence !3954
|
||||
- Fix viewing notification settings when a project is pending deletion
|
||||
- Updated compare dropdown menus to use GL dropdown
|
||||
|
@ -56,6 +61,7 @@ v 8.10.0 (unreleased)
|
|||
- Add "Enabled Git access protocols" to Application Settings
|
||||
- Diffs will create button/diff form on demand no on server side
|
||||
- Reduce size of HTML used by diff comment forms
|
||||
- Protected branches have a "Developers can Merge" setting. !4892 (original implementation by Mathias Vestergaard)
|
||||
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
|
||||
- Only show New Snippet button to users that can create snippets.
|
||||
- PipelinesFinder uses git cache data
|
||||
|
@ -102,6 +108,7 @@ v 8.10.0 (unreleased)
|
|||
- Add min value for project limit field on user's form !3622 (jastkand)
|
||||
- Reset project pushes_since_gc when we enqueue the git gc call
|
||||
- Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt)
|
||||
- Collapsed diffs lines/size don't acumulate to overflow diffs.
|
||||
- Remove duplicate `description` field in `MergeRequest` entities (Ben Boeckel)
|
||||
- Style of import project buttons were fixed in the new project page. !5183 (rdemirbay)
|
||||
- Fix GitHub client requests when rate limit is disabled
|
||||
|
@ -113,9 +120,13 @@ v 8.10.0 (unreleased)
|
|||
- Fix last update timestamp on issues not preserved on gitlab.com and project imports
|
||||
- Fix issues importing projects from EE to CE
|
||||
- Fix creating group with space in group path
|
||||
- Improve cron_jobs loading error messages !5318
|
||||
- Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska)
|
||||
- Limit the number of retries on error to 3 for exporting projects
|
||||
- Allow empty repositories on project import/export
|
||||
- Render only commit message title in builds (Katarzyna Kobierska Ula Budziszewska)
|
||||
- Allow bulk (un)subscription from issues in issue index
|
||||
- Fix MR diff encoding issues exporting GitLab projects
|
||||
|
||||
v 8.9.6
|
||||
- Fix importing of events under notes for GitLab projects. !5154
|
||||
|
|
7
Gemfile
7
Gemfile
|
@ -52,7 +52,7 @@ gem 'browser', '~> 2.2'
|
|||
|
||||
# Extracting information from a git repository
|
||||
# Provide access to Gitlab::Git library
|
||||
gem 'gitlab_git', '~> 10.2'
|
||||
gem 'gitlab_git', '~> 10.3.2'
|
||||
|
||||
# LDAP Auth
|
||||
# GitLab fork with several improvements to original library. For full list of changes
|
||||
|
@ -223,7 +223,7 @@ gem 'jquery-turbolinks', '~> 2.1.0'
|
|||
gem 'addressable', '~> 2.3.8'
|
||||
gem 'bootstrap-sass', '~> 3.3.0'
|
||||
gem 'font-awesome-rails', '~> 4.6.1'
|
||||
gem 'gemojione', '~> 2.6'
|
||||
gem 'gemojione', '~> 3.0'
|
||||
gem 'gon', '~> 6.0.1'
|
||||
gem 'jquery-atwho-rails', '~> 1.3.2'
|
||||
gem 'jquery-rails', '~> 4.1.0'
|
||||
|
@ -349,3 +349,6 @@ gem 'health_check', '~> 2.1.0'
|
|||
# System information
|
||||
gem 'vmstat', '~> 2.1.0'
|
||||
gem 'sys-filesystem', '~> 1.1.6'
|
||||
|
||||
# Secure headers for Content Security Policy
|
||||
gem 'secure_headers', '~> 3.3'
|
||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -255,7 +255,7 @@ GEM
|
|||
ruby-progressbar (~> 1.4)
|
||||
gemnasium-gitlab-service (0.2.6)
|
||||
rugged (~> 0.21)
|
||||
gemojione (2.6.1)
|
||||
gemojione (3.0.1)
|
||||
json
|
||||
get_process_mem (0.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
|
@ -274,7 +274,7 @@ GEM
|
|||
diff-lcs (~> 1.1)
|
||||
mime-types (>= 1.16, < 3)
|
||||
posix-spawn (~> 0.3)
|
||||
gitlab_git (10.3.0)
|
||||
gitlab_git (10.3.2)
|
||||
activesupport (~> 4.0)
|
||||
charlock_holmes (~> 0.7.3)
|
||||
github-linguist (~> 4.7.0)
|
||||
|
@ -645,6 +645,8 @@ GEM
|
|||
sdoc (0.3.20)
|
||||
json (>= 1.1.3)
|
||||
rdoc (~> 3.10)
|
||||
secure_headers (3.3.2)
|
||||
useragent
|
||||
seed-fu (2.3.6)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
|
@ -767,6 +769,7 @@ GEM
|
|||
get_process_mem (~> 0)
|
||||
unicorn (>= 4, < 6)
|
||||
uniform_notifier (1.9.0)
|
||||
useragent (0.16.7)
|
||||
uuid (2.3.8)
|
||||
macaddr (~> 1.0)
|
||||
version_sorter (2.0.0)
|
||||
|
@ -857,11 +860,11 @@ DEPENDENCIES
|
|||
foreman (~> 0.78.0)
|
||||
fuubar (~> 2.0.0)
|
||||
gemnasium-gitlab-service (~> 0.2)
|
||||
gemojione (~> 2.6)
|
||||
gemojione (~> 3.0)
|
||||
github-linguist (~> 4.7.0)
|
||||
github-markup (~> 1.4)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab_git (~> 10.2)
|
||||
gitlab_git (~> 10.3.2)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.2)
|
||||
|
@ -944,6 +947,7 @@ DEPENDENCIES
|
|||
sass-rails (~> 5.0.0)
|
||||
scss_lint (~> 0.47.0)
|
||||
sdoc (~> 0.3.20)
|
||||
secure_headers (~> 3.3)
|
||||
seed-fu (~> 2.3.5)
|
||||
select2-rails (~> 3.5.9)
|
||||
sentry-raven (~> 1.1.0)
|
||||
|
|
|
@ -1,15 +1,35 @@
|
|||
# GitLab Maintenance Policy
|
||||
|
||||
GitLab is a fast moving and evolving project. We currently don't have the resources to support many releases concurrently. We support exactly one stable release at any given time.
|
||||
GitLab follows the [Semantic Versioning](http://semver.org/) for its releases:
|
||||
`(Major).(Minor).(Patch)` in a [pragmatic way].
|
||||
|
||||
GitLab follows the [Semantic Versioning](http://semver.org/) for its releases: `(Major).(Minor).(Patch)` in a [pragmatic way](https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e).
|
||||
- **Major version**: Whenever there is something significant or any backwards
|
||||
incompatible changes are introduced to the public API.
|
||||
- **Minor version**: When new, backwards compatible functionality is introduced
|
||||
to the public API or a minor feature is introduced, or when a set of smaller
|
||||
features is rolled out.
|
||||
- **Patch number**: When backwards compatible bug fixes are introduced that fix
|
||||
incorrect behavior.
|
||||
|
||||
- **Major version**: Whenever there is something significant or any backwards incompatible changes are introduced to the public API.
|
||||
- **Minor version**: When new, backwards compatible functionality is introduced to the public API or a minor feature is introduced, or when a set of smaller features is rolled out.
|
||||
- **Patch number**: When backwards compatible bug fixes are introduced that fix incorrect behavior.
|
||||
The current stable release will receive security patches and bug fixes
|
||||
(eg. `8.9.0` -> `8.9.1`). Feature releases will mark the next supported stable
|
||||
release where the minor version is increased numerically by increments of one
|
||||
(eg. `8.9 -> 8.10`).
|
||||
|
||||
The current stable release will receive security patches and bug fixes (eg. `5.0` -> `5.0.1`). Feature releases will mark the next supported stable release where the minor version is increased numerically by increments of one (eg. `5.0 -> 5.1`).
|
||||
Our current policy is to support one stable release at any given time, but for
|
||||
medium-level security issues, we may consider [backporting to the previous two
|
||||
monthly releases][rel-sec].
|
||||
|
||||
We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable.
|
||||
We encourage everyone to run the latest stable release to ensure that you can
|
||||
easily upgrade to the most secure and feature-rich GitLab experience. In order
|
||||
to make sure you can easily run the most recent stable release, we are working
|
||||
hard to keep the update process simple and reliable.
|
||||
|
||||
More information about the release procedures can be found in the doc/release directory.
|
||||
More information about the release procedures can be found in our
|
||||
[release-tools documentation][rel]. You may also want to read our
|
||||
[Responsible Disclosure Policy][disclosure].
|
||||
|
||||
[rel-sec]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/security.md#backporting
|
||||
[rel]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/
|
||||
[disclosure]: https://about.gitlab.com/disclosure/
|
||||
[pragmatic way]: https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1,002 KiB After Width: | Height: | Size: 1 MiB |
Binary file not shown.
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.5 MiB |
|
@ -250,6 +250,8 @@ class GitLabDropdown
|
|||
if self.options.clicked
|
||||
self.options.clicked(selected, $el, e)
|
||||
|
||||
$el.trigger('blur')
|
||||
|
||||
# Finds an element inside wrapper element
|
||||
getElement: (selector) ->
|
||||
@dropdown.find selector
|
||||
|
|
|
@ -85,12 +85,13 @@ class @IssuableBulkActions
|
|||
getFormDataAsObject: ->
|
||||
formData =
|
||||
update:
|
||||
state_event : @form.find('input[name="update[state_event]"]').val()
|
||||
assignee_id : @form.find('input[name="update[assignee_id]"]').val()
|
||||
milestone_id : @form.find('input[name="update[milestone_id]"]').val()
|
||||
issues_ids : @form.find('input[name="update[issues_ids]"]').val()
|
||||
add_label_ids : []
|
||||
remove_label_ids : []
|
||||
state_event : @form.find('input[name="update[state_event]"]').val()
|
||||
assignee_id : @form.find('input[name="update[assignee_id]"]').val()
|
||||
milestone_id : @form.find('input[name="update[milestone_id]"]').val()
|
||||
issues_ids : @form.find('input[name="update[issues_ids]"]').val()
|
||||
subscription_event : @form.find('input[name="update[subscription_event]"]').val()
|
||||
add_label_ids : []
|
||||
remove_label_ids : []
|
||||
|
||||
if @willUpdateLabels
|
||||
@getLabelsToApply().map (id) ->
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
w.gl ?= {}
|
||||
w.gl.utils ?= {}
|
||||
w.gl.utils.days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
||||
w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
||||
|
||||
w.gl.utils.formatDate = (datetime) ->
|
||||
dateFormat(datetime, 'mmm d, yyyy h:MMtt Z')
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
$ ->
|
||||
$(".protected-branches-list :checkbox").change (e) ->
|
||||
name = $(this).attr("name")
|
||||
if name == "developers_can_push"
|
||||
if name == "developers_can_push" || name == "developers_can_merge"
|
||||
id = $(this).val()
|
||||
checked = $(this).is(":checked")
|
||||
can_push = $(this).is(":checked")
|
||||
url = $(this).data("url")
|
||||
$.ajax
|
||||
type: "PUT"
|
||||
type: "PATCH"
|
||||
url: url
|
||||
dataType: "json"
|
||||
data:
|
||||
id: id
|
||||
protected_branch:
|
||||
developers_can_push: checked
|
||||
"#{name}": can_push
|
||||
|
||||
success: ->
|
||||
row = $(e.target)
|
||||
|
|
18
app/assets/javascripts/subscription_select.js.coffee
Normal file
18
app/assets/javascripts/subscription_select.js.coffee
Normal file
|
@ -0,0 +1,18 @@
|
|||
class @SubscriptionSelect
|
||||
constructor: ->
|
||||
$('.js-subscription-event').each (i, el) ->
|
||||
fieldName = $(el).data("field-name")
|
||||
|
||||
$(el).glDropdown(
|
||||
selectable: true
|
||||
fieldName: fieldName
|
||||
toggleLabel: (selected, el, instance) =>
|
||||
label = 'Subscription'
|
||||
$item = instance.dropdown.find('.is-active')
|
||||
label = $item.text() if $item.length
|
||||
label
|
||||
clicked: (item, $el, e)->
|
||||
e.preventDefault()
|
||||
id: (obj, el) ->
|
||||
$(el).data("id")
|
||||
)
|
|
@ -70,7 +70,7 @@
|
|||
}
|
||||
|
||||
&.wiki {
|
||||
padding: $gl-padding;
|
||||
padding: 30px $gl-padding;
|
||||
|
||||
.highlight {
|
||||
margin-bottom: 9px;
|
||||
|
|
|
@ -37,39 +37,41 @@
|
|||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.3em;
|
||||
font-size: 2em;
|
||||
font-weight: 600;
|
||||
margin: 24px 0 12px;
|
||||
padding: 0 0 10px;
|
||||
border-bottom: 1px solid #e7e9ed;
|
||||
margin: 1em 0 10px;
|
||||
padding: 0 0 0.3em;
|
||||
border-bottom: 1px solid $btn-default-border;
|
||||
color: $gl-gray-dark;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2em;
|
||||
font-size: 1.6em;
|
||||
font-weight: 600;
|
||||
margin: 24px 0 12px;
|
||||
margin: 1em 0 10px;
|
||||
padding-bottom: 0.3em;
|
||||
border-bottom: 1px solid $btn-default-border;
|
||||
color: $gl-gray-dark;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 24px 0 12px;
|
||||
font-size: 1.1em;
|
||||
margin: 1em 0 10px;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 24px 0 12px;
|
||||
font-size: 0.98em;
|
||||
margin: 1em 0 10px;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 24px 0 12px;
|
||||
font-size: 0.95em;
|
||||
margin: 1em 0 10px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin: 24px 0 12px;
|
||||
font-size: 0.90em;
|
||||
margin: 1em 0 10px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
|
@ -115,7 +117,7 @@
|
|||
|
||||
ul, ol {
|
||||
padding: 0;
|
||||
margin: 6px 0 6px 28px !important;
|
||||
margin: 3px 0 3px 28px !important;
|
||||
}
|
||||
|
||||
li {
|
||||
|
|
|
@ -16,7 +16,7 @@ $border-color: #e5e5e5;
|
|||
$focus-border-color: #3aabf0;
|
||||
$table-border-color: #f0f0f0;
|
||||
$background-color: #fafafa;
|
||||
$dark-background-color: #f7f7f7;
|
||||
$dark-background-color: #f5f5f5;
|
||||
$table-text-gray: #8f8f8f;
|
||||
|
||||
/*
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -270,7 +270,7 @@
|
|||
|
||||
.item-title {
|
||||
@media (min-width: $screen-sm-min) {
|
||||
width: 49%;
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
border-top: 1px solid $table-border-gray;
|
||||
|
||||
td, th {
|
||||
line-height: 23px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -10,7 +10,6 @@ module DiffForPath
|
|||
|
||||
diff_commit = commit_for_diff(diff_file)
|
||||
blob = diff_file.blob(diff_commit)
|
||||
@expand_all_diffs = true
|
||||
|
||||
locals = {
|
||||
diff_file: diff_file,
|
||||
|
|
|
@ -226,6 +226,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
:assignee_id,
|
||||
:milestone_id,
|
||||
:state_event,
|
||||
:subscription_event,
|
||||
label_ids: [],
|
||||
add_label_ids: [],
|
||||
remove_label_ids: []
|
||||
|
|
|
@ -50,6 +50,6 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def protected_branch_params
|
||||
params.require(:protected_branch).permit(:name, :developers_can_push)
|
||||
params.require(:protected_branch).permit(:name, :developers_can_push, :developers_can_merge)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -45,8 +45,9 @@ class Projects::ServicesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def test
|
||||
data = Gitlab::PushDataBuilder.build_sample(project, current_user)
|
||||
data = @service.test_data(project, current_user)
|
||||
outcome = @service.test(data)
|
||||
|
||||
if outcome[:success]
|
||||
message = { notice: 'We sent a request to the provided URL' }
|
||||
else
|
||||
|
|
|
@ -12,7 +12,7 @@ module BranchesHelper
|
|||
def can_push_branch?(project, branch_name)
|
||||
return false unless project.repository.branch_exists?(branch_name)
|
||||
|
||||
::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(branch_name)
|
||||
::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(branch_name)
|
||||
end
|
||||
|
||||
def project_branches
|
||||
|
|
|
@ -9,7 +9,7 @@ module DiffHelper
|
|||
end
|
||||
|
||||
def expand_all_diffs?
|
||||
@expand_all_diffs || params[:expand_all_diffs].present?
|
||||
params[:expand_all_diffs].present?
|
||||
end
|
||||
|
||||
def diff_view
|
||||
|
@ -23,13 +23,14 @@ module DiffHelper
|
|||
end
|
||||
|
||||
def diff_options
|
||||
default_options = Commit.max_diff_options
|
||||
options = { ignore_whitespace_change: hide_whitespace?, no_collapse: expand_all_diffs? }
|
||||
|
||||
if action_name == 'diff_for_path'
|
||||
default_options[:paths] = params.values_at(:old_path, :new_path)
|
||||
options[:no_collapse] = true
|
||||
options[:paths] = params.values_at(:old_path, :new_path)
|
||||
end
|
||||
|
||||
default_options.merge(ignore_whitespace_change: hide_whitespace?)
|
||||
Commit.max_diff_options.merge(options)
|
||||
end
|
||||
|
||||
def safe_diff_files(diffs, diff_refs: nil, repository: nil)
|
||||
|
|
|
@ -6,6 +6,7 @@ module Emails
|
|||
|
||||
add_project_headers
|
||||
add_build_headers('failed')
|
||||
|
||||
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ module Ci
|
|||
commit.try(:message)
|
||||
end
|
||||
|
||||
def git_commit_title
|
||||
commit.try(:title)
|
||||
end
|
||||
|
||||
def short_sha
|
||||
Ci::Pipeline.truncate_sha(sha)
|
||||
end
|
||||
|
|
|
@ -552,7 +552,13 @@ class MergeRequest < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def can_be_merged_by?(user)
|
||||
::Gitlab::GitAccess.new(user, project, 'web').can_push_to_branch?(target_branch)
|
||||
access = ::Gitlab::UserAccess.new(user, project: project)
|
||||
access.can_push_to_branch?(target_branch) || access.can_merge_to_branch?(target_branch)
|
||||
end
|
||||
|
||||
def can_be_merged_via_command_line_by?(user)
|
||||
access = ::Gitlab::UserAccess.new(user, project: project)
|
||||
access.can_push_to_branch?(target_branch)
|
||||
end
|
||||
|
||||
def mergeable_ci_state?
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class MergeRequestDiff < ActiveRecord::Base
|
||||
include Sortable
|
||||
include Importable
|
||||
include EncodingHelper
|
||||
|
||||
# Prevent store of diff if commits amount more then 500
|
||||
COMMITS_SAFE_SIZE = 100
|
||||
|
@ -211,6 +212,14 @@ class MergeRequestDiff < ActiveRecord::Base
|
|||
branch_base_commit.try(:sha)
|
||||
end
|
||||
|
||||
def utf8_st_diffs
|
||||
st_diffs.map do |diff|
|
||||
diff.each do |k, v|
|
||||
diff[k] = encode_utf8(v) if v.respond_to?(:encoding)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# #save or #update_attributes providing changes on serialized attributes do a lot of
|
||||
# serialization and deserialization calls resulting in bad performance.
|
||||
|
|
|
@ -838,6 +838,10 @@ class Project < ActiveRecord::Base
|
|||
protected_branches.matching(branch_name).any?(&:developers_can_push)
|
||||
end
|
||||
|
||||
def developers_can_merge_to_protected_branch?(branch_name)
|
||||
protected_branches.matching(branch_name).any?(&:developers_can_merge)
|
||||
end
|
||||
|
||||
def forked?
|
||||
!(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
|
||||
end
|
||||
|
|
|
@ -42,6 +42,19 @@ class BuildsEmailService < Service
|
|||
end
|
||||
end
|
||||
|
||||
def can_test?
|
||||
project.builds.count > 0
|
||||
end
|
||||
|
||||
def disabled_title
|
||||
"Please setup a build on your repository."
|
||||
end
|
||||
|
||||
def test_data(project = nil, user = nil)
|
||||
build = project.builds.last
|
||||
Gitlab::BuildDataBuilder.build(build)
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'textarea', name: 'recipients', placeholder: 'Emails separated by comma' },
|
||||
|
@ -50,6 +63,20 @@ class BuildsEmailService < Service
|
|||
]
|
||||
end
|
||||
|
||||
def test(data)
|
||||
begin
|
||||
# bypass build status verification when testing
|
||||
data[:build_status] = "failed"
|
||||
data[:build_allow_failure] = false
|
||||
|
||||
result = execute(data)
|
||||
rescue StandardError => error
|
||||
return { success: false, result: error }
|
||||
end
|
||||
|
||||
{ success: true, result: result }
|
||||
end
|
||||
|
||||
def should_build_be_notified?(data)
|
||||
case data[:build_status]
|
||||
when 'success'
|
||||
|
|
|
@ -704,6 +704,7 @@ class Repository
|
|||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref,
|
||||
update_ref: false,
|
||||
}
|
||||
|
||||
raw_repository.mkdir(path, options)
|
||||
|
@ -719,6 +720,7 @@ class Repository
|
|||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref,
|
||||
update_ref: false,
|
||||
}
|
||||
|
||||
options[:file] = {
|
||||
|
@ -765,7 +767,8 @@ class Repository
|
|||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref
|
||||
branch: ref,
|
||||
update_ref: false,
|
||||
}
|
||||
|
||||
options[:file] = {
|
||||
|
@ -795,9 +798,9 @@ class Repository
|
|||
end
|
||||
end
|
||||
|
||||
def merge(user, source_sha, target_branch, options = {})
|
||||
our_commit = rugged.branches[target_branch].target
|
||||
their_commit = rugged.lookup(source_sha)
|
||||
def merge(user, merge_request, options = {})
|
||||
our_commit = rugged.branches[merge_request.target_branch].target
|
||||
their_commit = rugged.lookup(merge_request.diff_head_sha)
|
||||
|
||||
raise "Invalid merge target" if our_commit.nil?
|
||||
raise "Invalid merge source" if their_commit.nil?
|
||||
|
@ -805,14 +808,15 @@ class Repository
|
|||
merge_index = rugged.merge_commits(our_commit, their_commit)
|
||||
return false if merge_index.conflicts?
|
||||
|
||||
commit_with_hooks(user, target_branch) do |ref|
|
||||
commit_with_hooks(user, merge_request.target_branch) do
|
||||
actual_options = options.merge(
|
||||
parents: [our_commit, their_commit],
|
||||
tree: merge_index.write_tree(rugged),
|
||||
update_ref: ref
|
||||
)
|
||||
|
||||
Rugged::Commit.create(rugged, actual_options)
|
||||
commit_id = Rugged::Commit.create(rugged, actual_options)
|
||||
merge_request.update(in_progress_merge_commit_sha: commit_id)
|
||||
commit_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -822,15 +826,14 @@ class Repository
|
|||
|
||||
return false unless revert_tree_id
|
||||
|
||||
commit_with_hooks(user, base_branch) do |ref|
|
||||
commit_with_hooks(user, base_branch) do
|
||||
committer = user_to_committer(user)
|
||||
source_sha = Rugged::Commit.create(rugged,
|
||||
message: commit.revert_message,
|
||||
author: committer,
|
||||
committer: committer,
|
||||
tree: revert_tree_id,
|
||||
parents: [rugged.lookup(source_sha)],
|
||||
update_ref: ref)
|
||||
parents: [rugged.lookup(source_sha)])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -840,7 +843,7 @@ class Repository
|
|||
|
||||
return false unless cherry_pick_tree_id
|
||||
|
||||
commit_with_hooks(user, base_branch) do |ref|
|
||||
commit_with_hooks(user, base_branch) do
|
||||
committer = user_to_committer(user)
|
||||
source_sha = Rugged::Commit.create(rugged,
|
||||
message: commit.message,
|
||||
|
@ -851,8 +854,7 @@ class Repository
|
|||
},
|
||||
committer: committer,
|
||||
tree: cherry_pick_tree_id,
|
||||
parents: [rugged.lookup(source_sha)],
|
||||
update_ref: ref)
|
||||
parents: [rugged.lookup(source_sha)])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -953,20 +955,6 @@ class Repository
|
|||
Gitlab::Popen.popen(args, path_to_repo)
|
||||
end
|
||||
|
||||
def with_tmp_ref(oldrev = nil)
|
||||
random_string = SecureRandom.hex
|
||||
tmp_ref = "refs/tmp/#{random_string}/head"
|
||||
|
||||
if oldrev && !Gitlab::Git.blank_ref?(oldrev)
|
||||
rugged.references.create(tmp_ref, oldrev)
|
||||
end
|
||||
|
||||
# Make commit in tmp ref
|
||||
yield(tmp_ref)
|
||||
ensure
|
||||
rugged.references.delete(tmp_ref) rescue nil
|
||||
end
|
||||
|
||||
def commit_with_hooks(current_user, branch)
|
||||
update_autocrlf_option
|
||||
|
||||
|
@ -979,33 +967,31 @@ class Repository
|
|||
oldrev = target_branch.target
|
||||
end
|
||||
|
||||
with_tmp_ref(oldrev) do |tmp_ref|
|
||||
# Make commit in tmp ref
|
||||
newrev = yield(tmp_ref)
|
||||
# Make commit
|
||||
newrev = yield(ref)
|
||||
|
||||
unless newrev
|
||||
raise CommitError.new('Failed to create commit')
|
||||
end
|
||||
unless newrev
|
||||
raise CommitError.new('Failed to create commit')
|
||||
end
|
||||
|
||||
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
|
||||
if was_empty || !target_branch
|
||||
# Create branch
|
||||
rugged.references.create(ref, newrev)
|
||||
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
|
||||
if was_empty || !target_branch
|
||||
# Create branch
|
||||
rugged.references.create(ref, newrev)
|
||||
else
|
||||
# Update head
|
||||
current_head = find_branch(branch).target
|
||||
|
||||
# Make sure target branch was not changed during pre-receive hook
|
||||
if current_head == oldrev
|
||||
rugged.references.update(ref, newrev)
|
||||
else
|
||||
# Update head
|
||||
current_head = find_branch(branch).target
|
||||
|
||||
# Make sure target branch was not changed during pre-receive hook
|
||||
if current_head == oldrev
|
||||
rugged.references.update(ref, newrev)
|
||||
else
|
||||
raise CommitError.new('Commit was rejected because branch received new push')
|
||||
end
|
||||
raise CommitError.new('Commit was rejected because branch received new push')
|
||||
end
|
||||
end
|
||||
|
||||
newrev
|
||||
end
|
||||
|
||||
newrev
|
||||
end
|
||||
|
||||
def ls_files(ref)
|
||||
|
|
|
@ -76,6 +76,10 @@ class Service < ActiveRecord::Base
|
|||
[]
|
||||
end
|
||||
|
||||
def test_data(project, user)
|
||||
Gitlab::PushDataBuilder.build_sample(project, user)
|
||||
end
|
||||
|
||||
def supported_events
|
||||
%w(push tag_push issue merge_request wiki_page)
|
||||
end
|
||||
|
@ -94,6 +98,11 @@ class Service < ActiveRecord::Base
|
|||
!project.empty_repo?
|
||||
end
|
||||
|
||||
# reason why service cannot be tested
|
||||
def disabled_title
|
||||
"Please setup a project repository."
|
||||
end
|
||||
|
||||
# Provide convenient accessor methods
|
||||
# for each serialized property.
|
||||
# Also keep track of updated properties in a similar way as ActiveModel::Dirty
|
||||
|
|
|
@ -23,7 +23,7 @@ module Commits
|
|||
private
|
||||
|
||||
def check_push_permissions
|
||||
allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch)
|
||||
allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch)
|
||||
|
||||
unless allowed
|
||||
raise ValidationError.new('You are not allowed to push into this branch')
|
||||
|
@ -31,7 +31,7 @@ module Commits
|
|||
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def create_target_branch(new_branch)
|
||||
# Temporary branch exists and contains the change commit
|
||||
return success if repository.find_branch(new_branch)
|
||||
|
|
|
@ -15,21 +15,19 @@ class CreateBranchService < BaseService
|
|||
return error('Branch already exists')
|
||||
end
|
||||
|
||||
new_branch = nil
|
||||
new_branch = if source_project != @project
|
||||
repository.fetch_ref(
|
||||
source_project.repository.path_to_repo,
|
||||
"refs/heads/#{ref}",
|
||||
"refs/heads/#{branch_name}"
|
||||
)
|
||||
|
||||
if source_project != @project
|
||||
repository.with_tmp_ref do |tmp_ref|
|
||||
repository.fetch_ref(
|
||||
source_project.repository.path_to_repo,
|
||||
"refs/heads/#{ref}",
|
||||
tmp_ref
|
||||
)
|
||||
repository.after_create_branch
|
||||
|
||||
new_branch = repository.add_branch(current_user, branch_name, tmp_ref)
|
||||
end
|
||||
else
|
||||
new_branch = repository.add_branch(current_user, branch_name, ref)
|
||||
end
|
||||
repository.find_branch(branch_name)
|
||||
else
|
||||
repository.add_branch(current_user, branch_name, ref)
|
||||
end
|
||||
|
||||
if new_branch
|
||||
success(new_branch)
|
||||
|
|
|
@ -44,7 +44,7 @@ module Files
|
|||
end
|
||||
|
||||
def validate
|
||||
allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch)
|
||||
allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch)
|
||||
|
||||
unless allowed
|
||||
raise_error("You are not allowed to push into this branch")
|
||||
|
|
|
@ -89,7 +89,8 @@ class GitPushService < BaseService
|
|||
# Set protection on the default branch if configured
|
||||
if current_application_settings.default_branch_protection != PROTECTION_NONE
|
||||
developers_can_push = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_PUSH ? true : false
|
||||
@project.protected_branches.create({ name: @project.default_branch, developers_can_push: developers_can_push })
|
||||
developers_can_merge = current_application_settings.default_branch_protection == PROTECTION_DEV_CAN_MERGE ? true : false
|
||||
@project.protected_branches.create({ name: @project.default_branch, developers_can_push: developers_can_push, developers_can_merge: developers_can_merge })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ class IssuableBaseService < BaseService
|
|||
|
||||
def update(issuable)
|
||||
change_state(issuable)
|
||||
change_subscription(issuable)
|
||||
filter_params
|
||||
old_labels = issuable.labels.to_a
|
||||
|
||||
|
@ -124,6 +125,15 @@ class IssuableBaseService < BaseService
|
|||
end
|
||||
end
|
||||
|
||||
def change_subscription(issuable)
|
||||
case params.delete(:subscription_event)
|
||||
when 'subscribe'
|
||||
issuable.subscribe(current_user)
|
||||
when 'unsubscribe'
|
||||
issuable.unsubscribe(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def has_changes?(issuable, old_labels: [])
|
||||
valid_attrs = [:title, :description, :assignee_id, :milestone_id, :target_branch]
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ module Issues
|
|||
issues_ids = params.delete(:issues_ids).split(",")
|
||||
issue_params = params
|
||||
|
||||
%i(state_event milestone_id assignee_id add_label_ids remove_label_ids).each do |key|
|
||||
%i(state_event milestone_id assignee_id add_label_ids remove_label_ids subscription_event).each do |key|
|
||||
issue_params.delete(key) unless issue_params[key].present?
|
||||
end
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ module MergeRequests
|
|||
committer: committer
|
||||
}
|
||||
|
||||
commit_id = repository.merge(current_user, merge_request.diff_head_sha, merge_request.target_branch, options)
|
||||
commit_id = repository.merge(current_user, merge_request, options)
|
||||
merge_request.update(merge_commit_sha: commit_id)
|
||||
rescue GitHooksService::PreReceiveError => e
|
||||
merge_request.update(merge_error: e.message)
|
||||
|
@ -43,6 +43,8 @@ module MergeRequests
|
|||
merge_request.update(merge_error: "Something went wrong during merge")
|
||||
Rails.logger.error(e.message)
|
||||
false
|
||||
ensure
|
||||
merge_request.update(in_progress_merge_commit_sha: nil)
|
||||
end
|
||||
|
||||
def after_merge
|
||||
|
|
|
@ -48,7 +48,7 @@ module MergeRequests
|
|||
end
|
||||
|
||||
def force_push?
|
||||
Gitlab::ForcePushCheck.force_push?(@project, @oldrev, @newrev)
|
||||
Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev)
|
||||
end
|
||||
|
||||
# Refresh merge request diff if we push to source or target branch of merge request
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.emoji-menu
|
||||
= text_field_tag :emoji_search, "", class: "emoji-search search-input form-control", placeholder: "Seach emojis"
|
||||
= text_field_tag :emoji_search, "", class: "emoji-search search-input form-control", placeholder: "Search emoji"
|
||||
.emoji-menu-content
|
||||
- Gitlab::AwardEmoji.emoji_by_category.each do |category, emojis|
|
||||
%h5.emoji-menu-title
|
||||
|
|
|
@ -94,9 +94,9 @@
|
|||
|
||||
.block
|
||||
.title
|
||||
Commit message
|
||||
Commit title
|
||||
%p.build-light-text.append-bottom-0
|
||||
#{@build.pipeline.git_commit_message}
|
||||
#{@build.pipeline.git_commit_title}
|
||||
|
||||
- if @build.tags.any?
|
||||
.block
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
- elsif blob_text_viewable?(blob)
|
||||
- if !project.repository.diffable?(blob)
|
||||
.nothing-here-block This diff was suppressed by a .gitattributes entry.
|
||||
- elsif diff_file.collapsed?
|
||||
- url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path))
|
||||
.nothing-here-block.diff-collapsed{data: { diff_for_path: url } }
|
||||
This diff is collapsed. Click to expand it.
|
||||
- elsif diff_file.diff_lines.length > 0
|
||||
- if diff_file.collapsed_by_default? && !expand_all_diffs?
|
||||
- url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path))
|
||||
.nothing-here-block.diff-collapsed{data: { diff_for_path: url } }
|
||||
This diff is collapsed. Click to expand it.
|
||||
- elsif diff_view == 'parallel'
|
||||
- if diff_view == 'parallel'
|
||||
= render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob
|
||||
- else
|
||||
= render "projects/diffs/text_file", diff_file: diff_file
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
.content-block.oneline-block.files-changed
|
||||
.inline-parallel-buttons
|
||||
- unless expand_all_diffs?
|
||||
- if !expand_all_diffs? && diff_files.any? { |diff_file| diff_file.collapsed? }
|
||||
= link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: 'html')), class: 'btn btn-default'
|
||||
- if show_whitespace_toggle
|
||||
- if current_controller?(:commit)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%p
|
||||
Please resolve these conflicts or
|
||||
- if @merge_request.can_be_merged_by?(current_user)
|
||||
- if @merge_request.can_be_merged_via_command_line_by?(current_user)
|
||||
#{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}.
|
||||
- else
|
||||
ask someone with write access to this repository to merge this request manually.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
.table-responsive
|
||||
%table.table.protected-branches-list
|
||||
%colgroup
|
||||
%col{ width: "20%" }
|
||||
%col{ width: "30%" }
|
||||
%col{ width: "25%" }
|
||||
%col{ width: "25%" }
|
||||
|
@ -18,6 +19,7 @@
|
|||
%th Protected Branch
|
||||
%th Commit
|
||||
%th Developers Can Push
|
||||
%th Developers Can Merge
|
||||
- if can_admin_project
|
||||
%th
|
||||
%tbody
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
(branch was removed from repository)
|
||||
%td
|
||||
= check_box_tag("developers_can_push", protected_branch.id, protected_branch.developers_can_push, data: { url: url })
|
||||
%td
|
||||
= check_box_tag("developers_can_merge", protected_branch.id, protected_branch.developers_can_merge, data: { url: url })
|
||||
- if can_admin_project
|
||||
%td
|
||||
= link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning btn-sm pull-right"
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
= f.label :developers_can_push, "Developers can push", class: "label-light append-bottom-0"
|
||||
%p.light.append-bottom-0
|
||||
Allow developers to push to this branch
|
||||
|
||||
.form-group
|
||||
= f.check_box :developers_can_merge, class: "pull-left"
|
||||
.prepend-left-20
|
||||
= f.label :developers_can_merge, "Developers can merge", class: "label-light append-bottom-0"
|
||||
%p.light.append-bottom-0
|
||||
Allow developers to accept merge requests to this branch
|
||||
= f.submit "Protect", class: "btn-create btn protect-branch-btn", disabled: true
|
||||
|
||||
%hr
|
||||
= render "branches_list"
|
||||
|
|
|
@ -12,5 +12,5 @@
|
|||
|
||||
- if @service.valid? && @service.activated?
|
||||
- disabled = @service.can_test? ? '':'disabled'
|
||||
= link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service.to_param), class: "btn #{disabled}"
|
||||
= link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service), class: "btn #{disabled}", title: @service.disabled_title
|
||||
= link_to "Cancel", namespace_project_services_path(@project.namespace, @project), class: "btn btn-cancel"
|
||||
|
|
|
@ -44,9 +44,15 @@
|
|||
placeholder: "Search authors", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: @project.id, field_name: "update[assignee_id]" } })
|
||||
.filter-item.inline
|
||||
= dropdown_tag("Milestone", options: { title: "Assign milestone", toggle_class: 'js-milestone-select js-extra-options js-filter-submit js-filter-bulk-update', filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", placeholder: "Search milestones", data: { show_no: true, field_name: "update[milestone_id]", project_id: @project.id, milestones: namespace_project_milestones_path(@project.namespace, @project, :json), use_id: true } })
|
||||
|
||||
.filter-item.inline.labels-filter
|
||||
= render "shared/issuable/label_dropdown", classes: ['js-filter-bulk-update', 'js-multiselect'], show_create: false, show_footer: false, extra_options: false, filter_submit: false, show_footer: false, data_options: { persist_when_hide: "true", field_name: "update[label_ids][]", show_no: false, show_any: false, use_id: true }
|
||||
.filter-item.inline
|
||||
= dropdown_tag("Subscription", options: { toggle_class: "js-subscription-event", title: "Change subscription", dropdown_class: "dropdown-menu-selectable", data: { field_name: "update[subscription_event]" } } ) do
|
||||
%ul
|
||||
%li
|
||||
%a{href: "#", data: {id: "subscribe"}} Subscribe
|
||||
%li
|
||||
%a{href: "#", data: {id: "unsubscribe"}} Unsubscribe
|
||||
|
||||
= hidden_field_tag 'update[issues_ids]', []
|
||||
= hidden_field_tag :state_event, params[:state_event]
|
||||
|
@ -63,6 +69,7 @@
|
|||
new LabelsSelect();
|
||||
new MilestoneSelect();
|
||||
new IssueStatusSelect();
|
||||
new SubscriptionSelect();
|
||||
$('form.filter-form').on('submit', function (event) {
|
||||
event.preventDefault();
|
||||
Turbolinks.visit(this.action + '&' + $(this).serialize());
|
||||
|
|
|
@ -76,7 +76,7 @@ module Gitlab
|
|||
|
||||
# Enable the asset pipeline
|
||||
config.assets.enabled = true
|
||||
config.assets.paths << Gemojione.index.images_path
|
||||
config.assets.paths << Gemojione.images_path
|
||||
config.assets.precompile << "*.png"
|
||||
config.assets.precompile << "print.css"
|
||||
config.assets.precompile << "notify.css"
|
||||
|
|
109
config/initializers/secure_headers.rb
Normal file
109
config/initializers/secure_headers.rb
Normal file
|
@ -0,0 +1,109 @@
|
|||
# CSP headers have to have single quotes, so failures relating to quotes
|
||||
# inside Ruby string arrays are irrelevant.
|
||||
# rubocop:disable Lint/PercentStringArray
|
||||
require 'gitlab/current_settings'
|
||||
include Gitlab::CurrentSettings
|
||||
|
||||
# If Sentry is enabled and the Rails app is running in production mode,
|
||||
# this will construct the Report URI for Sentry.
|
||||
if Rails.env.production? && current_application_settings.sentry_enabled
|
||||
uri = URI.parse(current_application_settings.sentry_dsn)
|
||||
CSP_REPORT_URI = "#{uri.scheme}://#{uri.host}/api#{uri.path}/csp-report/?sentry_key=#{uri.user}"
|
||||
else
|
||||
CSP_REPORT_URI = ''
|
||||
end
|
||||
|
||||
# Content Security Policy Headers
|
||||
# For more information on CSP see:
|
||||
# - https://gitlab.com/gitlab-org/gitlab-ce/issues/18231
|
||||
# - https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives
|
||||
SecureHeaders::Configuration.default do |config|
|
||||
# Mark all cookies as "Secure", "HttpOnly", and "SameSite=Strict".
|
||||
config.cookies = {
|
||||
secure: true,
|
||||
httponly: true,
|
||||
samesite: {
|
||||
strict: true
|
||||
}
|
||||
}
|
||||
config.x_content_type_options = "nosniff"
|
||||
config.x_xss_protection = "1; mode=block"
|
||||
config.x_download_options = "noopen"
|
||||
config.x_permitted_cross_domain_policies = "none"
|
||||
config.referrer_policy = "origin-when-cross-origin"
|
||||
config.csp = {
|
||||
# "Meta" values.
|
||||
report_only: true,
|
||||
preserve_schemes: true,
|
||||
|
||||
# "Directive" values.
|
||||
# Default source allows nothing, more permissive values are set per-policy.
|
||||
default_src: %w('none'),
|
||||
# (Deprecated) Don't allow iframes.
|
||||
frame_src: %w('none'),
|
||||
# Only allow XMLHTTPRequests from the GitLab instance itself.
|
||||
connect_src: %w('self'),
|
||||
# Only load local fonts.
|
||||
font_src: %w('self'),
|
||||
# Load local images, any external image available over HTTPS.
|
||||
img_src: %w(* 'self' data:),
|
||||
# Audio and video can't be played on GitLab currently, so it's disabled.
|
||||
media_src: %w('none'),
|
||||
# Don't allow <object>, <embed>, or <applet> elements.
|
||||
object_src: %w('none'),
|
||||
# Allow local scripts and inline scripts.
|
||||
script_src: %w('unsafe-inline' 'unsafe-eval' 'self'),
|
||||
# Allow local stylesheets and inline styles.
|
||||
style_src: %w('unsafe-inline' 'self'),
|
||||
# The URIs that a user agent may use as the document base URL.
|
||||
base_uri: %w('self'),
|
||||
# Only allow local iframes and service workers
|
||||
child_src: %w('self'),
|
||||
# Only submit form information to the GitLab instance.
|
||||
form_action: %w('self'),
|
||||
# Disallow any parents from embedding a page in an iframe.
|
||||
frame_ancestors: %w('none'),
|
||||
# Don't allow any plugins (Flash, Shockwave, etc.)
|
||||
plugin_types: %w(),
|
||||
# Blocks all mixed (HTTP) content.
|
||||
block_all_mixed_content: true,
|
||||
# Upgrades insecure requests to HTTPS when possible.
|
||||
upgrade_insecure_requests: true
|
||||
}
|
||||
|
||||
# Reports are sent to Sentry if it's enabled.
|
||||
if current_application_settings.sentry_enabled
|
||||
config.csp[:report_uri] = %W(#{CSP_REPORT_URI})
|
||||
end
|
||||
|
||||
# Allow Bootstrap Linter in development mode.
|
||||
if Rails.env.development?
|
||||
config.csp[:script_src] << "maxcdn.bootstrapcdn.com"
|
||||
end
|
||||
|
||||
# reCAPTCHA
|
||||
if current_application_settings.recaptcha_enabled
|
||||
config.csp[:script_src] << "https://www.google.com/recaptcha/"
|
||||
config.csp[:script_src] << "https://www.gstatic.com/recaptcha/"
|
||||
config.csp[:frame_src] << "https://www.google.com/recaptcha/"
|
||||
config.x_frame_options = "SAMEORIGIN"
|
||||
end
|
||||
|
||||
# Gravatar
|
||||
if current_application_settings.gravatar_enabled?
|
||||
config.csp[:img_src] << "www.gravatar.com"
|
||||
config.csp[:img_src] << "secure.gravatar.com"
|
||||
config.csp[:img_src] << Gitlab.config.gravatar.host
|
||||
end
|
||||
|
||||
# Piwik
|
||||
if Gitlab.config.extra.has_key?('piwik_url') && Gitlab.config.extra.has_key?('piwik_site_id')
|
||||
config.csp[:script_src] << Gitlab.config.extra.piwik_url
|
||||
config.csp[:img_src] << Gitlab.config.extra.piwik_url
|
||||
end
|
||||
|
||||
# Google Analytics
|
||||
if Gitlab.config.extra.has_key?('google_analytics_id')
|
||||
config.csp[:script_src] << "https://www.google-analytics.com"
|
||||
end
|
||||
end
|
|
@ -13,7 +13,14 @@ Sidekiq.configure_server do |config|
|
|||
# UGLY Hack to get nested hash from settingslogic
|
||||
cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json)
|
||||
# UGLY hack: Settingslogic doesn't allow 'class' key
|
||||
cron_jobs.each { |k, v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') }
|
||||
cron_jobs_required_keys = %w(job_class cron)
|
||||
cron_jobs.each do |k, v|
|
||||
if cron_jobs[k] && cron_jobs_required_keys.all? { |s| cron_jobs[k].key?(s) }
|
||||
cron_jobs[k]['class'] = cron_jobs[k].delete('job_class')
|
||||
else
|
||||
raise("Invalid cron_jobs config key: '#{k}'. Check your gitlab config file.")
|
||||
end
|
||||
end
|
||||
Sidekiq::Cron::Job.load_from_hash! cron_jobs
|
||||
|
||||
# Database pool should be at least `sidekiq_concurrency` + 2
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class AddDevelopersCanMergeToProtectedBranches < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_column_with_default :protected_branches, :developers_can_merge, :boolean, default: false, allow_null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddColumnInProgressMergeCommitShaToMergeRequests < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :merge_requests, :in_progress_merge_commit_sha, :string
|
||||
end
|
||||
end
|
|
@ -628,8 +628,8 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.integer "merge_user_id"
|
||||
t.string "merge_commit_sha"
|
||||
t.datetime "deleted_at"
|
||||
t.string "in_progress_merge_commit_sha"
|
||||
end
|
||||
|
||||
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
|
||||
add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
|
||||
add_index "merge_requests", ["created_at", "id"], name: "index_merge_requests_on_created_at_and_id", using: :btree
|
||||
|
@ -862,11 +862,12 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
add_index "projects", ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree
|
||||
|
||||
create_table "protected_branches", force: :cascade do |t|
|
||||
t.integer "project_id", null: false
|
||||
t.string "name", null: false
|
||||
t.integer "project_id", null: false
|
||||
t.string "name", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "developers_can_push", default: false, null: false
|
||||
t.boolean "developers_can_push", default: false, null: false
|
||||
t.boolean "developers_can_merge", default: false, null: false
|
||||
end
|
||||
|
||||
add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree
|
||||
|
|
|
@ -757,12 +757,13 @@ Introduced in GitLab 8.6 and GitLab Runner v1.1.1.
|
|||
This feature should be used in conjunction with [`artifacts`](#artifacts) and
|
||||
allows you to define the artifacts to pass between different builds.
|
||||
|
||||
Note that `artifacts` from previous [stages](#stages) are passed by default.
|
||||
Note that `artifacts` from all previous [stages](#stages) are passed by default.
|
||||
|
||||
To use this feature, define `dependencies` in context of the job and pass
|
||||
a list of all previous builds from which the artifacts should be downloaded.
|
||||
You can only define builds from stages that are executed before the current one.
|
||||
An error will be shown if you define builds from the current stage or next ones.
|
||||
Defining an empty array will skip downloading any artifacts for that job.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -53,3 +53,8 @@ Generating a sprite file containing all the Emoji can be done by running:
|
|||
```
|
||||
bundle exec rake gemojione:sprite
|
||||
```
|
||||
|
||||
If new emoji are added, the spritesheet may change size. To compensate for
|
||||
such changes, first generate the `emoji.png` spritesheet with the above Rake
|
||||
task, then check the dimensions of the new spritesheet and update the
|
||||
`SPRITESHEET_WIDTH` and `SPRITESHEET_HEIGHT` constants accordingly.
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
{
|
||||
"northeast_pointing_airplane":"airplane_northeast",
|
||||
"small_airplane":"airplane_small",
|
||||
"up_pointing_small_airplane":"airplane_small_up",
|
||||
"up_pointing_airplane":"airplane_up",
|
||||
"left_anger_bubble":"anger_left",
|
||||
"right_anger_bubble":"anger_right",
|
||||
"keycap_asterisk":"asterisk",
|
||||
"atom_symbol":"atom",
|
||||
"ballot_box_with_ballot":"ballot_box",
|
||||
"ballot_box_with_bold_check":"ballot_box_check",
|
||||
"ballot_box_with_script_x":"ballot_box_x",
|
||||
"ballot_script_x":"ballot_x",
|
||||
"person_with_ball":"basketball_player",
|
||||
"person_with_ball_tone1":"basketball_player_tone1",
|
||||
"person_with_ball_tone2":"basketball_player_tone2",
|
||||
|
@ -21,51 +14,65 @@
|
|||
"umbrella_on_ground":"beach_umbrella",
|
||||
"bellhop_bell":"bellhop",
|
||||
"biohazard_sign":"biohazard",
|
||||
"bouquet_of_flowers":"bouquet2",
|
||||
"archery":"bow_and_arrow",
|
||||
"bullhorn_with_sound_waves":"bullhorn_waves",
|
||||
"pocket calculator":"calculator",
|
||||
"boxing_gloves":"boxing_glove",
|
||||
"spiral_calendar_pad":"calendar_spiral",
|
||||
"call_me_hand":"call_me",
|
||||
"call_me_hand_tone1":"call_me_tone1",
|
||||
"call_me_hand_tone2":"call_me_tone2",
|
||||
"call_me_hand_tone3":"call_me_tone3",
|
||||
"call_me_hand_tone4":"call_me_tone4",
|
||||
"call_me_hand_tone5":"call_me_tone5",
|
||||
"kayak":"canoe",
|
||||
"card_file_box":"card_box",
|
||||
"tape_cartridge":"cartridge",
|
||||
"person_doing_cartwheel":"cartwheel",
|
||||
"person_doing_cartwheel_tone1":"cartwheel_tone1",
|
||||
"person_doing_cartwheel_tone2":"cartwheel_tone2",
|
||||
"person_doing_cartwheel_tone3":"cartwheel_tone3",
|
||||
"person_doing_cartwheel_tone4":"cartwheel_tone4",
|
||||
"person_doing_cartwheel_tone5":"cartwheel_tone5",
|
||||
"bottle_with_popping_cork":"champagne",
|
||||
"clinking_glass":"champagne_glass",
|
||||
"cheese_wedge":"cheese",
|
||||
"city_sunrise":"city_sunset",
|
||||
"mantlepiece_clock":"clock",
|
||||
"clockwise_right_and_left_semicircle_arrows":"clockwise_arrows",
|
||||
"cloud_with_lightning":"cloud_lightning",
|
||||
"cloud_with_rain":"cloud_rain",
|
||||
"cloud_with_snow":"cloud_snow",
|
||||
"cloud_with_tornado":"cloud_tornado",
|
||||
"old_personal_computer":"computer_old",
|
||||
"building_construction":"contruction_site",
|
||||
"clown_face":"clown",
|
||||
"building_construction":"construction_site",
|
||||
"couch_and_lamp":"couch",
|
||||
"couple_with_heart_mm":"couple_mm",
|
||||
"couple_with_heart_ww":"couple_ww",
|
||||
"face_with_cowboy_hat":"cowboy",
|
||||
"lower_left_crayon":"crayon",
|
||||
"cricket_bat_ball":"cricket",
|
||||
"latin_cross":"cross",
|
||||
"heavy_latin_cross":"cross_heavy",
|
||||
"white_latin_cross":"cross_white",
|
||||
"black_skull_and_crossbones":"crossbones",
|
||||
"passenger_ship":"cruise_ship",
|
||||
"dagger_knife":"dagger",
|
||||
"desktop_computer":"desktop",
|
||||
"card_index_dividers":"dividers",
|
||||
"document_with_text":"document_text",
|
||||
"dove_of_peace":"dove",
|
||||
"drool":"drooling_face",
|
||||
"drum_with_drumsticks":"drum",
|
||||
"email":"e-mail",
|
||||
"back_of_envelope":"envelope_back",
|
||||
"flying_envelope":"envelope_flying",
|
||||
"stamped_envelope":"envelope_stamped",
|
||||
"pen_over_stamped_envelope":"envelope_stamped_pen",
|
||||
"white_down_pointing_left_hand_index":"finger_pointing_down",
|
||||
"sideways_white_down_pointing_index":"finger_pointing_down2",
|
||||
"sideways_white_left_pointing_index":"finger_pointing_left",
|
||||
"sideways_white_right_pointing_index":"finger_pointing_right",
|
||||
"sideways_white_up_pointing_index":"finger_pointing_up",
|
||||
"eject_symbol":"eject",
|
||||
"facepalm":"face_palm",
|
||||
"facepalm_tone1":"face_palm_tone1",
|
||||
"facepalm_tone2":"face_palm_tone2",
|
||||
"facepalm_tone3":"face_palm_tone3",
|
||||
"facepalm_tone4":"face_palm_tone4",
|
||||
"facepalm_tone5":"face_palm_tone5",
|
||||
"fencing":"fencer",
|
||||
"hand_with_index_and_middle_finger_crossed":"fingers_crossed",
|
||||
"hand_with_index_and_middle_fingers_crossed_tone1":"fingers_crossed_tone1",
|
||||
"hand_with_index_and_middle_fingers_crossed_tone2":"fingers_crossed_tone2",
|
||||
"hand_with_index_and_middle_fingers_crossed_tone3":"fingers_crossed_tone3",
|
||||
"hand_with_index_and_middle_fingers_crossed_tone4":"fingers_crossed_tone4",
|
||||
"hand_with_index_and_middle_fingers_crossed_tone5":"fingers_crossed_tone5",
|
||||
"flame":"fire",
|
||||
"oncoming_fire_engine":"fire_engine_oncoming",
|
||||
"first_place_medal":"first_place",
|
||||
"ac":"flag_ac",
|
||||
"ad":"flag_ad",
|
||||
"ae":"flag_ae",
|
||||
|
@ -326,44 +333,51 @@
|
|||
"za":"flag_za",
|
||||
"zm":"flag_zm",
|
||||
"zw":"flag_zw",
|
||||
"clamshell_mobile_phone":"flip_phone",
|
||||
"black_hard_shell_floppy_disk":"floppy_black",
|
||||
"white_hard_shell_floppy_disk":"floppy_white",
|
||||
"open_folder":"folder_open",
|
||||
"fork_and_knife_with_plate":"fork_knife_plate",
|
||||
"fox_face":"fox",
|
||||
"frame_with_picture":"frame_photo",
|
||||
"frame_with_tiles":"frame_tiles",
|
||||
"frame_with_an_x":"frame_x",
|
||||
"baguette_bread":"french_bread",
|
||||
"anguished":"frowning",
|
||||
"white_frowning_face":"frowning2",
|
||||
"goal_net":"goal",
|
||||
"hammer_and_pick":"hammer_pick",
|
||||
"raised_hand_with_fingers_splayed":"hand_splayed",
|
||||
"reversed_raised_hand_with_fingers_splayed":"hand_splayed_reverse",
|
||||
"raised_hand_with_fingers_splayed_tone1":"hand_splayed_tone1",
|
||||
"raised_hand_with_fingers_splayed_tone2":"hand_splayed_tone2",
|
||||
"raised_hand_with_fingers_splayed_tone3":"hand_splayed_tone3",
|
||||
"raised_hand_with_fingers_splayed_tone4":"hand_splayed_tone4",
|
||||
"raised_hand_with_fingers_splayed_tone5":"hand_splayed_tone5",
|
||||
"reversed_victory_hand":"hand_victory",
|
||||
"shaking_hands":"handshake",
|
||||
"shaking_hands_tone1":"handshake_tone1",
|
||||
"shaking_hands_tone2":"handshake_tone2",
|
||||
"shaking_hands_tone3":"handshake_tone3",
|
||||
"shaking_hands_tone4":"handshake_tone4",
|
||||
"shaking_hands_tone5":"handshake_tone5",
|
||||
"face_with_head_bandage":"head_bandage",
|
||||
"heavy_heart_exclamation_mark_ornament":"heart_exclamation",
|
||||
"heart_with_tip_on_the_left":"heart_tip",
|
||||
"helmet_with_white_cross":"helmet_with_cross",
|
||||
"house_buildings":"homes",
|
||||
"hot_dog":"hotdog",
|
||||
"derelict_house_building":"house_abandoned",
|
||||
"hugging_face":"hugging",
|
||||
"circled_information_source":"info",
|
||||
"desert_island":"island",
|
||||
"up_pointing_military_airplane":"jet_up",
|
||||
"juggler":"juggling",
|
||||
"juggler_tone1":"juggling_tone1",
|
||||
"juggler_tone2":"juggling_tone2",
|
||||
"juggler_tone3":"juggling_tone3",
|
||||
"juggler_tone4":"juggling_tone4",
|
||||
"juggler_tone5":"juggling_tone5",
|
||||
"old_key":"key2",
|
||||
"wired_keyboard":"keyboard",
|
||||
"keyboard_and_mouse":"keyboard_mouse",
|
||||
"musical_keyboard_with_jacks":"keyboard_with_jacks",
|
||||
"couplekiss_mm":"kiss_mm",
|
||||
"couplekiss_ww":"kiss_ww",
|
||||
"kiwifruit":"kiwi",
|
||||
"satisfied":"laughing",
|
||||
"left_hand_telephone_receiver":"left_receiver",
|
||||
"left_fist":"left_facing_fist",
|
||||
"left_fist_tone1":"left_facing_fist_tone1",
|
||||
"left_fist_tone2":"left_facing_fist_tone2",
|
||||
"left_fist_tone3":"left_facing_fist_tone3",
|
||||
"left_fist_tone4":"left_facing_fist_tone4",
|
||||
"left_fist_tone5":"left_facing_fist_tone5",
|
||||
"man_in_business_suit_levitating":"levitate",
|
||||
"weight_lifter":"lifter",
|
||||
"weight_lifter_tone1":"lifter_tone1",
|
||||
|
@ -371,9 +385,21 @@
|
|||
"weight_lifter_tone3":"lifter_tone3",
|
||||
"weight_lifter_tone4":"lifter_tone4",
|
||||
"weight_lifter_tone5":"lifter_tone5",
|
||||
"light_mark":"light_check_mark",
|
||||
"lion":"lion_face",
|
||||
"liar":"lying_face",
|
||||
"male_dancer":"man_dancing",
|
||||
"male_dancer_tone1":"man_dancing_tone1",
|
||||
"male_dancer_tone2":"man_dancing_tone2",
|
||||
"male_dancer_tone3":"man_dancing_tone3",
|
||||
"male_dancer_tone4":"man_dancing_tone4",
|
||||
"male_dancer_tone5":"man_dancing_tone5",
|
||||
"tuxedo_tone1":"man_in_tuxedo_tone1",
|
||||
"tuxedo_tone2":"man_in_tuxedo_tone2",
|
||||
"tuxedo_tone3":"man_in_tuxedo_tone3",
|
||||
"tuxedo_tone4":"man_in_tuxedo_tone4",
|
||||
"tuxedo_tone5":"man_in_tuxedo_tone5",
|
||||
"world_map":"map",
|
||||
"karate_uniform":"martial_arts_uniform",
|
||||
"sports_medal":"medal",
|
||||
"sign_of_the_horns":"metal",
|
||||
"sign_of_the_horns_tone1":"metal_tone1",
|
||||
|
@ -388,21 +414,23 @@
|
|||
"reversed_hand_with_middle_finger_extended_tone3":"middle_finger_tone3",
|
||||
"reversed_hand_with_middle_finger_extended_tone4":"middle_finger_tone4",
|
||||
"reversed_hand_with_middle_finger_extended_tone5":"middle_finger_tone5",
|
||||
"glass_of_milk":"milk",
|
||||
"money_mouth_face":"money_mouth",
|
||||
"lightning_mood_bubble":"mood_bubble_lightning",
|
||||
"lightning_mood":"mood_lightning",
|
||||
"motorbike":"motor_scooter",
|
||||
"racing_motorcycle":"motorcycle",
|
||||
"snow_capped_mountain":"mountain_snow",
|
||||
"one_button_mouse":"mouse_one",
|
||||
"three_button_mouse":"mouse_three_button",
|
||||
"mother_christmas":"mrs_claus",
|
||||
"mother_christmas_tone1":"mrs_claus_tone1",
|
||||
"mother_christmas_tone2":"mrs_claus_tone2",
|
||||
"mother_christmas_tone3":"mrs_claus_tone3",
|
||||
"mother_christmas_tone4":"mrs_claus_tone4",
|
||||
"mother_christmas_tone5":"mrs_claus_tone5",
|
||||
"sick":"nauseated_face",
|
||||
"nerd_face":"nerd",
|
||||
"three_networked_computers":"network",
|
||||
"rolled_up_newspaper":"newspaper2",
|
||||
"note_page":"note",
|
||||
"empty_note_page":"note_empty",
|
||||
"note_pad":"notepad",
|
||||
"empty_note_pad":"notepad_empty",
|
||||
"spiral_note_pad":"notepad_spiral",
|
||||
"stop_sign":"octagonal_sign",
|
||||
"oil_drum":"oil",
|
||||
"grandma":"older_woman",
|
||||
"grandma_tone1":"older_woman_tone1",
|
||||
|
@ -410,57 +438,66 @@
|
|||
"grandma_tone3":"older_woman_tone3",
|
||||
"grandma_tone4":"older_woman_tone4",
|
||||
"grandma_tone5":"older_woman_tone5",
|
||||
"optical_disc_icon":"optical_disk",
|
||||
"lower_left_paintbrush":"paintbrush",
|
||||
"linked_paperclips":"paperclips",
|
||||
"national_park":"park",
|
||||
"double_vertical_bar":"pause_button",
|
||||
"peace_symbol":"peace",
|
||||
"shelled_peanut":"peanuts",
|
||||
"lower_left_ballpoint_pen":"pen_ballpoint",
|
||||
"lower_left_fountain_pen":"pen_fountain",
|
||||
"memo":"pencil",
|
||||
"lower_left_pencil":"pencil3",
|
||||
"black_pennant":"pennant_black",
|
||||
"white_pennant":"pennant_white",
|
||||
"table_tennis":"ping_pong",
|
||||
"no_piracy":"piracy",
|
||||
"worship_symbol":"place_of_worship",
|
||||
"shit":"poop",
|
||||
"hankey":"poop",
|
||||
"poo":"poop",
|
||||
"prohibited_sign":"prohibited",
|
||||
"expecting_woman":"pregnant_woman",
|
||||
"expecting_woman_tone1":"pregnant_woman_tone1",
|
||||
"expecting_woman_tone2":"pregnant_woman_tone2",
|
||||
"expecting_woman_tone3":"pregnant_woman_tone3",
|
||||
"expecting_woman_tone4":"pregnant_woman_tone4",
|
||||
"expecting_woman_tone5":"pregnant_woman_tone5",
|
||||
"film_projector":"projector",
|
||||
"racing_car":"race_car",
|
||||
"radioactive_sign":"radioactive",
|
||||
"railroad_track":"railway_track",
|
||||
"right_speaker_with_one_sound_wave":"right_speaker_one",
|
||||
"right_speaker_with_three_sound_waves":"right_speaker_three",
|
||||
"back_of_hand":"raised_back_of_hand",
|
||||
"back_of_hand_tone1":"raised_back_of_hand_tone1",
|
||||
"back_of_hand_tone2":"raised_back_of_hand_tone2",
|
||||
"back_of_hand_tone3":"raised_back_of_hand_tone3",
|
||||
"back_of_hand_tone4":"raised_back_of_hand_tone4",
|
||||
"back_of_hand_tone5":"raised_back_of_hand_tone5",
|
||||
"rhinoceros":"rhino",
|
||||
"right_fist":"right_facing_fist",
|
||||
"right_fist_tone1":"right_facing_fist_tone1",
|
||||
"right_fist_tone2":"right_facing_fist_tone2",
|
||||
"right_fist_tone3":"right_facing_fist_tone3",
|
||||
"right_fist_tone4":"right_facing_fist_tone4",
|
||||
"right_fist_tone5":"right_facing_fist_tone5",
|
||||
"robot_face":"robot",
|
||||
"rolling_on_the_floor_laughing":"rofl",
|
||||
"face_with_rolling_eyes":"rolling_eyes",
|
||||
"green_salad":"salad",
|
||||
"second_place_medal":"second_place",
|
||||
"paella":"shallow_pan_of_food",
|
||||
"shopping_trolley":"shopping_cart",
|
||||
"skeleton":"skull",
|
||||
"skull_and_crossbones":"skull_crossbones",
|
||||
"slightly_frowning_face":"slight_frown",
|
||||
"slightly_smiling_face":"slight_smile",
|
||||
"sneeze":"sneezing_face",
|
||||
"speaking_head_in_silhouette":"speaking_head",
|
||||
"left_speech_bubble":"speech_left",
|
||||
"right_speech_bubble":"speech_right",
|
||||
"three_speech_bubbles":"speech_three",
|
||||
"two_speech_bubbles":"speech_two",
|
||||
"sleuth_or_spy":"spy",
|
||||
"sleuth_or_spy_tone1":"spy_tone1",
|
||||
"sleuth_or_spy_tone2":"spy_tone2",
|
||||
"sleuth_or_spy_tone3":"spy_tone3",
|
||||
"sleuth_or_spy_tone4":"spy_tone4",
|
||||
"sleuth_or_spy_tone5":"spy_tone5",
|
||||
"portable_stereo":"stereo",
|
||||
"black_touchtone_telephone":"telephone_black",
|
||||
"white_touchtone_telephone":"telephone_white",
|
||||
"stuffed_pita":"stuffed_flatbread",
|
||||
"face_with_thermometer":"thermometer_face",
|
||||
"thinking_face":"thinking",
|
||||
"left_thought_bubble":"thought_left",
|
||||
"right_thought_bubble":"thought_right",
|
||||
"reversed_thumbs_down_sign":"thumbs_down_reverse",
|
||||
"reversed_thumbs_up_sign":"thumbs_up_reverse",
|
||||
"third_place_medal":"third_place",
|
||||
"-1":"thumbsdown",
|
||||
"-1_tone1":"thumbsdown_tone1",
|
||||
"-1_tone2":"thumbsdown_tone2",
|
||||
|
@ -479,9 +516,7 @@
|
|||
"hammer_and_wrench":"tools",
|
||||
"next_track":"track_next",
|
||||
"previous_track":"track_previous",
|
||||
"diesel_locomotive":"train_diesel",
|
||||
"triangle_with_rounded_corners":"triangle_round",
|
||||
"turned_ok_hand_sign":"turned_ok_hand",
|
||||
"whisky":"tumbler_glass",
|
||||
"unicorn_face":"unicorn",
|
||||
"upside_down_face":"upside_down",
|
||||
"funeral_urn":"urn",
|
||||
|
@ -494,6 +529,12 @@
|
|||
"white_sun_behind_cloud":"white_sun_cloud",
|
||||
"white_sun_behind_cloud_with_rain":"white_sun_rain_cloud",
|
||||
"white_sun_with_small_cloud":"white_sun_small_cloud",
|
||||
"left_writing_hand":"writing_hand",
|
||||
"wilted_flower":"wilted_rose",
|
||||
"wrestling":"wrestlers",
|
||||
"wrestling_tone1":"wrestlers_tone1",
|
||||
"wrestling_tone2":"wrestlers_tone2",
|
||||
"wrestling_tone3":"wrestlers_tone3",
|
||||
"wrestling_tone4":"wrestlers_tone4",
|
||||
"wrestling_tone5":"wrestlers_tone5",
|
||||
"zipper_mouth_face":"zipper_mouth"
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@ module API
|
|||
def current_user
|
||||
@current_user ||= (find_user_by_private_token || doorkeeper_guard)
|
||||
|
||||
unless @current_user && Gitlab::UserAccess.allowed?(@current_user)
|
||||
unless @current_user && Gitlab::UserAccess.new(@current_user).allowed?
|
||||
return nil
|
||||
end
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@ module Gitlab
|
|||
OWNER = 50
|
||||
|
||||
# Branch protection settings
|
||||
PROTECTION_NONE = 0
|
||||
PROTECTION_DEV_CAN_PUSH = 1
|
||||
PROTECTION_FULL = 2
|
||||
PROTECTION_NONE = 0
|
||||
PROTECTION_DEV_CAN_PUSH = 1
|
||||
PROTECTION_FULL = 2
|
||||
PROTECTION_DEV_CAN_MERGE = 3
|
||||
|
||||
class << self
|
||||
def values
|
||||
|
@ -54,6 +55,7 @@ module Gitlab
|
|||
def protection_options
|
||||
{
|
||||
"Not protected: Both developers and masters can push new commits, force push, or delete the branch." => PROTECTION_NONE,
|
||||
"Protected against pushes: Developers cannot push new commits, but are allowed to accept merge requests to the branch." => PROTECTION_DEV_CAN_MERGE,
|
||||
"Partially protected: Developers can push new commits, but cannot force push or delete the branch. Masters can do all of those." => PROTECTION_DEV_CAN_PUSH,
|
||||
"Fully protected: Developers cannot push new commits, force push, or delete the branch. Only masters can do any of those." => PROTECTION_FULL,
|
||||
}
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
module Gitlab
|
||||
class AwardEmoji
|
||||
CATEGORIES = {
|
||||
other: "Other",
|
||||
objects: "Objects",
|
||||
places: "Places",
|
||||
travel_places: "Travel",
|
||||
emoticons: "Emoticons",
|
||||
objects_symbols: "Symbols",
|
||||
travel: "Travel",
|
||||
symbols: "Symbols",
|
||||
nature: "Nature",
|
||||
celebration: "Celebration",
|
||||
people: "People",
|
||||
activity: "Activity",
|
||||
flags: "Flags",
|
||||
food_drink: "Food"
|
||||
}.with_indifferent_access
|
||||
|
||||
CATEGORY_ALIASES = {
|
||||
symbols: "objects_symbols",
|
||||
foods: "food_drink",
|
||||
travel: "travel_places"
|
||||
food: "Food"
|
||||
}.with_indifferent_access
|
||||
|
||||
def self.normalize_emoji_name(name)
|
||||
|
@ -35,7 +25,7 @@ module Gitlab
|
|||
# Skip Fitzpatrick(tone) modifiers
|
||||
next if data["category"] == "modifier"
|
||||
|
||||
category = CATEGORY_ALIASES[data["category"]] || data["category"]
|
||||
category = data["category"]
|
||||
|
||||
@emoji_by_category[category] << data
|
||||
end
|
||||
|
@ -57,9 +47,9 @@ module Gitlab
|
|||
def self.aliases
|
||||
@aliases ||=
|
||||
begin
|
||||
json_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json' )
|
||||
JSON.parse(File.read(json_path))
|
||||
end
|
||||
json_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
|
||||
JSON.parse(File.read(json_path))
|
||||
end
|
||||
end
|
||||
|
||||
# Returns an Array of Emoji names and their asset URLs.
|
||||
|
|
96
lib/gitlab/checks/change_access.rb
Normal file
96
lib/gitlab/checks/change_access.rb
Normal file
|
@ -0,0 +1,96 @@
|
|||
module Gitlab
|
||||
module Checks
|
||||
class ChangeAccess
|
||||
attr_reader :user_access, :project
|
||||
|
||||
def initialize(change, user_access:, project:)
|
||||
@oldrev, @newrev, @ref = change.split(' ')
|
||||
@branch_name = branch_name(@ref)
|
||||
@user_access = user_access
|
||||
@project = project
|
||||
end
|
||||
|
||||
def exec
|
||||
error = protected_branch_checks || tag_checks || push_checks
|
||||
|
||||
if error
|
||||
GitAccessStatus.new(false, error)
|
||||
else
|
||||
GitAccessStatus.new(true)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def protected_branch_checks
|
||||
return unless project.protected_branch?(@branch_name)
|
||||
|
||||
if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches)
|
||||
return "You are not allowed to force push code to a protected branch on this project."
|
||||
elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches)
|
||||
return "You are not allowed to delete protected branches from this project."
|
||||
end
|
||||
|
||||
if matching_merge_request?
|
||||
if user_access.can_merge_to_branch?(@branch_name) || user_access.can_push_to_branch?(@branch_name)
|
||||
return
|
||||
else
|
||||
"You are not allowed to merge code into protected branches on this project."
|
||||
end
|
||||
else
|
||||
if user_access.can_push_to_branch?(@branch_name)
|
||||
return
|
||||
else
|
||||
"You are not allowed to push code to protected branches on this project."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def tag_checks
|
||||
tag_ref = tag_name(@ref)
|
||||
|
||||
if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project)
|
||||
"You are not allowed to change existing tags on this project."
|
||||
end
|
||||
end
|
||||
|
||||
def push_checks
|
||||
if user_access.cannot_do_action?(:push_code)
|
||||
"You are not allowed to push code to this project."
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def protected_tag?(tag_name)
|
||||
project.repository.tag_exists?(tag_name)
|
||||
end
|
||||
|
||||
def forced_push?
|
||||
Gitlab::Checks::ForcePush.force_push?(@project, @oldrev, @newrev)
|
||||
end
|
||||
|
||||
def matching_merge_request?
|
||||
Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match?
|
||||
end
|
||||
|
||||
def branch_name(ref)
|
||||
ref = @ref.to_s
|
||||
if Gitlab::Git.branch_ref?(ref)
|
||||
Gitlab::Git.ref_name(ref)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def tag_name(ref)
|
||||
ref = @ref.to_s
|
||||
if Gitlab::Git.tag_ref?(ref)
|
||||
Gitlab::Git.ref_name(ref)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
lib/gitlab/checks/force_push.rb
Normal file
17
lib/gitlab/checks/force_push.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Gitlab
|
||||
module Checks
|
||||
class ForcePush
|
||||
def self.force_push?(project, oldrev, newrev)
|
||||
return false if project.empty_repo?
|
||||
|
||||
# Created or deleted branch
|
||||
if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
|
||||
false
|
||||
else
|
||||
missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
|
||||
missed_refs.split("\n").size > 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
lib/gitlab/checks/matching_merge_request.rb
Normal file
18
lib/gitlab/checks/matching_merge_request.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
module Gitlab
|
||||
module Checks
|
||||
class MatchingMergeRequest
|
||||
def initialize(newrev, branch_name, project)
|
||||
@newrev = newrev
|
||||
@branch_name = branch_name
|
||||
@project = project
|
||||
end
|
||||
|
||||
def match?
|
||||
@project.merge_requests
|
||||
.with_state(:locked)
|
||||
.where(in_progress_merge_commit_sha: @newrev, target_branch: @branch_name)
|
||||
.exists?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ module Gitlab
|
|||
|
||||
delegate :new_file, :deleted_file, :renamed_file,
|
||||
:old_path, :new_path, :a_mode, :b_mode,
|
||||
:submodule?, :too_large?, to: :diff, prefix: false
|
||||
:submodule?, :too_large?, :collapsed?, to: :diff, prefix: false
|
||||
|
||||
def initialize(diff, repository:, diff_refs: nil)
|
||||
@diff = diff
|
||||
|
@ -68,10 +68,6 @@ module Gitlab
|
|||
@lines ||= Gitlab::Diff::Parser.new.parse(raw_diff.each_line).to_a
|
||||
end
|
||||
|
||||
def collapsed_by_default?
|
||||
diff.diff.bytesize > 10240 # 10 KB
|
||||
end
|
||||
|
||||
def highlighted_diff_lines
|
||||
@highlighted_diff_lines ||= Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight
|
||||
end
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
module Gitlab
|
||||
class ForcePushCheck
|
||||
def self.force_push?(project, oldrev, newrev)
|
||||
return false if project.empty_repo?
|
||||
|
||||
# Created or deleted branch
|
||||
if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
|
||||
false
|
||||
else
|
||||
missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
|
||||
missed_refs.split("\n").size > 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,52 +1,17 @@
|
|||
# Check a user's access to perform a git action. All public methods in this
|
||||
# class return an instance of `GitlabAccessStatus`
|
||||
module Gitlab
|
||||
class GitAccess
|
||||
DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
|
||||
PUSH_COMMANDS = %w{ git-receive-pack }
|
||||
|
||||
attr_reader :actor, :project, :protocol
|
||||
attr_reader :actor, :project, :protocol, :user_access
|
||||
|
||||
def initialize(actor, project, protocol)
|
||||
@actor = actor
|
||||
@project = project
|
||||
@protocol = protocol
|
||||
end
|
||||
|
||||
def user
|
||||
return @user if defined?(@user)
|
||||
|
||||
@user =
|
||||
case actor
|
||||
when User
|
||||
actor
|
||||
when DeployKey
|
||||
nil
|
||||
when Key
|
||||
actor.user
|
||||
end
|
||||
end
|
||||
|
||||
def deploy_key
|
||||
actor if actor.is_a?(DeployKey)
|
||||
end
|
||||
|
||||
def can_push_to_branch?(ref)
|
||||
return false unless user
|
||||
|
||||
if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref)
|
||||
user.can?(:push_code_to_protected_branches, project)
|
||||
else
|
||||
user.can?(:push_code, project)
|
||||
end
|
||||
end
|
||||
|
||||
def can_read_project?
|
||||
if user
|
||||
user.can?(:read_project, project)
|
||||
elsif deploy_key
|
||||
deploy_key.projects.include?(project)
|
||||
else
|
||||
false
|
||||
end
|
||||
@user_access = UserAccess.new(user, project: project)
|
||||
end
|
||||
|
||||
def check(cmd, changes = nil)
|
||||
|
@ -56,11 +21,11 @@ module Gitlab
|
|||
return build_status_object(false, "No user or key was provided.")
|
||||
end
|
||||
|
||||
if user && !user_allowed?
|
||||
if user && !user_access.allowed?
|
||||
return build_status_object(false, "Your account has been blocked.")
|
||||
end
|
||||
|
||||
unless project && can_read_project?
|
||||
unless project && (user_access.can_read_project? || deploy_key_can_read_project?)
|
||||
return build_status_object(false, 'The project you were looking for could not be found.')
|
||||
end
|
||||
|
||||
|
@ -95,7 +60,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def user_download_access_check
|
||||
unless user.can?(:download_code, project)
|
||||
unless user_access.can_do_action?(:download_code)
|
||||
return build_status_object(false, "You are not allowed to download code from this project.")
|
||||
end
|
||||
|
||||
|
@ -125,46 +90,8 @@ module Gitlab
|
|||
build_status_object(true)
|
||||
end
|
||||
|
||||
def can_user_do_action?(action)
|
||||
@permission_cache ||= {}
|
||||
@permission_cache[action] ||= user.can?(action, project)
|
||||
end
|
||||
|
||||
def change_access_check(change)
|
||||
oldrev, newrev, ref = change.split(' ')
|
||||
|
||||
action =
|
||||
if project.protected_branch?(branch_name(ref))
|
||||
protected_branch_action(oldrev, newrev, branch_name(ref))
|
||||
elsif (tag_ref = tag_name(ref)) && protected_tag?(tag_ref)
|
||||
# Prevent any changes to existing git tag unless user has permissions
|
||||
:admin_project
|
||||
else
|
||||
:push_code
|
||||
end
|
||||
|
||||
unless can_user_do_action?(action)
|
||||
status =
|
||||
case action
|
||||
when :force_push_code_to_protected_branches
|
||||
build_status_object(false, "You are not allowed to force push code to a protected branch on this project.")
|
||||
when :remove_protected_branches
|
||||
build_status_object(false, "You are not allowed to deleted protected branches from this project.")
|
||||
when :push_code_to_protected_branches
|
||||
build_status_object(false, "You are not allowed to push code to protected branches on this project.")
|
||||
when :admin_project
|
||||
build_status_object(false, "You are not allowed to change existing tags on this project.")
|
||||
else # :push_code
|
||||
build_status_object(false, "You are not allowed to push code to this project.")
|
||||
end
|
||||
return status
|
||||
end
|
||||
|
||||
build_status_object(true)
|
||||
end
|
||||
|
||||
def forced_push?(oldrev, newrev)
|
||||
Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev)
|
||||
Checks::ChangeAccess.new(change, user_access: user_access, project: project).exec
|
||||
end
|
||||
|
||||
def protocol_allowed?
|
||||
|
@ -173,48 +100,38 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def protected_branch_action(oldrev, newrev, branch_name)
|
||||
# we dont allow force push to protected branch
|
||||
if forced_push?(oldrev, newrev)
|
||||
:force_push_code_to_protected_branches
|
||||
elsif Gitlab::Git.blank_ref?(newrev)
|
||||
# and we dont allow remove of protected branch
|
||||
:remove_protected_branches
|
||||
elsif project.developers_can_push_to_protected_branch?(branch_name)
|
||||
:push_code
|
||||
def matching_merge_request?(newrev, branch_name)
|
||||
Checks::MatchingMergeRequest.new(newrev, branch_name, project).match?
|
||||
end
|
||||
|
||||
def deploy_key
|
||||
actor if actor.is_a?(DeployKey)
|
||||
end
|
||||
|
||||
def deploy_key_can_read_project?
|
||||
if deploy_key
|
||||
deploy_key.projects.include?(project)
|
||||
else
|
||||
:push_code_to_protected_branches
|
||||
end
|
||||
end
|
||||
|
||||
def protected_tag?(tag_name)
|
||||
project.repository.tag_exists?(tag_name)
|
||||
end
|
||||
|
||||
def user_allowed?
|
||||
Gitlab::UserAccess.allowed?(user)
|
||||
end
|
||||
|
||||
def branch_name(ref)
|
||||
ref = ref.to_s
|
||||
if Gitlab::Git.branch_ref?(ref)
|
||||
Gitlab::Git.ref_name(ref)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def tag_name(ref)
|
||||
ref = ref.to_s
|
||||
if Gitlab::Git.tag_ref?(ref)
|
||||
Gitlab::Git.ref_name(ref)
|
||||
else
|
||||
nil
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def user
|
||||
return @user if defined?(@user)
|
||||
|
||||
@user =
|
||||
case actor
|
||||
when User
|
||||
actor
|
||||
when DeployKey
|
||||
nil
|
||||
when Key
|
||||
actor.user
|
||||
end
|
||||
end
|
||||
|
||||
def build_status_object(status, message = '')
|
||||
GitAccessStatus.new(status, message)
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
class GitAccessWiki < GitAccess
|
||||
def change_access_check(change)
|
||||
if user.can?(:create_wiki, project)
|
||||
if user_access.can_do_action?(:create_wiki)
|
||||
build_status_object(true)
|
||||
else
|
||||
build_status_object(false, "You are not allowed to write to this project's wiki.")
|
||||
|
|
|
@ -2,7 +2,7 @@ module Gitlab
|
|||
module ImportExport
|
||||
extend self
|
||||
|
||||
VERSION = '0.1.1'
|
||||
VERSION = '0.1.2'
|
||||
FILENAME_LIMIT = 50
|
||||
|
||||
def export_path(relative_path:)
|
||||
|
|
|
@ -53,7 +53,11 @@ included_attributes:
|
|||
excluded_attributes:
|
||||
snippets:
|
||||
- :expired_at
|
||||
merge_request_diff:
|
||||
- :st_diffs
|
||||
|
||||
methods:
|
||||
statuses:
|
||||
- :type
|
||||
- :type
|
||||
merge_request_diff:
|
||||
- :utf8_st_diffs
|
|
@ -33,6 +33,7 @@ module Gitlab
|
|||
update_project_references
|
||||
reset_ci_tokens if @relation_name == 'Ci::Trigger'
|
||||
@relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data']
|
||||
set_st_diffs if @relation_name == :merge_request_diff
|
||||
|
||||
generate_imported_object
|
||||
end
|
||||
|
@ -129,6 +130,10 @@ module Gitlab
|
|||
def parsed_relation_hash
|
||||
@relation_hash.reject { |k, _v| !relation_class.attribute_method?(k) }
|
||||
end
|
||||
|
||||
def set_st_diffs
|
||||
@relation_hash['st_diffs'] = @relation_hash.delete('utf8_st_diffs')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
module Gitlab
|
||||
module UserAccess
|
||||
def self.allowed?(user)
|
||||
return false if user.blocked?
|
||||
class UserAccess
|
||||
attr_reader :user, :project
|
||||
|
||||
def initialize(user, project: nil)
|
||||
@user = user
|
||||
@project = project
|
||||
end
|
||||
|
||||
def can_do_action?(action)
|
||||
@permission_cache ||= {}
|
||||
@permission_cache[action] ||= user.can?(action, project)
|
||||
end
|
||||
|
||||
def cannot_do_action?(action)
|
||||
!can_do_action?(action)
|
||||
end
|
||||
|
||||
def allowed?
|
||||
return false if user.blank? || user.blocked?
|
||||
|
||||
if user.requires_ldap_check? && user.try_obtain_ldap_lease
|
||||
return false unless Gitlab::LDAP::Access.allowed?(user)
|
||||
|
@ -9,5 +25,31 @@ module Gitlab
|
|||
|
||||
true
|
||||
end
|
||||
|
||||
def can_push_to_branch?(ref)
|
||||
return false unless user
|
||||
|
||||
if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref)
|
||||
user.can?(:push_code_to_protected_branches, project)
|
||||
else
|
||||
user.can?(:push_code, project)
|
||||
end
|
||||
end
|
||||
|
||||
def can_merge_to_branch?(ref)
|
||||
return false unless user
|
||||
|
||||
if project.protected_branch?(ref) && !project.developers_can_merge_to_protected_branch?(ref)
|
||||
user.can?(:push_code_to_protected_branches, project)
|
||||
else
|
||||
user.can?(:push_code, project)
|
||||
end
|
||||
end
|
||||
|
||||
def can_read_project?
|
||||
return false unless user
|
||||
|
||||
user.can?(:read_project, project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace :gemojione do
|
|||
require 'digest/sha2'
|
||||
require 'json'
|
||||
|
||||
dir = Gemojione.index.images_path
|
||||
dir = Gemojione.images_path
|
||||
digests = []
|
||||
aliases = Hash.new { |hash, key| hash[key] = [] }
|
||||
aliases_path = File.join(Rails.root, 'fixtures', 'emojis', 'aliases.json')
|
||||
|
@ -50,9 +50,14 @@ namespace :gemojione do
|
|||
SIZE = 20
|
||||
RETINA = SIZE * 2
|
||||
|
||||
# Update these values to the width and height of the spritesheet when
|
||||
# new emoji are added.
|
||||
SPRITESHEET_WIDTH = 860
|
||||
SPRITESHEET_HEIGHT = 840
|
||||
|
||||
Dir.mktmpdir do |tmpdir|
|
||||
# Copy the Gemojione assets to the temporary folder for resizing
|
||||
FileUtils.cp_r(Gemojione.index.images_path, tmpdir)
|
||||
FileUtils.cp_r(Gemojione.images_path, tmpdir)
|
||||
|
||||
Dir.chdir(tmpdir) do
|
||||
Dir["**/*.png"].each do |png|
|
||||
|
@ -64,7 +69,7 @@ namespace :gemojione do
|
|||
|
||||
# Combine the resized assets into a packed sprite and re-generate the SCSS
|
||||
SpriteFactory.cssurl = "image-url('$IMAGE')"
|
||||
SpriteFactory.run!(File.join(tmpdir, 'images'), {
|
||||
SpriteFactory.run!(File.join(tmpdir, 'png'), {
|
||||
output_style: style_path,
|
||||
output_image: "app/assets/images/emoji.png",
|
||||
selector: '.emoji-',
|
||||
|
@ -97,7 +102,7 @@ namespace :gemojione do
|
|||
only screen and (min-resolution: 192dpi),
|
||||
only screen and (min-resolution: 2dppx) {
|
||||
background-image: image-url('emoji@2x.png');
|
||||
background-size: 840px 820px;
|
||||
background-size: #{SPRITESHEET_WIDTH}px #{SPRITESHEET_HEIGHT}px;
|
||||
}
|
||||
}
|
||||
CSS
|
||||
|
@ -107,7 +112,7 @@ namespace :gemojione do
|
|||
# Now do it again but for Retina
|
||||
Dir.mktmpdir do |tmpdir|
|
||||
# Copy the Gemojione assets to the temporary folder for resizing
|
||||
FileUtils.cp_r(Gemojione.index.images_path, tmpdir)
|
||||
FileUtils.cp_r(Gemojione.images_path, tmpdir)
|
||||
|
||||
Dir.chdir(tmpdir) do
|
||||
Dir["**/*.png"].each do |png|
|
||||
|
@ -116,7 +121,7 @@ namespace :gemojione do
|
|||
end
|
||||
|
||||
# Combine the resized assets into a packed sprite and re-generate the SCSS
|
||||
SpriteFactory.run!(File.join(tmpdir, 'images'), {
|
||||
SpriteFactory.run!(File.join(tmpdir), {
|
||||
output_image: "app/assets/images/emoji@2x.png",
|
||||
style: false,
|
||||
nocomments: true,
|
||||
|
|
|
@ -3,10 +3,11 @@ require 'spec_helper'
|
|||
feature 'Expand and collapse diffs', js: true, feature: true do
|
||||
include WaitForAjax
|
||||
|
||||
let(:branch) { 'expand-collapse-diffs' }
|
||||
|
||||
before do
|
||||
login_as :admin
|
||||
project = create(:project)
|
||||
branch = 'expand-collapse-diffs'
|
||||
|
||||
# Ensure that undiffable.md is in .gitattributes
|
||||
project.repository.copy_gitattributes(branch)
|
||||
|
@ -167,6 +168,46 @@ feature 'Expand and collapse diffs', js: true, feature: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'visiting a commit without collapsed diffs' do
|
||||
let(:branch) { 'feature' }
|
||||
|
||||
it 'does not show Expand all button' do
|
||||
expect(page).not_to have_link('Expand all')
|
||||
end
|
||||
end
|
||||
|
||||
context 'visiting a commit with more than safe files' do
|
||||
let(:branch) { 'expand-collapse-files' }
|
||||
|
||||
# safe-files -> 100 | safe-lines -> 5000 | commit-files -> 105
|
||||
it 'does collapsing from the safe number of files to the end on small files' do
|
||||
expect(page).to have_link('Expand all')
|
||||
|
||||
expect(page).to have_selector('.diff-content', count: 105)
|
||||
expect(page).to have_selector('.diff-collapsed', count: 5)
|
||||
|
||||
%w(file-95.txt file-96.txt file-97.txt file-98.txt file-99.txt).each do |filename|
|
||||
expect(find("[data-blob-diff-path*='#{filename}']")).to have_selector('.diff-collapsed')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'visiting a commit with more than safe lines' do
|
||||
let(:branch) { 'expand-collapse-lines' }
|
||||
|
||||
# safe-files -> 100 | safe-lines -> 5000 | commit_files -> 8 (each 1250 lines)
|
||||
it 'does collapsing from the safe number of lines to the end' do
|
||||
expect(page).to have_link('Expand all')
|
||||
|
||||
expect(page).to have_selector('.diff-content', count: 6)
|
||||
expect(page).to have_selector('.diff-collapsed', count: 2)
|
||||
|
||||
%w(file-4.txt file-5.txt).each do |filename|
|
||||
expect(find("[data-blob-diff-path*='#{filename}']")).to have_selector('.diff-collapsed')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'expanding all diffs' do
|
||||
before do
|
||||
click_link('Expand all')
|
||||
|
|
|
@ -30,12 +30,31 @@ describe DiffHelper do
|
|||
expect(helper.diff_view).to eq 'inline'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'diff_options' do
|
||||
it 'should return hard limit for a diff' do
|
||||
it 'should return hard limit for a diff if force diff is true' do
|
||||
allow(controller).to receive(:params) { { force_show_diff: true } }
|
||||
expect(diff_options).to include(Commit.max_diff_options)
|
||||
end
|
||||
|
||||
it 'should return hard limit for a diff if expand_all_diffs is true' do
|
||||
allow(controller).to receive(:params) { { expand_all_diffs: true } }
|
||||
expect(diff_options).to include(Commit.max_diff_options)
|
||||
end
|
||||
|
||||
it 'should return no collapse false' do
|
||||
expect(diff_options).to include(no_collapse: false)
|
||||
end
|
||||
|
||||
it 'should return no collapse true if expand_all_diffs' do
|
||||
allow(controller).to receive(:params) { { expand_all_diffs: true } }
|
||||
expect(diff_options).to include(no_collapse: true)
|
||||
end
|
||||
|
||||
it 'should return no collapse true if action name diff_for_path' do
|
||||
allow(controller).to receive(:action_name) { 'diff_for_path' }
|
||||
expect(diff_options).to include(no_collapse: true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unfold_bottom_class' do
|
||||
|
|
|
@ -32,4 +32,18 @@ describe Gitlab::Diff::File, lib: true do
|
|||
expect(diff_file.too_large?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#collapsed?' do
|
||||
it 'returns true for a file that is quite big' do
|
||||
expect(diff).to receive(:collapsed?).and_return(true)
|
||||
|
||||
expect(diff_file.collapsed?).to eq(true)
|
||||
end
|
||||
|
||||
it 'returns false for a file that is small enough' do
|
||||
expect(diff).to receive(:collapsed?).and_return(false)
|
||||
|
||||
expect(diff_file.collapsed?).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1639,7 +1639,8 @@ describe Gitlab::Diff::PositionTracer, lib: true do
|
|||
committer: committer
|
||||
}
|
||||
|
||||
repository.merge(current_user, second_create_file_commit.sha, branch_name, options)
|
||||
merge_request = create(:merge_request, source_branch: second_create_file_commit.sha, target_branch: branch_name, source_project: project)
|
||||
repository.merge(current_user, merge_request, options)
|
||||
project.commit(branch_name)
|
||||
end
|
||||
|
||||
|
|
|
@ -6,67 +6,6 @@ describe Gitlab::GitAccess, lib: true do
|
|||
let(:user) { create(:user) }
|
||||
let(:actor) { user }
|
||||
|
||||
describe 'can_push_to_branch?' do
|
||||
describe 'push to none protected branch' do
|
||||
it "returns true if user is a master" do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_push_to_branch?("random_branch")).to be_truthy
|
||||
end
|
||||
|
||||
it "returns true if user is a developer" do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_push_to_branch?("random_branch")).to be_truthy
|
||||
end
|
||||
|
||||
it "returns false if user is a reporter" do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_push_to_branch?("random_branch")).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe 'push to protected branch' do
|
||||
before do
|
||||
@branch = create :protected_branch, project: project
|
||||
end
|
||||
|
||||
it "returns true if user is a master" do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it "returns false if user is a developer" do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_falsey
|
||||
end
|
||||
|
||||
it "returns false if user is a reporter" do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe 'push to protected branch if allowed for developers' do
|
||||
before do
|
||||
@branch = create :protected_branch, project: project, developers_can_push: true
|
||||
end
|
||||
|
||||
it "returns true if user is a master" do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it "returns true if user is a developer" do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it "returns false if user is a reporter" do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check with single protocols allowed' do
|
||||
def disable_protocol(protocol)
|
||||
settings = ::ApplicationSetting.create_from_defaults
|
||||
|
@ -160,96 +99,46 @@ describe Gitlab::GitAccess, lib: true do
|
|||
end
|
||||
|
||||
describe 'push_access_check' do
|
||||
def protect_feature_branch
|
||||
create(:protected_branch, name: 'feature', project: project)
|
||||
end
|
||||
before { merge_into_protected_branch }
|
||||
let(:unprotected_branch) { FFaker::Internet.user_name }
|
||||
|
||||
def changes
|
||||
{
|
||||
push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow",
|
||||
let(:changes) do
|
||||
{ push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow",
|
||||
push_master: '6f6d7e7ed 570e7b2ab refs/heads/master',
|
||||
push_protected_branch: '6f6d7e7ed 570e7b2ab refs/heads/feature',
|
||||
push_remove_protected_branch: "570e7b2ab #{Gitlab::Git::BLANK_SHA} "\
|
||||
'refs/heads/feature',
|
||||
push_tag: '6f6d7e7ed 570e7b2ab refs/tags/v1.0.0',
|
||||
push_new_tag: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/tags/v7.8.9",
|
||||
push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature']
|
||||
}
|
||||
push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'],
|
||||
merge_into_protected_branch: "0b4bc9a #{merge_into_protected_branch} refs/heads/feature" }
|
||||
end
|
||||
|
||||
def self.permissions_matrix
|
||||
{
|
||||
master: {
|
||||
push_new_branch: true,
|
||||
push_master: true,
|
||||
push_protected_branch: true,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: true,
|
||||
push_new_tag: true,
|
||||
push_all: true,
|
||||
},
|
||||
|
||||
developer: {
|
||||
push_new_branch: true,
|
||||
push_master: true,
|
||||
push_protected_branch: false,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: false,
|
||||
push_new_tag: true,
|
||||
push_all: false,
|
||||
},
|
||||
|
||||
reporter: {
|
||||
push_new_branch: false,
|
||||
push_master: false,
|
||||
push_protected_branch: false,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: false,
|
||||
push_new_tag: false,
|
||||
push_all: false,
|
||||
},
|
||||
|
||||
guest: {
|
||||
push_new_branch: false,
|
||||
push_master: false,
|
||||
push_protected_branch: false,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: false,
|
||||
push_new_tag: false,
|
||||
push_all: false,
|
||||
}
|
||||
}
|
||||
def stub_git_hooks
|
||||
# Running the `pre-receive` hook is expensive, and not necessary for this test.
|
||||
allow_any_instance_of(GitHooksService).to receive(:execute).and_yield
|
||||
end
|
||||
|
||||
def self.updated_permissions_matrix
|
||||
updated_permissions_matrix = permissions_matrix.dup
|
||||
updated_permissions_matrix[:developer][:push_protected_branch] = true
|
||||
updated_permissions_matrix[:developer][:push_all] = true
|
||||
updated_permissions_matrix
|
||||
end
|
||||
def merge_into_protected_branch
|
||||
@protected_branch_merge_commit ||= begin
|
||||
stub_git_hooks
|
||||
project.repository.add_branch(user, unprotected_branch, 'feature')
|
||||
target_branch = project.repository.lookup('feature')
|
||||
source_branch = project.repository.commit_file(user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, FFaker::HipsterIpsum.sentence, unprotected_branch, false)
|
||||
rugged = project.repository.rugged
|
||||
author = { email: "email@example.com", time: Time.now, name: "Example Git User" }
|
||||
|
||||
permissions_matrix.keys.each do |role|
|
||||
describe "#{role} access" do
|
||||
before { protect_feature_branch }
|
||||
before { project.team << [user, role] }
|
||||
|
||||
permissions_matrix[role].each do |action, allowed|
|
||||
context action do
|
||||
subject { access.push_access_check(changes[action]) }
|
||||
|
||||
it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
|
||||
end
|
||||
end
|
||||
merge_index = rugged.merge_commits(target_branch, source_branch)
|
||||
Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged))
|
||||
end
|
||||
end
|
||||
|
||||
context "with enabled developers push to protected branches " do
|
||||
updated_permissions_matrix.keys.each do |role|
|
||||
def self.run_permission_checks(permissions_matrix)
|
||||
permissions_matrix.keys.each do |role|
|
||||
describe "#{role} access" do
|
||||
before { create(:protected_branch, name: 'feature', developers_can_push: true, project: project) }
|
||||
before { project.team << [user, role] }
|
||||
|
||||
updated_permissions_matrix[role].each do |action, allowed|
|
||||
permissions_matrix[role].each do |action, allowed|
|
||||
context action do
|
||||
subject { access.push_access_check(changes[action]) }
|
||||
|
||||
|
@ -259,5 +148,97 @@ describe Gitlab::GitAccess, lib: true do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions_matrix = {
|
||||
master: {
|
||||
push_new_branch: true,
|
||||
push_master: true,
|
||||
push_protected_branch: true,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: true,
|
||||
push_new_tag: true,
|
||||
push_all: true,
|
||||
merge_into_protected_branch: true
|
||||
},
|
||||
|
||||
developer: {
|
||||
push_new_branch: true,
|
||||
push_master: true,
|
||||
push_protected_branch: false,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: false,
|
||||
push_new_tag: true,
|
||||
push_all: false,
|
||||
merge_into_protected_branch: false
|
||||
},
|
||||
|
||||
reporter: {
|
||||
push_new_branch: false,
|
||||
push_master: false,
|
||||
push_protected_branch: false,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: false,
|
||||
push_new_tag: false,
|
||||
push_all: false,
|
||||
merge_into_protected_branch: false
|
||||
},
|
||||
|
||||
guest: {
|
||||
push_new_branch: false,
|
||||
push_master: false,
|
||||
push_protected_branch: false,
|
||||
push_remove_protected_branch: false,
|
||||
push_tag: false,
|
||||
push_new_tag: false,
|
||||
push_all: false,
|
||||
merge_into_protected_branch: false
|
||||
}
|
||||
}
|
||||
|
||||
[['feature', 'exact'], ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
|
||||
context do
|
||||
before { create(:protected_branch, name: protected_branch_name, project: project) }
|
||||
|
||||
run_permission_checks(permissions_matrix)
|
||||
end
|
||||
|
||||
context "when 'developers can push' is turned on for the #{protected_branch_type} protected branch" do
|
||||
before { create(:protected_branch, name: protected_branch_name, developers_can_push: true, project: project) }
|
||||
|
||||
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
|
||||
end
|
||||
|
||||
context "when 'developers can merge' is turned on for the #{protected_branch_type} protected branch" do
|
||||
before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, project: project) }
|
||||
|
||||
context "when a merge request exists for the given source/target branch" do
|
||||
context "when the merge request is in progress" do
|
||||
before do
|
||||
create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch)
|
||||
end
|
||||
|
||||
run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: true }))
|
||||
end
|
||||
|
||||
context "when the merge request is not in progress" do
|
||||
before do
|
||||
create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', in_progress_merge_commit_sha: nil)
|
||||
end
|
||||
|
||||
run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false }))
|
||||
end
|
||||
end
|
||||
|
||||
context "when a merge request does not exist for the given source/target branch" do
|
||||
run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false }))
|
||||
end
|
||||
end
|
||||
|
||||
context "when 'developers can merge' and 'developers can push' are turned on for the #{protected_branch_type} protected branch" do
|
||||
before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, developers_can_push: true, project: project) }
|
||||
|
||||
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2765,7 +2765,7 @@
|
|||
"committer_email": "dmitriy.zaporozhets@gmail.com"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "Binary files a/.DS_Store and /dev/null differ\n",
|
||||
"new_path": ".DS_Store",
|
||||
|
@ -3138,7 +3138,7 @@
|
|||
"committer_email": "dmitriy.zaporozhets@gmail.com"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "--- /dev/null\n+++ b/files/ruby/feature.rb\n@@ -0,0 +1,5 @@\n+class Feature\n+ def foo\n+ puts 'bar'\n+ end\n+end\n",
|
||||
"new_path": "files/ruby/feature.rb",
|
||||
|
@ -3423,7 +3423,7 @@
|
|||
"committer_email": "james@jameslopez.es"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "--- /dev/null\n+++ b/test\n",
|
||||
"new_path": "test",
|
||||
|
@ -3960,7 +3960,7 @@
|
|||
"committer_email": "dmitriy.zaporozhets@gmail.com"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "Binary files a/.DS_Store and /dev/null differ\n",
|
||||
"new_path": ".DS_Store",
|
||||
|
@ -4597,7 +4597,7 @@
|
|||
"committer_email": "marmis85@gmail.com"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n",
|
||||
"new_path": "CHANGELOG",
|
||||
|
@ -5108,7 +5108,7 @@
|
|||
"committer_email": "stanhu@packetzoom.com"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n",
|
||||
"new_path": "CHANGELOG",
|
||||
|
@ -5434,7 +5434,7 @@
|
|||
"id": 11,
|
||||
"state": "empty",
|
||||
"st_commits": null,
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
|
||||
],
|
||||
"merge_request_id": 11,
|
||||
|
@ -5961,7 +5961,7 @@
|
|||
"committer_email": "dmitriy.zaporozhets@gmail.com"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "Binary files a/.DS_Store and /dev/null differ\n",
|
||||
"new_path": ".DS_Store",
|
||||
|
@ -6400,7 +6400,7 @@
|
|||
"committer_email": "james@jameslopez.es"
|
||||
}
|
||||
],
|
||||
"st_diffs": [
|
||||
"utf8_st_diffs": [
|
||||
{
|
||||
"diff": "--- /dev/null\n+++ b/test\n",
|
||||
"new_path": "test",
|
||||
|
|
|
@ -2,6 +2,7 @@ require 'spec_helper'
|
|||
|
||||
describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
|
||||
describe 'restore project tree' do
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:namespace) { create(:namespace, owner: user) }
|
||||
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') }
|
||||
|
@ -53,6 +54,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
|
|||
expect(event.note.noteable.project).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'has the correct data for merge request st_diffs' do
|
||||
# makes sure we are renaming the custom method +utf8_st_diffs+ into +st_diffs+
|
||||
|
||||
expect { restored_project_json }.to change(MergeRequestDiff.where.not(st_diffs: nil), :count).by(9)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -102,12 +102,17 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
|
|||
it 'has ci pipeline notes' do
|
||||
expect(saved_project_json['pipelines'].first['notes']).not_to be_empty
|
||||
end
|
||||
|
||||
it 'does not complain about non UTF-8 characters in MR diffs' do
|
||||
ActiveRecord::Base.connection.execute("UPDATE merge_request_diffs SET st_diffs = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
|
||||
|
||||
expect(project_tree_saver.save).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setup_project
|
||||
issue = create(:issue, assignee: user)
|
||||
merge_request = create(:merge_request)
|
||||
label = create(:label)
|
||||
snippet = create(:project_snippet)
|
||||
release = create(:release)
|
||||
|
@ -115,12 +120,12 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
|
|||
project = create(:project,
|
||||
:public,
|
||||
issues: [issue],
|
||||
merge_requests: [merge_request],
|
||||
labels: [label],
|
||||
snippets: [snippet],
|
||||
releases: [release]
|
||||
)
|
||||
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
commit_status = create(:commit_status, project: project)
|
||||
|
||||
ci_pipeline = create(:ci_pipeline,
|
||||
|
|
88
spec/lib/gitlab/user_access_spec.rb
Normal file
88
spec/lib/gitlab/user_access_spec.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::UserAccess, lib: true do
|
||||
let(:access) { Gitlab::UserAccess.new(user, project: project) }
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
describe 'can_push_to_branch?' do
|
||||
describe 'push to none protected branch' do
|
||||
it 'returns true if user is a master' do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_push_to_branch?('random_branch')).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns true if user is a developer' do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_push_to_branch?('random_branch')).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if user is a reporter' do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_push_to_branch?('random_branch')).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe 'push to protected branch' do
|
||||
let(:branch) { create :protected_branch, project: project }
|
||||
|
||||
it 'returns true if user is a master' do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_push_to_branch?(branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if user is a developer' do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_push_to_branch?(branch.name)).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns false if user is a reporter' do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_push_to_branch?(branch.name)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe 'push to protected branch if allowed for developers' do
|
||||
before do
|
||||
@branch = create :protected_branch, project: project, developers_can_push: true
|
||||
end
|
||||
|
||||
it 'returns true if user is a master' do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns true if user is a developer' do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if user is a reporter' do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_push_to_branch?(@branch.name)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe 'merge to protected branch if allowed for developers' do
|
||||
before do
|
||||
@branch = create :protected_branch, project: project, developers_can_merge: true
|
||||
end
|
||||
|
||||
it 'returns true if user is a master' do
|
||||
project.team << [user, :master]
|
||||
expect(access.can_merge_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns true if user is a developer' do
|
||||
project.team << [user, :developer]
|
||||
expect(access.can_merge_to_branch?(@branch.name)).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if user is a reporter' do
|
||||
project.team << [user, :reporter]
|
||||
expect(access.can_merge_to_branch?(@branch.name)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -23,6 +23,44 @@ describe BuildsEmailService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#test_data' do
|
||||
let(:build) { create(:ci_build) }
|
||||
let(:project) { build.project }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before { project.team << [user, :developer] }
|
||||
|
||||
it 'builds test data' do
|
||||
data = subject.test_data(project)
|
||||
|
||||
expect(data[:object_kind]).to eq("build")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#test' do
|
||||
it 'sends email' do
|
||||
data = Gitlab::BuildDataBuilder.build(create(:ci_build))
|
||||
subject.recipients = 'test@gitlab.com'
|
||||
|
||||
expect(BuildEmailWorker).to receive(:perform_async)
|
||||
|
||||
subject.test(data)
|
||||
end
|
||||
|
||||
context 'notify only failed builds is true' do
|
||||
it 'sends email' do
|
||||
data = Gitlab::BuildDataBuilder.build(create(:ci_build))
|
||||
data[:build_status] = "success"
|
||||
subject.recipients = 'test@gitlab.com'
|
||||
|
||||
expect(subject).not_to receive(:notify_only_broken_builds)
|
||||
expect(BuildEmailWorker).to receive(:perform_async)
|
||||
|
||||
subject.test(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
it 'sends email' do
|
||||
subject.recipients = 'test@gitlab.com'
|
||||
|
|
|
@ -4,16 +4,17 @@ describe Repository, models: true do
|
|||
include RepoHelpers
|
||||
TestBlob = Struct.new(:name)
|
||||
|
||||
let(:repository) { create(:project).repository }
|
||||
let(:project) { create(:project) }
|
||||
let(:repository) { project.repository }
|
||||
let(:user) { create(:user) }
|
||||
let(:commit_options) do
|
||||
author = repository.user_to_committer(user)
|
||||
{ message: 'Test message', committer: author, author: author }
|
||||
end
|
||||
let(:merge_commit) do
|
||||
source_sha = repository.find_branch('feature').target
|
||||
merge_commit_sha = repository.merge(user, source_sha, 'master', commit_options)
|
||||
repository.commit(merge_commit_sha)
|
||||
merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project)
|
||||
merge_commit_id = repository.merge(user, merge_request, commit_options)
|
||||
repository.commit(merge_commit_id)
|
||||
end
|
||||
|
||||
describe '#branch_names_contains' do
|
||||
|
|
|
@ -49,7 +49,7 @@ describe API::Helpers, api: true do
|
|||
|
||||
it "should return nil for a user without access" do
|
||||
env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
|
||||
allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
|
||||
allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
|
||||
expect(current_user).to be_nil
|
||||
end
|
||||
|
||||
|
@ -73,7 +73,7 @@ describe API::Helpers, api: true do
|
|||
|
||||
it "should return nil for a user without access" do
|
||||
env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
|
||||
allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
|
||||
allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
|
||||
expect(current_user).to be_nil
|
||||
end
|
||||
|
||||
|
|
|
@ -224,7 +224,7 @@ describe GitPushService, services: true do
|
|||
it "when pushing a branch for the first time" do
|
||||
expect(project).to receive(:execute_hooks)
|
||||
expect(project.default_branch).to eq("master")
|
||||
expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false })
|
||||
expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: false })
|
||||
execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
|
||||
end
|
||||
|
||||
|
@ -242,7 +242,17 @@ describe GitPushService, services: true do
|
|||
|
||||
expect(project).to receive(:execute_hooks)
|
||||
expect(project.default_branch).to eq("master")
|
||||
expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true })
|
||||
expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true, developers_can_merge: false })
|
||||
|
||||
execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master')
|
||||
end
|
||||
|
||||
it "when pushing a branch for the first time with default branch protection set to 'developers can merge'" do
|
||||
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
|
||||
|
||||
expect(project).to receive(:execute_hooks)
|
||||
expect(project.default_branch).to eq("master")
|
||||
expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: true })
|
||||
execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
|
||||
end
|
||||
|
||||
|
|
|
@ -262,4 +262,42 @@ describe Issues::BulkUpdateService, services: true do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :subscribe_issues do
|
||||
let(:issues) { create_list(:issue, 5, project: project) }
|
||||
let(:params) do
|
||||
{
|
||||
subscription_event: 'subscribe',
|
||||
issues_ids: issues.map(&:id).join(',')
|
||||
}
|
||||
end
|
||||
|
||||
it 'subscribes the given user' do
|
||||
issues.each do |issue|
|
||||
expect(issue.subscribed?(user)).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :unsubscribe_issues do
|
||||
let(:issues) { create_list(:closed_issue, 5, project: project) }
|
||||
let(:params) do
|
||||
{
|
||||
subscription_event: 'unsubscribe',
|
||||
issues_ids: issues.map(&:id).join(',')
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
issues.each do |issue|
|
||||
issue.subscriptions.create(user: user, subscribed: true)
|
||||
end
|
||||
end
|
||||
|
||||
it 'unsubscribes the given user' do
|
||||
issues.each do |issue|
|
||||
expect(issue.subscribed?(user)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -88,8 +88,7 @@ describe MergeRequests::RefreshService, services: true do
|
|||
# Merge master -> feature branch
|
||||
author = { email: 'test@gitlab.com', time: Time.now, name: "Me" }
|
||||
commit_options = { message: 'Test message', committer: author, author: author }
|
||||
master_commit = @project.repository.commit('master')
|
||||
@project.repository.merge(@user, master_commit.id, 'feature', commit_options)
|
||||
@project.repository.merge(@user, @merge_request, commit_options)
|
||||
commit = @project.repository.commit('feature')
|
||||
service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature')
|
||||
reload_mrs
|
||||
|
|
|
@ -18,7 +18,9 @@ module TestEnv
|
|||
'orphaned-branch' => '45127a9',
|
||||
'binary-encoding' => '7b1cf43',
|
||||
'gitattributes' => '5a62481',
|
||||
'expand-collapse-diffs' => '4842455'
|
||||
'expand-collapse-diffs' => '4842455',
|
||||
'expand-collapse-files' => '025db92',
|
||||
'expand-collapse-lines' => '238e82d'
|
||||
}
|
||||
|
||||
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
|
||||
|
|
|
@ -3,8 +3,12 @@ require 'spec_helper'
|
|||
describe 'projects/builds/show' do
|
||||
include Devise::TestHelpers
|
||||
|
||||
let(:build) { create(:ci_build) }
|
||||
let(:project) { build.project }
|
||||
let(:project) { create(:project) }
|
||||
let(:pipeline) do
|
||||
create(:ci_pipeline, project: project,
|
||||
sha: project.commit.id)
|
||||
end
|
||||
let(:build) { create(:ci_build, pipeline: pipeline) }
|
||||
|
||||
before do
|
||||
assign(:build, build)
|
||||
|
@ -34,4 +38,15 @@ describe 'projects/builds/show' do
|
|||
expect(rendered).to have_link('Retry')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'commit title in sidebar' do
|
||||
let(:commit_title) { project.commit.title }
|
||||
|
||||
it 'shows commit title and not show commit message' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_css('p.build-light-text.append-bottom-0',
|
||||
text: /\A\n#{Regexp.escape(commit_title)}\n\Z/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue