Commit 7b014338 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into contributor-graph-by-email

parents bb8b6f38 1c040b3f
......@@ -37,8 +37,10 @@ nohup.out
public/assets/
public/uploads.*
public/uploads/
shared/artifacts/
rails_best_practices_output.html
/tags
tmp/
vendor/bundle/*
builds/*
shared/*
......@@ -73,3 +73,18 @@ brakeman:
tags:
- ruby
- mysql
flog:
script:
- bundle exec rake flog
tags:
- ruby
- mysql
flay:
script:
- bundle exec rake flay
tags:
- ruby
- mysql
allow_failure: true
......@@ -2,6 +2,13 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.2.0 (unreleased)
- Fix grouping of contributors by email in graph.
- Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu)
- Fix Drone CI service template not saving properly (Stan Hu)
- Fix avatars not showing in Atom feeds and project issues when Gravatar disabled (Stan Hu)
- Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749)
- Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu)
- Improved performance of finding users by one of their Email addresses
- Add allow_failure field to commit status API (Stan Hu)
- Improved performance of replacing references in comments
- Show last project commit to default branch on project home page
- Highlight comment based on anchor in URL
......@@ -12,11 +19,47 @@ v 8.2.0 (unreleased)
- Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork
- Use git follow flag for commits page when retrieve history for file or directory
- Show merge request CI status on merge requests index page
- Send build name and stage in CI notification e-mail
- Extend yml syntax for only and except to support specifying repository path
- Enable shared runners to all new projects
- Bump GitLab-Workhorse to 0.4.1
- Allow to define cache in `.gitlab-ci.yml`
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
- Remove deprecated CI events from project settings page
- Use issue editor as cross reference comment author when issue is edited with a new mention.
v 8.1.1
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file
- Fix omniauth documentation setting for omnibus configuration (Jon Cairns)
- Add "New file" link to dropdown on project page
- Include commit logs in project search
- Add "added", "modified" and "removed" properties to commit object in webhook
- Rename "Back to" links to "Go to" because its not always a case it point to place user come from
- Allow groups to appear in the search results if the group owner allows it
- New design for project graphs page
- Remove deprecated dumped yaml file generated from previous job definitions
- Fix incoming email config defaults
- Show specific runners from projects where user is master or owner
- MR target branch is now visible on a list view when it is different from project's default one
- Improve Continuous Integration graphs page
- Make color of "Accept Merge Request" button consistent with current build status
- Add ignore white space option in merge request diff and commit and compare view
- Ability to add release notes (markdown text and attachments) to git tags (aka Releases)
- Relative links from a repositories README.md now link to the default branch
- Fix trailing whitespace issue in merge request/issue title
- Fix bug when milestone/label filter was empty for dashboard issues page
- Add ability to create milestone in group projects from single form
v 8.1.4
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
- Prevent redirect loop when home_page_url is set to the root URL
- Fix incoming email config defaults
- Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu)
v 8.1.3
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Spread out runner contacted_at updates
- Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication
v 8.1.2
- Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory
- Fix specific runners visibility
......@@ -26,10 +69,15 @@ v 8.1.1
- Fix CI badge
- Allow developer to manage builds
v 8.1.1
- Removed, see 8.1.2
v 8.1.0
- Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu)
- Fix duplicate repositories in GitHub import page (Stan Hu)
- Redirect to a default path if HTTP_REFERER is not set (Stan Hu)
- Adds ability to create directories using the web editor (Ben Ford)
- Cleanup stuck CI builds
- Send an email to admin email when a user is reported for spam (Jonathan Rochkind)
- Show notifications button when user is member of group rather than project (Grzegorz Bizon)
- Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.
......@@ -67,6 +115,7 @@ v 8.1.0
- Show CI status on Your projects page and Starred projects page
- Remove "Continuous Integration" page from dashboard
- Add notes and SSL verification entries to hook APIs (Ben Boeckel)
- Added build artifacts
- Fix grammar in admin area "labels" .nothing-here-block when no labels exist.
- Move CI runners page to project settings area
- Move CI variables page to project settings area
......
......@@ -10,7 +10,7 @@ By submitting code as an individual you agree to the [individual contributor lic
## Security vulnerability disclosure
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](https://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
## Closing policy for issues and merge requests
......@@ -35,7 +35,7 @@ The [GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab
Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](https://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
### Issue tracker guidelines
......@@ -72,7 +72,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you are changing the README, some documentation or other things which have no effect on the tests, add `[ci skip]` somewhere in the commit message
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
1. If you have multiple commits please combine them into one commit by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
1. Push the commit to your fork
1. Submit a merge request (MR) to the master branch
1. The MR title should describe the change you want to make
......@@ -181,4 +181,4 @@ This code of conduct applies both within project spaces and in public spaces whe
Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
......@@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0'
......@@ -39,7 +40,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.19'
gem "gitlab_git", '~> 7.2.20'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -50,20 +51,16 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
gem 'gollum-lib', '~> 4.0.2'
# Language detection
# GitLab fork of linguist does not require pygments/python dependency.
# New version of original gem also dropped pygments support but it has strict
# dependency to unstable rugged version. We have internal issue for replacing
# fork with original gem when we meet on same rugged version - https://dev.gitlab.org/gitlab/gitlabhq/issues/2052.
gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
gem "github-linguist", "~> 4.7.0", require: "linguist"
# API
gem 'grape', '~> 0.6.1'
gem 'grape', '~> 0.13.0'
gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times
# based on human-friendly examples
gem "stamp", '~> 0.5.0'
gem "stamp", '~> 0.6.0'
# Enumeration fields
gem 'enumerize', '~> 0.7.0'
......@@ -112,7 +109,7 @@ group :unicorn do
end
# State machine
gem "state_machine", '~> 1.2.0'
gem "state_machines-activerecord", '~> 0.3.0'
# Run events after state machine commits
gem 'after_commit_queue'
......@@ -184,7 +181,7 @@ gem 'ace-rails-ap', '~> 2.0.1'
gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.6.9.4'
gem 'charlock_holmes', '~> 0.7.3'
gem "sass-rails", '~> 4.0.5'
gem "coffee-rails", '~> 4.1.0'
......@@ -214,11 +211,9 @@ group :development do
gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2'
gem 'rack-mini-profiler', '~> 0.9.0', require: false
gem 'rerun', '~> 0.10.0'
gem 'bullet', require: false
gem 'active_record_query_trace', require: false
gem 'rack-lineprof', platform: :mri
gem 'rblineprof', platform: :mri, require: false
# Better errors handler
gem 'better_errors', '~> 1.0.1'
......@@ -264,6 +259,8 @@ group :development, :test do
gem 'rubocop', '~> 0.28.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
gem 'flay', require: false
gem 'benchmark-ips', require: false
end
......
......@@ -17,7 +17,6 @@ GEM
activesupport (= 4.1.12)
builder (~> 3.1)
erubis (~> 2.7.0)
active_record_query_trace (1.5)
activemodel (4.1.12)
activesupport (= 4.1.12)
builder (~> 3.1)
......@@ -108,7 +107,7 @@ GEM
json (>= 1.7)
celluloid (0.16.0)
timers (~> 4.0.0)
charlock_holmes (0.6.9.4)
charlock_holmes (0.7.3)
chunky_png (1.3.4)
cliver (0.3.2)
coderay (1.1.0)
......@@ -176,7 +175,7 @@ GEM
activesupport (>= 3.2)
equalizer (0.0.11)
erubis (2.7.0)
escape_utils (0.2.4)
escape_utils (1.1.0)
eventmachine (1.0.8)
excon (0.45.4)
execjs (2.6.0)
......@@ -195,6 +194,12 @@ GEM
ffi (1.9.10)
fission (0.5.0)
CFPropertyList (~> 2.2)
flay (2.6.1)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
flog (4.3.2)
ruby_parser (~> 3.1, > 3.1.0)
sexp_processor (~> 4.4)
flowdock (0.7.0)
httparty (~> 0.7)
multi_json
......@@ -267,6 +272,11 @@ GEM
json
get_process_mem (0.2.0)
gherkin-ruby (0.3.2)
github-linguist (4.7.0)
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
rugged (>= 0.23.0b)
github-markup (1.3.3)
gitlab-flowdock-git-hook (1.0.1)
flowdock (~> 0.7)
......@@ -277,17 +287,13 @@ GEM
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3)
gitlab-linguist (3.0.1)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4)
mime-types (~> 1.19)
gitlab_emoji (0.1.1)
gemojione (~> 2.0)
gitlab_git (7.2.19)
gitlab_git (7.2.20)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
rugged (~> 0.22.2)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
rugged (~> 0.23.3)
gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9)
......@@ -306,10 +312,10 @@ GEM
gon (5.0.4)
actionpack (>= 2.3.0)
json
grape (0.6.1)
grape (0.13.0)
activesupport
builder
hashie (>= 1.2.0)
hashie (>= 2.1.0)
multi_json (>= 1.3.2)
multi_xml (>= 0.5.2)
rack (>= 1.3.0)
......@@ -423,6 +429,8 @@ GEM
multi_json (~> 1.7)
omniauth (~> 1.1)
omniauth-oauth (~> 1.0)
omniauth-facebook (3.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
......@@ -489,12 +497,6 @@ GEM
rack-attack (4.3.0)
rack
rack-cors (0.4.0)
rack-lineprof (0.0.3)
rack (~> 1.5)
rblineprof (~> 0.3.6)
term-ansicolor (~> 1.3)
rack-mini-profiler (0.9.7)
rack (>= 1.1.3)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-oauth2 (1.0.10)
......@@ -615,7 +617,7 @@ GEM
sexp_processor (~> 4.1)
rubyntlm (0.5.2)
rubypants (0.2.0)
rugged (0.22.2)
rugged (0.23.3)
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
......@@ -689,8 +691,14 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
stamp (0.5.0)
state_machine (1.2.0)
stamp (0.6.0)
state_machines (0.4.0)
state_machines-activemodel (0.3.0)
activemodel (~> 4.1)
state_machines (>= 0.4.0)
state_machines-activerecord (0.3.0)
activerecord (~> 4.1)
state_machines-activemodel (>= 0.3.0)
stringex (2.5.2)
systemu (2.6.5)
task_list (1.0.2)
......@@ -777,7 +785,6 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.2.9)
ace-rails-ap (~> 2.0.1)
active_record_query_trace
activerecord-deprecated_finders (~> 1.0.3)
activerecord-session_store (~> 0.1.0)
acts-as-taggable-on (~> 3.4)
......@@ -800,7 +807,7 @@ DEPENDENCIES
capybara (~> 2.4.0)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.9.0)
charlock_holmes (~> 0.6.9.4)
charlock_holmes (~> 0.7.3)
coffee-rails (~> 4.1.0)
colored (~> 1.2)
colorize (~> 0.5.8)
......@@ -820,21 +827,23 @@ DEPENDENCIES
enumerize (~> 0.7.0)
factory_girl_rails (~> 4.3.0)
ffaker (~> 2.0.0)
flay
flog
fog (~> 1.25.0)
font-awesome-rails (~> 4.2)
foreman
fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2)
github-linguist (~> 4.7.0)
github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
gitlab_git (~> 7.2.19)
gitlab_git (~> 7.2.20)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.0.2)
gon (~> 5.0.0)
grape (~> 0.6.1)
grape (~> 0.13.0)
grape-entity (~> 0.4.2)
haml-rails (~> 0.9.0)
hipchat (~> 1.5.0)
......@@ -859,6 +868,7 @@ DEPENDENCIES
octokit (~> 3.7.0)
omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2)
omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0)
......@@ -875,11 +885,10 @@ DEPENDENCIES
quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.0)
rack-cors (~> 0.4.0)
rack-lineprof
rack-mini-profiler (~> 0.9.0)
rack-oauth2 (~> 1.0.5)
rails (= 4.1.12)
raphael-rails (~> 2.1.2)
rblineprof
rdoc (~> 3.6)
redcarpet (~> 3.3.3)
redis-rails (~> 4.0.0)
......@@ -909,8 +918,8 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3)
stamp (~> 0.5.0)
state_machine (~> 1.2.0)
stamp (~> 0.6.0)
state_machines-activerecord (~> 0.3.0)
task_list (~> 1.0.2)
teaspoon (~> 1.0.0)
teaspoon-jasmine (~> 2.2.0)
......
......@@ -119,6 +119,6 @@ rebase with master to see if that solves the issue.
### Closing down the issue tracker on GitHub
We are currently in the process of closing down the issue tracker on GitHub, to
prevent duplication with the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues].
prevent duplication with the GitLab.com issue tracker.
Since this is an older issue I'll be closing this for now. If you think this is
still an issue I encourage you to open it on the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues].
still an issue I encourage you to open it on the \[GitLab.com issue tracker\](https://gitlab.com/gitlab-org/gitlab-ce/issues).
......@@ -11,10 +11,10 @@ class @EditBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
return false
# Before a form submission, move the content from the Ace editor into the
# submitted textarea
$('form').submit ->
$("#file-content").val(editor.getValue())
editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a")
......
......@@ -11,10 +11,10 @@ class @NewBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
return false
# Before a form submission, move the content from the Ace editor into the
# submitted textarea
$('form').submit ->
$("#file-content").val(editor.getValue())
editor: ->
return @editor
......@@ -25,7 +25,7 @@ class @Calendar
30
]
legendCellPadding: 3
cellSize: $('.user-calendar').width() / 80
cellSize: $('.user-calendar').width() / 73
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax
......
......@@ -28,6 +28,8 @@ class Dispatcher
when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode()
new DropzoneInput($('.milestone-form'))
when 'groups:milestones:new'
new ZenMode()
when 'projects:compare:show'
new Diff()
when 'projects:issues:new','projects:issues:edit'
......@@ -39,6 +41,12 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
new DropzoneInput($('.merge-request-form'))
new IssuableForm($('.merge-request-form'))
when 'projects:tags:new'
new ZenMode()
new DropzoneInput($('.tag-form'))
when 'projects:releases:edit'
new ZenMode()
new DropzoneInput($('.release-form'))
when 'projects:merge_requests:show'
new Diff()
shortcut_handler = new ShortcutsIssuable()
......
......@@ -29,7 +29,6 @@ class @Notes
$(document).on "ajax:success", "form.edit_note", @updateNote
# Edit note link
$(document).on "click", ".js-note-edit", @showEditForm
$(document).on "click", ".note-edit-cancel", @cancelEdit
# Reopen and close actions for Issue/MR combined with note form submit
......@@ -67,7 +66,6 @@ class @Notes
$(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form"
$(document).off "ajax:success", "form.edit_note"
$(document).off "click", ".js-note-edit"
$(document).off "click", ".note-edit-cancel"
$(document).off "click", ".js-note-delete"
$(document).off "click", ".js-note-attachment-delete"
......@@ -287,13 +285,14 @@ class @Notes
Adds a hidden div with the original content of the note to fill the edit note form with
if the user cancels
###
showEditForm: (e) ->
e.preventDefault()
note = $(this).closest(".note")
showEditForm: (note, formHTML) ->
nodeText = note.find(".note-text");
nodeText.hide()
note.find('.note-edit-form').remove()
nodeText.after(formHTML)
note.find(".note-body > .note-text").hide()
note.find(".note-header").hide()
base_form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form)
form = note.find(".note-edit-form")
form.addClass('current-note-edit-form gfm-form')
form.find('.div-dropzone').remove()
......
......@@ -28,6 +28,10 @@
border-bottom: 1px solid $border-color;
color: $gl-gray;
&.oneline-block {
line-height: 42px;
}
&.white {
background-color: white;
}
......@@ -100,7 +104,7 @@
}
.cover-desc {
padding: 0 $gl-padding;
padding: 0 $gl-padding 3px;
color: $gl-text-color;
}
......
......@@ -180,3 +180,7 @@
}
}
}
.btn-clipboard {
border: none;
}
......@@ -9,9 +9,9 @@
.bs-callout {
margin: 20px 0;
padding: 20px;
border-left: 3px solid #eee;
color: #666;
background: #f9f9f9;
border-left: 3px solid $border-color;
color: $text-color;
background: $background-color;
}
.bs-callout h4 {
margin-top: 0;
......
......@@ -16,6 +16,7 @@
.append-bottom-10 { margin-bottom:10px }
.append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block }
.center { text-align: center }
......@@ -387,6 +388,36 @@ table {
}
}
.center-middle-menu {
@include nav-menu;
padding: 0;
text-align: center;
margin: -$gl-padding;
margin-top: 0;
margin-bottom: 0;
height: 58px;
border-bottom: 1px solid $border-color;
li {
&:after {
content: "|";
color: $border-gray-light;
}
&:last-child {
&:after {
content: none;
}
}
> a {
display: inline-block;
text-transform: uppercase;
font-size: 13px;
}
}
}
.dropzone .dz-preview .dz-progress {
border-color: $border-color !important;
}
......
......@@ -118,6 +118,10 @@ header {
}
}
}
.impersonation i {
color: $red-normal;
}
}
@mixin collapsed-header {
......
......@@ -5,7 +5,6 @@ html {
body {
padding-top: $header-height;
text-rendering: geometricPrecision;
}
}
......
......@@ -117,7 +117,7 @@ ul.content-list {
}
.controls {
padding-top: 4px;
padding-top: 1px;
float: right;
.btn {
......
......@@ -106,6 +106,7 @@
}
.markdown-area {
@include border-radius(0);
background: #FFF;
border: 1px solid #ddd;
min-height: 140px;
......
......@@ -72,9 +72,10 @@
list-style: none;
> li {
@include clearfix;
padding: 10px 0;
border-bottom: 1px solid #EEE;
overflow: hidden;
display: block;
margin: 0px;
......@@ -137,6 +138,7 @@
&:hover, &:active, &:focus {
text-decoration: none;
outline: none;
}
}
......
......@@ -64,6 +64,7 @@
text-decoration: none;
padding-left: 22px;
font-weight: normal;
outline: none;
&:hover {
text-decoration: none;
......@@ -176,6 +177,7 @@
text-align: center;
line-height: 40px;
transition-duration: .3s;
outline: none;
}
.collapse-nav a:hover {
......@@ -238,6 +240,7 @@
width: 100%;
padding: 10px 22px;
overflow: hidden;
outline: none;
img {
width: 36px;
......
......@@ -173,7 +173,6 @@
*
*/
body {
text-rendering:optimizeLegibility;
-webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px;
}
......
......@@ -33,6 +33,8 @@
}
li.commit {
list-style: none;
.commit-row-title {
font-size: $list-font-size;
line-height: 20px;
......@@ -113,3 +115,10 @@ li.commit {
}
}
}
.branch-commit {
color: $gl-gray;
.commit-id, .commit-row-message {
color: $gl-gray;
}
}
......@@ -367,7 +367,6 @@
.inline-parallel-buttons {
float: right;
margin-top: -5px;
}
// Mobile
......
......@@ -50,7 +50,7 @@
.editor-file-name {
.new-file-name {
display: inline-block;
width: 200px;
width: 450px;
}
.form-control {
......
......@@ -4,7 +4,7 @@
*/
.event-item {
font-size: $gl-font-size;
padding: $gl-padding;
padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px);
margin-left: -$gl-padding;
margin-right: -$gl-padding;
border-bottom: 1px solid $table-border-color;
......@@ -16,10 +16,7 @@
top: -2px;
}
.event-title {
line-height: 44px;
}
.event-title,
.event-item-timestamp {
line-height: 44px;
}
......@@ -30,7 +27,7 @@
}
.avatar {
margin-right: 15px;
margin-left: -($gl-avatar-size + 15px);
}
.event-title {
......@@ -43,8 +40,7 @@
}
.event-body {
margin-left: 63px;
margin-right: 80px;
margin-right: 174px;
.event-note {
margin-top: 5px;
......@@ -155,6 +151,8 @@
@media (max-width: $screen-xs-max) {
.event-item {
padding-left: $gl-padding;
.event-title {
white-space: normal;
overflow: visible;
......
......@@ -19,6 +19,20 @@
.accept-merge-holder {
.accept-action {
display: inline-block;
.accept_merge_request {
&.ci-pending,
&.ci-running {
@include btn-orange;
}
&.ci-skipped,
&.ci-failed,
&.ci-canceled,
&.ci-error {
@include btn-red;
}
}
}
.accept-control {
......
......@@ -56,6 +56,10 @@
.note_text {
width: 100%;
}
.comment-hints {
margin-top: -12px;
}
}
/* loading indicator */
......@@ -168,7 +172,7 @@
color: #999;
background: #FFF;
padding: 7px;
margin-top: -11px;
margin-top: -7px;
border: 1px solid $border-color;
font-size: 13px;
}
......@@ -53,3 +53,25 @@
float: right;
font-size: 12px;
}
.profile-link-holder {
display: inline;
&:after {
content: "\00B7";
padding: 0px 6px;
font-weight: bold;
}
&:last-child {
&:after {
content: "";
padding: 0;
}
}
a {
color: $blue-dark;
text-decoration: none;
}
}
table .sherlock-code {
max-width: 700px;
}
.sherlock-code {
pre {
word-wrap: normal;
}
pre code {
white-space: pre;
}
}
.sherlock-line-samples-table {
margin-bottom: 0px !important;
thead tr th,
tbody tr td {
font-size: 13px !important;
text-align: right;
padding: 0px 10px !important;
}
}
.sherlock-file-sample pre {
padding-top: 28px !important;
}
.sherlock-line-samples-table .slow {
color: $red-light;
font-weight: bold;
}
......@@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController
def authenticate_admin!
return render_404 unless current_user.is_admin?
end
def authorize_impersonator!
if session[:impersonator_id]
User.find_by!(username: session[:impersonator_id]).admin?
end
end
end
......@@ -57,6 +57,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:version_check_enabled,
:admin_notification_email,
:user_oauth_applications,
:shared_runners_enabled,
:max_artifacts_size,
restricted_visibility_levels: [],
import_sources: []
)
......
class Admin::ImpersonationController < Admin::ApplicationController
skip_before_action :authenticate_admin!, only: :destroy
before_action :user
before_action :authorize_impersonator!
def create
session[:impersonator_id] = current_user.username
session[:impersonator_return_to] = request.env['HTTP_REFERER']
warden.set_user(user, scope: 'user')
flash[:alert] = "You are impersonating #{user.username}."
redirect_to root_path
end
def destroy
redirect = session[:impersonator_return_to]
warden.set_user(user, scope: 'user')
session[:impersonator_return_to] = nil
session[:impersonator_id] = nil
redirect_to redirect || root_path
end
def user
@user ||= User.find_by!(username: params[:id] || session[:impersonator_id])
end
end
......@@ -63,12 +63,6 @@ class Admin::UsersController < Admin::ApplicationController
end
end
def login_as
sign_in(user)
flash[:alert] = "Logged in as #{user.username}"
redirect_to root_path
end
def disable_two_factor
user.disable_two_factor!
redirect_to admin_user_path(user),
......
......@@ -59,14 +59,9 @@ class ApplicationController < ActionController::Base
end
def authenticate_user!(*args)
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
if current_application_settings.home_page_url.present? &&
current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
if current_user.nil? && root_path == request.path
if redirect_to_home_page_url?
redirect_to current_application_settings.home_page_url and return
end
end
super(*args)
end
......@@ -346,4 +341,17 @@ class ApplicationController < ActionController::Base
def git_import_enabled?
current_application_settings.import_sources.include?('git')
end
def redirect_to_home_page_url?
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
return false unless current_application_settings.home_page_url.present?
home_page_url = current_application_settings.home_page_url.chomp('/')
root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
return false if root_urls.include?(home_page_url)
current_user.nil? && root_path == request.path
end
end
......@@ -26,10 +26,6 @@ module Ci
redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
end
def dumped_yaml
send_data @project.generated_yaml_config, filename: '.gitlab-ci.yml'
end
protected
def project
......
module GlobalMilestones
extend ActiveSupport::Concern
def milestones
@milestones = MilestonesFinder.new.execute(@projects, params)
@milestones = GlobalMilestone.build_collection(@milestones)
@milestones = Kaminari.paginate_array(@milestones).page(params[:page]).per(ApplicationController::PER_PAGE)
end
def milestone
milestones = Milestone.of_projects(@projects).where(title: params[:title])
if milestones.present?
@milestone = GlobalMilestone.new(params[:title], milestones)
else
render_404
end
end
end
class Dashboard::MilestonesController < Dashboard::ApplicationController
before_action :load_projects
include GlobalMilestones
before_action :projects
before_action :milestones, only: [:index]
before_action :milestone, only: [:show]
def index
project_milestones = case params[:state]
when 'all'; state
when 'closed'; state('closed')
else state('active')
end
@dashboard_milestones = Milestones::GroupService.new(project_milestones).execute
@dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(PER_PAGE)
end
def show
project_milestones = Milestone.where(project_id: @projects).order("due_date ASC")
@dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end
private
def load_projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
end
def title
params[:title]
end
def state(state = nil)
conditions = { project_id: @projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
def projects
@projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
end
end
class DashboardController < Dashboard::ApplicationController
before_action :event_filter, only: :activity
before_action :projects, only: [:issues, :merge_requests]
respond_to :html
......@@ -47,4 +48,8 @@ class DashboardController < Dashboard::ApplicationController
@events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end
def projects
@projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
end
end
class Groups::ApplicationController < ApplicationController
layout 'group'
before_action :group
private
def group
@group ||= Group.find_by(path: params[:group_id])
end
def authorize_read_group!
unless @group and can?(current_user, :read_group, @group)
if current_user.nil?
......
class Groups::AvatarsController < ApplicationController
class Groups::AvatarsController < Groups::ApplicationController
def destroy
@group = Group.find_by(path: params[:group_id])
@group.remove_avatar!
@group.save
redirect_to edit_group_path(@group)
......
class Groups::GroupMembersController < Groups::ApplicationController
skip_before_action :authenticate_user!, only: [:index]
before_action :group
# Authorize
before_action :authorize_read_group!
......@@ -80,10 +79,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
protected
def group
@group ||= Group.find_by(path: params[:group_id])
end
def member_params
params.require(:group_member).permit(:access_level, :user_id)
end
......
class Groups::MilestonesController < Groups::ApplicationController
before_action :authorize_group_milestone!, only: :update
include GlobalMilestones
before_action :projects
before_action :milestones, only: [:index]
before_action :milestone, only: [:show, :update]
before_action :authorize_group_milestone!, only: [:create, :update]
def index
project_milestones = case params[:state]
when 'all'; state
when 'closed'; state('closed')
else state('active')
end
@group_milestones = Milestones::GroupService.new(project_milestones).execute
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(PER_PAGE)
end
def show
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
def new
@milestone = Milestone.new
end
def update
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestones = Milestones::GroupService.new(project_milestones).milestone(title)
def create
project_ids = params[:milestone][:project_ids]
title = milestone_params[:title]
@group.projects.where(id: project_ids).each do |project|
Milestones::CreateService.new(project, current_user, milestone_params).execute
end
@group_milestones.milestones.each do |milestone|
Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone)
redirect_to milestone_path(title)
end
respond_to do |format|
format.js
format.html do
redirect_to group_milestones_path(group)
def show
end
def update
@milestone.milestones.each do |milestone|
Milestones::UpdateService.new(milestone.project, current_user, milestone_params).execute(milestone)
end
redirect_back_or_default(default: milestone_path(@milestone.title))
end
private
def group
@group ||= Group.find_by(path: params[:group_id])
def authorize_group_milestone!
return render_404 unless can?(current_user, :admin_milestones, group)
end
def title
params[:title]
def milestone_params
params.require(:milestone).permit(:title, :description, :due_date, :state_event)
end
def state(state = nil)
conditions = { project_id: group.projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
def milestone_path(title)
group_milestone_path(@group, title.parameterize, title: title)
end
def authorize_group_milestone!
return render_404 unless can?(current_user, :admin_group, group)
def projects
@projects ||= @group.projects
end
end
......@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController
before_action :group, except: [:new, :create]
# Authorize
before_action :authorize_read_group!, except: [:show, :new, :create]
before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
# Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update]
before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show
layout :determine_layout
......@@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar)
params.require(:group).permit(:name, :description, :path, :avatar, :public)
end
def load_events
......
......@@ -29,7 +29,7 @@ class Projects::ApplicationController < ApplicationController
private
def ci_enabled
return render_404 unless @project.gitlab_ci?
return render_404 unless @project.builds_enabled?
end
def ci_project
......
......@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present?
params[:file_name] = params[:file].original_filename
end
File.join(@path, File.basename(params[:file_name]))
File.join(@path, params[:file_name])
else
@path
end
......
......@@ -3,6 +3,7 @@ class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status]
before_action :authorize_download_build_artifacts!, only: [:download]
layout "project"
......@@ -30,7 +31,7 @@ class Projects::BuildsController < Projects::ApplicationController
def show
@builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20)
@builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit
respond_to do |format|
......@@ -42,17 +43,25 @@ class Projects::BuildsController < Projects::ApplicationController
end
def retry
if @build.commands.blank?
unless @build.retryable?
return page_404
end
build = Ci::Build.retry(@build)
if params[:return_to]
redirect_to URI.parse(params[:return_to]).path
else
redirect_to build_path(build)
end
def download
unless artifacts_file.file_storage?
return redirect_to artifacts_file.url
end
unless artifacts_file.exists?
return not_found!
end
send_file artifacts_file.path, disposition: 'attachment'
end
def status
......@@ -71,6 +80,10 @@ class Projects::BuildsController < Projects::ApplicationController
@build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
end
def artifacts_file
build.artifacts_file
end
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end
......@@ -80,4 +93,14 @@ class Projects::BuildsController < Projects::ApplicationController
return page_404
end
end
def authorize_download_build_artifacts!
unless can?(current_user, :download_build_artifacts, @project)
if current_user.nil?
return authenticate_user!
else
return render_404
end
end
end
end
......@@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController
before_action :authorize_download_code!, except: [:cancel_builds]
before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit
before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
before_action :define_show_vars, only: [:show, :builds]
def show
return git_not_found! unless @commit
@line_notes = commit.notes.inline
@diffs = @commit.diffs
@note = @project.build_commit_note(commit)
@notes_count = commit.notes.count
@notes = commit.notes.not_inline.fresh
@noteable = @commit
@comments_allowed = @reply_allowed = true
......@@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController
commit_id: @commit.id
}
@ci_commit = project.ci_commit(commit.sha)
respond_to do |format|
format.html
format.diff { render text: @commit.to_diff }
......@@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController
end
end
def ci
@ci_commit = @project.ci_commit(@commit.sha)
@builds = @ci_commit.builds if @ci_commit
@notes_count = @commit.notes.count
def builds
@ci_project = @project.gitlab_ci_project
end
def cancel_builds
@ci_commit = @project.ci_commit(@commit.sha)
@ci_commit.builds.running_or_pending.each(&:cancel)
ci_commit.builds.running_or_pending.each(&:cancel)
redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha)
redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end
def retry_builds
ci_commit.builds.latest.failed.each do |build|
if build.retryable?
Ci::Build.retry(build)
end
end
redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end
def branches
@branches = @project.repository.branch_names_contains(commit.id)
......@@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController
render layout: false
end
private
def commit
@commit ||= @project.commit(params[:id])
end
private
def ci_commit
@ci_commit ||= project.ci_commit(commit.sha)
end
def define_show_vars
@diffs = commit.diffs
@notes_count = commit.notes.count
@builds = ci_commit.builds if ci_commit
end
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
......
......@@ -12,9 +12,10 @@ class Projects::CompareController < Projects::ApplicationController
def show
base_ref = Addressable::URI.unescape(params[:from])
@ref = head_ref = Addressable::URI.unescape(params[:to])
diff_options = { ignore_whitespace_change: true } if params[:w] == '1'
compare_result = CompareService.new.
execute(@project, head_ref, @project, base_ref)
execute(@project, head_ref, @project, base_ref, diff_options)
if compare_result
@commits = Commit.decorate(compare_result.commits, @project)
......
......@@ -158,10 +158,12 @@ class Projects::IssuesController < Projects::ApplicationController
end
def issue_params
params.require(:issue).permit(
permitted = params.require(:issue).permit(
:title, :assignee_id, :position, :description,
:milestone_id, :state_event, :task_num, label_ids: []
)
params[:issue][:title].strip! if params[:issue][:title]
permitted
end
def bulk_update_params
......
......@@ -31,6 +31,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:target_project)
respond_to do |format|
format.html
......@@ -275,11 +276,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def merge_request_params
params.require(:merge_request).permit(
permitted = params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, :task_num, label_ids: []
)
params[:merge_request][:title].strip! if params[:merge_request][:title]
permitted
end
# Make sure merge requests created before 8.0
......
......@@ -3,7 +3,7 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :find_current_user_notes, except: [:destroy, :delete_attachment]
before_action :find_current_user_notes, except: [:destroy, :edit, :delete_attachment]
def index
current_fetched_at = Time.now.to_i
......@@ -29,6 +29,11 @@ class Projects::NotesController < Projects::ApplicationController
end
end
def edit
@note = note
render layout: false
end
def update
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
......
class Projects::ReleasesController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :authorize_push_code!
before_action :tag
before_action :release
def edit
end
def update
release.update_attributes(release_params)
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
end
private
def tag
@tag ||= @repository.find_tag(params[:tag_id])
end
def release
@release ||= @project.releases.find_or_initialize_by(tag: @tag.name)
end
def release_params
params.require(:release).permit(:description)
end
end
......@@ -8,15 +8,23 @@ class Projects::TagsController < Projects::ApplicationController
def index
sorted = VersionSorter.rsort(@repository.tag_names)
@tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE)
@releases = project.releases.where(tag: @tags)
end
def show
@tag = @repository.find_tag(params[:id])
@release = @project.releases.find_or_initialize_by(tag: @tag.name)
@commit = @repository.commit(@tag.target)
end
def create
result = CreateTagService.new(@project, current_user).
execute(params[:tag_name], params[:ref], params[:message])
execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
if result[:status] == :success
@tag = result[:tag]
redirect_to namespace_project_tags_path(@project.namespace, @project)
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
else
@error = result[:message]
render action: 'new'
......@@ -26,12 +34,6 @@ class Projects::TagsController < Projects::ApplicationController
def destroy
DeleteTagService.new(project, current_user).execute(params[:id])
respond_to do |format|
format.html do
redirect_to namespace_project_tags_path(@project.namespace,
@project)
end
format.js
end
redirect_to namespace_project_tags_path(@project.namespace, @project)
end
end
class ProjectsController < ApplicationController
include ExtractsPath
prepend_before_filter :render_go_import, only: [:show]
prepend_before_action :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
......@@ -72,8 +72,7 @@ class ProjectsController < ApplicationController
def remove_fork
return access_denied! unless can?(current_user, :remove_fork_project, @project)
if @project.forked?
@project.forked_project_link.destroy
if @project.unlink_fork
flash[:notice] = 'The fork relationship has been removed.'
end
end
......@@ -213,7 +212,8 @@ class ProjectsController < ApplicationController
params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled
)
end
......
......@@ -23,8 +23,8 @@ class SearchController < ApplicationController
@search_results =
if @project
unless %w(blobs notes issues merge_requests milestones wiki_blobs).
include?(@scope)
unless %w(blobs notes issues merge_requests milestones wiki_blobs
commits).include?(@scope)
@scope = 'blobs'
end
......
module Sherlock
class ApplicationController < ::ApplicationController
before_action :find_transaction
def find_transaction
if params[:transaction_id]
@transaction = Gitlab::Sherlock.collection.
find_transaction(params[:transaction_id])
end
end
end
end
module Sherlock
class FileSamplesController < Sherlock::ApplicationController
def show
@file_sample = @transaction.find_file_sample(params[:id])
end
end
end
module Sherlock
class QueriesController < Sherlock::ApplicationController
def show
@query = @transaction.find_query(params[:id])
end
end
end
module Sherlock
class TransactionsController < Sherlock::ApplicationController
def index
@transactions = Gitlab::Sherlock.collection.newest_first
end
def show
@transaction = Gitlab::Sherlock.collection.find_transaction(params[:id])
render_404 unless @transaction
end
def destroy_all
Gitlab::Sherlock.collection.clear
redirect_to(:back)
end
end
end
......@@ -6,7 +6,7 @@ class GroupsFinder
private
def all_groups(current_user)
if current_user
group_ids = if current_user
if current_user.authorized_groups.any?
# User has access to groups
#
......@@ -15,9 +15,8 @@ class GroupsFinder
# groups with internal projects
# groups with joined projects
#
group_ids = Project.public_and_internal_only.pluck(:namespace_id) +
Project.public_and_internal_only.pluck(:namespace_id) +
current_user.authorized_groups.pluck(:id)
Group.where(id: group_ids)
else
# User has no group membership
#
......@@ -25,14 +24,16 @@ class GroupsFinder
# groups with public projects
# groups with internal projects
#
Group.where(id: Project.public_and_internal_only.pluck(:namespace_id))
Project.public_and_internal_only.pluck(:namespace_id)
end
else
# Not authenticated
#
# Return only:
# groups with public projects
Group.where(id: Project.public_only.pluck(:namespace_id))
Project.public_only.pluck(:namespace_id)
end
Group.where("public IS TRUE OR id IN(?)", group_ids)
end
end
class MilestonesFinder
def execute(projects, params)
milestones = Milestone.of_projects(projects)
milestones = milestones.order("due_date ASC")
case params[:state]
when 'closed' then milestones.closed
when 'all' then milestones
else milestones.active
end
end
end
module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
def ldap_enabled?
......
module BuildsHelper
def build_ref_link build
gitlab_ref_link build.project, build.ref
end
def build_commit_link build
gitlab_commit_link build.project, build.short_sha
end
def build_url(build)
namespace_project_build_path(build.gl_project, build.project, build)
end
end
......@@ -4,25 +4,6 @@ module Ci
{ :"data-no-turbolink" => "data-no-turbolink" }
end
def gitlab_ref_link project, ref
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commits/#{ref}"
link_to ref, gitlab_url, no_turbolink
end
def gitlab_compare_link project, before, after
gitlab_url = project.gitlab_url.dup
gitlab_url << "/compare/#{before}...#{after}"
link_to "#{before}...#{after}", gitlab_url, no_turbolink
end
def gitlab_commit_link project, sha
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commit/#{sha}"
link_to Ci::Commit.truncate_sha(sha), gitlab_url, no_turbolink
end
def yaml_web_editor_link(project)
commits = project.commits
......
module CiStatusHelper
def ci_status_path(ci_commit)
project = ci_commit.gl_project
ci_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
end
def ci_status_icon(ci_commit)
......
......@@ -137,7 +137,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do
link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do
'Inline'
end
end
......@@ -148,7 +148,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do
link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do
'Side-by-side'
end
end
......
......@@ -108,6 +108,11 @@ module EventsHelper
end
end
elsif event.push?
push_event_feed_url(event)
end
end
def push_event_feed_url(event)
if event.push_with_commits? && event.md_ref?
if event.commits_count > 1
namespace_project_compare_url(event.project.namespace, event.project,
......@@ -122,7 +127,6 @@ module EventsHelper
event.ref_name)
end
end
end
def event_feed_summary(event)
if event.issue?
......@@ -198,7 +202,7 @@ module EventsHelper
xml.link href: event_link
xml.title truncate(event_title, length: 80)
xml.updated event.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(event.author_email)
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
xml.author do |author|
xml.name event.author_name
xml.email event.author_email
......
......@@ -74,7 +74,7 @@ module IssuesHelper
issue.project, issue)
xml.title truncate(issue.title, length: 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(issue.author_email)
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
xml.author do |author|
xml.name issue.author_name
xml.email issue.author_email
......
......@@ -100,7 +100,7 @@ module LabelsHelper
Label.where(project_id: @projects)
end
grouped_labels = Labels::GroupService.new(labels).execute
grouped_labels = GlobalLabel.build_collection(labels)
grouped_labels.unshift(Label::None)
grouped_labels.unshift(Label::Any)
......
......@@ -28,7 +28,7 @@ module MilestonesHelper
Milestone.where(project_id: @projects)
end.active
grouped_milestones = Milestones::GroupService.new(milestones).execute
grouped_milestones = GlobalMilestone.build_collection(milestones)
grouped_milestones.unshift(Milestone::None)
grouped_milestones.unshift(Milestone::Any)
......
......@@ -16,40 +16,28 @@ module NotificationsHelper
def notification_list_item(notification_level, user_membership)
case notification_level
when Notification::N_DISABLED
content_tag(:li, class: active_level_for(user_membership, Notification::N_DISABLED)) do
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_DISABLED } do
icon('microphone-slash fw', text: 'Disabled')
end
end
update_notification_link(Notification::N_DISABLED, user_membership, 'Disabled', 'microphone-slash')
when Notification::N_PARTICIPATING
content_tag(:li, class: active_level_for(user_membership, Notification::N_PARTICIPATING)) do
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_PARTICIPATING } do
icon('volume-up fw', text: 'Participate')
end
end
update_notification_link(Notification::N_PARTICIPATING, user_membership, 'Participate', 'volume-up')
when Notification::N_WATCH
content_tag(:li, class: active_level_for(user_membership, Notification::N_WATCH)) do
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_WATCH } do
icon('eye fw', text: 'Watch')
end
end
update_notification_link(Notification::N_WATCH, user_membership, 'Watch', 'eye')
when Notification::N_MENTION
content_tag(:li, class: active_level_for(user_membership, Notification::N_MENTION)) do
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_MENTION } do
icon('at fw', text: 'On mention')
end
end
update_notification_link(Notification::N_MENTION, user_membership, 'On mention', 'at')
when Notification::N_GLOBAL
content_tag(:li, class: active_level_for(user_membership, Notification::N_GLOBAL)) do
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_GLOBAL } do
icon('globe fw', text: 'Global')
end
end
update_notification_link(Notification::N_GLOBAL, user_membership, 'Global', 'globe')
else
# do nothing
end
end
def update_notification_link(notification_level, user_membership, title, icon)
content_tag(:li, class: active_level_for(user_membership, notification_level)) do
link_to '#', class: 'update-notification', data: { notification_level: notification_level } do
icon("#{icon} fw", text: title)
end
end
end
def notification_label(user_membership)
Notification.new(user_membership).to_s
end
......
......@@ -117,7 +117,7 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
if project.gitlab_ci? && can?(current_user, :read_build, project)
if project.builds_enabled? && can?(current_user, :read_build, project)
nav_tabs << :builds
end
......
......@@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group|
GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
{
label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group)
......
......@@ -154,6 +154,7 @@ class Ability
:create_merge_request,
:create_wiki,
:manage_builds,
:download_build_artifacts,
:push_code
]
end
......@@ -232,6 +233,7 @@ class Ability
if group.has_master?(user) || group.has_owner?(user) || user.admin?
rules.push(*[
:create_projects,
:admin_milestones
])
end
......
......@@ -23,6 +23,10 @@
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
# import_sources :text
# help_page_text :text
# admin_notification_email :string(255)
# shared_runners_enabled :boolean default(TRUE), not null
# max_artifacts_size :integer default(100), not null
#
class ApplicationSetting < ActiveRecord::Base
......@@ -68,9 +72,15 @@ class ApplicationSetting < ActiveRecord::Base
end
end
after_commit do
Rails.cache.write('application_setting.last', self)
end
def self.current
Rails.cache.fetch('application_setting.last') do
ApplicationSetting.last
end
end
def self.create_from_defaults
create(
......@@ -87,7 +97,9 @@ class ApplicationSetting < ActiveRecord::Base
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
restricted_signup_domains: Settings.gitlab['restricted_signup_domains'],
import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'],
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
max_artifacts_size: Settings.gitlab_ci['max_artifacts_size'],
)
end
......
# == Schema Information
#
# Table name: application_settings
# Table name: ci_application_settings
#
# id :integer not null, primary key
# all_broken_builds :boolean
......@@ -13,9 +13,15 @@ module Ci
class ApplicationSetting < ActiveRecord::Base
extend Ci::Model
after_commit do
Rails.cache.write('ci_application_setting.last', self)
end
def self.current
Rails.cache.fetch('ci_application_setting.last') do
Ci::ApplicationSetting.last
end
end
def self.create_from_defaults
create(
......
# == Schema Information
#
# Table name: builds
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
......@@ -11,16 +11,24 @@
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# commit_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# deploy :boolean default(FALSE)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
#
module Ci
......@@ -39,6 +47,8 @@ module Ci
scope :ignore_failures, ->() { where(allow_failure: false) }
scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) }
mount_uploader :artifacts_file, ArtifactUploader
acts_as_taggable
# To prevent db load megabytes of data from trace
......@@ -106,6 +116,14 @@ module Ci
failed? && allow_failure?
end
def retryable?
commands.present?
end
def retried?
!self.commit.latest_builds_for_ref(self.ref).include?(self)
end
def trace_html
html = Ci::Ansi2html::convert(trace) if trace.present?
html || ''
......@@ -209,6 +227,14 @@ module Ci
"#{dir_to_trace}/#{id}.log"
end
def token
project.token
end
def valid_token? token
project.valid_token? token
end
def target_url
Gitlab::Application.routes.url_helpers.
namespace_project_build_url(gl_project.namespace, gl_project, self)
......@@ -222,7 +248,7 @@ module Ci
end
def retry_url
if commands.present?
if retryable?
Gitlab::Application.routes.url_helpers.
retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
end
......@@ -240,6 +266,13 @@ module Ci
pending? && !any_runners_online?
end
def download_url
if artifacts_file.exists?
Gitlab::Application.routes.url_helpers.
download_namespace_project_build_path(gl_project.namespace, gl_project, self)
end
end
private
def yaml_variables
......
# == Schema Information
#
# Table name: commits
# Table name: ci_commits
#
# id :integer not null, primary key
# project_id :integer
......@@ -13,6 +13,7 @@
# tag :boolean default(FALSE)
# yaml_errors :text
# committed_at :datetime
# gl_project_id :integer
#
module Ci
......@@ -187,7 +188,7 @@ module Ci
end
def config_processor
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
save_yaml_error(e.message)
nil
......
# == Schema Information
#
# Table name: events
# Table name: ci_events
#
# id :integer not null, primary key
# project_id :integer
......
# == Schema Information
#
# Table name: projects
# Table name: ci_projects
#
# id :integer not null, primary key
# name :string(255) not null
# name :string(255)
# timeout :integer default(3600), not null
# created_at :datetime
# updated_at :datetime
......@@ -66,30 +66,6 @@ module Ci
class << self
include Ci::CurrentSettings
def base_build_script
<<-eos
git submodule update --init
ls -la
eos
end
def parse(project)
params = {
gitlab_id: project.id,
default_ref: project.default_branch || 'master',
email_add_pusher: current_application_settings.add_pusher,
email_only_broken_builds: current_application_settings.all_broken_builds,
}
project = Ci::Project.new(params)
project.build_missing_services
project
end
def already_added?(project)
where(gitlab_id: project.id).any?
end
def unassigned(runner)
joins("LEFT JOIN #{Ci::RunnerProject.table_name} ON #{Ci::RunnerProject.table_name}.project_id = #{Ci::Project.table_name}.id " \
"AND #{Ci::RunnerProject.table_name}.runner_id = #{runner.id}").
......
# == Schema Information
#
# Table name: runners
# Table name: ci_runners
#
# id :integer not null, primary key
# token :string(255)
......
# == Schema Information
#
# Table name: runner_projects
# Table name: ci_runner_projects
#
# id :integer not null, primary key
# runner_id :integer not null
......
# == Schema Information
#
# Table name: services
# Table name: ci_services
#
# id :integer not null, primary key
# type :string(255)
......
# == Schema Information
#
# Table name: triggers
# Table name: ci_triggers
#
# id :integer not null, primary key
# token :string(255)
......
# == Schema Information
#
# Table name: trigger_requests
# Table name: ci_trigger_requests
#
# id :integer not null, primary key
# trigger_id :integer not null
......
# == Schema Information
#
# Table name: variables
# Table name: ci_variables
#
# id :integer not null, primary key
# project_id :integer not null
......
# == Schema Information
#
# Table name: web_hooks
# Table name: ci_web_hooks
#
# id :integer not null, primary key
# url :string(255) not null
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
#
class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds'
......@@ -15,8 +48,8 @@ class CommitStatus < ActiveRecord::Base
scope :pending, -> { where(status: 'pending') }
scope :success, -> { where(status: 'success') }
scope :failed, -> { where(status: 'failed') }
scope :running_or_pending, -> { where(status:[:running, :pending]) }
scope :finished, -> { where(status:[:success, :failed, :canceled]) }
scope :running_or_pending, -> { where(status: [:running, :pending]) }
scope :finished, -> { where(status: [:success, :failed, :canceled]) }
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) }
......@@ -92,4 +125,8 @@ class CommitStatus < ActiveRecord::Base
def show_warning?
false
end
def download_url
nil
end
end
......@@ -24,7 +24,7 @@ module Issuable
scope :authored, ->(user) { where(author_id: user) }
scope :assigned_to, ->(u) { where(assignee_id: u.id)}
scope :recent, -> { order("created_at DESC") }
scope :recent, -> { reorder(id: :desc) }
scope :assigned, -> { where("assignee_id IS NOT NULL") }
scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) }
......
......@@ -8,12 +8,12 @@ module Sortable
included do
# By default all models should be ordered
# by created_at field starting from newest
default_scope { order(created_at: :desc, id: :desc) }
default_scope { order(id: :desc) }
scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) }
scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) }
scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) }
scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) }
scope :order_created_desc, -> { reorder(created_at: :desc) }
scope :order_created_asc, -> { reorder(created_at: :asc) }
scope :order_updated_desc, -> { reorder(updated_at: :desc) }
scope :order_updated_asc, -> { reorder(updated_at: :asc) }
scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) }
end
......
......@@ -45,7 +45,7 @@ class Event < ActiveRecord::Base
after_create :reset_project_activity
# Scopes
scope :recent, -> { order(created_at: :desc) }
scope :recent, -> { reorder(id: :desc) }
scope :code_push, -> { where(action: PUSHED) }
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
scope :with_associations, -> { includes(project: :namespace) }
......
# == Schema Information
#
# Table name: ci_builds
#
# id :integer not null, primary key
# project_id :integer
# status :string(255)
# finished_at :datetime
# trace :text
# created_at :datetime
# updated_at :datetime
# started_at :datetime
# runner_id :integer
# coverage :float
# commit_id :integer
# commands :text
# job_id :integer
# name :string(255)
# deploy :boolean default(FALSE)
# options :text
# allow_failure :boolean default(FALSE), not null
# stage :string(255)
# trigger_request_id :integer
# stage_idx :integer
# tag :boolean
# ref :string(255)
# user_id :integer
# type :string(255)
# target_url :string(255)
# description :string(255)
# artifacts_file :text
#
class GenericCommitStatus < CommitStatus
before_validation :set_default_values
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment